https://Robo.Fish/wiki/api.php?action=feedcontributions&user=Kai&feedformat=atomRobo.Fish Wiki - User contributions [en]2024-03-29T14:49:23ZUser contributionsMediaWiki 1.41.0https://Robo.Fish/wiki/index.php?title=Linux&diff=3171Linux2023-01-17T11:04:32Z<p>Kai: /* SSH Logins Without Typing The Password */</p>
<hr />
<div>= Boot Procedure =<br />
# The primary bootloader, which is usually a fixed part of the hardware recognizes bootable media.<br />
#* On PC compatible systems, [https://en.wikipedia.org/wiki/UEFI UEFI] or BIOS are the primary bootloaders.<br />
#* On BIOS systems, the Master Boot Record (MBR) area of a connected storage device is searched for a boot executable. The MBR is a special area, separate from the actual data storage area. BIOS is an old system, dating back to the early 1980s, but not yet obsolete.<br />
#* On a UEFI system, which supports storage media with much larger capacity, the ''GPT'' partition table is used to determine if the storage device provides an ''EFI System Partition'' containing the folder ''/efi'' with a subfolder that contains the secondary boot loader. ''/efi/microsoft'' or ''/efi/grub'', for example. After a Linux system is booted by UEFI hardware, you can open a terminal and inspect the partition table by typing <span class="terminal">sudo gdisk /dev/sda</span>.<br />
# If a secondary bootloader is found on the bootable media, it is loaded.<br />
#* On PC compatibles the secondary bootloader is usually [https://www.gnu.org/software/grub GRUB2].<br />
#* On [[Arm Cortex-A]] based systems, this is often [https://u-boot.readthedocs.io/en/latest/ U-Boot].<br />
#* Some systems have proprietary bootloaders. Raspberry Pi, for example.<br />
#* To support the bootloader, a standard interface called LBA (linear block access) exists for storage media. This interface is not optimized for the capabilities of the storage device but is sufficient for the bootloader to search for a bootable operating system, which will later load the appropriate driver for the storage media.<br />
# The secondary bootloader loads the [https://www.kernel.org Linux kernel].<br />
#* In the case of GRUB2, the boot media is searched for the boot partition using LBA mode, stage 2 is loaded from a separate data area of the boot media, the module for working with the boot partitions filesystem is loaded, the GRUB config file (''/boot/grub/grub.cfg'') is loaded from the boot partition, the user is optionally shown a GRUB menu, the kernel is loaded with the user parameters.<br />
# The kernel optionally loads an initial root file system into memory (often [https://en.wikipedia.org/wiki/Initial_ramdisk initramfs]), which includes the device drivers specific for the target hardware. For example, display drivers for showing graphical output during the boot sequence.<br />
#* Technically, all hardware-specific device drivers can be compiled into the kernel itself. In order to keep the kernel generic, however, and to avoid mixing components with incompatible distribution licenses (the GPL 2.0 license used by Linux prevents distributing a kernel with built-in proprietary drivers), certain drivers are placed into initramfs, from where they are loaded when needed.<br />
#* After the hardware is initialized, the kernel switches from initramfs to the real filesystem.<br />
# The kernel starts the first process, the '''init''' process. The ''init'' process starts all the system processes (a.k.a. ''services'') configured to run when the system launches.<br />
#* ''init'' used to be a shell script located in the filesystem at ''/sbin/init''. Nowadays, many Linux distributions use the '''[https://wiki.debian.org/systemd systemd]''' initialization method, where a binary executable is called instead of a shell script.<br />
<br /><br />
<br />
= Device Trees =<br />
Device trees are files that contain a static, hierarchical description of the hardware components of a Linux system with Arm processor architecture. Device trees are usually read by the bootloader. The specification of the device tree file format can be found at [https://devicetree.org devicetree.org].<br />
<br /><br />
<br /><br />
In a Linux kernel source repository, device tree source files are located in the ''linux/arch/arm/boot/dts'' directory. Device tree source files are also usually provided by manufacturers of hardware components that are connected via GPIO.<br />
<br /><br />
Device tree definitions are written in text form into ''.dts'' or ''.dtsi'' files, compiled into binary ''.dtb'' files, and placed into the ''/boot'' directory of the Linux system.<br />
<br /><br />
<br /><br />
== DTS Syntax ==<br />
<pre class="code"><br />
/dts-v1/;<br />
#include "bcm2711.dtsi"<br />
#include "bcm2711-rpi.dtsi"<br />
/ {<br />
compatible = "raspberrypi,4-model-b", "brcm,bcm2711";<br />
model = "Raspberry Pi 4 Model B";<br />
<br />
chosen {<br />
/* 8250 auxiliary UART instead of pl011 */<br />
stdout-path = "serial1:115200n8";<br />
};<br />
<br />
leds {<br />
led-act {<br />
gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;<br />
};<br />
<br />
led-pwr {<br />
label = "PWR";<br />
gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;<br />
default-state = "keep";<br />
linux,default-trigger = "default-on";<br />
};<br />
};<br />
<br />
...<br />
</pre><br />
<br /><br />
== Device Tree Compiler ==<br />
<pre class="terminal"><br />
sudo apt install device-tree-compiler<br />
dtc -I dts -O dtb -o my_system.dtb my_system.dts<br />
</pre><br />
<br /><br />
<br /><br />
<br />
== Device Tree Overlays ==<br />
Overlays are partial device tree definitions that modify an existing device tree file. The sources files have the extension ''.dts'', just like ordinary device tree source files. Compiled overlays have the '''.dtbo''' file extension and are placed in the '''/boot/overlays''' directory.<br />
<br /><br />
<br /><br />
Overlays are compiled by adding the ''-@'' flag, which generates symbols for referenced items (that the compiler would otherwise not be able to resolve). <br />
<pre class="terminal"><br />
dtc -@ -I dts -O dtb -o camera_overlay.dtbo camera_overlay.dts<br />
</pre><br />
<br /><br />
<br />
= Systemd =<br />
== Systemd Unit Files ==<br />
Unit files determine what kind of task is being started. The types of tasks are<br />
* '''service''' for running daemons<br />
* '''mount''' for mounting storage media, etc<br />
* '''automount''' for mounting directories when needed<br />
* '''timer''' for starting jobs at specific times<br />
* '''target''' (a group of unit files, or a state that the machine should be in after booting)<br />
* '''path''' (monitoring filesystem events)<br />
<br />
The original unit files that are installed by the package manager are placed in ''/usr/lib/systemd/system'' and should not be modified.<br />
If modifications to unit files are to be made, the modified unit files should be placed into ''/etc/systemd/system''.<br />
<br /><br />
<br />
=== Unit Relationships (Dependencies) ===<br />
There are various relationships between two units:<br />
* '''requires''': The dependent unit must be loaded in order to load the current unit.<br />
* '''wants''': The dependent unit is not critical<br />
* '''requisite''': the dependent unit must be loaded and already active.<br />
* '''conflicts''': the unit must not be loaded for the current to be loaded<br />
* '''before''': the current unit must be activated before the given units<br />
* '''after''': the current unit must be activated after the given units<br />
<br /><br />
The dependency graph can be displayed on the terminal via<br />
<pre class="terminal"><br />
sudo systemctl list-dependencies<br />
</pre><br />
<br /><br />
<br />
== Systemd Services ==<br />
Here is an example of using ''systemctl'' to query the status of the SSH server.<br />
<pre class="terminal"><br />
systemctl status sshd<br />
</pre><br />
<br /><br />
To start or stop the server, you would type<br />
<pre class="terminal"><br />
sudo systemctl start sshd<br />
sudo systemctl stop sshd<br />
</pre><br />
<br /><br />
To configure a service, edit its configuration file located in '''/etc/systemd/system'''.<br />
<br /><br />
<br /><br />
<br />
== Systemd Targets ==<br />
Targets are groups of unit files. If a target includes the statement <span class="code">AllowIsolate = yes</span> the target becomes an initialization endpoint at which systemd stops executing other units. Isolate targets are therefore similar to System V runlevels that were used for initialization before systemd.<br />
<br /><br />
<br /><br />
For a custom target (or service), the relationship to the unit files that are ''WantedBy'' or ''RequiredBy'' the target (or service) will be established by systemd through symbolic links to the wanted or required unit files. These symbolic links are placed in ''/etc/systemd/system'', within a subdirectory whose name starts with the name of the unit file and ends with the name of the type of relationship.<br />
<br /><br />
<br /><br />
== Systemd Analysis ==<br />
Systemd can plot a chart that shows how the units are launched over time.<br />
<pre class="terminal"><br />
systemd-analyze plot > analysis.html<br />
</pre><br />
generates an HTML page with a chart like this<br />
<br /><br />
<br /><br />
[[File:systemd-analysis.png | x300px ]]<br />
<br /><br />
<br /><br />
<br />
= Which Linux distro and version am I running? =<br />
<pre class="terminal"><br />
cat /etc/os-release<br />
</pre><br />
<br /><br />
<br />
= Dynamic Shared Objects (DSO) =<br />
Ulrich Drepper's [https://www.akkadia.org/drepper/dsohowto.pdf How To Write Shared Libraries] is a good resource for learning more about the ELF format, about optimizing your shared objects, and how to control the visibility of program symbols in the generated binaries.<br />
<br /><br />
<br /><br />
<br />
= Tracing system calls with ''strace'' =<br />
<br />
'''strace''' is a command that lets you trace the system calls made by the command that is passed as the argument. For example,<br />
<pre class="terminal"><br />
strace echo "hello"<br />
</pre><br />
prints<br />
<pre class="terminal"><br />
execve("/usr/bin/echo", ["echo", "hello"], 0x7ffefa8f4928 /* 42 vars */) = 0<br />
brk(NULL) = 0x561cf6532000<br />
arch_prctl(0x3001 /* ARCH_??? */, 0x7fff61293910) = -1 EINVAL (Invalid argument)<br />
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf85c44000<br />
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)<br />
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=53267, ...}, AT_EMPTY_PATH) = 0<br />
mmap(NULL, 53267, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7faf85c36000<br />
close(3) = 0<br />
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3<br />
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\237\2\0\0\0\0\0"..., 832) = 832<br />
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784<br />
pread64(3, "\4\0\0\0 \0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0"..., 48, 848) = 48<br />
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0i8\235HZ\227\223\333\350s\360\352,\223\340."..., 68, 896) = 68<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=2216304, ...}, AT_EMPTY_PATH) = 0<br />
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784<br />
mmap(NULL, 2260560, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7faf85a0e000<br />
mmap(0x7faf85a36000, 1658880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x28000) = 0x7faf85a36000<br />
mmap(0x7faf85bcb000, 360448, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x7faf85bcb000<br />
mmap(0x7faf85c23000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x214000) = 0x7faf85c23000<br />
mmap(0x7faf85c29000, 52816, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7faf85c29000<br />
close(3) = 0<br />
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf85a0b000<br />
arch_prctl(ARCH_SET_FS, 0x7faf85a0b740) = 0<br />
set_tid_address(0x7faf85a0ba10) = 1874<br />
set_robust_list(0x7faf85a0ba20, 24) = 0<br />
rseq(0x7faf85a0c0e0, 0x20, 0, 0x53053053) = 0<br />
mprotect(0x7faf85c23000, 16384, PROT_READ) = 0<br />
mprotect(0x561cf5067000, 4096, PROT_READ) = 0<br />
mprotect(0x7faf85c7e000, 8192, PROT_READ) = 0<br />
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0<br />
munmap(0x7faf85c36000, 53267) = 0<br />
getrandom("\x01\x62\x8d\xf4\xec\xea\xd8\x4e", 8, GRND_NONBLOCK) = 8<br />
brk(NULL) = 0x561cf6532000<br />
brk(0x561cf6553000) = 0x561cf6553000<br />
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=6070224, ...}, AT_EMPTY_PATH) = 0<br />
mmap(NULL, 6070224, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7faf85441000<br />
close(3) = 0<br />
newfstatat(1, "", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}, AT_EMPTY_PATH) = 0<br />
write(1, "hello\n", 6) = 6<br />
close(1) = 0<br />
close(2) = 0<br />
exit_group(0) = ?<br />
+++ exited with 0 +++<br />
</pre><br />
lists system calls made by ''echo'' as they are made.<br />
<br /><br />
<br /><br />
Instead of printing system calls as they are made, ''strace'' can print a short summary of which system calls were how many times and the time spent.<br />
<pre class="terminal"><br />
strace -c echo "hello"<br />
</pre><br />
prints<br />
<pre class="terminal"><br />
hello<br />
% time seconds usecs/call calls errors syscall<br />
------ ----------- ----------- --------- --------- ----------------<br />
0,00 0,000000 0 1 read<br />
0,00 0,000000 0 1 write<br />
0,00 0,000000 0 5 close<br />
0,00 0,000000 0 9 mmap<br />
0,00 0,000000 0 3 mprotect<br />
0,00 0,000000 0 1 munmap<br />
0,00 0,000000 0 3 brk<br />
0,00 0,000000 0 4 pread64<br />
0,00 0,000000 0 1 1 access<br />
0,00 0,000000 0 1 execve<br />
0,00 0,000000 0 2 1 arch_prctl<br />
0,00 0,000000 0 1 set_tid_address<br />
0,00 0,000000 0 3 openat<br />
0,00 0,000000 0 4 newfstatat<br />
0,00 0,000000 0 1 set_robust_list<br />
0,00 0,000000 0 1 prlimit64<br />
0,00 0,000000 0 1 getrandom<br />
0,00 0,000000 0 1 rseq<br />
------ ----------- ----------- --------- --------- ----------------<br />
100,00 0,000000 0 43 2 total<br />
</pre><br />
<br /><br />
<br /><br />
<br />
Similarly, '''ltrace''' will list the calls to library functions made by the command that was passed as the argument to ''ltrace''.<br />
<pre class="terminal"><br />
sudo apt install ltrace<br />
</pre><br />
<br /><br />
<br />
== Signals ==<br />
Signals are software interrupts that the the kernel can send an executable. The executable may react to the signal or choose to ignore it. The two signals SIGKILL and SIGTERM, however, can not be ignored by executable and must be handled.<br />
<br /><br />
An overview of the signals can be found in the man pages entry about signals<br />
<pre class="terminal"><br />
man 7 signal<br />
</pre><br />
<br /><br />
Some command-line tools do useful stuff when certain signals are sent to them. For example, the ''dd'' tool prints the progress of the copying task when the SIGUSR1 signal is sent to it via the ''kill'' command.<br />
<pre class="terminal"><br />
dd if=${HOME}/image.iso of=/dev/sdb &<br />
kill -s USR1 $(pidof dd)<br />
</pre><br />
<br /><br />
<br />
= Interprocess Communication Mechanisms =<br />
<br />
== Shared Memory ==<br />
Linux offers creating System V shared memory segments, which can be used for interprocess communication.<br />
<pre class="code"><br />
#include <sys/types.h><br />
#include <sys/ipc.h><br />
#include <sys/shm.h><br />
<br />
// creating an IPC key<br />
key_t segmentKey = ftok(”path_to_some_existing_file", 'R')<br />
if (segmentKey == -1) {<br />
perror("could not create IPC key");<br />
exit(1);<br />
}<br />
// accessing the shared memory segment, creating it if it doesn't exist<br />
int sharedMemoryID = shmget(segmentKey, SHM_SIZE, 0644 | IPC_CREAT)<br />
if (sharedMemoryID == -1) {<br />
perror("could not access (or create) the shared memory segment");<br />
exit(1);<br />
}<br />
// attaching a pointer<br />
void* memoryPtr = shmat(sharedMemoryID, NULL, 0);<br />
if (*((char*)memoryPtr) == -1) {<br />
perror("could not attach a pointer to the shared memory segment");<br />
exit(1);<br />
}<br />
</pre><br />
To learn more about shared memory segments, type<br />
<pre class="terminal"><br />
man ftok<br />
man shmget<br />
man shmat<br />
</pre><br />
<br /><br />
<br />
== Memory Mapped Files ==<br />
Linux offers mapping files to memory regions, which enables working on the file contents much more efficiently, as if it is a memory region. For example, pointers can be used in a C/C++ program to edit the contents. The memory mapped region can be shared between processes. This allows the processes to operate on large files, for example in a writer-subscriber architecture, while preserving memory. Unlike the shared memory method described above, the contents of the shared memory region are written to a file and thus persist between sessions and even system reboots.<br />
<pre class="code"><br />
#include <stdlib.h> <br />
#include <stdio.h> <br />
#include <unistd.h><br />
#include <errno.h> <br />
#include <string.h> <br />
#include <fcntl.h> <br />
#include <sys/types.h> <br />
#include <sys/stat.h> <br />
#include <sys/mman.h> <br />
<br />
static const int MAX_INPUT_LENGTH = 50;<br />
<br />
int main(int argc, char** argv)<br />
{<br />
int fd = open(argv[1], O_RDWR | O_CREAT); <br />
char* shared_mem = mmap(NULL, MAX_INPUT_LENGTH, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); <br />
close(fd); <br />
<br />
if (!strcmp(argv[2], "read")) { <br />
// continously listens to text messages from the 'write' process and writes to the terminal<br />
while (1) { <br />
shared_mem[MAX_INPUT_LENGTH-1] = '\0'; <br />
printf("%s", shared_mem); <br />
sleep(1); <br />
} <br />
} <br />
else if (!strcmp(argv[2], "write")) {<br />
// continuously sends the input from the terminal to the 'read' process<br />
while (1) {<br />
fgets(shared_mem, MAX_INPUT_LENGTH, stdin);<br />
}<br />
}<br />
else {<br />
printf("Unsupported command\n"); <br />
}<br />
}<br />
</pre><br />
<br />
To learn more about memory mapped files, refer to the man page<br />
<pre class="terminal"><br />
man mmap<br />
</pre><br />
<br /><br />
<br />
== Pipes ==<br />
Pipes are another IPC mechanism where one process can send messages to another.<br />
<pre class="code"><br />
#include <stdio.h><br />
#include <stdlib.h> <br />
#include <errno.h> <br />
#include <sys/types.h> <br />
#include <unistd.h> <br />
<br />
int main(void)<br />
{ <br />
int pipeDescriptor[2]; <br />
<br />
pipe(pipeDescriptor); // writing to pipeDescriptor[0], reading from pipeDescriptor[1]<br />
<br />
if (!fork())<br />
{ <br />
printf(" CHILD: writing to pipe and exiting\n"); <br />
write(pipeDescriptor[1], "test", 5); <br />
}<br />
else<br />
{ <br />
char buffer[5]; <br />
printf("PARENT: reading from pipe\n"); <br />
read(pipeDescriptor[0], buffer, 5); <br />
printf("PARENT: read \"%s\"\n", buf); <br />
wait(NULL); <br />
} <br />
return 0; <br />
}<br />
</pre><br />
<br /><br />
To learn more about pipes, refer to the man page<br />
<pre class="terminal"><br />
man pipe<br />
</pre><br />
<br /><br />
<br />
= D-Bus and dmesg =<br />
<br /><br />
<br />
= GUI-less Mode =<br />
<br />
== Switching to GUI-less (Multi-User) Mode with Systemd ==<br />
On a Linux system that uses systemd, we can control whether the graphical user interface is loaded and shown by specifying a suitable systemd target. To turn off the graphical desktop immediately, enter<br />
<pre class="terminal"><br />
sudo systemctl isolate multi-user.target<br />
</pre><br />
To prevent the GUI from being loaded during the system startup, type<br />
<pre class="terminal"><br />
sudo systemctl set-default multi-user.target<br />
</pre><br />
To return to the graphical desktop, type<br />
<br/><br />
<pre class="terminal"><br />
sudo systemctl isolate graphical.target<br />
</pre><br />
and to make the graphical desktop the default again, type<br />
<pre class="terminal"><br />
sudo systemctl set-default graphical.target<br />
</pre><br />
<br /><br />
<br />
== Setting the Screen Resolution for GUI-less Mode ==<br />
* Restart the machine to the Grub boot menu.<br />
* Press 'c' to get into the Grub command console.<br />
* Run the command 'vbeinfo' to list possible resolutions.<br />
* Note down the desired resolution. For example, ''1024x768x32'', where ''32'' is the color mode.<br />
* Type ''exit'' to return to the Grub boot menu and boot into Ubuntu.<br />
* Open '''/etc/default/grub''' in an editor to add the line<br />
<pre class="code"><br />
GRUB_GFXPAYLOAD_LINUX=1024x768x32<br />
</pre><br />
* Optionally, add the line<br />
<pre class="code"><br />
GRUB_GFXMODE=1024x768<br />
</pre><br />
to set the screen resolution for the GRUB boot menu itself.<br />
* Finally, run the Grub updater<br />
<pre class="terminal"><br />
sudo update-grub<br />
</pre><br />
<br /><br />
<br />
= Message of the Day (MOTD) =<br />
For users that open simultaneous terminal sessions to different Linux machines, it is helpful to see a distinct ''message of the day'' (''MOTD'') on each terminal. The MOTD can be customized by editing the shell scripts located in '''/etc/update-motd.d/'''. The shell scripts are executed in alphabetical order, their output is the MOTD. The names of the script files start with a number between 1 and 99, which makes ordering of the scripts immediately visible. Script files can be deleted or their execution bit flipped via ''chmod'' in order to disable the corresponding output. New script files can be added, and their file names chosen according to the desired position of their output.<br />
<br /><br />
<br /><br />
Additionally, it is possible to create the '''/etc/motd''' file with static content, whose output will be appended to the dynamically generated MOTD. With ''/etc/motd'', the MOTD can be embellished with ASCII art, like the Robo.Fish logo below<br />
<br /><br />
<br /><br />
<pre class="code"><br />
.';cldxxkkkxxdolc;,..<br />
.;oOXWWMMMMMMMMMMMMMMWWXKOxo:,.<br />
'o0WMMMMMMMMMMMMMMMMMMMMMMMMMMMWX0xl:'.<br />
.;xXMMMMMMMMMMMMMMMMMMMMMMMMMWWWNNXXKKK0kd:.<br />
.:ONMMMMMMMMMMMMMMMMMMWXKOxdoc:;;,'..........<br />
. 'o0WMMMMMMMMMMMMMMWN0xl:,..<br />
Xx:. .:kXWMMMMMMMMMMMMMN0d:'.<br />
MMWKxc'. .'cxXWMMMMMMMMMMMMNOo:,.<br />
MMMMMMN0xc,. .,cd0NWMMMMMMMMMMMMN0o,.<br />
MMMMMMWWNX0d:;ckKNWMMMMMMMMMMWN0xl,.<br />
lllcc:;,'.. ..,;:clloollc:,..<br />
</pre><br />
<br /><br />
The MOTD can be previewed without needing to start a new shell session:<br />
<pre class="terminal"><br />
sudo run-parts /etc/update-motd.d/<br />
</pre><br />
<br /><br />
<br />
= SSH Logins Without Typing The Password =<br />
If you connect to a remote machine via ''ssh'' or copy files via ''scp'' frequently, you should consider transferring your public key to the remote machine and using ''ssh-agent'' locally in order to log in without typing your password.<br />
<br /><br />
== Generating An SSH Key ==<br />
First, you create an RSA public/private key pair that identifies your local machine. You may already have created such a key in your SSH keychain. It is good security practice, however, to use a separate key for each device you want to connect to. Let us assume you want to connect to a [[Raspberry Pi]]. The command to create a new SSH key would be<br />
<pre class="terminal"><br />
ssh-keygen -t rsa -b 2048 -C "for Raspberry Pi"<br />
</pre><br />
where '-b 2048' specifies the key length in bits. You will be prompted to enter the path and name of the file in which the key will be saved. Choose a name that makes it clear that it was created for connecting to the Raspberry Pi. Next, you will be prompted for a password. Just press the Enter key for no password.<br />
<br /><br />
== Transferring Your Public SSH Key ==<br />
Now that the SSH key is created, you need to transfer the generated public(!) key to the remote machine. If the remote machine will ever only be accessed with a single SSH identity, you can simply copy the user's public key into the ''~/.ssh'' folder on the remove machine.<br />
<pre class="terminal"><br />
scp ~/.ssh/id_rsa.pub pi@192.168.1.10:/home/pi/.ssh/authorized_keys<br />
</pre><br />
where the copied file is renamed to '''authorized_keys''', which is the expected file name for the SSH server to look up the public keys of trusted clients.<br />
<br /><br />
<br /><br />
Generally, however, you should use '''ssh-copy-id''' to transfer the SSH identity. This tool appends the SSH identity to the remote ''~/.ssh/authorized_keys'' instead of overwriting it.<br />
<pre class="terminal"><br />
ssh-copy-id -i ~/.ssh/id_rsa.pub pi@192.168.1.10<br />
</pre><br />
<br /><br />
== Launching ssh-agent ==<br />
Use ''ssh-agent'' on your local machine to start a special shell session that uses the new SSH key to automatically authenticate any SSH connection from your machine to the Raspberry Pi:<br />
<pre class="terminal"><br />
eval "$(ssh-agent -s)" # starting a new shell session<br />
ssh-add ~/.ssh/for-raspberry-pi_rsa<br />
</pre><br />
<br /><br />
Done! This was the last time you had to enter the password for the remote user.<br />
<br /><br />
<br /><br />
By the way, you can list all the keys that were added to the SSH agent by entering<br />
<pre class="terminal"><br />
ssh-add -l<br />
</pre><br />
<br /><br />
<br />
= Bluetooth =<br />
On most Linux systems, Bluetooth functionality is provided by the kernel module, libraries and utilities of the [http://www.bluez.org BlueZ] project. So, make sure that BlueZ is installed.<br />
<pre class="terminal"><br />
sudo apt install bluez<br />
</pre><br />
<br /><br />
<br />
== Bluetooth Low Energy (BLE) Control in Terminal ==<br />
Set the Bluetooth controller to operate in BLE mode only by editing '''/etc/bluetooth/main.conf''' to make sure that the value of ''ControllerMode'' is set to ''le''.<br />
<pre class="code"><br />
ControllerMode = le<br />
</pre><br />
If a change had to be made, you need to reboot the system.<br />
<br /><br />
<br /><br />
Now issue the command <br />
<pre class="terminal"><br />
sudo systemctl start bluetooth<br />
</pre><br />
to start the ''bluetooth'' service. You can also stop, restart and query the status with by replacing ''start'' with ''stop'', ''restart'', ''status'', respectively.<br />
<br /><br />
<br /><br />
With the bluetooth service running, enter the command<br />
<pre class="terminal"><br />
bluetoothctl<br />
</pre><br />
which runs a Bluetooth control program in the terminal. In this program you can, for example, display the list of commands, query the controller, power on the controller, scan for devices with RSSI 80 or better, advertise with the local name ''RPi3'' and, finally, power off and quit the program with the following commands: <br />
<pre class="terminal"><br />
help<br />
show<br />
power on<br />
menu scan<br />
rssi 80<br />
back<br />
scan on<br />
...<br />
scan off<br />
discoverable on<br />
advertise on<br />
menu advertise<br />
name RPi3<br />
back<br />
...<br />
advertise off<br />
power off<br />
quit<br />
</pre><br />
<br />
<br />
== Bluetooth Programming with D-Bus ==<br />
Here is an (incomplete!) example of programming D-Bus in C++ using the [https://github.com/Kistler-Group/sdbus-cpp/blob/master/docs/using-sdbus-c++.md sdbus-c++] C++ binding, for which you need to install ''libsdbus-c++-dev''.<br />
<pre class="terminal"><br />
sudo apt install libbluetooth-dev libsdbus-c++-dev<br />
</pre><br />
<br /><br />
<br />
Inspired by [https://punchthrough.com/creating-a-ble-peripheral-with-bluez/ this article from PunchThrough's Andy Lee], I have created a basic BLE peripheral.<br />
<pre class="code"><br />
#include <sdbus-c++/sdbus-c++.h><br />
#include <iostream><br />
<br />
/**<br />
* Names of D-Bus system services can be looked up with the terminal command<br />
*<br />
* busctl list<br />
*<br />
* We see that the name of the D-Bus system service of the bluetooth daemon is 'org.bluez'.<br />
* The D-Bus object path for a given system service can be queried with the terminal command<br />
*<br />
* busctl tree <service name><br />
*<br />
* For 'org.bluez' let us assume the object path is '/org/bluez/hci0'.<br />
* We can now introspect the interfaces available in the D-Bus object via<br />
*<br />
* busctl introspect org.bluez /org/bluez/hci0<br />
*<br />
* or<br />
*<br />
* gdbus introspect -y -d "org.bluez" -o "/org/bluez/hci0"<br />
* <br />
* We will use to the methods and properties in the published interfaces<br />
* to create a BLE peripheral which advertises a service named 'Test'.<br />
* Additional information on the methods and their parameters can be looked up from<br />
* the BlueZ documentation at https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc<br />
*/<br />
int main(int numargs, char* args[])<br />
{<br />
const char* bluezServiceName = "org.bluez";<br />
const char* bluezObjectPath = "/org/bluez/hci0";<br />
const char* interface_adapter = "org.bluez.Adapter1";<br />
const char* interface_advertisingManager = "org.bluez.LEAdvertisingManager1";<br />
auto bluezProxy = sdbus::createProxy(bluezServiceName, bluezObjectPath);<br />
if (bluezProxy == nullptr)<br />
{<br />
std::cerr << "Error while creating proxy to BlueZ D-Bus service." << std::endl;<br />
return EXIT_FAILURE;<br />
}<br />
bluezProxy->setProperty("Powered").onInterface(interface_adapter).toValue(true);<br />
bluezProxy->setProperty("Alias").onInterface(interface_adapter).toValue("Test");<br />
<br />
// TO BE DONE<br />
<br />
bluezProxy->finishRegistration();<br />
std::cout << "BLE Peripheral Example" << std::endl;<br />
<br />
return EXIT_SUCCESS;<br />
}<br />
<br />
</pre><br />
<br /><br />
<br />
build with<br />
<pre class="terminal"><br />
my_arch=`uname -i`<br />
g++ -o ble-peripheral main.cpp -L/usr/lib/${my_arch}-linux-gnu -lsdbus-c++<br />
</pre><br />
<br /><br />
<br />
= Video4Linux =<br />
Video4Linux is the video pipeline control system in Linux. Start by installing the required packages. On a Debian distribution, type<br />
<pre class="terminal"><br />
sudo apt install libv4l-0 v4l-utils v4l-conf libv4lconvert0<br />
<br />
v4l2-ctl --list-devices<br />
</pre><br />
<br /><br />
<br />
<br />
= C++ programming notes =<br />
== Platform detection ==<br />
To detect whether code is compiled for the Linux platform you can check if ''__linux__'' is defined.<br />
<pre class="code"><br />
#ifdef __linux__<br />
</pre><br />
(here you can find [https://sourceforge.net/p/predef/wiki/OperatingSystems preprocessor definitions for many operating systems])<br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Yocto&diff=3170Yocto2022-12-30T00:14:35Z<p>Kai: /* NFS */</p>
<hr />
<div>= Yocto and OpenEmbedded =<br />
The package management tools used by the [https://yoctoproject.org Yocto project] have been developed by the [https://www.openembedded.org OpenEmbedded] project. The Yocto project basically uses these generic build tools to provide a basic Linux system called ''Poky''. Stable releases of Poky serve as standard platforms for third parties that provide additional features (e.g., hardware support layers).<br />
<br /><br />
<br /><br />
Unless stated otherwise, the information on this page applies to '''version 4.0.5 (Kirkstone)''' of Yocto.<br />
<br /><br />
<br /><br />
<br />
= Prerequisites =<br />
* A Linux system supported by the Yocto project.<br />Assuming that [[Ubuntu]] is used. <br />
* Following package installed:<br />
<pre class=terminal><br />
sudo apt install gcc g++ \<br />
python3-distutils python-is-python3<br />
</pre><br />
<br /><br />
<br />
= Bitbake =<br />
Bitbake is the build tool from the OpenEmbedded project, which parses the project's metadata, resolves dependencies and the ordering of the build steps, runs the builds to create packages, to finally create an image from the packages.<br />
<br /><br />
=== Metadata Types ===<br />
Yocto metadata, which controls how a system image is built, can be categorized at a high level into these four types:<br />
* ''Machine''<br />the targeted hardware platform (e.g. Raspberry Pi 4)<br />
* ''Distro''<br />common characteristic of a family of related images<br />
* ''Recipes''<br />instructions on how to process the source files for a component of the image<br />
* ''Image''<br />recipes that define the contents of generated system images<br />
<br /><br />
=== Layers ===<br />
Layers are purposeful collections of metadata. Yocto layers often Layers often add the provide that for a that can be combined with other layers in order to directories in which <br />
<br /><br />
<br />
<br /> <br />
<br />
= Images =<br />
<br />
Images are recipes that ultimately inherit from '''meta/classes/image.bbclass''' and set the global variable '''IMAGE_INSTALL'''. Most images, however, will inherit from ''meta/classes/core-image.bbclass'' which inherits directly from ''image.bbclass'', provides a mapping from ''IMAGE_FEATURES'' to package groups, and adds the two package groups ''packagegroup-core-boot'' and ''packagegroup-base-extended'' to ''IMAGE_INSTALL''.<br />
<br />
Images are defined in recipe files with the file extension 'bb'. In order to separate them from package recipes, there is a convention to put image recipes into a folder named ''images''. Making use of this, we can list all images defined by all layers via<br />
<pre class="terminal"><br />
cd poky<br />
ls meta*/recipes*/images/*.bb<br />
</pre><br />
<br /><br />
<br />
=== ''IMAGE_FEATURES'' ===<br />
The ''IMAGE_FEATURES'' variable is defined in ''meta/classes/image.bbclass'' with an empty value. It accepts only a predefined set of features (e.g., ''x11'', ''debug-tweaks'', ''dev-pkgs'', ''dbg-pkgs''). This affects how recipes will execute their tasks and which packages will be selected to go into the image. The image recipe ''meta/recipes-core/images/core-image-base.bb'', for example, adds the ''splash'' feature.<br />
<br /><br />
<br />
=== ''IMAGE_INSTALL'' ===<br />
Holds a list of package groups whose packages (from the package feed area) will go into the filesystem image.<br />
<br /><br />
<br />
== Reference images ==<br />
The following reference images are defined in the ''meta'' layer:<br />
{| style="padding: 10px;"<br />
! style="width: 20px" | || || <br />
|-<br />
| || ''core-image-minimal'' || small image that just boots the target device<br />
|-<br />
| || ''core-image-minimal-dev'' || ''core-image-minimal'' with headers and libraries allowing development work<br />
|-<br />
| || style="padding-right: 10px" | ''core-image-minimal-initramfs'' || ''core-image-minimal'' with kernel support for in-RAM filesystem<br />
|-<br />
| || '''core-image-base''' || '''console-only system fully supporting the target hardware'''<br />
|-<br />
| || ''core-image-full-cmdline'' || console-only image that includes many system tools<br />
|-<br />
| || ''core-image-x11'' || image with basic X11 and a terminal<br />
|-<br />
|}<br />
<br />
These image definitions are provided as a starting point for creating project-specific, custom image definitions.<br />
<br /><br />
<br /><br />
<br />
== Creating a Custom Image ==<br />
* In your custom layer, create the ''images'' subdirectory in one of your ''recipes-...' directory.<br />
* In the ''images'' directory, create two image recipe files that inherit from ''core-image'':<br />
<pre class="code"><br />
SUMMARY = "My deployment image"<br />
LICENSE = "MIT"<br />
<br />
inherit core-image<br />
IMAGE_FEATURES += "splash"<br />
</pre><br />
and<br />
<pre class="code"><br />
SUMMARY = "My development image"<br />
<br />
inherit core-image<br />
require my-image.bb<br />
<br />
IMAGE_FEATURES += "ssh-server-dropbear tools-debug debug-tweaks"<br />
<br />
CORE_IMAGE_EXTRA_INSTALL += "i2c-tools "<br />
</pre><br />
where the first image recipe is for deployment and the second is for development. Note that the development version includes the deployment version with the ''require'' statement, and adds to IMAGE_FEATURES and CORE_IMAGE_EXTRA_INSTALL.<br />
<br /><br />
<br />
== Image Filesystem Packaging ==<br />
The system image generated by Bitbake can be packaged in the form of an image file, whose contents can be transferred on a boot medium (SD card or eMMC) such that the primary boot loader of the target device can discover the system and boot it.<br />
<br />
Unless you restrict the type of packaging used for the image file, Yocto will generate multiple rootfs packages, each with a large footprint. To restrict the generated image files to a desired type, edit ''conf/local.conf'' of your project build directory and set the type.<br />
<pre class="code"><br />
#IMAGE_FSTYPES = "tar.gz"<br />
#IMAGE_FSTYPES = "tar.bz2"<br />
IMAGE_FSTYPES = "wic.bz2 wic.bmap"<br />
</pre><br />
The wic ([https://pykickstart.readthedocs.io/en/latest/kickstart-docs.html kickstart]) format with accompanying [https://github.com/intel/bmap-tools bmap] is recommended.<br />
<br /><br />
<br />
== Installing the Rootfs Image ==<br />
Using [https://github.com/intel/bmap-tools bmaptool] we can copy the generated ''wic'' image (with matching bmap file) to a mounted SD card or eMMC storage.<br />
<pre class="terminal"><br />
sudo bmaptool copy tmp/deploy/images/raspberrypi4-64/<wic.bz2 file> <drive><br />
</pre><br />
where ''<wic.bz2 file>'' is the root filesystem image wic.bz2 file, and ''<drive>'' is the drive at which the storage is mounted (for example, ''/dev/sdb'').<br />
<br /><br />
<br /><br />
<br />
= Package Groups =<br />
Package groups are recipes that inherit from '''meta/classes/packagegroup.bbclass''' and set the content of the global variable '''PACKAGES'''. Package groups are defined in recipe files with the file extension 'bb'.<br />
<br /><br />
<br /><br />
Note that the ''packagegroup'' must be inherited before ''PACKAGES is defined.<br />
<pre class="code"><br />
inherit packagegroup<br />
<br />
PACKAGES = '...'<br />
</pre><br />
<br /><br />
<br />
= Useful Image Features =<br />
<br /><br />
<br />
== Distro Features ==<br />
Distro features are system features that affect multiple recipes. '''Large parts of the Poky image may need to be rebaked after making changes to the distro features!'''<br />
<br /><br />
<br />
=== systemd ===<br />
After the kernel is done with its basic booting tasks, it passes control to the initialization manager. To use the ''systemd'' initialization manager instead of ''SysVinit'', make the following entries either in ''conf/distro/distro.conf'' or in your layer's ''conf/layer.conf'', or in ''conf/local.conf'':<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " systemd"<br />
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"<br />
VIRTUAL-RUNTIME_init_manager = "systemd"<br />
VIRTUAL-RUNTIME_initscripts = ""<br />
</pre><br />
<br /><br />
<br />
=== sshd ===<br />
The OpenSSH server is installed via<br />
<pre class="code"><br />
EXTRA_IMAGE_FEATURES:append = " ssh-server-openssh"<br />
</pre><br />
This installs a socket-based SSH server, which runs only when a connection request comes in, thereby reducing memory consumption when no SSH client is connected.<br />
<br /><br />
<br /><br />
To check the status of the SSH server, on the target device, type<br />
<pre class="terminal"><br />
systemctl status sshd.socket<br />
</pre><br />
<br /><br />
<br />
=== NFS ===<br />
In Embedded Linux projects, NFS is often included in development images to enable faster code-deploy turnaround times.<br />
<br /><br />
In the ''conf/local.conf'' file of your Yocto build directory (or ''conf/layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " nfs"<br />
</pre><br />
<br /><br />
On your Debian-based Yocto machine, [[Ubuntu#Setting_up_an_NFS_Server|set up an NFS server]] where the served directory in ''/etc/exports'' must be<br />
<br /><br />
: ${YOCTO_BUILD_DIR}'''/tmp/work/'''${TARGET}'''-poky-linux/'''${IMAGE}'''/1.0-r0/rootfs'''<br />
For example,<br />
: ''build-robofish-lt0/tmp/work/raspberrypi4_64-poky-linux/robofish-lt0-image-dev/1.0-r0/rootfs''<br />
<br /><br />
<br /><br />
<br />
=== [https://vulkan.org Vulkan] and [https://opengl.org OpenGL] ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " vulkan opengl x11 wayland"<br />
</pre><br />
<br /><br />
<br />
=== Bluetooth and NFC ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " bluetooth nfc"<br />
</pre><br />
<br /><br />
<br />
= Recipes =<br />
Recipes are Yocto metadata files that are interpreted by Bitbake and describe how a build task is performed.<br />
<br /><br />
== Patching A Device Tree ==<br />
Follow these steps to patch an existing device tree by creating an ''append recipe'' in a custom layer.<br />
<br /><br />
<br /><br />
In the custom layer, create the directory for a linux kernel append recipe.<br />
<pre class="terminal"><br />
mkdir -p ${LAYER_DIR}/recipes-kernel/linux/files<br />
</pre><br />
where it is assumed that ''${LAYER_DIR}'' contains the path to the root directory of the custom Yocto layer. <br />
<br /><br />
<br /><br />
Copy the kernel device tree file from your Yocto project build directory to the ''files'' directory of your new recipe. For a Raspberry Pi Compute Module 4, for example, type<br />
<pre class="terminal"><br />
cp ${YOCTO_BUILD_DIR}/tmp/work-shared/${MACHINE}/kernel-source/arch/arm/boot/dts/some.dts ${LAYER_DIR}/recipes-kernel/linux/files/<br />
</pre><br />
where ''${YOCTO_BUILD_DIR}'' is the path to the Yocto project build directory, and ''${MACHINE}'' is the chosen target platform (e.g. "raspberrypi4-64").<br />
<br /><br />
<div class="sidenote"><br />
If the ''tmp/work-shared'' directory does not exists anymore, you can recreate it by typing<br />
<pre class="terminal"><br />
bitbake -c menuconfig virtual/kernel<br />
</pre><br />
and exiting the kernel configuration menu without making changes.<br />
</div><br />
<br /><br />
Make the necessary changes to the copied device tree file. Then create a git patch file using ''git diff'' as shown below<br />
<pre class="terminal"><br />
git diff --no-index {DTS_DIR}/some.dts some.dts > 0001-my_modifications-dts.patch<br />
</pre><br />
<br /><br />
Edit the generated patch file to fix the file paths at the top. The paths must be relative to the kernel sources directory:<br />
: ''${YOCTO_BUILD_DIR}'''''/tmp/work-shared/'''''${MACHINE}'''''/kernel-source'''<br />
The header should look like this:<br />
<pre class="code"><br />
diff --git a/arch/arm/boot/dts/some.dts b/some.dts<br />
index 6e99da1..4567735 100644<br />
--- a/arch/arm/boot/dts/some.dts<br />
+++ b/arch/arm/boot/dts/some.dts<br />
</pre><br />
where "--- a" and "+++ b" are followed by the same relative file path.<br />
<br />
<br /><br />
Create and edit the append recipe<br />
<pre class="terminal"><br />
vim ${LAYER_DIR}/recipes-kernel/linux/${KERNEL_NAME}_%.bbappend<br />
</pre><br />
where ''${KERNEL_NAME}'' is the kernel name, which usually starts with "linux-" (for example, ''linux-raspberrypi''), and ''_%'' denotes all versions of the kernel package.<br />
<br /><br />
<div class="sidenote"><br />
If in doubt, use the ''oe-pkgdata-util'' tool from within your build directory to find out the kernel name.<br />
<pre class="terminal"><br />
oe-pkgdata-util lookup-recipe kernel<br />
</pre><br />
</div><br />
The contents of the recipe file should be similar to this:<br />
<pre class="code"><br />
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"<br />
SRC_URI += "file://0001-my_modifications-dts.patch"<br />
SRC_URI[md5sum] = "e2eba462f773f46fe6930a08323f5e1f"<br />
SRC_URI[sha256sum] = "2ef2b2e9b33b5d2af0425940387bc6c1c2c305e6a685defbdc7cf3f584bc1edc"<br />
</pre><br />
where ''0001-my_modifications-dts.patch'' needs to be replaced with the actual patch file name.<br />
<br />
== Creating a New Device Tree ==<br />
Creating a new device tree requires an input dts file which completely defines the hardware configuration. The ''KERNEL_DEVICETREE'' variable is used to make the Linux kernel select the new device tree during booting.<br />
<pre class="code"><br />
inherit kernel-devicetree<br />
<br />
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"<br />
<br />
# Make custom kernel with PRU enabled<br />
SRC_URI += " \<br />
file://some.dts \<br />
file://0001-some.patch \<br />
"<br />
<br />
KERNEL_DEVICETREE = "some.dtb"<br />
</pre><br />
<br /><br />
<br />
= Accessing the OpenEmbedded package collection =<br />
The OpenEmbedded project provides recipes for many useful programs that are not included with Yocto, like tmux, VLC, Gnome, various multimedia codecs, more filesystems, gRPC and much more.<br />
<br /><br />
To access the recipes for those software packages, clone the OpenEmbedded layers repository into your third-party layers directory: <br />
<pre class="terminal"><br />
git clone git://git.openembedded.org/meta-openembedded<br />
</pre><br />
<br /><br />
<br />
= devtool =<br />
<br />
Use '''devtool''' to make changes to an existing recipe and automatically generate an append recipe from those changes.<br />
<br /><br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Yocto&diff=3169Yocto2022-12-26T12:39:58Z<p>Kai: Removes duplicate information about systemd.</p>
<hr />
<div>= Yocto and OpenEmbedded =<br />
The package management tools used by the [https://yoctoproject.org Yocto project] have been developed by the [https://www.openembedded.org OpenEmbedded] project. The Yocto project basically uses these generic build tools to provide a basic Linux system called ''Poky''. Stable releases of Poky serve as standard platforms for third parties that provide additional features (e.g., hardware support layers).<br />
<br /><br />
<br /><br />
Unless stated otherwise, the information on this page applies to '''version 4.0.5 (Kirkstone)''' of Yocto.<br />
<br /><br />
<br /><br />
<br />
= Prerequisites =<br />
* A Linux system supported by the Yocto project.<br />Assuming that [[Ubuntu]] is used. <br />
* Following package installed:<br />
<pre class=terminal><br />
sudo apt install gcc g++ \<br />
python3-distutils python-is-python3<br />
</pre><br />
<br /><br />
<br />
= Bitbake =<br />
Bitbake is the build tool from the OpenEmbedded project, which parses the project's metadata, resolves dependencies and the ordering of the build steps, runs the builds to create packages, to finally create an image from the packages.<br />
<br /><br />
=== Metadata Types ===<br />
Yocto metadata, which controls how a system image is built, can be categorized at a high level into these four types:<br />
* ''Machine''<br />the targeted hardware platform (e.g. Raspberry Pi 4)<br />
* ''Distro''<br />common characteristic of a family of related images<br />
* ''Recipes''<br />instructions on how to process the source files for a component of the image<br />
* ''Image''<br />recipes that define the contents of generated system images<br />
<br /><br />
=== Layers ===<br />
Layers are purposeful collections of metadata. Yocto layers often Layers often add the provide that for a that can be combined with other layers in order to directories in which <br />
<br /><br />
<br />
<br /> <br />
<br />
= Images =<br />
<br />
Images are recipes that ultimately inherit from '''meta/classes/image.bbclass''' and set the global variable '''IMAGE_INSTALL'''. Most images, however, will inherit from ''meta/classes/core-image.bbclass'' which inherits directly from ''image.bbclass'', provides a mapping from ''IMAGE_FEATURES'' to package groups, and adds the two package groups ''packagegroup-core-boot'' and ''packagegroup-base-extended'' to ''IMAGE_INSTALL''.<br />
<br />
Images are defined in recipe files with the file extension 'bb'. In order to separate them from package recipes, there is a convention to put image recipes into a folder named ''images''. Making use of this, we can list all images defined by all layers via<br />
<pre class="terminal"><br />
cd poky<br />
ls meta*/recipes*/images/*.bb<br />
</pre><br />
<br /><br />
<br />
=== ''IMAGE_FEATURES'' ===<br />
The ''IMAGE_FEATURES'' variable is defined in ''meta/classes/image.bbclass'' with an empty value. It accepts only a predefined set of features (e.g., ''x11'', ''debug-tweaks'', ''dev-pkgs'', ''dbg-pkgs''). This affects how recipes will execute their tasks and which packages will be selected to go into the image. The image recipe ''meta/recipes-core/images/core-image-base.bb'', for example, adds the ''splash'' feature.<br />
<br /><br />
<br />
=== ''IMAGE_INSTALL'' ===<br />
Holds a list of package groups whose packages (from the package feed area) will go into the filesystem image.<br />
<br /><br />
<br />
== Reference images ==<br />
The following reference images are defined in the ''meta'' layer:<br />
{| style="padding: 10px;"<br />
! style="width: 20px" | || || <br />
|-<br />
| || ''core-image-minimal'' || small image that just boots the target device<br />
|-<br />
| || ''core-image-minimal-dev'' || ''core-image-minimal'' with headers and libraries allowing development work<br />
|-<br />
| || style="padding-right: 10px" | ''core-image-minimal-initramfs'' || ''core-image-minimal'' with kernel support for in-RAM filesystem<br />
|-<br />
| || '''core-image-base''' || '''console-only system fully supporting the target hardware'''<br />
|-<br />
| || ''core-image-full-cmdline'' || console-only image that includes many system tools<br />
|-<br />
| || ''core-image-x11'' || image with basic X11 and a terminal<br />
|-<br />
|}<br />
<br />
These image definitions are provided as a starting point for creating project-specific, custom image definitions.<br />
<br /><br />
<br /><br />
<br />
== Creating a Custom Image ==<br />
* In your custom layer, create the ''images'' subdirectory in one of your ''recipes-...' directory.<br />
* In the ''images'' directory, create two image recipe files that inherit from ''core-image'':<br />
<pre class="code"><br />
SUMMARY = "My deployment image"<br />
LICENSE = "MIT"<br />
<br />
inherit core-image<br />
IMAGE_FEATURES += "splash"<br />
</pre><br />
and<br />
<pre class="code"><br />
SUMMARY = "My development image"<br />
<br />
inherit core-image<br />
require my-image.bb<br />
<br />
IMAGE_FEATURES += "ssh-server-dropbear tools-debug debug-tweaks"<br />
<br />
CORE_IMAGE_EXTRA_INSTALL += "i2c-tools "<br />
</pre><br />
where the first image recipe is for deployment and the second is for development. Note that the development version includes the deployment version with the ''require'' statement, and adds to IMAGE_FEATURES and CORE_IMAGE_EXTRA_INSTALL.<br />
<br /><br />
<br />
== Image Filesystem Packaging ==<br />
The system image generated by Bitbake can be packaged in the form of an image file, whose contents can be transferred on a boot medium (SD card or eMMC) such that the primary boot loader of the target device can discover the system and boot it.<br />
<br />
Unless you restrict the type of packaging used for the image file, Yocto will generate multiple rootfs packages, each with a large footprint. To restrict the generated image files to a desired type, edit ''conf/local.conf'' of your project build directory and set the type.<br />
<pre class="code"><br />
#IMAGE_FSTYPES = "tar.gz"<br />
#IMAGE_FSTYPES = "tar.bz2"<br />
IMAGE_FSTYPES = "wic.bz2 wic.bmap"<br />
</pre><br />
The wic ([https://pykickstart.readthedocs.io/en/latest/kickstart-docs.html kickstart]) format with accompanying [https://github.com/intel/bmap-tools bmap] is recommended.<br />
<br /><br />
<br />
== Installing the Rootfs Image ==<br />
Using [https://github.com/intel/bmap-tools bmaptool] we can copy the generated ''wic'' image (with matching bmap file) to a mounted SD card or eMMC storage.<br />
<pre class="terminal"><br />
sudo bmaptool copy tmp/deploy/images/raspberrypi4-64/<wic.bz2 file> <drive><br />
</pre><br />
where ''<wic.bz2 file>'' is the root filesystem image wic.bz2 file, and ''<drive>'' is the drive at which the storage is mounted (for example, ''/dev/sdb'').<br />
<br /><br />
<br /><br />
<br />
= Package Groups =<br />
Package groups are recipes that inherit from '''meta/classes/packagegroup.bbclass''' and set the content of the global variable '''PACKAGES'''. Package groups are defined in recipe files with the file extension 'bb'.<br />
<br /><br />
<br /><br />
Note that the ''packagegroup'' must be inherited before ''PACKAGES is defined.<br />
<pre class="code"><br />
inherit packagegroup<br />
<br />
PACKAGES = '...'<br />
</pre><br />
<br /><br />
<br />
= Useful Image Features =<br />
<br /><br />
<br />
== Distro Features ==<br />
Distro features are system features that affect multiple recipes. '''Large parts of the Poky image may need to be rebaked after making changes to the distro features!'''<br />
<br /><br />
<br />
=== systemd ===<br />
After the kernel is done with its basic booting tasks, it passes control to the initialization manager. To use the ''systemd'' initialization manager instead of ''SysVinit'', make the following entries either in ''conf/distro/distro.conf'' or in your layer's ''conf/layer.conf'', or in ''conf/local.conf'':<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " systemd"<br />
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"<br />
VIRTUAL-RUNTIME_init_manager = "systemd"<br />
VIRTUAL-RUNTIME_initscripts = ""<br />
</pre><br />
<br /><br />
<br />
=== sshd ===<br />
The OpenSSH server is installed via<br />
<pre class="code"><br />
EXTRA_IMAGE_FEATURES:append = " ssh-server-openssh"<br />
</pre><br />
This installs a socket-based SSH server, which runs only when a connection request comes in, thereby reducing memory consumption when no SSH client is connected.<br />
<br /><br />
<br /><br />
To check the status of the SSH server, on the target device, type<br />
<pre class="terminal"><br />
systemctl status sshd.socket<br />
</pre><br />
<br /><br />
<br />
=== NFS ===<br />
In Embedded Linux projects, NFS is often included in development images to enable faster code-deploy turnaround times.<br />
<br /><br />
In the ''conf/local.conf'' file of your Yocto build directory (or ''conf/layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " nfs"<br />
</pre><br />
<br /><br />
On your Debian-based Yocto machine, [[Ubuntu#Setting_up_an_NFS_Server|set up an NFS server]].<br />
<br /><br />
<br /><br />
In Yocto, use the directory<br />
<br /><br />
: '''{YOCTO_BUILD_DIR}/tmp/work/{TARGET}-poky-linux/{IMAGE}/1.0-r0/rootfs'''<br />
as the root directory provided by the NFS server. For example,<br />
: ''build-robofish-core/tmp/work/raspberrypi4_64-poky-linux/robofish-core-image-dev/1.0-r0/rootfs''<br />
<br /><br />
<br /><br />
<br />
=== [https://vulkan.org Vulkan] and [https://opengl.org OpenGL] ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " vulkan opengl x11 wayland"<br />
</pre><br />
<br /><br />
<br />
=== Bluetooth and NFC ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " bluetooth nfc"<br />
</pre><br />
<br /><br />
<br />
= Recipes =<br />
Recipes are Yocto metadata files that are interpreted by Bitbake and describe how a build task is performed.<br />
<br /><br />
== Patching A Device Tree ==<br />
Follow these steps to patch an existing device tree by creating an ''append recipe'' in a custom layer.<br />
<br /><br />
<br /><br />
In the custom layer, create the directory for a linux kernel append recipe.<br />
<pre class="terminal"><br />
mkdir -p ${LAYER_DIR}/recipes-kernel/linux/files<br />
</pre><br />
where it is assumed that ''${LAYER_DIR}'' contains the path to the root directory of the custom Yocto layer. <br />
<br /><br />
<br /><br />
Copy the kernel device tree file from your Yocto project build directory to the ''files'' directory of your new recipe. For a Raspberry Pi Compute Module 4, for example, type<br />
<pre class="terminal"><br />
cp ${YOCTO_BUILD_DIR}/tmp/work-shared/${MACHINE}/kernel-source/arch/arm/boot/dts/some.dts ${LAYER_DIR}/recipes-kernel/linux/files/<br />
</pre><br />
where ''${YOCTO_BUILD_DIR}'' is the path to the Yocto project build directory, and ''${MACHINE}'' is the chosen target platform (e.g. "raspberrypi4-64").<br />
<br /><br />
<div class="sidenote"><br />
If the ''tmp/work-shared'' directory does not exists anymore, you can recreate it by typing<br />
<pre class="terminal"><br />
bitbake -c menuconfig virtual/kernel<br />
</pre><br />
and exiting the kernel configuration menu without making changes.<br />
</div><br />
<br /><br />
Make the necessary changes to the copied device tree file. Then create a git patch file using ''git diff'' as shown below<br />
<pre class="terminal"><br />
git diff --no-index {DTS_DIR}/some.dts some.dts > 0001-my_modifications-dts.patch<br />
</pre><br />
<br /><br />
Edit the generated patch file to fix the file paths at the top. The paths must be relative to the kernel sources directory:<br />
: ''${YOCTO_BUILD_DIR}'''''/tmp/work-shared/'''''${MACHINE}'''''/kernel-source'''<br />
The header should look like this:<br />
<pre class="code"><br />
diff --git a/arch/arm/boot/dts/some.dts b/some.dts<br />
index 6e99da1..4567735 100644<br />
--- a/arch/arm/boot/dts/some.dts<br />
+++ b/arch/arm/boot/dts/some.dts<br />
</pre><br />
where "--- a" and "+++ b" are followed by the same relative file path.<br />
<br />
<br /><br />
Create and edit the append recipe<br />
<pre class="terminal"><br />
vim ${LAYER_DIR}/recipes-kernel/linux/${KERNEL_NAME}_%.bbappend<br />
</pre><br />
where ''${KERNEL_NAME}'' is the kernel name, which usually starts with "linux-" (for example, ''linux-raspberrypi''), and ''_%'' denotes all versions of the kernel package.<br />
<br /><br />
<div class="sidenote"><br />
If in doubt, use the ''oe-pkgdata-util'' tool from within your build directory to find out the kernel name.<br />
<pre class="terminal"><br />
oe-pkgdata-util lookup-recipe kernel<br />
</pre><br />
</div><br />
The contents of the recipe file should be similar to this:<br />
<pre class="code"><br />
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"<br />
SRC_URI += "file://0001-my_modifications-dts.patch"<br />
SRC_URI[md5sum] = "e2eba462f773f46fe6930a08323f5e1f"<br />
SRC_URI[sha256sum] = "2ef2b2e9b33b5d2af0425940387bc6c1c2c305e6a685defbdc7cf3f584bc1edc"<br />
</pre><br />
where ''0001-my_modifications-dts.patch'' needs to be replaced with the actual patch file name.<br />
<br />
== Creating a New Device Tree ==<br />
Creating a new device tree requires an input dts file which completely defines the hardware configuration. The ''KERNEL_DEVICETREE'' variable is used to make the Linux kernel select the new device tree during booting.<br />
<pre class="code"><br />
inherit kernel-devicetree<br />
<br />
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"<br />
<br />
# Make custom kernel with PRU enabled<br />
SRC_URI += " \<br />
file://some.dts \<br />
file://0001-some.patch \<br />
"<br />
<br />
KERNEL_DEVICETREE = "some.dtb"<br />
</pre><br />
<br /><br />
<br />
= Accessing the OpenEmbedded package collection =<br />
The OpenEmbedded project provides recipes for many useful programs that are not included with Yocto, like tmux, VLC, Gnome, various multimedia codecs, more filesystems, gRPC and much more.<br />
<br /><br />
To access the recipes for those software packages, clone the OpenEmbedded layers repository into your third-party layers directory: <br />
<pre class="terminal"><br />
git clone git://git.openembedded.org/meta-openembedded<br />
</pre><br />
<br /><br />
<br />
= devtool =<br />
<br />
Use '''devtool''' to make changes to an existing recipe and automatically generate an append recipe from those changes.<br />
<br /><br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Yocto&diff=3168Yocto2022-12-26T12:28:59Z<p>Kai: /* Yocto and OpenEmbedded */</p>
<hr />
<div>= Yocto and OpenEmbedded =<br />
The package management tools used by the [https://yoctoproject.org Yocto project] have been developed by the [https://www.openembedded.org OpenEmbedded] project. The Yocto project basically uses these generic build tools to provide a basic Linux system called ''Poky''. Stable releases of Poky serve as standard platforms for third parties that provide additional features (e.g., hardware support layers).<br />
<br /><br />
<br /><br />
Unless stated otherwise, the information on this page applies to '''version 4.0.5 (Kirkstone)''' of Yocto.<br />
<br /><br />
<br /><br />
<br />
= Prerequisites =<br />
* A Linux system supported by the Yocto project.<br />Assuming that [[Ubuntu]] is used. <br />
* Following package installed:<br />
<pre class=terminal><br />
sudo apt install gcc g++ \<br />
python3-distutils python-is-python3<br />
</pre><br />
<br /><br />
<br />
= Bitbake =<br />
Bitbake is the build tool from the OpenEmbedded project, which parses the project's metadata, resolves dependencies and the ordering of the build steps, runs the builds to create packages, to finally create an image from the packages.<br />
<br /><br />
=== Metadata Types ===<br />
Yocto metadata, which controls how a system image is built, can be categorized at a high level into these four types:<br />
* ''Machine''<br />the targeted hardware platform (e.g. Raspberry Pi 4)<br />
* ''Distro''<br />common characteristic of a family of related images<br />
* ''Recipes''<br />instructions on how to process the source files for a component of the image<br />
* ''Image''<br />recipes that define the contents of generated system images<br />
<br /><br />
=== Layers ===<br />
Layers are purposeful collections of metadata. Yocto layers often Layers often add the provide that for a that can be combined with other layers in order to directories in which <br />
<br /><br />
<br />
<br /> <br />
<br />
= Images =<br />
<br />
Images are recipes that ultimately inherit from '''meta/classes/image.bbclass''' and set the global variable '''IMAGE_INSTALL'''. Most images, however, will inherit from ''meta/classes/core-image.bbclass'' which inherits directly from ''image.bbclass'', provides a mapping from ''IMAGE_FEATURES'' to package groups, and adds the two package groups ''packagegroup-core-boot'' and ''packagegroup-base-extended'' to ''IMAGE_INSTALL''.<br />
<br />
Images are defined in recipe files with the file extension 'bb'. In order to separate them from package recipes, there is a convention to put image recipes into a folder named ''images''. Making use of this, we can list all images defined by all layers via<br />
<pre class="terminal"><br />
cd poky<br />
ls meta*/recipes*/images/*.bb<br />
</pre><br />
<br /><br />
<br />
=== ''IMAGE_FEATURES'' ===<br />
The ''IMAGE_FEATURES'' variable is defined in ''meta/classes/image.bbclass'' with an empty value. It accepts only a predefined set of features (e.g., ''x11'', ''debug-tweaks'', ''dev-pkgs'', ''dbg-pkgs''). This affects how recipes will execute their tasks and which packages will be selected to go into the image. The image recipe ''meta/recipes-core/images/core-image-base.bb'', for example, adds the ''splash'' feature.<br />
<br /><br />
<br />
=== ''IMAGE_INSTALL'' ===<br />
Holds a list of package groups whose packages (from the package feed area) will go into the filesystem image.<br />
<br /><br />
<br />
== Reference images ==<br />
The following reference images are defined in the ''meta'' layer:<br />
{| style="padding: 10px;"<br />
! style="width: 20px" | || || <br />
|-<br />
| || ''core-image-minimal'' || small image that just boots the target device<br />
|-<br />
| || ''core-image-minimal-dev'' || ''core-image-minimal'' with headers and libraries allowing development work<br />
|-<br />
| || style="padding-right: 10px" | ''core-image-minimal-initramfs'' || ''core-image-minimal'' with kernel support for in-RAM filesystem<br />
|-<br />
| || '''core-image-base''' || '''console-only system fully supporting the target hardware'''<br />
|-<br />
| || ''core-image-full-cmdline'' || console-only image that includes many system tools<br />
|-<br />
| || ''core-image-x11'' || image with basic X11 and a terminal<br />
|-<br />
|}<br />
<br />
These image definitions are provided as a starting point for creating project-specific, custom image definitions.<br />
<br /><br />
<br /><br />
<br />
== Creating a Custom Image ==<br />
* In your custom layer, create the ''images'' subdirectory in one of your ''recipes-...' directory.<br />
* In the ''images'' directory, create two image recipe files that inherit from ''core-image'':<br />
<pre class="code"><br />
SUMMARY = "My deployment image"<br />
LICENSE = "MIT"<br />
<br />
inherit core-image<br />
IMAGE_FEATURES += "splash"<br />
</pre><br />
and<br />
<pre class="code"><br />
SUMMARY = "My development image"<br />
<br />
inherit core-image<br />
require my-image.bb<br />
<br />
IMAGE_FEATURES += "ssh-server-dropbear tools-debug debug-tweaks"<br />
<br />
CORE_IMAGE_EXTRA_INSTALL += "i2c-tools "<br />
</pre><br />
where the first image recipe is for deployment and the second is for development. Note that the development version includes the deployment version with the ''require'' statement, and adds to IMAGE_FEATURES and CORE_IMAGE_EXTRA_INSTALL.<br />
<br /><br />
<br />
== Image Filesystem Packaging ==<br />
The system image generated by Bitbake can be packaged in the form of an image file, whose contents can be transferred on a boot medium (SD card or eMMC) such that the primary boot loader of the target device can discover the system and boot it.<br />
<br />
Unless you restrict the type of packaging used for the image file, Yocto will generate multiple rootfs packages, each with a large footprint. To restrict the generated image files to a desired type, edit ''conf/local.conf'' of your project build directory and set the type.<br />
<pre class="code"><br />
#IMAGE_FSTYPES = "tar.gz"<br />
#IMAGE_FSTYPES = "tar.bz2"<br />
IMAGE_FSTYPES = "wic.bz2 wic.bmap"<br />
</pre><br />
The wic ([https://pykickstart.readthedocs.io/en/latest/kickstart-docs.html kickstart]) format with accompanying [https://github.com/intel/bmap-tools bmap] is recommended.<br />
<br /><br />
<br />
== Installing the Rootfs Image ==<br />
Using [https://github.com/intel/bmap-tools bmaptool] we can copy the generated ''wic'' image (with matching bmap file) to a mounted SD card or eMMC storage.<br />
<pre class="terminal"><br />
sudo bmaptool copy tmp/deploy/images/raspberrypi4-64/<wic.bz2 file> <drive><br />
</pre><br />
where ''<wic.bz2 file>'' is the root filesystem image wic.bz2 file, and ''<drive>'' is the drive at which the storage is mounted (for example, ''/dev/sdb'').<br />
<br /><br />
<br /><br />
<br />
= Package Groups =<br />
Package groups are recipes that inherit from '''meta/classes/packagegroup.bbclass''' and set the content of the global variable '''PACKAGES'''. Package groups are defined in recipe files with the file extension 'bb'.<br />
<br /><br />
<br /><br />
Note that the ''packagegroup'' must be inherited before ''PACKAGES is defined.<br />
<pre class="code"><br />
inherit packagegroup<br />
<br />
PACKAGES = '...'<br />
</pre><br />
<br /><br />
<br />
= Useful Image Features =<br />
<br /><br />
<br />
== Distro Features ==<br />
Distro features are system features that affect multiple recipes. '''Large parts of the Poky image may need to be rebaked after making changes to the distro features!'''<br />
<br /><br />
<br />
=== systemd ===<br />
In the ''conf/local.conf'' file of your project build directory (or ''layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " systemd"<br />
</pre><br />
<br /><br />
<br />
=== sshd ===<br />
The OpenSSH server is installed via<br />
<pre class="code"><br />
EXTRA_IMAGE_FEATURES:append = " ssh-server-openssh"<br />
</pre><br />
This installs a socket-based SSH server, which runs only when a connection request comes in, thereby reducing memory consumption when no SSH client is connected.<br />
<br /><br />
<br /><br />
To check the status of the SSH server, on the target device, type<br />
<pre class="terminal"><br />
systemctl status sshd.socket<br />
</pre><br />
<br /><br />
<br />
=== NFS ===<br />
In Embedded Linux projects, NFS is often included in development images to enable faster code-deploy turnaround times.<br />
<br /><br />
In the ''conf/local.conf'' file of your Yocto build directory (or ''conf/layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " nfs"<br />
</pre><br />
<br /><br />
On your Debian-based Yocto machine, [[Ubuntu#Setting_up_an_NFS_Server|set up an SSH server]].<br />
<br /><br />
<br /><br />
In Yocto, use the directory<br />
<br /><br />
: '''{YOCTO_BUILD_DIR}/tmp/work/{TARGET}-poky-linux/{IMAGE}/1.0-r0/rootfs'''<br />
as the root directory provided by the NFS server. For example,<br />
: ''build-robofish-core/tmp/work/raspberrypi4_64-poky-linux/robofish-core-image-dev/1.0-r0/rootfs''<br />
<br /><br />
<br /><br />
<br />
=== [https://vulkan.org Vulkan] and [https://opengl.org OpenGL] ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " vulkan opengl x11 wayland"<br />
</pre><br />
<br /><br />
<br />
=== Bluetooth and NFC ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " bluetooth nfc"<br />
</pre><br />
<br /><br />
<br />
= Recipes =<br />
Recipes are Yocto metadata files that are interpreted by Bitbake and describe how a build task is performed.<br />
<br /><br />
== Patching A Device Tree ==<br />
Follow these steps to patch an existing device tree by creating an ''append recipe'' in a custom layer.<br />
<br /><br />
<br /><br />
In the custom layer, create the directory for a linux kernel append recipe.<br />
<pre class="terminal"><br />
mkdir -p ${LAYER_DIR}/recipes-kernel/linux/files<br />
</pre><br />
where it is assumed that ''${LAYER_DIR}'' contains the path to the root directory of the custom Yocto layer. <br />
<br /><br />
<br /><br />
Copy the kernel device tree file from your Yocto project build directory to the ''files'' directory of your new recipe. For a Raspberry Pi Compute Module 4, for example, type<br />
<pre class="terminal"><br />
cp ${YOCTO_BUILD_DIR}/tmp/work-shared/${MACHINE}/kernel-source/arch/arm/boot/dts/some.dts ${LAYER_DIR}/recipes-kernel/linux/files/<br />
</pre><br />
where ''${YOCTO_BUILD_DIR}'' is the path to the Yocto project build directory, and ''${MACHINE}'' is the chosen target platform (e.g. "raspberrypi4-64").<br />
<br /><br />
<div class="sidenote"><br />
If the ''tmp/work-shared'' directory does not exists anymore, you can recreate it by typing<br />
<pre class="terminal"><br />
bitbake -c menuconfig virtual/kernel<br />
</pre><br />
and exiting the kernel configuration menu without making changes.<br />
</div><br />
<br /><br />
Make the necessary changes to the copied device tree file. Then create a git patch file using ''git diff'' as shown below<br />
<pre class="terminal"><br />
git diff --no-index {DTS_DIR}/some.dts some.dts > 0001-my_modifications-dts.patch<br />
</pre><br />
<br /><br />
Edit the generated patch file to fix the file paths at the top. The paths must be relative to the kernel sources directory:<br />
: ''${YOCTO_BUILD_DIR}'''''/tmp/work-shared/'''''${MACHINE}'''''/kernel-source'''<br />
The header should look like this:<br />
<pre class="code"><br />
diff --git a/arch/arm/boot/dts/some.dts b/some.dts<br />
index 6e99da1..4567735 100644<br />
--- a/arch/arm/boot/dts/some.dts<br />
+++ b/arch/arm/boot/dts/some.dts<br />
</pre><br />
where "--- a" and "+++ b" are followed by the same relative file path.<br />
<br />
<br /><br />
Create and edit the append recipe<br />
<pre class="terminal"><br />
vim ${LAYER_DIR}/recipes-kernel/linux/${KERNEL_NAME}_%.bbappend<br />
</pre><br />
where ''${KERNEL_NAME}'' is the kernel name, which usually starts with "linux-" (for example, ''linux-raspberrypi''), and ''_%'' denotes all versions of the kernel package.<br />
<br /><br />
<div class="sidenote"><br />
If in doubt, use the ''oe-pkgdata-util'' tool from within your build directory to find out the kernel name.<br />
<pre class="terminal"><br />
oe-pkgdata-util lookup-recipe kernel<br />
</pre><br />
</div><br />
The contents of the recipe file should be similar to this:<br />
<pre class="code"><br />
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"<br />
SRC_URI += "file://0001-my_modifications-dts.patch"<br />
SRC_URI[md5sum] = "e2eba462f773f46fe6930a08323f5e1f"<br />
SRC_URI[sha256sum] = "2ef2b2e9b33b5d2af0425940387bc6c1c2c305e6a685defbdc7cf3f584bc1edc"<br />
</pre><br />
where ''0001-my_modifications-dts.patch'' needs to be replaced with the actual patch file name.<br />
<br />
== Creating a New Device Tree ==<br />
Creating a new device tree requires an input dts file which completely defines the hardware configuration. The ''KERNEL_DEVICETREE'' variable is used to make the Linux kernel select the new device tree during booting.<br />
<pre class="code"><br />
inherit kernel-devicetree<br />
<br />
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"<br />
<br />
# Make custom kernel with PRU enabled<br />
SRC_URI += " \<br />
file://some.dts \<br />
file://0001-some.patch \<br />
"<br />
<br />
KERNEL_DEVICETREE = "some.dtb"<br />
</pre><br />
<br /><br />
<br />
= Accessing the OpenEmbedded package collection =<br />
The OpenEmbedded project provides recipes for many useful programs that are not included with Yocto, like tmux, VLC, Gnome, various multimedia codecs, more filesystems, gRPC and much more.<br />
<br /><br />
To access the recipes for those software packages, clone the OpenEmbedded layers repository into your third-party layers directory: <br />
<pre class="terminal"><br />
git clone git://git.openembedded.org/meta-openembedded<br />
</pre><br />
<br /><br />
<br />
= devtool =<br />
<br />
Use '''devtool''' to make changes to an existing recipe and automatically generate an append recipe from those changes.<br />
<br /><br />
<br /><br />
<br />
== Initialization Manager ==<br />
After the kernel is done with its basic booting tasks, it passes control to the initialization manager. To use the ''systemd'' initialization manager (used by the Linux distributions Debian and Ubuntu) instead of ''SysVinit'', make the following entries in ''${TOPDIR}/conf/distro/distro.conf''<br />
<pre class="code"><br />
DISTRO_FEATURES_append = " systemd"<br />
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"<br />
VIRTUAL-RUNTIME_init_manager = "systemd"<br />
VIRTUAL-RUNTIME_initscripts = ""<br />
</pre><br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Yocto&diff=3167Yocto2022-12-26T12:24:32Z<p>Kai: Adds section about installing the OpenSSH server.</p>
<hr />
<div>= Yocto and OpenEmbedded =<br />
The collection of software tools used by the Yocto project have been developed by the [https://www.openembedded.org OpenEmbedded] project. The Yocto project basically uses these generic build tools to provide a basic Linux system called ''Poky''. Stable releases of Poky serve as standard platforms for third parties that provide additional features (e.g., hardware support layers).<br />
<br /><br />
<br /><br />
<br />
= Prerequisites =<br />
* A Linux system supported by the Yocto project.<br />Assuming that [[Ubuntu]] is used. <br />
* Following package installed:<br />
<pre class=terminal><br />
sudo apt install gcc g++ \<br />
python3-distutils python-is-python3<br />
</pre><br />
<br /><br />
<br />
= Bitbake =<br />
Bitbake is the build tool from the OpenEmbedded project, which parses the project's metadata, resolves dependencies and the ordering of the build steps, runs the builds to create packages, to finally create an image from the packages.<br />
<br /><br />
=== Metadata Types ===<br />
Yocto metadata, which controls how a system image is built, can be categorized at a high level into these four types:<br />
* ''Machine''<br />the targeted hardware platform (e.g. Raspberry Pi 4)<br />
* ''Distro''<br />common characteristic of a family of related images<br />
* ''Recipes''<br />instructions on how to process the source files for a component of the image<br />
* ''Image''<br />recipes that define the contents of generated system images<br />
<br /><br />
=== Layers ===<br />
Layers are purposeful collections of metadata. Yocto layers often Layers often add the provide that for a that can be combined with other layers in order to directories in which <br />
<br /><br />
<br />
<br /> <br />
<br />
= Images =<br />
<br />
Images are recipes that ultimately inherit from '''meta/classes/image.bbclass''' and set the global variable '''IMAGE_INSTALL'''. Most images, however, will inherit from ''meta/classes/core-image.bbclass'' which inherits directly from ''image.bbclass'', provides a mapping from ''IMAGE_FEATURES'' to package groups, and adds the two package groups ''packagegroup-core-boot'' and ''packagegroup-base-extended'' to ''IMAGE_INSTALL''.<br />
<br />
Images are defined in recipe files with the file extension 'bb'. In order to separate them from package recipes, there is a convention to put image recipes into a folder named ''images''. Making use of this, we can list all images defined by all layers via<br />
<pre class="terminal"><br />
cd poky<br />
ls meta*/recipes*/images/*.bb<br />
</pre><br />
<br /><br />
<br />
=== ''IMAGE_FEATURES'' ===<br />
The ''IMAGE_FEATURES'' variable is defined in ''meta/classes/image.bbclass'' with an empty value. It accepts only a predefined set of features (e.g., ''x11'', ''debug-tweaks'', ''dev-pkgs'', ''dbg-pkgs''). This affects how recipes will execute their tasks and which packages will be selected to go into the image. The image recipe ''meta/recipes-core/images/core-image-base.bb'', for example, adds the ''splash'' feature.<br />
<br /><br />
<br />
=== ''IMAGE_INSTALL'' ===<br />
Holds a list of package groups whose packages (from the package feed area) will go into the filesystem image.<br />
<br /><br />
<br />
== Reference images ==<br />
The following reference images are defined in the ''meta'' layer:<br />
{| style="padding: 10px;"<br />
! style="width: 20px" | || || <br />
|-<br />
| || ''core-image-minimal'' || small image that just boots the target device<br />
|-<br />
| || ''core-image-minimal-dev'' || ''core-image-minimal'' with headers and libraries allowing development work<br />
|-<br />
| || style="padding-right: 10px" | ''core-image-minimal-initramfs'' || ''core-image-minimal'' with kernel support for in-RAM filesystem<br />
|-<br />
| || '''core-image-base''' || '''console-only system fully supporting the target hardware'''<br />
|-<br />
| || ''core-image-full-cmdline'' || console-only image that includes many system tools<br />
|-<br />
| || ''core-image-x11'' || image with basic X11 and a terminal<br />
|-<br />
|}<br />
<br />
These image definitions are provided as a starting point for creating project-specific, custom image definitions.<br />
<br /><br />
<br /><br />
<br />
== Creating a Custom Image ==<br />
* In your custom layer, create the ''images'' subdirectory in one of your ''recipes-...' directory.<br />
* In the ''images'' directory, create two image recipe files that inherit from ''core-image'':<br />
<pre class="code"><br />
SUMMARY = "My deployment image"<br />
LICENSE = "MIT"<br />
<br />
inherit core-image<br />
IMAGE_FEATURES += "splash"<br />
</pre><br />
and<br />
<pre class="code"><br />
SUMMARY = "My development image"<br />
<br />
inherit core-image<br />
require my-image.bb<br />
<br />
IMAGE_FEATURES += "ssh-server-dropbear tools-debug debug-tweaks"<br />
<br />
CORE_IMAGE_EXTRA_INSTALL += "i2c-tools "<br />
</pre><br />
where the first image recipe is for deployment and the second is for development. Note that the development version includes the deployment version with the ''require'' statement, and adds to IMAGE_FEATURES and CORE_IMAGE_EXTRA_INSTALL.<br />
<br /><br />
<br />
== Image Filesystem Packaging ==<br />
The system image generated by Bitbake can be packaged in the form of an image file, whose contents can be transferred on a boot medium (SD card or eMMC) such that the primary boot loader of the target device can discover the system and boot it.<br />
<br />
Unless you restrict the type of packaging used for the image file, Yocto will generate multiple rootfs packages, each with a large footprint. To restrict the generated image files to a desired type, edit ''conf/local.conf'' of your project build directory and set the type.<br />
<pre class="code"><br />
#IMAGE_FSTYPES = "tar.gz"<br />
#IMAGE_FSTYPES = "tar.bz2"<br />
IMAGE_FSTYPES = "wic.bz2 wic.bmap"<br />
</pre><br />
The wic ([https://pykickstart.readthedocs.io/en/latest/kickstart-docs.html kickstart]) format with accompanying [https://github.com/intel/bmap-tools bmap] is recommended.<br />
<br /><br />
<br />
== Installing the Rootfs Image ==<br />
Using [https://github.com/intel/bmap-tools bmaptool] we can copy the generated ''wic'' image (with matching bmap file) to a mounted SD card or eMMC storage.<br />
<pre class="terminal"><br />
sudo bmaptool copy tmp/deploy/images/raspberrypi4-64/<wic.bz2 file> <drive><br />
</pre><br />
where ''<wic.bz2 file>'' is the root filesystem image wic.bz2 file, and ''<drive>'' is the drive at which the storage is mounted (for example, ''/dev/sdb'').<br />
<br /><br />
<br /><br />
<br />
= Package Groups =<br />
Package groups are recipes that inherit from '''meta/classes/packagegroup.bbclass''' and set the content of the global variable '''PACKAGES'''. Package groups are defined in recipe files with the file extension 'bb'.<br />
<br /><br />
<br /><br />
Note that the ''packagegroup'' must be inherited before ''PACKAGES is defined.<br />
<pre class="code"><br />
inherit packagegroup<br />
<br />
PACKAGES = '...'<br />
</pre><br />
<br /><br />
<br />
= Useful Image Features =<br />
<br /><br />
<br />
== Distro Features ==<br />
Distro features are system features that affect multiple recipes. '''Large parts of the Poky image may need to be rebaked after making changes to the distro features!'''<br />
<br /><br />
<br />
=== systemd ===<br />
In the ''conf/local.conf'' file of your project build directory (or ''layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " systemd"<br />
</pre><br />
<br /><br />
<br />
=== sshd ===<br />
The OpenSSH server is installed via<br />
<pre class="code"><br />
EXTRA_IMAGE_FEATURES:append = " ssh-server-openssh"<br />
</pre><br />
This installs a socket-based SSH server, which runs only when a connection request comes in, thereby reducing memory consumption when no SSH client is connected.<br />
<br /><br />
<br /><br />
To check the status of the SSH server, on the target device, type<br />
<pre class="terminal"><br />
systemctl status sshd.socket<br />
</pre><br />
<br /><br />
<br />
=== NFS ===<br />
In Embedded Linux projects, NFS is often included in development images to enable faster code-deploy turnaround times.<br />
<br /><br />
In the ''conf/local.conf'' file of your Yocto build directory (or ''conf/layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " nfs"<br />
</pre><br />
<br /><br />
On your Debian-based Yocto machine, [[Ubuntu#Setting_up_an_NFS_Server|set up an SSH server]].<br />
<br /><br />
<br /><br />
In Yocto, use the directory<br />
<br /><br />
: '''{YOCTO_BUILD_DIR}/tmp/work/{TARGET}-poky-linux/{IMAGE}/1.0-r0/rootfs'''<br />
as the root directory provided by the NFS server. For example,<br />
: ''build-robofish-core/tmp/work/raspberrypi4_64-poky-linux/robofish-core-image-dev/1.0-r0/rootfs''<br />
<br /><br />
<br /><br />
<br />
=== [https://vulkan.org Vulkan] and [https://opengl.org OpenGL] ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " vulkan opengl x11 wayland"<br />
</pre><br />
<br /><br />
<br />
=== Bluetooth and NFC ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " bluetooth nfc"<br />
</pre><br />
<br /><br />
<br />
= Recipes =<br />
Recipes are Yocto metadata files that are interpreted by Bitbake and describe how a build task is performed.<br />
<br /><br />
== Patching A Device Tree ==<br />
Follow these steps to patch an existing device tree by creating an ''append recipe'' in a custom layer.<br />
<br /><br />
<br /><br />
In the custom layer, create the directory for a linux kernel append recipe.<br />
<pre class="terminal"><br />
mkdir -p ${LAYER_DIR}/recipes-kernel/linux/files<br />
</pre><br />
where it is assumed that ''${LAYER_DIR}'' contains the path to the root directory of the custom Yocto layer. <br />
<br /><br />
<br /><br />
Copy the kernel device tree file from your Yocto project build directory to the ''files'' directory of your new recipe. For a Raspberry Pi Compute Module 4, for example, type<br />
<pre class="terminal"><br />
cp ${YOCTO_BUILD_DIR}/tmp/work-shared/${MACHINE}/kernel-source/arch/arm/boot/dts/some.dts ${LAYER_DIR}/recipes-kernel/linux/files/<br />
</pre><br />
where ''${YOCTO_BUILD_DIR}'' is the path to the Yocto project build directory, and ''${MACHINE}'' is the chosen target platform (e.g. "raspberrypi4-64").<br />
<br /><br />
<div class="sidenote"><br />
If the ''tmp/work-shared'' directory does not exists anymore, you can recreate it by typing<br />
<pre class="terminal"><br />
bitbake -c menuconfig virtual/kernel<br />
</pre><br />
and exiting the kernel configuration menu without making changes.<br />
</div><br />
<br /><br />
Make the necessary changes to the copied device tree file. Then create a git patch file using ''git diff'' as shown below<br />
<pre class="terminal"><br />
git diff --no-index {DTS_DIR}/some.dts some.dts > 0001-my_modifications-dts.patch<br />
</pre><br />
<br /><br />
Edit the generated patch file to fix the file paths at the top. The paths must be relative to the kernel sources directory:<br />
: ''${YOCTO_BUILD_DIR}'''''/tmp/work-shared/'''''${MACHINE}'''''/kernel-source'''<br />
The header should look like this:<br />
<pre class="code"><br />
diff --git a/arch/arm/boot/dts/some.dts b/some.dts<br />
index 6e99da1..4567735 100644<br />
--- a/arch/arm/boot/dts/some.dts<br />
+++ b/arch/arm/boot/dts/some.dts<br />
</pre><br />
where "--- a" and "+++ b" are followed by the same relative file path.<br />
<br />
<br /><br />
Create and edit the append recipe<br />
<pre class="terminal"><br />
vim ${LAYER_DIR}/recipes-kernel/linux/${KERNEL_NAME}_%.bbappend<br />
</pre><br />
where ''${KERNEL_NAME}'' is the kernel name, which usually starts with "linux-" (for example, ''linux-raspberrypi''), and ''_%'' denotes all versions of the kernel package.<br />
<br /><br />
<div class="sidenote"><br />
If in doubt, use the ''oe-pkgdata-util'' tool from within your build directory to find out the kernel name.<br />
<pre class="terminal"><br />
oe-pkgdata-util lookup-recipe kernel<br />
</pre><br />
</div><br />
The contents of the recipe file should be similar to this:<br />
<pre class="code"><br />
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"<br />
SRC_URI += "file://0001-my_modifications-dts.patch"<br />
SRC_URI[md5sum] = "e2eba462f773f46fe6930a08323f5e1f"<br />
SRC_URI[sha256sum] = "2ef2b2e9b33b5d2af0425940387bc6c1c2c305e6a685defbdc7cf3f584bc1edc"<br />
</pre><br />
where ''0001-my_modifications-dts.patch'' needs to be replaced with the actual patch file name.<br />
<br />
== Creating a New Device Tree ==<br />
Creating a new device tree requires an input dts file which completely defines the hardware configuration. The ''KERNEL_DEVICETREE'' variable is used to make the Linux kernel select the new device tree during booting.<br />
<pre class="code"><br />
inherit kernel-devicetree<br />
<br />
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"<br />
<br />
# Make custom kernel with PRU enabled<br />
SRC_URI += " \<br />
file://some.dts \<br />
file://0001-some.patch \<br />
"<br />
<br />
KERNEL_DEVICETREE = "some.dtb"<br />
</pre><br />
<br /><br />
<br />
= Accessing the OpenEmbedded package collection =<br />
The OpenEmbedded project provides recipes for many useful programs that are not included with Yocto, like tmux, VLC, Gnome, various multimedia codecs, more filesystems, gRPC and much more.<br />
<br /><br />
To access the recipes for those software packages, clone the OpenEmbedded layers repository into your third-party layers directory: <br />
<pre class="terminal"><br />
git clone git://git.openembedded.org/meta-openembedded<br />
</pre><br />
<br /><br />
<br />
= devtool =<br />
<br />
Use '''devtool''' to make changes to an existing recipe and automatically generate an append recipe from those changes.<br />
<br /><br />
<br /><br />
<br />
== Initialization Manager ==<br />
After the kernel is done with its basic booting tasks, it passes control to the initialization manager. To use the ''systemd'' initialization manager (used by the Linux distributions Debian and Ubuntu) instead of ''SysVinit'', make the following entries in ''${TOPDIR}/conf/distro/distro.conf''<br />
<pre class="code"><br />
DISTRO_FEATURES_append = " systemd"<br />
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"<br />
VIRTUAL-RUNTIME_init_manager = "systemd"<br />
VIRTUAL-RUNTIME_initscripts = ""<br />
</pre><br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Raspberry_Pi&diff=3166Raspberry Pi2022-12-26T09:09:16Z<p>Kai: Adds note about missing dsi entry in Compute Module 4 default dts.</p>
<hr />
<div>= Introduction =<br />
The [http://raspberrypi.org Raspberry Pi Ltd.] is a company producing small and affordable single-board, bare-bones computer systems, microcontrollers and accessories, marketed under the ''Raspberry Pi'' brand. All Raspberry Pi computing products use Arm-based processors. I use Raspberry Pi computers as [[Robot Task Controller | task controller]], and the microcontrollers as [[Robot State Agent | state agent]] in my robots.<br />
<br /><br />
<br /><br />
= Processors and Architectures =<br />
<br />
* [https://developer.arm.com/Processors/Cortex-A7 Arm Cortex-A7] with 32-bit Armv7 programming model<br />
** Raspberry Pi 2 B (Broadcom BCM2836 processor @ 900 MHz)<br />
<br /><br />
<br />
* [https://developer.arm.com/Processors/Cortex-A53 Arm Cortex-A53] with 64-bit Armv8-A programming model.<br />
** Raspberry Pi 2 B rev 1.2 (Broadcom BCM2837 processor @ 900 MHz)<br />
** Raspberry Pi 3 B (Broadcom BCM2837 processor @ 1.2 GHz)<br />
** Raspberry Pi 3 B+ (Broadcom BCM2837B0 processor @ 1.4 GHz)<br />
** Raspberry Pi Zero 2 W (@ 1 GHz)<br />
<br /><br />
<br />
* [https://developer.arm.com/Processors/Cortex-A72 Arm Cortex-A72] with 64-bit Armv8-A programming model<br />
** Raspberry Pi 4 (Broadcom BCM2711 processor @ 1.5 GHz)<br />
** Compute Module 4 (Broadcom BCM2711 @ 1.5 GHz)<br />
<br /><br />
<br />
* [https://developer.arm.com/Processors/Cortex-M0+ Arm Cortex-M0+] with Armv6-M programming model<br />
** Raspberry Pi Pico (up to 133 MHz)<br />
<br /><br />
<br />
= Installing a System Image =<br />
[https://www.raspberrypi.com/software/operating-systems/ Raspberry Pi OS] is the offical operating system of a Raspberry Pi. The Lite version, without a graphical desktop, is recommended for embedded applications unless you decide to create a custom system image. The fewer software modules are running, the lower the power consumption, and the lower the chance that user-space processes will be interrupted.<br />
<br /><br />
<br /><br />
== Installing the System Image on SD Card ==<br />
This is the most popular method of installing a system image on a single-board computers. SD cards are cheap and reusable, almost all Raspberry Pi models come with an SD card reader. However, SD card memory is not designed to support frequent rewrite operations and may not be as durable as other storage solutions. <br />
<br />
The preferred way of putting a system image on an SD card is to use the [https://www.raspberrypi.com/software Raspberry Pi Imager] tool that can fetch a Raspberry Pi OS image over the Internet or use a local image file, create a derived image with preconfigured user credentials, WLAN access and more, before writing it to the SD card.<br />
<br />
=== Using built-in tools on Linux ===<br />
The SD card can also be prepared by using standard Linux tools instead of Raspberry Pi Imager. First, we need to find out which device to copy the install image to. Type<br />
<pre class="terminal"><br />
df -h<br />
</pre><br />
or<br />
<pre class="terminal"><br />
sudo fdisk --list<br />
</pre><br />
in the command terminal to look up the mount point for the SD card. Let us assume the card was mounted as ''/dev/sdb2''. The card needs to be unmounted before we can copy the downloaded Raspberry Pi OS install image:<br />
<br /><br />
<pre class="terminal"><br />
umount /dev/sdb2<br />
</pre><br />
<br /><br />
Copy the image to the card with the ''dd'' command:<br />
<pre class="terminal"><br />
sudo dd bs=4M if=2021-01-11-raspios-buster-armhf-lite.img of=/dev/sdb<br />
</pre><br />
where we use the path to the device file ''/dev/sdb'' instead of the partition ''/dev/sdb2'', which was unmounted. The option ''bs'' is used for adjusting the buffer size for the writing operation.<br />
<br /><br />
<br /><br />
<br />
=== Using built-in tools on macOS ===<br />
On Apple macOS, you can use the built-in 'diskutil' tool as an alternative to the Raspberry Pi Imager. First, attach the SD card to your Mac and determine the assigned disk number ''disk#'' (e.g., disk2) under which the card has been mounted to the filesystem by opening Terminal and typing<br />
<br /><br />
<pre class="terminal"><br />
diskutil list<br />
</pre><br />
then unmount the disk<br />
<pre class="terminal"><br />
diskutil unmountDisk disk2<br />
</pre><br />
and copy the data with the ''dd'' tool<br />
<pre class="terminal"><br />
sudo dd bs=1m if=~/Downloads/raspios.img of=/dev/rdisk2<br />
</pre><br />
where I assume that the downloaded and <u>unzipped</u> Raspberry Pi OS image file is located at ''~/Downloads/raspios.img'' and the SD card was mounted as ''disk2''.<br />
<br /><br />
<br />
== Installing the System Image on eMMC ==<br />
Some Raspberry Pi models, like the Compute Module 4, come with an embedded MultiMediaCard (eMMC) storage component. A switch or jumper on the carrier board serves to make the Raspberry Pi bootloader boot the compute module into USB mass storage mode. In this mode you can attach the compute module to an external computer via USB. On Ubuntu you can use the<br />
<pre class="terminal"><br />
lsusb<br />
</pre><br />
command to list all connected USB devices. The Compute Module 4, for example, should show up as "Broadcom Corp. BCM2711 Boot".<br />
<br /><br />
To make the operating system recognize the USB device as a mass storage device, we need to build and run Raspberry Pi's ''rpiboot'' tool.<br />
<pre class="terminal"><br />
sudo apt install libusb-1.0-0-dev<br />
git clone --depth=1 https://github.com/raspberrypi/usbboot<br />
cd usbboot<br />
make<br />
sudo ./rpiboot<br />
</pre><br />
On Ubuntu, ''lsusb'' will now list the Compute Module 4 as "Broadcom Corp. Compute Module". The compute module will also show up in the ''Disks'' app as ''RPi-MSD-0001''.<br />
<br /><br />
[[File: raspberrypi_emmc_shows_up_in_disks_app.png | x300px ]]<br />
<br /><br />
You can now use Raspberry Pi Imager or any flashing utility to flash a system image on the compute module eMMC.<br />
<br /><br />
<br /><br />
<br />
= Upgrading a Raspberry Pi OS Installation =<br />
You don't want to erase your existing Raspberry Pi OS environment and set up all the software from start each time a new version of Raspberry Pi OS is released. Fortunately, [https://www.raspberrypi.com/documentation/computers/os.html#updating-and-upgrading-raspberry-pi-os Raspberry Pi OS can upgrade itself to the latest release] with the following commands.<br />
<pre class="terminal"><br />
sudo apt-get update<br />
sudo apt-get dist-upgrade<br />
</pre><br />
<br /><br />
<br /><br />
<br />
= Assigning a Static Ethernet IP Address =<br />
Edit the file '''/etc/network/interfaces''' and make sure that the entries for the interface ''eth0'' are as follows:<br />
<pre class="terminal"><br />
auto eth0<br />
iface eth0 inet static<br />
address 192.168.0.20<br />
netmask 255.255.255.0<br />
broadcast 192.168.0.255<br />
</pre><br />
where the IP address ''192.168.0.20'' is just an example.<br />
<br /><br />
<br /><br />
Make sure you don't break the WiFi connectivity because of editing ''/etc/network/interfaces''. If there is no empty describing ''wlan0'' we will need to create one. For dynamically assigned IPs via DHCP you will need these lines:<br />
<pre class="terminal"><br />
auto wlan0<br />
iface wlan0 inet dhcp<br />
wpa-ssid <your WiFi router name (SSID)><br />
wpa-psk <your WiFi password><br />
</pre><br />
<br /><br />
The new network setting becomes effective on the next system boot or when you type<br />
<pre class="terminal"><br />
sudo ifdown eth0<br />
sudo ifup eth0<br />
</pre><br />
<br /><br />
<br /><br />
= Setting Up SSH =<br />
* As a security measure, SSH is not enabled by default on headless (= Raspbian Lite, without GUI) installations. Place a file named "ssh" into the root folder of the boot partition (= ''/boot'') to enable SSH.<br />
* In the web browser go to the configuration page of your home Internet router (e.g., http://192.168.1.1).<br />
* Open the page that lists all currently connected LAN devices.<br />
* Connect the Raspberry Pi via Ethernet cable to the LAN router.<br />
* Look for a new entry in the list of LAN devices. That should be your Raspberry Pi. Note the IP address. Let's assume it is ''192.168.1.10''.<br />
* Optional: You should be able to read the [https://en.wikipedia.org/wiki/MAC_address MAC address] of the Raspberry Pi from the table. For future reference, write down the MAC address somewhere.<br />
* Open Terminal and type '''ssh pi@192.168.1.10''' to log in via SSH. On a fresh Raspbian installation the username is '''pi''' and the password is '''raspberry'''.<br />
* After logging in type '''sudo raspi-config''' to start the Raspbian configuration tool, where you can change the password or expand the filesystem to take up the whole SD card, among other things.<br />
<br /><br />
<br /><br />
= Setting Up WiFi =<br />
== Raspberry Pi 2 ==<br />
The Raspberry Pi 2 does not have built-in WiFi. I assume that you are using a USB WiFi adapter. Before connecting the adapter you need to edit the network interfaces on the Raspberry Pi. Log in to the Raspberry Pi over SSH and edit '''/etc/network/interfaces''' as follows:<br />
<br /><br />
<pre class="code"><br />
auto lo<br />
<br />
iface lo inet loopback<br />
iface eth0 inet dhcp<br />
<br />
allow-hotplug wlan0<br />
auto wlan0<br />
<br />
iface wlan0 inet dhcp<br />
wpa-ssid "ssid"<br />
wpa-psk “password"<br />
</pre><br />
<br /><br />
where ''ssid'' is the SSID (a.k.a. name) of your WLAN router, and ''password'' is supplied in encoded form. Do not type the quotation marks. The password is encoded by running<br />
<br /><br />
<pre class="terminal"><br />
wpa_passphrase <ssid> <password><br />
</pre><br />
<br /><br />
If your WLAN router uses a hidden SSID use this configuration:<br />
<pre class="code"><br />
auto lo<br />
<br />
iface lo inet loopback<br />
iface eth0 inet dhcp<br />
<br />
auto wlan0<br />
allow-hotplug wlan0<br />
iface wlan0 inet dhcp<br />
wpa-scan-ssid 1<br />
wpa-ap-scan 1<br />
wpa-key-mgmt WPA-PSK<br />
wpa-proto RSN WPA<br />
wpa-pairwise CCMP TKIP<br />
wpa-group CCMP TKIP<br />
wpa-ssid "My Secret SSID"<br />
wpa-psk "My SSID PSK”<br />
<br />
iface default inet dhcp<br />
</pre><br />
<br /><br />
Instead of putting the WPA configuration directly into '''interfaces''' you can put it into the file '''/etc/wpa_supplicant/wpa_supplicant.conf'''<br />
<pre class="code"><br />
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev<br />
update_config=1<br />
<br />
network={<br />
ssid="<your ssid>"<br />
psk=<your encoded password given by running wpa_passphrase><br />
scan_ssid=1<br />
proto=WPA RSN<br />
key_mgmt=WPA-PSK<br />
pairwise=CCMP TKIP<br />
}<br />
</pre><br />
<br /><br />
and refer to it from '''interfaces''' like so<br />
<pre class="code"><br />
auto lo<br />
iface lo inet loopback<br />
<br />
iface eth0 inet dhcp<br />
<br />
allow-hotplug wlan0<br />
iface wlan0 inet dhcp<br />
wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf<br />
<br />
iface default inet dhcp<br />
</pre><br />
<br /><br />
<br /><br />
<br />
== Raspberry Pi 3 or newer ==<br />
The Raspberry Pi 3 has a WLAN transmitter built in and it is turned on by default. You should see the device '''wlan0''' along with '''eth0''' and '''lo''' when typing<br />
<br /><br />
<pre class="terminal"><br />
ifconfig -a<br />
</pre><br />
<br /><br />
Make sure the Raspberry Pi can log in to your WLAN router. If a MAC filter is active, add the Raspberry Pi WiFi MAC address to the list of allowed devices. The MAC address of the Pi is displayed in the output of ''ifconfig -a'' as '''HWaddr'''. Open a text editor to add the network configuration details, such as your login credentials, to the file ''/etc/wpa_supplicant/wpa_supplicant.conf''.<br />
<br /><br />
<pre class="code"><br />
network={<br />
ssid="MySSID"<br />
psk=MyCodedPassword<br />
scan_ssid=1<br />
proto=WPA RSN<br />
key_mgmt=WPA-PSK<br />
pairwise=CCMP TKIP<br />
}<br />
</pre><br />
<br /><br />
where '''MySSID''' is the SSID (a.k.a. name) of the router, and '''MyCodedPassword''' is the encoded password obtained via<br />
<br /><br />
<pre class="terminal"><br />
wpa_passphrase MySSID MyPassword<br />
</pre><br />
and where '''MyPassword''' is the actual password.<br />
<br /><br />
<br /><br />
<br />
== Power Saving ==<br />
If the WiFi connection is unstable you can turn off the WiFi power management feature, which may cause connection dropouts, by issuing the command<br />
<pre class="terminal"><br />
sudo iw dev wlan0 set power_save off<br />
</pre><br />
or by manually editing '''/etc/network/interfaces''', where you add the line<br />
<pre class="code"><br />
wireless-power off<br />
</pre><br />
right after the line<br />
<pre class="code"><br />
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf<br />
</pre><br />
within the '''wlan0''' block. You can check whether power management is currently turned on or off, among other parameters, with the command<br />
<pre class="terminal"><br />
iwconfig<br />
</pre><br />
<br /><br />
<br /><br />
For Raspberry Pi 2 and WiFi dongles with 8192CU or 8188CUS chip (for example, Edimax EW-7811un dongles)you can prevent connections from being dropped by creating the file '''/etc/modprobe.d/8192cu.conf'''<br />
<br><br />
<pre class="terminal"><br />
sudo nano /etc/modprobe.d/8192cu.conf<br />
</pre><br />
and adding the line<br />
<br /><br />
<pre class="code"><br />
options 8192cu rtw_power_mgnt=0 rtw_enusbss=0<br />
</pre><br />
<br /><br />
<br />
= Camera =<br />
There is a [https://www.raspberrypi.org/products/camera-module/ camera module] for Raspberry Pi, which I use in my robots. In fact, the camera module is part of the [[Core Module]].<br />
<br /><br />
<br /><br />
Refer to the official [https://www.raspberrypi.org/documentation/usage/camera/README.md camera setup instructions]. Be careful with the camera module, handle the camera board and the connector strip delicately.<br />
<br /><br />
<br /><br />
To be able to access the camera through the Python programming environment you need to install the '''python-picamera''' package<br />
<br /><br />
<br /><br />
The Raspberry Pi project does not provide a C/C++ library for accessing the camera. Instead it provides utility applications ''raspistill'' and ''raspivid'' which record still images and videos, respectively. A number of third-party C++ libraries have been created based on the open source code of these utility applications. The [http://www.uco.es/investiga/grupos/ava/node/40 RaspiCam] C++ library developed at the University of Cordoba is one such library (source code available [https://sourceforge.net/projects/raspicam/ from SourceForge]).<br />
<br /><br />
<br /><br />
== Video Streaming ==<br />
To stream video from the Raspberry Pi camera to the network, open a terminal on the RPi and type<br />
<pre class="terminal"><br />
raspivid -t 0 -w 1280 -h 720 -hf -ih -fps 30 -o - | nc -k -l 8100<br />
</pre><br />
<br /><br />
To view the stream on a client computer with [http://www.mplayerhq.hu Mplayer] installed, open a terminal there and type<br />
<pre class="terminal"><br />
mplayer -fps 300 -demuxer h264es ffmpeg://tcp://192.168.0.20:8100<br />
</pre><br />
<br /><br />
<br /><br />
Alternatively, you can use [[GStreamer]] to transport the video frames. Make sure that the command line interface to GStreamer, ''gst-launch-1.0'', is installed. <br />
<pre class="terminal"><br />
sudo apt install gstreamer1.0-tools<br />
</pre><br />
<br /><br />
For streaming from the RPi you can type<br />
<pre class="terminal"><br />
raspivid -t 0 -w 640 -h 480 -fps 30 -hf -b 2000000 -o - | gst-launch-1.0 -q fdsrc ! h264parse ! rtph264pay config-interval=1 pt=96 ! gdppay ! tcpserversink host=0.0.0.0 port=8100<br />
</pre><br />
<br /><br />
For viewing on the client, you can type<br />
<pre class="terminal"><br />
gst-launch-1.0 -v tcpclientsrc host=192.168.0.20 port=8100 ! gdpdepay ! rtph264depay ! avdec_h264 ! videoconvert ! videoflip method=vertical-flip ! autovideosink sync=false<br />
</pre><br />
where ''192.168.0.20'' is assumed to be the IP address of the server (Raspberry Pi).<br />
<br /><br />
<br /><br />
* On the Raspberry Pi side you can elevate the priority of the process by beginning the command with ''"nice -20"''.<br />
* For verbose output from ''gst-launch-1.0'', use the option ''-v'' instead of ''-q''.<br />
* Note that we used the [https://gstreamer.freedesktop.org/documentation/videofilter/videoflip.html?gi-language=c#GstVideoFlipMethod videoflip] filter to correct the rotation of the decoded image.<br />
<br /><br />
=== Disabling the LED ===<br />
To disable the red indicator light of the camera, add the following line to '''/boot/config.txt''' and reboot:<br />
<pre class="code"><br />
disable_camera_led=1<br />
</pre><br />
<br /><br />
<br />
= pinout =<br />
A cool command-line tool provided by Raspberry Pi, and also available when running Ubuntu instead of Raspberry Pi OS, is '''pinout'''. It displays a layout of the Raspberry Pi board using ASCII art, a list of significant hardware features of the board, and the GPIO pin layout in tabular form.<br />
<br /><br />
<pre class="terminal"><br />
sudo apt install python3-gpiozero<br />
pinout<br />
</pre><br />
<br /><br />
[[File:Raspberry_Pi_pinout_command.png | x600px]]<br />
<br /><br />
<br /><br />
<br />
= raspi-gpio =<br />
The documentation states that ''"raspi-gpio can get and print the state of a GPIO (or all GPIOs) and can be used to set the function, pulls and value of a GPIO. raspi-gpio must be run as root."''<br />
"<br />
<pre class="terminal"><br />
> sudo apt install raspi-gpio<br />
> raspi-gpio funcs 20,21,22<br />
GPIO, DEFAULT PULL, ALT0, ALT1, ALT2, ALT3, ALT4, ALT5<br />
20, DOWN, PCM_DIN, SD12, DPI_D16, SPI6_MOSI, SPI1_MOSI, GPCLK0<br />
21, DOWN, PCM_DOUT, SD13, DPI_D17, SPI6_SCLK, SPI1_SCLK, GPCLK1<br />
22, DOWN, SD0_CLK, SD14, DPI_D18, SD1_CLK, ARM_TRST, SDA6<br />
> raspi-gpio get 20<br />
GPIO 20: level=0 func=INPUT pull=DOWN<br />
GPIO 21: level=1 func=INPUT pull=DOWN<br />
GPIO 22: level=0 func=INPUT pull=DOWN<br />
> raspi-gpio raw 21<br />
00: 00000000 00012000 12000000 3fffffff<br />
10: 24000040 00000924 00000000 6770696f<br />
20: 6770696f 6770696f 6770696f 6770696f<br />
30: 6770696f 102081ff 00003bfb 00000000<br />
40: 00000000 00000000 00000000 00000000<br />
50: 00000000 00000000 00000000 00000000<br />
60: 00000000 00000000 00000000 00000000<br />
70: 00000000 00000000 00000000 00000000<br />
80: 00000000 00000000 00000000 00000000<br />
90: 00000000 00000000 00000000 00000000<br />
e0: 4aa95555 19aaaaaa 50aa5544<br />
f0: 000aaaaa<br />
</pre><br />
<br /><br />
<br />
= GPIO Programming in C =<br />
Raspberry Pi 2, 3 & 4 come with 40 ''General Purpose Input Output'' (GPIO) pins ([https://www.raspberrypi.com/documentation/computers/os.html#gpio-and-the-40-pin-header layout]) that can be used to interface with the other electronic components of your project.<br />
<br />
== Using libgpiod ==<br />
The standard C++ programming interface for GPIO on Linux is ''libgpiod'', as described on [[Nvidia_Jetson#Using_Libgpiod | the Jetson page]].<br />
<br />
== Using WiringPi ==<br />
Using the [http://wiringpi.coml WiringPi] library is a more popular method for programming the GPIO pins on a Raspberry Pi with C/C++. WiringPi is [http://wiringpi.com/download-and-install installed from source] like this<br />
<pre class="terminal"><br />
sudo apt-get install git-core<br />
git clone git://git.drogon.net/wiringPi<br />
cd wiringPi<br />
./build<br />
</pre><br />
Read the ''INSTALL'' file for what to do with the created shared library. Basically you need to copy ''wiringPi/libwiringPi.so.x.xx'' to ''/usr/local/lib'' and add the line<br />
<pre class="code"><br />
include /usr/local/lib<br />
</pre><br />
to the file ''/etc/ld.so.conf'' so that the library loader also looks in ''/usr/local/lib'' for dynamically loadable libraries. It is also possible to create a static library.<br />
<br /><br />
<br/><br />
After installation, create a test program called ''blink.cpp''<br />
<pre class="code"><br />
#include <stdio.h><br />
#include <iostream><br />
#include <wiringPi.h><br />
<br />
static int LED_PORT = 7; // The physical pin number. Corresponds to BCM GPIO pin 4.<br />
<br />
void blink()<br />
{<br />
digitalWrite(4, HIGH);<br />
delay(1000);<br />
digitalWrite(4, LOW);<br />
delay(1000);<br />
};<br />
<br />
int main(int numargs, char** args)<br />
{<br />
wiringPiSetup();<br />
pinMode(LED_PORT, OUTPUT);<br />
for (int n = 0; n < 10; n++)<br />
{<br />
blink();<br />
}<br />
std::cout << "finished blinking" << std::endl;<br />
return 0;<br />
}<br />
</pre><br />
and build like this<br />
<pre class="terminal"><br />
g++ blink.cpp -o blink -lstdc++ -lwiringPi -IwiringPi<br />
</pre><br />
where I assumed that the wiringPi root folder is located in the same folder as the ''blink.cpp'' source file.<br />
<br /><br />
<br/><br />
Which pins can be used for what purpose is explained on the [http://wiringpi.com/pins wiringPi pins] page.<br />
<br /><br />
<br/><br />
<br />
= PWM =<br />
There are some Python libraries that communicate with the GPIO daemon to provide hardware PWM on selected pins. [https://gpiozero.readthedocs.org/ GPIO Zero] ([https://www.raspberrypi.org/blog/gpio-zero-a-friendly-python-api-for-physical-computing/ tutorial]) is one such library and is included in [https://www.raspberrypi.org/downloads/raspbian/ Raspbian]. With GPIO Zero you can implement dimming LEDs or control a brushed DC motor behind an [https://en.wikipedia.org/wiki/H_bridge H-Bridge] circuit.<br />
<br />
<br /><br />
= Running A Program On Startup =<br />
== Using SysVInit ==<br />
We want the Raspberry Pi to start the robot control program as soon as it's done with booting. In order to make sure that the system has completely initialized itself we will not use ''/etc/rc.local'' for starting our program. Instead, we will create a ''cron'' task with the ''crontab'' command<br />
<br /><br />
<pre class="terminal"><br />
sudo crontab -e<br />
</pre><br />
which opens the editor of choice (most likely ''nano'') where you can enter the program launch command. In our case this will be<br />
<pre class="code"><br />
@reboot python /home/pi/Core.py<br />
</pre><br />
where the leading ''@reboot'' indicates to ''cron'' that this command shall be executed only once, right after the booting process has completed. Notice that it is not necessary to start the command with ''sudo'', which is necessary when running program from the command line.<br />
<br /><br />
<br />
== Using Systemd ==<br />
<br /><br />
<br />
<br /><br />
<br />
= Communicating With Other Devices =<br />
There are three popular communication protocols that the Raspberry Pi supports and that are often used in embedded systems: I<sup>2</sup>C, SPI, and UART.<br />
<br /><br />
<br /><br />
<br />
== I<sup>2</sup>C ==<br />
Set the [[I2C | I<sup>2</sup>C]] clock speed by editing '''/boot/config.txt'''<br />
<pre class="code"><br />
dtparam=i2c1=on<br />
dtparam=i2c_arm_baudrate=xxx<br />
</pre><br />
where ''xxx'' is the desired frequency. Keep in mind that ATmega microcontrollers used on Arduino boards support only up to 400 kHz while Raspberry Pi can support higher speeds.<br />
<br /><br />
<br /><br />
=== Wiring To I<sup>2</sup>C Devices With 5 V Logic Level ===<br />
Normally you can not connect a GPIO pin to a device with 5 V logic (most of the Arduino models, for example). The GPIO data pins of the Raspberry Pi use 3.3 V as the HIGH voltage level and can be damaged when 5 V is applied. However, because I<sup>2</sup>C pins have [https://en.wikipedia.org/wiki/Open_collector open-collector] outputs they can be wired directly to I<sup>2</sup>C pins of devices with incompatible voltage levels. As long as the pull-up line voltage, which corresponds to the lowest of the device HIGH voltage levels, exceeds the minimum voltage for which HIGH is defined on each device, the devices will be able to sense the correct data bit.<br />
<br /><br />
<br /><br />
Links:<br />
* [https://learn.sparkfun.com/tutorials/i2c Tutorial by SparkFun] on I<sup>2</sup>C<br />
* [https://learn.adafruit.com/adafruits-raspberry-pi-lesson-4-gpio-setup?view=all Article by Adafruit] on how to set up I<sup>2</sup>C and SPI on a Raspberry Pi<br />
* Tutorial for setting up an I2C bus [http://blog.oscarliang.net/raspberry-pi-arduino-connected-i2c/ between a Raspberry Pi and an Arduino].<br />
<br /><br />
<br />
== SPI ==<br />
First of all, you need to use the ''raspi-config'' command-line configuration utility to enable the SPI pins.<br />
<pre class="terminal"><br />
sudo raspi-config<br />
</pre><br />
<br /><br />
You can use [http://wiringpi.com/reference/spi-library/ WiringPi SPI] to add SPI capability to your C/C++ program.<br />
<br /><br />
<br /><br />
<br />
== UART ==<br />
[http://www.andremiller.net/content/raspberry-pi-and-arduino-via-gpio-uart Here is a tutorial] that shows how to communicate with an Arduino using the UART interface.<br />
<br /><br />
<br /><br />
<br />
== CAN ==<br />
There are various [[CAN]] adapter boards available for Raspberry Pi. For example [http://skpang.co.uk/catalog/pican2-canbus-board-for-raspberry-pi-2-p-1475.html PiCAN2].<br />
<br /><br />
<br /><br />
<br />
= Device Tree Overlays =<br />
A device tree overlay is a mechanism in Raspberry Pi computers to dynamically apply changes to existing device trees. This mechanism is mostly used to enable kernel-space support for hardware components that are attached to the Raspberry Pi via its GPIO headers.<br />
<br /><br />
<br /><br />
Operations with device tree overlays are performed by the Raspberry Pi GPU (VideoCore), without needing to preempt the Linux kernel. The Raspberry Pi primary bootloader, also a VideoCore firmware application, makes use of this device tree parsing and editing capability to apply device tree overlays during the boot process, before passing control to the Linux kernel.<br />
<br /><br />
==== /boot/config.txt ====<br />
The primary bootloader parses and interprets the ''/boot/config.txt'' file. It specifies, among other things, which device tree to select and which overlays to apply.<br />
<br /><br />
==== dtoverlay ====<br />
'''dtoverlay''' is the command-line tool for loading a device tree overlay (or unloading a previously loaded overlay) while the Linux system is running.<br />
<pre class="terminal"><br />
</pre><br />
<br /><br />
<br />
= VideoCore Device Tree Blob =<br />
VideoCore functions both as the GPU of the Raspberry Pi and as a separately programmable unit that connects to a number of I/O devices. The pin assignments for connecting to external devices can be customized through a user-provided device tree blob file, '''dt-blob.bin'''. See [https://www.raspberrypi.com/documentation/computers/configuration.html#changing-the-default-pin-configuration Raspberry Pi's documentation on the VideoCore device tree blob]. This configuration feature is necessary for adapting a compute module to the hardware configuration of a project. <br />
<br /><br />
<br /><br />
Below is an example configuration for a Compute Module 4, in which the I<sup>2</sup>C pins for accessing a MIPI CSI-2 camera and a MIPI DSI display are set. Applying this pin configuration is sufficient to make the camera available to user space applications because the device tree, ''bcm2711-rpi-cm4.dts'', already includes a ''csi'' entry. The ''dsi'' entry for the display, however, needs to be added.<br />
<pre class="code"><br />
/dts-v1/;<br />
<br />
// Enabling MIPI DSI display and MIPI CSI-2 camera for<br />
// WaveShare CM4-Nano B (https://www.waveshare.com/wiki/CM4-NANO-B).<br />
<br />
/ {<br />
videocore {<br />
<br />
pins_cm4 { // Pi 4 CM4<br />
pin_config {<br />
pin@default {<br />
polarity = "active_high";<br />
termination = "pull_down";<br />
startup_state = "inactive";<br />
function = "input";<br />
}; // pin<br />
pin@p0 { function = "input"; termination = "pull_up"; }; // CAMERA 0 I2C0 SDA<br />
pin@p1 { function = "input"; termination = "pull_up"; }; // CAMERA 0 I2C0 SCL<br />
pin@p44 { function = "input"; termination = "pull_up"; }; // DISPLAY 1 I2C0 SDA<br />
pin@p45 { function = "input"; termination = "pull_up"; }; // DISPLAY 1 I2C0 SCL<br />
<br />
pin@p128 { function = "output"; termination = "no_pulling"; }; // BT_ON<br />
pin@p129 { function = "output"; termination = "no_pulling"; }; // WL_ON<br />
pin@p131 { function = "output"; termination = "no_pulling"; }; // ANT1<br />
pin@p133 { function = "output"; termination = "no_pulling"; }; // Camera shutdown<br />
<br />
}; // pin_config<br />
<br />
pin_defines {<br />
pin_define@HDMI_CONTROL_ATTACHED {<br />
type = "external";<br />
number = <0>;<br />
};<br />
pin_define@EMMC_ENABLE {<br />
type = "external";<br />
number = <1>;<br />
};<br />
pin_define@NUM_CAMERAS {<br />
type = "internal";<br />
number = <1>;<br />
};<br />
pin_define@POWER_LOW {<br />
type = "absent";<br />
};<br />
pin_define@LEDS_DISK_ACTIVITY {<br />
type = "absent";<br />
};<br />
pin_define@LAN_RUN {<br />
type = "absent";<br />
};<br />
pin_define@BT_ON {<br />
type = "external";<br />
number = <0>;<br />
};<br />
pin_define@WL_ON {<br />
type = "external";<br />
number = <1>;<br />
};<br />
pin_define@ETH_CLK {<br />
type = "absent";<br />
};<br />
pin_define@WL_LPO_CLK {<br />
type = "absent";<br />
};<br />
pin_define@USB_LIMIT_1A2 {<br />
type = "absent";<br />
};<br />
pin_define@SIO_1V8_SEL {<br />
type = "absent";<br />
};<br />
pin_define@SAFE_MODE {<br />
type = "absent";<br />
};<br />
<br />
// Display<br />
<br />
pin_define@DISPLAY_I2C_PORT {<br />
type = "internal";<br />
number = <0>;<br />
};<br />
pin_define@DISPLAY_SDA {<br />
type = "internal";<br />
number = <44>;<br />
};<br />
pin_define@DISPLAY_SCL {<br />
type = "internal";<br />
number = <45>;<br />
};<br />
pin_define@DISPLAY_DSI_PORT {<br />
type = "internal";<br />
number = <1>;<br />
};<br />
<br />
// Camera<br />
<br />
pin_define@CAMERA_0_I2C_PORT {<br />
type = "internal";<br />
number = <0>;<br />
};<br />
pin_define@CAMERA_0_SDA_PIN {<br />
type = "internal";<br />
number = <0>;<br />
};<br />
pin_define@CAMERA_0_SCL_PIN {<br />
type = "internal";<br />
number = <1>;<br />
};<br />
pin_define@CAMERA_0_SHUTDOWN {<br />
type = "external";<br />
number = <5>;<br />
};<br />
pin_define@CAMERA_0_UNICAM_PORT {<br />
type = "internal";<br />
number = <0>;<br />
};<br />
pin_define@CAMERA_0_LED {<br />
type = "absent";<br />
};<br />
}; // pin_defines<br />
}; // pins<br />
<br />
};<br />
};<br />
</pre><br />
<br /><br />
<br />
= Yocto Tips =<br />
== Creating Kernel Patches for Compute Module 4 ==<br />
A compute module does not know what hardware components its carrier board provides unless the default device tree is modified to include the interfaces to these hardware components. Instead of providing a different complete device tree, you would normally [[Yocto#Patching_A_Device_Tree | create a patch]] for the device tree source file provided by a lower Yocto layer.<br />
<br /><br />
<br /><br />
The modified device tree must be based on the device tree used by the kernel in Yocto. For Compute Module 4, the device tree file to patch is<br />
: ''${YOCTO_BUILD_DIR}'''''/tmp/work-shared/raspberrypi4-64/kernel-source/arch/arm/boot/dts/bcm2711-rpi-cm4.dts'''<br />
Copy this file to your layer's recipe directory and edit the copy to add the peripherals. The Raspberry Pi reference device tree files at the [https://datasheets.raspberrypi.com/ Raspberry Pi Datasheets collection page] can be helpful in creating your modified device tree.<br />
<br /><br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Raspberry_Pi&diff=3165Raspberry Pi2022-12-26T01:22:01Z<p>Kai: Adds section about configuring the VideoCore pins.</p>
<hr />
<div>= Introduction =<br />
The [http://raspberrypi.org Raspberry Pi Ltd.] is a company producing small and affordable single-board, bare-bones computer systems, microcontrollers and accessories, marketed under the ''Raspberry Pi'' brand. All Raspberry Pi computing products use Arm-based processors. I use Raspberry Pi computers as [[Robot Task Controller | task controller]], and the microcontrollers as [[Robot State Agent | state agent]] in my robots.<br />
<br /><br />
<br /><br />
= Processors and Architectures =<br />
<br />
* [https://developer.arm.com/Processors/Cortex-A7 Arm Cortex-A7] with 32-bit Armv7 programming model<br />
** Raspberry Pi 2 B (Broadcom BCM2836 processor @ 900 MHz)<br />
<br /><br />
<br />
* [https://developer.arm.com/Processors/Cortex-A53 Arm Cortex-A53] with 64-bit Armv8-A programming model.<br />
** Raspberry Pi 2 B rev 1.2 (Broadcom BCM2837 processor @ 900 MHz)<br />
** Raspberry Pi 3 B (Broadcom BCM2837 processor @ 1.2 GHz)<br />
** Raspberry Pi 3 B+ (Broadcom BCM2837B0 processor @ 1.4 GHz)<br />
** Raspberry Pi Zero 2 W (@ 1 GHz)<br />
<br /><br />
<br />
* [https://developer.arm.com/Processors/Cortex-A72 Arm Cortex-A72] with 64-bit Armv8-A programming model<br />
** Raspberry Pi 4 (Broadcom BCM2711 processor @ 1.5 GHz)<br />
** Compute Module 4 (Broadcom BCM2711 @ 1.5 GHz)<br />
<br /><br />
<br />
* [https://developer.arm.com/Processors/Cortex-M0+ Arm Cortex-M0+] with Armv6-M programming model<br />
** Raspberry Pi Pico (up to 133 MHz)<br />
<br /><br />
<br />
= Installing a System Image =<br />
[https://www.raspberrypi.com/software/operating-systems/ Raspberry Pi OS] is the offical operating system of a Raspberry Pi. The Lite version, without a graphical desktop, is recommended for embedded applications unless you decide to create a custom system image. The fewer software modules are running, the lower the power consumption, and the lower the chance that user-space processes will be interrupted.<br />
<br /><br />
<br /><br />
== Installing the System Image on SD Card ==<br />
This is the most popular method of installing a system image on a single-board computers. SD cards are cheap and reusable, almost all Raspberry Pi models come with an SD card reader. However, SD card memory is not designed to support frequent rewrite operations and may not be as durable as other storage solutions. <br />
<br />
The preferred way of putting a system image on an SD card is to use the [https://www.raspberrypi.com/software Raspberry Pi Imager] tool that can fetch a Raspberry Pi OS image over the Internet or use a local image file, create a derived image with preconfigured user credentials, WLAN access and more, before writing it to the SD card.<br />
<br />
=== Using built-in tools on Linux ===<br />
The SD card can also be prepared by using standard Linux tools instead of Raspberry Pi Imager. First, we need to find out which device to copy the install image to. Type<br />
<pre class="terminal"><br />
df -h<br />
</pre><br />
or<br />
<pre class="terminal"><br />
sudo fdisk --list<br />
</pre><br />
in the command terminal to look up the mount point for the SD card. Let us assume the card was mounted as ''/dev/sdb2''. The card needs to be unmounted before we can copy the downloaded Raspberry Pi OS install image:<br />
<br /><br />
<pre class="terminal"><br />
umount /dev/sdb2<br />
</pre><br />
<br /><br />
Copy the image to the card with the ''dd'' command:<br />
<pre class="terminal"><br />
sudo dd bs=4M if=2021-01-11-raspios-buster-armhf-lite.img of=/dev/sdb<br />
</pre><br />
where we use the path to the device file ''/dev/sdb'' instead of the partition ''/dev/sdb2'', which was unmounted. The option ''bs'' is used for adjusting the buffer size for the writing operation.<br />
<br /><br />
<br /><br />
<br />
=== Using built-in tools on macOS ===<br />
On Apple macOS, you can use the built-in 'diskutil' tool as an alternative to the Raspberry Pi Imager. First, attach the SD card to your Mac and determine the assigned disk number ''disk#'' (e.g., disk2) under which the card has been mounted to the filesystem by opening Terminal and typing<br />
<br /><br />
<pre class="terminal"><br />
diskutil list<br />
</pre><br />
then unmount the disk<br />
<pre class="terminal"><br />
diskutil unmountDisk disk2<br />
</pre><br />
and copy the data with the ''dd'' tool<br />
<pre class="terminal"><br />
sudo dd bs=1m if=~/Downloads/raspios.img of=/dev/rdisk2<br />
</pre><br />
where I assume that the downloaded and <u>unzipped</u> Raspberry Pi OS image file is located at ''~/Downloads/raspios.img'' and the SD card was mounted as ''disk2''.<br />
<br /><br />
<br />
== Installing the System Image on eMMC ==<br />
Some Raspberry Pi models, like the Compute Module 4, come with an embedded MultiMediaCard (eMMC) storage component. A switch or jumper on the carrier board serves to make the Raspberry Pi bootloader boot the compute module into USB mass storage mode. In this mode you can attach the compute module to an external computer via USB. On Ubuntu you can use the<br />
<pre class="terminal"><br />
lsusb<br />
</pre><br />
command to list all connected USB devices. The Compute Module 4, for example, should show up as "Broadcom Corp. BCM2711 Boot".<br />
<br /><br />
To make the operating system recognize the USB device as a mass storage device, we need to build and run Raspberry Pi's ''rpiboot'' tool.<br />
<pre class="terminal"><br />
sudo apt install libusb-1.0-0-dev<br />
git clone --depth=1 https://github.com/raspberrypi/usbboot<br />
cd usbboot<br />
make<br />
sudo ./rpiboot<br />
</pre><br />
On Ubuntu, ''lsusb'' will now list the Compute Module 4 as "Broadcom Corp. Compute Module". The compute module will also show up in the ''Disks'' app as ''RPi-MSD-0001''.<br />
<br /><br />
[[File: raspberrypi_emmc_shows_up_in_disks_app.png | x300px ]]<br />
<br /><br />
You can now use Raspberry Pi Imager or any flashing utility to flash a system image on the compute module eMMC.<br />
<br /><br />
<br /><br />
<br />
= Upgrading a Raspberry Pi OS Installation =<br />
You don't want to erase your existing Raspberry Pi OS environment and set up all the software from start each time a new version of Raspberry Pi OS is released. Fortunately, [https://www.raspberrypi.com/documentation/computers/os.html#updating-and-upgrading-raspberry-pi-os Raspberry Pi OS can upgrade itself to the latest release] with the following commands.<br />
<pre class="terminal"><br />
sudo apt-get update<br />
sudo apt-get dist-upgrade<br />
</pre><br />
<br /><br />
<br /><br />
<br />
= Assigning a Static Ethernet IP Address =<br />
Edit the file '''/etc/network/interfaces''' and make sure that the entries for the interface ''eth0'' are as follows:<br />
<pre class="terminal"><br />
auto eth0<br />
iface eth0 inet static<br />
address 192.168.0.20<br />
netmask 255.255.255.0<br />
broadcast 192.168.0.255<br />
</pre><br />
where the IP address ''192.168.0.20'' is just an example.<br />
<br /><br />
<br /><br />
Make sure you don't break the WiFi connectivity because of editing ''/etc/network/interfaces''. If there is no empty describing ''wlan0'' we will need to create one. For dynamically assigned IPs via DHCP you will need these lines:<br />
<pre class="terminal"><br />
auto wlan0<br />
iface wlan0 inet dhcp<br />
wpa-ssid <your WiFi router name (SSID)><br />
wpa-psk <your WiFi password><br />
</pre><br />
<br /><br />
The new network setting becomes effective on the next system boot or when you type<br />
<pre class="terminal"><br />
sudo ifdown eth0<br />
sudo ifup eth0<br />
</pre><br />
<br /><br />
<br /><br />
= Setting Up SSH =<br />
* As a security measure, SSH is not enabled by default on headless (= Raspbian Lite, without GUI) installations. Place a file named "ssh" into the root folder of the boot partition (= ''/boot'') to enable SSH.<br />
* In the web browser go to the configuration page of your home Internet router (e.g., http://192.168.1.1).<br />
* Open the page that lists all currently connected LAN devices.<br />
* Connect the Raspberry Pi via Ethernet cable to the LAN router.<br />
* Look for a new entry in the list of LAN devices. That should be your Raspberry Pi. Note the IP address. Let's assume it is ''192.168.1.10''.<br />
* Optional: You should be able to read the [https://en.wikipedia.org/wiki/MAC_address MAC address] of the Raspberry Pi from the table. For future reference, write down the MAC address somewhere.<br />
* Open Terminal and type '''ssh pi@192.168.1.10''' to log in via SSH. On a fresh Raspbian installation the username is '''pi''' and the password is '''raspberry'''.<br />
* After logging in type '''sudo raspi-config''' to start the Raspbian configuration tool, where you can change the password or expand the filesystem to take up the whole SD card, among other things.<br />
<br /><br />
<br /><br />
= Setting Up WiFi =<br />
== Raspberry Pi 2 ==<br />
The Raspberry Pi 2 does not have built-in WiFi. I assume that you are using a USB WiFi adapter. Before connecting the adapter you need to edit the network interfaces on the Raspberry Pi. Log in to the Raspberry Pi over SSH and edit '''/etc/network/interfaces''' as follows:<br />
<br /><br />
<pre class="code"><br />
auto lo<br />
<br />
iface lo inet loopback<br />
iface eth0 inet dhcp<br />
<br />
allow-hotplug wlan0<br />
auto wlan0<br />
<br />
iface wlan0 inet dhcp<br />
wpa-ssid "ssid"<br />
wpa-psk “password"<br />
</pre><br />
<br /><br />
where ''ssid'' is the SSID (a.k.a. name) of your WLAN router, and ''password'' is supplied in encoded form. Do not type the quotation marks. The password is encoded by running<br />
<br /><br />
<pre class="terminal"><br />
wpa_passphrase <ssid> <password><br />
</pre><br />
<br /><br />
If your WLAN router uses a hidden SSID use this configuration:<br />
<pre class="code"><br />
auto lo<br />
<br />
iface lo inet loopback<br />
iface eth0 inet dhcp<br />
<br />
auto wlan0<br />
allow-hotplug wlan0<br />
iface wlan0 inet dhcp<br />
wpa-scan-ssid 1<br />
wpa-ap-scan 1<br />
wpa-key-mgmt WPA-PSK<br />
wpa-proto RSN WPA<br />
wpa-pairwise CCMP TKIP<br />
wpa-group CCMP TKIP<br />
wpa-ssid "My Secret SSID"<br />
wpa-psk "My SSID PSK”<br />
<br />
iface default inet dhcp<br />
</pre><br />
<br /><br />
Instead of putting the WPA configuration directly into '''interfaces''' you can put it into the file '''/etc/wpa_supplicant/wpa_supplicant.conf'''<br />
<pre class="code"><br />
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev<br />
update_config=1<br />
<br />
network={<br />
ssid="<your ssid>"<br />
psk=<your encoded password given by running wpa_passphrase><br />
scan_ssid=1<br />
proto=WPA RSN<br />
key_mgmt=WPA-PSK<br />
pairwise=CCMP TKIP<br />
}<br />
</pre><br />
<br /><br />
and refer to it from '''interfaces''' like so<br />
<pre class="code"><br />
auto lo<br />
iface lo inet loopback<br />
<br />
iface eth0 inet dhcp<br />
<br />
allow-hotplug wlan0<br />
iface wlan0 inet dhcp<br />
wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf<br />
<br />
iface default inet dhcp<br />
</pre><br />
<br /><br />
<br /><br />
<br />
== Raspberry Pi 3 or newer ==<br />
The Raspberry Pi 3 has a WLAN transmitter built in and it is turned on by default. You should see the device '''wlan0''' along with '''eth0''' and '''lo''' when typing<br />
<br /><br />
<pre class="terminal"><br />
ifconfig -a<br />
</pre><br />
<br /><br />
Make sure the Raspberry Pi can log in to your WLAN router. If a MAC filter is active, add the Raspberry Pi WiFi MAC address to the list of allowed devices. The MAC address of the Pi is displayed in the output of ''ifconfig -a'' as '''HWaddr'''. Open a text editor to add the network configuration details, such as your login credentials, to the file ''/etc/wpa_supplicant/wpa_supplicant.conf''.<br />
<br /><br />
<pre class="code"><br />
network={<br />
ssid="MySSID"<br />
psk=MyCodedPassword<br />
scan_ssid=1<br />
proto=WPA RSN<br />
key_mgmt=WPA-PSK<br />
pairwise=CCMP TKIP<br />
}<br />
</pre><br />
<br /><br />
where '''MySSID''' is the SSID (a.k.a. name) of the router, and '''MyCodedPassword''' is the encoded password obtained via<br />
<br /><br />
<pre class="terminal"><br />
wpa_passphrase MySSID MyPassword<br />
</pre><br />
and where '''MyPassword''' is the actual password.<br />
<br /><br />
<br /><br />
<br />
== Power Saving ==<br />
If the WiFi connection is unstable you can turn off the WiFi power management feature, which may cause connection dropouts, by issuing the command<br />
<pre class="terminal"><br />
sudo iw dev wlan0 set power_save off<br />
</pre><br />
or by manually editing '''/etc/network/interfaces''', where you add the line<br />
<pre class="code"><br />
wireless-power off<br />
</pre><br />
right after the line<br />
<pre class="code"><br />
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf<br />
</pre><br />
within the '''wlan0''' block. You can check whether power management is currently turned on or off, among other parameters, with the command<br />
<pre class="terminal"><br />
iwconfig<br />
</pre><br />
<br /><br />
<br /><br />
For Raspberry Pi 2 and WiFi dongles with 8192CU or 8188CUS chip (for example, Edimax EW-7811un dongles)you can prevent connections from being dropped by creating the file '''/etc/modprobe.d/8192cu.conf'''<br />
<br><br />
<pre class="terminal"><br />
sudo nano /etc/modprobe.d/8192cu.conf<br />
</pre><br />
and adding the line<br />
<br /><br />
<pre class="code"><br />
options 8192cu rtw_power_mgnt=0 rtw_enusbss=0<br />
</pre><br />
<br /><br />
<br />
= Camera =<br />
There is a [https://www.raspberrypi.org/products/camera-module/ camera module] for Raspberry Pi, which I use in my robots. In fact, the camera module is part of the [[Core Module]].<br />
<br /><br />
<br /><br />
Refer to the official [https://www.raspberrypi.org/documentation/usage/camera/README.md camera setup instructions]. Be careful with the camera module, handle the camera board and the connector strip delicately.<br />
<br /><br />
<br /><br />
To be able to access the camera through the Python programming environment you need to install the '''python-picamera''' package<br />
<br /><br />
<br /><br />
The Raspberry Pi project does not provide a C/C++ library for accessing the camera. Instead it provides utility applications ''raspistill'' and ''raspivid'' which record still images and videos, respectively. A number of third-party C++ libraries have been created based on the open source code of these utility applications. The [http://www.uco.es/investiga/grupos/ava/node/40 RaspiCam] C++ library developed at the University of Cordoba is one such library (source code available [https://sourceforge.net/projects/raspicam/ from SourceForge]).<br />
<br /><br />
<br /><br />
== Video Streaming ==<br />
To stream video from the Raspberry Pi camera to the network, open a terminal on the RPi and type<br />
<pre class="terminal"><br />
raspivid -t 0 -w 1280 -h 720 -hf -ih -fps 30 -o - | nc -k -l 8100<br />
</pre><br />
<br /><br />
To view the stream on a client computer with [http://www.mplayerhq.hu Mplayer] installed, open a terminal there and type<br />
<pre class="terminal"><br />
mplayer -fps 300 -demuxer h264es ffmpeg://tcp://192.168.0.20:8100<br />
</pre><br />
<br /><br />
<br /><br />
Alternatively, you can use [[GStreamer]] to transport the video frames. Make sure that the command line interface to GStreamer, ''gst-launch-1.0'', is installed. <br />
<pre class="terminal"><br />
sudo apt install gstreamer1.0-tools<br />
</pre><br />
<br /><br />
For streaming from the RPi you can type<br />
<pre class="terminal"><br />
raspivid -t 0 -w 640 -h 480 -fps 30 -hf -b 2000000 -o - | gst-launch-1.0 -q fdsrc ! h264parse ! rtph264pay config-interval=1 pt=96 ! gdppay ! tcpserversink host=0.0.0.0 port=8100<br />
</pre><br />
<br /><br />
For viewing on the client, you can type<br />
<pre class="terminal"><br />
gst-launch-1.0 -v tcpclientsrc host=192.168.0.20 port=8100 ! gdpdepay ! rtph264depay ! avdec_h264 ! videoconvert ! videoflip method=vertical-flip ! autovideosink sync=false<br />
</pre><br />
where ''192.168.0.20'' is assumed to be the IP address of the server (Raspberry Pi).<br />
<br /><br />
<br /><br />
* On the Raspberry Pi side you can elevate the priority of the process by beginning the command with ''"nice -20"''.<br />
* For verbose output from ''gst-launch-1.0'', use the option ''-v'' instead of ''-q''.<br />
* Note that we used the [https://gstreamer.freedesktop.org/documentation/videofilter/videoflip.html?gi-language=c#GstVideoFlipMethod videoflip] filter to correct the rotation of the decoded image.<br />
<br /><br />
=== Disabling the LED ===<br />
To disable the red indicator light of the camera, add the following line to '''/boot/config.txt''' and reboot:<br />
<pre class="code"><br />
disable_camera_led=1<br />
</pre><br />
<br /><br />
<br />
= pinout =<br />
A cool command-line tool provided by Raspberry Pi, and also available when running Ubuntu instead of Raspberry Pi OS, is '''pinout'''. It displays a layout of the Raspberry Pi board using ASCII art, a list of significant hardware features of the board, and the GPIO pin layout in tabular form.<br />
<br /><br />
<pre class="terminal"><br />
sudo apt install python3-gpiozero<br />
pinout<br />
</pre><br />
<br /><br />
[[File:Raspberry_Pi_pinout_command.png | x600px]]<br />
<br /><br />
<br /><br />
<br />
= raspi-gpio =<br />
The documentation states that ''"raspi-gpio can get and print the state of a GPIO (or all GPIOs) and can be used to set the function, pulls and value of a GPIO. raspi-gpio must be run as root."''<br />
"<br />
<pre class="terminal"><br />
> sudo apt install raspi-gpio<br />
> raspi-gpio funcs 20,21,22<br />
GPIO, DEFAULT PULL, ALT0, ALT1, ALT2, ALT3, ALT4, ALT5<br />
20, DOWN, PCM_DIN, SD12, DPI_D16, SPI6_MOSI, SPI1_MOSI, GPCLK0<br />
21, DOWN, PCM_DOUT, SD13, DPI_D17, SPI6_SCLK, SPI1_SCLK, GPCLK1<br />
22, DOWN, SD0_CLK, SD14, DPI_D18, SD1_CLK, ARM_TRST, SDA6<br />
> raspi-gpio get 20<br />
GPIO 20: level=0 func=INPUT pull=DOWN<br />
GPIO 21: level=1 func=INPUT pull=DOWN<br />
GPIO 22: level=0 func=INPUT pull=DOWN<br />
> raspi-gpio raw 21<br />
00: 00000000 00012000 12000000 3fffffff<br />
10: 24000040 00000924 00000000 6770696f<br />
20: 6770696f 6770696f 6770696f 6770696f<br />
30: 6770696f 102081ff 00003bfb 00000000<br />
40: 00000000 00000000 00000000 00000000<br />
50: 00000000 00000000 00000000 00000000<br />
60: 00000000 00000000 00000000 00000000<br />
70: 00000000 00000000 00000000 00000000<br />
80: 00000000 00000000 00000000 00000000<br />
90: 00000000 00000000 00000000 00000000<br />
e0: 4aa95555 19aaaaaa 50aa5544<br />
f0: 000aaaaa<br />
</pre><br />
<br /><br />
<br />
= GPIO Programming in C =<br />
Raspberry Pi 2, 3 & 4 come with 40 ''General Purpose Input Output'' (GPIO) pins ([https://www.raspberrypi.com/documentation/computers/os.html#gpio-and-the-40-pin-header layout]) that can be used to interface with the other electronic components of your project.<br />
<br />
== Using libgpiod ==<br />
The standard C++ programming interface for GPIO on Linux is ''libgpiod'', as described on [[Nvidia_Jetson#Using_Libgpiod | the Jetson page]].<br />
<br />
== Using WiringPi ==<br />
Using the [http://wiringpi.coml WiringPi] library is a more popular method for programming the GPIO pins on a Raspberry Pi with C/C++. WiringPi is [http://wiringpi.com/download-and-install installed from source] like this<br />
<pre class="terminal"><br />
sudo apt-get install git-core<br />
git clone git://git.drogon.net/wiringPi<br />
cd wiringPi<br />
./build<br />
</pre><br />
Read the ''INSTALL'' file for what to do with the created shared library. Basically you need to copy ''wiringPi/libwiringPi.so.x.xx'' to ''/usr/local/lib'' and add the line<br />
<pre class="code"><br />
include /usr/local/lib<br />
</pre><br />
to the file ''/etc/ld.so.conf'' so that the library loader also looks in ''/usr/local/lib'' for dynamically loadable libraries. It is also possible to create a static library.<br />
<br /><br />
<br/><br />
After installation, create a test program called ''blink.cpp''<br />
<pre class="code"><br />
#include <stdio.h><br />
#include <iostream><br />
#include <wiringPi.h><br />
<br />
static int LED_PORT = 7; // The physical pin number. Corresponds to BCM GPIO pin 4.<br />
<br />
void blink()<br />
{<br />
digitalWrite(4, HIGH);<br />
delay(1000);<br />
digitalWrite(4, LOW);<br />
delay(1000);<br />
};<br />
<br />
int main(int numargs, char** args)<br />
{<br />
wiringPiSetup();<br />
pinMode(LED_PORT, OUTPUT);<br />
for (int n = 0; n < 10; n++)<br />
{<br />
blink();<br />
}<br />
std::cout << "finished blinking" << std::endl;<br />
return 0;<br />
}<br />
</pre><br />
and build like this<br />
<pre class="terminal"><br />
g++ blink.cpp -o blink -lstdc++ -lwiringPi -IwiringPi<br />
</pre><br />
where I assumed that the wiringPi root folder is located in the same folder as the ''blink.cpp'' source file.<br />
<br /><br />
<br/><br />
Which pins can be used for what purpose is explained on the [http://wiringpi.com/pins wiringPi pins] page.<br />
<br /><br />
<br/><br />
<br />
= PWM =<br />
There are some Python libraries that communicate with the GPIO daemon to provide hardware PWM on selected pins. [https://gpiozero.readthedocs.org/ GPIO Zero] ([https://www.raspberrypi.org/blog/gpio-zero-a-friendly-python-api-for-physical-computing/ tutorial]) is one such library and is included in [https://www.raspberrypi.org/downloads/raspbian/ Raspbian]. With GPIO Zero you can implement dimming LEDs or control a brushed DC motor behind an [https://en.wikipedia.org/wiki/H_bridge H-Bridge] circuit.<br />
<br />
<br /><br />
= Running A Program On Startup =<br />
== Using SysVInit ==<br />
We want the Raspberry Pi to start the robot control program as soon as it's done with booting. In order to make sure that the system has completely initialized itself we will not use ''/etc/rc.local'' for starting our program. Instead, we will create a ''cron'' task with the ''crontab'' command<br />
<br /><br />
<pre class="terminal"><br />
sudo crontab -e<br />
</pre><br />
which opens the editor of choice (most likely ''nano'') where you can enter the program launch command. In our case this will be<br />
<pre class="code"><br />
@reboot python /home/pi/Core.py<br />
</pre><br />
where the leading ''@reboot'' indicates to ''cron'' that this command shall be executed only once, right after the booting process has completed. Notice that it is not necessary to start the command with ''sudo'', which is necessary when running program from the command line.<br />
<br /><br />
<br />
== Using Systemd ==<br />
<br /><br />
<br />
<br /><br />
<br />
= Communicating With Other Devices =<br />
There are three popular communication protocols that the Raspberry Pi supports and that are often used in embedded systems: I<sup>2</sup>C, SPI, and UART.<br />
<br /><br />
<br /><br />
<br />
== I<sup>2</sup>C ==<br />
Set the [[I2C | I<sup>2</sup>C]] clock speed by editing '''/boot/config.txt'''<br />
<pre class="code"><br />
dtparam=i2c1=on<br />
dtparam=i2c_arm_baudrate=xxx<br />
</pre><br />
where ''xxx'' is the desired frequency. Keep in mind that ATmega microcontrollers used on Arduino boards support only up to 400 kHz while Raspberry Pi can support higher speeds.<br />
<br /><br />
<br /><br />
=== Wiring To I<sup>2</sup>C Devices With 5 V Logic Level ===<br />
Normally you can not connect a GPIO pin to a device with 5 V logic (most of the Arduino models, for example). The GPIO data pins of the Raspberry Pi use 3.3 V as the HIGH voltage level and can be damaged when 5 V is applied. However, because I<sup>2</sup>C pins have [https://en.wikipedia.org/wiki/Open_collector open-collector] outputs they can be wired directly to I<sup>2</sup>C pins of devices with incompatible voltage levels. As long as the pull-up line voltage, which corresponds to the lowest of the device HIGH voltage levels, exceeds the minimum voltage for which HIGH is defined on each device, the devices will be able to sense the correct data bit.<br />
<br /><br />
<br /><br />
Links:<br />
* [https://learn.sparkfun.com/tutorials/i2c Tutorial by SparkFun] on I<sup>2</sup>C<br />
* [https://learn.adafruit.com/adafruits-raspberry-pi-lesson-4-gpio-setup?view=all Article by Adafruit] on how to set up I<sup>2</sup>C and SPI on a Raspberry Pi<br />
* Tutorial for setting up an I2C bus [http://blog.oscarliang.net/raspberry-pi-arduino-connected-i2c/ between a Raspberry Pi and an Arduino].<br />
<br /><br />
<br />
== SPI ==<br />
First of all, you need to use the ''raspi-config'' command-line configuration utility to enable the SPI pins.<br />
<pre class="terminal"><br />
sudo raspi-config<br />
</pre><br />
<br /><br />
You can use [http://wiringpi.com/reference/spi-library/ WiringPi SPI] to add SPI capability to your C/C++ program.<br />
<br /><br />
<br /><br />
<br />
== UART ==<br />
[http://www.andremiller.net/content/raspberry-pi-and-arduino-via-gpio-uart Here is a tutorial] that shows how to communicate with an Arduino using the UART interface.<br />
<br /><br />
<br /><br />
<br />
== CAN ==<br />
There are various [[CAN]] adapter boards available for Raspberry Pi. For example [http://skpang.co.uk/catalog/pican2-canbus-board-for-raspberry-pi-2-p-1475.html PiCAN2].<br />
<br /><br />
<br /><br />
<br />
= Device Tree Overlays =<br />
A device tree overlay is a mechanism in Raspberry Pi computers to dynamically apply changes to existing device trees. This mechanism is mostly used to enable kernel-space support for hardware components that are attached to the Raspberry Pi via its GPIO headers.<br />
<br /><br />
<br /><br />
Operations with device tree overlays are performed by the Raspberry Pi GPU (VideoCore), without needing to preempt the Linux kernel. The Raspberry Pi primary bootloader, also a VideoCore firmware application, makes use of this device tree parsing and editing capability to apply device tree overlays during the boot process, before passing control to the Linux kernel.<br />
<br /><br />
==== /boot/config.txt ====<br />
The primary bootloader parses and interprets the ''/boot/config.txt'' file. It specifies, among other things, which device tree to select and which overlays to apply.<br />
<br /><br />
==== dtoverlay ====<br />
'''dtoverlay''' is the command-line tool for loading a device tree overlay (or unloading a previously loaded overlay) while the Linux system is running.<br />
<pre class="terminal"><br />
</pre><br />
<br /><br />
<br />
= VideoCore Device Tree Blob =<br />
VideoCore functions both as the GPU of the Raspberry Pi and as a separately programmable unit that connects to a number of I/O devices. The pin assignments for connecting to external devices can be customized through a user-provided device tree blob file, '''dt-blob.bin'''. See [https://www.raspberrypi.com/documentation/computers/configuration.html#changing-the-default-pin-configuration Raspberry Pi's documentation on the VideoCore device tree blob]. This configuration feature is necessary for adapting a compute module to the hardware configuration of a project. <br />
<br /><br />
<br /><br />
Below is an example configuration for a Compute Module 4 in which a MIPI CSI-2 camera and a MIPI DSI display are accessed at specific I<sup>2</sup>C pins:<br />
<pre class="code"><br />
/dts-v1/;<br />
<br />
// Enabling MIPI DSI display and MIPI CSI-2 camera for<br />
// WaveShare CM4-Nano B (https://www.waveshare.com/wiki/CM4-NANO-B).<br />
<br />
/ {<br />
videocore {<br />
<br />
pins_cm4 { // Pi 4 CM4<br />
pin_config {<br />
pin@default {<br />
polarity = "active_high";<br />
termination = "pull_down";<br />
startup_state = "inactive";<br />
function = "input";<br />
}; // pin<br />
pin@p0 { function = "input"; termination = "pull_up"; }; // CAMERA 0 I2C0 SDA<br />
pin@p1 { function = "input"; termination = "pull_up"; }; // CAMERA 0 I2C0 SCL<br />
pin@p44 { function = "input"; termination = "pull_up"; }; // DISPLAY 1 I2C0 SDA<br />
pin@p45 { function = "input"; termination = "pull_up"; }; // DISPLAY 1 I2C0 SCL<br />
<br />
pin@p128 { function = "output"; termination = "no_pulling"; }; // BT_ON<br />
pin@p129 { function = "output"; termination = "no_pulling"; }; // WL_ON<br />
pin@p131 { function = "output"; termination = "no_pulling"; }; // ANT1<br />
pin@p133 { function = "output"; termination = "no_pulling"; }; // Camera shutdown<br />
<br />
}; // pin_config<br />
<br />
pin_defines {<br />
pin_define@HDMI_CONTROL_ATTACHED {<br />
type = "external";<br />
number = <0>;<br />
};<br />
pin_define@EMMC_ENABLE {<br />
type = "external";<br />
number = <1>;<br />
};<br />
pin_define@NUM_CAMERAS {<br />
type = "internal";<br />
number = <1>;<br />
};<br />
pin_define@POWER_LOW {<br />
type = "absent";<br />
};<br />
pin_define@LEDS_DISK_ACTIVITY {<br />
type = "absent";<br />
};<br />
pin_define@LAN_RUN {<br />
type = "absent";<br />
};<br />
pin_define@BT_ON {<br />
type = "external";<br />
number = <0>;<br />
};<br />
pin_define@WL_ON {<br />
type = "external";<br />
number = <1>;<br />
};<br />
pin_define@ETH_CLK {<br />
type = "absent";<br />
};<br />
pin_define@WL_LPO_CLK {<br />
type = "absent";<br />
};<br />
pin_define@USB_LIMIT_1A2 {<br />
type = "absent";<br />
};<br />
pin_define@SIO_1V8_SEL {<br />
type = "absent";<br />
};<br />
pin_define@SAFE_MODE {<br />
type = "absent";<br />
};<br />
<br />
// Display<br />
<br />
pin_define@DISPLAY_I2C_PORT {<br />
type = "internal";<br />
number = <0>;<br />
};<br />
pin_define@DISPLAY_SDA {<br />
type = "internal";<br />
number = <44>;<br />
};<br />
pin_define@DISPLAY_SCL {<br />
type = "internal";<br />
number = <45>;<br />
};<br />
pin_define@DISPLAY_DSI_PORT {<br />
type = "internal";<br />
number = <1>;<br />
};<br />
<br />
// Camera<br />
<br />
pin_define@CAMERA_0_I2C_PORT {<br />
type = "internal";<br />
number = <0>;<br />
};<br />
pin_define@CAMERA_0_SDA_PIN {<br />
type = "internal";<br />
number = <0>;<br />
};<br />
pin_define@CAMERA_0_SCL_PIN {<br />
type = "internal";<br />
number = <1>;<br />
};<br />
pin_define@CAMERA_0_SHUTDOWN {<br />
type = "external";<br />
number = <5>;<br />
};<br />
pin_define@CAMERA_0_UNICAM_PORT {<br />
type = "internal";<br />
number = <0>;<br />
};<br />
pin_define@CAMERA_0_LED {<br />
type = "absent";<br />
};<br />
}; // pin_defines<br />
}; // pins<br />
<br />
};<br />
};<br />
</pre><br />
<br /><br />
<br />
= Yocto Tips =<br />
== Creating Kernel Patches for Compute Module 4 ==<br />
A compute module does not know what hardware components its carrier board provides unless the default device tree is modified to include the interfaces to these hardware components. Instead of providing a different complete device tree, you would normally [[Yocto#Patching_A_Device_Tree | create a patch]] for the device tree source file provided by a lower Yocto layer.<br />
<br /><br />
<br /><br />
The modified device tree must be based on the device tree used by the kernel in Yocto. For Compute Module 4, the device tree file to patch is<br />
: ''${YOCTO_BUILD_DIR}'''''/tmp/work-shared/raspberrypi4-64/kernel-source/arch/arm/boot/dts/bcm2711-rpi-cm4.dts'''<br />
Copy this file to your layer's recipe directory and edit the copy to add the peripherals. The Raspberry Pi reference device tree files at the [https://datasheets.raspberrypi.com/ Raspberry Pi Datasheets collection page] can be helpful in creating your modified device tree.<br />
<br /><br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Raspberry_Pi&diff=3164Raspberry Pi2022-12-25T19:52:39Z<p>Kai: Adds Compute Module 4 example device tree with camera and display.</p>
<hr />
<div>= Introduction =<br />
The [http://raspberrypi.org Raspberry Pi Ltd.] is a company producing small and affordable single-board, bare-bones computer systems, microcontrollers and accessories, marketed under the ''Raspberry Pi'' brand. All Raspberry Pi computing products use Arm-based processors. I use Raspberry Pi computers as [[Robot Task Controller | task controller]], and the microcontrollers as [[Robot State Agent | state agent]] in my robots.<br />
<br /><br />
<br /><br />
= Processors and Architectures =<br />
<br />
* [https://developer.arm.com/Processors/Cortex-A7 Arm Cortex-A7] with 32-bit Armv7 programming model<br />
** Raspberry Pi 2 B (Broadcom BCM2836 processor @ 900 MHz)<br />
<br /><br />
<br />
* [https://developer.arm.com/Processors/Cortex-A53 Arm Cortex-A53] with 64-bit Armv8-A programming model.<br />
** Raspberry Pi 2 B rev 1.2 (Broadcom BCM2837 processor @ 900 MHz)<br />
** Raspberry Pi 3 B (Broadcom BCM2837 processor @ 1.2 GHz)<br />
** Raspberry Pi 3 B+ (Broadcom BCM2837B0 processor @ 1.4 GHz)<br />
** Raspberry Pi Zero 2 W (@ 1 GHz)<br />
<br /><br />
<br />
* [https://developer.arm.com/Processors/Cortex-A72 Arm Cortex-A72] with 64-bit Armv8-A programming model<br />
** Raspberry Pi 4 (Broadcom BCM2711 processor @ 1.5 GHz)<br />
** Compute Module 4 (Broadcom BCM2711 @ 1.5 GHz)<br />
<br /><br />
<br />
* [https://developer.arm.com/Processors/Cortex-M0+ Arm Cortex-M0+] with Armv6-M programming model<br />
** Raspberry Pi Pico (up to 133 MHz)<br />
<br /><br />
<br />
= Installing a System Image =<br />
[https://www.raspberrypi.com/software/operating-systems/ Raspberry Pi OS] is the offical operating system of a Raspberry Pi. The Lite version, without a graphical desktop, is recommended for embedded applications unless you decide to create a custom system image. The fewer software modules are running, the lower the power consumption, and the lower the chance that user-space processes will be interrupted.<br />
<br /><br />
<br /><br />
== Installing the System Image on SD Card ==<br />
This is the most popular method of installing a system image on a single-board computers. SD cards are cheap and reusable, almost all Raspberry Pi models come with an SD card reader. However, SD card memory is not designed to support frequent rewrite operations and may not be as durable as other storage solutions. <br />
<br />
The preferred way of putting a system image on an SD card is to use the [https://www.raspberrypi.com/software Raspberry Pi Imager] tool that can fetch a Raspberry Pi OS image over the Internet or use a local image file, create a derived image with preconfigured user credentials, WLAN access and more, before writing it to the SD card.<br />
<br />
=== Using built-in tools on Linux ===<br />
The SD card can also be prepared by using standard Linux tools instead of Raspberry Pi Imager. First, we need to find out which device to copy the install image to. Type<br />
<pre class="terminal"><br />
df -h<br />
</pre><br />
or<br />
<pre class="terminal"><br />
sudo fdisk --list<br />
</pre><br />
in the command terminal to look up the mount point for the SD card. Let us assume the card was mounted as ''/dev/sdb2''. The card needs to be unmounted before we can copy the downloaded Raspberry Pi OS install image:<br />
<br /><br />
<pre class="terminal"><br />
umount /dev/sdb2<br />
</pre><br />
<br /><br />
Copy the image to the card with the ''dd'' command:<br />
<pre class="terminal"><br />
sudo dd bs=4M if=2021-01-11-raspios-buster-armhf-lite.img of=/dev/sdb<br />
</pre><br />
where we use the path to the device file ''/dev/sdb'' instead of the partition ''/dev/sdb2'', which was unmounted. The option ''bs'' is used for adjusting the buffer size for the writing operation.<br />
<br /><br />
<br /><br />
<br />
=== Using built-in tools on macOS ===<br />
On Apple macOS, you can use the built-in 'diskutil' tool as an alternative to the Raspberry Pi Imager. First, attach the SD card to your Mac and determine the assigned disk number ''disk#'' (e.g., disk2) under which the card has been mounted to the filesystem by opening Terminal and typing<br />
<br /><br />
<pre class="terminal"><br />
diskutil list<br />
</pre><br />
then unmount the disk<br />
<pre class="terminal"><br />
diskutil unmountDisk disk2<br />
</pre><br />
and copy the data with the ''dd'' tool<br />
<pre class="terminal"><br />
sudo dd bs=1m if=~/Downloads/raspios.img of=/dev/rdisk2<br />
</pre><br />
where I assume that the downloaded and <u>unzipped</u> Raspberry Pi OS image file is located at ''~/Downloads/raspios.img'' and the SD card was mounted as ''disk2''.<br />
<br /><br />
<br />
== Installing the System Image on eMMC ==<br />
Some Raspberry Pi models, like the Compute Module 4, come with an embedded MultiMediaCard (eMMC) storage component. A switch or jumper on the carrier board serves to make the Raspberry Pi bootloader boot the compute module into USB mass storage mode. In this mode you can attach the compute module to an external computer via USB. On Ubuntu you can use the<br />
<pre class="terminal"><br />
lsusb<br />
</pre><br />
command to list all connected USB devices. The Compute Module 4, for example, should show up as "Broadcom Corp. BCM2711 Boot".<br />
<br /><br />
To make the operating system recognize the USB device as a mass storage device, we need to build and run Raspberry Pi's ''rpiboot'' tool.<br />
<pre class="terminal"><br />
sudo apt install libusb-1.0-0-dev<br />
git clone --depth=1 https://github.com/raspberrypi/usbboot<br />
cd usbboot<br />
make<br />
sudo ./rpiboot<br />
</pre><br />
On Ubuntu, ''lsusb'' will now list the Compute Module 4 as "Broadcom Corp. Compute Module". The compute module will also show up in the ''Disks'' app as ''RPi-MSD-0001''.<br />
<br /><br />
[[File: raspberrypi_emmc_shows_up_in_disks_app.png | x300px ]]<br />
<br /><br />
You can now use Raspberry Pi Imager or any flashing utility to flash a system image on the compute module eMMC.<br />
<br /><br />
<br /><br />
<br />
= Upgrading a Raspberry Pi OS Installation =<br />
You don't want to erase your existing Raspberry Pi OS environment and set up all the software from start each time a new version of Raspberry Pi OS is released. Fortunately, [https://www.raspberrypi.com/documentation/computers/os.html#updating-and-upgrading-raspberry-pi-os Raspberry Pi OS can upgrade itself to the latest release] with the following commands.<br />
<pre class="terminal"><br />
sudo apt-get update<br />
sudo apt-get dist-upgrade<br />
</pre><br />
<br /><br />
<br /><br />
<br />
= Assigning a Static Ethernet IP Address =<br />
Edit the file '''/etc/network/interfaces''' and make sure that the entries for the interface ''eth0'' are as follows:<br />
<pre class="terminal"><br />
auto eth0<br />
iface eth0 inet static<br />
address 192.168.0.20<br />
netmask 255.255.255.0<br />
broadcast 192.168.0.255<br />
</pre><br />
where the IP address ''192.168.0.20'' is just an example.<br />
<br /><br />
<br /><br />
Make sure you don't break the WiFi connectivity because of editing ''/etc/network/interfaces''. If there is no empty describing ''wlan0'' we will need to create one. For dynamically assigned IPs via DHCP you will need these lines:<br />
<pre class="terminal"><br />
auto wlan0<br />
iface wlan0 inet dhcp<br />
wpa-ssid <your WiFi router name (SSID)><br />
wpa-psk <your WiFi password><br />
</pre><br />
<br /><br />
The new network setting becomes effective on the next system boot or when you type<br />
<pre class="terminal"><br />
sudo ifdown eth0<br />
sudo ifup eth0<br />
</pre><br />
<br /><br />
<br /><br />
= Setting Up SSH =<br />
* As a security measure, SSH is not enabled by default on headless (= Raspbian Lite, without GUI) installations. Place a file named "ssh" into the root folder of the boot partition (= ''/boot'') to enable SSH.<br />
* In the web browser go to the configuration page of your home Internet router (e.g., http://192.168.1.1).<br />
* Open the page that lists all currently connected LAN devices.<br />
* Connect the Raspberry Pi via Ethernet cable to the LAN router.<br />
* Look for a new entry in the list of LAN devices. That should be your Raspberry Pi. Note the IP address. Let's assume it is ''192.168.1.10''.<br />
* Optional: You should be able to read the [https://en.wikipedia.org/wiki/MAC_address MAC address] of the Raspberry Pi from the table. For future reference, write down the MAC address somewhere.<br />
* Open Terminal and type '''ssh pi@192.168.1.10''' to log in via SSH. On a fresh Raspbian installation the username is '''pi''' and the password is '''raspberry'''.<br />
* After logging in type '''sudo raspi-config''' to start the Raspbian configuration tool, where you can change the password or expand the filesystem to take up the whole SD card, among other things.<br />
<br /><br />
<br /><br />
= Setting Up WiFi =<br />
== Raspberry Pi 2 ==<br />
The Raspberry Pi 2 does not have built-in WiFi. I assume that you are using a USB WiFi adapter. Before connecting the adapter you need to edit the network interfaces on the Raspberry Pi. Log in to the Raspberry Pi over SSH and edit '''/etc/network/interfaces''' as follows:<br />
<br /><br />
<pre class="code"><br />
auto lo<br />
<br />
iface lo inet loopback<br />
iface eth0 inet dhcp<br />
<br />
allow-hotplug wlan0<br />
auto wlan0<br />
<br />
iface wlan0 inet dhcp<br />
wpa-ssid "ssid"<br />
wpa-psk “password"<br />
</pre><br />
<br /><br />
where ''ssid'' is the SSID (a.k.a. name) of your WLAN router, and ''password'' is supplied in encoded form. Do not type the quotation marks. The password is encoded by running<br />
<br /><br />
<pre class="terminal"><br />
wpa_passphrase <ssid> <password><br />
</pre><br />
<br /><br />
If your WLAN router uses a hidden SSID use this configuration:<br />
<pre class="code"><br />
auto lo<br />
<br />
iface lo inet loopback<br />
iface eth0 inet dhcp<br />
<br />
auto wlan0<br />
allow-hotplug wlan0<br />
iface wlan0 inet dhcp<br />
wpa-scan-ssid 1<br />
wpa-ap-scan 1<br />
wpa-key-mgmt WPA-PSK<br />
wpa-proto RSN WPA<br />
wpa-pairwise CCMP TKIP<br />
wpa-group CCMP TKIP<br />
wpa-ssid "My Secret SSID"<br />
wpa-psk "My SSID PSK”<br />
<br />
iface default inet dhcp<br />
</pre><br />
<br /><br />
Instead of putting the WPA configuration directly into '''interfaces''' you can put it into the file '''/etc/wpa_supplicant/wpa_supplicant.conf'''<br />
<pre class="code"><br />
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev<br />
update_config=1<br />
<br />
network={<br />
ssid="<your ssid>"<br />
psk=<your encoded password given by running wpa_passphrase><br />
scan_ssid=1<br />
proto=WPA RSN<br />
key_mgmt=WPA-PSK<br />
pairwise=CCMP TKIP<br />
}<br />
</pre><br />
<br /><br />
and refer to it from '''interfaces''' like so<br />
<pre class="code"><br />
auto lo<br />
iface lo inet loopback<br />
<br />
iface eth0 inet dhcp<br />
<br />
allow-hotplug wlan0<br />
iface wlan0 inet dhcp<br />
wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf<br />
<br />
iface default inet dhcp<br />
</pre><br />
<br /><br />
<br /><br />
<br />
== Raspberry Pi 3 or newer ==<br />
The Raspberry Pi 3 has a WLAN transmitter built in and it is turned on by default. You should see the device '''wlan0''' along with '''eth0''' and '''lo''' when typing<br />
<br /><br />
<pre class="terminal"><br />
ifconfig -a<br />
</pre><br />
<br /><br />
Make sure the Raspberry Pi can log in to your WLAN router. If a MAC filter is active, add the Raspberry Pi WiFi MAC address to the list of allowed devices. The MAC address of the Pi is displayed in the output of ''ifconfig -a'' as '''HWaddr'''. Open a text editor to add the network configuration details, such as your login credentials, to the file ''/etc/wpa_supplicant/wpa_supplicant.conf''.<br />
<br /><br />
<pre class="code"><br />
network={<br />
ssid="MySSID"<br />
psk=MyCodedPassword<br />
scan_ssid=1<br />
proto=WPA RSN<br />
key_mgmt=WPA-PSK<br />
pairwise=CCMP TKIP<br />
}<br />
</pre><br />
<br /><br />
where '''MySSID''' is the SSID (a.k.a. name) of the router, and '''MyCodedPassword''' is the encoded password obtained via<br />
<br /><br />
<pre class="terminal"><br />
wpa_passphrase MySSID MyPassword<br />
</pre><br />
and where '''MyPassword''' is the actual password.<br />
<br /><br />
<br /><br />
<br />
== Power Saving ==<br />
If the WiFi connection is unstable you can turn off the WiFi power management feature, which may cause connection dropouts, by issuing the command<br />
<pre class="terminal"><br />
sudo iw dev wlan0 set power_save off<br />
</pre><br />
or by manually editing '''/etc/network/interfaces''', where you add the line<br />
<pre class="code"><br />
wireless-power off<br />
</pre><br />
right after the line<br />
<pre class="code"><br />
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf<br />
</pre><br />
within the '''wlan0''' block. You can check whether power management is currently turned on or off, among other parameters, with the command<br />
<pre class="terminal"><br />
iwconfig<br />
</pre><br />
<br /><br />
<br /><br />
For Raspberry Pi 2 and WiFi dongles with 8192CU or 8188CUS chip (for example, Edimax EW-7811un dongles)you can prevent connections from being dropped by creating the file '''/etc/modprobe.d/8192cu.conf'''<br />
<br><br />
<pre class="terminal"><br />
sudo nano /etc/modprobe.d/8192cu.conf<br />
</pre><br />
and adding the line<br />
<br /><br />
<pre class="code"><br />
options 8192cu rtw_power_mgnt=0 rtw_enusbss=0<br />
</pre><br />
<br /><br />
<br />
= Camera =<br />
There is a [https://www.raspberrypi.org/products/camera-module/ camera module] for Raspberry Pi, which I use in my robots. In fact, the camera module is part of the [[Core Module]].<br />
<br /><br />
<br /><br />
Refer to the official [https://www.raspberrypi.org/documentation/usage/camera/README.md camera setup instructions]. Be careful with the camera module, handle the camera board and the connector strip delicately.<br />
<br /><br />
<br /><br />
To be able to access the camera through the Python programming environment you need to install the '''python-picamera''' package<br />
<br /><br />
<br /><br />
The Raspberry Pi project does not provide a C/C++ library for accessing the camera. Instead it provides utility applications ''raspistill'' and ''raspivid'' which record still images and videos, respectively. A number of third-party C++ libraries have been created based on the open source code of these utility applications. The [http://www.uco.es/investiga/grupos/ava/node/40 RaspiCam] C++ library developed at the University of Cordoba is one such library (source code available [https://sourceforge.net/projects/raspicam/ from SourceForge]).<br />
<br /><br />
<br /><br />
== Video Streaming ==<br />
To stream video from the Raspberry Pi camera to the network, open a terminal on the RPi and type<br />
<pre class="terminal"><br />
raspivid -t 0 -w 1280 -h 720 -hf -ih -fps 30 -o - | nc -k -l 8100<br />
</pre><br />
<br /><br />
To view the stream on a client computer with [http://www.mplayerhq.hu Mplayer] installed, open a terminal there and type<br />
<pre class="terminal"><br />
mplayer -fps 300 -demuxer h264es ffmpeg://tcp://192.168.0.20:8100<br />
</pre><br />
<br /><br />
<br /><br />
Alternatively, you can use [[GStreamer]] to transport the video frames. Make sure that the command line interface to GStreamer, ''gst-launch-1.0'', is installed. <br />
<pre class="terminal"><br />
sudo apt install gstreamer1.0-tools<br />
</pre><br />
<br /><br />
For streaming from the RPi you can type<br />
<pre class="terminal"><br />
raspivid -t 0 -w 640 -h 480 -fps 30 -hf -b 2000000 -o - | gst-launch-1.0 -q fdsrc ! h264parse ! rtph264pay config-interval=1 pt=96 ! gdppay ! tcpserversink host=0.0.0.0 port=8100<br />
</pre><br />
<br /><br />
For viewing on the client, you can type<br />
<pre class="terminal"><br />
gst-launch-1.0 -v tcpclientsrc host=192.168.0.20 port=8100 ! gdpdepay ! rtph264depay ! avdec_h264 ! videoconvert ! videoflip method=vertical-flip ! autovideosink sync=false<br />
</pre><br />
where ''192.168.0.20'' is assumed to be the IP address of the server (Raspberry Pi).<br />
<br /><br />
<br /><br />
* On the Raspberry Pi side you can elevate the priority of the process by beginning the command with ''"nice -20"''.<br />
* For verbose output from ''gst-launch-1.0'', use the option ''-v'' instead of ''-q''.<br />
* Note that we used the [https://gstreamer.freedesktop.org/documentation/videofilter/videoflip.html?gi-language=c#GstVideoFlipMethod videoflip] filter to correct the rotation of the decoded image.<br />
<br /><br />
=== Disabling the LED ===<br />
To disable the red indicator light of the camera, add the following line to '''/boot/config.txt''' and reboot:<br />
<pre class="code"><br />
disable_camera_led=1<br />
</pre><br />
<br /><br />
<br />
= pinout =<br />
A cool command-line tool provided by Raspberry Pi, and also available when running Ubuntu instead of Raspberry Pi OS, is '''pinout'''. It displays a layout of the Raspberry Pi board using ASCII art, a list of significant hardware features of the board, and the GPIO pin layout in tabular form.<br />
<br /><br />
<pre class="terminal"><br />
sudo apt install python3-gpiozero<br />
pinout<br />
</pre><br />
<br /><br />
[[File:Raspberry_Pi_pinout_command.png | x600px]]<br />
<br /><br />
<br /><br />
<br />
= raspi-gpio =<br />
The documentation states that ''"raspi-gpio can get and print the state of a GPIO (or all GPIOs) and can be used to set the function, pulls and value of a GPIO. raspi-gpio must be run as root."''<br />
"<br />
<pre class="terminal"><br />
> sudo apt install raspi-gpio<br />
> raspi-gpio funcs 20,21,22<br />
GPIO, DEFAULT PULL, ALT0, ALT1, ALT2, ALT3, ALT4, ALT5<br />
20, DOWN, PCM_DIN, SD12, DPI_D16, SPI6_MOSI, SPI1_MOSI, GPCLK0<br />
21, DOWN, PCM_DOUT, SD13, DPI_D17, SPI6_SCLK, SPI1_SCLK, GPCLK1<br />
22, DOWN, SD0_CLK, SD14, DPI_D18, SD1_CLK, ARM_TRST, SDA6<br />
> raspi-gpio get 20<br />
GPIO 20: level=0 func=INPUT pull=DOWN<br />
GPIO 21: level=1 func=INPUT pull=DOWN<br />
GPIO 22: level=0 func=INPUT pull=DOWN<br />
> raspi-gpio raw 21<br />
00: 00000000 00012000 12000000 3fffffff<br />
10: 24000040 00000924 00000000 6770696f<br />
20: 6770696f 6770696f 6770696f 6770696f<br />
30: 6770696f 102081ff 00003bfb 00000000<br />
40: 00000000 00000000 00000000 00000000<br />
50: 00000000 00000000 00000000 00000000<br />
60: 00000000 00000000 00000000 00000000<br />
70: 00000000 00000000 00000000 00000000<br />
80: 00000000 00000000 00000000 00000000<br />
90: 00000000 00000000 00000000 00000000<br />
e0: 4aa95555 19aaaaaa 50aa5544<br />
f0: 000aaaaa<br />
</pre><br />
<br /><br />
<br />
= GPIO Programming in C =<br />
Raspberry Pi 2, 3 & 4 come with 40 ''General Purpose Input Output'' (GPIO) pins ([https://www.raspberrypi.com/documentation/computers/os.html#gpio-and-the-40-pin-header layout]) that can be used to interface with the other electronic components of your project.<br />
<br />
== Using libgpiod ==<br />
The standard C++ programming interface for GPIO on Linux is ''libgpiod'', as described on [[Nvidia_Jetson#Using_Libgpiod | the Jetson page]].<br />
<br />
== Using WiringPi ==<br />
Using the [http://wiringpi.coml WiringPi] library is a more popular method for programming the GPIO pins on a Raspberry Pi with C/C++. WiringPi is [http://wiringpi.com/download-and-install installed from source] like this<br />
<pre class="terminal"><br />
sudo apt-get install git-core<br />
git clone git://git.drogon.net/wiringPi<br />
cd wiringPi<br />
./build<br />
</pre><br />
Read the ''INSTALL'' file for what to do with the created shared library. Basically you need to copy ''wiringPi/libwiringPi.so.x.xx'' to ''/usr/local/lib'' and add the line<br />
<pre class="code"><br />
include /usr/local/lib<br />
</pre><br />
to the file ''/etc/ld.so.conf'' so that the library loader also looks in ''/usr/local/lib'' for dynamically loadable libraries. It is also possible to create a static library.<br />
<br /><br />
<br/><br />
After installation, create a test program called ''blink.cpp''<br />
<pre class="code"><br />
#include <stdio.h><br />
#include <iostream><br />
#include <wiringPi.h><br />
<br />
static int LED_PORT = 7; // The physical pin number. Corresponds to BCM GPIO pin 4.<br />
<br />
void blink()<br />
{<br />
digitalWrite(4, HIGH);<br />
delay(1000);<br />
digitalWrite(4, LOW);<br />
delay(1000);<br />
};<br />
<br />
int main(int numargs, char** args)<br />
{<br />
wiringPiSetup();<br />
pinMode(LED_PORT, OUTPUT);<br />
for (int n = 0; n < 10; n++)<br />
{<br />
blink();<br />
}<br />
std::cout << "finished blinking" << std::endl;<br />
return 0;<br />
}<br />
</pre><br />
and build like this<br />
<pre class="terminal"><br />
g++ blink.cpp -o blink -lstdc++ -lwiringPi -IwiringPi<br />
</pre><br />
where I assumed that the wiringPi root folder is located in the same folder as the ''blink.cpp'' source file.<br />
<br /><br />
<br/><br />
Which pins can be used for what purpose is explained on the [http://wiringpi.com/pins wiringPi pins] page.<br />
<br /><br />
<br/><br />
<br />
= PWM =<br />
There are some Python libraries that communicate with the GPIO daemon to provide hardware PWM on selected pins. [https://gpiozero.readthedocs.org/ GPIO Zero] ([https://www.raspberrypi.org/blog/gpio-zero-a-friendly-python-api-for-physical-computing/ tutorial]) is one such library and is included in [https://www.raspberrypi.org/downloads/raspbian/ Raspbian]. With GPIO Zero you can implement dimming LEDs or control a brushed DC motor behind an [https://en.wikipedia.org/wiki/H_bridge H-Bridge] circuit.<br />
<br />
<br /><br />
= Running A Program On Startup =<br />
== Using SysVInit ==<br />
We want the Raspberry Pi to start the robot control program as soon as it's done with booting. In order to make sure that the system has completely initialized itself we will not use ''/etc/rc.local'' for starting our program. Instead, we will create a ''cron'' task with the ''crontab'' command<br />
<br /><br />
<pre class="terminal"><br />
sudo crontab -e<br />
</pre><br />
which opens the editor of choice (most likely ''nano'') where you can enter the program launch command. In our case this will be<br />
<pre class="code"><br />
@reboot python /home/pi/Core.py<br />
</pre><br />
where the leading ''@reboot'' indicates to ''cron'' that this command shall be executed only once, right after the booting process has completed. Notice that it is not necessary to start the command with ''sudo'', which is necessary when running program from the command line.<br />
<br /><br />
<br />
== Using Systemd ==<br />
<br /><br />
<br />
<br /><br />
<br />
= Communicating With Other Devices =<br />
There are three popular communication protocols that the Raspberry Pi supports and that are often used in embedded systems: I<sup>2</sup>C, SPI, and UART.<br />
<br /><br />
<br /><br />
<br />
== I<sup>2</sup>C ==<br />
Set the [[I2C | I<sup>2</sup>C]] clock speed by editing '''/boot/config.txt'''<br />
<pre class="code"><br />
dtparam=i2c1=on<br />
dtparam=i2c_arm_baudrate=xxx<br />
</pre><br />
where ''xxx'' is the desired frequency. Keep in mind that ATmega microcontrollers used on Arduino boards support only up to 400 kHz while Raspberry Pi can support higher speeds.<br />
<br /><br />
<br /><br />
=== Wiring To I<sup>2</sup>C Devices With 5 V Logic Level ===<br />
Normally you can not connect a GPIO pin to a device with 5 V logic (most of the Arduino models, for example). The GPIO data pins of the Raspberry Pi use 3.3 V as the HIGH voltage level and can be damaged when 5 V is applied. However, because I<sup>2</sup>C pins have [https://en.wikipedia.org/wiki/Open_collector open-collector] outputs they can be wired directly to I<sup>2</sup>C pins of devices with incompatible voltage levels. As long as the pull-up line voltage, which corresponds to the lowest of the device HIGH voltage levels, exceeds the minimum voltage for which HIGH is defined on each device, the devices will be able to sense the correct data bit.<br />
<br /><br />
<br /><br />
Links:<br />
* [https://learn.sparkfun.com/tutorials/i2c Tutorial by SparkFun] on I<sup>2</sup>C<br />
* [https://learn.adafruit.com/adafruits-raspberry-pi-lesson-4-gpio-setup?view=all Article by Adafruit] on how to set up I<sup>2</sup>C and SPI on a Raspberry Pi<br />
* Tutorial for setting up an I2C bus [http://blog.oscarliang.net/raspberry-pi-arduino-connected-i2c/ between a Raspberry Pi and an Arduino].<br />
<br /><br />
<br />
== SPI ==<br />
First of all, you need to use the ''raspi-config'' command-line configuration utility to enable the SPI pins.<br />
<pre class="terminal"><br />
sudo raspi-config<br />
</pre><br />
<br /><br />
You can use [http://wiringpi.com/reference/spi-library/ WiringPi SPI] to add SPI capability to your C/C++ program.<br />
<br /><br />
<br /><br />
<br />
== UART ==<br />
[http://www.andremiller.net/content/raspberry-pi-and-arduino-via-gpio-uart Here is a tutorial] that shows how to communicate with an Arduino using the UART interface.<br />
<br /><br />
<br /><br />
<br />
== CAN ==<br />
There are various [[CAN]] adapter boards available for Raspberry Pi. For example [http://skpang.co.uk/catalog/pican2-canbus-board-for-raspberry-pi-2-p-1475.html PiCAN2].<br />
<br /><br />
<br /><br />
<br />
= Device Tree Overlays =<br />
A device tree overlay is a mechanism in Raspberry Pi computers to dynamically apply changes to existing device trees. This mechanism is mostly used to enable kernel-space support for hardware components that are attached to the Raspberry Pi via its GPIO headers.<br />
<br /><br />
<br /><br />
Operations with device tree overlays are performed by the Raspberry Pi GPU (VideoCore), without needing to preempt the Linux kernel. The Raspberry Pi primary bootloader, also a VideoCore firmware application, makes use of this device tree parsing and editing capability to apply device tree overlays during the boot process, before passing control to the Linux kernel.<br />
<br /><br />
==== /boot/config.txt ====<br />
The primary bootloader parses and interprets the ''/boot/config.txt'' file. It specifies, among other things, which device tree to select and which overlays to apply.<br />
<br /><br />
==== dtoverlay ====<br />
'''dtoverlay''' is the command-line tool for loading a device tree overlay (or unloading a previously loaded overlay) while the Linux system is running.<br />
<pre class="terminal"><br />
</pre><br />
<br /><br />
<br />
= Yocto Tips =<br />
== Adding Peripherals for a Compute Module ==<br />
A compute module does not know what hardware components its carrier board provides unless the default device tree is modified to include the interfaces to these hardware components. Instead of providing a different complete device tree, you would normally [[Yocto#Patching_A_Device_Tree | create a patch]] for the device tree source file provided by a lower Yocto layer.<br />
<br /><br />
<br /><br />
The modified device tree must be based on the device tree used by the kernel in Yocto. For Compute Module 4, the device tree file to patch is<br />
: ''${YOCTO_BUILD_DIR}'''''/tmp/work-shared/raspberrypi4-64/kernel-source/arch/arm/boot/dts/bcm2711-rpi-cm4.dts'''<br />
Copy this file to your layer's recipe directory and edit the copy to add the peripherals. The Raspberry Pi reference device tree files at the [https://datasheets.raspberrypi.com/ Raspberry Pi Datasheets collection page] can be helpful in creating your modified device tree.<br />
<br /><br />
<br /><br />
Below is an example that adds, among other things, a MIPI CSI-2 camera and a MIPI DSI display to the device tree:<br />
<pre class="code"><br />
/ {<br />
videocore {<br />
<br />
pins_cm4 { // Pi 4 CM4<br />
pin_config {<br />
pin@default {<br />
polarity = "active_high";<br />
termination = "pull_down";<br />
startup_state = "inactive";<br />
function = "input";<br />
}; // pin<br />
pin@p0 { function = "input"; termination = "pull_up"; }; // CAMERA 0 I2C0 SDA<br />
pin@p1 { function = "input"; termination = "pull_up"; }; // CAMERA 0 I2C0 SCL<br />
pin@p44 { function = "input"; termination = "pull_up"; }; // DISPLAY 1 I2C0 SDA<br />
pin@p45 { function = "input"; termination = "pull_up"; }; // DISPLAY 1 I2C0 SCL<br />
<br />
pin@p128 { function = "output"; termination = "no_pulling"; }; // BT_ON<br />
pin@p129 { function = "output"; termination = "no_pulling"; }; // WL_ON<br />
pin@p131 { function = "output"; termination = "no_pulling"; }; // ANT1<br />
pin@p133 { function = "output"; termination = "no_pulling"; }; // Camera shutdown<br />
<br />
}; // pin_config<br />
<br />
pin_defines {<br />
pin_define@HDMI_CONTROL_ATTACHED {<br />
type = "external";<br />
number = <0>;<br />
};<br />
pin_define@EMMC_ENABLE {<br />
type = "external";<br />
number = <1>;<br />
};<br />
pin_define@NUM_CAMERAS {<br />
type = "internal";<br />
number = <1>;<br />
};<br />
pin_define@POWER_LOW {<br />
type = "absent";<br />
};<br />
pin_define@LEDS_DISK_ACTIVITY {<br />
type = "absent";<br />
};<br />
pin_define@LAN_RUN {<br />
type = "absent";<br />
};<br />
pin_define@BT_ON {<br />
type = "external";<br />
number = <0>;<br />
};<br />
pin_define@WL_ON {<br />
type = "external";<br />
number = <1>;<br />
};<br />
pin_define@ETH_CLK {<br />
type = "absent";<br />
};<br />
pin_define@WL_LPO_CLK {<br />
type = "absent";<br />
};<br />
pin_define@USB_LIMIT_1A2 {<br />
type = "absent";<br />
};<br />
pin_define@SIO_1V8_SEL {<br />
type = "absent";<br />
};<br />
pin_define@SAFE_MODE {<br />
type = "absent";<br />
};<br />
<br />
// Display<br />
<br />
pin_define@DISPLAY_I2C_PORT {<br />
type = "internal";<br />
number = <0>;<br />
};<br />
pin_define@DISPLAY_SDA {<br />
type = "internal";<br />
number = <44>;<br />
};<br />
pin_define@DISPLAY_SCL {<br />
type = "internal";<br />
number = <45>;<br />
};<br />
pin_define@DISPLAY_DSI_PORT {<br />
type = "internal";<br />
number = <1>;<br />
};<br />
<br />
// Camera<br />
<br />
pin_define@CAMERA_0_I2C_PORT {<br />
type = "internal";<br />
number = <0>;<br />
};<br />
pin_define@CAMERA_0_SDA_PIN {<br />
type = "internal";<br />
number = <0>;<br />
};<br />
pin_define@CAMERA_0_SCL_PIN {<br />
type = "internal";<br />
number = <1>;<br />
};<br />
pin_define@CAMERA_0_SHUTDOWN {<br />
type = "external";<br />
number = <5>;<br />
};<br />
pin_define@CAMERA_0_UNICAM_PORT {<br />
type = "internal";<br />
number = <0>;<br />
};<br />
pin_define@CAMERA_0_LED {<br />
type = "absent";<br />
};<br />
}; // pin_defines<br />
}; // pins<br />
<br />
};<br />
};<br />
</pre><br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Yocto&diff=3163Yocto2022-12-25T19:10:56Z<p>Kai: removes trailing empty line in code example</p>
<hr />
<div>= Yocto and OpenEmbedded =<br />
The collection of software tools used by the Yocto project have been developed by the [https://www.openembedded.org OpenEmbedded] project. The Yocto project basically uses these generic build tools to provide a basic Linux system called ''Poky''. Stable releases of Poky serve as standard platforms for third parties that provide additional features (e.g., hardware support layers).<br />
<br /><br />
<br /><br />
<br />
= Prerequisites =<br />
* A Linux system supported by the Yocto project.<br />Assuming that [[Ubuntu]] is used. <br />
* Following package installed:<br />
<pre class=terminal><br />
sudo apt install gcc g++ \<br />
python3-distutils python-is-python3<br />
</pre><br />
<br /><br />
<br />
= Bitbake =<br />
Bitbake is the build tool from the OpenEmbedded project, which parses the project's metadata, resolves dependencies and the ordering of the build steps, runs the builds to create packages, to finally create an image from the packages.<br />
<br /><br />
=== Metadata Types ===<br />
Yocto metadata, which controls how a system image is built, can be categorized at a high level into these four types:<br />
* ''Machine''<br />the targeted hardware platform (e.g. Raspberry Pi 4)<br />
* ''Distro''<br />common characteristic of a family of related images<br />
* ''Recipes''<br />instructions on how to process the source files for a component of the image<br />
* ''Image''<br />recipes that define the contents of generated system images<br />
<br /><br />
=== Layers ===<br />
Layers are purposeful collections of metadata. Yocto layers often Layers often add the provide that for a that can be combined with other layers in order to directories in which <br />
<br /><br />
<br />
<br /> <br />
<br />
= Images =<br />
<br />
Images are recipes that ultimately inherit from '''meta/classes/image.bbclass''' and set the global variable '''IMAGE_INSTALL'''. Most images, however, will inherit from ''meta/classes/core-image.bbclass'' which inherits directly from ''image.bbclass'', provides a mapping from ''IMAGE_FEATURES'' to package groups, and adds the two package groups ''packagegroup-core-boot'' and ''packagegroup-base-extended'' to ''IMAGE_INSTALL''.<br />
<br />
Images are defined in recipe files with the file extension 'bb'. In order to separate them from package recipes, there is a convention to put image recipes into a folder named ''images''. Making use of this, we can list all images defined by all layers via<br />
<pre class="terminal"><br />
cd poky<br />
ls meta*/recipes*/images/*.bb<br />
</pre><br />
<br /><br />
<br />
=== ''IMAGE_FEATURES'' ===<br />
The ''IMAGE_FEATURES'' variable is defined in ''meta/classes/image.bbclass'' with an empty value. It accepts only a predefined set of features (e.g., ''x11'', ''debug-tweaks'', ''dev-pkgs'', ''dbg-pkgs''). This affects how recipes will execute their tasks and which packages will be selected to go into the image. The image recipe ''meta/recipes-core/images/core-image-base.bb'', for example, adds the ''splash'' feature.<br />
<br /><br />
<br />
=== ''IMAGE_INSTALL'' ===<br />
Holds a list of package groups whose packages (from the package feed area) will go into the filesystem image.<br />
<br /><br />
<br />
== Reference images ==<br />
The following reference images are defined in the ''meta'' layer:<br />
{| style="padding: 10px;"<br />
! style="width: 20px" | || || <br />
|-<br />
| || ''core-image-minimal'' || small image that just boots the target device<br />
|-<br />
| || ''core-image-minimal-dev'' || ''core-image-minimal'' with headers and libraries allowing development work<br />
|-<br />
| || style="padding-right: 10px" | ''core-image-minimal-initramfs'' || ''core-image-minimal'' with kernel support for in-RAM filesystem<br />
|-<br />
| || '''core-image-base''' || '''console-only system fully supporting the target hardware'''<br />
|-<br />
| || ''core-image-full-cmdline'' || console-only image that includes many system tools<br />
|-<br />
| || ''core-image-x11'' || image with basic X11 and a terminal<br />
|-<br />
|}<br />
<br />
These image definitions are provided as a starting point for creating project-specific, custom image definitions.<br />
<br /><br />
<br /><br />
<br />
== Creating a Custom Image ==<br />
* In your custom layer, create the ''images'' subdirectory in one of your ''recipes-...' directory.<br />
* In the ''images'' directory, create two image recipe files that inherit from ''core-image'':<br />
<pre class="code"><br />
SUMMARY = "My deployment image"<br />
LICENSE = "MIT"<br />
<br />
inherit core-image<br />
IMAGE_FEATURES += "splash"<br />
</pre><br />
and<br />
<pre class="code"><br />
SUMMARY = "My development image"<br />
<br />
inherit core-image<br />
require my-image.bb<br />
<br />
IMAGE_FEATURES += "ssh-server-dropbear tools-debug debug-tweaks"<br />
<br />
CORE_IMAGE_EXTRA_INSTALL += "i2c-tools "<br />
</pre><br />
where the first image recipe is for deployment and the second is for development. Note that the development version includes the deployment version with the ''require'' statement, and adds to IMAGE_FEATURES and CORE_IMAGE_EXTRA_INSTALL.<br />
<br /><br />
<br />
== Image Filesystem Packaging ==<br />
The system image generated by Bitbake can be packaged in the form of an image file, whose contents can be transferred on a boot medium (SD card or eMMC) such that the primary boot loader of the target device can discover the system and boot it.<br />
<br />
Unless you restrict the type of packaging used for the image file, Yocto will generate multiple rootfs packages, each with a large footprint. To restrict the generated image files to a desired type, edit ''conf/local.conf'' of your project build directory and set the type.<br />
<pre class="code"><br />
#IMAGE_FSTYPES = "tar.gz"<br />
#IMAGE_FSTYPES = "tar.bz2"<br />
IMAGE_FSTYPES = "wic.bz2 wic.bmap"<br />
</pre><br />
The wic ([https://pykickstart.readthedocs.io/en/latest/kickstart-docs.html kickstart]) format with accompanying [https://github.com/intel/bmap-tools bmap] is recommended.<br />
<br /><br />
<br />
== Installing the Rootfs Image ==<br />
Using [https://github.com/intel/bmap-tools bmaptool] we can copy the generated ''wic'' image (with matching bmap file) to a mounted SD card or eMMC storage.<br />
<pre class="terminal"><br />
sudo bmaptool copy tmp/deploy/images/raspberrypi4-64/<wic.bz2 file> <drive><br />
</pre><br />
where ''<wic.bz2 file>'' is the root filesystem image wic.bz2 file, and ''<drive>'' is the drive at which the storage is mounted (for example, ''/dev/sdb'').<br />
<br /><br />
<br /><br />
<br />
= Package Groups =<br />
Package groups are recipes that inherit from '''meta/classes/packagegroup.bbclass''' and set the content of the global variable '''PACKAGES'''. Package groups are defined in recipe files with the file extension 'bb'.<br />
<br /><br />
<br /><br />
Note that the ''packagegroup'' must be inherited before ''PACKAGES is defined.<br />
<pre class="code"><br />
inherit packagegroup<br />
<br />
PACKAGES = '...'<br />
</pre><br />
<br /><br />
<br />
= Useful Image Features =<br />
<br /><br />
<br />
== Distro Features ==<br />
Distro features are system features that affect multiple recipes. '''Large parts of the Poky image may need to be rebaked after making changes to the distro features!'''<br />
<br /><br />
<br />
=== systemd ===<br />
In the ''conf/local.conf'' file of your project build directory (or ''layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " systemd"<br />
</pre><br />
<br /><br />
<br />
=== NFS ===<br />
In Embedded Linux projects, NFS is often included in development images to enable faster code-deploy turnaround times.<br />
<br /><br />
In the ''conf/local.conf'' file of your Yocto build directory (or ''conf/layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " nfs"<br />
</pre><br />
<br /><br />
On your Debian-based Yocto machine, [[Ubuntu#Setting_up_an_NFS_Server|set up an SSH server]].<br />
<br /><br />
<br /><br />
In Yocto, use the directory<br />
<br /><br />
: '''{YOCTO_BUILD_DIR}/tmp/work/{TARGET}-poky-linux/{IMAGE}/1.0-r0/rootfs'''<br />
as the root directory provided by the NFS server. For example,<br />
: ''build-robofish-core/tmp/work/raspberrypi4_64-poky-linux/robofish-core-image-dev/1.0-r0/rootfs''<br />
<br /><br />
<br /><br />
<br />
=== [https://vulkan.org Vulkan] and [https://opengl.org OpenGL] ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " vulkan opengl x11 wayland"<br />
</pre><br />
<br /><br />
<br />
=== Bluetooth and NFC ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " bluetooth nfc"<br />
</pre><br />
<br /><br />
<br />
= Recipes =<br />
Recipes are Yocto metadata files that are interpreted by Bitbake and describe how a build task is performed.<br />
<br /><br />
== Patching A Device Tree ==<br />
Follow these steps to patch an existing device tree by creating an ''append recipe'' in a custom layer.<br />
<br /><br />
<br /><br />
In the custom layer, create the directory for a linux kernel append recipe.<br />
<pre class="terminal"><br />
mkdir -p ${LAYER_DIR}/recipes-kernel/linux/files<br />
</pre><br />
where it is assumed that ''${LAYER_DIR}'' contains the path to the root directory of the custom Yocto layer. <br />
<br /><br />
<br /><br />
Copy the kernel device tree file from your Yocto project build directory to the ''files'' directory of your new recipe. For a Raspberry Pi Compute Module 4, for example, type<br />
<pre class="terminal"><br />
cp ${YOCTO_BUILD_DIR}/tmp/work-shared/${MACHINE}/kernel-source/arch/arm/boot/dts/some.dts ${LAYER_DIR}/recipes-kernel/linux/files/<br />
</pre><br />
where ''${YOCTO_BUILD_DIR}'' is the path to the Yocto project build directory, and ''${MACHINE}'' is the chosen target platform (e.g. "raspberrypi4-64").<br />
<br /><br />
<div class="sidenote"><br />
If the ''tmp/work-shared'' directory does not exists anymore, you can recreate it by typing<br />
<pre class="terminal"><br />
bitbake -c menuconfig virtual/kernel<br />
</pre><br />
and exiting the kernel configuration menu without making changes.<br />
</div><br />
<br /><br />
Make the necessary changes to the copied device tree file. Then create a git patch file using ''git diff'' as shown below<br />
<pre class="terminal"><br />
git diff --no-index {DTS_DIR}/some.dts some.dts > 0001-my_modifications-dts.patch<br />
</pre><br />
<br /><br />
Edit the generated patch file to fix the file paths at the top. The paths must be relative to the kernel sources directory:<br />
: ''${YOCTO_BUILD_DIR}'''''/tmp/work-shared/'''''${MACHINE}'''''/kernel-source'''<br />
The header should look like this:<br />
<pre class="code"><br />
diff --git a/arch/arm/boot/dts/some.dts b/some.dts<br />
index 6e99da1..4567735 100644<br />
--- a/arch/arm/boot/dts/some.dts<br />
+++ b/arch/arm/boot/dts/some.dts<br />
</pre><br />
where "--- a" and "+++ b" are followed by the same relative file path.<br />
<br />
<br /><br />
Create and edit the append recipe<br />
<pre class="terminal"><br />
vim ${LAYER_DIR}/recipes-kernel/linux/${KERNEL_NAME}_%.bbappend<br />
</pre><br />
where ''${KERNEL_NAME}'' is the kernel name, which usually starts with "linux-" (for example, ''linux-raspberrypi''), and ''_%'' denotes all versions of the kernel package.<br />
<br /><br />
<div class="sidenote"><br />
If in doubt, use the ''oe-pkgdata-util'' tool from within your build directory to find out the kernel name.<br />
<pre class="terminal"><br />
oe-pkgdata-util lookup-recipe kernel<br />
</pre><br />
</div><br />
The contents of the recipe file should be similar to this:<br />
<pre class="code"><br />
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"<br />
SRC_URI += "file://0001-my_modifications-dts.patch"<br />
SRC_URI[md5sum] = "e2eba462f773f46fe6930a08323f5e1f"<br />
SRC_URI[sha256sum] = "2ef2b2e9b33b5d2af0425940387bc6c1c2c305e6a685defbdc7cf3f584bc1edc"<br />
</pre><br />
where ''0001-my_modifications-dts.patch'' needs to be replaced with the actual patch file name.<br />
<br />
== Creating a New Device Tree ==<br />
Creating a new device tree requires an input dts file which completely defines the hardware configuration. The ''KERNEL_DEVICETREE'' variable is used to make the Linux kernel select the new device tree during booting.<br />
<pre class="code"><br />
inherit kernel-devicetree<br />
<br />
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"<br />
<br />
# Make custom kernel with PRU enabled<br />
SRC_URI += " \<br />
file://some.dts \<br />
file://0001-some.patch \<br />
"<br />
<br />
KERNEL_DEVICETREE = "some.dtb"<br />
</pre><br />
<br /><br />
<br />
= Accessing the OpenEmbedded package collection =<br />
The OpenEmbedded project provides recipes for many useful programs that are not included with Yocto, like tmux, VLC, Gnome, various multimedia codecs, more filesystems, gRPC and much more.<br />
<br /><br />
To access the recipes for those software packages, clone the OpenEmbedded layers repository into your third-party layers directory: <br />
<pre class="terminal"><br />
git clone git://git.openembedded.org/meta-openembedded<br />
</pre><br />
<br /><br />
<br />
= devtool =<br />
<br />
Use '''devtool''' to make changes to an existing recipe and automatically generate an append recipe from those changes.<br />
<br /><br />
<br /><br />
<br />
== Initialization Manager ==<br />
After the kernel is done with its basic booting tasks, it passes control to the initialization manager. To use the ''systemd'' initialization manager (used by the Linux distributions Debian and Ubuntu) instead of ''SysVinit'', make the following entries in ''${TOPDIR}/conf/distro/distro.conf''<br />
<pre class="code"><br />
DISTRO_FEATURES_append = " systemd"<br />
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"<br />
VIRTUAL-RUNTIME_init_manager = "systemd"<br />
VIRTUAL-RUNTIME_initscripts = ""<br />
</pre><br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Yocto&diff=3162Yocto2022-12-25T19:08:15Z<p>Kai: fixes syntax</p>
<hr />
<div>= Yocto and OpenEmbedded =<br />
The collection of software tools used by the Yocto project have been developed by the [https://www.openembedded.org OpenEmbedded] project. The Yocto project basically uses these generic build tools to provide a basic Linux system called ''Poky''. Stable releases of Poky serve as standard platforms for third parties that provide additional features (e.g., hardware support layers).<br />
<br /><br />
<br /><br />
<br />
= Prerequisites =<br />
* A Linux system supported by the Yocto project.<br />Assuming that [[Ubuntu]] is used. <br />
* Following package installed:<br />
<pre class=terminal><br />
sudo apt install gcc g++ \<br />
python3-distutils python-is-python3<br />
</pre><br />
<br /><br />
<br />
= Bitbake =<br />
Bitbake is the build tool from the OpenEmbedded project, which parses the project's metadata, resolves dependencies and the ordering of the build steps, runs the builds to create packages, to finally create an image from the packages.<br />
<br /><br />
=== Metadata Types ===<br />
Yocto metadata, which controls how a system image is built, can be categorized at a high level into these four types:<br />
* ''Machine''<br />the targeted hardware platform (e.g. Raspberry Pi 4)<br />
* ''Distro''<br />common characteristic of a family of related images<br />
* ''Recipes''<br />instructions on how to process the source files for a component of the image<br />
* ''Image''<br />recipes that define the contents of generated system images<br />
<br /><br />
=== Layers ===<br />
Layers are purposeful collections of metadata. Yocto layers often Layers often add the provide that for a that can be combined with other layers in order to directories in which <br />
<br /><br />
<br />
<br /> <br />
<br />
= Images =<br />
<br />
Images are recipes that ultimately inherit from '''meta/classes/image.bbclass''' and set the global variable '''IMAGE_INSTALL'''. Most images, however, will inherit from ''meta/classes/core-image.bbclass'' which inherits directly from ''image.bbclass'', provides a mapping from ''IMAGE_FEATURES'' to package groups, and adds the two package groups ''packagegroup-core-boot'' and ''packagegroup-base-extended'' to ''IMAGE_INSTALL''.<br />
<br />
Images are defined in recipe files with the file extension 'bb'. In order to separate them from package recipes, there is a convention to put image recipes into a folder named ''images''. Making use of this, we can list all images defined by all layers via<br />
<pre class="terminal"><br />
cd poky<br />
ls meta*/recipes*/images/*.bb<br />
</pre><br />
<br /><br />
<br />
=== ''IMAGE_FEATURES'' ===<br />
The ''IMAGE_FEATURES'' variable is defined in ''meta/classes/image.bbclass'' with an empty value. It accepts only a predefined set of features (e.g., ''x11'', ''debug-tweaks'', ''dev-pkgs'', ''dbg-pkgs''). This affects how recipes will execute their tasks and which packages will be selected to go into the image. The image recipe ''meta/recipes-core/images/core-image-base.bb'', for example, adds the ''splash'' feature.<br />
<br /><br />
<br />
=== ''IMAGE_INSTALL'' ===<br />
Holds a list of package groups whose packages (from the package feed area) will go into the filesystem image.<br />
<br /><br />
<br />
== Reference images ==<br />
The following reference images are defined in the ''meta'' layer:<br />
{| style="padding: 10px;"<br />
! style="width: 20px" | || || <br />
|-<br />
| || ''core-image-minimal'' || small image that just boots the target device<br />
|-<br />
| || ''core-image-minimal-dev'' || ''core-image-minimal'' with headers and libraries allowing development work<br />
|-<br />
| || style="padding-right: 10px" | ''core-image-minimal-initramfs'' || ''core-image-minimal'' with kernel support for in-RAM filesystem<br />
|-<br />
| || '''core-image-base''' || '''console-only system fully supporting the target hardware'''<br />
|-<br />
| || ''core-image-full-cmdline'' || console-only image that includes many system tools<br />
|-<br />
| || ''core-image-x11'' || image with basic X11 and a terminal<br />
|-<br />
|}<br />
<br />
These image definitions are provided as a starting point for creating project-specific, custom image definitions.<br />
<br /><br />
<br /><br />
<br />
== Creating a Custom Image ==<br />
* In your custom layer, create the ''images'' subdirectory in one of your ''recipes-...' directory.<br />
* In the ''images'' directory, create two image recipe files that inherit from ''core-image'':<br />
<pre class="code"><br />
SUMMARY = "My deployment image"<br />
LICENSE = "MIT"<br />
<br />
inherit core-image<br />
IMAGE_FEATURES += "splash"<br />
</pre><br />
and<br />
<pre class="code"><br />
SUMMARY = "My development image"<br />
<br />
inherit core-image<br />
require my-image.bb<br />
<br />
IMAGE_FEATURES += "ssh-server-dropbear tools-debug debug-tweaks"<br />
<br />
CORE_IMAGE_EXTRA_INSTALL += "i2c-tools "<br />
</pre><br />
where the first image recipe is for deployment and the second is for development. Note that the development version includes the deployment version with the ''require'' statement, and adds to IMAGE_FEATURES and CORE_IMAGE_EXTRA_INSTALL.<br />
<br /><br />
<br />
== Image Filesystem Packaging ==<br />
The system image generated by Bitbake can be packaged in the form of an image file, whose contents can be transferred on a boot medium (SD card or eMMC) such that the primary boot loader of the target device can discover the system and boot it.<br />
<br />
Unless you restrict the type of packaging used for the image file, Yocto will generate multiple rootfs packages, each with a large footprint. To restrict the generated image files to a desired type, edit ''conf/local.conf'' of your project build directory and set the type.<br />
<pre class="code"><br />
#IMAGE_FSTYPES = "tar.gz"<br />
#IMAGE_FSTYPES = "tar.bz2"<br />
IMAGE_FSTYPES = "wic.bz2 wic.bmap"<br />
</pre><br />
The wic ([https://pykickstart.readthedocs.io/en/latest/kickstart-docs.html kickstart]) format with accompanying [https://github.com/intel/bmap-tools bmap] is recommended.<br />
<br /><br />
<br />
== Installing the Rootfs Image ==<br />
Using [https://github.com/intel/bmap-tools bmaptool] we can copy the generated ''wic'' image (with matching bmap file) to a mounted SD card or eMMC storage.<br />
<pre class="terminal"><br />
sudo bmaptool copy tmp/deploy/images/raspberrypi4-64/<wic.bz2 file> <drive><br />
</pre><br />
where ''<wic.bz2 file>'' is the root filesystem image wic.bz2 file, and ''<drive>'' is the drive at which the storage is mounted (for example, ''/dev/sdb'').<br />
<br /><br />
<br /><br />
<br />
= Package Groups =<br />
Package groups are recipes that inherit from '''meta/classes/packagegroup.bbclass''' and set the content of the global variable '''PACKAGES'''. Package groups are defined in recipe files with the file extension 'bb'.<br />
<br /><br />
<br /><br />
Note that the ''packagegroup'' must be inherited before ''PACKAGES is defined.<br />
<pre class="code"><br />
inherit packagegroup<br />
<br />
PACKAGES = '...'<br />
</pre><br />
<br /><br />
<br />
= Useful Image Features =<br />
<br /><br />
<br />
== Distro Features ==<br />
Distro features are system features that affect multiple recipes. '''Large parts of the Poky image may need to be rebaked after making changes to the distro features!'''<br />
<br /><br />
<br />
=== systemd ===<br />
In the ''conf/local.conf'' file of your project build directory (or ''layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " systemd"<br />
</pre><br />
<br /><br />
<br />
=== NFS ===<br />
In Embedded Linux projects, NFS is often included in development images to enable faster code-deploy turnaround times.<br />
<br /><br />
In the ''conf/local.conf'' file of your Yocto build directory (or ''conf/layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " nfs"<br />
</pre><br />
<br /><br />
On your Debian-based Yocto machine, [[Ubuntu#Setting_up_an_NFS_Server|set up an SSH server]].<br />
<br /><br />
<br /><br />
In Yocto, use the directory<br />
<br /><br />
: '''{YOCTO_BUILD_DIR}/tmp/work/{TARGET}-poky-linux/{IMAGE}/1.0-r0/rootfs'''<br />
as the root directory provided by the NFS server. For example,<br />
: ''build-robofish-core/tmp/work/raspberrypi4_64-poky-linux/robofish-core-image-dev/1.0-r0/rootfs''<br />
<br /><br />
<br /><br />
<br />
=== [https://vulkan.org Vulkan] and [https://opengl.org OpenGL] ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " vulkan opengl x11 wayland"<br />
</pre><br />
<br /><br />
<br />
=== Bluetooth and NFC ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " bluetooth nfc"<br />
</pre><br />
<br /><br />
<br />
= Recipes =<br />
Recipes are Yocto metadata files that are interpreted by Bitbake and describe how a build task is performed.<br />
<br /><br />
== Patching A Device Tree ==<br />
Follow these steps to patch an existing device tree by creating an ''append recipe'' in a custom layer.<br />
<br /><br />
<br /><br />
In the custom layer, create the directory for a linux kernel append recipe.<br />
<pre class="terminal"><br />
mkdir -p ${LAYER_DIR}/recipes-kernel/linux/files<br />
</pre><br />
where it is assumed that ''${LAYER_DIR}'' contains the path to the root directory of the custom Yocto layer. <br />
<br /><br />
<br /><br />
Copy the kernel device tree file from your Yocto project build directory to the ''files'' directory of your new recipe. For a Raspberry Pi Compute Module 4, for example, type<br />
<pre class="terminal"><br />
cp ${YOCTO_BUILD_DIR}/tmp/work-shared/${MACHINE}/kernel-source/arch/arm/boot/dts/some.dts ${LAYER_DIR}/recipes-kernel/linux/files/<br />
</pre><br />
where ''${YOCTO_BUILD_DIR}'' is the path to the Yocto project build directory, and ''${MACHINE}'' is the chosen target platform (e.g. "raspberrypi4-64").<br />
<br /><br />
<div class="sidenote"><br />
If the ''tmp/work-shared'' directory does not exists anymore, you can recreate it by typing<br />
<pre class="terminal"><br />
bitbake -c menuconfig virtual/kernel<br />
</pre><br />
and exiting the kernel configuration menu without making changes.<br />
</div><br />
<br /><br />
Make the necessary changes to the copied device tree file. Then create a git patch file using ''git diff'' as shown below<br />
<pre class="terminal"><br />
git diff --no-index {DTS_DIR}/some.dts some.dts > 0001-my_modifications-dts.patch<br />
</pre><br />
<br /><br />
Edit the generated patch file to fix the file paths at the top. The paths must be relative to the kernel sources directory:<br />
: ''${YOCTO_BUILD_DIR}'''''/tmp/work-shared/'''''${MACHINE}'''''/kernel-source'''<br />
The header should look like this:<br />
<pre class="code"><br />
diff --git a/arch/arm/boot/dts/some.dts b/some.dts<br />
index 6e99da1..4567735 100644<br />
--- a/arch/arm/boot/dts/some.dts<br />
+++ b/arch/arm/boot/dts/some.dts<br />
</pre><br />
where "--- a" and "+++ b" are followed by the same relative file path.<br />
<br />
<br /><br />
Create and edit the append recipe<br />
<pre class="terminal"><br />
vim ${LAYER_DIR}/recipes-kernel/linux/${KERNEL_NAME}_%.bbappend<br />
</pre><br />
where ''${KERNEL_NAME}'' is the kernel name, which usually starts with "linux-" (for example, ''linux-raspberrypi''), and ''_%'' denotes all versions of the kernel package.<br />
<br /><br />
<div class="sidenote"><br />
If in doubt, use the ''oe-pkgdata-util'' tool from within your build directory to find out the kernel name.<br />
<pre class="terminal"><br />
oe-pkgdata-util lookup-recipe kernel<br />
</pre><br />
</div><br />
The contents of the recipe file should be similar to this:<br />
<pre class="code"><br />
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"<br />
SRC_URI += "file://0001-my_modifications-dts.patch"<br />
SRC_URI[md5sum] = "e2eba462f773f46fe6930a08323f5e1f"<br />
SRC_URI[sha256sum] = "2ef2b2e9b33b5d2af0425940387bc6c1c2c305e6a685defbdc7cf3f584bc1edc"<br />
<br />
</pre><br />
where ''0001-my_modifications-dts.patch'' needs to be replaced with the actual patch file name.<br />
<br />
== Creating a New Device Tree ==<br />
Creating a new device tree requires an input dts file which completely defines the hardware configuration. The ''KERNEL_DEVICETREE'' variable is used to make the Linux kernel select the new device tree during booting.<br />
<pre class="code"><br />
inherit kernel-devicetree<br />
<br />
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"<br />
<br />
# Make custom kernel with PRU enabled<br />
SRC_URI += " \<br />
file://some.dts \<br />
file://0001-some.patch \<br />
"<br />
<br />
KERNEL_DEVICETREE = "some.dtb"<br />
</pre><br />
<br /><br />
<br />
= Accessing the OpenEmbedded package collection =<br />
The OpenEmbedded project provides recipes for many useful programs that are not included with Yocto, like tmux, VLC, Gnome, various multimedia codecs, more filesystems, gRPC and much more.<br />
<br /><br />
To access the recipes for those software packages, clone the OpenEmbedded layers repository into your third-party layers directory: <br />
<pre class="terminal"><br />
git clone git://git.openembedded.org/meta-openembedded<br />
</pre><br />
<br /><br />
<br />
= devtool =<br />
<br />
Use '''devtool''' to make changes to an existing recipe and automatically generate an append recipe from those changes.<br />
<br /><br />
<br /><br />
<br />
== Initialization Manager ==<br />
After the kernel is done with its basic booting tasks, it passes control to the initialization manager. To use the ''systemd'' initialization manager (used by the Linux distributions Debian and Ubuntu) instead of ''SysVinit'', make the following entries in ''${TOPDIR}/conf/distro/distro.conf''<br />
<pre class="code"><br />
DISTRO_FEATURES_append = " systemd"<br />
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"<br />
VIRTUAL-RUNTIME_init_manager = "systemd"<br />
VIRTUAL-RUNTIME_initscripts = ""<br />
</pre><br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Yocto&diff=3161Yocto2022-12-25T19:07:33Z<p>Kai: fixes the append recipe file content</p>
<hr />
<div>= Yocto and OpenEmbedded =<br />
The collection of software tools used by the Yocto project have been developed by the [https://www.openembedded.org OpenEmbedded] project. The Yocto project basically uses these generic build tools to provide a basic Linux system called ''Poky''. Stable releases of Poky serve as standard platforms for third parties that provide additional features (e.g., hardware support layers).<br />
<br /><br />
<br /><br />
<br />
= Prerequisites =<br />
* A Linux system supported by the Yocto project.<br />Assuming that [[Ubuntu]] is used. <br />
* Following package installed:<br />
<pre class=terminal><br />
sudo apt install gcc g++ \<br />
python3-distutils python-is-python3<br />
</pre><br />
<br /><br />
<br />
= Bitbake =<br />
Bitbake is the build tool from the OpenEmbedded project, which parses the project's metadata, resolves dependencies and the ordering of the build steps, runs the builds to create packages, to finally create an image from the packages.<br />
<br /><br />
=== Metadata Types ===<br />
Yocto metadata, which controls how a system image is built, can be categorized at a high level into these four types:<br />
* ''Machine''<br />the targeted hardware platform (e.g. Raspberry Pi 4)<br />
* ''Distro''<br />common characteristic of a family of related images<br />
* ''Recipes''<br />instructions on how to process the source files for a component of the image<br />
* ''Image''<br />recipes that define the contents of generated system images<br />
<br /><br />
=== Layers ===<br />
Layers are purposeful collections of metadata. Yocto layers often Layers often add the provide that for a that can be combined with other layers in order to directories in which <br />
<br /><br />
<br />
<br /> <br />
<br />
= Images =<br />
<br />
Images are recipes that ultimately inherit from '''meta/classes/image.bbclass''' and set the global variable '''IMAGE_INSTALL'''. Most images, however, will inherit from ''meta/classes/core-image.bbclass'' which inherits directly from ''image.bbclass'', provides a mapping from ''IMAGE_FEATURES'' to package groups, and adds the two package groups ''packagegroup-core-boot'' and ''packagegroup-base-extended'' to ''IMAGE_INSTALL''.<br />
<br />
Images are defined in recipe files with the file extension 'bb'. In order to separate them from package recipes, there is a convention to put image recipes into a folder named ''images''. Making use of this, we can list all images defined by all layers via<br />
<pre class="terminal"><br />
cd poky<br />
ls meta*/recipes*/images/*.bb<br />
</pre><br />
<br /><br />
<br />
=== ''IMAGE_FEATURES'' ===<br />
The ''IMAGE_FEATURES'' variable is defined in ''meta/classes/image.bbclass'' with an empty value. It accepts only a predefined set of features (e.g., ''x11'', ''debug-tweaks'', ''dev-pkgs'', ''dbg-pkgs''). This affects how recipes will execute their tasks and which packages will be selected to go into the image. The image recipe ''meta/recipes-core/images/core-image-base.bb'', for example, adds the ''splash'' feature.<br />
<br /><br />
<br />
=== ''IMAGE_INSTALL'' ===<br />
Holds a list of package groups whose packages (from the package feed area) will go into the filesystem image.<br />
<br /><br />
<br />
== Reference images ==<br />
The following reference images are defined in the ''meta'' layer:<br />
{| style="padding: 10px;"<br />
! style="width: 20px" | || || <br />
|-<br />
| || ''core-image-minimal'' || small image that just boots the target device<br />
|-<br />
| || ''core-image-minimal-dev'' || ''core-image-minimal'' with headers and libraries allowing development work<br />
|-<br />
| || style="padding-right: 10px" | ''core-image-minimal-initramfs'' || ''core-image-minimal'' with kernel support for in-RAM filesystem<br />
|-<br />
| || '''core-image-base''' || '''console-only system fully supporting the target hardware'''<br />
|-<br />
| || ''core-image-full-cmdline'' || console-only image that includes many system tools<br />
|-<br />
| || ''core-image-x11'' || image with basic X11 and a terminal<br />
|-<br />
|}<br />
<br />
These image definitions are provided as a starting point for creating project-specific, custom image definitions.<br />
<br /><br />
<br /><br />
<br />
== Creating a Custom Image ==<br />
* In your custom layer, create the ''images'' subdirectory in one of your ''recipes-...' directory.<br />
* In the ''images'' directory, create two image recipe files that inherit from ''core-image'':<br />
<pre class="code"><br />
SUMMARY = "My deployment image"<br />
LICENSE = "MIT"<br />
<br />
inherit core-image<br />
IMAGE_FEATURES += "splash"<br />
</pre><br />
and<br />
<pre class="code"><br />
SUMMARY = "My development image"<br />
<br />
inherit core-image<br />
require my-image.bb<br />
<br />
IMAGE_FEATURES += "ssh-server-dropbear tools-debug debug-tweaks"<br />
<br />
CORE_IMAGE_EXTRA_INSTALL += "i2c-tools "<br />
</pre><br />
where the first image recipe is for deployment and the second is for development. Note that the development version includes the deployment version with the ''require'' statement, and adds to IMAGE_FEATURES and CORE_IMAGE_EXTRA_INSTALL.<br />
<br /><br />
<br />
== Image Filesystem Packaging ==<br />
The system image generated by Bitbake can be packaged in the form of an image file, whose contents can be transferred on a boot medium (SD card or eMMC) such that the primary boot loader of the target device can discover the system and boot it.<br />
<br />
Unless you restrict the type of packaging used for the image file, Yocto will generate multiple rootfs packages, each with a large footprint. To restrict the generated image files to a desired type, edit ''conf/local.conf'' of your project build directory and set the type.<br />
<pre class="code"><br />
#IMAGE_FSTYPES = "tar.gz"<br />
#IMAGE_FSTYPES = "tar.bz2"<br />
IMAGE_FSTYPES = "wic.bz2 wic.bmap"<br />
</pre><br />
The wic ([https://pykickstart.readthedocs.io/en/latest/kickstart-docs.html kickstart]) format with accompanying [https://github.com/intel/bmap-tools bmap] is recommended.<br />
<br /><br />
<br />
== Installing the Rootfs Image ==<br />
Using [https://github.com/intel/bmap-tools bmaptool] we can copy the generated ''wic'' image (with matching bmap file) to a mounted SD card or eMMC storage.<br />
<pre class="terminal"><br />
sudo bmaptool copy tmp/deploy/images/raspberrypi4-64/<wic.bz2 file> <drive><br />
</pre><br />
where ''<wic.bz2 file>'' is the root filesystem image wic.bz2 file, and ''<drive>'' is the drive at which the storage is mounted (for example, ''/dev/sdb'').<br />
<br /><br />
<br /><br />
<br />
= Package Groups =<br />
Package groups are recipes that inherit from '''meta/classes/packagegroup.bbclass''' and set the content of the global variable '''PACKAGES'''. Package groups are defined in recipe files with the file extension 'bb'.<br />
<br /><br />
<br /><br />
Note that the ''packagegroup'' must be inherited before ''PACKAGES is defined.<br />
<pre class="code"><br />
inherit packagegroup<br />
<br />
PACKAGES = '...'<br />
</pre><br />
<br /><br />
<br />
= Useful Image Features =<br />
<br /><br />
<br />
== Distro Features ==<br />
Distro features are system features that affect multiple recipes. '''Large parts of the Poky image may need to be rebaked after making changes to the distro features!'''<br />
<br /><br />
<br />
=== systemd ===<br />
In the ''conf/local.conf'' file of your project build directory (or ''layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " systemd"<br />
</pre><br />
<br /><br />
<br />
=== NFS ===<br />
In Embedded Linux projects, NFS is often included in development images to enable faster code-deploy turnaround times.<br />
<br /><br />
In the ''conf/local.conf'' file of your Yocto build directory (or ''conf/layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " nfs"<br />
</pre><br />
<br /><br />
On your Debian-based Yocto machine, [[Ubuntu#Setting_up_an_NFS_Server|set up an SSH server]].<br />
<br /><br />
<br /><br />
In Yocto, use the directory<br />
<br /><br />
: '''{YOCTO_BUILD_DIR}/tmp/work/{TARGET}-poky-linux/{IMAGE}/1.0-r0/rootfs'''<br />
as the root directory provided by the NFS server. For example,<br />
: ''build-robofish-core/tmp/work/raspberrypi4_64-poky-linux/robofish-core-image-dev/1.0-r0/rootfs''<br />
<br /><br />
<br /><br />
<br />
=== [https://vulkan.org Vulkan] and [https://opengl.org OpenGL] ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " vulkan opengl x11 wayland"<br />
</pre><br />
<br /><br />
<br />
=== Bluetooth and NFC ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " bluetooth nfc"<br />
</pre><br />
<br /><br />
<br />
= Recipes =<br />
Recipes are Yocto metadata files that are interpreted by Bitbake and describe how a build task is performed.<br />
<br /><br />
== Patching A Device Tree ==<br />
Follow these steps to patch an existing device tree by creating an ''append recipe'' in a custom layer.<br />
<br /><br />
<br /><br />
In the custom layer, create the directory for a linux kernel append recipe.<br />
<pre class="terminal"><br />
mkdir -p ${LAYER_DIR}/recipes-kernel/linux/files<br />
</pre><br />
where it is assumed that ''${LAYER_DIR}'' contains the path to the root directory of the custom Yocto layer. <br />
<br /><br />
<br /><br />
Copy the kernel device tree file from your Yocto project build directory to the ''files'' directory of your new recipe. For a Raspberry Pi Compute Module 4, for example, type<br />
<pre class="terminal"><br />
cp ${YOCTO_BUILD_DIR}/tmp/work-shared/${MACHINE}/kernel-source/arch/arm/boot/dts/some.dts ${LAYER_DIR}/recipes-kernel/linux/files/<br />
</pre><br />
where ''${YOCTO_BUILD_DIR}'' is the path to the Yocto project build directory, and ''${MACHINE}'' is the chosen target platform (e.g. "raspberrypi4-64").<br />
<br /><br />
<div class="sidenote"><br />
If the ''tmp/work-shared'' directory does not exists anymore, you can recreate it by typing<br />
<pre class="terminal"><br />
bitbake -c menuconfig virtual/kernel<br />
</pre><br />
and exiting the kernel configuration menu without making changes.<br />
</div><br />
<br /><br />
Make the necessary changes to the copied device tree file. Then create a git patch file using ''git diff'' as shown below<br />
<pre class="terminal"><br />
git diff --no-index {DTS_DIR}/some.dts some.dts > 0001-my_modifications-dts.patch<br />
</pre><br />
<br /><br />
Edit the generated patch file to fix the file paths at the top. The paths must be relative to the kernel sources directory:<br />
: ''${YOCTO_BUILD_DIR}'''''/tmp/work-shared/'''''${MACHINE}'''''/kernel-source'''<br />
The header should look like this:<br />
<pre class="code"><br />
diff --git a/arch/arm/boot/dts/some.dts b/some.dts<br />
index 6e99da1..4567735 100644<br />
--- a/arch/arm/boot/dts/some.dts<br />
+++ b/arch/arm/boot/dts/some.dts<br />
</pre><br />
where "--- a" and "+++ b" are followed by the same relative file path.<br />
<br />
<br /><br />
Create and edit the append recipe<br />
<pre class="terminal"><br />
vim ${LAYER_DIR}/recipes-kernel/linux/${KERNEL_NAME}_%.bbappend<br />
</pre><br />
where ''${KERNEL_NAME}'' is the kernel name, which usually starts with "linux-" (for example, ''linux-raspberrypi''), and ''_%'' denotes all versions of the kernel package.<br />
<br /><br />
<div class="sidenote"><br />
If in doubt, use the ''oe-pkgdata-util'' tool from within your build directory to find out the kernel name.<br />
<pre class="terminal"><br />
oe-pkgdata-util lookup-recipe kernel<br />
</pre><br />
</div><br />
The contents of the recipe file should be similar to this:<br />
<pre class="code"><br />
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"<br />
SRC_URI += "file://0001-my_modifications-dts.patch"<br />
SRC_URI[md5sum] = "e2eba462f773f46fe6930a08323f5e1f"<br />
SRC_URI[sha256sum] = "2ef2b2e9b33b5d2af0425940387bc6c1c2c305e6a685defbdc7cf3f584bc1edc"<br />
<br />
</pre><br />
where ''0001-my_modifications-dts.patch'' needs to be replaced with the actual patch file name.<br />
<br />
== Creating a New Device Tree ==<br />
Creating a new device tree requires an input dts file which completely defines the hardware configuration. The ''KERNEL_DEVICETREE'' variable is used to make the Linux kernel select the new device tree during booting.<br />
<pre class="code"><br />
inherit kernel-devicetree<br />
<br />
FILESEXTRAPATHS_prepend := "${THISDIR}/files:"<br />
<br />
# Make custom kernel with PRU enabled<br />
SRC_URI += " \<br />
file://some.dts \<br />
file://0001-some.patch \<br />
"<br />
<br />
KERNEL_DEVICETREE = "some.dtb"<br />
</pre><br />
<br /><br />
<br />
= Accessing the OpenEmbedded package collection =<br />
The OpenEmbedded project provides recipes for many useful programs that are not included with Yocto, like tmux, VLC, Gnome, various multimedia codecs, more filesystems, gRPC and much more.<br />
<br /><br />
To access the recipes for those software packages, clone the OpenEmbedded layers repository into your third-party layers directory: <br />
<pre class="terminal"><br />
git clone git://git.openembedded.org/meta-openembedded<br />
</pre><br />
<br /><br />
<br />
= devtool =<br />
<br />
Use '''devtool''' to make changes to an existing recipe and automatically generate an append recipe from those changes.<br />
<br /><br />
<br /><br />
<br />
== Initialization Manager ==<br />
After the kernel is done with its basic booting tasks, it passes control to the initialization manager. To use the ''systemd'' initialization manager (used by the Linux distributions Debian and Ubuntu) instead of ''SysVinit'', make the following entries in ''${TOPDIR}/conf/distro/distro.conf''<br />
<pre class="code"><br />
DISTRO_FEATURES_append = " systemd"<br />
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"<br />
VIRTUAL-RUNTIME_init_manager = "systemd"<br />
VIRTUAL-RUNTIME_initscripts = ""<br />
</pre><br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Yocto&diff=3160Yocto2022-12-25T18:01:34Z<p>Kai: Adds section about using a new device tree file (instead of patching an existing one).</p>
<hr />
<div>= Yocto and OpenEmbedded =<br />
The collection of software tools used by the Yocto project have been developed by the [https://www.openembedded.org OpenEmbedded] project. The Yocto project basically uses these generic build tools to provide a basic Linux system called ''Poky''. Stable releases of Poky serve as standard platforms for third parties that provide additional features (e.g., hardware support layers).<br />
<br /><br />
<br /><br />
<br />
= Prerequisites =<br />
* A Linux system supported by the Yocto project.<br />Assuming that [[Ubuntu]] is used. <br />
* Following package installed:<br />
<pre class=terminal><br />
sudo apt install gcc g++ \<br />
python3-distutils python-is-python3<br />
</pre><br />
<br /><br />
<br />
= Bitbake =<br />
Bitbake is the build tool from the OpenEmbedded project, which parses the project's metadata, resolves dependencies and the ordering of the build steps, runs the builds to create packages, to finally create an image from the packages.<br />
<br /><br />
=== Metadata Types ===<br />
Yocto metadata, which controls how a system image is built, can be categorized at a high level into these four types:<br />
* ''Machine''<br />the targeted hardware platform (e.g. Raspberry Pi 4)<br />
* ''Distro''<br />common characteristic of a family of related images<br />
* ''Recipes''<br />instructions on how to process the source files for a component of the image<br />
* ''Image''<br />recipes that define the contents of generated system images<br />
<br /><br />
=== Layers ===<br />
Layers are purposeful collections of metadata. Yocto layers often Layers often add the provide that for a that can be combined with other layers in order to directories in which <br />
<br /><br />
<br />
<br /> <br />
<br />
= Images =<br />
<br />
Images are recipes that ultimately inherit from '''meta/classes/image.bbclass''' and set the global variable '''IMAGE_INSTALL'''. Most images, however, will inherit from ''meta/classes/core-image.bbclass'' which inherits directly from ''image.bbclass'', provides a mapping from ''IMAGE_FEATURES'' to package groups, and adds the two package groups ''packagegroup-core-boot'' and ''packagegroup-base-extended'' to ''IMAGE_INSTALL''.<br />
<br />
Images are defined in recipe files with the file extension 'bb'. In order to separate them from package recipes, there is a convention to put image recipes into a folder named ''images''. Making use of this, we can list all images defined by all layers via<br />
<pre class="terminal"><br />
cd poky<br />
ls meta*/recipes*/images/*.bb<br />
</pre><br />
<br /><br />
<br />
=== ''IMAGE_FEATURES'' ===<br />
The ''IMAGE_FEATURES'' variable is defined in ''meta/classes/image.bbclass'' with an empty value. It accepts only a predefined set of features (e.g., ''x11'', ''debug-tweaks'', ''dev-pkgs'', ''dbg-pkgs''). This affects how recipes will execute their tasks and which packages will be selected to go into the image. The image recipe ''meta/recipes-core/images/core-image-base.bb'', for example, adds the ''splash'' feature.<br />
<br /><br />
<br />
=== ''IMAGE_INSTALL'' ===<br />
Holds a list of package groups whose packages (from the package feed area) will go into the filesystem image.<br />
<br /><br />
<br />
== Reference images ==<br />
The following reference images are defined in the ''meta'' layer:<br />
{| style="padding: 10px;"<br />
! style="width: 20px" | || || <br />
|-<br />
| || ''core-image-minimal'' || small image that just boots the target device<br />
|-<br />
| || ''core-image-minimal-dev'' || ''core-image-minimal'' with headers and libraries allowing development work<br />
|-<br />
| || style="padding-right: 10px" | ''core-image-minimal-initramfs'' || ''core-image-minimal'' with kernel support for in-RAM filesystem<br />
|-<br />
| || '''core-image-base''' || '''console-only system fully supporting the target hardware'''<br />
|-<br />
| || ''core-image-full-cmdline'' || console-only image that includes many system tools<br />
|-<br />
| || ''core-image-x11'' || image with basic X11 and a terminal<br />
|-<br />
|}<br />
<br />
These image definitions are provided as a starting point for creating project-specific, custom image definitions.<br />
<br /><br />
<br /><br />
<br />
== Creating a Custom Image ==<br />
* In your custom layer, create the ''images'' subdirectory in one of your ''recipes-...' directory.<br />
* In the ''images'' directory, create two image recipe files that inherit from ''core-image'':<br />
<pre class="code"><br />
SUMMARY = "My deployment image"<br />
LICENSE = "MIT"<br />
<br />
inherit core-image<br />
IMAGE_FEATURES += "splash"<br />
</pre><br />
and<br />
<pre class="code"><br />
SUMMARY = "My development image"<br />
<br />
inherit core-image<br />
require my-image.bb<br />
<br />
IMAGE_FEATURES += "ssh-server-dropbear tools-debug debug-tweaks"<br />
<br />
CORE_IMAGE_EXTRA_INSTALL += "i2c-tools "<br />
</pre><br />
where the first image recipe is for deployment and the second is for development. Note that the development version includes the deployment version with the ''require'' statement, and adds to IMAGE_FEATURES and CORE_IMAGE_EXTRA_INSTALL.<br />
<br /><br />
<br />
== Image Filesystem Packaging ==<br />
The system image generated by Bitbake can be packaged in the form of an image file, whose contents can be transferred on a boot medium (SD card or eMMC) such that the primary boot loader of the target device can discover the system and boot it.<br />
<br />
Unless you restrict the type of packaging used for the image file, Yocto will generate multiple rootfs packages, each with a large footprint. To restrict the generated image files to a desired type, edit ''conf/local.conf'' of your project build directory and set the type.<br />
<pre class="code"><br />
#IMAGE_FSTYPES = "tar.gz"<br />
#IMAGE_FSTYPES = "tar.bz2"<br />
IMAGE_FSTYPES = "wic.bz2 wic.bmap"<br />
</pre><br />
The wic ([https://pykickstart.readthedocs.io/en/latest/kickstart-docs.html kickstart]) format with accompanying [https://github.com/intel/bmap-tools bmap] is recommended.<br />
<br /><br />
<br />
== Installing the Rootfs Image ==<br />
Using [https://github.com/intel/bmap-tools bmaptool] we can copy the generated ''wic'' image (with matching bmap file) to a mounted SD card or eMMC storage.<br />
<pre class="terminal"><br />
sudo bmaptool copy tmp/deploy/images/raspberrypi4-64/<wic.bz2 file> <drive><br />
</pre><br />
where ''<wic.bz2 file>'' is the root filesystem image wic.bz2 file, and ''<drive>'' is the drive at which the storage is mounted (for example, ''/dev/sdb'').<br />
<br /><br />
<br /><br />
<br />
= Package Groups =<br />
Package groups are recipes that inherit from '''meta/classes/packagegroup.bbclass''' and set the content of the global variable '''PACKAGES'''. Package groups are defined in recipe files with the file extension 'bb'.<br />
<br /><br />
<br /><br />
Note that the ''packagegroup'' must be inherited before ''PACKAGES is defined.<br />
<pre class="code"><br />
inherit packagegroup<br />
<br />
PACKAGES = '...'<br />
</pre><br />
<br /><br />
<br />
= Useful Image Features =<br />
<br /><br />
<br />
== Distro Features ==<br />
Distro features are system features that affect multiple recipes. '''Large parts of the Poky image may need to be rebaked after making changes to the distro features!'''<br />
<br /><br />
<br />
=== systemd ===<br />
In the ''conf/local.conf'' file of your project build directory (or ''layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " systemd"<br />
</pre><br />
<br /><br />
<br />
=== NFS ===<br />
In Embedded Linux projects, NFS is often included in development images to enable faster code-deploy turnaround times.<br />
<br /><br />
In the ''conf/local.conf'' file of your Yocto build directory (or ''conf/layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " nfs"<br />
</pre><br />
<br /><br />
On your Debian-based Yocto machine, [[Ubuntu#Setting_up_an_NFS_Server|set up an SSH server]].<br />
<br /><br />
<br /><br />
In Yocto, use the directory<br />
<br /><br />
: '''{YOCTO_BUILD_DIR}/tmp/work/{TARGET}-poky-linux/{IMAGE}/1.0-r0/rootfs'''<br />
as the root directory provided by the NFS server. For example,<br />
: ''build-robofish-core/tmp/work/raspberrypi4_64-poky-linux/robofish-core-image-dev/1.0-r0/rootfs''<br />
<br /><br />
<br /><br />
<br />
=== [https://vulkan.org Vulkan] and [https://opengl.org OpenGL] ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " vulkan opengl x11 wayland"<br />
</pre><br />
<br /><br />
<br />
=== Bluetooth and NFC ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " bluetooth nfc"<br />
</pre><br />
<br /><br />
<br />
= Recipes =<br />
Recipes are Yocto metadata files that are interpreted by Bitbake and describe how a build task is performed.<br />
<br /><br />
== Patching A Device Tree ==<br />
Follow these steps to patch an existing device tree by creating an ''append recipe'' in a custom layer.<br />
<br /><br />
<br /><br />
In the custom layer, create the directory for a linux kernel append recipe.<br />
<pre class="terminal"><br />
mkdir -p ${LAYER_DIR}/recipes-kernel/linux/files<br />
</pre><br />
where it is assumed that ''${LAYER_DIR}'' contains the path to the root directory of the custom Yocto layer. <br />
<br /><br />
<br /><br />
Copy the kernel device tree file from your Yocto project build directory to the ''files'' directory of your new recipe. For a Raspberry Pi Compute Module 4, for example, type<br />
<pre class="terminal"><br />
cp ${YOCTO_BUILD_DIR}/tmp/work-shared/${MACHINE}/kernel-source/arch/arm/boot/dts/some.dts ${LAYER_DIR}/recipes-kernel/linux/files/<br />
</pre><br />
where ''${YOCTO_BUILD_DIR}'' is the path to the Yocto project build directory, and ''${MACHINE}'' is the chosen target platform (e.g. "raspberrypi4-64").<br />
<br /><br />
<div class="sidenote"><br />
If the ''tmp/work-shared'' directory does not exists anymore, you can recreate it by typing<br />
<pre class="terminal"><br />
bitbake -c menuconfig virtual/kernel<br />
</pre><br />
and exiting the kernel configuration menu without making changes.<br />
</div><br />
<br /><br />
Make the necessary changes to the copied device tree file. Then create a git patch file using ''git diff'' as shown below<br />
<pre class="terminal"><br />
git diff --no-index {DTS_DIR}/some.dts some.dts > 0001-my_modifications-dts.patch<br />
</pre><br />
<br /><br />
Edit the generated patch file to fix the file paths at the top. The paths must be relative to the kernel sources directory:<br />
: ''${YOCTO_BUILD_DIR}'''''/tmp/work-shared/'''''${MACHINE}'''''/kernel-source'''<br />
The header should look like this:<br />
<pre class="code"><br />
diff --git a/arch/arm/boot/dts/some.dts b/some.dts<br />
index 6e99da1..4567735 100644<br />
--- a/arch/arm/boot/dts/some.dts<br />
+++ b/arch/arm/boot/dts/some.dts<br />
</pre><br />
where "--- a" and "+++ b" are followed by the same relative file path.<br />
<br />
<br /><br />
Create and edit the append recipe<br />
<pre class="terminal"><br />
vim ${LAYER_DIR}/recipes-kernel/linux/${KERNEL_NAME}_%.bbappend<br />
</pre><br />
where ''${KERNEL_NAME}'' is the kernel name, which usually starts with "linux-" (for example, ''linux-raspberrypi''), and ''_%'' denotes all versions of the kernel package.<br />
<br /><br />
<div class="sidenote"><br />
If in doubt, use the ''oe-pkgdata-util'' tool from within your build directory to find out the kernel name.<br />
<pre class="terminal"><br />
oe-pkgdata-util lookup-recipe kernel<br />
</pre><br />
</div><br />
The contents of the recipe file should be similar to this:<br />
<pre class="code"><br />
FILESEXTRAPATHS:prepend = "${THISDIR}:"<br />
SRC_URI += "file://0001-my_modifications-dts.patch"<br />
</pre><br />
where ''0001-my_modifications-dts.patch'' needs to be replaced with the actual patch file name.<br />
<br />
== Creating a New Device Tree ==<br />
Creating a new device tree requires an input dts file which completely defines the hardware configuration. The ''KERNEL_DEVICETREE'' variable is used to make the Linux kernel select the new device tree during booting.<br />
<pre class="code"><br />
inherit kernel-devicetree<br />
<br />
FILESEXTRAPATHS_prepend := "${THISDIR}/files:"<br />
<br />
# Make custom kernel with PRU enabled<br />
SRC_URI += " \<br />
file://some.dts \<br />
file://0001-some.patch \<br />
"<br />
<br />
KERNEL_DEVICETREE = "some.dtb"<br />
</pre><br />
<br /><br />
<br />
= Accessing the OpenEmbedded package collection =<br />
The OpenEmbedded project provides recipes for many useful programs that are not included with Yocto, like tmux, VLC, Gnome, various multimedia codecs, more filesystems, gRPC and much more.<br />
<br /><br />
To access the recipes for those software packages, clone the OpenEmbedded layers repository into your third-party layers directory: <br />
<pre class="terminal"><br />
git clone git://git.openembedded.org/meta-openembedded<br />
</pre><br />
<br /><br />
<br />
= devtool =<br />
<br />
Use '''devtool''' to make changes to an existing recipe and automatically generate an append recipe from those changes.<br />
<br /><br />
<br /><br />
<br />
== Initialization Manager ==<br />
After the kernel is done with its basic booting tasks, it passes control to the initialization manager. To use the ''systemd'' initialization manager (used by the Linux distributions Debian and Ubuntu) instead of ''SysVinit'', make the following entries in ''${TOPDIR}/conf/distro/distro.conf''<br />
<pre class="code"><br />
DISTRO_FEATURES_append = " systemd"<br />
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"<br />
VIRTUAL-RUNTIME_init_manager = "systemd"<br />
VIRTUAL-RUNTIME_initscripts = ""<br />
</pre><br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Yocto&diff=3159Yocto2022-12-25T17:40:44Z<p>Kai: /* Patching A Device Tree */</p>
<hr />
<div>= Yocto and OpenEmbedded =<br />
The collection of software tools used by the Yocto project have been developed by the [https://www.openembedded.org OpenEmbedded] project. The Yocto project basically uses these generic build tools to provide a basic Linux system called ''Poky''. Stable releases of Poky serve as standard platforms for third parties that provide additional features (e.g., hardware support layers).<br />
<br /><br />
<br /><br />
<br />
= Prerequisites =<br />
* A Linux system supported by the Yocto project.<br />Assuming that [[Ubuntu]] is used. <br />
* Following package installed:<br />
<pre class=terminal><br />
sudo apt install gcc g++ \<br />
python3-distutils python-is-python3<br />
</pre><br />
<br /><br />
<br />
= Bitbake =<br />
Bitbake is the build tool from the OpenEmbedded project, which parses the project's metadata, resolves dependencies and the ordering of the build steps, runs the builds to create packages, to finally create an image from the packages.<br />
<br /><br />
=== Metadata Types ===<br />
Yocto metadata, which controls how a system image is built, can be categorized at a high level into these four types:<br />
* ''Machine''<br />the targeted hardware platform (e.g. Raspberry Pi 4)<br />
* ''Distro''<br />common characteristic of a family of related images<br />
* ''Recipes''<br />instructions on how to process the source files for a component of the image<br />
* ''Image''<br />recipes that define the contents of generated system images<br />
<br /><br />
=== Layers ===<br />
Layers are purposeful collections of metadata. Yocto layers often Layers often add the provide that for a that can be combined with other layers in order to directories in which <br />
<br /><br />
<br />
<br /> <br />
<br />
= Images =<br />
<br />
Images are recipes that ultimately inherit from '''meta/classes/image.bbclass''' and set the global variable '''IMAGE_INSTALL'''. Most images, however, will inherit from ''meta/classes/core-image.bbclass'' which inherits directly from ''image.bbclass'', provides a mapping from ''IMAGE_FEATURES'' to package groups, and adds the two package groups ''packagegroup-core-boot'' and ''packagegroup-base-extended'' to ''IMAGE_INSTALL''.<br />
<br />
Images are defined in recipe files with the file extension 'bb'. In order to separate them from package recipes, there is a convention to put image recipes into a folder named ''images''. Making use of this, we can list all images defined by all layers via<br />
<pre class="terminal"><br />
cd poky<br />
ls meta*/recipes*/images/*.bb<br />
</pre><br />
<br /><br />
<br />
=== ''IMAGE_FEATURES'' ===<br />
The ''IMAGE_FEATURES'' variable is defined in ''meta/classes/image.bbclass'' with an empty value. It accepts only a predefined set of features (e.g., ''x11'', ''debug-tweaks'', ''dev-pkgs'', ''dbg-pkgs''). This affects how recipes will execute their tasks and which packages will be selected to go into the image. The image recipe ''meta/recipes-core/images/core-image-base.bb'', for example, adds the ''splash'' feature.<br />
<br /><br />
<br />
=== ''IMAGE_INSTALL'' ===<br />
Holds a list of package groups whose packages (from the package feed area) will go into the filesystem image.<br />
<br /><br />
<br />
== Reference images ==<br />
The following reference images are defined in the ''meta'' layer:<br />
{| style="padding: 10px;"<br />
! style="width: 20px" | || || <br />
|-<br />
| || ''core-image-minimal'' || small image that just boots the target device<br />
|-<br />
| || ''core-image-minimal-dev'' || ''core-image-minimal'' with headers and libraries allowing development work<br />
|-<br />
| || style="padding-right: 10px" | ''core-image-minimal-initramfs'' || ''core-image-minimal'' with kernel support for in-RAM filesystem<br />
|-<br />
| || '''core-image-base''' || '''console-only system fully supporting the target hardware'''<br />
|-<br />
| || ''core-image-full-cmdline'' || console-only image that includes many system tools<br />
|-<br />
| || ''core-image-x11'' || image with basic X11 and a terminal<br />
|-<br />
|}<br />
<br />
These image definitions are provided as a starting point for creating project-specific, custom image definitions.<br />
<br /><br />
<br /><br />
<br />
== Creating a Custom Image ==<br />
* In your custom layer, create the ''images'' subdirectory in one of your ''recipes-...' directory.<br />
* In the ''images'' directory, create two image recipe files that inherit from ''core-image'':<br />
<pre class="code"><br />
SUMMARY = "My deployment image"<br />
LICENSE = "MIT"<br />
<br />
inherit core-image<br />
IMAGE_FEATURES += "splash"<br />
</pre><br />
and<br />
<pre class="code"><br />
SUMMARY = "My development image"<br />
<br />
inherit core-image<br />
require my-image.bb<br />
<br />
IMAGE_FEATURES += "ssh-server-dropbear tools-debug debug-tweaks"<br />
<br />
CORE_IMAGE_EXTRA_INSTALL += "i2c-tools "<br />
</pre><br />
where the first image recipe is for deployment and the second is for development. Note that the development version includes the deployment version with the ''require'' statement, and adds to IMAGE_FEATURES and CORE_IMAGE_EXTRA_INSTALL.<br />
<br /><br />
<br />
== Image Filesystem Packaging ==<br />
The system image generated by Bitbake can be packaged in the form of an image file, whose contents can be transferred on a boot medium (SD card or eMMC) such that the primary boot loader of the target device can discover the system and boot it.<br />
<br />
Unless you restrict the type of packaging used for the image file, Yocto will generate multiple rootfs packages, each with a large footprint. To restrict the generated image files to a desired type, edit ''conf/local.conf'' of your project build directory and set the type.<br />
<pre class="code"><br />
#IMAGE_FSTYPES = "tar.gz"<br />
#IMAGE_FSTYPES = "tar.bz2"<br />
IMAGE_FSTYPES = "wic.bz2 wic.bmap"<br />
</pre><br />
The wic ([https://pykickstart.readthedocs.io/en/latest/kickstart-docs.html kickstart]) format with accompanying [https://github.com/intel/bmap-tools bmap] is recommended.<br />
<br /><br />
<br />
== Installing the Rootfs Image ==<br />
Using [https://github.com/intel/bmap-tools bmaptool] we can copy the generated ''wic'' image (with matching bmap file) to a mounted SD card or eMMC storage.<br />
<pre class="terminal"><br />
sudo bmaptool copy tmp/deploy/images/raspberrypi4-64/<wic.bz2 file> <drive><br />
</pre><br />
where ''<wic.bz2 file>'' is the root filesystem image wic.bz2 file, and ''<drive>'' is the drive at which the storage is mounted (for example, ''/dev/sdb'').<br />
<br /><br />
<br /><br />
<br />
= Package Groups =<br />
Package groups are recipes that inherit from '''meta/classes/packagegroup.bbclass''' and set the content of the global variable '''PACKAGES'''. Package groups are defined in recipe files with the file extension 'bb'.<br />
<br /><br />
<br /><br />
Note that the ''packagegroup'' must be inherited before ''PACKAGES is defined.<br />
<pre class="code"><br />
inherit packagegroup<br />
<br />
PACKAGES = '...'<br />
</pre><br />
<br /><br />
<br />
= Useful Image Features =<br />
<br /><br />
<br />
== Distro Features ==<br />
Distro features are system features that affect multiple recipes. '''Large parts of the Poky image may need to be rebaked after making changes to the distro features!'''<br />
<br /><br />
<br />
=== systemd ===<br />
In the ''conf/local.conf'' file of your project build directory (or ''layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " systemd"<br />
</pre><br />
<br /><br />
<br />
=== NFS ===<br />
In Embedded Linux projects, NFS is often included in development images to enable faster code-deploy turnaround times.<br />
<br /><br />
In the ''conf/local.conf'' file of your Yocto build directory (or ''conf/layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " nfs"<br />
</pre><br />
<br /><br />
On your Debian-based Yocto machine, [[Ubuntu#Setting_up_an_NFS_Server|set up an SSH server]].<br />
<br /><br />
<br /><br />
In Yocto, use the directory<br />
<br /><br />
: '''{YOCTO_BUILD_DIR}/tmp/work/{TARGET}-poky-linux/{IMAGE}/1.0-r0/rootfs'''<br />
as the root directory provided by the NFS server. For example,<br />
: ''build-robofish-core/tmp/work/raspberrypi4_64-poky-linux/robofish-core-image-dev/1.0-r0/rootfs''<br />
<br /><br />
<br /><br />
<br />
=== [https://vulkan.org Vulkan] and [https://opengl.org OpenGL] ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " vulkan opengl x11 wayland"<br />
</pre><br />
<br /><br />
<br />
=== Bluetooth and NFC ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " bluetooth nfc"<br />
</pre><br />
<br /><br />
<br />
= Recipes =<br />
Recipes are Yocto metadata files that are interpreted by Bitbake and describe how a build task is performed.<br />
<br /><br />
== Patching A Device Tree ==<br />
Follow these steps to patch an existing device tree by creating an ''append recipe'' in a custom layer.<br />
<br /><br />
<br /><br />
In the custom layer, create the directory for a linux kernel append recipe.<br />
<pre class="terminal"><br />
mkdir -p ${LAYER_DIR}/recipes-kernel/linux/files<br />
</pre><br />
where it is assumed that ''${LAYER_DIR}'' contains the path to the root directory of the custom Yocto layer. <br />
<br /><br />
<br /><br />
Copy the kernel device tree file from your Yocto project build directory to the ''files'' directory of your new recipe. For a Raspberry Pi Compute Module 4, for example, type<br />
<pre class="terminal"><br />
cp ${YOCTO_BUILD_DIR}/tmp/work-shared/${MACHINE}/kernel-source/arch/arm/boot/dts/some.dts ${LAYER_DIR}/recipes-kernel/linux/files/<br />
</pre><br />
where ''${YOCTO_BUILD_DIR}'' is the path to the Yocto project build directory, and ''${MACHINE}'' is the chosen target platform (e.g. "raspberrypi4-64").<br />
<br /><br />
<div class="sidenote"><br />
If the ''tmp/work-shared'' directory does not exists anymore, you can recreate it by typing<br />
<pre class="terminal"><br />
bitbake -c menuconfig virtual/kernel<br />
</pre><br />
and exiting the kernel configuration menu without making changes.<br />
</div><br />
<br /><br />
Make the necessary changes to the copied device tree file. Then create a git patch file using ''git diff'' as shown below<br />
<pre class="terminal"><br />
git diff --no-index {DTS_DIR}/some.dts some.dts > 0001-my_modifications-dts.patch<br />
</pre><br />
<br /><br />
Edit the generated patch file to fix the file paths at the top. The paths must be relative to the kernel sources directory:<br />
: ''${YOCTO_BUILD_DIR}'''''/tmp/work-shared/'''''${MACHINE}'''''/kernel-source'''<br />
The header should look like this:<br />
<pre class="code"><br />
diff --git a/arch/arm/boot/dts/some.dts b/some.dts<br />
index 6e99da1..4567735 100644<br />
--- a/arch/arm/boot/dts/some.dts<br />
+++ b/arch/arm/boot/dts/some.dts<br />
</pre><br />
where "--- a" and "+++ b" are followed by the same relative file path.<br />
<br />
<br /><br />
Create and edit the append recipe<br />
<pre class="terminal"><br />
vim ${LAYER_DIR}/recipes-kernel/linux/${KERNEL_NAME}_%.bbappend<br />
</pre><br />
where ''${KERNEL_NAME}'' is the kernel name, which usually starts with "linux-" (for example, ''linux-raspberrypi''), and ''_%'' denotes all versions of the kernel package.<br />
<br /><br />
<div class="sidenote"><br />
If in doubt, use the ''oe-pkgdata-util'' tool from within your build directory to find out the kernel name.<br />
<pre class="terminal"><br />
oe-pkgdata-util lookup-recipe kernel<br />
</pre><br />
</div><br />
The contents of the recipe file should be similar to this:<br />
<pre class="code"><br />
FILESEXTRAPATHS:prepend = "${THISDIR}:"<br />
SRC_URI += "file://0001-my_modifications-dts.patch"<br />
</pre><br />
where ''0001-my_modifications-dts.patch'' needs to be replaced with the actual patch file name.<br />
<br />
<br /><br />
<br />
= Accessing the OpenEmbedded package collection =<br />
The OpenEmbedded project provides recipes for many useful programs that are not included with Yocto, like tmux, VLC, Gnome, various multimedia codecs, more filesystems, gRPC and much more.<br />
<br /><br />
To access the recipes for those software packages, clone the OpenEmbedded layers repository into your third-party layers directory: <br />
<pre class="terminal"><br />
git clone git://git.openembedded.org/meta-openembedded<br />
</pre><br />
<br /><br />
<br />
= devtool =<br />
<br />
Use '''devtool''' to make changes to an existing recipe and automatically generate an append recipe from those changes.<br />
<br /><br />
<br /><br />
<br />
== Initialization Manager ==<br />
After the kernel is done with its basic booting tasks, it passes control to the initialization manager. To use the ''systemd'' initialization manager (used by the Linux distributions Debian and Ubuntu) instead of ''SysVinit'', make the following entries in ''${TOPDIR}/conf/distro/distro.conf''<br />
<pre class="code"><br />
DISTRO_FEATURES_append = " systemd"<br />
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"<br />
VIRTUAL-RUNTIME_init_manager = "systemd"<br />
VIRTUAL-RUNTIME_initscripts = ""<br />
</pre><br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=MediaWiki:Common.css&diff=3158MediaWiki:Common.css2022-12-25T17:27:09Z<p>Kai: </p>
<hr />
<div>/* CSS placed here will be applied to all skins */<br />
<br />
body.page-Main_Page .title, body.page-Main_Page #tagline<br />
{<br />
display: none;<br />
}<br />
<br />
.tocnumber<br />
{<br />
display: none;<br />
}<br />
<br />
/* source code */<br />
pre.code<br />
{<br />
color: black;<br />
background: #eee;<br />
border: 0px solid #eee;<br />
border-radius: 6px;<br />
}<br />
span.code<br />
{<br />
color: black;<br />
background: #eee;<br />
border-radius: 6px;<br />
padding-left: 4px;<br />
padding-right: 4px;<br />
}<br />
<br />
/* terminal commands */<br />
pre.terminal<br />
{<br />
color: #ffe;<br />
background: #888;<br />
border: 0px solid #888;<br />
border-radius: 6px;<br />
}<br />
span.terminal<br />
{<br />
color: #ffe;<br />
background: #888;<br />
border-radius: 6px;<br />
padding-left: 4px;<br />
padding-right: 4px;<br />
}<br />
<br />
/* side note area */<br />
div.sidenote<br />
{<br />
background: #f8f8f0;<br />
margin-left: 1em;<br />
padding-left: 1em;<br />
padding-right: 1em;<br />
padding-top: 0.5em;<br />
padding-bottom: 0.5em;<br />
border-radius: 6px;<br />
}</div>Kaihttps://Robo.Fish/wiki/index.php?title=MediaWiki:Common.css&diff=3157MediaWiki:Common.css2022-12-25T17:24:50Z<p>Kai: </p>
<hr />
<div>/* CSS placed here will be applied to all skins */<br />
<br />
body.page-Main_Page .title, body.page-Main_Page #tagline<br />
{<br />
display: none;<br />
}<br />
<br />
.tocnumber<br />
{<br />
display: none;<br />
}<br />
<br />
/* source code */<br />
pre.code<br />
{<br />
color: black;<br />
background: #eee;<br />
border: 0px solid #eee;<br />
border-radius: 0.5em;<br />
}<br />
span.code<br />
{<br />
color: black;<br />
background: #eee;<br />
border-radius: 6px;<br />
padding-left: 4px;<br />
padding-right: 4px;<br />
}<br />
<br />
/* terminal commands */<br />
pre.terminal<br />
{<br />
color: #ffe;<br />
background: #888;<br />
border: 0px solid #888;<br />
border-radius: 6px;<br />
padding-left: 0.5em;<br />
}<br />
span.terminal<br />
{<br />
color: #ffe;<br />
background: #888;<br />
border-radius: 6px;<br />
padding-left: 4px;<br />
padding-right: 4px;<br />
}<br />
<br />
/* side note area */<br />
div.sidenote<br />
{<br />
background: #f8f8f0;<br />
margin-left: 1em;<br />
padding-left: 1em;<br />
padding-right: 1em;<br />
padding-top: 0.5em;<br />
padding-bottom: 0.5em;<br />
border-radius: 6px;<br />
}</div>Kaihttps://Robo.Fish/wiki/index.php?title=Yocto&diff=3156Yocto2022-12-25T17:22:52Z<p>Kai: Adds diffing step for patch generation.</p>
<hr />
<div>= Yocto and OpenEmbedded =<br />
The collection of software tools used by the Yocto project have been developed by the [https://www.openembedded.org OpenEmbedded] project. The Yocto project basically uses these generic build tools to provide a basic Linux system called ''Poky''. Stable releases of Poky serve as standard platforms for third parties that provide additional features (e.g., hardware support layers).<br />
<br /><br />
<br /><br />
<br />
= Prerequisites =<br />
* A Linux system supported by the Yocto project.<br />Assuming that [[Ubuntu]] is used. <br />
* Following package installed:<br />
<pre class=terminal><br />
sudo apt install gcc g++ \<br />
python3-distutils python-is-python3<br />
</pre><br />
<br /><br />
<br />
= Bitbake =<br />
Bitbake is the build tool from the OpenEmbedded project, which parses the project's metadata, resolves dependencies and the ordering of the build steps, runs the builds to create packages, to finally create an image from the packages.<br />
<br /><br />
=== Metadata Types ===<br />
Yocto metadata, which controls how a system image is built, can be categorized at a high level into these four types:<br />
* ''Machine''<br />the targeted hardware platform (e.g. Raspberry Pi 4)<br />
* ''Distro''<br />common characteristic of a family of related images<br />
* ''Recipes''<br />instructions on how to process the source files for a component of the image<br />
* ''Image''<br />recipes that define the contents of generated system images<br />
<br /><br />
=== Layers ===<br />
Layers are purposeful collections of metadata. Yocto layers often Layers often add the provide that for a that can be combined with other layers in order to directories in which <br />
<br /><br />
<br />
<br /> <br />
<br />
= Images =<br />
<br />
Images are recipes that ultimately inherit from '''meta/classes/image.bbclass''' and set the global variable '''IMAGE_INSTALL'''. Most images, however, will inherit from ''meta/classes/core-image.bbclass'' which inherits directly from ''image.bbclass'', provides a mapping from ''IMAGE_FEATURES'' to package groups, and adds the two package groups ''packagegroup-core-boot'' and ''packagegroup-base-extended'' to ''IMAGE_INSTALL''.<br />
<br />
Images are defined in recipe files with the file extension 'bb'. In order to separate them from package recipes, there is a convention to put image recipes into a folder named ''images''. Making use of this, we can list all images defined by all layers via<br />
<pre class="terminal"><br />
cd poky<br />
ls meta*/recipes*/images/*.bb<br />
</pre><br />
<br /><br />
<br />
=== ''IMAGE_FEATURES'' ===<br />
The ''IMAGE_FEATURES'' variable is defined in ''meta/classes/image.bbclass'' with an empty value. It accepts only a predefined set of features (e.g., ''x11'', ''debug-tweaks'', ''dev-pkgs'', ''dbg-pkgs''). This affects how recipes will execute their tasks and which packages will be selected to go into the image. The image recipe ''meta/recipes-core/images/core-image-base.bb'', for example, adds the ''splash'' feature.<br />
<br /><br />
<br />
=== ''IMAGE_INSTALL'' ===<br />
Holds a list of package groups whose packages (from the package feed area) will go into the filesystem image.<br />
<br /><br />
<br />
== Reference images ==<br />
The following reference images are defined in the ''meta'' layer:<br />
{| style="padding: 10px;"<br />
! style="width: 20px" | || || <br />
|-<br />
| || ''core-image-minimal'' || small image that just boots the target device<br />
|-<br />
| || ''core-image-minimal-dev'' || ''core-image-minimal'' with headers and libraries allowing development work<br />
|-<br />
| || style="padding-right: 10px" | ''core-image-minimal-initramfs'' || ''core-image-minimal'' with kernel support for in-RAM filesystem<br />
|-<br />
| || '''core-image-base''' || '''console-only system fully supporting the target hardware'''<br />
|-<br />
| || ''core-image-full-cmdline'' || console-only image that includes many system tools<br />
|-<br />
| || ''core-image-x11'' || image with basic X11 and a terminal<br />
|-<br />
|}<br />
<br />
These image definitions are provided as a starting point for creating project-specific, custom image definitions.<br />
<br /><br />
<br /><br />
<br />
== Creating a Custom Image ==<br />
* In your custom layer, create the ''images'' subdirectory in one of your ''recipes-...' directory.<br />
* In the ''images'' directory, create two image recipe files that inherit from ''core-image'':<br />
<pre class="code"><br />
SUMMARY = "My deployment image"<br />
LICENSE = "MIT"<br />
<br />
inherit core-image<br />
IMAGE_FEATURES += "splash"<br />
</pre><br />
and<br />
<pre class="code"><br />
SUMMARY = "My development image"<br />
<br />
inherit core-image<br />
require my-image.bb<br />
<br />
IMAGE_FEATURES += "ssh-server-dropbear tools-debug debug-tweaks"<br />
<br />
CORE_IMAGE_EXTRA_INSTALL += "i2c-tools "<br />
</pre><br />
where the first image recipe is for deployment and the second is for development. Note that the development version includes the deployment version with the ''require'' statement, and adds to IMAGE_FEATURES and CORE_IMAGE_EXTRA_INSTALL.<br />
<br /><br />
<br />
== Image Filesystem Packaging ==<br />
The system image generated by Bitbake can be packaged in the form of an image file, whose contents can be transferred on a boot medium (SD card or eMMC) such that the primary boot loader of the target device can discover the system and boot it.<br />
<br />
Unless you restrict the type of packaging used for the image file, Yocto will generate multiple rootfs packages, each with a large footprint. To restrict the generated image files to a desired type, edit ''conf/local.conf'' of your project build directory and set the type.<br />
<pre class="code"><br />
#IMAGE_FSTYPES = "tar.gz"<br />
#IMAGE_FSTYPES = "tar.bz2"<br />
IMAGE_FSTYPES = "wic.bz2 wic.bmap"<br />
</pre><br />
The wic ([https://pykickstart.readthedocs.io/en/latest/kickstart-docs.html kickstart]) format with accompanying [https://github.com/intel/bmap-tools bmap] is recommended.<br />
<br /><br />
<br />
== Installing the Rootfs Image ==<br />
Using [https://github.com/intel/bmap-tools bmaptool] we can copy the generated ''wic'' image (with matching bmap file) to a mounted SD card or eMMC storage.<br />
<pre class="terminal"><br />
sudo bmaptool copy tmp/deploy/images/raspberrypi4-64/<wic.bz2 file> <drive><br />
</pre><br />
where ''<wic.bz2 file>'' is the root filesystem image wic.bz2 file, and ''<drive>'' is the drive at which the storage is mounted (for example, ''/dev/sdb'').<br />
<br /><br />
<br /><br />
<br />
= Package Groups =<br />
Package groups are recipes that inherit from '''meta/classes/packagegroup.bbclass''' and set the content of the global variable '''PACKAGES'''. Package groups are defined in recipe files with the file extension 'bb'.<br />
<br /><br />
<br /><br />
Note that the ''packagegroup'' must be inherited before ''PACKAGES is defined.<br />
<pre class="code"><br />
inherit packagegroup<br />
<br />
PACKAGES = '...'<br />
</pre><br />
<br /><br />
<br />
= Useful Image Features =<br />
<br /><br />
<br />
== Distro Features ==<br />
Distro features are system features that affect multiple recipes. '''Large parts of the Poky image may need to be rebaked after making changes to the distro features!'''<br />
<br /><br />
<br />
=== systemd ===<br />
In the ''conf/local.conf'' file of your project build directory (or ''layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " systemd"<br />
</pre><br />
<br /><br />
<br />
=== NFS ===<br />
In Embedded Linux projects, NFS is often included in development images to enable faster code-deploy turnaround times.<br />
<br /><br />
In the ''conf/local.conf'' file of your Yocto build directory (or ''conf/layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " nfs"<br />
</pre><br />
<br /><br />
On your Debian-based Yocto machine, [[Ubuntu#Setting_up_an_NFS_Server|set up an SSH server]].<br />
<br /><br />
<br /><br />
In Yocto, use the directory<br />
<br /><br />
: '''{YOCTO_BUILD_DIR}/tmp/work/{TARGET}-poky-linux/{IMAGE}/1.0-r0/rootfs'''<br />
as the root directory provided by the NFS server. For example,<br />
: ''build-robofish-core/tmp/work/raspberrypi4_64-poky-linux/robofish-core-image-dev/1.0-r0/rootfs''<br />
<br /><br />
<br /><br />
<br />
=== [https://vulkan.org Vulkan] and [https://opengl.org OpenGL] ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " vulkan opengl x11 wayland"<br />
</pre><br />
<br /><br />
<br />
=== Bluetooth and NFC ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " bluetooth nfc"<br />
</pre><br />
<br /><br />
<br />
= Recipes =<br />
Recipes are Yocto metadata files that are interpreted by Bitbake and describe how a build task is performed.<br />
<br /><br />
== Patching A Device Tree ==<br />
Follow these steps to patch an existing device tree by creating an ''append recipe'' in a custom layer.<br />
<br /><br />
<br /><br />
In the custom layer, create the directory for a linux kernel append recipe.<br />
<pre class="terminal"><br />
mkdir -p ${LAYER_DIR}/recipes-kernel/linux/files<br />
</pre><br />
where it is assumed that ''${LAYER_DIR}'' contains the path to the root directory of the custom Yocto layer. <br />
<br /><br />
<br /><br />
Copy the kernel device tree file from your Yocto project build directory to the ''files'' directory of your new recipe. For a Raspberry Pi Compute Module 4, for example, type<br />
<pre class="terminal"><br />
cp ${YOCTO_BUILD_DIR}/tmp/work-shared/${MACHINE}/kernel-source/arch/arm/boot/dts/some.dts ${LAYER_DIR}/recipes-kernel/linux/files/<br />
</pre><br />
where ''${YOCTO_BUILD_DIR}'' is the path to the Yocto project build directory, and ''${MACHINE}'' is the chosen target platform (e.g. "raspberrypi4-64").<br />
<br /><br />
<div class="sidenote"><br />
If the ''tmp/work-shared'' directory does not exists anymore, you can recreate it by typing<br />
<pre class="terminal"><br />
bitbake -c menuconfig virtual/kernel<br />
</pre><br />
and exiting the kernel configuration menu without making changes.<br />
</div><br />
<br /><br />
Make the necessary changes to the copied device tree file. Then create a git patch file using ''git diff'' as shown below<br />
<pre class="terminal"><br />
git diff --no-index {DTS_DIR}/some.dts some.dts > 0001-my_modifications-dts.patch<br />
</pre><br />
<br /><br />
Edit the generated patch file to fix the file paths at the top. The paths must be relative to the kernel sources directory:<br />
: ''${YOCTO_BUILD_DIR}'''''/tmp/work-shared/'''''${MACHINE}'''''/kernel-source'''<br />
The header should look like this:<br />
<pre class="code"><br />
diff --git a/arch/arm/boot/dts/some.dts b/some.dts<br />
index 6e99da1..4567735 100644<br />
--- a/arch/arm/boot/dts/some.dts<br />
+++ b/arch/arm/boot/dts/some.dts<br />
</pre><br />
where "--- a" and "+++ b" are followed by the same relative file path.<br />
<br />
<br /><br />
Create and edit the append recipe<br />
<pre class="terminal"><br />
vim ${LAYER_DIR}/recipes-kernel/linux/linux-<platform>_%.bbappend<br />
</pre><br />
where ''platform'' is the hardware or machine designator (for example, ''raspberrypi'').<br />
<br /><br />
<div class="sidenote"><br />
If in doubt, use the ''oe-pkgdata-util'' tool from within your build directory to find out the kernel name.<br />
<pre class="terminal"><br />
oe-pkgdata-util lookup-recipe kernel<br />
</pre><br />
</div><br />
The contents of the recipe file should be similar to this:<br />
<pre class="code"><br />
FILESEXTRAPATHS:prepend = "${THISDIR}:"<br />
SRC_URI += "file://0001-my_modifications-dts.patch"<br />
</pre><br />
where ''0001-my_modifications-dts.patch'' needs to be replaced with the actual patch file name.<br />
<br />
<br /><br />
<br />
= Accessing the OpenEmbedded package collection =<br />
The OpenEmbedded project provides recipes for many useful programs that are not included with Yocto, like tmux, VLC, Gnome, various multimedia codecs, more filesystems, gRPC and much more.<br />
<br /><br />
To access the recipes for those software packages, clone the OpenEmbedded layers repository into your third-party layers directory: <br />
<pre class="terminal"><br />
git clone git://git.openembedded.org/meta-openembedded<br />
</pre><br />
<br /><br />
<br />
= devtool =<br />
<br />
Use '''devtool''' to make changes to an existing recipe and automatically generate an append recipe from those changes.<br />
<br /><br />
<br /><br />
<br />
== Initialization Manager ==<br />
After the kernel is done with its basic booting tasks, it passes control to the initialization manager. To use the ''systemd'' initialization manager (used by the Linux distributions Debian and Ubuntu) instead of ''SysVinit'', make the following entries in ''${TOPDIR}/conf/distro/distro.conf''<br />
<pre class="code"><br />
DISTRO_FEATURES_append = " systemd"<br />
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"<br />
VIRTUAL-RUNTIME_init_manager = "systemd"<br />
VIRTUAL-RUNTIME_initscripts = ""<br />
</pre><br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=MediaWiki:Common.css&diff=3155MediaWiki:Common.css2022-12-25T17:04:59Z<p>Kai: </p>
<hr />
<div>/* CSS placed here will be applied to all skins */<br />
<br />
body.page-Main_Page .title, body.page-Main_Page #tagline<br />
{<br />
display: none;<br />
}<br />
<br />
.tocnumber<br />
{<br />
display: none;<br />
}<br />
<br />
/* source code */<br />
pre.code<br />
{<br />
color: black;<br />
background: #eee;<br />
border: 0px solid #eee;<br />
border-radius: 6px;<br />
}<br />
span.code<br />
{<br />
color: black;<br />
background: #eee;<br />
border-radius: 6px;<br />
padding-left: 4px;<br />
padding-right: 4px;<br />
}<br />
<br />
/* terminal commands */<br />
pre.terminal<br />
{<br />
color: #ffe;<br />
background: #888;<br />
border: 0px solid #888;<br />
border-radius: 6px;<br />
padding-left: 6px;<br />
}<br />
span.terminal<br />
{<br />
color: #ffe;<br />
background: #888;<br />
border-radius: 6px;<br />
padding-left: 4px;<br />
padding-right: 4px;<br />
}<br />
<br />
/* side note area */<br />
div.sidenote<br />
{<br />
background: #f8f8f0;<br />
margin-left: 1em;<br />
padding-left: 1em;<br />
padding-right: 1em;<br />
padding-top: 0.5em;<br />
padding-bottom: 0.5em;<br />
border-radius: 6px;<br />
}</div>Kaihttps://Robo.Fish/wiki/index.php?title=MediaWiki:Common.css&diff=3154MediaWiki:Common.css2022-12-25T17:01:36Z<p>Kai: </p>
<hr />
<div>/* CSS placed here will be applied to all skins */<br />
<br />
body.page-Main_Page .title, body.page-Main_Page #tagline<br />
{<br />
display: none;<br />
}<br />
<br />
.tocnumber<br />
{<br />
display: none;<br />
}<br />
<br />
/* source code */<br />
pre.code<br />
{<br />
color: black;<br />
background: #eee;<br />
border: 0px solid #eee;<br />
border-radius: 6px;<br />
}<br />
span.code<br />
{<br />
color: black;<br />
background: #eee;<br />
border-radius: 6px;<br />
padding-left: 4px;<br />
padding-right: 4px;<br />
}<br />
<br />
/* terminal commands */<br />
pre.terminal<br />
{<br />
color: #ffe;<br />
background: #888;<br />
border: 0px solid #888;<br />
border-radius: 6px;<br />
padding-left: 6px;<br />
}<br />
span.terminal<br />
{<br />
color: #ffe;<br />
background: #888;<br />
border-radius: 6px;<br />
padding-left: 4px;<br />
padding-right: 4px;<br />
}<br />
<br />
/* side note area */<br />
div.sidenote<br />
{<br />
background: #f8f8f0;<br />
padding-left: 1em;<br />
padding-right: 1em;<br />
padding-top: 0.5em;<br />
padding-bottom: 0.5em;<br />
border-radius: 6px;<br />
}</div>Kaihttps://Robo.Fish/wiki/index.php?title=MediaWiki:Common.css&diff=3153MediaWiki:Common.css2022-12-25T17:00:33Z<p>Kai: </p>
<hr />
<div>/* CSS placed here will be applied to all skins */<br />
<br />
body.page-Main_Page .title, body.page-Main_Page #tagline<br />
{<br />
display: none;<br />
}<br />
<br />
.tocnumber<br />
{<br />
display: none;<br />
}<br />
<br />
/* source code */<br />
pre.code<br />
{<br />
color: black;<br />
background: #eee;<br />
border: 0.1em solid #eee;<br />
border-radius: 6px;<br />
}<br />
span.code<br />
{<br />
color: black;<br />
background: #eee;<br />
border-radius: 6px;<br />
padding-left: 4px;<br />
padding-right: 4px;<br />
}<br />
<br />
/* terminal commands */<br />
pre.terminal<br />
{<br />
color: #ffe;<br />
background: #888;<br />
border: 0.1em solid #888;<br />
border-radius: 6px;<br />
padding-left: 6px;<br />
}<br />
span.terminal<br />
{<br />
color: #ffe;<br />
background: #888;<br />
border-radius: 6px;<br />
padding-left: 4px;<br />
padding-right: 4px;<br />
}<br />
<br />
/* side note area */<br />
div.sidenote<br />
{<br />
background: #f8f8f0;<br />
padding-left: 1em;<br />
padding-right: 1em;<br />
padding-top: 0.5em;<br />
padding-bottom: 0.5em;<br />
border-radius: 6px;<br />
}</div>Kaihttps://Robo.Fish/wiki/index.php?title=MediaWiki:Common.css&diff=3152MediaWiki:Common.css2022-12-25T16:57:55Z<p>Kai: </p>
<hr />
<div>/* CSS placed here will be applied to all skins */<br />
<br />
body.page-Main_Page .title, body.page-Main_Page #tagline<br />
{<br />
display: none;<br />
}<br />
<br />
.tocnumber<br />
{<br />
display: none;<br />
}<br />
<br />
/* source code */<br />
pre.code<br />
{<br />
color: black;<br />
background: #eee;<br />
border: 0.2em solid #eee;<br />
border-radius: 6px;<br />
}<br />
span.code<br />
{<br />
color: black;<br />
background: #eee;<br />
border-radius: 6px;<br />
padding-left: 4px;<br />
padding-right: 4px;<br />
}<br />
<br />
/* terminal commands */<br />
pre.terminal<br />
{<br />
color: #ffe;<br />
background: #888;<br />
border: 4px solid #888;<br />
border-radius: 6px;<br />
padding-left: 6px;<br />
}<br />
span.terminal<br />
{<br />
color: #ffe;<br />
background: #888;<br />
border-radius: 6px;<br />
padding-left: 4px;<br />
padding-right: 4px;<br />
}<br />
<br />
/* side note area */<br />
div.sidenote<br />
{<br />
background: #f8f8f0;<br />
padding-left: 1em;<br />
padding-right: 1em;<br />
padding-top: 0.5em;<br />
padding-bottom: 0.5em;<br />
border-radius: 6px;<br />
}</div>Kaihttps://Robo.Fish/wiki/index.php?title=MediaWiki:Common.css&diff=3151MediaWiki:Common.css2022-12-25T16:56:03Z<p>Kai: </p>
<hr />
<div>/* CSS placed here will be applied to all skins */<br />
<br />
body.page-Main_Page .title, body.page-Main_Page #tagline<br />
{<br />
display: none;<br />
}<br />
<br />
.tocnumber<br />
{<br />
display: none;<br />
}<br />
<br />
/* source code */<br />
pre.code<br />
{<br />
color: black;<br />
background: #eee;<br />
border: 0.4em solid #eee;<br />
border-radius: 6px;<br />
}<br />
span.code<br />
{<br />
color: black;<br />
background: #eee;<br />
border-radius: 6px;<br />
padding-left: 4px;<br />
padding-right: 4px;<br />
}<br />
<br />
/* terminal commands */<br />
pre.terminal<br />
{<br />
color: #ffe;<br />
background: #888;<br />
border: 0.2em solid #888;<br />
border-radius: 6px;<br />
padding-left: 6px;<br />
}<br />
span.terminal<br />
{<br />
color: #ffe;<br />
background: #888;<br />
border-radius: 6px;<br />
padding-left: 4px;<br />
padding-right: 4px;<br />
}<br />
<br />
/* side note area */<br />
div.sidenote<br />
{<br />
background: #f8f8f0;<br />
padding-left: 1em;<br />
padding-right: 1em;<br />
padding-top: 0.5em;<br />
padding-bottom: 0.5em;<br />
border-radius: 6px;<br />
}</div>Kaihttps://Robo.Fish/wiki/index.php?title=MediaWiki:Common.css&diff=3150MediaWiki:Common.css2022-12-25T16:51:46Z<p>Kai: </p>
<hr />
<div>/* CSS placed here will be applied to all skins */<br />
<br />
body.page-Main_Page .title, body.page-Main_Page #tagline<br />
{<br />
display: none;<br />
}<br />
<br />
.tocnumber<br />
{<br />
display: none;<br />
}<br />
<br />
/* source code */<br />
pre.code<br />
{<br />
color: black;<br />
background: #eee;<br />
border: 0.8em solid #eee;<br />
border-radius: 6px;<br />
}<br />
span.code<br />
{<br />
color: black;<br />
background: #eee;<br />
border-radius: 6px;<br />
padding-left: 4px;<br />
padding-right: 4px;<br />
}<br />
<br />
/* terminal commands */<br />
pre.terminal<br />
{<br />
color: #ffe;<br />
background: #888;<br />
border: 0.4em solid #888;<br />
border-radius: 6px;<br />
padding-left: 6px;<br />
}<br />
span.terminal<br />
{<br />
color: #ffe;<br />
background: #888;<br />
border-radius: 6px;<br />
padding-left: 4px;<br />
padding-right: 4px;<br />
}<br />
<br />
/* side note area */<br />
div.sidenote<br />
{<br />
background: #f8f8f0;<br />
padding-left: 1em;<br />
padding-right: 1em;<br />
padding-top: 0.5em;<br />
padding-bottom: 0.5em;<br />
border-radius: 6px;<br />
}</div>Kaihttps://Robo.Fish/wiki/index.php?title=Yocto&diff=3149Yocto2022-12-25T16:50:53Z<p>Kai: /* Patching A Device Tree */</p>
<hr />
<div>= Yocto and OpenEmbedded =<br />
The collection of software tools used by the Yocto project have been developed by the [https://www.openembedded.org OpenEmbedded] project. The Yocto project basically uses these generic build tools to provide a basic Linux system called ''Poky''. Stable releases of Poky serve as standard platforms for third parties that provide additional features (e.g., hardware support layers).<br />
<br /><br />
<br /><br />
<br />
= Prerequisites =<br />
* A Linux system supported by the Yocto project.<br />Assuming that [[Ubuntu]] is used. <br />
* Following package installed:<br />
<pre class=terminal><br />
sudo apt install gcc g++ \<br />
python3-distutils python-is-python3<br />
</pre><br />
<br /><br />
<br />
= Bitbake =<br />
Bitbake is the build tool from the OpenEmbedded project, which parses the project's metadata, resolves dependencies and the ordering of the build steps, runs the builds to create packages, to finally create an image from the packages.<br />
<br /><br />
=== Metadata Types ===<br />
Yocto metadata, which controls how a system image is built, can be categorized at a high level into these four types:<br />
* ''Machine''<br />the targeted hardware platform (e.g. Raspberry Pi 4)<br />
* ''Distro''<br />common characteristic of a family of related images<br />
* ''Recipes''<br />instructions on how to process the source files for a component of the image<br />
* ''Image''<br />recipes that define the contents of generated system images<br />
<br /><br />
=== Layers ===<br />
Layers are purposeful collections of metadata. Yocto layers often Layers often add the provide that for a that can be combined with other layers in order to directories in which <br />
<br /><br />
<br />
<br /> <br />
<br />
= Images =<br />
<br />
Images are recipes that ultimately inherit from '''meta/classes/image.bbclass''' and set the global variable '''IMAGE_INSTALL'''. Most images, however, will inherit from ''meta/classes/core-image.bbclass'' which inherits directly from ''image.bbclass'', provides a mapping from ''IMAGE_FEATURES'' to package groups, and adds the two package groups ''packagegroup-core-boot'' and ''packagegroup-base-extended'' to ''IMAGE_INSTALL''.<br />
<br />
Images are defined in recipe files with the file extension 'bb'. In order to separate them from package recipes, there is a convention to put image recipes into a folder named ''images''. Making use of this, we can list all images defined by all layers via<br />
<pre class="terminal"><br />
cd poky<br />
ls meta*/recipes*/images/*.bb<br />
</pre><br />
<br /><br />
<br />
=== ''IMAGE_FEATURES'' ===<br />
The ''IMAGE_FEATURES'' variable is defined in ''meta/classes/image.bbclass'' with an empty value. It accepts only a predefined set of features (e.g., ''x11'', ''debug-tweaks'', ''dev-pkgs'', ''dbg-pkgs''). This affects how recipes will execute their tasks and which packages will be selected to go into the image. The image recipe ''meta/recipes-core/images/core-image-base.bb'', for example, adds the ''splash'' feature.<br />
<br /><br />
<br />
=== ''IMAGE_INSTALL'' ===<br />
Holds a list of package groups whose packages (from the package feed area) will go into the filesystem image.<br />
<br /><br />
<br />
== Reference images ==<br />
The following reference images are defined in the ''meta'' layer:<br />
{| style="padding: 10px;"<br />
! style="width: 20px" | || || <br />
|-<br />
| || ''core-image-minimal'' || small image that just boots the target device<br />
|-<br />
| || ''core-image-minimal-dev'' || ''core-image-minimal'' with headers and libraries allowing development work<br />
|-<br />
| || style="padding-right: 10px" | ''core-image-minimal-initramfs'' || ''core-image-minimal'' with kernel support for in-RAM filesystem<br />
|-<br />
| || '''core-image-base''' || '''console-only system fully supporting the target hardware'''<br />
|-<br />
| || ''core-image-full-cmdline'' || console-only image that includes many system tools<br />
|-<br />
| || ''core-image-x11'' || image with basic X11 and a terminal<br />
|-<br />
|}<br />
<br />
These image definitions are provided as a starting point for creating project-specific, custom image definitions.<br />
<br /><br />
<br /><br />
<br />
== Creating a Custom Image ==<br />
* In your custom layer, create the ''images'' subdirectory in one of your ''recipes-...' directory.<br />
* In the ''images'' directory, create two image recipe files that inherit from ''core-image'':<br />
<pre class="code"><br />
SUMMARY = "My deployment image"<br />
LICENSE = "MIT"<br />
<br />
inherit core-image<br />
IMAGE_FEATURES += "splash"<br />
</pre><br />
and<br />
<pre class="code"><br />
SUMMARY = "My development image"<br />
<br />
inherit core-image<br />
require my-image.bb<br />
<br />
IMAGE_FEATURES += "ssh-server-dropbear tools-debug debug-tweaks"<br />
<br />
CORE_IMAGE_EXTRA_INSTALL += "i2c-tools "<br />
</pre><br />
where the first image recipe is for deployment and the second is for development. Note that the development version includes the deployment version with the ''require'' statement, and adds to IMAGE_FEATURES and CORE_IMAGE_EXTRA_INSTALL.<br />
<br /><br />
<br />
== Image Filesystem Packaging ==<br />
The system image generated by Bitbake can be packaged in the form of an image file, whose contents can be transferred on a boot medium (SD card or eMMC) such that the primary boot loader of the target device can discover the system and boot it.<br />
<br />
Unless you restrict the type of packaging used for the image file, Yocto will generate multiple rootfs packages, each with a large footprint. To restrict the generated image files to a desired type, edit ''conf/local.conf'' of your project build directory and set the type.<br />
<pre class="code"><br />
#IMAGE_FSTYPES = "tar.gz"<br />
#IMAGE_FSTYPES = "tar.bz2"<br />
IMAGE_FSTYPES = "wic.bz2 wic.bmap"<br />
</pre><br />
The wic ([https://pykickstart.readthedocs.io/en/latest/kickstart-docs.html kickstart]) format with accompanying [https://github.com/intel/bmap-tools bmap] is recommended.<br />
<br /><br />
<br />
== Installing the Rootfs Image ==<br />
Using [https://github.com/intel/bmap-tools bmaptool] we can copy the generated ''wic'' image (with matching bmap file) to a mounted SD card or eMMC storage.<br />
<pre class="terminal"><br />
sudo bmaptool copy tmp/deploy/images/raspberrypi4-64/<wic.bz2 file> <drive><br />
</pre><br />
where ''<wic.bz2 file>'' is the root filesystem image wic.bz2 file, and ''<drive>'' is the drive at which the storage is mounted (for example, ''/dev/sdb'').<br />
<br /><br />
<br /><br />
<br />
= Package Groups =<br />
Package groups are recipes that inherit from '''meta/classes/packagegroup.bbclass''' and set the content of the global variable '''PACKAGES'''. Package groups are defined in recipe files with the file extension 'bb'.<br />
<br /><br />
<br /><br />
Note that the ''packagegroup'' must be inherited before ''PACKAGES is defined.<br />
<pre class="code"><br />
inherit packagegroup<br />
<br />
PACKAGES = '...'<br />
</pre><br />
<br /><br />
<br />
= Useful Image Features =<br />
<br /><br />
<br />
== Distro Features ==<br />
Distro features are system features that affect multiple recipes. '''Large parts of the Poky image may need to be rebaked after making changes to the distro features!'''<br />
<br /><br />
<br />
=== systemd ===<br />
In the ''conf/local.conf'' file of your project build directory (or ''layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " systemd"<br />
</pre><br />
<br /><br />
<br />
=== NFS ===<br />
In Embedded Linux projects, NFS is often included in development images to enable faster code-deploy turnaround times.<br />
<br /><br />
In the ''conf/local.conf'' file of your Yocto build directory (or ''conf/layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " nfs"<br />
</pre><br />
<br /><br />
On your Debian-based Yocto machine, [[Ubuntu#Setting_up_an_NFS_Server|set up an SSH server]].<br />
<br /><br />
<br /><br />
In Yocto, use the directory<br />
<br /><br />
: '''{YOCTO_BUILD_DIR}/tmp/work/{TARGET}-poky-linux/{IMAGE}/1.0-r0/rootfs'''<br />
as the root directory provided by the NFS server. For example,<br />
: ''build-robofish-core/tmp/work/raspberrypi4_64-poky-linux/robofish-core-image-dev/1.0-r0/rootfs''<br />
<br /><br />
<br /><br />
<br />
=== [https://vulkan.org Vulkan] and [https://opengl.org OpenGL] ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " vulkan opengl x11 wayland"<br />
</pre><br />
<br /><br />
<br />
=== Bluetooth and NFC ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " bluetooth nfc"<br />
</pre><br />
<br /><br />
<br />
= Recipes =<br />
Recipes are Yocto metadata files that are interpreted by Bitbake and describe how a build task is performed.<br />
<br /><br />
== Patching A Device Tree ==<br />
Follow these steps to patch an existing device tree by creating an ''append recipe'' in a custom layer.<br />
<br /><br />
<br /><br />
In the custom layer, create the directory for a linux kernel append recipe.<br />
<pre class="terminal"><br />
mkdir -p ${LAYER_DIR}/recipes-kernel/linux/files<br />
</pre><br />
where it is assumed that ''${LAYER_DIR}'' contains the path to the root directory of the custom Yocto layer. <br />
<br /><br />
<br /><br />
Copy the kernel device tree file from your Yocto project build directory to the ''files'' directory of your new recipe. For a Raspberry Pi Compute Module 4, for example, type<br />
<pre class="terminal"><br />
cp ${YOCTO_BUILD_DIR}/tmp/work-shared/raspberrypi4-64/kernel-source/arch/arm/boot/dts/bcm2711-rpi-cm4.dts ${LAYER_DIR}/recipes-kernel/linux/files/<br />
</pre><br />
where it is assumed that ''${YOCTO_BUILD_DIR}'' contains the path to the Yocto project build directory.<br />
<br /><br />
<div class="sidenote"><br />
If the ''tmp/work-shared'' directory does not exists anymore, you can recreate it by typing<br />
<pre class="terminal"><br />
bitbake -c menuconfig virtual/kernel<br />
</pre><br />
and exiting the kernel configuration menu without making changes.<br />
</div><br />
<br /><br />
Create and edit the append recipe<br />
<pre class="terminal"><br />
vim ${LAYER_DIR}/recipes-kernel/linux/linux-<platform>_%.bbappend<br />
</pre><br />
where ''platform'' is the hardware or machine designator (for example, ''raspberrypi'').<br />
<br /><br />
<div class="sidenote"><br />
If in doubt, use the ''oe-pkgdata-util'' tool from within your build directory to find out the kernel name.<br />
<pre class="terminal"><br />
oe-pkgdata-util lookup-recipe kernel<br />
</pre><br />
</div><br />
The contents of the recipe file should be similar to this:<br />
<pre class="code"><br />
FILESEXTRAPATHS:prepend = "${THISDIR}:"<br />
SRC_URI += "file://0001-my_modifications-dts.patch"<br />
</pre><br />
where ''0001-my_modifications-dts.patch'' needs to be replaced with the actual patch file name.<br />
<br />
<br /><br />
<br />
= Accessing the OpenEmbedded package collection =<br />
The OpenEmbedded project provides recipes for many useful programs that are not included with Yocto, like tmux, VLC, Gnome, various multimedia codecs, more filesystems, gRPC and much more.<br />
<br /><br />
To access the recipes for those software packages, clone the OpenEmbedded layers repository into your third-party layers directory: <br />
<pre class="terminal"><br />
git clone git://git.openembedded.org/meta-openembedded<br />
</pre><br />
<br /><br />
<br />
= devtool =<br />
<br />
Use '''devtool''' to make changes to an existing recipe and automatically generate an append recipe from those changes.<br />
<br /><br />
<br /><br />
<br />
== Initialization Manager ==<br />
After the kernel is done with its basic booting tasks, it passes control to the initialization manager. To use the ''systemd'' initialization manager (used by the Linux distributions Debian and Ubuntu) instead of ''SysVinit'', make the following entries in ''${TOPDIR}/conf/distro/distro.conf''<br />
<pre class="code"><br />
DISTRO_FEATURES_append = " systemd"<br />
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"<br />
VIRTUAL-RUNTIME_init_manager = "systemd"<br />
VIRTUAL-RUNTIME_initscripts = ""<br />
</pre><br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=MediaWiki:Common.css&diff=3148MediaWiki:Common.css2022-12-25T16:48:40Z<p>Kai: Adds the style for sidenote areas.</p>
<hr />
<div>/* CSS placed here will be applied to all skins */<br />
<br />
body.page-Main_Page .title, body.page-Main_Page #tagline<br />
{<br />
display: none;<br />
}<br />
<br />
.tocnumber<br />
{<br />
display: none;<br />
}<br />
<br />
/* source code */<br />
pre.code<br />
{<br />
color: black;<br />
background: #eee;<br />
border: 0.8em solid #eee;<br />
border-radius: 6px;<br />
}<br />
span.code<br />
{<br />
color: black;<br />
background: #eee;<br />
border-radius: 6px;<br />
padding-left: 4px;<br />
padding-right: 4px;<br />
}<br />
<br />
/* terminal commands */<br />
pre.terminal<br />
{<br />
color: #ffe;<br />
background: #888;<br />
border: 0.4em solid #888;<br />
border-radius: 6px;<br />
padding-left: 6px;<br />
}<br />
span.terminal<br />
{<br />
color: #ffe;<br />
background: #888;<br />
border-radius: 6px;<br />
padding-left: 4px;<br />
padding-right: 4px;<br />
}<br />
<br />
/* side note area */<br />
div.sidenote<br />
{<br />
background: #f8f8f0;<br />
padding-left: 1em;<br />
padding-right: 1em;<br />
border-radius: 6px;<br />
}</div>Kaihttps://Robo.Fish/wiki/index.php?title=Yocto&diff=3147Yocto2022-12-25T16:40:47Z<p>Kai: Adds an example recipe file content.</p>
<hr />
<div>= Yocto and OpenEmbedded =<br />
The collection of software tools used by the Yocto project have been developed by the [https://www.openembedded.org OpenEmbedded] project. The Yocto project basically uses these generic build tools to provide a basic Linux system called ''Poky''. Stable releases of Poky serve as standard platforms for third parties that provide additional features (e.g., hardware support layers).<br />
<br /><br />
<br /><br />
<br />
= Prerequisites =<br />
* A Linux system supported by the Yocto project.<br />Assuming that [[Ubuntu]] is used. <br />
* Following package installed:<br />
<pre class=terminal><br />
sudo apt install gcc g++ \<br />
python3-distutils python-is-python3<br />
</pre><br />
<br /><br />
<br />
= Bitbake =<br />
Bitbake is the build tool from the OpenEmbedded project, which parses the project's metadata, resolves dependencies and the ordering of the build steps, runs the builds to create packages, to finally create an image from the packages.<br />
<br /><br />
=== Metadata Types ===<br />
Yocto metadata, which controls how a system image is built, can be categorized at a high level into these four types:<br />
* ''Machine''<br />the targeted hardware platform (e.g. Raspberry Pi 4)<br />
* ''Distro''<br />common characteristic of a family of related images<br />
* ''Recipes''<br />instructions on how to process the source files for a component of the image<br />
* ''Image''<br />recipes that define the contents of generated system images<br />
<br /><br />
=== Layers ===<br />
Layers are purposeful collections of metadata. Yocto layers often Layers often add the provide that for a that can be combined with other layers in order to directories in which <br />
<br /><br />
<br />
<br /> <br />
<br />
= Images =<br />
<br />
Images are recipes that ultimately inherit from '''meta/classes/image.bbclass''' and set the global variable '''IMAGE_INSTALL'''. Most images, however, will inherit from ''meta/classes/core-image.bbclass'' which inherits directly from ''image.bbclass'', provides a mapping from ''IMAGE_FEATURES'' to package groups, and adds the two package groups ''packagegroup-core-boot'' and ''packagegroup-base-extended'' to ''IMAGE_INSTALL''.<br />
<br />
Images are defined in recipe files with the file extension 'bb'. In order to separate them from package recipes, there is a convention to put image recipes into a folder named ''images''. Making use of this, we can list all images defined by all layers via<br />
<pre class="terminal"><br />
cd poky<br />
ls meta*/recipes*/images/*.bb<br />
</pre><br />
<br /><br />
<br />
=== ''IMAGE_FEATURES'' ===<br />
The ''IMAGE_FEATURES'' variable is defined in ''meta/classes/image.bbclass'' with an empty value. It accepts only a predefined set of features (e.g., ''x11'', ''debug-tweaks'', ''dev-pkgs'', ''dbg-pkgs''). This affects how recipes will execute their tasks and which packages will be selected to go into the image. The image recipe ''meta/recipes-core/images/core-image-base.bb'', for example, adds the ''splash'' feature.<br />
<br /><br />
<br />
=== ''IMAGE_INSTALL'' ===<br />
Holds a list of package groups whose packages (from the package feed area) will go into the filesystem image.<br />
<br /><br />
<br />
== Reference images ==<br />
The following reference images are defined in the ''meta'' layer:<br />
{| style="padding: 10px;"<br />
! style="width: 20px" | || || <br />
|-<br />
| || ''core-image-minimal'' || small image that just boots the target device<br />
|-<br />
| || ''core-image-minimal-dev'' || ''core-image-minimal'' with headers and libraries allowing development work<br />
|-<br />
| || style="padding-right: 10px" | ''core-image-minimal-initramfs'' || ''core-image-minimal'' with kernel support for in-RAM filesystem<br />
|-<br />
| || '''core-image-base''' || '''console-only system fully supporting the target hardware'''<br />
|-<br />
| || ''core-image-full-cmdline'' || console-only image that includes many system tools<br />
|-<br />
| || ''core-image-x11'' || image with basic X11 and a terminal<br />
|-<br />
|}<br />
<br />
These image definitions are provided as a starting point for creating project-specific, custom image definitions.<br />
<br /><br />
<br /><br />
<br />
== Creating a Custom Image ==<br />
* In your custom layer, create the ''images'' subdirectory in one of your ''recipes-...' directory.<br />
* In the ''images'' directory, create two image recipe files that inherit from ''core-image'':<br />
<pre class="code"><br />
SUMMARY = "My deployment image"<br />
LICENSE = "MIT"<br />
<br />
inherit core-image<br />
IMAGE_FEATURES += "splash"<br />
</pre><br />
and<br />
<pre class="code"><br />
SUMMARY = "My development image"<br />
<br />
inherit core-image<br />
require my-image.bb<br />
<br />
IMAGE_FEATURES += "ssh-server-dropbear tools-debug debug-tweaks"<br />
<br />
CORE_IMAGE_EXTRA_INSTALL += "i2c-tools "<br />
</pre><br />
where the first image recipe is for deployment and the second is for development. Note that the development version includes the deployment version with the ''require'' statement, and adds to IMAGE_FEATURES and CORE_IMAGE_EXTRA_INSTALL.<br />
<br /><br />
<br />
== Image Filesystem Packaging ==<br />
The system image generated by Bitbake can be packaged in the form of an image file, whose contents can be transferred on a boot medium (SD card or eMMC) such that the primary boot loader of the target device can discover the system and boot it.<br />
<br />
Unless you restrict the type of packaging used for the image file, Yocto will generate multiple rootfs packages, each with a large footprint. To restrict the generated image files to a desired type, edit ''conf/local.conf'' of your project build directory and set the type.<br />
<pre class="code"><br />
#IMAGE_FSTYPES = "tar.gz"<br />
#IMAGE_FSTYPES = "tar.bz2"<br />
IMAGE_FSTYPES = "wic.bz2 wic.bmap"<br />
</pre><br />
The wic ([https://pykickstart.readthedocs.io/en/latest/kickstart-docs.html kickstart]) format with accompanying [https://github.com/intel/bmap-tools bmap] is recommended.<br />
<br /><br />
<br />
== Installing the Rootfs Image ==<br />
Using [https://github.com/intel/bmap-tools bmaptool] we can copy the generated ''wic'' image (with matching bmap file) to a mounted SD card or eMMC storage.<br />
<pre class="terminal"><br />
sudo bmaptool copy tmp/deploy/images/raspberrypi4-64/<wic.bz2 file> <drive><br />
</pre><br />
where ''<wic.bz2 file>'' is the root filesystem image wic.bz2 file, and ''<drive>'' is the drive at which the storage is mounted (for example, ''/dev/sdb'').<br />
<br /><br />
<br /><br />
<br />
= Package Groups =<br />
Package groups are recipes that inherit from '''meta/classes/packagegroup.bbclass''' and set the content of the global variable '''PACKAGES'''. Package groups are defined in recipe files with the file extension 'bb'.<br />
<br /><br />
<br /><br />
Note that the ''packagegroup'' must be inherited before ''PACKAGES is defined.<br />
<pre class="code"><br />
inherit packagegroup<br />
<br />
PACKAGES = '...'<br />
</pre><br />
<br /><br />
<br />
= Useful Image Features =<br />
<br /><br />
<br />
== Distro Features ==<br />
Distro features are system features that affect multiple recipes. '''Large parts of the Poky image may need to be rebaked after making changes to the distro features!'''<br />
<br /><br />
<br />
=== systemd ===<br />
In the ''conf/local.conf'' file of your project build directory (or ''layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " systemd"<br />
</pre><br />
<br /><br />
<br />
=== NFS ===<br />
In Embedded Linux projects, NFS is often included in development images to enable faster code-deploy turnaround times.<br />
<br /><br />
In the ''conf/local.conf'' file of your Yocto build directory (or ''conf/layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " nfs"<br />
</pre><br />
<br /><br />
On your Debian-based Yocto machine, [[Ubuntu#Setting_up_an_NFS_Server|set up an SSH server]].<br />
<br /><br />
<br /><br />
In Yocto, use the directory<br />
<br /><br />
: '''{YOCTO_BUILD_DIR}/tmp/work/{TARGET}-poky-linux/{IMAGE}/1.0-r0/rootfs'''<br />
as the root directory provided by the NFS server. For example,<br />
: ''build-robofish-core/tmp/work/raspberrypi4_64-poky-linux/robofish-core-image-dev/1.0-r0/rootfs''<br />
<br /><br />
<br /><br />
<br />
=== [https://vulkan.org Vulkan] and [https://opengl.org OpenGL] ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " vulkan opengl x11 wayland"<br />
</pre><br />
<br /><br />
<br />
=== Bluetooth and NFC ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " bluetooth nfc"<br />
</pre><br />
<br /><br />
<br />
= Recipes =<br />
Recipes are Yocto metadata files that are interpreted by Bitbake and describe how a build task is performed.<br />
<br /><br />
== Patching A Device Tree ==<br />
Follow these steps to patch an existing device tree by creating an ''append recipe'' in a custom layer.<br />
<br /><br />
<br /><br />
In the custom layer, create the directory for a linux kernel append recipe.<br />
<pre class="terminal"><br />
mkdir -p ${LAYER_DIR}/recipes-kernel/linux/files<br />
</pre><br />
where it is assumed that ''${LAYER_DIR}'' contains the path to the root directory of the custom Yocto layer. <br />
<br /><br />
<br /><br />
Copy the kernel device tree file from your Yocto project build directory to the ''files'' directory of your new recipe. For a Raspberry Pi Compute Module 4, for example, type<br />
<pre class="terminal"><br />
cp ${YOCTO_BUILD_DIR}/tmp/work-shared/raspberrypi4-64/kernel-source/arch/arm/boot/dts/bcm2711-rpi-cm4.dts ${LAYER_DIR}/recipes-kernel/linux/files/<br />
</pre><br />
where it is assumed that ''${YOCTO_BUILD_DIR}'' contains the path to the Yocto project build directory.<br />
<br /><br />
<div style="background:#f8f8f0; padding-left: 1em; padding-right: 1em; border-radius:6px"><br />
If the ''tmp/work-shared'' directory does not exists anymore, you can recreate it by typing<br />
<pre class="terminal"><br />
bitbake -c menuconfig virtual/kernel<br />
</pre><br />
and exiting the kernel configuration menu without making changes.<br />
</div><br />
<br /><br />
Create and edit the append recipe<br />
<pre class="terminal"><br />
vim ${LAYER_DIR}/recipes-kernel/linux/linux-<platform>_%.bbappend<br />
</pre><br />
where ''platform'' is the hardware or machine designator (for example, ''raspberrypi'').<br />
<br /><br />
<div style="background:#f8f8f0; padding-left: 1em; padding-right: 1em; padding-bottom: 1em; border-radius:6px"><br />
If in doubt, use the ''oe-pkgdata-util'' tool from within your build directory to find out the kernel name.<br />
<pre class="terminal"><br />
oe-pkgdata-util lookup-recipe kernel<br />
</pre><br />
</div><br />
The contents of the recipe file should be similar to this:<br />
<pre class="code"><br />
FILESEXTRAPATHS:prepend = "${THISDIR}:"<br />
SRC_URI += "file://0001-my_modifications-dts.patch"<br />
</pre><br />
where ''0001-my_modifications-dts.patch'' needs to be replaced with the actual patch file name.<br />
<br />
<br /><br />
<br />
= Accessing the OpenEmbedded package collection =<br />
The OpenEmbedded project provides recipes for many useful programs that are not included with Yocto, like tmux, VLC, Gnome, various multimedia codecs, more filesystems, gRPC and much more.<br />
<br /><br />
To access the recipes for those software packages, clone the OpenEmbedded layers repository into your third-party layers directory: <br />
<pre class="terminal"><br />
git clone git://git.openembedded.org/meta-openembedded<br />
</pre><br />
<br /><br />
<br />
= devtool =<br />
<br />
Use '''devtool''' to make changes to an existing recipe and automatically generate an append recipe from those changes.<br />
<br /><br />
<br /><br />
<br />
== Initialization Manager ==<br />
After the kernel is done with its basic booting tasks, it passes control to the initialization manager. To use the ''systemd'' initialization manager (used by the Linux distributions Debian and Ubuntu) instead of ''SysVinit'', make the following entries in ''${TOPDIR}/conf/distro/distro.conf''<br />
<pre class="code"><br />
DISTRO_FEATURES_append = " systemd"<br />
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"<br />
VIRTUAL-RUNTIME_init_manager = "systemd"<br />
VIRTUAL-RUNTIME_initscripts = ""<br />
</pre><br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Raspberry_Pi&diff=3146Raspberry Pi2022-12-25T16:21:08Z<p>Kai: Adds Yocto kernel patching knowledge.</p>
<hr />
<div>= Introduction =<br />
The [http://raspberrypi.org Raspberry Pi Ltd.] is a company producing small and affordable single-board, bare-bones computer systems, microcontrollers and accessories, marketed under the ''Raspberry Pi'' brand. All Raspberry Pi computing products use Arm-based processors. I use Raspberry Pi computers as [[Robot Task Controller | task controller]], and the microcontrollers as [[Robot State Agent | state agent]] in my robots.<br />
<br /><br />
<br /><br />
= Processors and Architectures =<br />
<br />
* [https://developer.arm.com/Processors/Cortex-A7 Arm Cortex-A7] with 32-bit Armv7 programming model<br />
** Raspberry Pi 2 B (Broadcom BCM2836 processor @ 900 MHz)<br />
<br /><br />
<br />
* [https://developer.arm.com/Processors/Cortex-A53 Arm Cortex-A53] with 64-bit Armv8-A programming model.<br />
** Raspberry Pi 2 B rev 1.2 (Broadcom BCM2837 processor @ 900 MHz)<br />
** Raspberry Pi 3 B (Broadcom BCM2837 processor @ 1.2 GHz)<br />
** Raspberry Pi 3 B+ (Broadcom BCM2837B0 processor @ 1.4 GHz)<br />
** Raspberry Pi Zero 2 W (@ 1 GHz)<br />
<br /><br />
<br />
* [https://developer.arm.com/Processors/Cortex-A72 Arm Cortex-A72] with 64-bit Armv8-A programming model<br />
** Raspberry Pi 4 (Broadcom BCM2711 processor @ 1.5 GHz)<br />
** Compute Module 4 (Broadcom BCM2711 @ 1.5 GHz)<br />
<br /><br />
<br />
* [https://developer.arm.com/Processors/Cortex-M0+ Arm Cortex-M0+] with Armv6-M programming model<br />
** Raspberry Pi Pico (up to 133 MHz)<br />
<br /><br />
<br />
= Installing a System Image =<br />
[https://www.raspberrypi.com/software/operating-systems/ Raspberry Pi OS] is the offical operating system of a Raspberry Pi. The Lite version, without a graphical desktop, is recommended for embedded applications unless you decide to create a custom system image. The fewer software modules are running, the lower the power consumption, and the lower the chance that user-space processes will be interrupted.<br />
<br /><br />
<br /><br />
== Installing the System Image on SD Card ==<br />
This is the most popular method of installing a system image on a single-board computers. SD cards are cheap and reusable, almost all Raspberry Pi models come with an SD card reader. However, SD card memory is not designed to support frequent rewrite operations and may not be as durable as other storage solutions. <br />
<br />
The preferred way of putting a system image on an SD card is to use the [https://www.raspberrypi.com/software Raspberry Pi Imager] tool that can fetch a Raspberry Pi OS image over the Internet or use a local image file, create a derived image with preconfigured user credentials, WLAN access and more, before writing it to the SD card.<br />
<br />
=== Using built-in tools on Linux ===<br />
The SD card can also be prepared by using standard Linux tools instead of Raspberry Pi Imager. First, we need to find out which device to copy the install image to. Type<br />
<pre class="terminal"><br />
df -h<br />
</pre><br />
or<br />
<pre class="terminal"><br />
sudo fdisk --list<br />
</pre><br />
in the command terminal to look up the mount point for the SD card. Let us assume the card was mounted as ''/dev/sdb2''. The card needs to be unmounted before we can copy the downloaded Raspberry Pi OS install image:<br />
<br /><br />
<pre class="terminal"><br />
umount /dev/sdb2<br />
</pre><br />
<br /><br />
Copy the image to the card with the ''dd'' command:<br />
<pre class="terminal"><br />
sudo dd bs=4M if=2021-01-11-raspios-buster-armhf-lite.img of=/dev/sdb<br />
</pre><br />
where we use the path to the device file ''/dev/sdb'' instead of the partition ''/dev/sdb2'', which was unmounted. The option ''bs'' is used for adjusting the buffer size for the writing operation.<br />
<br /><br />
<br /><br />
<br />
=== Using built-in tools on macOS ===<br />
On Apple macOS, you can use the built-in 'diskutil' tool as an alternative to the Raspberry Pi Imager. First, attach the SD card to your Mac and determine the assigned disk number ''disk#'' (e.g., disk2) under which the card has been mounted to the filesystem by opening Terminal and typing<br />
<br /><br />
<pre class="terminal"><br />
diskutil list<br />
</pre><br />
then unmount the disk<br />
<pre class="terminal"><br />
diskutil unmountDisk disk2<br />
</pre><br />
and copy the data with the ''dd'' tool<br />
<pre class="terminal"><br />
sudo dd bs=1m if=~/Downloads/raspios.img of=/dev/rdisk2<br />
</pre><br />
where I assume that the downloaded and <u>unzipped</u> Raspberry Pi OS image file is located at ''~/Downloads/raspios.img'' and the SD card was mounted as ''disk2''.<br />
<br /><br />
<br />
== Installing the System Image on eMMC ==<br />
Some Raspberry Pi models, like the Compute Module 4, come with an embedded MultiMediaCard (eMMC) storage component. A switch or jumper on the carrier board serves to make the Raspberry Pi bootloader boot the compute module into USB mass storage mode. In this mode you can attach the compute module to an external computer via USB. On Ubuntu you can use the<br />
<pre class="terminal"><br />
lsusb<br />
</pre><br />
command to list all connected USB devices. The Compute Module 4, for example, should show up as "Broadcom Corp. BCM2711 Boot".<br />
<br /><br />
To make the operating system recognize the USB device as a mass storage device, we need to build and run Raspberry Pi's ''rpiboot'' tool.<br />
<pre class="terminal"><br />
sudo apt install libusb-1.0-0-dev<br />
git clone --depth=1 https://github.com/raspberrypi/usbboot<br />
cd usbboot<br />
make<br />
sudo ./rpiboot<br />
</pre><br />
On Ubuntu, ''lsusb'' will now list the Compute Module 4 as "Broadcom Corp. Compute Module". The compute module will also show up in the ''Disks'' app as ''RPi-MSD-0001''.<br />
<br /><br />
[[File: raspberrypi_emmc_shows_up_in_disks_app.png | x300px ]]<br />
<br /><br />
You can now use Raspberry Pi Imager or any flashing utility to flash a system image on the compute module eMMC.<br />
<br /><br />
<br /><br />
<br />
= Upgrading a Raspberry Pi OS Installation =<br />
You don't want to erase your existing Raspberry Pi OS environment and set up all the software from start each time a new version of Raspberry Pi OS is released. Fortunately, [https://www.raspberrypi.com/documentation/computers/os.html#updating-and-upgrading-raspberry-pi-os Raspberry Pi OS can upgrade itself to the latest release] with the following commands.<br />
<pre class="terminal"><br />
sudo apt-get update<br />
sudo apt-get dist-upgrade<br />
</pre><br />
<br /><br />
<br /><br />
<br />
= Assigning a Static Ethernet IP Address =<br />
Edit the file '''/etc/network/interfaces''' and make sure that the entries for the interface ''eth0'' are as follows:<br />
<pre class="terminal"><br />
auto eth0<br />
iface eth0 inet static<br />
address 192.168.0.20<br />
netmask 255.255.255.0<br />
broadcast 192.168.0.255<br />
</pre><br />
where the IP address ''192.168.0.20'' is just an example.<br />
<br /><br />
<br /><br />
Make sure you don't break the WiFi connectivity because of editing ''/etc/network/interfaces''. If there is no empty describing ''wlan0'' we will need to create one. For dynamically assigned IPs via DHCP you will need these lines:<br />
<pre class="terminal"><br />
auto wlan0<br />
iface wlan0 inet dhcp<br />
wpa-ssid <your WiFi router name (SSID)><br />
wpa-psk <your WiFi password><br />
</pre><br />
<br /><br />
The new network setting becomes effective on the next system boot or when you type<br />
<pre class="terminal"><br />
sudo ifdown eth0<br />
sudo ifup eth0<br />
</pre><br />
<br /><br />
<br /><br />
= Setting Up SSH =<br />
* As a security measure, SSH is not enabled by default on headless (= Raspbian Lite, without GUI) installations. Place a file named "ssh" into the root folder of the boot partition (= ''/boot'') to enable SSH.<br />
* In the web browser go to the configuration page of your home Internet router (e.g., http://192.168.1.1).<br />
* Open the page that lists all currently connected LAN devices.<br />
* Connect the Raspberry Pi via Ethernet cable to the LAN router.<br />
* Look for a new entry in the list of LAN devices. That should be your Raspberry Pi. Note the IP address. Let's assume it is ''192.168.1.10''.<br />
* Optional: You should be able to read the [https://en.wikipedia.org/wiki/MAC_address MAC address] of the Raspberry Pi from the table. For future reference, write down the MAC address somewhere.<br />
* Open Terminal and type '''ssh pi@192.168.1.10''' to log in via SSH. On a fresh Raspbian installation the username is '''pi''' and the password is '''raspberry'''.<br />
* After logging in type '''sudo raspi-config''' to start the Raspbian configuration tool, where you can change the password or expand the filesystem to take up the whole SD card, among other things.<br />
<br /><br />
<br /><br />
= Setting Up WiFi =<br />
== Raspberry Pi 2 ==<br />
The Raspberry Pi 2 does not have built-in WiFi. I assume that you are using a USB WiFi adapter. Before connecting the adapter you need to edit the network interfaces on the Raspberry Pi. Log in to the Raspberry Pi over SSH and edit '''/etc/network/interfaces''' as follows:<br />
<br /><br />
<pre class="code"><br />
auto lo<br />
<br />
iface lo inet loopback<br />
iface eth0 inet dhcp<br />
<br />
allow-hotplug wlan0<br />
auto wlan0<br />
<br />
iface wlan0 inet dhcp<br />
wpa-ssid "ssid"<br />
wpa-psk “password"<br />
</pre><br />
<br /><br />
where ''ssid'' is the SSID (a.k.a. name) of your WLAN router, and ''password'' is supplied in encoded form. Do not type the quotation marks. The password is encoded by running<br />
<br /><br />
<pre class="terminal"><br />
wpa_passphrase <ssid> <password><br />
</pre><br />
<br /><br />
If your WLAN router uses a hidden SSID use this configuration:<br />
<pre class="code"><br />
auto lo<br />
<br />
iface lo inet loopback<br />
iface eth0 inet dhcp<br />
<br />
auto wlan0<br />
allow-hotplug wlan0<br />
iface wlan0 inet dhcp<br />
wpa-scan-ssid 1<br />
wpa-ap-scan 1<br />
wpa-key-mgmt WPA-PSK<br />
wpa-proto RSN WPA<br />
wpa-pairwise CCMP TKIP<br />
wpa-group CCMP TKIP<br />
wpa-ssid "My Secret SSID"<br />
wpa-psk "My SSID PSK”<br />
<br />
iface default inet dhcp<br />
</pre><br />
<br /><br />
Instead of putting the WPA configuration directly into '''interfaces''' you can put it into the file '''/etc/wpa_supplicant/wpa_supplicant.conf'''<br />
<pre class="code"><br />
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev<br />
update_config=1<br />
<br />
network={<br />
ssid="<your ssid>"<br />
psk=<your encoded password given by running wpa_passphrase><br />
scan_ssid=1<br />
proto=WPA RSN<br />
key_mgmt=WPA-PSK<br />
pairwise=CCMP TKIP<br />
}<br />
</pre><br />
<br /><br />
and refer to it from '''interfaces''' like so<br />
<pre class="code"><br />
auto lo<br />
iface lo inet loopback<br />
<br />
iface eth0 inet dhcp<br />
<br />
allow-hotplug wlan0<br />
iface wlan0 inet dhcp<br />
wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf<br />
<br />
iface default inet dhcp<br />
</pre><br />
<br /><br />
<br /><br />
<br />
== Raspberry Pi 3 or newer ==<br />
The Raspberry Pi 3 has a WLAN transmitter built in and it is turned on by default. You should see the device '''wlan0''' along with '''eth0''' and '''lo''' when typing<br />
<br /><br />
<pre class="terminal"><br />
ifconfig -a<br />
</pre><br />
<br /><br />
Make sure the Raspberry Pi can log in to your WLAN router. If a MAC filter is active, add the Raspberry Pi WiFi MAC address to the list of allowed devices. The MAC address of the Pi is displayed in the output of ''ifconfig -a'' as '''HWaddr'''. Open a text editor to add the network configuration details, such as your login credentials, to the file ''/etc/wpa_supplicant/wpa_supplicant.conf''.<br />
<br /><br />
<pre class="code"><br />
network={<br />
ssid="MySSID"<br />
psk=MyCodedPassword<br />
scan_ssid=1<br />
proto=WPA RSN<br />
key_mgmt=WPA-PSK<br />
pairwise=CCMP TKIP<br />
}<br />
</pre><br />
<br /><br />
where '''MySSID''' is the SSID (a.k.a. name) of the router, and '''MyCodedPassword''' is the encoded password obtained via<br />
<br /><br />
<pre class="terminal"><br />
wpa_passphrase MySSID MyPassword<br />
</pre><br />
and where '''MyPassword''' is the actual password.<br />
<br /><br />
<br /><br />
<br />
== Power Saving ==<br />
If the WiFi connection is unstable you can turn off the WiFi power management feature, which may cause connection dropouts, by issuing the command<br />
<pre class="terminal"><br />
sudo iw dev wlan0 set power_save off<br />
</pre><br />
or by manually editing '''/etc/network/interfaces''', where you add the line<br />
<pre class="code"><br />
wireless-power off<br />
</pre><br />
right after the line<br />
<pre class="code"><br />
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf<br />
</pre><br />
within the '''wlan0''' block. You can check whether power management is currently turned on or off, among other parameters, with the command<br />
<pre class="terminal"><br />
iwconfig<br />
</pre><br />
<br /><br />
<br /><br />
For Raspberry Pi 2 and WiFi dongles with 8192CU or 8188CUS chip (for example, Edimax EW-7811un dongles)you can prevent connections from being dropped by creating the file '''/etc/modprobe.d/8192cu.conf'''<br />
<br><br />
<pre class="terminal"><br />
sudo nano /etc/modprobe.d/8192cu.conf<br />
</pre><br />
and adding the line<br />
<br /><br />
<pre class="code"><br />
options 8192cu rtw_power_mgnt=0 rtw_enusbss=0<br />
</pre><br />
<br /><br />
<br />
= Camera =<br />
There is a [https://www.raspberrypi.org/products/camera-module/ camera module] for Raspberry Pi, which I use in my robots. In fact, the camera module is part of the [[Core Module]].<br />
<br /><br />
<br /><br />
Refer to the official [https://www.raspberrypi.org/documentation/usage/camera/README.md camera setup instructions]. Be careful with the camera module, handle the camera board and the connector strip delicately.<br />
<br /><br />
<br /><br />
To be able to access the camera through the Python programming environment you need to install the '''python-picamera''' package<br />
<br /><br />
<br /><br />
The Raspberry Pi project does not provide a C/C++ library for accessing the camera. Instead it provides utility applications ''raspistill'' and ''raspivid'' which record still images and videos, respectively. A number of third-party C++ libraries have been created based on the open source code of these utility applications. The [http://www.uco.es/investiga/grupos/ava/node/40 RaspiCam] C++ library developed at the University of Cordoba is one such library (source code available [https://sourceforge.net/projects/raspicam/ from SourceForge]).<br />
<br /><br />
<br /><br />
== Video Streaming ==<br />
To stream video from the Raspberry Pi camera to the network, open a terminal on the RPi and type<br />
<pre class="terminal"><br />
raspivid -t 0 -w 1280 -h 720 -hf -ih -fps 30 -o - | nc -k -l 8100<br />
</pre><br />
<br /><br />
To view the stream on a client computer with [http://www.mplayerhq.hu Mplayer] installed, open a terminal there and type<br />
<pre class="terminal"><br />
mplayer -fps 300 -demuxer h264es ffmpeg://tcp://192.168.0.20:8100<br />
</pre><br />
<br /><br />
<br /><br />
Alternatively, you can use [[GStreamer]] to transport the video frames. Make sure that the command line interface to GStreamer, ''gst-launch-1.0'', is installed. <br />
<pre class="terminal"><br />
sudo apt install gstreamer1.0-tools<br />
</pre><br />
<br /><br />
For streaming from the RPi you can type<br />
<pre class="terminal"><br />
raspivid -t 0 -w 640 -h 480 -fps 30 -hf -b 2000000 -o - | gst-launch-1.0 -q fdsrc ! h264parse ! rtph264pay config-interval=1 pt=96 ! gdppay ! tcpserversink host=0.0.0.0 port=8100<br />
</pre><br />
<br /><br />
For viewing on the client, you can type<br />
<pre class="terminal"><br />
gst-launch-1.0 -v tcpclientsrc host=192.168.0.20 port=8100 ! gdpdepay ! rtph264depay ! avdec_h264 ! videoconvert ! videoflip method=vertical-flip ! autovideosink sync=false<br />
</pre><br />
where ''192.168.0.20'' is assumed to be the IP address of the server (Raspberry Pi).<br />
<br /><br />
<br /><br />
* On the Raspberry Pi side you can elevate the priority of the process by beginning the command with ''"nice -20"''.<br />
* For verbose output from ''gst-launch-1.0'', use the option ''-v'' instead of ''-q''.<br />
* Note that we used the [https://gstreamer.freedesktop.org/documentation/videofilter/videoflip.html?gi-language=c#GstVideoFlipMethod videoflip] filter to correct the rotation of the decoded image.<br />
<br /><br />
=== Disabling the LED ===<br />
To disable the red indicator light of the camera, add the following line to '''/boot/config.txt''' and reboot:<br />
<pre class="code"><br />
disable_camera_led=1<br />
</pre><br />
<br /><br />
<br />
= pinout =<br />
A cool command-line tool provided by Raspberry Pi, and also available when running Ubuntu instead of Raspberry Pi OS, is '''pinout'''. It displays a layout of the Raspberry Pi board using ASCII art, a list of significant hardware features of the board, and the GPIO pin layout in tabular form.<br />
<br /><br />
<pre class="terminal"><br />
sudo apt install python3-gpiozero<br />
pinout<br />
</pre><br />
<br /><br />
[[File:Raspberry_Pi_pinout_command.png | x600px]]<br />
<br /><br />
<br /><br />
<br />
= raspi-gpio =<br />
The documentation states that ''"raspi-gpio can get and print the state of a GPIO (or all GPIOs) and can be used to set the function, pulls and value of a GPIO. raspi-gpio must be run as root."''<br />
"<br />
<pre class="terminal"><br />
> sudo apt install raspi-gpio<br />
> raspi-gpio funcs 20,21,22<br />
GPIO, DEFAULT PULL, ALT0, ALT1, ALT2, ALT3, ALT4, ALT5<br />
20, DOWN, PCM_DIN, SD12, DPI_D16, SPI6_MOSI, SPI1_MOSI, GPCLK0<br />
21, DOWN, PCM_DOUT, SD13, DPI_D17, SPI6_SCLK, SPI1_SCLK, GPCLK1<br />
22, DOWN, SD0_CLK, SD14, DPI_D18, SD1_CLK, ARM_TRST, SDA6<br />
> raspi-gpio get 20<br />
GPIO 20: level=0 func=INPUT pull=DOWN<br />
GPIO 21: level=1 func=INPUT pull=DOWN<br />
GPIO 22: level=0 func=INPUT pull=DOWN<br />
> raspi-gpio raw 21<br />
00: 00000000 00012000 12000000 3fffffff<br />
10: 24000040 00000924 00000000 6770696f<br />
20: 6770696f 6770696f 6770696f 6770696f<br />
30: 6770696f 102081ff 00003bfb 00000000<br />
40: 00000000 00000000 00000000 00000000<br />
50: 00000000 00000000 00000000 00000000<br />
60: 00000000 00000000 00000000 00000000<br />
70: 00000000 00000000 00000000 00000000<br />
80: 00000000 00000000 00000000 00000000<br />
90: 00000000 00000000 00000000 00000000<br />
e0: 4aa95555 19aaaaaa 50aa5544<br />
f0: 000aaaaa<br />
</pre><br />
<br /><br />
<br />
= GPIO Programming in C =<br />
Raspberry Pi 2, 3 & 4 come with 40 ''General Purpose Input Output'' (GPIO) pins ([https://www.raspberrypi.com/documentation/computers/os.html#gpio-and-the-40-pin-header layout]) that can be used to interface with the other electronic components of your project.<br />
<br />
== Using libgpiod ==<br />
The standard C++ programming interface for GPIO on Linux is ''libgpiod'', as described on [[Nvidia_Jetson#Using_Libgpiod | the Jetson page]].<br />
<br />
== Using WiringPi ==<br />
Using the [http://wiringpi.coml WiringPi] library is a more popular method for programming the GPIO pins on a Raspberry Pi with C/C++. WiringPi is [http://wiringpi.com/download-and-install installed from source] like this<br />
<pre class="terminal"><br />
sudo apt-get install git-core<br />
git clone git://git.drogon.net/wiringPi<br />
cd wiringPi<br />
./build<br />
</pre><br />
Read the ''INSTALL'' file for what to do with the created shared library. Basically you need to copy ''wiringPi/libwiringPi.so.x.xx'' to ''/usr/local/lib'' and add the line<br />
<pre class="code"><br />
include /usr/local/lib<br />
</pre><br />
to the file ''/etc/ld.so.conf'' so that the library loader also looks in ''/usr/local/lib'' for dynamically loadable libraries. It is also possible to create a static library.<br />
<br /><br />
<br/><br />
After installation, create a test program called ''blink.cpp''<br />
<pre class="code"><br />
#include <stdio.h><br />
#include <iostream><br />
#include <wiringPi.h><br />
<br />
static int LED_PORT = 7; // The physical pin number. Corresponds to BCM GPIO pin 4.<br />
<br />
void blink()<br />
{<br />
digitalWrite(4, HIGH);<br />
delay(1000);<br />
digitalWrite(4, LOW);<br />
delay(1000);<br />
};<br />
<br />
int main(int numargs, char** args)<br />
{<br />
wiringPiSetup();<br />
pinMode(LED_PORT, OUTPUT);<br />
for (int n = 0; n < 10; n++)<br />
{<br />
blink();<br />
}<br />
std::cout << "finished blinking" << std::endl;<br />
return 0;<br />
}<br />
</pre><br />
and build like this<br />
<pre class="terminal"><br />
g++ blink.cpp -o blink -lstdc++ -lwiringPi -IwiringPi<br />
</pre><br />
where I assumed that the wiringPi root folder is located in the same folder as the ''blink.cpp'' source file.<br />
<br /><br />
<br/><br />
Which pins can be used for what purpose is explained on the [http://wiringpi.com/pins wiringPi pins] page.<br />
<br /><br />
<br/><br />
<br />
= PWM =<br />
There are some Python libraries that communicate with the GPIO daemon to provide hardware PWM on selected pins. [https://gpiozero.readthedocs.org/ GPIO Zero] ([https://www.raspberrypi.org/blog/gpio-zero-a-friendly-python-api-for-physical-computing/ tutorial]) is one such library and is included in [https://www.raspberrypi.org/downloads/raspbian/ Raspbian]. With GPIO Zero you can implement dimming LEDs or control a brushed DC motor behind an [https://en.wikipedia.org/wiki/H_bridge H-Bridge] circuit.<br />
<br />
<br /><br />
= Running A Program On Startup =<br />
== Using SysVInit ==<br />
We want the Raspberry Pi to start the robot control program as soon as it's done with booting. In order to make sure that the system has completely initialized itself we will not use ''/etc/rc.local'' for starting our program. Instead, we will create a ''cron'' task with the ''crontab'' command<br />
<br /><br />
<pre class="terminal"><br />
sudo crontab -e<br />
</pre><br />
which opens the editor of choice (most likely ''nano'') where you can enter the program launch command. In our case this will be<br />
<pre class="code"><br />
@reboot python /home/pi/Core.py<br />
</pre><br />
where the leading ''@reboot'' indicates to ''cron'' that this command shall be executed only once, right after the booting process has completed. Notice that it is not necessary to start the command with ''sudo'', which is necessary when running program from the command line.<br />
<br /><br />
<br />
== Using Systemd ==<br />
<br /><br />
<br />
<br /><br />
<br />
= Communicating With Other Devices =<br />
There are three popular communication protocols that the Raspberry Pi supports and that are often used in embedded systems: I<sup>2</sup>C, SPI, and UART.<br />
<br /><br />
<br /><br />
<br />
== I<sup>2</sup>C ==<br />
Set the [[I2C | I<sup>2</sup>C]] clock speed by editing '''/boot/config.txt'''<br />
<pre class="code"><br />
dtparam=i2c1=on<br />
dtparam=i2c_arm_baudrate=xxx<br />
</pre><br />
where ''xxx'' is the desired frequency. Keep in mind that ATmega microcontrollers used on Arduino boards support only up to 400 kHz while Raspberry Pi can support higher speeds.<br />
<br /><br />
<br /><br />
=== Wiring To I<sup>2</sup>C Devices With 5 V Logic Level ===<br />
Normally you can not connect a GPIO pin to a device with 5 V logic (most of the Arduino models, for example). The GPIO data pins of the Raspberry Pi use 3.3 V as the HIGH voltage level and can be damaged when 5 V is applied. However, because I<sup>2</sup>C pins have [https://en.wikipedia.org/wiki/Open_collector open-collector] outputs they can be wired directly to I<sup>2</sup>C pins of devices with incompatible voltage levels. As long as the pull-up line voltage, which corresponds to the lowest of the device HIGH voltage levels, exceeds the minimum voltage for which HIGH is defined on each device, the devices will be able to sense the correct data bit.<br />
<br /><br />
<br /><br />
Links:<br />
* [https://learn.sparkfun.com/tutorials/i2c Tutorial by SparkFun] on I<sup>2</sup>C<br />
* [https://learn.adafruit.com/adafruits-raspberry-pi-lesson-4-gpio-setup?view=all Article by Adafruit] on how to set up I<sup>2</sup>C and SPI on a Raspberry Pi<br />
* Tutorial for setting up an I2C bus [http://blog.oscarliang.net/raspberry-pi-arduino-connected-i2c/ between a Raspberry Pi and an Arduino].<br />
<br /><br />
<br />
== SPI ==<br />
First of all, you need to use the ''raspi-config'' command-line configuration utility to enable the SPI pins.<br />
<pre class="terminal"><br />
sudo raspi-config<br />
</pre><br />
<br /><br />
You can use [http://wiringpi.com/reference/spi-library/ WiringPi SPI] to add SPI capability to your C/C++ program.<br />
<br /><br />
<br /><br />
<br />
== UART ==<br />
[http://www.andremiller.net/content/raspberry-pi-and-arduino-via-gpio-uart Here is a tutorial] that shows how to communicate with an Arduino using the UART interface.<br />
<br /><br />
<br /><br />
<br />
== CAN ==<br />
There are various [[CAN]] adapter boards available for Raspberry Pi. For example [http://skpang.co.uk/catalog/pican2-canbus-board-for-raspberry-pi-2-p-1475.html PiCAN2].<br />
<br /><br />
<br /><br />
<br />
= Device Tree Overlays =<br />
A device tree overlay is a mechanism in Raspberry Pi computers to dynamically apply changes to existing device trees. This mechanism is mostly used to enable kernel-space support for hardware components that are attached to the Raspberry Pi via its GPIO headers.<br />
<br /><br />
<br /><br />
Operations with device tree overlays are performed by the Raspberry Pi GPU (VideoCore), without needing to preempt the Linux kernel. The Raspberry Pi primary bootloader, also a VideoCore firmware application, makes use of this device tree parsing and editing capability to apply device tree overlays during the boot process, before passing control to the Linux kernel.<br />
<br /><br />
==== /boot/config.txt ====<br />
The primary bootloader parses and interprets the ''/boot/config.txt'' file. It specifies, among other things, which device tree to select and which overlays to apply.<br />
<br /><br />
==== dtoverlay ====<br />
'''dtoverlay''' is the command-line tool for loading a device tree overlay (or unloading a previously loaded overlay) while the Linux system is running.<br />
<pre class="terminal"><br />
</pre><br />
<br /><br />
<br />
= Yocto Tips =<br />
== Adding Peripherals for a Compute Module ==<br />
A compute module does not know what hardware components its carrier board provides unless the default device tree is modified to include the interfaces to these hardware components. Instead of providing a different complete device tree, you would normally [[Yocto#Patching_A_Device_Tree | create a patch]] for the device tree source file provided by a lower Yocto layer.<br />
<br /><br />
<br /><br />
The modified device tree must be based on the device tree used by the kernel in Yocto. Copy that device tree from the Yocto build directory to the layer's recipe directory.<br />
<pre class="terminal"><br />
DTS_DIR=${YOCTO_BUILD_DIR}/tmp/work-shared/raspberrypi4-64/kernel-source/arch/arm/boot/dts<br />
cp ${DTS_DIR}/bcm2711-rpi-cm4.dts ${LAYER_DIR}/recipes-kernel/linux/files/<br />
</pre><br />
<br /><br />
Edit the copy to fit your needs. The Raspberry Pi reference device tree files at the [https://datasheets.raspberrypi.com/ Raspberry Pi Datasheets collection page] can be helpful in creating your modified device tree.<br />
<br /><br />
<br /><br />
After making the changes, create a git patch file using ''git diff'':<br />
<pre class="terminal"><br />
git diff --no-index {DTS_DIR}/bcm2711-rpi-cm4.dts bcm2711-rpi-cm4.dts > 0001-my_modifications-dts.patch<br />
</pre><br />
<br /><br />
Edit the generated patch file to fix the file paths at the top. The paths must be relative to the kernel sources directory ''${YOCTO_BUILD_DIR}/tmp/work-shared/raspberrypi4-64/kernel-source''. The header should look like this:<br />
<pre class="code"><br />
diff --git a/arch/arm/boot/dts/bcm2711-rpi-cm4.dts b/bcm2711-rpi-cm4.dts<br />
index 6e99da1..4567735 100644<br />
--- a/arch/arm/boot/dts/bcm2711-rpi-cm4.dts<br />
+++ b/arch/arm/boot/dts/bcm2711-rpi-cm4.dts<br />
</pre><br />
where "--- a" and "+++ b" are followed by the same relative file path.<br />
<br /><br />
<br />
<br /><br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Raspberry_Pi&diff=3145Raspberry Pi2022-12-25T13:26:59Z<p>Kai: Changes headings classes, adds Yocto Tips section.</p>
<hr />
<div>= Introduction =<br />
The [http://raspberrypi.org Raspberry Pi Ltd.] is a company producing small and affordable single-board, bare-bones computer systems, microcontrollers and accessories, marketed under the ''Raspberry Pi'' brand. All Raspberry Pi computing products use Arm-based processors. I use Raspberry Pi computers as [[Robot Task Controller | task controller]], and the microcontrollers as [[Robot State Agent | state agent]] in my robots.<br />
<br /><br />
<br /><br />
= Processors and Architectures =<br />
<br />
* [https://developer.arm.com/Processors/Cortex-A7 Arm Cortex-A7] with 32-bit Armv7 programming model<br />
** Raspberry Pi 2 B (Broadcom BCM2836 processor @ 900 MHz)<br />
<br /><br />
<br />
* [https://developer.arm.com/Processors/Cortex-A53 Arm Cortex-A53] with 64-bit Armv8-A programming model.<br />
** Raspberry Pi 2 B rev 1.2 (Broadcom BCM2837 processor @ 900 MHz)<br />
** Raspberry Pi 3 B (Broadcom BCM2837 processor @ 1.2 GHz)<br />
** Raspberry Pi 3 B+ (Broadcom BCM2837B0 processor @ 1.4 GHz)<br />
** Raspberry Pi Zero 2 W (@ 1 GHz)<br />
<br /><br />
<br />
* [https://developer.arm.com/Processors/Cortex-A72 Arm Cortex-A72] with 64-bit Armv8-A programming model<br />
** Raspberry Pi 4 (Broadcom BCM2711 processor @ 1.5 GHz)<br />
** Compute Module 4 (Broadcom BCM2711 @ 1.5 GHz)<br />
<br /><br />
<br />
* [https://developer.arm.com/Processors/Cortex-M0+ Arm Cortex-M0+] with Armv6-M programming model<br />
** Raspberry Pi Pico (up to 133 MHz)<br />
<br /><br />
<br />
= Installing a System Image =<br />
[https://www.raspberrypi.com/software/operating-systems/ Raspberry Pi OS] is the offical operating system of a Raspberry Pi. The Lite version, without a graphical desktop, is recommended for embedded applications unless you decide to create a custom system image. The fewer software modules are running, the lower the power consumption, and the lower the chance that user-space processes will be interrupted.<br />
<br /><br />
<br /><br />
== Installing the System Image on SD Card ==<br />
This is the most popular method of installing a system image on a single-board computers. SD cards are cheap and reusable, almost all Raspberry Pi models come with an SD card reader. However, SD card memory is not designed to support frequent rewrite operations and may not be as durable as other storage solutions. <br />
<br />
The preferred way of putting a system image on an SD card is to use the [https://www.raspberrypi.com/software Raspberry Pi Imager] tool that can fetch a Raspberry Pi OS image over the Internet or use a local image file, create a derived image with preconfigured user credentials, WLAN access and more, before writing it to the SD card.<br />
<br />
=== Using built-in tools on Linux ===<br />
The SD card can also be prepared by using standard Linux tools instead of Raspberry Pi Imager. First, we need to find out which device to copy the install image to. Type<br />
<pre class="terminal"><br />
df -h<br />
</pre><br />
or<br />
<pre class="terminal"><br />
sudo fdisk --list<br />
</pre><br />
in the command terminal to look up the mount point for the SD card. Let us assume the card was mounted as ''/dev/sdb2''. The card needs to be unmounted before we can copy the downloaded Raspberry Pi OS install image:<br />
<br /><br />
<pre class="terminal"><br />
umount /dev/sdb2<br />
</pre><br />
<br /><br />
Copy the image to the card with the ''dd'' command:<br />
<pre class="terminal"><br />
sudo dd bs=4M if=2021-01-11-raspios-buster-armhf-lite.img of=/dev/sdb<br />
</pre><br />
where we use the path to the device file ''/dev/sdb'' instead of the partition ''/dev/sdb2'', which was unmounted. The option ''bs'' is used for adjusting the buffer size for the writing operation.<br />
<br /><br />
<br /><br />
<br />
=== Using built-in tools on macOS ===<br />
On Apple macOS, you can use the built-in 'diskutil' tool as an alternative to the Raspberry Pi Imager. First, attach the SD card to your Mac and determine the assigned disk number ''disk#'' (e.g., disk2) under which the card has been mounted to the filesystem by opening Terminal and typing<br />
<br /><br />
<pre class="terminal"><br />
diskutil list<br />
</pre><br />
then unmount the disk<br />
<pre class="terminal"><br />
diskutil unmountDisk disk2<br />
</pre><br />
and copy the data with the ''dd'' tool<br />
<pre class="terminal"><br />
sudo dd bs=1m if=~/Downloads/raspios.img of=/dev/rdisk2<br />
</pre><br />
where I assume that the downloaded and <u>unzipped</u> Raspberry Pi OS image file is located at ''~/Downloads/raspios.img'' and the SD card was mounted as ''disk2''.<br />
<br /><br />
<br />
== Installing the System Image on eMMC ==<br />
Some Raspberry Pi models, like the Compute Module 4, come with an embedded MultiMediaCard (eMMC) storage component. A switch or jumper on the carrier board serves to make the Raspberry Pi bootloader boot the compute module into USB mass storage mode. In this mode you can attach the compute module to an external computer via USB. On Ubuntu you can use the<br />
<pre class="terminal"><br />
lsusb<br />
</pre><br />
command to list all connected USB devices. The Compute Module 4, for example, should show up as "Broadcom Corp. BCM2711 Boot".<br />
<br /><br />
To make the operating system recognize the USB device as a mass storage device, we need to build and run Raspberry Pi's ''rpiboot'' tool.<br />
<pre class="terminal"><br />
sudo apt install libusb-1.0-0-dev<br />
git clone --depth=1 https://github.com/raspberrypi/usbboot<br />
cd usbboot<br />
make<br />
sudo ./rpiboot<br />
</pre><br />
On Ubuntu, ''lsusb'' will now list the Compute Module 4 as "Broadcom Corp. Compute Module". The compute module will also show up in the ''Disks'' app as ''RPi-MSD-0001''.<br />
<br /><br />
[[File: raspberrypi_emmc_shows_up_in_disks_app.png | x300px ]]<br />
<br /><br />
You can now use Raspberry Pi Imager or any flashing utility to flash a system image on the compute module eMMC.<br />
<br /><br />
<br /><br />
<br />
= Upgrading a Raspberry Pi OS Installation =<br />
You don't want to erase your existing Raspberry Pi OS environment and set up all the software from start each time a new version of Raspberry Pi OS is released. Fortunately, [https://www.raspberrypi.com/documentation/computers/os.html#updating-and-upgrading-raspberry-pi-os Raspberry Pi OS can upgrade itself to the latest release] with the following commands.<br />
<pre class="terminal"><br />
sudo apt-get update<br />
sudo apt-get dist-upgrade<br />
</pre><br />
<br /><br />
<br /><br />
<br />
= Assigning a Static Ethernet IP Address =<br />
Edit the file '''/etc/network/interfaces''' and make sure that the entries for the interface ''eth0'' are as follows:<br />
<pre class="terminal"><br />
auto eth0<br />
iface eth0 inet static<br />
address 192.168.0.20<br />
netmask 255.255.255.0<br />
broadcast 192.168.0.255<br />
</pre><br />
where the IP address ''192.168.0.20'' is just an example.<br />
<br /><br />
<br /><br />
Make sure you don't break the WiFi connectivity because of editing ''/etc/network/interfaces''. If there is no empty describing ''wlan0'' we will need to create one. For dynamically assigned IPs via DHCP you will need these lines:<br />
<pre class="terminal"><br />
auto wlan0<br />
iface wlan0 inet dhcp<br />
wpa-ssid <your WiFi router name (SSID)><br />
wpa-psk <your WiFi password><br />
</pre><br />
<br /><br />
The new network setting becomes effective on the next system boot or when you type<br />
<pre class="terminal"><br />
sudo ifdown eth0<br />
sudo ifup eth0<br />
</pre><br />
<br /><br />
<br /><br />
= Setting Up SSH =<br />
* As a security measure, SSH is not enabled by default on headless (= Raspbian Lite, without GUI) installations. Place a file named "ssh" into the root folder of the boot partition (= ''/boot'') to enable SSH.<br />
* In the web browser go to the configuration page of your home Internet router (e.g., http://192.168.1.1).<br />
* Open the page that lists all currently connected LAN devices.<br />
* Connect the Raspberry Pi via Ethernet cable to the LAN router.<br />
* Look for a new entry in the list of LAN devices. That should be your Raspberry Pi. Note the IP address. Let's assume it is ''192.168.1.10''.<br />
* Optional: You should be able to read the [https://en.wikipedia.org/wiki/MAC_address MAC address] of the Raspberry Pi from the table. For future reference, write down the MAC address somewhere.<br />
* Open Terminal and type '''ssh pi@192.168.1.10''' to log in via SSH. On a fresh Raspbian installation the username is '''pi''' and the password is '''raspberry'''.<br />
* After logging in type '''sudo raspi-config''' to start the Raspbian configuration tool, where you can change the password or expand the filesystem to take up the whole SD card, among other things.<br />
<br /><br />
<br /><br />
= Setting Up WiFi =<br />
== Raspberry Pi 2 ==<br />
The Raspberry Pi 2 does not have built-in WiFi. I assume that you are using a USB WiFi adapter. Before connecting the adapter you need to edit the network interfaces on the Raspberry Pi. Log in to the Raspberry Pi over SSH and edit '''/etc/network/interfaces''' as follows:<br />
<br /><br />
<pre class="code"><br />
auto lo<br />
<br />
iface lo inet loopback<br />
iface eth0 inet dhcp<br />
<br />
allow-hotplug wlan0<br />
auto wlan0<br />
<br />
iface wlan0 inet dhcp<br />
wpa-ssid "ssid"<br />
wpa-psk “password"<br />
</pre><br />
<br /><br />
where ''ssid'' is the SSID (a.k.a. name) of your WLAN router, and ''password'' is supplied in encoded form. Do not type the quotation marks. The password is encoded by running<br />
<br /><br />
<pre class="terminal"><br />
wpa_passphrase <ssid> <password><br />
</pre><br />
<br /><br />
If your WLAN router uses a hidden SSID use this configuration:<br />
<pre class="code"><br />
auto lo<br />
<br />
iface lo inet loopback<br />
iface eth0 inet dhcp<br />
<br />
auto wlan0<br />
allow-hotplug wlan0<br />
iface wlan0 inet dhcp<br />
wpa-scan-ssid 1<br />
wpa-ap-scan 1<br />
wpa-key-mgmt WPA-PSK<br />
wpa-proto RSN WPA<br />
wpa-pairwise CCMP TKIP<br />
wpa-group CCMP TKIP<br />
wpa-ssid "My Secret SSID"<br />
wpa-psk "My SSID PSK”<br />
<br />
iface default inet dhcp<br />
</pre><br />
<br /><br />
Instead of putting the WPA configuration directly into '''interfaces''' you can put it into the file '''/etc/wpa_supplicant/wpa_supplicant.conf'''<br />
<pre class="code"><br />
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev<br />
update_config=1<br />
<br />
network={<br />
ssid="<your ssid>"<br />
psk=<your encoded password given by running wpa_passphrase><br />
scan_ssid=1<br />
proto=WPA RSN<br />
key_mgmt=WPA-PSK<br />
pairwise=CCMP TKIP<br />
}<br />
</pre><br />
<br /><br />
and refer to it from '''interfaces''' like so<br />
<pre class="code"><br />
auto lo<br />
iface lo inet loopback<br />
<br />
iface eth0 inet dhcp<br />
<br />
allow-hotplug wlan0<br />
iface wlan0 inet dhcp<br />
wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf<br />
<br />
iface default inet dhcp<br />
</pre><br />
<br /><br />
<br /><br />
<br />
== Raspberry Pi 3 or newer ==<br />
The Raspberry Pi 3 has a WLAN transmitter built in and it is turned on by default. You should see the device '''wlan0''' along with '''eth0''' and '''lo''' when typing<br />
<br /><br />
<pre class="terminal"><br />
ifconfig -a<br />
</pre><br />
<br /><br />
Make sure the Raspberry Pi can log in to your WLAN router. If a MAC filter is active, add the Raspberry Pi WiFi MAC address to the list of allowed devices. The MAC address of the Pi is displayed in the output of ''ifconfig -a'' as '''HWaddr'''. Open a text editor to add the network configuration details, such as your login credentials, to the file ''/etc/wpa_supplicant/wpa_supplicant.conf''.<br />
<br /><br />
<pre class="code"><br />
network={<br />
ssid="MySSID"<br />
psk=MyCodedPassword<br />
scan_ssid=1<br />
proto=WPA RSN<br />
key_mgmt=WPA-PSK<br />
pairwise=CCMP TKIP<br />
}<br />
</pre><br />
<br /><br />
where '''MySSID''' is the SSID (a.k.a. name) of the router, and '''MyCodedPassword''' is the encoded password obtained via<br />
<br /><br />
<pre class="terminal"><br />
wpa_passphrase MySSID MyPassword<br />
</pre><br />
and where '''MyPassword''' is the actual password.<br />
<br /><br />
<br /><br />
<br />
== Power Saving ==<br />
If the WiFi connection is unstable you can turn off the WiFi power management feature, which may cause connection dropouts, by issuing the command<br />
<pre class="terminal"><br />
sudo iw dev wlan0 set power_save off<br />
</pre><br />
or by manually editing '''/etc/network/interfaces''', where you add the line<br />
<pre class="code"><br />
wireless-power off<br />
</pre><br />
right after the line<br />
<pre class="code"><br />
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf<br />
</pre><br />
within the '''wlan0''' block. You can check whether power management is currently turned on or off, among other parameters, with the command<br />
<pre class="terminal"><br />
iwconfig<br />
</pre><br />
<br /><br />
<br /><br />
For Raspberry Pi 2 and WiFi dongles with 8192CU or 8188CUS chip (for example, Edimax EW-7811un dongles)you can prevent connections from being dropped by creating the file '''/etc/modprobe.d/8192cu.conf'''<br />
<br><br />
<pre class="terminal"><br />
sudo nano /etc/modprobe.d/8192cu.conf<br />
</pre><br />
and adding the line<br />
<br /><br />
<pre class="code"><br />
options 8192cu rtw_power_mgnt=0 rtw_enusbss=0<br />
</pre><br />
<br /><br />
<br />
= Camera =<br />
There is a [https://www.raspberrypi.org/products/camera-module/ camera module] for Raspberry Pi, which I use in my robots. In fact, the camera module is part of the [[Core Module]].<br />
<br /><br />
<br /><br />
Refer to the official [https://www.raspberrypi.org/documentation/usage/camera/README.md camera setup instructions]. Be careful with the camera module, handle the camera board and the connector strip delicately.<br />
<br /><br />
<br /><br />
To be able to access the camera through the Python programming environment you need to install the '''python-picamera''' package<br />
<br /><br />
<br /><br />
The Raspberry Pi project does not provide a C/C++ library for accessing the camera. Instead it provides utility applications ''raspistill'' and ''raspivid'' which record still images and videos, respectively. A number of third-party C++ libraries have been created based on the open source code of these utility applications. The [http://www.uco.es/investiga/grupos/ava/node/40 RaspiCam] C++ library developed at the University of Cordoba is one such library (source code available [https://sourceforge.net/projects/raspicam/ from SourceForge]).<br />
<br /><br />
<br /><br />
== Video Streaming ==<br />
To stream video from the Raspberry Pi camera to the network, open a terminal on the RPi and type<br />
<pre class="terminal"><br />
raspivid -t 0 -w 1280 -h 720 -hf -ih -fps 30 -o - | nc -k -l 8100<br />
</pre><br />
<br /><br />
To view the stream on a client computer with [http://www.mplayerhq.hu Mplayer] installed, open a terminal there and type<br />
<pre class="terminal"><br />
mplayer -fps 300 -demuxer h264es ffmpeg://tcp://192.168.0.20:8100<br />
</pre><br />
<br /><br />
<br /><br />
Alternatively, you can use [[GStreamer]] to transport the video frames. Make sure that the command line interface to GStreamer, ''gst-launch-1.0'', is installed. <br />
<pre class="terminal"><br />
sudo apt install gstreamer1.0-tools<br />
</pre><br />
<br /><br />
For streaming from the RPi you can type<br />
<pre class="terminal"><br />
raspivid -t 0 -w 640 -h 480 -fps 30 -hf -b 2000000 -o - | gst-launch-1.0 -q fdsrc ! h264parse ! rtph264pay config-interval=1 pt=96 ! gdppay ! tcpserversink host=0.0.0.0 port=8100<br />
</pre><br />
<br /><br />
For viewing on the client, you can type<br />
<pre class="terminal"><br />
gst-launch-1.0 -v tcpclientsrc host=192.168.0.20 port=8100 ! gdpdepay ! rtph264depay ! avdec_h264 ! videoconvert ! videoflip method=vertical-flip ! autovideosink sync=false<br />
</pre><br />
where ''192.168.0.20'' is assumed to be the IP address of the server (Raspberry Pi).<br />
<br /><br />
<br /><br />
* On the Raspberry Pi side you can elevate the priority of the process by beginning the command with ''"nice -20"''.<br />
* For verbose output from ''gst-launch-1.0'', use the option ''-v'' instead of ''-q''.<br />
* Note that we used the [https://gstreamer.freedesktop.org/documentation/videofilter/videoflip.html?gi-language=c#GstVideoFlipMethod videoflip] filter to correct the rotation of the decoded image.<br />
<br /><br />
=== Disabling the LED ===<br />
To disable the red indicator light of the camera, add the following line to '''/boot/config.txt''' and reboot:<br />
<pre class="code"><br />
disable_camera_led=1<br />
</pre><br />
<br /><br />
<br />
= pinout =<br />
A cool command-line tool provided by Raspberry Pi, and also available when running Ubuntu instead of Raspberry Pi OS, is '''pinout'''. It displays a layout of the Raspberry Pi board using ASCII art, a list of significant hardware features of the board, and the GPIO pin layout in tabular form.<br />
<br /><br />
<pre class="terminal"><br />
sudo apt install python3-gpiozero<br />
pinout<br />
</pre><br />
<br /><br />
[[File:Raspberry_Pi_pinout_command.png | x600px]]<br />
<br /><br />
<br /><br />
<br />
= raspi-gpio =<br />
The documentation states that ''"raspi-gpio can get and print the state of a GPIO (or all GPIOs) and can be used to set the function, pulls and value of a GPIO. raspi-gpio must be run as root."''<br />
"<br />
<pre class="terminal"><br />
> sudo apt install raspi-gpio<br />
> raspi-gpio funcs 20,21,22<br />
GPIO, DEFAULT PULL, ALT0, ALT1, ALT2, ALT3, ALT4, ALT5<br />
20, DOWN, PCM_DIN, SD12, DPI_D16, SPI6_MOSI, SPI1_MOSI, GPCLK0<br />
21, DOWN, PCM_DOUT, SD13, DPI_D17, SPI6_SCLK, SPI1_SCLK, GPCLK1<br />
22, DOWN, SD0_CLK, SD14, DPI_D18, SD1_CLK, ARM_TRST, SDA6<br />
> raspi-gpio get 20<br />
GPIO 20: level=0 func=INPUT pull=DOWN<br />
GPIO 21: level=1 func=INPUT pull=DOWN<br />
GPIO 22: level=0 func=INPUT pull=DOWN<br />
> raspi-gpio raw 21<br />
00: 00000000 00012000 12000000 3fffffff<br />
10: 24000040 00000924 00000000 6770696f<br />
20: 6770696f 6770696f 6770696f 6770696f<br />
30: 6770696f 102081ff 00003bfb 00000000<br />
40: 00000000 00000000 00000000 00000000<br />
50: 00000000 00000000 00000000 00000000<br />
60: 00000000 00000000 00000000 00000000<br />
70: 00000000 00000000 00000000 00000000<br />
80: 00000000 00000000 00000000 00000000<br />
90: 00000000 00000000 00000000 00000000<br />
e0: 4aa95555 19aaaaaa 50aa5544<br />
f0: 000aaaaa<br />
</pre><br />
<br /><br />
<br />
= GPIO Programming in C =<br />
Raspberry Pi 2, 3 & 4 come with 40 ''General Purpose Input Output'' (GPIO) pins ([https://www.raspberrypi.com/documentation/computers/os.html#gpio-and-the-40-pin-header layout]) that can be used to interface with the other electronic components of your project.<br />
<br />
== Using libgpiod ==<br />
The standard C++ programming interface for GPIO on Linux is ''libgpiod'', as described on [[Nvidia_Jetson#Using_Libgpiod | the Jetson page]].<br />
<br />
== Using WiringPi ==<br />
Using the [http://wiringpi.coml WiringPi] library is a more popular method for programming the GPIO pins on a Raspberry Pi with C/C++. WiringPi is [http://wiringpi.com/download-and-install installed from source] like this<br />
<pre class="terminal"><br />
sudo apt-get install git-core<br />
git clone git://git.drogon.net/wiringPi<br />
cd wiringPi<br />
./build<br />
</pre><br />
Read the ''INSTALL'' file for what to do with the created shared library. Basically you need to copy ''wiringPi/libwiringPi.so.x.xx'' to ''/usr/local/lib'' and add the line<br />
<pre class="code"><br />
include /usr/local/lib<br />
</pre><br />
to the file ''/etc/ld.so.conf'' so that the library loader also looks in ''/usr/local/lib'' for dynamically loadable libraries. It is also possible to create a static library.<br />
<br /><br />
<br/><br />
After installation, create a test program called ''blink.cpp''<br />
<pre class="code"><br />
#include <stdio.h><br />
#include <iostream><br />
#include <wiringPi.h><br />
<br />
static int LED_PORT = 7; // The physical pin number. Corresponds to BCM GPIO pin 4.<br />
<br />
void blink()<br />
{<br />
digitalWrite(4, HIGH);<br />
delay(1000);<br />
digitalWrite(4, LOW);<br />
delay(1000);<br />
};<br />
<br />
int main(int numargs, char** args)<br />
{<br />
wiringPiSetup();<br />
pinMode(LED_PORT, OUTPUT);<br />
for (int n = 0; n < 10; n++)<br />
{<br />
blink();<br />
}<br />
std::cout << "finished blinking" << std::endl;<br />
return 0;<br />
}<br />
</pre><br />
and build like this<br />
<pre class="terminal"><br />
g++ blink.cpp -o blink -lstdc++ -lwiringPi -IwiringPi<br />
</pre><br />
where I assumed that the wiringPi root folder is located in the same folder as the ''blink.cpp'' source file.<br />
<br /><br />
<br/><br />
Which pins can be used for what purpose is explained on the [http://wiringpi.com/pins wiringPi pins] page.<br />
<br /><br />
<br/><br />
<br />
= PWM =<br />
There are some Python libraries that communicate with the GPIO daemon to provide hardware PWM on selected pins. [https://gpiozero.readthedocs.org/ GPIO Zero] ([https://www.raspberrypi.org/blog/gpio-zero-a-friendly-python-api-for-physical-computing/ tutorial]) is one such library and is included in [https://www.raspberrypi.org/downloads/raspbian/ Raspbian]. With GPIO Zero you can implement dimming LEDs or control a brushed DC motor behind an [https://en.wikipedia.org/wiki/H_bridge H-Bridge] circuit.<br />
<br />
<br /><br />
= Running A Program On Startup =<br />
== Using SysVInit ==<br />
We want the Raspberry Pi to start the robot control program as soon as it's done with booting. In order to make sure that the system has completely initialized itself we will not use ''/etc/rc.local'' for starting our program. Instead, we will create a ''cron'' task with the ''crontab'' command<br />
<br /><br />
<pre class="terminal"><br />
sudo crontab -e<br />
</pre><br />
which opens the editor of choice (most likely ''nano'') where you can enter the program launch command. In our case this will be<br />
<pre class="code"><br />
@reboot python /home/pi/Core.py<br />
</pre><br />
where the leading ''@reboot'' indicates to ''cron'' that this command shall be executed only once, right after the booting process has completed. Notice that it is not necessary to start the command with ''sudo'', which is necessary when running program from the command line.<br />
<br /><br />
<br />
== Using Systemd ==<br />
<br /><br />
<br />
<br /><br />
<br />
= Communicating With Other Devices =<br />
There are three popular communication protocols that the Raspberry Pi supports and that are often used in embedded systems: I<sup>2</sup>C, SPI, and UART.<br />
<br /><br />
<br /><br />
<br />
== I<sup>2</sup>C ==<br />
Set the [[I2C | I<sup>2</sup>C]] clock speed by editing '''/boot/config.txt'''<br />
<pre class="code"><br />
dtparam=i2c1=on<br />
dtparam=i2c_arm_baudrate=xxx<br />
</pre><br />
where ''xxx'' is the desired frequency. Keep in mind that ATmega microcontrollers used on Arduino boards support only up to 400 kHz while Raspberry Pi can support higher speeds.<br />
<br /><br />
<br /><br />
=== Wiring To I<sup>2</sup>C Devices With 5 V Logic Level ===<br />
Normally you can not connect a GPIO pin to a device with 5 V logic (most of the Arduino models, for example). The GPIO data pins of the Raspberry Pi use 3.3 V as the HIGH voltage level and can be damaged when 5 V is applied. However, because I<sup>2</sup>C pins have [https://en.wikipedia.org/wiki/Open_collector open-collector] outputs they can be wired directly to I<sup>2</sup>C pins of devices with incompatible voltage levels. As long as the pull-up line voltage, which corresponds to the lowest of the device HIGH voltage levels, exceeds the minimum voltage for which HIGH is defined on each device, the devices will be able to sense the correct data bit.<br />
<br /><br />
<br /><br />
Links:<br />
* [https://learn.sparkfun.com/tutorials/i2c Tutorial by SparkFun] on I<sup>2</sup>C<br />
* [https://learn.adafruit.com/adafruits-raspberry-pi-lesson-4-gpio-setup?view=all Article by Adafruit] on how to set up I<sup>2</sup>C and SPI on a Raspberry Pi<br />
* Tutorial for setting up an I2C bus [http://blog.oscarliang.net/raspberry-pi-arduino-connected-i2c/ between a Raspberry Pi and an Arduino].<br />
<br /><br />
<br />
== SPI ==<br />
First of all, you need to use the ''raspi-config'' command-line configuration utility to enable the SPI pins.<br />
<pre class="terminal"><br />
sudo raspi-config<br />
</pre><br />
<br /><br />
You can use [http://wiringpi.com/reference/spi-library/ WiringPi SPI] to add SPI capability to your C/C++ program.<br />
<br /><br />
<br /><br />
<br />
== UART ==<br />
[http://www.andremiller.net/content/raspberry-pi-and-arduino-via-gpio-uart Here is a tutorial] that shows how to communicate with an Arduino using the UART interface.<br />
<br /><br />
<br /><br />
<br />
== CAN ==<br />
There are various [[CAN]] adapter boards available for Raspberry Pi. For example [http://skpang.co.uk/catalog/pican2-canbus-board-for-raspberry-pi-2-p-1475.html PiCAN2].<br />
<br /><br />
<br /><br />
<br />
= Device Tree Overlays =<br />
A device tree overlay is a mechanism in Raspberry Pi computers to dynamically apply changes to existing device trees. This mechanism is mostly used to enable kernel-space support for hardware components that are attached to the Raspberry Pi via its GPIO headers.<br />
<br /><br />
<br /><br />
Operations with device tree overlays are performed by the Raspberry Pi GPU (VideoCore), without needing to preempt the Linux kernel. The Raspberry Pi primary bootloader, also a VideoCore firmware application, makes use of this device tree parsing and editing capability to apply device tree overlays during the boot process, before passing control to the Linux kernel.<br />
<br /><br />
==== /boot/config.txt ====<br />
The primary bootloader parses and interprets the ''/boot/config.txt'' file. It specifies, among other things, which device tree to select and which overlays to apply.<br />
<br /><br />
==== dtoverlay ====<br />
'''dtoverlay''' is the command-line tool for loading a device tree overlay (or unloading a previously loaded overlay) while the Linux system is running.<br />
<pre class="terminal"><br />
</pre><br />
<br /><br />
<br />
= Yocto Tips =<br />
== Adding Peripherals for a Compute Module ==<br />
A compute module does not know what hardware components its carrier board provides unless the default device tree is modified to include the interfaces to these hardware components. Instead of providing a different complete device tree, you would normally [[Yocto#Patching_A_Device_Tree | create a patch]] for the device tree source file provided by a lower Yocto layer.<br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Yocto&diff=3144Yocto2022-12-25T13:05:54Z<p>Kai: Adds instructions for patching a device tree.</p>
<hr />
<div>= Yocto and OpenEmbedded =<br />
The collection of software tools used by the Yocto project have been developed by the [https://www.openembedded.org OpenEmbedded] project. The Yocto project basically uses these generic build tools to provide a basic Linux system called ''Poky''. Stable releases of Poky serve as standard platforms for third parties that provide additional features (e.g., hardware support layers).<br />
<br /><br />
<br /><br />
<br />
= Prerequisites =<br />
* A Linux system supported by the Yocto project.<br />Assuming that [[Ubuntu]] is used. <br />
* Following package installed:<br />
<pre class=terminal><br />
sudo apt install gcc g++ \<br />
python3-distutils python-is-python3<br />
</pre><br />
<br /><br />
<br />
= Bitbake =<br />
Bitbake is the build tool from the OpenEmbedded project, which parses the project's metadata, resolves dependencies and the ordering of the build steps, runs the builds to create packages, to finally create an image from the packages.<br />
<br /><br />
=== Metadata Types ===<br />
Yocto metadata, which controls how a system image is built, can be categorized at a high level into these four types:<br />
* ''Machine''<br />the targeted hardware platform (e.g. Raspberry Pi 4)<br />
* ''Distro''<br />common characteristic of a family of related images<br />
* ''Recipes''<br />instructions on how to process the source files for a component of the image<br />
* ''Image''<br />recipes that define the contents of generated system images<br />
<br /><br />
=== Layers ===<br />
Layers are purposeful collections of metadata. Yocto layers often Layers often add the provide that for a that can be combined with other layers in order to directories in which <br />
<br /><br />
<br />
<br /> <br />
<br />
= Images =<br />
<br />
Images are recipes that ultimately inherit from '''meta/classes/image.bbclass''' and set the global variable '''IMAGE_INSTALL'''. Most images, however, will inherit from ''meta/classes/core-image.bbclass'' which inherits directly from ''image.bbclass'', provides a mapping from ''IMAGE_FEATURES'' to package groups, and adds the two package groups ''packagegroup-core-boot'' and ''packagegroup-base-extended'' to ''IMAGE_INSTALL''.<br />
<br />
Images are defined in recipe files with the file extension 'bb'. In order to separate them from package recipes, there is a convention to put image recipes into a folder named ''images''. Making use of this, we can list all images defined by all layers via<br />
<pre class="terminal"><br />
cd poky<br />
ls meta*/recipes*/images/*.bb<br />
</pre><br />
<br /><br />
<br />
=== ''IMAGE_FEATURES'' ===<br />
The ''IMAGE_FEATURES'' variable is defined in ''meta/classes/image.bbclass'' with an empty value. It accepts only a predefined set of features (e.g., ''x11'', ''debug-tweaks'', ''dev-pkgs'', ''dbg-pkgs''). This affects how recipes will execute their tasks and which packages will be selected to go into the image. The image recipe ''meta/recipes-core/images/core-image-base.bb'', for example, adds the ''splash'' feature.<br />
<br /><br />
<br />
=== ''IMAGE_INSTALL'' ===<br />
Holds a list of package groups whose packages (from the package feed area) will go into the filesystem image.<br />
<br /><br />
<br />
== Reference images ==<br />
The following reference images are defined in the ''meta'' layer:<br />
{| style="padding: 10px;"<br />
! style="width: 20px" | || || <br />
|-<br />
| || ''core-image-minimal'' || small image that just boots the target device<br />
|-<br />
| || ''core-image-minimal-dev'' || ''core-image-minimal'' with headers and libraries allowing development work<br />
|-<br />
| || style="padding-right: 10px" | ''core-image-minimal-initramfs'' || ''core-image-minimal'' with kernel support for in-RAM filesystem<br />
|-<br />
| || '''core-image-base''' || '''console-only system fully supporting the target hardware'''<br />
|-<br />
| || ''core-image-full-cmdline'' || console-only image that includes many system tools<br />
|-<br />
| || ''core-image-x11'' || image with basic X11 and a terminal<br />
|-<br />
|}<br />
<br />
These image definitions are provided as a starting point for creating project-specific, custom image definitions.<br />
<br /><br />
<br /><br />
<br />
== Creating a Custom Image ==<br />
* In your custom layer, create the ''images'' subdirectory in one of your ''recipes-...' directory.<br />
* In the ''images'' directory, create two image recipe files that inherit from ''core-image'':<br />
<pre class="code"><br />
SUMMARY = "My deployment image"<br />
LICENSE = "MIT"<br />
<br />
inherit core-image<br />
IMAGE_FEATURES += "splash"<br />
</pre><br />
and<br />
<pre class="code"><br />
SUMMARY = "My development image"<br />
<br />
inherit core-image<br />
require my-image.bb<br />
<br />
IMAGE_FEATURES += "ssh-server-dropbear tools-debug debug-tweaks"<br />
<br />
CORE_IMAGE_EXTRA_INSTALL += "i2c-tools "<br />
</pre><br />
where the first image recipe is for deployment and the second is for development. Note that the development version includes the deployment version with the ''require'' statement, and adds to IMAGE_FEATURES and CORE_IMAGE_EXTRA_INSTALL.<br />
<br /><br />
<br />
== Image Filesystem Packaging ==<br />
The system image generated by Bitbake can be packaged in the form of an image file, whose contents can be transferred on a boot medium (SD card or eMMC) such that the primary boot loader of the target device can discover the system and boot it.<br />
<br />
Unless you restrict the type of packaging used for the image file, Yocto will generate multiple rootfs packages, each with a large footprint. To restrict the generated image files to a desired type, edit ''conf/local.conf'' of your project build directory and set the type.<br />
<pre class="code"><br />
#IMAGE_FSTYPES = "tar.gz"<br />
#IMAGE_FSTYPES = "tar.bz2"<br />
IMAGE_FSTYPES = "wic.bz2 wic.bmap"<br />
</pre><br />
The wic ([https://pykickstart.readthedocs.io/en/latest/kickstart-docs.html kickstart]) format with accompanying [https://github.com/intel/bmap-tools bmap] is recommended.<br />
<br /><br />
<br />
== Installing the Rootfs Image ==<br />
Using [https://github.com/intel/bmap-tools bmaptool] we can copy the generated ''wic'' image (with matching bmap file) to a mounted SD card or eMMC storage.<br />
<pre class="terminal"><br />
sudo bmaptool copy tmp/deploy/images/raspberrypi4-64/<wic.bz2 file> <drive><br />
</pre><br />
where ''<wic.bz2 file>'' is the root filesystem image wic.bz2 file, and ''<drive>'' is the drive at which the storage is mounted (for example, ''/dev/sdb'').<br />
<br /><br />
<br /><br />
<br />
= Package Groups =<br />
Package groups are recipes that inherit from '''meta/classes/packagegroup.bbclass''' and set the content of the global variable '''PACKAGES'''. Package groups are defined in recipe files with the file extension 'bb'.<br />
<br /><br />
<br /><br />
Note that the ''packagegroup'' must be inherited before ''PACKAGES is defined.<br />
<pre class="code"><br />
inherit packagegroup<br />
<br />
PACKAGES = '...'<br />
</pre><br />
<br /><br />
<br />
= Useful Image Features =<br />
<br /><br />
<br />
== Distro Features ==<br />
Distro features are system features that affect multiple recipes. '''Large parts of the Poky image may need to be rebaked after making changes to the distro features!'''<br />
<br /><br />
<br />
=== systemd ===<br />
In the ''conf/local.conf'' file of your project build directory (or ''layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " systemd"<br />
</pre><br />
<br /><br />
<br />
=== NFS ===<br />
In Embedded Linux projects, NFS is often included in development images to enable faster code-deploy turnaround times.<br />
<br /><br />
In the ''conf/local.conf'' file of your Yocto build directory (or ''conf/layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " nfs"<br />
</pre><br />
<br /><br />
On your Debian-based Yocto machine, [[Ubuntu#Setting_up_an_NFS_Server|set up an SSH server]].<br />
<br /><br />
<br /><br />
In Yocto, use the directory<br />
<br /><br />
: '''{YOCTO_BUILD_DIR}/tmp/work/{TARGET}-poky-linux/{IMAGE}/1.0-r0/rootfs'''<br />
as the root directory provided by the NFS server. For example,<br />
: ''build-robofish-core/tmp/work/raspberrypi4_64-poky-linux/robofish-core-image-dev/1.0-r0/rootfs''<br />
<br /><br />
<br /><br />
<br />
=== [https://vulkan.org Vulkan] and [https://opengl.org OpenGL] ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " vulkan opengl x11 wayland"<br />
</pre><br />
<br /><br />
<br />
=== Bluetooth and NFC ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " bluetooth nfc"<br />
</pre><br />
<br /><br />
<br />
= Recipes =<br />
Recipes are Yocto metadata files that are interpreted by Bitbake and describe how a build task is performed.<br />
<br /><br />
== Patching A Device Tree ==<br />
Follow these steps to patch an existing device tree by creating an ''append recipe'' in a custom layer.<br />
<br /><br />
<br /><br />
In the custom layer, create the directory for a linux kernel append recipe.<br />
<pre class="terminal"><br />
mkdir -p ${LAYER_DIR}/recipes-kernel/linux/files<br />
</pre><br />
where it is assumed that ''${LAYER_DIR}'' contains the path to the root directory of the custom Yocto layer. <br />
<br /><br />
<br /><br />
Copy the kernel device tree file from your Yocto project build directory to the ''files'' directory of your new recipe. For a Raspberry Pi Compute Module 4, for example, type<br />
<pre class="terminal"><br />
cp ${YOCTO_BUILD_DIR}/tmp/work-shared/raspberrypi4-64/kernel-source/arch/arm/boot/dts/bcm2711-rpi-cm4.dts ${LAYER_DIR}/recipes-kernel/linux/files/<br />
</pre><br />
where it is assumed that ''${YOCTO_BUILD_DIR}'' contains the path to the Yocto project build directory.<br />
<br /><br />
<div style="background:#f8f8f0; padding-left: 1em; padding-right: 1em; border-radius:6px"><br />
If the ''tmp/work-shared'' directory does not exists anymore, you can recreate it by typing<br />
<pre class="terminal"><br />
bitbake -c menuconfig virtual/kernel<br />
</pre><br />
and exiting the kernel configuration menu without making changes.<br />
</div><br />
<br /><br />
Edit the append recipe<br />
<pre class="terminal"><br />
vim ${LAYER_DIR}/recipes-kernel/linux/linux-<platform>_%.bbappend<br />
</pre><br />
where ''platform'' is the hardware or machine designator (for example, ''raspberrypi''). The contents of the file should be as shown below<br />
<pre class="code"><br />
<br />
</pre><br />
<br />
<br /><br />
<br />
= Accessing the OpenEmbedded package collection =<br />
The OpenEmbedded project provides recipes for many useful programs that are not included with Yocto, like tmux, VLC, Gnome, various multimedia codecs, more filesystems, gRPC and much more.<br />
<br /><br />
To access the recipes for those software packages, clone the OpenEmbedded layers repository into your third-party layers directory: <br />
<pre class="terminal"><br />
git clone git://git.openembedded.org/meta-openembedded<br />
</pre><br />
<br /><br />
<br />
= devtool =<br />
<br />
Use '''devtool''' to make changes to an existing recipe and automatically generate an append recipe from those changes.<br />
<br /><br />
<br /><br />
<br />
== Initialization Manager ==<br />
After the kernel is done with its basic booting tasks, it passes control to the initialization manager. To use the ''systemd'' initialization manager (used by the Linux distributions Debian and Ubuntu) instead of ''SysVinit'', make the following entries in ''${TOPDIR}/conf/distro/distro.conf''<br />
<pre class="code"><br />
DISTRO_FEATURES_append = " systemd"<br />
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"<br />
VIRTUAL-RUNTIME_init_manager = "systemd"<br />
VIRTUAL-RUNTIME_initscripts = ""<br />
</pre><br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Yocto&diff=3143Yocto2022-12-25T10:07:39Z<p>Kai: Adds section about bitbake recipes.</p>
<hr />
<div>= Yocto and OpenEmbedded =<br />
The collection of software tools used by the Yocto project have been developed by the [https://www.openembedded.org OpenEmbedded] project. The Yocto project basically uses these generic build tools to provide a basic Linux system called ''Poky''. Stable releases of Poky serve as standard platforms for third parties that provide additional features (e.g., hardware support layers).<br />
<br /><br />
<br /><br />
<br />
= Prerequisites =<br />
* A Linux system supported by the Yocto project.<br />Assuming that [[Ubuntu]] is used. <br />
* Following package installed:<br />
<pre class=terminal><br />
sudo apt install gcc g++ \<br />
python3-distutils python-is-python3<br />
</pre><br />
<br /><br />
<br />
= Bitbake =<br />
Bitbake is the build tool from the OpenEmbedded project, which parses the project's metadata, resolves dependencies and the ordering of the build steps, runs the builds to create packages, to finally create an image from the packages.<br />
<br /><br />
=== Metadata Types ===<br />
Yocto metadata, which controls how a system image is built, can be categorized at a high level into these four types:<br />
* ''Machine''<br />the targeted hardware platform (e.g. Raspberry Pi 4)<br />
* ''Distro''<br />common characteristic of a family of related images<br />
* ''Recipes''<br />instructions on how to process the source files for a component of the image<br />
* ''Image''<br />recipes that define the contents of generated system images<br />
<br /><br />
=== Layers ===<br />
Layers are purposeful collections of metadata. Yocto layers often Layers often add the provide that for a that can be combined with other layers in order to directories in which <br />
<br /><br />
<br />
<br /> <br />
<br />
= Images =<br />
<br />
Images are recipes that ultimately inherit from '''meta/classes/image.bbclass''' and set the global variable '''IMAGE_INSTALL'''. Most images, however, will inherit from ''meta/classes/core-image.bbclass'' which inherits directly from ''image.bbclass'', provides a mapping from ''IMAGE_FEATURES'' to package groups, and adds the two package groups ''packagegroup-core-boot'' and ''packagegroup-base-extended'' to ''IMAGE_INSTALL''.<br />
<br />
Images are defined in recipe files with the file extension 'bb'. In order to separate them from package recipes, there is a convention to put image recipes into a folder named ''images''. Making use of this, we can list all images defined by all layers via<br />
<pre class="terminal"><br />
cd poky<br />
ls meta*/recipes*/images/*.bb<br />
</pre><br />
<br /><br />
<br />
=== ''IMAGE_FEATURES'' ===<br />
The ''IMAGE_FEATURES'' variable is defined in ''meta/classes/image.bbclass'' with an empty value. It accepts only a predefined set of features (e.g., ''x11'', ''debug-tweaks'', ''dev-pkgs'', ''dbg-pkgs''). This affects how recipes will execute their tasks and which packages will be selected to go into the image. The image recipe ''meta/recipes-core/images/core-image-base.bb'', for example, adds the ''splash'' feature.<br />
<br /><br />
<br />
=== ''IMAGE_INSTALL'' ===<br />
Holds a list of package groups whose packages (from the package feed area) will go into the filesystem image.<br />
<br /><br />
<br />
== Reference images ==<br />
The following reference images are defined in the ''meta'' layer:<br />
{| style="padding: 10px;"<br />
! style="width: 20px" | || || <br />
|-<br />
| || ''core-image-minimal'' || small image that just boots the target device<br />
|-<br />
| || ''core-image-minimal-dev'' || ''core-image-minimal'' with headers and libraries allowing development work<br />
|-<br />
| || style="padding-right: 10px" | ''core-image-minimal-initramfs'' || ''core-image-minimal'' with kernel support for in-RAM filesystem<br />
|-<br />
| || '''core-image-base''' || '''console-only system fully supporting the target hardware'''<br />
|-<br />
| || ''core-image-full-cmdline'' || console-only image that includes many system tools<br />
|-<br />
| || ''core-image-x11'' || image with basic X11 and a terminal<br />
|-<br />
|}<br />
<br />
These image definitions are provided as a starting point for creating project-specific, custom image definitions.<br />
<br /><br />
<br /><br />
<br />
== Creating a Custom Image ==<br />
* In your custom layer, create the ''images'' subdirectory in one of your ''recipes-...' directory.<br />
* In the ''images'' directory, create two image recipe files that inherit from ''core-image'':<br />
<pre class="code"><br />
SUMMARY = "My deployment image"<br />
LICENSE = "MIT"<br />
<br />
inherit core-image<br />
IMAGE_FEATURES += "splash"<br />
</pre><br />
and<br />
<pre class="code"><br />
SUMMARY = "My development image"<br />
<br />
inherit core-image<br />
require my-image.bb<br />
<br />
IMAGE_FEATURES += "ssh-server-dropbear tools-debug debug-tweaks"<br />
<br />
CORE_IMAGE_EXTRA_INSTALL += "i2c-tools "<br />
</pre><br />
where the first image recipe is for deployment and the second is for development. Note that the development version includes the deployment version with the ''require'' statement, and adds to IMAGE_FEATURES and CORE_IMAGE_EXTRA_INSTALL.<br />
<br /><br />
<br />
== Image Filesystem Packaging ==<br />
The system image generated by Bitbake can be packaged in the form of an image file, whose contents can be transferred on a boot medium (SD card or eMMC) such that the primary boot loader of the target device can discover the system and boot it.<br />
<br />
Unless you restrict the type of packaging used for the image file, Yocto will generate multiple rootfs packages, each with a large footprint. To restrict the generated image files to a desired type, edit ''conf/local.conf'' of your project build directory and set the type.<br />
<pre class="code"><br />
#IMAGE_FSTYPES = "tar.gz"<br />
#IMAGE_FSTYPES = "tar.bz2"<br />
IMAGE_FSTYPES = "wic.bz2 wic.bmap"<br />
</pre><br />
The wic ([https://pykickstart.readthedocs.io/en/latest/kickstart-docs.html kickstart]) format with accompanying [https://github.com/intel/bmap-tools bmap] is recommended.<br />
<br /><br />
<br />
== Installing the Rootfs Image ==<br />
Using [https://github.com/intel/bmap-tools bmaptool] we can copy the generated ''wic'' image (with matching bmap file) to a mounted SD card or eMMC storage.<br />
<pre class="terminal"><br />
sudo bmaptool copy tmp/deploy/images/raspberrypi4-64/<wic.bz2 file> <drive><br />
</pre><br />
where ''<wic.bz2 file>'' is the root filesystem image wic.bz2 file, and ''<drive>'' is the drive at which the storage is mounted (for example, ''/dev/sdb'').<br />
<br /><br />
<br /><br />
<br />
= Package Groups =<br />
Package groups are recipes that inherit from '''meta/classes/packagegroup.bbclass''' and set the content of the global variable '''PACKAGES'''. Package groups are defined in recipe files with the file extension 'bb'.<br />
<br /><br />
<br /><br />
Note that the ''packagegroup'' must be inherited before ''PACKAGES is defined.<br />
<pre class="code"><br />
inherit packagegroup<br />
<br />
PACKAGES = '...'<br />
</pre><br />
<br /><br />
<br />
= Useful Image Features =<br />
<br /><br />
<br />
== Distro Features ==<br />
Distro features are system features that affect multiple recipes. '''Large parts of the Poky image may need to be rebaked after making changes to the distro features!'''<br />
<br /><br />
<br />
=== systemd ===<br />
In the ''conf/local.conf'' file of your project build directory (or ''layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " systemd"<br />
</pre><br />
<br /><br />
<br />
=== NFS ===<br />
In Embedded Linux projects, NFS is often included in development images to enable faster code-deploy turnaround times.<br />
<br /><br />
In the ''conf/local.conf'' file of your Yocto build directory (or ''conf/layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " nfs"<br />
</pre><br />
<br /><br />
On your Debian-based Yocto machine, [[Ubuntu#Setting_up_an_NFS_Server|set up an SSH server]].<br />
<br /><br />
<br /><br />
In Yocto, use the directory<br />
<br /><br />
: '''{YOCTO_BUILD_DIR}/tmp/work/{TARGET}-poky-linux/{IMAGE}/1.0-r0/rootfs'''<br />
as the root directory provided by the NFS server. For example,<br />
: ''build-robofish-core/tmp/work/raspberrypi4_64-poky-linux/robofish-core-image-dev/1.0-r0/rootfs''<br />
<br /><br />
<br /><br />
<br />
=== [https://vulkan.org Vulkan] and [https://opengl.org OpenGL] ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " vulkan opengl x11 wayland"<br />
</pre><br />
<br /><br />
<br />
=== Bluetooth and NFC ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " bluetooth nfc"<br />
</pre><br />
<br /><br />
<br />
= Recipes =<br />
Recipes are Yocto metadata files that are interpreted by Bitbake and describe how a build task is performed.<br />
<br /><br />
== Patching a Device Tree ==<br />
In your layer, create the recipe<br />
: '''recipes-kernel/linux/linux-'''''platform'''''_%.bbappend'''<br />
where ''platform'' is the hardware or machine designator (for example, ''raspberrypi'')<br />
<br /><br />
<br /><br />
<br />
= Accessing the OpenEmbedded package collection =<br />
The OpenEmbedded project provides recipes for many useful programs that are not included with Yocto, like tmux, VLC, Gnome, various multimedia codecs, more filesystems, gRPC and much more.<br />
<br /><br />
To access the recipes for those software packages, clone the OpenEmbedded layers repository into your third-party layers directory: <br />
<pre class="terminal"><br />
git clone git://git.openembedded.org/meta-openembedded<br />
</pre><br />
<br /><br />
<br />
= devtool =<br />
<br />
Use '''devtool''' to make changes to an existing recipe and automatically generate an append recipe from those changes.<br />
<br /><br />
<br /><br />
<br />
== Initialization Manager ==<br />
After the kernel is done with its basic booting tasks, it passes control to the initialization manager. To use the ''systemd'' initialization manager (used by the Linux distributions Debian and Ubuntu) instead of ''SysVinit'', make the following entries in ''${TOPDIR}/conf/distro/distro.conf''<br />
<pre class="code"><br />
DISTRO_FEATURES_append = " systemd"<br />
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"<br />
VIRTUAL-RUNTIME_init_manager = "systemd"<br />
VIRTUAL-RUNTIME_initscripts = ""<br />
</pre><br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Yocto&diff=3142Yocto2022-12-24T22:00:22Z<p>Kai: Adds introductory section and a section on Bitbake.</p>
<hr />
<div>= Yocto and OpenEmbedded =<br />
The collection of software tools used by the Yocto project have been developed by the [https://www.openembedded.org OpenEmbedded] project. The Yocto project basically uses these generic build tools to provide a basic Linux system called ''Poky''. Stable releases of Poky serve as standard platforms for third parties that provide additional features (e.g., hardware support layers).<br />
<br /><br />
<br /><br />
<br />
= Prerequisites =<br />
* A Linux system supported by the Yocto project.<br />Assuming that [[Ubuntu]] is used. <br />
* Following package installed:<br />
<pre class=terminal><br />
sudo apt install gcc g++ \<br />
python3-distutils python-is-python3<br />
</pre><br />
<br /><br />
<br />
= Bitbake =<br />
Bitbake is the build tool from the OpenEmbedded project, which parses the project's metadata, resolves dependencies and the ordering of the build steps, runs the builds to create packages, to finally create an image from the packages.<br />
<br /><br />
=== Metadata Types ===<br />
Yocto metadata, which controls how a system image is built, can be categorized at a high level into these four types:<br />
* ''Machine''<br />the targeted hardware platform (e.g. Raspberry Pi 4)<br />
* ''Distro''<br />common characteristic of a family of related images<br />
* ''Recipes''<br />instructions on how to process the source files for a component of the image<br />
* ''Image''<br />recipes that define the contents of generated system images<br />
<br /><br />
=== Layers ===<br />
Layers are purposeful collections of metadata. Yocto layers often Layers often add the provide that for a that can be combined with other layers in order to directories in which <br />
<br /><br />
<br />
<br /> <br />
<br />
= Images =<br />
<br />
Images are recipes that ultimately inherit from '''meta/classes/image.bbclass''' and set the global variable '''IMAGE_INSTALL'''. Most images, however, will inherit from ''meta/classes/core-image.bbclass'' which inherits directly from ''image.bbclass'', provides a mapping from ''IMAGE_FEATURES'' to package groups, and adds the two package groups ''packagegroup-core-boot'' and ''packagegroup-base-extended'' to ''IMAGE_INSTALL''.<br />
<br />
Images are defined in recipe files with the file extension 'bb'. In order to separate them from package recipes, there is a convention to put image recipes into a folder named ''images''. Making use of this, we can list all images defined by all layers via<br />
<pre class="terminal"><br />
cd poky<br />
ls meta*/recipes*/images/*.bb<br />
</pre><br />
<br /><br />
<br />
=== ''IMAGE_FEATURES'' ===<br />
The ''IMAGE_FEATURES'' variable is defined in ''meta/classes/image.bbclass'' with an empty value. It accepts only a predefined set of features (e.g., ''x11'', ''debug-tweaks'', ''dev-pkgs'', ''dbg-pkgs''). This affects how recipes will execute their tasks and which packages will be selected to go into the image. The image recipe ''meta/recipes-core/images/core-image-base.bb'', for example, adds the ''splash'' feature.<br />
<br /><br />
<br />
=== ''IMAGE_INSTALL'' ===<br />
Holds a list of package groups whose packages (from the package feed area) will go into the filesystem image.<br />
<br /><br />
<br />
== Reference images ==<br />
The following reference images are defined in the ''meta'' layer:<br />
{| style="padding: 10px;"<br />
! style="width: 20px" | || || <br />
|-<br />
| || ''core-image-minimal'' || small image that just boots the target device<br />
|-<br />
| || ''core-image-minimal-dev'' || ''core-image-minimal'' with headers and libraries allowing development work<br />
|-<br />
| || style="padding-right: 10px" | ''core-image-minimal-initramfs'' || ''core-image-minimal'' with kernel support for in-RAM filesystem<br />
|-<br />
| || '''core-image-base''' || '''console-only system fully supporting the target hardware'''<br />
|-<br />
| || ''core-image-full-cmdline'' || console-only image that includes many system tools<br />
|-<br />
| || ''core-image-x11'' || image with basic X11 and a terminal<br />
|-<br />
|}<br />
<br />
These image definitions are provided as a starting point for creating project-specific, custom image definitions.<br />
<br /><br />
<br /><br />
<br />
== Creating a Custom Image ==<br />
* In your custom layer, create the ''images'' subdirectory in one of your ''recipes-...' directory.<br />
* In the ''images'' directory, create two image recipe files that inherit from ''core-image'':<br />
<pre class="code"><br />
SUMMARY = "My deployment image"<br />
LICENSE = "MIT"<br />
<br />
inherit core-image<br />
IMAGE_FEATURES += "splash"<br />
</pre><br />
and<br />
<pre class="code"><br />
SUMMARY = "My development image"<br />
<br />
inherit core-image<br />
require my-image.bb<br />
<br />
IMAGE_FEATURES += "ssh-server-dropbear tools-debug debug-tweaks"<br />
<br />
CORE_IMAGE_EXTRA_INSTALL += "i2c-tools "<br />
</pre><br />
where the first image recipe is for deployment and the second is for development. Note that the development version includes the deployment version with the ''require'' statement, and adds to IMAGE_FEATURES and CORE_IMAGE_EXTRA_INSTALL.<br />
<br /><br />
<br />
== Image Filesystem Packaging ==<br />
The system image generated by Bitbake can be packaged in the form of an image file, whose contents can be transferred on a boot medium (SD card or eMMC) such that the primary boot loader of the target device can discover the system and boot it.<br />
<br />
Unless you restrict the type of packaging used for the image file, Yocto will generate multiple rootfs packages, each with a large footprint. To restrict the generated image files to a desired type, edit ''conf/local.conf'' of your project build directory and set the type.<br />
<pre class="code"><br />
#IMAGE_FSTYPES = "tar.gz"<br />
#IMAGE_FSTYPES = "tar.bz2"<br />
IMAGE_FSTYPES = "wic.bz2 wic.bmap"<br />
</pre><br />
The wic ([https://pykickstart.readthedocs.io/en/latest/kickstart-docs.html kickstart]) format with accompanying [https://github.com/intel/bmap-tools bmap] is recommended.<br />
<br /><br />
<br />
== Installing the Rootfs Image ==<br />
Using [https://github.com/intel/bmap-tools bmaptool] we can copy the generated ''wic'' image (with matching bmap file) to a mounted SD card or eMMC storage.<br />
<pre class="terminal"><br />
sudo bmaptool copy tmp/deploy/images/raspberrypi4-64/<wic.bz2 file> <drive><br />
</pre><br />
where ''<wic.bz2 file>'' is the root filesystem image wic.bz2 file, and ''<drive>'' is the drive at which the storage is mounted (for example, ''/dev/sdb'').<br />
<br /><br />
<br /><br />
<br />
= Package Groups =<br />
Package groups are recipes that inherit from '''meta/classes/packagegroup.bbclass''' and set the content of the global variable '''PACKAGES'''. Package groups are defined in recipe files with the file extension 'bb'.<br />
<br /><br />
<br /><br />
Note that the ''packagegroup'' must be inherited before ''PACKAGES is defined.<br />
<pre class="code"><br />
inherit packagegroup<br />
<br />
PACKAGES = '...'<br />
</pre><br />
<br /><br />
<br />
= Useful Image Features =<br />
<br /><br />
<br />
== Distro Features ==<br />
Distro features are system features that affect multiple recipes. '''Large parts of the Poky image may need to be rebaked after making changes to the distro features!'''<br />
<br /><br />
<br />
=== systemd ===<br />
In the ''conf/local.conf'' file of your project build directory (or ''layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " systemd"<br />
</pre><br />
<br /><br />
<br />
=== NFS ===<br />
In Embedded Linux projects, NFS is often included in development images to enable faster code-deploy turnaround times.<br />
<br /><br />
In the ''conf/local.conf'' file of your Yocto build directory (or ''conf/layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " nfs"<br />
</pre><br />
<br /><br />
On your Debian-based Yocto machine, [[Ubuntu#Setting_up_an_NFS_Server|set up an SSH server]].<br />
<br /><br />
<br /><br />
In Yocto, use the directory<br />
<br /><br />
: '''{YOCTO_BUILD_DIR}/tmp/work/{TARGET}-poky-linux/{IMAGE}/1.0-r0/rootfs'''<br />
as the root directory provided by the NFS server. For example,<br />
: ''build-robofish-core/tmp/work/raspberrypi4_64-poky-linux/robofish-core-image-dev/1.0-r0/rootfs''<br />
<br /><br />
<br /><br />
<br />
=== [https://vulkan.org Vulkan] and [https://opengl.org OpenGL] ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " vulkan opengl x11 wayland"<br />
</pre><br />
<br /><br />
<br />
=== Bluetooth and NFC ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " bluetooth nfc"<br />
</pre><br />
<br /><br />
<br />
= Accessing the OpenEmbedded recipe collection =<br />
The OpenEmbedded project provides recipes for many useful programs that are not included with Yocto, like tmux, VLC, Gnome, various multimedia codecs, more filesystems, gRPC and much more.<br />
<br /><br />
To access the recipes for those software packages, clone the OpenEmbedded layers repository into your third-party layers directory: <br />
<pre class="terminal"><br />
git clone git://git.openembedded.org/meta-openembedded<br />
</pre><br />
<br /><br />
<br />
= devtool =<br />
<br />
Use '''devtool''' to make changes to an existing recipe and automatically generate an append recipe from those changes.<br />
<br /><br />
<br /><br />
<br />
== Initialization Manager ==<br />
After the kernel is done with its basic booting tasks, it passes control to the initialization manager. To use the ''systemd'' initialization manager (used by the Linux distributions Debian and Ubuntu) instead of ''SysVinit'', make the following entries in ''${TOPDIR}/conf/distro/distro.conf''<br />
<pre class="code"><br />
DISTRO_FEATURES_append = " systemd"<br />
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"<br />
VIRTUAL-RUNTIME_init_manager = "systemd"<br />
VIRTUAL-RUNTIME_initscripts = ""<br />
</pre><br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Raspberry_Pi&diff=3141Raspberry Pi2022-12-24T17:03:09Z<p>Kai: Adds section about raspi-gpio</p>
<hr />
<div><br /><br />
== <br />Introduction ==<br />
The [http://raspberrypi.org Raspberry Pi Ltd.] is a company producing small and affordable single-board, bare-bones computer systems, microcontrollers and accessories, marketed under the ''Raspberry Pi'' brand. All Raspberry Pi computing products use Arm-based processors. I use Raspberry Pi computers as [[Robot Task Controller | task controller]], and the microcontrollers as [[Robot State Agent | state agent]] in my robots.<br />
<br /><br />
<br /><br />
=== Processors and Architectures ===<br />
<br />
* [https://developer.arm.com/Processors/Cortex-A7 Arm Cortex-A7] with 32-bit Armv7 programming model<br />
** Raspberry Pi 2 B (Broadcom BCM2836 processor @ 900 MHz)<br />
<br /><br />
<br />
* [https://developer.arm.com/Processors/Cortex-A53 Arm Cortex-A53] with 64-bit Armv8-A programming model.<br />
** Raspberry Pi 2 B rev 1.2 (Broadcom BCM2837 processor @ 900 MHz)<br />
** Raspberry Pi 3 B (Broadcom BCM2837 processor @ 1.2 GHz)<br />
** Raspberry Pi 3 B+ (Broadcom BCM2837B0 processor @ 1.4 GHz)<br />
** Raspberry Pi Zero 2 W (@ 1 GHz)<br />
<br /><br />
<br />
* [https://developer.arm.com/Processors/Cortex-A72 Arm Cortex-A72] with 64-bit Armv8-A programming model<br />
** Raspberry Pi 4 (Broadcom BCM2711 processor @ 1.5 GHz)<br />
** Compute Module 4 (Broadcom BCM2711 @ 1.5 GHz)<br />
<br /><br />
<br />
* [https://developer.arm.com/Processors/Cortex-M0+ Arm Cortex-M0+] with Armv6-M programming model<br />
** Raspberry Pi Pico (up to 133 MHz)<br />
<br /><br />
<br />
== Installing a System Image ==<br />
[https://www.raspberrypi.com/software/operating-systems/ Raspberry Pi OS] is the offical operating system of a Raspberry Pi. The Lite version, without a graphical desktop, is recommended for embedded applications unless you decide to create a custom system image. The fewer software modules are running, the lower the power consumption, and the lower the chance that user-space processes will be interrupted.<br />
<br /><br />
<br /><br />
=== Installing the System Image on SD Card ===<br />
This is the most popular method of installing a system image on a single-board computers. SD cards are cheap and reusable, almost all Raspberry Pi models come with an SD card reader. However, SD card memory is not designed to support frequent rewrite operations and may not be as durable as other storage solutions. <br />
<br />
The preferred way of putting a system image on an SD card is to use the [https://www.raspberrypi.com/software Raspberry Pi Imager] tool that can fetch a Raspberry Pi OS image over the Internet or use a local image file, create a derived image with preconfigured user credentials, WLAN access and more, before writing it to the SD card.<br />
<br />
==== Using built-in tools on Linux ====<br />
The SD card can also be prepared by using standard Linux tools instead of Raspberry Pi Imager. First, we need to find out which device to copy the install image to. Type<br />
<pre class="terminal"><br />
df -h<br />
</pre><br />
or<br />
<pre class="terminal"><br />
sudo fdisk --list<br />
</pre><br />
in the command terminal to look up the mount point for the SD card. Let us assume the card was mounted as ''/dev/sdb2''. The card needs to be unmounted before we can copy the downloaded Raspberry Pi OS install image:<br />
<br /><br />
<pre class="terminal"><br />
umount /dev/sdb2<br />
</pre><br />
<br /><br />
Copy the image to the card with the ''dd'' command:<br />
<pre class="terminal"><br />
sudo dd bs=4M if=2021-01-11-raspios-buster-armhf-lite.img of=/dev/sdb<br />
</pre><br />
where we use the path to the device file ''/dev/sdb'' instead of the partition ''/dev/sdb2'', which was unmounted. The option ''bs'' is used for adjusting the buffer size for the writing operation.<br />
<br /><br />
<br /><br />
<br />
==== Using built-in tools on macOS ====<br />
On Apple macOS, you can use the built-in 'diskutil' tool as an alternative to the Raspberry Pi Imager. First, attach the SD card to your Mac and determine the assigned disk number ''disk#'' (e.g., disk2) under which the card has been mounted to the filesystem by opening Terminal and typing<br />
<br /><br />
<pre class="terminal"><br />
diskutil list<br />
</pre><br />
then unmount the disk<br />
<pre class="terminal"><br />
diskutil unmountDisk disk2<br />
</pre><br />
and copy the data with the ''dd'' tool<br />
<pre class="terminal"><br />
sudo dd bs=1m if=~/Downloads/raspios.img of=/dev/rdisk2<br />
</pre><br />
where I assume that the downloaded and <u>unzipped</u> Raspberry Pi OS image file is located at ''~/Downloads/raspios.img'' and the SD card was mounted as ''disk2''.<br />
<br /><br />
<br />
=== Installing the System Image on eMMC ===<br />
Some Raspberry Pi models, like the Compute Module 4, come with an embedded MultiMediaCard (eMMC) storage component. A switch or jumper on the carrier board serves to make the Raspberry Pi bootloader boot the compute module into USB mass storage mode. In this mode you can attach the compute module to an external computer via USB. On Ubuntu you can use the<br />
<pre class="terminal"><br />
lsusb<br />
</pre><br />
command to list all connected USB devices. The Compute Module 4, for example, should show up as "Broadcom Corp. BCM2711 Boot".<br />
<br /><br />
To make the operating system recognize the USB device as a mass storage device, we need to build and run Raspberry Pi's ''rpiboot'' tool.<br />
<pre class="terminal"><br />
sudo apt install libusb-1.0-0-dev<br />
git clone --depth=1 https://github.com/raspberrypi/usbboot<br />
cd usbboot<br />
make<br />
sudo ./rpiboot<br />
</pre><br />
On Ubuntu, ''lsusb'' will now list the Compute Module 4 as "Broadcom Corp. Compute Module". The compute module will also show up in the ''Disks'' app as ''RPi-MSD-0001''.<br />
<br /><br />
[[File: raspberrypi_emmc_shows_up_in_disks_app.png | x300px ]]<br />
<br /><br />
You can now use Raspberry Pi Imager or any flashing utility to flash a system image on the compute module eMMC.<br />
<br /><br />
<br /><br />
<br />
== Upgrading a Raspberry Pi OS Installation ==<br />
You don't want to erase your existing Raspberry Pi OS environment and set up all the software from start each time a new version of Raspberry Pi OS is released. Fortunately, [https://www.raspberrypi.com/documentation/computers/os.html#updating-and-upgrading-raspberry-pi-os Raspberry Pi OS can upgrade itself to the latest release] with the following commands.<br />
<pre class="terminal"><br />
sudo apt-get update<br />
sudo apt-get dist-upgrade<br />
</pre><br />
<br /><br />
<br /><br />
<br />
== Assigning a Static Ethernet IP Address ==<br />
Edit the file '''/etc/network/interfaces''' and make sure that the entries for the interface ''eth0'' are as follows:<br />
<pre class="terminal"><br />
auto eth0<br />
iface eth0 inet static<br />
address 192.168.0.20<br />
netmask 255.255.255.0<br />
broadcast 192.168.0.255<br />
</pre><br />
where the IP address ''192.168.0.20'' is just an example.<br />
<br /><br />
<br /><br />
Make sure you don't break the WiFi connectivity because of editing ''/etc/network/interfaces''. If there is no empty describing ''wlan0'' we will need to create one. For dynamically assigned IPs via DHCP you will need these lines:<br />
<pre class="terminal"><br />
auto wlan0<br />
iface wlan0 inet dhcp<br />
wpa-ssid <your WiFi router name (SSID)><br />
wpa-psk <your WiFi password><br />
</pre><br />
<br /><br />
The new network setting becomes effective on the next system boot or when you type<br />
<pre class="terminal"><br />
sudo ifdown eth0<br />
sudo ifup eth0<br />
</pre><br />
<br /><br />
<br /><br />
== Setting Up SSH ==<br />
* As a security measure, SSH is not enabled by default on headless (= Raspbian Lite, without GUI) installations. Place a file named "ssh" into the root folder of the boot partition (= ''/boot'') to enable SSH.<br />
* In the web browser go to the configuration page of your home Internet router (e.g., http://192.168.1.1).<br />
* Open the page that lists all currently connected LAN devices.<br />
* Connect the Raspberry Pi via Ethernet cable to the LAN router.<br />
* Look for a new entry in the list of LAN devices. That should be your Raspberry Pi. Note the IP address. Let's assume it is ''192.168.1.10''.<br />
* Optional: You should be able to read the [https://en.wikipedia.org/wiki/MAC_address MAC address] of the Raspberry Pi from the table. For future reference, write down the MAC address somewhere.<br />
* Open Terminal and type '''ssh pi@192.168.1.10''' to log in via SSH. On a fresh Raspbian installation the username is '''pi''' and the password is '''raspberry'''.<br />
* After logging in type '''sudo raspi-config''' to start the Raspbian configuration tool, where you can change the password or expand the filesystem to take up the whole SD card, among other things.<br />
<br /><br />
<br /><br />
== Setting Up WiFi ==<br />
=== Raspberry Pi 2 ===<br />
The Raspberry Pi 2 does not have built-in WiFi. I assume that you are using a USB WiFi adapter. Before connecting the adapter you need to edit the network interfaces on the Raspberry Pi. Log in to the Raspberry Pi over SSH and edit '''/etc/network/interfaces''' as follows:<br />
<br /><br />
<pre class="code"><br />
auto lo<br />
<br />
iface lo inet loopback<br />
iface eth0 inet dhcp<br />
<br />
allow-hotplug wlan0<br />
auto wlan0<br />
<br />
iface wlan0 inet dhcp<br />
wpa-ssid "ssid"<br />
wpa-psk “password"<br />
</pre><br />
<br /><br />
where ''ssid'' is the SSID (a.k.a. name) of your WLAN router, and ''password'' is supplied in encoded form. Do not type the quotation marks. The password is encoded by running<br />
<br /><br />
<pre class="terminal"><br />
wpa_passphrase <ssid> <password><br />
</pre><br />
<br /><br />
If your WLAN router uses a hidden SSID use this configuration:<br />
<pre class="code"><br />
auto lo<br />
<br />
iface lo inet loopback<br />
iface eth0 inet dhcp<br />
<br />
auto wlan0<br />
allow-hotplug wlan0<br />
iface wlan0 inet dhcp<br />
wpa-scan-ssid 1<br />
wpa-ap-scan 1<br />
wpa-key-mgmt WPA-PSK<br />
wpa-proto RSN WPA<br />
wpa-pairwise CCMP TKIP<br />
wpa-group CCMP TKIP<br />
wpa-ssid "My Secret SSID"<br />
wpa-psk "My SSID PSK”<br />
<br />
iface default inet dhcp<br />
</pre><br />
<br /><br />
Instead of putting the WPA configuration directly into '''interfaces''' you can put it into the file '''/etc/wpa_supplicant/wpa_supplicant.conf'''<br />
<pre class="code"><br />
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev<br />
update_config=1<br />
<br />
network={<br />
ssid="<your ssid>"<br />
psk=<your encoded password given by running wpa_passphrase><br />
scan_ssid=1<br />
proto=WPA RSN<br />
key_mgmt=WPA-PSK<br />
pairwise=CCMP TKIP<br />
}<br />
</pre><br />
<br /><br />
and refer to it from '''interfaces''' like so<br />
<pre class="code"><br />
auto lo<br />
iface lo inet loopback<br />
<br />
iface eth0 inet dhcp<br />
<br />
allow-hotplug wlan0<br />
iface wlan0 inet dhcp<br />
wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf<br />
<br />
iface default inet dhcp<br />
</pre><br />
<br /><br />
<br /><br />
<br />
=== Raspberry Pi 3 or newer ===<br />
The Raspberry Pi 3 has a WLAN transmitter built in and it is turned on by default. You should see the device '''wlan0''' along with '''eth0''' and '''lo''' when typing<br />
<br /><br />
<pre class="terminal"><br />
ifconfig -a<br />
</pre><br />
<br /><br />
Make sure the Raspberry Pi can log in to your WLAN router. If a MAC filter is active, add the Raspberry Pi WiFi MAC address to the list of allowed devices. The MAC address of the Pi is displayed in the output of ''ifconfig -a'' as '''HWaddr'''. Open a text editor to add the network configuration details, such as your login credentials, to the file ''/etc/wpa_supplicant/wpa_supplicant.conf''.<br />
<br /><br />
<pre class="code"><br />
network={<br />
ssid="MySSID"<br />
psk=MyCodedPassword<br />
scan_ssid=1<br />
proto=WPA RSN<br />
key_mgmt=WPA-PSK<br />
pairwise=CCMP TKIP<br />
}<br />
</pre><br />
<br /><br />
where '''MySSID''' is the SSID (a.k.a. name) of the router, and '''MyCodedPassword''' is the encoded password obtained via<br />
<br /><br />
<pre class="terminal"><br />
wpa_passphrase MySSID MyPassword<br />
</pre><br />
and where '''MyPassword''' is the actual password.<br />
<br /><br />
<br /><br />
<br />
=== Power Saving ===<br />
If the WiFi connection is unstable you can turn off the WiFi power management feature, which may cause connection dropouts, by issuing the command<br />
<pre class="terminal"><br />
sudo iw dev wlan0 set power_save off<br />
</pre><br />
or by manually editing '''/etc/network/interfaces''', where you add the line<br />
<pre class="code"><br />
wireless-power off<br />
</pre><br />
right after the line<br />
<pre class="code"><br />
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf<br />
</pre><br />
within the '''wlan0''' block. You can check whether power management is currently turned on or off, among other parameters, with the command<br />
<pre class="terminal"><br />
iwconfig<br />
</pre><br />
<br /><br />
<br /><br />
For Raspberry Pi 2 and WiFi dongles with 8192CU or 8188CUS chip (for example, Edimax EW-7811un dongles)you can prevent connections from being dropped by creating the file '''/etc/modprobe.d/8192cu.conf'''<br />
<br><br />
<pre class="terminal"><br />
sudo nano /etc/modprobe.d/8192cu.conf<br />
</pre><br />
and adding the line<br />
<br /><br />
<pre class="code"><br />
options 8192cu rtw_power_mgnt=0 rtw_enusbss=0<br />
</pre><br />
<br /><br />
<br />
== Camera ==<br />
There is a [https://www.raspberrypi.org/products/camera-module/ camera module] for Raspberry Pi, which I use in my robots. In fact, the camera module is part of the [[Core Module]].<br />
<br /><br />
<br /><br />
Refer to the official [https://www.raspberrypi.org/documentation/usage/camera/README.md camera setup instructions]. Be careful with the camera module, handle the camera board and the connector strip delicately.<br />
<br /><br />
<br /><br />
To be able to access the camera through the Python programming environment you need to install the '''python-picamera''' package<br />
<br /><br />
<br /><br />
The Raspberry Pi project does not provide a C/C++ library for accessing the camera. Instead it provides utility applications ''raspistill'' and ''raspivid'' which record still images and videos, respectively. A number of third-party C++ libraries have been created based on the open source code of these utility applications. The [http://www.uco.es/investiga/grupos/ava/node/40 RaspiCam] C++ library developed at the University of Cordoba is one such library (source code available [https://sourceforge.net/projects/raspicam/ from SourceForge]).<br />
<br /><br />
<br /><br />
=== Video Streaming ===<br />
To stream video from the Raspberry Pi camera to the network, open a terminal on the RPi and type<br />
<pre class="terminal"><br />
raspivid -t 0 -w 1280 -h 720 -hf -ih -fps 30 -o - | nc -k -l 8100<br />
</pre><br />
<br /><br />
To view the stream on a client computer with [http://www.mplayerhq.hu Mplayer] installed, open a terminal there and type<br />
<pre class="terminal"><br />
mplayer -fps 300 -demuxer h264es ffmpeg://tcp://192.168.0.20:8100<br />
</pre><br />
<br /><br />
<br /><br />
Alternatively, you can use [[GStreamer]] to transport the video frames. Make sure that the command line interface to GStreamer, ''gst-launch-1.0'', is installed. <br />
<pre class="terminal"><br />
sudo apt install gstreamer1.0-tools<br />
</pre><br />
<br /><br />
For streaming from the RPi you can type<br />
<pre class="terminal"><br />
raspivid -t 0 -w 640 -h 480 -fps 30 -hf -b 2000000 -o - | gst-launch-1.0 -q fdsrc ! h264parse ! rtph264pay config-interval=1 pt=96 ! gdppay ! tcpserversink host=0.0.0.0 port=8100<br />
</pre><br />
<br /><br />
For viewing on the client, you can type<br />
<pre class="terminal"><br />
gst-launch-1.0 -v tcpclientsrc host=192.168.0.20 port=8100 ! gdpdepay ! rtph264depay ! avdec_h264 ! videoconvert ! videoflip method=vertical-flip ! autovideosink sync=false<br />
</pre><br />
where ''192.168.0.20'' is assumed to be the IP address of the server (Raspberry Pi).<br />
<br /><br />
<br /><br />
* On the Raspberry Pi side you can elevate the priority of the process by beginning the command with ''"nice -20"''.<br />
* For verbose output from ''gst-launch-1.0'', use the option ''-v'' instead of ''-q''.<br />
* Note that we used the [https://gstreamer.freedesktop.org/documentation/videofilter/videoflip.html?gi-language=c#GstVideoFlipMethod videoflip] filter to correct the rotation of the decoded image.<br />
<br /><br />
=== Disabling the LED ===<br />
To disable the red indicator light of the camera, add the following line to '''/boot/config.txt''' and reboot:<br />
<pre class="code"><br />
disable_camera_led=1<br />
</pre><br />
<br /><br />
<br />
== pinout ==<br />
A cool command-line tool provided by Raspberry Pi, and also available when running Ubuntu instead of Raspberry Pi OS, is '''pinout'''. It displays a layout of the Raspberry Pi board using ASCII art, a list of significant hardware features of the board, and the GPIO pin layout in tabular form.<br />
<br /><br />
<pre class="terminal"><br />
sudo apt install python3-gpiozero<br />
pinout<br />
</pre><br />
<br /><br />
[[File:Raspberry_Pi_pinout_command.png | x600px]]<br />
<br /><br />
<br /><br />
<br />
== raspi-gpio ==<br />
The documentation states that ''"raspi-gpio can get and print the state of a GPIO (or all GPIOs) and can be used to set the function, pulls and value of a GPIO. raspi-gpio must be run as root."''<br />
"<br />
<pre class="terminal"><br />
> sudo apt install raspi-gpio<br />
> raspi-gpio funcs 20,21,22<br />
GPIO, DEFAULT PULL, ALT0, ALT1, ALT2, ALT3, ALT4, ALT5<br />
20, DOWN, PCM_DIN, SD12, DPI_D16, SPI6_MOSI, SPI1_MOSI, GPCLK0<br />
21, DOWN, PCM_DOUT, SD13, DPI_D17, SPI6_SCLK, SPI1_SCLK, GPCLK1<br />
22, DOWN, SD0_CLK, SD14, DPI_D18, SD1_CLK, ARM_TRST, SDA6<br />
> raspi-gpio get 20<br />
GPIO 20: level=0 func=INPUT pull=DOWN<br />
GPIO 21: level=1 func=INPUT pull=DOWN<br />
GPIO 22: level=0 func=INPUT pull=DOWN<br />
> raspi-gpio raw 21<br />
00: 00000000 00012000 12000000 3fffffff<br />
10: 24000040 00000924 00000000 6770696f<br />
20: 6770696f 6770696f 6770696f 6770696f<br />
30: 6770696f 102081ff 00003bfb 00000000<br />
40: 00000000 00000000 00000000 00000000<br />
50: 00000000 00000000 00000000 00000000<br />
60: 00000000 00000000 00000000 00000000<br />
70: 00000000 00000000 00000000 00000000<br />
80: 00000000 00000000 00000000 00000000<br />
90: 00000000 00000000 00000000 00000000<br />
e0: 4aa95555 19aaaaaa 50aa5544<br />
f0: 000aaaaa<br />
</pre><br />
<br /><br />
<br />
== GPIO Programming in C ==<br />
Raspberry Pi 2, 3 & 4 come with 40 ''General Purpose Input Output'' (GPIO) pins ([https://www.raspberrypi.com/documentation/computers/os.html#gpio-and-the-40-pin-header layout]) that can be used to interface with the other electronic components of your project.<br />
<br />
=== Using libgpiod ===<br />
The standard C++ programming interface for GPIO on Linux is ''libgpiod'', as described on [[Nvidia_Jetson#Using_Libgpiod | the Jetson page]].<br />
<br />
=== Using WiringPi ===<br />
Using the [http://wiringpi.coml WiringPi] library is a more popular method for programming the GPIO pins on a Raspberry Pi with C/C++. WiringPi is [http://wiringpi.com/download-and-install installed from source] like this<br />
<pre class="terminal"><br />
sudo apt-get install git-core<br />
git clone git://git.drogon.net/wiringPi<br />
cd wiringPi<br />
./build<br />
</pre><br />
Read the ''INSTALL'' file for what to do with the created shared library. Basically you need to copy ''wiringPi/libwiringPi.so.x.xx'' to ''/usr/local/lib'' and add the line<br />
<pre class="code"><br />
include /usr/local/lib<br />
</pre><br />
to the file ''/etc/ld.so.conf'' so that the library loader also looks in ''/usr/local/lib'' for dynamically loadable libraries. It is also possible to create a static library.<br />
<br /><br />
<br/><br />
After installation, create a test program called ''blink.cpp''<br />
<pre class="code"><br />
#include <stdio.h><br />
#include <iostream><br />
#include <wiringPi.h><br />
<br />
static int LED_PORT = 7; // The physical pin number. Corresponds to BCM GPIO pin 4.<br />
<br />
void blink()<br />
{<br />
digitalWrite(4, HIGH);<br />
delay(1000);<br />
digitalWrite(4, LOW);<br />
delay(1000);<br />
};<br />
<br />
int main(int numargs, char** args)<br />
{<br />
wiringPiSetup();<br />
pinMode(LED_PORT, OUTPUT);<br />
for (int n = 0; n < 10; n++)<br />
{<br />
blink();<br />
}<br />
std::cout << "finished blinking" << std::endl;<br />
return 0;<br />
}<br />
</pre><br />
and build like this<br />
<pre class="terminal"><br />
g++ blink.cpp -o blink -lstdc++ -lwiringPi -IwiringPi<br />
</pre><br />
where I assumed that the wiringPi root folder is located in the same folder as the ''blink.cpp'' source file.<br />
<br /><br />
<br/><br />
Which pins can be used for what purpose is explained on the [http://wiringpi.com/pins wiringPi pins] page.<br />
<br /><br />
<br/><br />
<br />
== PWM ==<br />
There are some Python libraries that communicate with the GPIO daemon to provide hardware PWM on selected pins. [https://gpiozero.readthedocs.org/ GPIO Zero] ([https://www.raspberrypi.org/blog/gpio-zero-a-friendly-python-api-for-physical-computing/ tutorial]) is one such library and is included in [https://www.raspberrypi.org/downloads/raspbian/ Raspbian]. With GPIO Zero you can implement dimming LEDs or control a brushed DC motor behind an [https://en.wikipedia.org/wiki/H_bridge H-Bridge] circuit.<br />
<br />
<br /><br />
== Running A Program On Startup ==<br />
We want the Raspberry Pi to start the robot control program as soon as it's done with booting. In order to make sure that the system has completely initialized itself we will not use ''/etc/rc.local'' for starting our program. Instead, we will create a ''cron'' task with the ''crontab'' command<br />
<br /><br />
<pre class="terminal"><br />
sudo crontab -e<br />
</pre><br />
which opens the editor of choice (most likely ''nano'') where you can enter the program launch command. In our case this will be<br />
<pre class="code"><br />
@reboot python /home/pi/Core.py<br />
</pre><br />
where the leading ''@reboot'' indicates to ''cron'' that this command shall be executed only once, right after the booting process has completed. Notice that it is not necessary to start the command with ''sudo'', which is necessary when running program from the command line.<br />
<br />
<br /><br />
<br />
== Communicating With Other Devices ==<br />
There are three popular communication protocols that the Raspberry Pi supports and that are often used in embedded systems: I<sup>2</sup>C, SPI, and UART.<br />
<br /><br />
<br /><br />
<br />
=== I<sup>2</sup>C ===<br />
Set the [[I2C | I<sup>2</sup>C]] clock speed by editing '''/boot/config.txt'''<br />
<pre class="code"><br />
dtparam=i2c1=on<br />
dtparam=i2c_arm_baudrate=xxx<br />
</pre><br />
where ''xxx'' is the desired frequency. Keep in mind that ATmega microcontrollers used on Arduino boards support only up to 400 kHz while Raspberry Pi can support higher speeds.<br />
<br /><br />
<br /><br />
==== Wiring To I<sup>2</sup>C Devices With 5 V Logic Level ====<br />
Normally you can not connect a GPIO pin to a device with 5 V logic (most of the Arduino models, for example). The GPIO data pins of the Raspberry Pi use 3.3 V as the HIGH voltage level and can be damaged when 5 V is applied. However, because I<sup>2</sup>C pins have [https://en.wikipedia.org/wiki/Open_collector open-collector] outputs they can be wired directly to I<sup>2</sup>C pins of devices with incompatible voltage levels. As long as the pull-up line voltage, which corresponds to the lowest of the device HIGH voltage levels, exceeds the minimum voltage for which HIGH is defined on each device, the devices will be able to sense the correct data bit.<br />
<br /><br />
<br /><br />
Links:<br />
* [https://learn.sparkfun.com/tutorials/i2c Tutorial by SparkFun] on I<sup>2</sup>C<br />
* [https://learn.adafruit.com/adafruits-raspberry-pi-lesson-4-gpio-setup?view=all Article by Adafruit] on how to set up I<sup>2</sup>C and SPI on a Raspberry Pi<br />
* Tutorial for setting up an I2C bus [http://blog.oscarliang.net/raspberry-pi-arduino-connected-i2c/ between a Raspberry Pi and an Arduino].<br />
<br /><br />
<br />
=== SPI ===<br />
First of all, you need to use the ''raspi-config'' command-line configuration utility to enable the SPI pins.<br />
<pre class="terminal"><br />
sudo raspi-config<br />
</pre><br />
<br /><br />
You can use [http://wiringpi.com/reference/spi-library/ WiringPi SPI] to add SPI capability to your C/C++ program.<br />
<br /><br />
<br /><br />
<br />
=== UART ===<br />
[http://www.andremiller.net/content/raspberry-pi-and-arduino-via-gpio-uart Here is a tutorial] that shows how to communicate with an Arduino using the UART interface.<br />
<br /><br />
<br /><br />
<br />
=== CAN ===<br />
There are various [[CAN]] adapter boards available for Raspberry Pi. For example [http://skpang.co.uk/catalog/pican2-canbus-board-for-raspberry-pi-2-p-1475.html PiCAN2].<br />
<br /><br />
<br /><br />
<br />
=== Device Tree Overlays ===<br />
A device tree overlay is a mechanism in Raspberry Pi computers to dynamically apply changes to existing device trees. This mechanism is mostly used to enable kernel-space support for hardware components that are attached to the Raspberry Pi via its GPIO headers.<br />
<br /><br />
<br /><br />
Operations with device tree overlays are performed by the Raspberry Pi GPU (VideoCore), without needing to preempt the Linux kernel. The Raspberry Pi primary bootloader, also a VideoCore firmware application, makes use of this device tree parsing and editing capability to apply device tree overlays during the boot process, before passing control to the Linux kernel.<br />
<br /><br />
==== /boot/config.txt ====<br />
The primary bootloader parses and interprets the ''/boot/config.txt'' file. It specifies, among other things, which device tree to select and which overlays to apply.<br />
<br /><br />
==== dtoverlay ====<br />
'''dtoverlay''' is the command-line tool for loading a device tree overlay (or unloading a previously loaded overlay) while the Linux system is running.<br />
<pre class="terminal"><br />
</pre><br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Raspberry_Pi&diff=3140Raspberry Pi2022-12-24T16:38:27Z<p>Kai: Replaces the outdated 'Development Tools' section with information about device tree overlays.</p>
<hr />
<div><br /><br />
== <br />Introduction ==<br />
The [http://raspberrypi.org Raspberry Pi Ltd.] is a company producing small and affordable single-board, bare-bones computer systems, microcontrollers and accessories, marketed under the ''Raspberry Pi'' brand. All Raspberry Pi computing products use Arm-based processors. I use Raspberry Pi computers as [[Robot Task Controller | task controller]], and the microcontrollers as [[Robot State Agent | state agent]] in my robots.<br />
<br /><br />
<br /><br />
=== Processors and Architectures ===<br />
<br />
* [https://developer.arm.com/Processors/Cortex-A7 Arm Cortex-A7] with 32-bit Armv7 programming model<br />
** Raspberry Pi 2 B (Broadcom BCM2836 processor @ 900 MHz)<br />
<br /><br />
<br />
* [https://developer.arm.com/Processors/Cortex-A53 Arm Cortex-A53] with 64-bit Armv8-A programming model.<br />
** Raspberry Pi 2 B rev 1.2 (Broadcom BCM2837 processor @ 900 MHz)<br />
** Raspberry Pi 3 B (Broadcom BCM2837 processor @ 1.2 GHz)<br />
** Raspberry Pi 3 B+ (Broadcom BCM2837B0 processor @ 1.4 GHz)<br />
** Raspberry Pi Zero 2 W (@ 1 GHz)<br />
<br /><br />
<br />
* [https://developer.arm.com/Processors/Cortex-A72 Arm Cortex-A72] with 64-bit Armv8-A programming model<br />
** Raspberry Pi 4 (Broadcom BCM2711 processor @ 1.5 GHz)<br />
** Compute Module 4 (Broadcom BCM2711 @ 1.5 GHz)<br />
<br /><br />
<br />
* [https://developer.arm.com/Processors/Cortex-M0+ Arm Cortex-M0+] with Armv6-M programming model<br />
** Raspberry Pi Pico (up to 133 MHz)<br />
<br /><br />
<br />
== Installing a System Image ==<br />
[https://www.raspberrypi.com/software/operating-systems/ Raspberry Pi OS] is the offical operating system of a Raspberry Pi. The Lite version, without a graphical desktop, is recommended for embedded applications unless you decide to create a custom system image. The fewer software modules are running, the lower the power consumption, and the lower the chance that user-space processes will be interrupted.<br />
<br /><br />
<br /><br />
=== Installing the System Image on SD Card ===<br />
This is the most popular method of installing a system image on a single-board computers. SD cards are cheap and reusable, almost all Raspberry Pi models come with an SD card reader. However, SD card memory is not designed to support frequent rewrite operations and may not be as durable as other storage solutions. <br />
<br />
The preferred way of putting a system image on an SD card is to use the [https://www.raspberrypi.com/software Raspberry Pi Imager] tool that can fetch a Raspberry Pi OS image over the Internet or use a local image file, create a derived image with preconfigured user credentials, WLAN access and more, before writing it to the SD card.<br />
<br />
==== Using built-in tools on Linux ====<br />
The SD card can also be prepared by using standard Linux tools instead of Raspberry Pi Imager. First, we need to find out which device to copy the install image to. Type<br />
<pre class="terminal"><br />
df -h<br />
</pre><br />
or<br />
<pre class="terminal"><br />
sudo fdisk --list<br />
</pre><br />
in the command terminal to look up the mount point for the SD card. Let us assume the card was mounted as ''/dev/sdb2''. The card needs to be unmounted before we can copy the downloaded Raspberry Pi OS install image:<br />
<br /><br />
<pre class="terminal"><br />
umount /dev/sdb2<br />
</pre><br />
<br /><br />
Copy the image to the card with the ''dd'' command:<br />
<pre class="terminal"><br />
sudo dd bs=4M if=2021-01-11-raspios-buster-armhf-lite.img of=/dev/sdb<br />
</pre><br />
where we use the path to the device file ''/dev/sdb'' instead of the partition ''/dev/sdb2'', which was unmounted. The option ''bs'' is used for adjusting the buffer size for the writing operation.<br />
<br /><br />
<br /><br />
<br />
==== Using built-in tools on macOS ====<br />
On Apple macOS, you can use the built-in 'diskutil' tool as an alternative to the Raspberry Pi Imager. First, attach the SD card to your Mac and determine the assigned disk number ''disk#'' (e.g., disk2) under which the card has been mounted to the filesystem by opening Terminal and typing<br />
<br /><br />
<pre class="terminal"><br />
diskutil list<br />
</pre><br />
then unmount the disk<br />
<pre class="terminal"><br />
diskutil unmountDisk disk2<br />
</pre><br />
and copy the data with the ''dd'' tool<br />
<pre class="terminal"><br />
sudo dd bs=1m if=~/Downloads/raspios.img of=/dev/rdisk2<br />
</pre><br />
where I assume that the downloaded and <u>unzipped</u> Raspberry Pi OS image file is located at ''~/Downloads/raspios.img'' and the SD card was mounted as ''disk2''.<br />
<br /><br />
<br />
=== Installing the System Image on eMMC ===<br />
Some Raspberry Pi models, like the Compute Module 4, come with an embedded MultiMediaCard (eMMC) storage component. A switch or jumper on the carrier board serves to make the Raspberry Pi bootloader boot the compute module into USB mass storage mode. In this mode you can attach the compute module to an external computer via USB. On Ubuntu you can use the<br />
<pre class="terminal"><br />
lsusb<br />
</pre><br />
command to list all connected USB devices. The Compute Module 4, for example, should show up as "Broadcom Corp. BCM2711 Boot".<br />
<br /><br />
To make the operating system recognize the USB device as a mass storage device, we need to build and run Raspberry Pi's ''rpiboot'' tool.<br />
<pre class="terminal"><br />
sudo apt install libusb-1.0-0-dev<br />
git clone --depth=1 https://github.com/raspberrypi/usbboot<br />
cd usbboot<br />
make<br />
sudo ./rpiboot<br />
</pre><br />
On Ubuntu, ''lsusb'' will now list the Compute Module 4 as "Broadcom Corp. Compute Module". The compute module will also show up in the ''Disks'' app as ''RPi-MSD-0001''.<br />
<br /><br />
[[File: raspberrypi_emmc_shows_up_in_disks_app.png | x300px ]]<br />
<br /><br />
You can now use Raspberry Pi Imager or any flashing utility to flash a system image on the compute module eMMC.<br />
<br /><br />
<br /><br />
<br />
== Upgrading a Raspberry Pi OS Installation ==<br />
You don't want to erase your existing Raspberry Pi OS environment and set up all the software from start each time a new version of Raspberry Pi OS is released. Fortunately, [https://www.raspberrypi.com/documentation/computers/os.html#updating-and-upgrading-raspberry-pi-os Raspberry Pi OS can upgrade itself to the latest release] with the following commands.<br />
<pre class="terminal"><br />
sudo apt-get update<br />
sudo apt-get dist-upgrade<br />
</pre><br />
<br /><br />
<br /><br />
<br />
== Assigning a Static Ethernet IP Address ==<br />
Edit the file '''/etc/network/interfaces''' and make sure that the entries for the interface ''eth0'' are as follows:<br />
<pre class="terminal"><br />
auto eth0<br />
iface eth0 inet static<br />
address 192.168.0.20<br />
netmask 255.255.255.0<br />
broadcast 192.168.0.255<br />
</pre><br />
where the IP address ''192.168.0.20'' is just an example.<br />
<br /><br />
<br /><br />
Make sure you don't break the WiFi connectivity because of editing ''/etc/network/interfaces''. If there is no empty describing ''wlan0'' we will need to create one. For dynamically assigned IPs via DHCP you will need these lines:<br />
<pre class="terminal"><br />
auto wlan0<br />
iface wlan0 inet dhcp<br />
wpa-ssid <your WiFi router name (SSID)><br />
wpa-psk <your WiFi password><br />
</pre><br />
<br /><br />
The new network setting becomes effective on the next system boot or when you type<br />
<pre class="terminal"><br />
sudo ifdown eth0<br />
sudo ifup eth0<br />
</pre><br />
<br /><br />
<br /><br />
== Setting Up SSH ==<br />
* As a security measure, SSH is not enabled by default on headless (= Raspbian Lite, without GUI) installations. Place a file named "ssh" into the root folder of the boot partition (= ''/boot'') to enable SSH.<br />
* In the web browser go to the configuration page of your home Internet router (e.g., http://192.168.1.1).<br />
* Open the page that lists all currently connected LAN devices.<br />
* Connect the Raspberry Pi via Ethernet cable to the LAN router.<br />
* Look for a new entry in the list of LAN devices. That should be your Raspberry Pi. Note the IP address. Let's assume it is ''192.168.1.10''.<br />
* Optional: You should be able to read the [https://en.wikipedia.org/wiki/MAC_address MAC address] of the Raspberry Pi from the table. For future reference, write down the MAC address somewhere.<br />
* Open Terminal and type '''ssh pi@192.168.1.10''' to log in via SSH. On a fresh Raspbian installation the username is '''pi''' and the password is '''raspberry'''.<br />
* After logging in type '''sudo raspi-config''' to start the Raspbian configuration tool, where you can change the password or expand the filesystem to take up the whole SD card, among other things.<br />
<br /><br />
<br /><br />
== Setting Up WiFi ==<br />
=== Raspberry Pi 2 ===<br />
The Raspberry Pi 2 does not have built-in WiFi. I assume that you are using a USB WiFi adapter. Before connecting the adapter you need to edit the network interfaces on the Raspberry Pi. Log in to the Raspberry Pi over SSH and edit '''/etc/network/interfaces''' as follows:<br />
<br /><br />
<pre class="code"><br />
auto lo<br />
<br />
iface lo inet loopback<br />
iface eth0 inet dhcp<br />
<br />
allow-hotplug wlan0<br />
auto wlan0<br />
<br />
iface wlan0 inet dhcp<br />
wpa-ssid "ssid"<br />
wpa-psk “password"<br />
</pre><br />
<br /><br />
where ''ssid'' is the SSID (a.k.a. name) of your WLAN router, and ''password'' is supplied in encoded form. Do not type the quotation marks. The password is encoded by running<br />
<br /><br />
<pre class="terminal"><br />
wpa_passphrase <ssid> <password><br />
</pre><br />
<br /><br />
If your WLAN router uses a hidden SSID use this configuration:<br />
<pre class="code"><br />
auto lo<br />
<br />
iface lo inet loopback<br />
iface eth0 inet dhcp<br />
<br />
auto wlan0<br />
allow-hotplug wlan0<br />
iface wlan0 inet dhcp<br />
wpa-scan-ssid 1<br />
wpa-ap-scan 1<br />
wpa-key-mgmt WPA-PSK<br />
wpa-proto RSN WPA<br />
wpa-pairwise CCMP TKIP<br />
wpa-group CCMP TKIP<br />
wpa-ssid "My Secret SSID"<br />
wpa-psk "My SSID PSK”<br />
<br />
iface default inet dhcp<br />
</pre><br />
<br /><br />
Instead of putting the WPA configuration directly into '''interfaces''' you can put it into the file '''/etc/wpa_supplicant/wpa_supplicant.conf'''<br />
<pre class="code"><br />
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev<br />
update_config=1<br />
<br />
network={<br />
ssid="<your ssid>"<br />
psk=<your encoded password given by running wpa_passphrase><br />
scan_ssid=1<br />
proto=WPA RSN<br />
key_mgmt=WPA-PSK<br />
pairwise=CCMP TKIP<br />
}<br />
</pre><br />
<br /><br />
and refer to it from '''interfaces''' like so<br />
<pre class="code"><br />
auto lo<br />
iface lo inet loopback<br />
<br />
iface eth0 inet dhcp<br />
<br />
allow-hotplug wlan0<br />
iface wlan0 inet dhcp<br />
wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf<br />
<br />
iface default inet dhcp<br />
</pre><br />
<br /><br />
<br /><br />
<br />
=== Raspberry Pi 3 or newer ===<br />
The Raspberry Pi 3 has a WLAN transmitter built in and it is turned on by default. You should see the device '''wlan0''' along with '''eth0''' and '''lo''' when typing<br />
<br /><br />
<pre class="terminal"><br />
ifconfig -a<br />
</pre><br />
<br /><br />
Make sure the Raspberry Pi can log in to your WLAN router. If a MAC filter is active, add the Raspberry Pi WiFi MAC address to the list of allowed devices. The MAC address of the Pi is displayed in the output of ''ifconfig -a'' as '''HWaddr'''. Open a text editor to add the network configuration details, such as your login credentials, to the file ''/etc/wpa_supplicant/wpa_supplicant.conf''.<br />
<br /><br />
<pre class="code"><br />
network={<br />
ssid="MySSID"<br />
psk=MyCodedPassword<br />
scan_ssid=1<br />
proto=WPA RSN<br />
key_mgmt=WPA-PSK<br />
pairwise=CCMP TKIP<br />
}<br />
</pre><br />
<br /><br />
where '''MySSID''' is the SSID (a.k.a. name) of the router, and '''MyCodedPassword''' is the encoded password obtained via<br />
<br /><br />
<pre class="terminal"><br />
wpa_passphrase MySSID MyPassword<br />
</pre><br />
and where '''MyPassword''' is the actual password.<br />
<br /><br />
<br /><br />
<br />
=== Power Saving ===<br />
If the WiFi connection is unstable you can turn off the WiFi power management feature, which may cause connection dropouts, by issuing the command<br />
<pre class="terminal"><br />
sudo iw dev wlan0 set power_save off<br />
</pre><br />
or by manually editing '''/etc/network/interfaces''', where you add the line<br />
<pre class="code"><br />
wireless-power off<br />
</pre><br />
right after the line<br />
<pre class="code"><br />
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf<br />
</pre><br />
within the '''wlan0''' block. You can check whether power management is currently turned on or off, among other parameters, with the command<br />
<pre class="terminal"><br />
iwconfig<br />
</pre><br />
<br /><br />
<br /><br />
For Raspberry Pi 2 and WiFi dongles with 8192CU or 8188CUS chip (for example, Edimax EW-7811un dongles)you can prevent connections from being dropped by creating the file '''/etc/modprobe.d/8192cu.conf'''<br />
<br><br />
<pre class="terminal"><br />
sudo nano /etc/modprobe.d/8192cu.conf<br />
</pre><br />
and adding the line<br />
<br /><br />
<pre class="code"><br />
options 8192cu rtw_power_mgnt=0 rtw_enusbss=0<br />
</pre><br />
<br /><br />
<br />
== Camera ==<br />
There is a [https://www.raspberrypi.org/products/camera-module/ camera module] for Raspberry Pi, which I use in my robots. In fact, the camera module is part of the [[Core Module]].<br />
<br /><br />
<br /><br />
Refer to the official [https://www.raspberrypi.org/documentation/usage/camera/README.md camera setup instructions]. Be careful with the camera module, handle the camera board and the connector strip delicately.<br />
<br /><br />
<br /><br />
To be able to access the camera through the Python programming environment you need to install the '''python-picamera''' package<br />
<br /><br />
<br /><br />
The Raspberry Pi project does not provide a C/C++ library for accessing the camera. Instead it provides utility applications ''raspistill'' and ''raspivid'' which record still images and videos, respectively. A number of third-party C++ libraries have been created based on the open source code of these utility applications. The [http://www.uco.es/investiga/grupos/ava/node/40 RaspiCam] C++ library developed at the University of Cordoba is one such library (source code available [https://sourceforge.net/projects/raspicam/ from SourceForge]).<br />
<br /><br />
<br /><br />
=== Video Streaming ===<br />
To stream video from the Raspberry Pi camera to the network, open a terminal on the RPi and type<br />
<pre class="terminal"><br />
raspivid -t 0 -w 1280 -h 720 -hf -ih -fps 30 -o - | nc -k -l 8100<br />
</pre><br />
<br /><br />
To view the stream on a client computer with [http://www.mplayerhq.hu Mplayer] installed, open a terminal there and type<br />
<pre class="terminal"><br />
mplayer -fps 300 -demuxer h264es ffmpeg://tcp://192.168.0.20:8100<br />
</pre><br />
<br /><br />
<br /><br />
Alternatively, you can use [[GStreamer]] to transport the video frames. Make sure that the command line interface to GStreamer, ''gst-launch-1.0'', is installed. <br />
<pre class="terminal"><br />
sudo apt install gstreamer1.0-tools<br />
</pre><br />
<br /><br />
For streaming from the RPi you can type<br />
<pre class="terminal"><br />
raspivid -t 0 -w 640 -h 480 -fps 30 -hf -b 2000000 -o - | gst-launch-1.0 -q fdsrc ! h264parse ! rtph264pay config-interval=1 pt=96 ! gdppay ! tcpserversink host=0.0.0.0 port=8100<br />
</pre><br />
<br /><br />
For viewing on the client, you can type<br />
<pre class="terminal"><br />
gst-launch-1.0 -v tcpclientsrc host=192.168.0.20 port=8100 ! gdpdepay ! rtph264depay ! avdec_h264 ! videoconvert ! videoflip method=vertical-flip ! autovideosink sync=false<br />
</pre><br />
where ''192.168.0.20'' is assumed to be the IP address of the server (Raspberry Pi).<br />
<br /><br />
<br /><br />
* On the Raspberry Pi side you can elevate the priority of the process by beginning the command with ''"nice -20"''.<br />
* For verbose output from ''gst-launch-1.0'', use the option ''-v'' instead of ''-q''.<br />
* Note that we used the [https://gstreamer.freedesktop.org/documentation/videofilter/videoflip.html?gi-language=c#GstVideoFlipMethod videoflip] filter to correct the rotation of the decoded image.<br />
<br /><br />
=== Disabling the LED ===<br />
To disable the red indicator light of the camera, add the following line to '''/boot/config.txt''' and reboot:<br />
<pre class="code"><br />
disable_camera_led=1<br />
</pre><br />
<br /><br />
<br />
== pinout ==<br />
A cool command-line tool provided by Raspberry Pi, and also available when running Ubuntu instead of Raspberry Pi OS, is '''pinout'''. It displays a layout of the Raspberry Pi board using ASCII art, a list of significant hardware features of the board, and the GPIO pin layout in tabular form.<br />
<br /><br />
<pre class="terminal"><br />
sudo apt install python3-gpiozero<br />
pinout<br />
</pre><br />
<br /><br />
[[File:Raspberry_Pi_pinout_command.png | x600px]]<br />
<br /><br />
<br />
== GPIO Programming in C ==<br />
Raspberry Pi 2, 3 & 4 come with 40 ''General Purpose Input Output'' (GPIO) pins ([https://www.raspberrypi.com/documentation/computers/os.html#gpio-and-the-40-pin-header layout]) that can be used to interface with the other electronic components of your project.<br />
<br />
=== Using libgpiod ===<br />
The standard C++ programming interface for GPIO on Linux is ''libgpiod'', as described on [[Nvidia_Jetson#Using_Libgpiod | the Jetson page]].<br />
<br />
=== Using WiringPi ===<br />
Using the [http://wiringpi.coml WiringPi] library is a more popular method for programming the GPIO pins on a Raspberry Pi with C/C++. WiringPi is [http://wiringpi.com/download-and-install installed from source] like this<br />
<pre class="terminal"><br />
sudo apt-get install git-core<br />
git clone git://git.drogon.net/wiringPi<br />
cd wiringPi<br />
./build<br />
</pre><br />
Read the ''INSTALL'' file for what to do with the created shared library. Basically you need to copy ''wiringPi/libwiringPi.so.x.xx'' to ''/usr/local/lib'' and add the line<br />
<pre class="code"><br />
include /usr/local/lib<br />
</pre><br />
to the file ''/etc/ld.so.conf'' so that the library loader also looks in ''/usr/local/lib'' for dynamically loadable libraries. It is also possible to create a static library.<br />
<br /><br />
<br/><br />
After installation, create a test program called ''blink.cpp''<br />
<pre class="code"><br />
#include <stdio.h><br />
#include <iostream><br />
#include <wiringPi.h><br />
<br />
static int LED_PORT = 7; // The physical pin number. Corresponds to BCM GPIO pin 4.<br />
<br />
void blink()<br />
{<br />
digitalWrite(4, HIGH);<br />
delay(1000);<br />
digitalWrite(4, LOW);<br />
delay(1000);<br />
};<br />
<br />
int main(int numargs, char** args)<br />
{<br />
wiringPiSetup();<br />
pinMode(LED_PORT, OUTPUT);<br />
for (int n = 0; n < 10; n++)<br />
{<br />
blink();<br />
}<br />
std::cout << "finished blinking" << std::endl;<br />
return 0;<br />
}<br />
</pre><br />
and build like this<br />
<pre class="terminal"><br />
g++ blink.cpp -o blink -lstdc++ -lwiringPi -IwiringPi<br />
</pre><br />
where I assumed that the wiringPi root folder is located in the same folder as the ''blink.cpp'' source file.<br />
<br /><br />
<br/><br />
Which pins can be used for what purpose is explained on the [http://wiringpi.com/pins wiringPi pins] page.<br />
<br /><br />
<br/><br />
<br />
== PWM ==<br />
There are some Python libraries that communicate with the GPIO daemon to provide hardware PWM on selected pins. [https://gpiozero.readthedocs.org/ GPIO Zero] ([https://www.raspberrypi.org/blog/gpio-zero-a-friendly-python-api-for-physical-computing/ tutorial]) is one such library and is included in [https://www.raspberrypi.org/downloads/raspbian/ Raspbian]. With GPIO Zero you can implement dimming LEDs or control a brushed DC motor behind an [https://en.wikipedia.org/wiki/H_bridge H-Bridge] circuit.<br />
<br />
<br /><br />
== Running A Program On Startup ==<br />
We want the Raspberry Pi to start the robot control program as soon as it's done with booting. In order to make sure that the system has completely initialized itself we will not use ''/etc/rc.local'' for starting our program. Instead, we will create a ''cron'' task with the ''crontab'' command<br />
<br /><br />
<pre class="terminal"><br />
sudo crontab -e<br />
</pre><br />
which opens the editor of choice (most likely ''nano'') where you can enter the program launch command. In our case this will be<br />
<pre class="code"><br />
@reboot python /home/pi/Core.py<br />
</pre><br />
where the leading ''@reboot'' indicates to ''cron'' that this command shall be executed only once, right after the booting process has completed. Notice that it is not necessary to start the command with ''sudo'', which is necessary when running program from the command line.<br />
<br />
<br /><br />
<br />
== Communicating With Other Devices ==<br />
There are three popular communication protocols that the Raspberry Pi supports and that are often used in embedded systems: I<sup>2</sup>C, SPI, and UART.<br />
<br /><br />
<br /><br />
<br />
=== I<sup>2</sup>C ===<br />
Set the [[I2C | I<sup>2</sup>C]] clock speed by editing '''/boot/config.txt'''<br />
<pre class="code"><br />
dtparam=i2c1=on<br />
dtparam=i2c_arm_baudrate=xxx<br />
</pre><br />
where ''xxx'' is the desired frequency. Keep in mind that ATmega microcontrollers used on Arduino boards support only up to 400 kHz while Raspberry Pi can support higher speeds.<br />
<br /><br />
<br /><br />
==== Wiring To I<sup>2</sup>C Devices With 5 V Logic Level ====<br />
Normally you can not connect a GPIO pin to a device with 5 V logic (most of the Arduino models, for example). The GPIO data pins of the Raspberry Pi use 3.3 V as the HIGH voltage level and can be damaged when 5 V is applied. However, because I<sup>2</sup>C pins have [https://en.wikipedia.org/wiki/Open_collector open-collector] outputs they can be wired directly to I<sup>2</sup>C pins of devices with incompatible voltage levels. As long as the pull-up line voltage, which corresponds to the lowest of the device HIGH voltage levels, exceeds the minimum voltage for which HIGH is defined on each device, the devices will be able to sense the correct data bit.<br />
<br /><br />
<br /><br />
Links:<br />
* [https://learn.sparkfun.com/tutorials/i2c Tutorial by SparkFun] on I<sup>2</sup>C<br />
* [https://learn.adafruit.com/adafruits-raspberry-pi-lesson-4-gpio-setup?view=all Article by Adafruit] on how to set up I<sup>2</sup>C and SPI on a Raspberry Pi<br />
* Tutorial for setting up an I2C bus [http://blog.oscarliang.net/raspberry-pi-arduino-connected-i2c/ between a Raspberry Pi and an Arduino].<br />
<br /><br />
<br />
=== SPI ===<br />
First of all, you need to use the ''raspi-config'' command-line configuration utility to enable the SPI pins.<br />
<pre class="terminal"><br />
sudo raspi-config<br />
</pre><br />
<br /><br />
You can use [http://wiringpi.com/reference/spi-library/ WiringPi SPI] to add SPI capability to your C/C++ program.<br />
<br /><br />
<br /><br />
<br />
=== UART ===<br />
[http://www.andremiller.net/content/raspberry-pi-and-arduino-via-gpio-uart Here is a tutorial] that shows how to communicate with an Arduino using the UART interface.<br />
<br /><br />
<br /><br />
<br />
=== CAN ===<br />
There are various [[CAN]] adapter boards available for Raspberry Pi. For example [http://skpang.co.uk/catalog/pican2-canbus-board-for-raspberry-pi-2-p-1475.html PiCAN2].<br />
<br /><br />
<br /><br />
<br />
=== Device Tree Overlays ===<br />
A device tree overlay is a mechanism in Raspberry Pi computers to dynamically apply changes to existing device trees. This mechanism is mostly used to enable kernel-space support for hardware components that are attached to the Raspberry Pi via its GPIO headers.<br />
<br /><br />
<br /><br />
Operations with device tree overlays are performed by the Raspberry Pi GPU (VideoCore), without needing to preempt the Linux kernel. The Raspberry Pi primary bootloader, also a VideoCore firmware application, makes use of this device tree parsing and editing capability to apply device tree overlays during the boot process, before passing control to the Linux kernel.<br />
<br /><br />
==== /boot/config.txt ====<br />
The primary bootloader parses and interprets the ''/boot/config.txt'' file. It specifies, among other things, which device tree to select and which overlays to apply.<br />
<br /><br />
==== dtoverlay ====<br />
'''dtoverlay''' is the command-line tool for loading a device tree overlay (or unloading a previously loaded overlay) while the Linux system is running.<br />
<pre class="terminal"><br />
</pre><br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Linux&diff=3139Linux2022-12-24T14:13:03Z<p>Kai: /* Device Tree Overlays */</p>
<hr />
<div>= Boot Procedure =<br />
# The primary bootloader, which is usually a fixed part of the hardware recognizes bootable media.<br />
#* On PC compatible systems, [https://en.wikipedia.org/wiki/UEFI UEFI] or BIOS are the primary bootloaders.<br />
#* On BIOS systems, the Master Boot Record (MBR) area of a connected storage device is searched for a boot executable. The MBR is a special area, separate from the actual data storage area. BIOS is an old system, dating back to the early 1980s, but not yet obsolete.<br />
#* On a UEFI system, which supports storage media with much larger capacity, the ''GPT'' partition table is used to determine if the storage device provides an ''EFI System Partition'' containing the folder ''/efi'' with a subfolder that contains the secondary boot loader. ''/efi/microsoft'' or ''/efi/grub'', for example. After a Linux system is booted by UEFI hardware, you can open a terminal and inspect the partition table by typing <span class="terminal">sudo gdisk /dev/sda</span>.<br />
# If a secondary bootloader is found on the bootable media, it is loaded.<br />
#* On PC compatibles the secondary bootloader is usually [https://www.gnu.org/software/grub GRUB2].<br />
#* On [[Arm Cortex-A]] based systems, this is often [https://u-boot.readthedocs.io/en/latest/ U-Boot].<br />
#* Some systems have proprietary bootloaders. Raspberry Pi, for example.<br />
#* To support the bootloader, a standard interface called LBA (linear block access) exists for storage media. This interface is not optimized for the capabilities of the storage device but is sufficient for the bootloader to search for a bootable operating system, which will later load the appropriate driver for the storage media.<br />
# The secondary bootloader loads the [https://www.kernel.org Linux kernel].<br />
#* In the case of GRUB2, the boot media is searched for the boot partition using LBA mode, stage 2 is loaded from a separate data area of the boot media, the module for working with the boot partitions filesystem is loaded, the GRUB config file (''/boot/grub/grub.cfg'') is loaded from the boot partition, the user is optionally shown a GRUB menu, the kernel is loaded with the user parameters.<br />
# The kernel optionally loads an initial root file system into memory (often [https://en.wikipedia.org/wiki/Initial_ramdisk initramfs]), which includes the device drivers specific for the target hardware. For example, display drivers for showing graphical output during the boot sequence.<br />
#* Technically, all hardware-specific device drivers can be compiled into the kernel itself. In order to keep the kernel generic, however, and to avoid mixing components with incompatible distribution licenses (the GPL 2.0 license used by Linux prevents distributing a kernel with built-in proprietary drivers), certain drivers are placed into initramfs, from where they are loaded when needed.<br />
#* After the hardware is initialized, the kernel switches from initramfs to the real filesystem.<br />
# The kernel starts the first process, the '''init''' process. The ''init'' process starts all the system processes (a.k.a. ''services'') configured to run when the system launches.<br />
#* ''init'' used to be a shell script located in the filesystem at ''/sbin/init''. Nowadays, many Linux distributions use the '''[https://wiki.debian.org/systemd systemd]''' initialization method, where a binary executable is called instead of a shell script.<br />
<br /><br />
<br />
= Device Trees =<br />
Device trees are files that contain a static, hierarchical description of the hardware components of a Linux system with Arm processor architecture. Device trees are usually read by the bootloader. The specification of the device tree file format can be found at [https://devicetree.org devicetree.org].<br />
<br /><br />
<br /><br />
In a Linux kernel source repository, device tree source files are located in the ''linux/arch/arm/boot/dts'' directory. Device tree source files are also usually provided by manufacturers of hardware components that are connected via GPIO.<br />
<br /><br />
Device tree definitions are written in text form into ''.dts'' or ''.dtsi'' files, compiled into binary ''.dtb'' files, and placed into the ''/boot'' directory of the Linux system.<br />
<br /><br />
<br /><br />
== DTS Syntax ==<br />
<pre class="code"><br />
/dts-v1/;<br />
#include "bcm2711.dtsi"<br />
#include "bcm2711-rpi.dtsi"<br />
/ {<br />
compatible = "raspberrypi,4-model-b", "brcm,bcm2711";<br />
model = "Raspberry Pi 4 Model B";<br />
<br />
chosen {<br />
/* 8250 auxiliary UART instead of pl011 */<br />
stdout-path = "serial1:115200n8";<br />
};<br />
<br />
leds {<br />
led-act {<br />
gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;<br />
};<br />
<br />
led-pwr {<br />
label = "PWR";<br />
gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;<br />
default-state = "keep";<br />
linux,default-trigger = "default-on";<br />
};<br />
};<br />
<br />
...<br />
</pre><br />
<br /><br />
== Device Tree Compiler ==<br />
<pre class="terminal"><br />
sudo apt install device-tree-compiler<br />
dtc -I dts -O dtb -o my_system.dtb my_system.dts<br />
</pre><br />
<br /><br />
<br /><br />
<br />
== Device Tree Overlays ==<br />
Overlays are partial device tree definitions that modify an existing device tree file. The sources files have the extension ''.dts'', just like ordinary device tree source files. Compiled overlays have the '''.dtbo''' file extension and are placed in the '''/boot/overlays''' directory.<br />
<br /><br />
<br /><br />
Overlays are compiled by adding the ''-@'' flag, which generates symbols for referenced items (that the compiler would otherwise not be able to resolve). <br />
<pre class="terminal"><br />
dtc -@ -I dts -O dtb -o camera_overlay.dtbo camera_overlay.dts<br />
</pre><br />
<br /><br />
<br />
= Systemd =<br />
== Systemd Unit Files ==<br />
Unit files determine what kind of task is being started. The types of tasks are<br />
* '''service''' for running daemons<br />
* '''mount''' for mounting storage media, etc<br />
* '''automount''' for mounting directories when needed<br />
* '''timer''' for starting jobs at specific times<br />
* '''target''' (a group of unit files, or a state that the machine should be in after booting)<br />
* '''path''' (monitoring filesystem events)<br />
<br />
The original unit files that are installed by the package manager are placed in ''/usr/lib/systemd/system'' and should not be modified.<br />
If modifications to unit files are to be made, the modified unit files should be placed into ''/etc/systemd/system''.<br />
<br /><br />
<br />
=== Unit Relationships (Dependencies) ===<br />
There are various relationships between two units:<br />
* '''requires''': The dependent unit must be loaded in order to load the current unit.<br />
* '''wants''': The dependent unit is not critical<br />
* '''requisite''': the dependent unit must be loaded and already active.<br />
* '''conflicts''': the unit must not be loaded for the current to be loaded<br />
* '''before''': the current unit must be activated before the given units<br />
* '''after''': the current unit must be activated after the given units<br />
<br /><br />
The dependency graph can be displayed on the terminal via<br />
<pre class="terminal"><br />
sudo systemctl list-dependencies<br />
</pre><br />
<br /><br />
<br />
== Systemd Services ==<br />
Here is an example of using ''systemctl'' to query the status of the SSH server.<br />
<pre class="terminal"><br />
systemctl status sshd<br />
</pre><br />
<br /><br />
To start or stop the server, you would type<br />
<pre class="terminal"><br />
sudo systemctl start sshd<br />
sudo systemctl stop sshd<br />
</pre><br />
<br /><br />
To configure a service, edit its configuration file located in '''/etc/systemd/system'''.<br />
<br /><br />
<br /><br />
<br />
== Systemd Targets ==<br />
Targets are groups of unit files. If a target includes the statement <span class="code">AllowIsolate = yes</span> the target becomes an initialization endpoint at which systemd stops executing other units. Isolate targets are therefore similar to System V runlevels that were used for initialization before systemd.<br />
<br /><br />
<br /><br />
For a custom target (or service), the relationship to the unit files that are ''WantedBy'' or ''RequiredBy'' the target (or service) will be established by systemd through symbolic links to the wanted or required unit files. These symbolic links are placed in ''/etc/systemd/system'', within a subdirectory whose name starts with the name of the unit file and ends with the name of the type of relationship.<br />
<br /><br />
<br /><br />
== Systemd Analysis ==<br />
Systemd can plot a chart that shows how the units are launched over time.<br />
<pre class="terminal"><br />
systemd-analyze plot > analysis.html<br />
</pre><br />
generates an HTML page with a chart like this<br />
<br /><br />
<br /><br />
[[File:systemd-analysis.png | x300px ]]<br />
<br /><br />
<br /><br />
<br />
= Which Linux distro and version am I running? =<br />
<pre class="terminal"><br />
cat /etc/os-release<br />
</pre><br />
<br /><br />
<br />
= Dynamic Shared Objects (DSO) =<br />
Ulrich Drepper's [https://www.akkadia.org/drepper/dsohowto.pdf How To Write Shared Libraries] is a good resource for learning more about the ELF format, about optimizing your shared objects, and how to control the visibility of program symbols in the generated binaries.<br />
<br /><br />
<br /><br />
<br />
= Tracing system calls with ''strace'' =<br />
<br />
'''strace''' is a command that lets you trace the system calls made by the command that is passed as the argument. For example,<br />
<pre class="terminal"><br />
strace echo "hello"<br />
</pre><br />
prints<br />
<pre class="terminal"><br />
execve("/usr/bin/echo", ["echo", "hello"], 0x7ffefa8f4928 /* 42 vars */) = 0<br />
brk(NULL) = 0x561cf6532000<br />
arch_prctl(0x3001 /* ARCH_??? */, 0x7fff61293910) = -1 EINVAL (Invalid argument)<br />
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf85c44000<br />
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)<br />
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=53267, ...}, AT_EMPTY_PATH) = 0<br />
mmap(NULL, 53267, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7faf85c36000<br />
close(3) = 0<br />
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3<br />
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\237\2\0\0\0\0\0"..., 832) = 832<br />
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784<br />
pread64(3, "\4\0\0\0 \0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0"..., 48, 848) = 48<br />
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0i8\235HZ\227\223\333\350s\360\352,\223\340."..., 68, 896) = 68<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=2216304, ...}, AT_EMPTY_PATH) = 0<br />
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784<br />
mmap(NULL, 2260560, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7faf85a0e000<br />
mmap(0x7faf85a36000, 1658880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x28000) = 0x7faf85a36000<br />
mmap(0x7faf85bcb000, 360448, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x7faf85bcb000<br />
mmap(0x7faf85c23000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x214000) = 0x7faf85c23000<br />
mmap(0x7faf85c29000, 52816, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7faf85c29000<br />
close(3) = 0<br />
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf85a0b000<br />
arch_prctl(ARCH_SET_FS, 0x7faf85a0b740) = 0<br />
set_tid_address(0x7faf85a0ba10) = 1874<br />
set_robust_list(0x7faf85a0ba20, 24) = 0<br />
rseq(0x7faf85a0c0e0, 0x20, 0, 0x53053053) = 0<br />
mprotect(0x7faf85c23000, 16384, PROT_READ) = 0<br />
mprotect(0x561cf5067000, 4096, PROT_READ) = 0<br />
mprotect(0x7faf85c7e000, 8192, PROT_READ) = 0<br />
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0<br />
munmap(0x7faf85c36000, 53267) = 0<br />
getrandom("\x01\x62\x8d\xf4\xec\xea\xd8\x4e", 8, GRND_NONBLOCK) = 8<br />
brk(NULL) = 0x561cf6532000<br />
brk(0x561cf6553000) = 0x561cf6553000<br />
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=6070224, ...}, AT_EMPTY_PATH) = 0<br />
mmap(NULL, 6070224, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7faf85441000<br />
close(3) = 0<br />
newfstatat(1, "", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}, AT_EMPTY_PATH) = 0<br />
write(1, "hello\n", 6) = 6<br />
close(1) = 0<br />
close(2) = 0<br />
exit_group(0) = ?<br />
+++ exited with 0 +++<br />
</pre><br />
lists system calls made by ''echo'' as they are made.<br />
<br /><br />
<br /><br />
Instead of printing system calls as they are made, ''strace'' can print a short summary of which system calls were how many times and the time spent.<br />
<pre class="terminal"><br />
strace -c echo "hello"<br />
</pre><br />
prints<br />
<pre class="terminal"><br />
hello<br />
% time seconds usecs/call calls errors syscall<br />
------ ----------- ----------- --------- --------- ----------------<br />
0,00 0,000000 0 1 read<br />
0,00 0,000000 0 1 write<br />
0,00 0,000000 0 5 close<br />
0,00 0,000000 0 9 mmap<br />
0,00 0,000000 0 3 mprotect<br />
0,00 0,000000 0 1 munmap<br />
0,00 0,000000 0 3 brk<br />
0,00 0,000000 0 4 pread64<br />
0,00 0,000000 0 1 1 access<br />
0,00 0,000000 0 1 execve<br />
0,00 0,000000 0 2 1 arch_prctl<br />
0,00 0,000000 0 1 set_tid_address<br />
0,00 0,000000 0 3 openat<br />
0,00 0,000000 0 4 newfstatat<br />
0,00 0,000000 0 1 set_robust_list<br />
0,00 0,000000 0 1 prlimit64<br />
0,00 0,000000 0 1 getrandom<br />
0,00 0,000000 0 1 rseq<br />
------ ----------- ----------- --------- --------- ----------------<br />
100,00 0,000000 0 43 2 total<br />
</pre><br />
<br /><br />
<br /><br />
<br />
Similarly, '''ltrace''' will list the calls to library functions made by the command that was passed as the argument to ''ltrace''.<br />
<pre class="terminal"><br />
sudo apt install ltrace<br />
</pre><br />
<br /><br />
<br />
== Signals ==<br />
Signals are software interrupts that the the kernel can send an executable. The executable may react to the signal or choose to ignore it. The two signals SIGKILL and SIGTERM, however, can not be ignored by executable and must be handled.<br />
<br /><br />
An overview of the signals can be found in the man pages entry about signals<br />
<pre class="terminal"><br />
man 7 signal<br />
</pre><br />
<br /><br />
Some command-line tools do useful stuff when certain signals are sent to them. For example, the ''dd'' tool prints the progress of the copying task when the SIGUSR1 signal is sent to it via the ''kill'' command.<br />
<pre class="terminal"><br />
dd if=${HOME}/image.iso of=/dev/sdb &<br />
kill -s USR1 $(pidof dd)<br />
</pre><br />
<br /><br />
<br />
= Interprocess Communication Mechanisms =<br />
<br />
== Shared Memory ==<br />
Linux offers creating System V shared memory segments, which can be used for interprocess communication.<br />
<pre class="code"><br />
#include <sys/types.h><br />
#include <sys/ipc.h><br />
#include <sys/shm.h><br />
<br />
// creating an IPC key<br />
key_t segmentKey = ftok(”path_to_some_existing_file", 'R')<br />
if (segmentKey == -1) {<br />
perror("could not create IPC key");<br />
exit(1);<br />
}<br />
// accessing the shared memory segment, creating it if it doesn't exist<br />
int sharedMemoryID = shmget(segmentKey, SHM_SIZE, 0644 | IPC_CREAT)<br />
if (sharedMemoryID == -1) {<br />
perror("could not access (or create) the shared memory segment");<br />
exit(1);<br />
}<br />
// attaching a pointer<br />
void* memoryPtr = shmat(sharedMemoryID, NULL, 0);<br />
if (*((char*)memoryPtr) == -1) {<br />
perror("could not attach a pointer to the shared memory segment");<br />
exit(1);<br />
}<br />
</pre><br />
To learn more about shared memory segments, type<br />
<pre class="terminal"><br />
man ftok<br />
man shmget<br />
man shmat<br />
</pre><br />
<br /><br />
<br />
== Memory Mapped Files ==<br />
Linux offers mapping files to memory regions, which enables working on the file contents much more efficiently, as if it is a memory region. For example, pointers can be used in a C/C++ program to edit the contents. The memory mapped region can be shared between processes. This allows the processes to operate on large files, for example in a writer-subscriber architecture, while preserving memory. Unlike the shared memory method described above, the contents of the shared memory region are written to a file and thus persist between sessions and even system reboots.<br />
<pre class="code"><br />
#include <stdlib.h> <br />
#include <stdio.h> <br />
#include <unistd.h><br />
#include <errno.h> <br />
#include <string.h> <br />
#include <fcntl.h> <br />
#include <sys/types.h> <br />
#include <sys/stat.h> <br />
#include <sys/mman.h> <br />
<br />
static const int MAX_INPUT_LENGTH = 50;<br />
<br />
int main(int argc, char** argv)<br />
{<br />
int fd = open(argv[1], O_RDWR | O_CREAT); <br />
char* shared_mem = mmap(NULL, MAX_INPUT_LENGTH, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); <br />
close(fd); <br />
<br />
if (!strcmp(argv[2], "read")) { <br />
// continously listens to text messages from the 'write' process and writes to the terminal<br />
while (1) { <br />
shared_mem[MAX_INPUT_LENGTH-1] = '\0'; <br />
printf("%s", shared_mem); <br />
sleep(1); <br />
} <br />
} <br />
else if (!strcmp(argv[2], "write")) {<br />
// continuously sends the input from the terminal to the 'read' process<br />
while (1) {<br />
fgets(shared_mem, MAX_INPUT_LENGTH, stdin);<br />
}<br />
}<br />
else {<br />
printf("Unsupported command\n"); <br />
}<br />
}<br />
</pre><br />
<br />
To learn more about memory mapped files, refer to the man page<br />
<pre class="terminal"><br />
man mmap<br />
</pre><br />
<br /><br />
<br />
== Pipes ==<br />
Pipes are another IPC mechanism where one process can send messages to another.<br />
<pre class="code"><br />
#include <stdio.h><br />
#include <stdlib.h> <br />
#include <errno.h> <br />
#include <sys/types.h> <br />
#include <unistd.h> <br />
<br />
int main(void)<br />
{ <br />
int pipeDescriptor[2]; <br />
<br />
pipe(pipeDescriptor); // writing to pipeDescriptor[0], reading from pipeDescriptor[1]<br />
<br />
if (!fork())<br />
{ <br />
printf(" CHILD: writing to pipe and exiting\n"); <br />
write(pipeDescriptor[1], "test", 5); <br />
}<br />
else<br />
{ <br />
char buffer[5]; <br />
printf("PARENT: reading from pipe\n"); <br />
read(pipeDescriptor[0], buffer, 5); <br />
printf("PARENT: read \"%s\"\n", buf); <br />
wait(NULL); <br />
} <br />
return 0; <br />
}<br />
</pre><br />
<br /><br />
To learn more about pipes, refer to the man page<br />
<pre class="terminal"><br />
man pipe<br />
</pre><br />
<br /><br />
<br />
= D-Bus and dmesg =<br />
<br /><br />
<br />
= GUI-less Mode =<br />
<br />
== Switching to GUI-less (Multi-User) Mode with Systemd ==<br />
On a Linux system that uses systemd, we can control whether the graphical user interface is loaded and shown by specifying a suitable systemd target. To turn off the graphical desktop immediately, enter<br />
<pre class="terminal"><br />
sudo systemctl isolate multi-user.target<br />
</pre><br />
To prevent the GUI from being loaded during the system startup, type<br />
<pre class="terminal"><br />
sudo systemctl set-default multi-user.target<br />
</pre><br />
To return to the graphical desktop, type<br />
<br/><br />
<pre class="terminal"><br />
sudo systemctl isolate graphical.target<br />
</pre><br />
and to make the graphical desktop the default again, type<br />
<pre class="terminal"><br />
sudo systemctl set-default graphical.target<br />
</pre><br />
<br /><br />
<br />
== Setting the Screen Resolution for GUI-less Mode ==<br />
* Restart the machine to the Grub boot menu.<br />
* Press 'c' to get into the Grub command console.<br />
* Run the command 'vbeinfo' to list possible resolutions.<br />
* Note down the desired resolution. For example, ''1024x768x32'', where ''32'' is the color mode.<br />
* Type ''exit'' to return to the Grub boot menu and boot into Ubuntu.<br />
* Open '''/etc/default/grub''' in an editor to add the line<br />
<pre class="code"><br />
GRUB_GFXPAYLOAD_LINUX=1024x768x32<br />
</pre><br />
* Optionally, add the line<br />
<pre class="code"><br />
GRUB_GFXMODE=1024x768<br />
</pre><br />
to set the screen resolution for the GRUB boot menu itself.<br />
* Finally, run the Grub updater<br />
<pre class="terminal"><br />
sudo update-grub<br />
</pre><br />
<br /><br />
<br />
= Message of the Day (MOTD) =<br />
For users that open simultaneous terminal sessions to different Linux machines, it is helpful to see a distinct ''message of the day'' (''MOTD'') on each terminal. The MOTD can be customized by editing the shell scripts located in '''/etc/update-motd.d/'''. The shell scripts are executed in alphabetical order, their output is the MOTD. The names of the script files start with a number between 1 and 99, which makes ordering of the scripts immediately visible. Script files can be deleted or their execution bit flipped via ''chmod'' in order to disable the corresponding output. New script files can be added, and their file names chosen according to the desired position of their output.<br />
<br /><br />
<br /><br />
Additionally, it is possible to create the '''/etc/motd''' file with static content, whose output will be appended to the dynamically generated MOTD. With ''/etc/motd'', the MOTD can be embellished with ASCII art, like the Robo.Fish logo below<br />
<br /><br />
<br /><br />
<pre class="code"><br />
.';cldxxkkkxxdolc;,..<br />
.;oOXWWMMMMMMMMMMMMMMWWXKOxo:,.<br />
'o0WMMMMMMMMMMMMMMMMMMMMMMMMMMMWX0xl:'.<br />
.;xXMMMMMMMMMMMMMMMMMMMMMMMMMWWWNNXXKKK0kd:.<br />
.:ONMMMMMMMMMMMMMMMMMMWXKOxdoc:;;,'..........<br />
. 'o0WMMMMMMMMMMMMMMWN0xl:,..<br />
Xx:. .:kXWMMMMMMMMMMMMMN0d:'.<br />
MMWKxc'. .'cxXWMMMMMMMMMMMMNOo:,.<br />
MMMMMMN0xc,. .,cd0NWMMMMMMMMMMMMN0o,.<br />
MMMMMMWWNX0d:;ckKNWMMMMMMMMMMWN0xl,.<br />
lllcc:;,'.. ..,;:clloollc:,..<br />
</pre><br />
<br /><br />
The MOTD can be previewed without needing to start a new shell session:<br />
<pre class="terminal"><br />
sudo run-parts /etc/update-motd.d/<br />
</pre><br />
<br /><br />
<br />
= SSH Logins Without Typing The Password =<br />
If you connect to a remote computer via ''ssh'' or copy files via ''scp'' frequently, you should consider using ''ssh-agent'', which saves you from typing your login password each time.<br />
<br /><br />
<br /><br />
First, you create an RSA public/private key pair that identifies your local machine. You may already have created such a key in your SSH keychain. It is good security practice, however, to use a separate key for each device you want to connect to. Let us assume you want to connect to a [[Raspberry Pi]]. The command to create a new SSH key would be<br />
<pre class="terminal"><br />
ssh-keygen -t rsa -b 2048 -C "for Raspberry Pi"<br />
</pre><br />
where '-b 2048' specifies the key length in bits. You will be prompted to enter the path and name of the file in which the key will be saved. Choose a name that makes it clear that it was created for connecting to the Raspberry Pi. Next, you will be prompted for a password. Just press the Enter key for no password.<br />
<br /><br />
<br /><br />
Now that the SSH key is created, you need to copy the generated key ('''public''') into the folder ''/home/pi/.ssh/'' on the Raspberry Pi:<br />
<pre class="terminal"><br />
scp ~/.ssh/for-raspberry-pi_rsa.pub pi@192.168.1.10:/home/pi/.ssh/authorized_keys<br />
</pre><br />
The copied file is renamed to '''authorized_keys''', which is the expected file name for the SSH server to look up the public keys of trusted clients.<br />
<br /><br />
If ''authorized_keys'' is to hold multiple keys, you should use '''ssh-copy-id''' instead of ''scp'':<br />
<pre class="terminal"><br />
ssh-copy-id -i ~/.ssh/for-raspberry-pi_rsa.pub pi@192.168.1.10<br />
</pre><br />
<br /><br />
Now use ''ssh-agent'' on your local machine to start a special shell session that uses the new SSH key to automatically authenticate any SSH connection from your machine to the Raspberry Pi:<br />
<pre class="terminal"><br />
eval "$(ssh-agent -s)" # starting a new shell session<br />
ssh-add ~/.ssh/for-raspberry-pi_rsa<br />
</pre><br />
Done! This was the last time you had to enter the password for user ''pi''.<br />
<br /><br />
<br /><br />
By the way, you can list all the keys that were added to the SSH agent by entering<br />
<pre class="terminal"><br />
ssh-add -l<br />
</pre><br />
<br /><br />
<br />
<br />
= Bluetooth =<br />
On most Linux systems, Bluetooth functionality is provided by the kernel module, libraries and utilities of the [http://www.bluez.org BlueZ] project. So, make sure that BlueZ is installed.<br />
<pre class="terminal"><br />
sudo apt install bluez<br />
</pre><br />
<br /><br />
<br />
== Bluetooth Low Energy (BLE) Control in Terminal ==<br />
Set the Bluetooth controller to operate in BLE mode only by editing '''/etc/bluetooth/main.conf''' to make sure that the value of ''ControllerMode'' is set to ''le''.<br />
<pre class="code"><br />
ControllerMode = le<br />
</pre><br />
If a change had to be made, you need to reboot the system.<br />
<br /><br />
<br /><br />
Now issue the command <br />
<pre class="terminal"><br />
sudo systemctl start bluetooth<br />
</pre><br />
to start the ''bluetooth'' service. You can also stop, restart and query the status with by replacing ''start'' with ''stop'', ''restart'', ''status'', respectively.<br />
<br /><br />
<br /><br />
With the bluetooth service running, enter the command<br />
<pre class="terminal"><br />
bluetoothctl<br />
</pre><br />
which runs a Bluetooth control program in the terminal. In this program you can, for example, display the list of commands, query the controller, power on the controller, scan for devices with RSSI 80 or better, advertise with the local name ''RPi3'' and, finally, power off and quit the program with the following commands: <br />
<pre class="terminal"><br />
help<br />
show<br />
power on<br />
menu scan<br />
rssi 80<br />
back<br />
scan on<br />
...<br />
scan off<br />
discoverable on<br />
advertise on<br />
menu advertise<br />
name RPi3<br />
back<br />
...<br />
advertise off<br />
power off<br />
quit<br />
</pre><br />
<br />
<br />
== Bluetooth Programming with D-Bus ==<br />
Here is an (incomplete!) example of programming D-Bus in C++ using the [https://github.com/Kistler-Group/sdbus-cpp/blob/master/docs/using-sdbus-c++.md sdbus-c++] C++ binding, for which you need to install ''libsdbus-c++-dev''.<br />
<pre class="terminal"><br />
sudo apt install libbluetooth-dev libsdbus-c++-dev<br />
</pre><br />
<br /><br />
<br />
Inspired by [https://punchthrough.com/creating-a-ble-peripheral-with-bluez/ this article from PunchThrough's Andy Lee], I have created a basic BLE peripheral.<br />
<pre class="code"><br />
#include <sdbus-c++/sdbus-c++.h><br />
#include <iostream><br />
<br />
/**<br />
* Names of D-Bus system services can be looked up with the terminal command<br />
*<br />
* busctl list<br />
*<br />
* We see that the name of the D-Bus system service of the bluetooth daemon is 'org.bluez'.<br />
* The D-Bus object path for a given system service can be queried with the terminal command<br />
*<br />
* busctl tree <service name><br />
*<br />
* For 'org.bluez' let us assume the object path is '/org/bluez/hci0'.<br />
* We can now introspect the interfaces available in the D-Bus object via<br />
*<br />
* busctl introspect org.bluez /org/bluez/hci0<br />
*<br />
* or<br />
*<br />
* gdbus introspect -y -d "org.bluez" -o "/org/bluez/hci0"<br />
* <br />
* We will use to the methods and properties in the published interfaces<br />
* to create a BLE peripheral which advertises a service named 'Test'.<br />
* Additional information on the methods and their parameters can be looked up from<br />
* the BlueZ documentation at https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc<br />
*/<br />
int main(int numargs, char* args[])<br />
{<br />
const char* bluezServiceName = "org.bluez";<br />
const char* bluezObjectPath = "/org/bluez/hci0";<br />
const char* interface_adapter = "org.bluez.Adapter1";<br />
const char* interface_advertisingManager = "org.bluez.LEAdvertisingManager1";<br />
auto bluezProxy = sdbus::createProxy(bluezServiceName, bluezObjectPath);<br />
if (bluezProxy == nullptr)<br />
{<br />
std::cerr << "Error while creating proxy to BlueZ D-Bus service." << std::endl;<br />
return EXIT_FAILURE;<br />
}<br />
bluezProxy->setProperty("Powered").onInterface(interface_adapter).toValue(true);<br />
bluezProxy->setProperty("Alias").onInterface(interface_adapter).toValue("Test");<br />
<br />
// TO BE DONE<br />
<br />
bluezProxy->finishRegistration();<br />
std::cout << "BLE Peripheral Example" << std::endl;<br />
<br />
return EXIT_SUCCESS;<br />
}<br />
<br />
</pre><br />
<br /><br />
<br />
build with<br />
<pre class="terminal"><br />
my_arch=`uname -i`<br />
g++ -o ble-peripheral main.cpp -L/usr/lib/${my_arch}-linux-gnu -lsdbus-c++<br />
</pre><br />
<br /><br />
<br />
= Video4Linux =<br />
Video4Linux is the video pipeline control system in Linux. Start by installing the required packages. On a Debian distribution, type<br />
<pre class="terminal"><br />
sudo apt install libv4l-0 v4l-utils v4l-conf libv4lconvert0<br />
<br />
v4l2-ctl --list-devices<br />
</pre><br />
<br /><br />
<br />
<br />
= C++ programming notes =<br />
== Platform detection ==<br />
To detect whether code is compiled for the Linux platform you can check if ''__linux__'' is defined.<br />
<pre class="code"><br />
#ifdef __linux__<br />
</pre><br />
(here you can find [https://sourceforge.net/p/predef/wiki/OperatingSystems preprocessor definitions for many operating systems])<br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Linux&diff=3138Linux2022-12-24T12:14:51Z<p>Kai: Adds initial content to device trees section.</p>
<hr />
<div>= Boot Procedure =<br />
# The primary bootloader, which is usually a fixed part of the hardware recognizes bootable media.<br />
#* On PC compatible systems, [https://en.wikipedia.org/wiki/UEFI UEFI] or BIOS are the primary bootloaders.<br />
#* On BIOS systems, the Master Boot Record (MBR) area of a connected storage device is searched for a boot executable. The MBR is a special area, separate from the actual data storage area. BIOS is an old system, dating back to the early 1980s, but not yet obsolete.<br />
#* On a UEFI system, which supports storage media with much larger capacity, the ''GPT'' partition table is used to determine if the storage device provides an ''EFI System Partition'' containing the folder ''/efi'' with a subfolder that contains the secondary boot loader. ''/efi/microsoft'' or ''/efi/grub'', for example. After a Linux system is booted by UEFI hardware, you can open a terminal and inspect the partition table by typing <span class="terminal">sudo gdisk /dev/sda</span>.<br />
# If a secondary bootloader is found on the bootable media, it is loaded.<br />
#* On PC compatibles the secondary bootloader is usually [https://www.gnu.org/software/grub GRUB2].<br />
#* On [[Arm Cortex-A]] based systems, this is often [https://u-boot.readthedocs.io/en/latest/ U-Boot].<br />
#* Some systems have proprietary bootloaders. Raspberry Pi, for example.<br />
#* To support the bootloader, a standard interface called LBA (linear block access) exists for storage media. This interface is not optimized for the capabilities of the storage device but is sufficient for the bootloader to search for a bootable operating system, which will later load the appropriate driver for the storage media.<br />
# The secondary bootloader loads the [https://www.kernel.org Linux kernel].<br />
#* In the case of GRUB2, the boot media is searched for the boot partition using LBA mode, stage 2 is loaded from a separate data area of the boot media, the module for working with the boot partitions filesystem is loaded, the GRUB config file (''/boot/grub/grub.cfg'') is loaded from the boot partition, the user is optionally shown a GRUB menu, the kernel is loaded with the user parameters.<br />
# The kernel optionally loads an initial root file system into memory (often [https://en.wikipedia.org/wiki/Initial_ramdisk initramfs]), which includes the device drivers specific for the target hardware. For example, display drivers for showing graphical output during the boot sequence.<br />
#* Technically, all hardware-specific device drivers can be compiled into the kernel itself. In order to keep the kernel generic, however, and to avoid mixing components with incompatible distribution licenses (the GPL 2.0 license used by Linux prevents distributing a kernel with built-in proprietary drivers), certain drivers are placed into initramfs, from where they are loaded when needed.<br />
#* After the hardware is initialized, the kernel switches from initramfs to the real filesystem.<br />
# The kernel starts the first process, the '''init''' process. The ''init'' process starts all the system processes (a.k.a. ''services'') configured to run when the system launches.<br />
#* ''init'' used to be a shell script located in the filesystem at ''/sbin/init''. Nowadays, many Linux distributions use the '''[https://wiki.debian.org/systemd systemd]''' initialization method, where a binary executable is called instead of a shell script.<br />
<br /><br />
<br />
= Device Trees =<br />
Device trees are files that contain a static, hierarchical description of the hardware components of a Linux system with Arm processor architecture. Device trees are usually read by the bootloader. The specification of the device tree file format can be found at [https://devicetree.org devicetree.org].<br />
<br /><br />
<br /><br />
In a Linux kernel source repository, device tree source files are located in the ''linux/arch/arm/boot/dts'' directory. Device tree source files are also usually provided by manufacturers of hardware components that are connected via GPIO.<br />
<br /><br />
Device tree definitions are written in text form into ''.dts'' or ''.dtsi'' files, compiled into binary ''.dtb'' files, and placed into the ''/boot'' directory of the Linux system.<br />
<br /><br />
<br /><br />
== DTS Syntax ==<br />
<pre class="code"><br />
/dts-v1/;<br />
#include "bcm2711.dtsi"<br />
#include "bcm2711-rpi.dtsi"<br />
/ {<br />
compatible = "raspberrypi,4-model-b", "brcm,bcm2711";<br />
model = "Raspberry Pi 4 Model B";<br />
<br />
chosen {<br />
/* 8250 auxiliary UART instead of pl011 */<br />
stdout-path = "serial1:115200n8";<br />
};<br />
<br />
leds {<br />
led-act {<br />
gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;<br />
};<br />
<br />
led-pwr {<br />
label = "PWR";<br />
gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;<br />
default-state = "keep";<br />
linux,default-trigger = "default-on";<br />
};<br />
};<br />
<br />
...<br />
</pre><br />
<br /><br />
== Device Tree Compiler ==<br />
<pre class="terminal"><br />
sudo apt install device-tree-compiler<br />
dtc -I dts -O dtb -o my_system.dtb my_system.dts<br />
</pre><br />
<br /><br />
<br /><br />
<br />
== Device Tree Overlays ==<br />
Overlays are partial device tree definitions that modify an existing device tree file. The sources files have the extension ''.dts'', just like ordinary device tree source files. Compiled overlays have the '''.dtbo''' file extension and are placed in the '''/boot/overlays''' directory.<br />
<br /><br />
<br /><br />
Overlays are compiled by adding the ''-@'' flag, which generates symbols for referenced items (that the compiler would otherwise not be able to resolve). <br />
<pre class="terminal"><br />
dtc -@ -I dts -O dtb -o camera_overlay.dtbo camera_overlay.dts<br />
</pre><br />
=== dtoverlay ===<br />
'''dtoverlay''' is used to dynamically load device tree overlays, or unload previously loaded overlays.<br />
<pre class="terminal"><br />
<br />
</pre><br />
<br />
= Systemd =<br />
== Systemd Unit Files ==<br />
Unit files determine what kind of task is being started. The types of tasks are<br />
* '''service''' for running daemons<br />
* '''mount''' for mounting storage media, etc<br />
* '''automount''' for mounting directories when needed<br />
* '''timer''' for starting jobs at specific times<br />
* '''target''' (a group of unit files, or a state that the machine should be in after booting)<br />
* '''path''' (monitoring filesystem events)<br />
<br />
The original unit files that are installed by the package manager are placed in ''/usr/lib/systemd/system'' and should not be modified.<br />
If modifications to unit files are to be made, the modified unit files should be placed into ''/etc/systemd/system''.<br />
<br /><br />
<br />
=== Unit Relationships (Dependencies) ===<br />
There are various relationships between two units:<br />
* '''requires''': The dependent unit must be loaded in order to load the current unit.<br />
* '''wants''': The dependent unit is not critical<br />
* '''requisite''': the dependent unit must be loaded and already active.<br />
* '''conflicts''': the unit must not be loaded for the current to be loaded<br />
* '''before''': the current unit must be activated before the given units<br />
* '''after''': the current unit must be activated after the given units<br />
<br /><br />
The dependency graph can be displayed on the terminal via<br />
<pre class="terminal"><br />
sudo systemctl list-dependencies<br />
</pre><br />
<br /><br />
<br />
== Systemd Services ==<br />
Here is an example of using ''systemctl'' to query the status of the SSH server.<br />
<pre class="terminal"><br />
systemctl status sshd<br />
</pre><br />
<br /><br />
To start or stop the server, you would type<br />
<pre class="terminal"><br />
sudo systemctl start sshd<br />
sudo systemctl stop sshd<br />
</pre><br />
<br /><br />
To configure a service, edit its configuration file located in '''/etc/systemd/system'''.<br />
<br /><br />
<br /><br />
<br />
== Systemd Targets ==<br />
Targets are groups of unit files. If a target includes the statement <span class="code">AllowIsolate = yes</span> the target becomes an initialization endpoint at which systemd stops executing other units. Isolate targets are therefore similar to System V runlevels that were used for initialization before systemd.<br />
<br /><br />
<br /><br />
For a custom target (or service), the relationship to the unit files that are ''WantedBy'' or ''RequiredBy'' the target (or service) will be established by systemd through symbolic links to the wanted or required unit files. These symbolic links are placed in ''/etc/systemd/system'', within a subdirectory whose name starts with the name of the unit file and ends with the name of the type of relationship.<br />
<br /><br />
<br /><br />
== Systemd Analysis ==<br />
Systemd can plot a chart that shows how the units are launched over time.<br />
<pre class="terminal"><br />
systemd-analyze plot > analysis.html<br />
</pre><br />
generates an HTML page with a chart like this<br />
<br /><br />
<br /><br />
[[File:systemd-analysis.png | x300px ]]<br />
<br /><br />
<br /><br />
<br />
= Which Linux distro and version am I running? =<br />
<pre class="terminal"><br />
cat /etc/os-release<br />
</pre><br />
<br /><br />
<br />
= Dynamic Shared Objects (DSO) =<br />
Ulrich Drepper's [https://www.akkadia.org/drepper/dsohowto.pdf How To Write Shared Libraries] is a good resource for learning more about the ELF format, about optimizing your shared objects, and how to control the visibility of program symbols in the generated binaries.<br />
<br /><br />
<br /><br />
<br />
= Tracing system calls with ''strace'' =<br />
<br />
'''strace''' is a command that lets you trace the system calls made by the command that is passed as the argument. For example,<br />
<pre class="terminal"><br />
strace echo "hello"<br />
</pre><br />
prints<br />
<pre class="terminal"><br />
execve("/usr/bin/echo", ["echo", "hello"], 0x7ffefa8f4928 /* 42 vars */) = 0<br />
brk(NULL) = 0x561cf6532000<br />
arch_prctl(0x3001 /* ARCH_??? */, 0x7fff61293910) = -1 EINVAL (Invalid argument)<br />
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf85c44000<br />
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)<br />
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=53267, ...}, AT_EMPTY_PATH) = 0<br />
mmap(NULL, 53267, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7faf85c36000<br />
close(3) = 0<br />
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3<br />
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\237\2\0\0\0\0\0"..., 832) = 832<br />
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784<br />
pread64(3, "\4\0\0\0 \0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0"..., 48, 848) = 48<br />
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0i8\235HZ\227\223\333\350s\360\352,\223\340."..., 68, 896) = 68<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=2216304, ...}, AT_EMPTY_PATH) = 0<br />
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784<br />
mmap(NULL, 2260560, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7faf85a0e000<br />
mmap(0x7faf85a36000, 1658880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x28000) = 0x7faf85a36000<br />
mmap(0x7faf85bcb000, 360448, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x7faf85bcb000<br />
mmap(0x7faf85c23000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x214000) = 0x7faf85c23000<br />
mmap(0x7faf85c29000, 52816, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7faf85c29000<br />
close(3) = 0<br />
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf85a0b000<br />
arch_prctl(ARCH_SET_FS, 0x7faf85a0b740) = 0<br />
set_tid_address(0x7faf85a0ba10) = 1874<br />
set_robust_list(0x7faf85a0ba20, 24) = 0<br />
rseq(0x7faf85a0c0e0, 0x20, 0, 0x53053053) = 0<br />
mprotect(0x7faf85c23000, 16384, PROT_READ) = 0<br />
mprotect(0x561cf5067000, 4096, PROT_READ) = 0<br />
mprotect(0x7faf85c7e000, 8192, PROT_READ) = 0<br />
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0<br />
munmap(0x7faf85c36000, 53267) = 0<br />
getrandom("\x01\x62\x8d\xf4\xec\xea\xd8\x4e", 8, GRND_NONBLOCK) = 8<br />
brk(NULL) = 0x561cf6532000<br />
brk(0x561cf6553000) = 0x561cf6553000<br />
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=6070224, ...}, AT_EMPTY_PATH) = 0<br />
mmap(NULL, 6070224, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7faf85441000<br />
close(3) = 0<br />
newfstatat(1, "", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}, AT_EMPTY_PATH) = 0<br />
write(1, "hello\n", 6) = 6<br />
close(1) = 0<br />
close(2) = 0<br />
exit_group(0) = ?<br />
+++ exited with 0 +++<br />
</pre><br />
lists system calls made by ''echo'' as they are made.<br />
<br /><br />
<br /><br />
Instead of printing system calls as they are made, ''strace'' can print a short summary of which system calls were how many times and the time spent.<br />
<pre class="terminal"><br />
strace -c echo "hello"<br />
</pre><br />
prints<br />
<pre class="terminal"><br />
hello<br />
% time seconds usecs/call calls errors syscall<br />
------ ----------- ----------- --------- --------- ----------------<br />
0,00 0,000000 0 1 read<br />
0,00 0,000000 0 1 write<br />
0,00 0,000000 0 5 close<br />
0,00 0,000000 0 9 mmap<br />
0,00 0,000000 0 3 mprotect<br />
0,00 0,000000 0 1 munmap<br />
0,00 0,000000 0 3 brk<br />
0,00 0,000000 0 4 pread64<br />
0,00 0,000000 0 1 1 access<br />
0,00 0,000000 0 1 execve<br />
0,00 0,000000 0 2 1 arch_prctl<br />
0,00 0,000000 0 1 set_tid_address<br />
0,00 0,000000 0 3 openat<br />
0,00 0,000000 0 4 newfstatat<br />
0,00 0,000000 0 1 set_robust_list<br />
0,00 0,000000 0 1 prlimit64<br />
0,00 0,000000 0 1 getrandom<br />
0,00 0,000000 0 1 rseq<br />
------ ----------- ----------- --------- --------- ----------------<br />
100,00 0,000000 0 43 2 total<br />
</pre><br />
<br /><br />
<br /><br />
<br />
Similarly, '''ltrace''' will list the calls to library functions made by the command that was passed as the argument to ''ltrace''.<br />
<pre class="terminal"><br />
sudo apt install ltrace<br />
</pre><br />
<br /><br />
<br />
== Signals ==<br />
Signals are software interrupts that the the kernel can send an executable. The executable may react to the signal or choose to ignore it. The two signals SIGKILL and SIGTERM, however, can not be ignored by executable and must be handled.<br />
<br /><br />
An overview of the signals can be found in the man pages entry about signals<br />
<pre class="terminal"><br />
man 7 signal<br />
</pre><br />
<br /><br />
Some command-line tools do useful stuff when certain signals are sent to them. For example, the ''dd'' tool prints the progress of the copying task when the SIGUSR1 signal is sent to it via the ''kill'' command.<br />
<pre class="terminal"><br />
dd if=${HOME}/image.iso of=/dev/sdb &<br />
kill -s USR1 $(pidof dd)<br />
</pre><br />
<br /><br />
<br />
= Interprocess Communication Mechanisms =<br />
<br />
== Shared Memory ==<br />
Linux offers creating System V shared memory segments, which can be used for interprocess communication.<br />
<pre class="code"><br />
#include <sys/types.h><br />
#include <sys/ipc.h><br />
#include <sys/shm.h><br />
<br />
// creating an IPC key<br />
key_t segmentKey = ftok(”path_to_some_existing_file", 'R')<br />
if (segmentKey == -1) {<br />
perror("could not create IPC key");<br />
exit(1);<br />
}<br />
// accessing the shared memory segment, creating it if it doesn't exist<br />
int sharedMemoryID = shmget(segmentKey, SHM_SIZE, 0644 | IPC_CREAT)<br />
if (sharedMemoryID == -1) {<br />
perror("could not access (or create) the shared memory segment");<br />
exit(1);<br />
}<br />
// attaching a pointer<br />
void* memoryPtr = shmat(sharedMemoryID, NULL, 0);<br />
if (*((char*)memoryPtr) == -1) {<br />
perror("could not attach a pointer to the shared memory segment");<br />
exit(1);<br />
}<br />
</pre><br />
To learn more about shared memory segments, type<br />
<pre class="terminal"><br />
man ftok<br />
man shmget<br />
man shmat<br />
</pre><br />
<br /><br />
<br />
== Memory Mapped Files ==<br />
Linux offers mapping files to memory regions, which enables working on the file contents much more efficiently, as if it is a memory region. For example, pointers can be used in a C/C++ program to edit the contents. The memory mapped region can be shared between processes. This allows the processes to operate on large files, for example in a writer-subscriber architecture, while preserving memory. Unlike the shared memory method described above, the contents of the shared memory region are written to a file and thus persist between sessions and even system reboots.<br />
<pre class="code"><br />
#include <stdlib.h> <br />
#include <stdio.h> <br />
#include <unistd.h><br />
#include <errno.h> <br />
#include <string.h> <br />
#include <fcntl.h> <br />
#include <sys/types.h> <br />
#include <sys/stat.h> <br />
#include <sys/mman.h> <br />
<br />
static const int MAX_INPUT_LENGTH = 50;<br />
<br />
int main(int argc, char** argv)<br />
{<br />
int fd = open(argv[1], O_RDWR | O_CREAT); <br />
char* shared_mem = mmap(NULL, MAX_INPUT_LENGTH, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); <br />
close(fd); <br />
<br />
if (!strcmp(argv[2], "read")) { <br />
// continously listens to text messages from the 'write' process and writes to the terminal<br />
while (1) { <br />
shared_mem[MAX_INPUT_LENGTH-1] = '\0'; <br />
printf("%s", shared_mem); <br />
sleep(1); <br />
} <br />
} <br />
else if (!strcmp(argv[2], "write")) {<br />
// continuously sends the input from the terminal to the 'read' process<br />
while (1) {<br />
fgets(shared_mem, MAX_INPUT_LENGTH, stdin);<br />
}<br />
}<br />
else {<br />
printf("Unsupported command\n"); <br />
}<br />
}<br />
</pre><br />
<br />
To learn more about memory mapped files, refer to the man page<br />
<pre class="terminal"><br />
man mmap<br />
</pre><br />
<br /><br />
<br />
== Pipes ==<br />
Pipes are another IPC mechanism where one process can send messages to another.<br />
<pre class="code"><br />
#include <stdio.h><br />
#include <stdlib.h> <br />
#include <errno.h> <br />
#include <sys/types.h> <br />
#include <unistd.h> <br />
<br />
int main(void)<br />
{ <br />
int pipeDescriptor[2]; <br />
<br />
pipe(pipeDescriptor); // writing to pipeDescriptor[0], reading from pipeDescriptor[1]<br />
<br />
if (!fork())<br />
{ <br />
printf(" CHILD: writing to pipe and exiting\n"); <br />
write(pipeDescriptor[1], "test", 5); <br />
}<br />
else<br />
{ <br />
char buffer[5]; <br />
printf("PARENT: reading from pipe\n"); <br />
read(pipeDescriptor[0], buffer, 5); <br />
printf("PARENT: read \"%s\"\n", buf); <br />
wait(NULL); <br />
} <br />
return 0; <br />
}<br />
</pre><br />
<br /><br />
To learn more about pipes, refer to the man page<br />
<pre class="terminal"><br />
man pipe<br />
</pre><br />
<br /><br />
<br />
= D-Bus and dmesg =<br />
<br /><br />
<br />
= GUI-less Mode =<br />
<br />
== Switching to GUI-less (Multi-User) Mode with Systemd ==<br />
On a Linux system that uses systemd, we can control whether the graphical user interface is loaded and shown by specifying a suitable systemd target. To turn off the graphical desktop immediately, enter<br />
<pre class="terminal"><br />
sudo systemctl isolate multi-user.target<br />
</pre><br />
To prevent the GUI from being loaded during the system startup, type<br />
<pre class="terminal"><br />
sudo systemctl set-default multi-user.target<br />
</pre><br />
To return to the graphical desktop, type<br />
<br/><br />
<pre class="terminal"><br />
sudo systemctl isolate graphical.target<br />
</pre><br />
and to make the graphical desktop the default again, type<br />
<pre class="terminal"><br />
sudo systemctl set-default graphical.target<br />
</pre><br />
<br /><br />
<br />
== Setting the Screen Resolution for GUI-less Mode ==<br />
* Restart the machine to the Grub boot menu.<br />
* Press 'c' to get into the Grub command console.<br />
* Run the command 'vbeinfo' to list possible resolutions.<br />
* Note down the desired resolution. For example, ''1024x768x32'', where ''32'' is the color mode.<br />
* Type ''exit'' to return to the Grub boot menu and boot into Ubuntu.<br />
* Open '''/etc/default/grub''' in an editor to add the line<br />
<pre class="code"><br />
GRUB_GFXPAYLOAD_LINUX=1024x768x32<br />
</pre><br />
* Optionally, add the line<br />
<pre class="code"><br />
GRUB_GFXMODE=1024x768<br />
</pre><br />
to set the screen resolution for the GRUB boot menu itself.<br />
* Finally, run the Grub updater<br />
<pre class="terminal"><br />
sudo update-grub<br />
</pre><br />
<br /><br />
<br />
= Message of the Day (MOTD) =<br />
For users that open simultaneous terminal sessions to different Linux machines, it is helpful to see a distinct ''message of the day'' (''MOTD'') on each terminal. The MOTD can be customized by editing the shell scripts located in '''/etc/update-motd.d/'''. The shell scripts are executed in alphabetical order, their output is the MOTD. The names of the script files start with a number between 1 and 99, which makes ordering of the scripts immediately visible. Script files can be deleted or their execution bit flipped via ''chmod'' in order to disable the corresponding output. New script files can be added, and their file names chosen according to the desired position of their output.<br />
<br /><br />
<br /><br />
Additionally, it is possible to create the '''/etc/motd''' file with static content, whose output will be appended to the dynamically generated MOTD. With ''/etc/motd'', the MOTD can be embellished with ASCII art, like the Robo.Fish logo below<br />
<br /><br />
<br /><br />
<pre class="code"><br />
.';cldxxkkkxxdolc;,..<br />
.;oOXWWMMMMMMMMMMMMMMWWXKOxo:,.<br />
'o0WMMMMMMMMMMMMMMMMMMMMMMMMMMMWX0xl:'.<br />
.;xXMMMMMMMMMMMMMMMMMMMMMMMMMWWWNNXXKKK0kd:.<br />
.:ONMMMMMMMMMMMMMMMMMMWXKOxdoc:;;,'..........<br />
. 'o0WMMMMMMMMMMMMMMWN0xl:,..<br />
Xx:. .:kXWMMMMMMMMMMMMMN0d:'.<br />
MMWKxc'. .'cxXWMMMMMMMMMMMMNOo:,.<br />
MMMMMMN0xc,. .,cd0NWMMMMMMMMMMMMN0o,.<br />
MMMMMMWWNX0d:;ckKNWMMMMMMMMMMWN0xl,.<br />
lllcc:;,'.. ..,;:clloollc:,..<br />
</pre><br />
<br /><br />
The MOTD can be previewed without needing to start a new shell session:<br />
<pre class="terminal"><br />
sudo run-parts /etc/update-motd.d/<br />
</pre><br />
<br /><br />
<br />
= SSH Logins Without Typing The Password =<br />
If you connect to a remote computer via ''ssh'' or copy files via ''scp'' frequently, you should consider using ''ssh-agent'', which saves you from typing your login password each time.<br />
<br /><br />
<br /><br />
First, you create an RSA public/private key pair that identifies your local machine. You may already have created such a key in your SSH keychain. It is good security practice, however, to use a separate key for each device you want to connect to. Let us assume you want to connect to a [[Raspberry Pi]]. The command to create a new SSH key would be<br />
<pre class="terminal"><br />
ssh-keygen -t rsa -b 2048 -C "for Raspberry Pi"<br />
</pre><br />
where '-b 2048' specifies the key length in bits. You will be prompted to enter the path and name of the file in which the key will be saved. Choose a name that makes it clear that it was created for connecting to the Raspberry Pi. Next, you will be prompted for a password. Just press the Enter key for no password.<br />
<br /><br />
<br /><br />
Now that the SSH key is created, you need to copy the generated key ('''public''') into the folder ''/home/pi/.ssh/'' on the Raspberry Pi:<br />
<pre class="terminal"><br />
scp ~/.ssh/for-raspberry-pi_rsa.pub pi@192.168.1.10:/home/pi/.ssh/authorized_keys<br />
</pre><br />
The copied file is renamed to '''authorized_keys''', which is the expected file name for the SSH server to look up the public keys of trusted clients.<br />
<br /><br />
If ''authorized_keys'' is to hold multiple keys, you should use '''ssh-copy-id''' instead of ''scp'':<br />
<pre class="terminal"><br />
ssh-copy-id -i ~/.ssh/for-raspberry-pi_rsa.pub pi@192.168.1.10<br />
</pre><br />
<br /><br />
Now use ''ssh-agent'' on your local machine to start a special shell session that uses the new SSH key to automatically authenticate any SSH connection from your machine to the Raspberry Pi:<br />
<pre class="terminal"><br />
eval "$(ssh-agent -s)" # starting a new shell session<br />
ssh-add ~/.ssh/for-raspberry-pi_rsa<br />
</pre><br />
Done! This was the last time you had to enter the password for user ''pi''.<br />
<br /><br />
<br /><br />
By the way, you can list all the keys that were added to the SSH agent by entering<br />
<pre class="terminal"><br />
ssh-add -l<br />
</pre><br />
<br /><br />
<br />
<br />
= Bluetooth =<br />
On most Linux systems, Bluetooth functionality is provided by the kernel module, libraries and utilities of the [http://www.bluez.org BlueZ] project. So, make sure that BlueZ is installed.<br />
<pre class="terminal"><br />
sudo apt install bluez<br />
</pre><br />
<br /><br />
<br />
== Bluetooth Low Energy (BLE) Control in Terminal ==<br />
Set the Bluetooth controller to operate in BLE mode only by editing '''/etc/bluetooth/main.conf''' to make sure that the value of ''ControllerMode'' is set to ''le''.<br />
<pre class="code"><br />
ControllerMode = le<br />
</pre><br />
If a change had to be made, you need to reboot the system.<br />
<br /><br />
<br /><br />
Now issue the command <br />
<pre class="terminal"><br />
sudo systemctl start bluetooth<br />
</pre><br />
to start the ''bluetooth'' service. You can also stop, restart and query the status with by replacing ''start'' with ''stop'', ''restart'', ''status'', respectively.<br />
<br /><br />
<br /><br />
With the bluetooth service running, enter the command<br />
<pre class="terminal"><br />
bluetoothctl<br />
</pre><br />
which runs a Bluetooth control program in the terminal. In this program you can, for example, display the list of commands, query the controller, power on the controller, scan for devices with RSSI 80 or better, advertise with the local name ''RPi3'' and, finally, power off and quit the program with the following commands: <br />
<pre class="terminal"><br />
help<br />
show<br />
power on<br />
menu scan<br />
rssi 80<br />
back<br />
scan on<br />
...<br />
scan off<br />
discoverable on<br />
advertise on<br />
menu advertise<br />
name RPi3<br />
back<br />
...<br />
advertise off<br />
power off<br />
quit<br />
</pre><br />
<br />
<br />
== Bluetooth Programming with D-Bus ==<br />
Here is an (incomplete!) example of programming D-Bus in C++ using the [https://github.com/Kistler-Group/sdbus-cpp/blob/master/docs/using-sdbus-c++.md sdbus-c++] C++ binding, for which you need to install ''libsdbus-c++-dev''.<br />
<pre class="terminal"><br />
sudo apt install libbluetooth-dev libsdbus-c++-dev<br />
</pre><br />
<br /><br />
<br />
Inspired by [https://punchthrough.com/creating-a-ble-peripheral-with-bluez/ this article from PunchThrough's Andy Lee], I have created a basic BLE peripheral.<br />
<pre class="code"><br />
#include <sdbus-c++/sdbus-c++.h><br />
#include <iostream><br />
<br />
/**<br />
* Names of D-Bus system services can be looked up with the terminal command<br />
*<br />
* busctl list<br />
*<br />
* We see that the name of the D-Bus system service of the bluetooth daemon is 'org.bluez'.<br />
* The D-Bus object path for a given system service can be queried with the terminal command<br />
*<br />
* busctl tree <service name><br />
*<br />
* For 'org.bluez' let us assume the object path is '/org/bluez/hci0'.<br />
* We can now introspect the interfaces available in the D-Bus object via<br />
*<br />
* busctl introspect org.bluez /org/bluez/hci0<br />
*<br />
* or<br />
*<br />
* gdbus introspect -y -d "org.bluez" -o "/org/bluez/hci0"<br />
* <br />
* We will use to the methods and properties in the published interfaces<br />
* to create a BLE peripheral which advertises a service named 'Test'.<br />
* Additional information on the methods and their parameters can be looked up from<br />
* the BlueZ documentation at https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc<br />
*/<br />
int main(int numargs, char* args[])<br />
{<br />
const char* bluezServiceName = "org.bluez";<br />
const char* bluezObjectPath = "/org/bluez/hci0";<br />
const char* interface_adapter = "org.bluez.Adapter1";<br />
const char* interface_advertisingManager = "org.bluez.LEAdvertisingManager1";<br />
auto bluezProxy = sdbus::createProxy(bluezServiceName, bluezObjectPath);<br />
if (bluezProxy == nullptr)<br />
{<br />
std::cerr << "Error while creating proxy to BlueZ D-Bus service." << std::endl;<br />
return EXIT_FAILURE;<br />
}<br />
bluezProxy->setProperty("Powered").onInterface(interface_adapter).toValue(true);<br />
bluezProxy->setProperty("Alias").onInterface(interface_adapter).toValue("Test");<br />
<br />
// TO BE DONE<br />
<br />
bluezProxy->finishRegistration();<br />
std::cout << "BLE Peripheral Example" << std::endl;<br />
<br />
return EXIT_SUCCESS;<br />
}<br />
<br />
</pre><br />
<br /><br />
<br />
build with<br />
<pre class="terminal"><br />
my_arch=`uname -i`<br />
g++ -o ble-peripheral main.cpp -L/usr/lib/${my_arch}-linux-gnu -lsdbus-c++<br />
</pre><br />
<br /><br />
<br />
= Video4Linux =<br />
Video4Linux is the video pipeline control system in Linux. Start by installing the required packages. On a Debian distribution, type<br />
<pre class="terminal"><br />
sudo apt install libv4l-0 v4l-utils v4l-conf libv4lconvert0<br />
<br />
v4l2-ctl --list-devices<br />
</pre><br />
<br /><br />
<br />
<br />
= C++ programming notes =<br />
== Platform detection ==<br />
To detect whether code is compiled for the Linux platform you can check if ''__linux__'' is defined.<br />
<pre class="code"><br />
#ifdef __linux__<br />
</pre><br />
(here you can find [https://sourceforge.net/p/predef/wiki/OperatingSystems preprocessor definitions for many operating systems])<br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Linux&diff=3137Linux2022-12-24T10:58:21Z<p>Kai: Adds empty section about device trees. Changes heading sizes.</p>
<hr />
<div>= Boot Procedure =<br />
# The primary bootloader, which is usually a fixed part of the hardware recognizes bootable media.<br />
#* On PC compatible systems, [https://en.wikipedia.org/wiki/UEFI UEFI] or BIOS are the primary bootloaders.<br />
#* On BIOS systems, the Master Boot Record (MBR) area of a connected storage device is searched for a boot executable. The MBR is a special area, separate from the actual data storage area. BIOS is an old system, dating back to the early 1980s, but not yet obsolete.<br />
#* On a UEFI system, which supports storage media with much larger capacity, the ''GPT'' partition table is used to determine if the storage device provides an ''EFI System Partition'' containing the folder ''/efi'' with a subfolder that contains the secondary boot loader. ''/efi/microsoft'' or ''/efi/grub'', for example. After a Linux system is booted by UEFI hardware, you can open a terminal and inspect the partition table by typing <span class="terminal">sudo gdisk /dev/sda</span>.<br />
# If a secondary bootloader is found on the bootable media, it is loaded.<br />
#* On PC compatibles the secondary bootloader is usually [https://www.gnu.org/software/grub GRUB2].<br />
#* On [[Arm Cortex-A]] based systems, this is often [https://u-boot.readthedocs.io/en/latest/ U-Boot].<br />
#* Some systems have proprietary bootloaders. Raspberry Pi, for example.<br />
#* To support the bootloader, a standard interface called LBA (linear block access) exists for storage media. This interface is not optimized for the capabilities of the storage device but is sufficient for the bootloader to search for a bootable operating system, which will later load the appropriate driver for the storage media.<br />
# The secondary bootloader loads the [https://www.kernel.org Linux kernel].<br />
#* In the case of GRUB2, the boot media is searched for the boot partition using LBA mode, stage 2 is loaded from a separate data area of the boot media, the module for working with the boot partitions filesystem is loaded, the GRUB config file (''/boot/grub/grub.cfg'') is loaded from the boot partition, the user is optionally shown a GRUB menu, the kernel is loaded with the user parameters.<br />
# The kernel optionally loads an initial root file system into memory (often [https://en.wikipedia.org/wiki/Initial_ramdisk initramfs]), which includes the device drivers specific for the target hardware. For example, display drivers for showing graphical output during the boot sequence.<br />
#* Technically, all hardware-specific device drivers can be compiled into the kernel itself. In order to keep the kernel generic, however, and to avoid mixing components with incompatible distribution licenses (the GPL 2.0 license used by Linux prevents distributing a kernel with built-in proprietary drivers), certain drivers are placed into initramfs, from where they are loaded when needed.<br />
#* After the hardware is initialized, the kernel switches from initramfs to the real filesystem.<br />
# The kernel starts the first process, the '''init''' process. The ''init'' process starts all the system processes (a.k.a. ''services'') configured to run when the system launches.<br />
#* ''init'' used to be a shell script located in the filesystem at ''/sbin/init''. Nowadays, many Linux distributions use the '''[https://wiki.debian.org/systemd systemd]''' initialization method, where a binary executable is called instead of a shell script.<br />
<br /><br />
<br />
= Device Trees =<br />
<br /><br />
<br />
= Systemd =<br />
== Systemd Unit Files ==<br />
Unit files determine what kind of task is being started. The types of tasks are<br />
* '''service''' for running daemons<br />
* '''mount''' for mounting storage media, etc<br />
* '''automount''' for mounting directories when needed<br />
* '''timer''' for starting jobs at specific times<br />
* '''target''' (a group of unit files, or a state that the machine should be in after booting)<br />
* '''path''' (monitoring filesystem events)<br />
<br />
The original unit files that are installed by the package manager are placed in ''/usr/lib/systemd/system'' and should not be modified.<br />
If modifications to unit files are to be made, the modified unit files should be placed into ''/etc/systemd/system''.<br />
<br /><br />
<br />
=== Unit Relationships (Dependencies) ===<br />
There are various relationships between two units:<br />
* '''requires''': The dependent unit must be loaded in order to load the current unit.<br />
* '''wants''': The dependent unit is not critical<br />
* '''requisite''': the dependent unit must be loaded and already active.<br />
* '''conflicts''': the unit must not be loaded for the current to be loaded<br />
* '''before''': the current unit must be activated before the given units<br />
* '''after''': the current unit must be activated after the given units<br />
<br /><br />
The dependency graph can be displayed on the terminal via<br />
<pre class="terminal"><br />
sudo systemctl list-dependencies<br />
</pre><br />
<br /><br />
<br />
== Systemd Services ==<br />
Here is an example of using ''systemctl'' to query the status of the SSH server.<br />
<pre class="terminal"><br />
systemctl status sshd<br />
</pre><br />
<br /><br />
To start or stop the server, you would type<br />
<pre class="terminal"><br />
sudo systemctl start sshd<br />
sudo systemctl stop sshd<br />
</pre><br />
<br /><br />
To configure a service, edit its configuration file located in '''/etc/systemd/system'''.<br />
<br /><br />
<br /><br />
<br />
== Systemd Targets ==<br />
Targets are groups of unit files. If a target includes the statement <span class="code">AllowIsolate = yes</span> the target becomes an initialization endpoint at which systemd stops executing other units. Isolate targets are therefore similar to System V runlevels that were used for initialization before systemd.<br />
<br /><br />
<br /><br />
For a custom target (or service), the relationship to the unit files that are ''WantedBy'' or ''RequiredBy'' the target (or service) will be established by systemd through symbolic links to the wanted or required unit files. These symbolic links are placed in ''/etc/systemd/system'', within a subdirectory whose name starts with the name of the unit file and ends with the name of the type of relationship.<br />
<br /><br />
<br /><br />
== Systemd Analysis ==<br />
Systemd can plot a chart that shows how the units are launched over time.<br />
<pre class="terminal"><br />
systemd-analyze plot > analysis.html<br />
</pre><br />
generates an HTML page with a chart like this<br />
<br /><br />
<br /><br />
[[File:systemd-analysis.png | x300px ]]<br />
<br /><br />
<br /><br />
<br />
= Which Linux distro and version am I running? =<br />
<pre class="terminal"><br />
cat /etc/os-release<br />
</pre><br />
<br /><br />
<br />
= Dynamic Shared Objects (DSO) =<br />
Ulrich Drepper's [https://www.akkadia.org/drepper/dsohowto.pdf How To Write Shared Libraries] is a good resource for learning more about the ELF format, about optimizing your shared objects, and how to control the visibility of program symbols in the generated binaries.<br />
<br /><br />
<br /><br />
<br />
= Tracing system calls with ''strace'' =<br />
<br />
'''strace''' is a command that lets you trace the system calls made by the command that is passed as the argument. For example,<br />
<pre class="terminal"><br />
strace echo "hello"<br />
</pre><br />
prints<br />
<pre class="terminal"><br />
execve("/usr/bin/echo", ["echo", "hello"], 0x7ffefa8f4928 /* 42 vars */) = 0<br />
brk(NULL) = 0x561cf6532000<br />
arch_prctl(0x3001 /* ARCH_??? */, 0x7fff61293910) = -1 EINVAL (Invalid argument)<br />
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf85c44000<br />
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)<br />
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=53267, ...}, AT_EMPTY_PATH) = 0<br />
mmap(NULL, 53267, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7faf85c36000<br />
close(3) = 0<br />
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3<br />
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\237\2\0\0\0\0\0"..., 832) = 832<br />
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784<br />
pread64(3, "\4\0\0\0 \0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0"..., 48, 848) = 48<br />
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0i8\235HZ\227\223\333\350s\360\352,\223\340."..., 68, 896) = 68<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=2216304, ...}, AT_EMPTY_PATH) = 0<br />
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784<br />
mmap(NULL, 2260560, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7faf85a0e000<br />
mmap(0x7faf85a36000, 1658880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x28000) = 0x7faf85a36000<br />
mmap(0x7faf85bcb000, 360448, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x7faf85bcb000<br />
mmap(0x7faf85c23000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x214000) = 0x7faf85c23000<br />
mmap(0x7faf85c29000, 52816, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7faf85c29000<br />
close(3) = 0<br />
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf85a0b000<br />
arch_prctl(ARCH_SET_FS, 0x7faf85a0b740) = 0<br />
set_tid_address(0x7faf85a0ba10) = 1874<br />
set_robust_list(0x7faf85a0ba20, 24) = 0<br />
rseq(0x7faf85a0c0e0, 0x20, 0, 0x53053053) = 0<br />
mprotect(0x7faf85c23000, 16384, PROT_READ) = 0<br />
mprotect(0x561cf5067000, 4096, PROT_READ) = 0<br />
mprotect(0x7faf85c7e000, 8192, PROT_READ) = 0<br />
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0<br />
munmap(0x7faf85c36000, 53267) = 0<br />
getrandom("\x01\x62\x8d\xf4\xec\xea\xd8\x4e", 8, GRND_NONBLOCK) = 8<br />
brk(NULL) = 0x561cf6532000<br />
brk(0x561cf6553000) = 0x561cf6553000<br />
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=6070224, ...}, AT_EMPTY_PATH) = 0<br />
mmap(NULL, 6070224, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7faf85441000<br />
close(3) = 0<br />
newfstatat(1, "", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}, AT_EMPTY_PATH) = 0<br />
write(1, "hello\n", 6) = 6<br />
close(1) = 0<br />
close(2) = 0<br />
exit_group(0) = ?<br />
+++ exited with 0 +++<br />
</pre><br />
lists system calls made by ''echo'' as they are made.<br />
<br /><br />
<br /><br />
Instead of printing system calls as they are made, ''strace'' can print a short summary of which system calls were how many times and the time spent.<br />
<pre class="terminal"><br />
strace -c echo "hello"<br />
</pre><br />
prints<br />
<pre class="terminal"><br />
hello<br />
% time seconds usecs/call calls errors syscall<br />
------ ----------- ----------- --------- --------- ----------------<br />
0,00 0,000000 0 1 read<br />
0,00 0,000000 0 1 write<br />
0,00 0,000000 0 5 close<br />
0,00 0,000000 0 9 mmap<br />
0,00 0,000000 0 3 mprotect<br />
0,00 0,000000 0 1 munmap<br />
0,00 0,000000 0 3 brk<br />
0,00 0,000000 0 4 pread64<br />
0,00 0,000000 0 1 1 access<br />
0,00 0,000000 0 1 execve<br />
0,00 0,000000 0 2 1 arch_prctl<br />
0,00 0,000000 0 1 set_tid_address<br />
0,00 0,000000 0 3 openat<br />
0,00 0,000000 0 4 newfstatat<br />
0,00 0,000000 0 1 set_robust_list<br />
0,00 0,000000 0 1 prlimit64<br />
0,00 0,000000 0 1 getrandom<br />
0,00 0,000000 0 1 rseq<br />
------ ----------- ----------- --------- --------- ----------------<br />
100,00 0,000000 0 43 2 total<br />
</pre><br />
<br /><br />
<br /><br />
<br />
Similarly, '''ltrace''' will list the calls to library functions made by the command that was passed as the argument to ''ltrace''.<br />
<pre class="terminal"><br />
sudo apt install ltrace<br />
</pre><br />
<br /><br />
<br />
== Signals ==<br />
Signals are software interrupts that the the kernel can send an executable. The executable may react to the signal or choose to ignore it. The two signals SIGKILL and SIGTERM, however, can not be ignored by executable and must be handled.<br />
<br /><br />
An overview of the signals can be found in the man pages entry about signals<br />
<pre class="terminal"><br />
man 7 signal<br />
</pre><br />
<br /><br />
Some command-line tools do useful stuff when certain signals are sent to them. For example, the ''dd'' tool prints the progress of the copying task when the SIGUSR1 signal is sent to it via the ''kill'' command.<br />
<pre class="terminal"><br />
dd if=${HOME}/image.iso of=/dev/sdb &<br />
kill -s USR1 $(pidof dd)<br />
</pre><br />
<br /><br />
<br />
= Interprocess Communication Mechanisms =<br />
<br />
== Shared Memory ==<br />
Linux offers creating System V shared memory segments, which can be used for interprocess communication.<br />
<pre class="code"><br />
#include <sys/types.h><br />
#include <sys/ipc.h><br />
#include <sys/shm.h><br />
<br />
// creating an IPC key<br />
key_t segmentKey = ftok(”path_to_some_existing_file", 'R')<br />
if (segmentKey == -1) {<br />
perror("could not create IPC key");<br />
exit(1);<br />
}<br />
// accessing the shared memory segment, creating it if it doesn't exist<br />
int sharedMemoryID = shmget(segmentKey, SHM_SIZE, 0644 | IPC_CREAT)<br />
if (sharedMemoryID == -1) {<br />
perror("could not access (or create) the shared memory segment");<br />
exit(1);<br />
}<br />
// attaching a pointer<br />
void* memoryPtr = shmat(sharedMemoryID, NULL, 0);<br />
if (*((char*)memoryPtr) == -1) {<br />
perror("could not attach a pointer to the shared memory segment");<br />
exit(1);<br />
}<br />
</pre><br />
To learn more about shared memory segments, type<br />
<pre class="terminal"><br />
man ftok<br />
man shmget<br />
man shmat<br />
</pre><br />
<br /><br />
<br />
== Memory Mapped Files ==<br />
Linux offers mapping files to memory regions, which enables working on the file contents much more efficiently, as if it is a memory region. For example, pointers can be used in a C/C++ program to edit the contents. The memory mapped region can be shared between processes. This allows the processes to operate on large files, for example in a writer-subscriber architecture, while preserving memory. Unlike the shared memory method described above, the contents of the shared memory region are written to a file and thus persist between sessions and even system reboots.<br />
<pre class="code"><br />
#include <stdlib.h> <br />
#include <stdio.h> <br />
#include <unistd.h><br />
#include <errno.h> <br />
#include <string.h> <br />
#include <fcntl.h> <br />
#include <sys/types.h> <br />
#include <sys/stat.h> <br />
#include <sys/mman.h> <br />
<br />
static const int MAX_INPUT_LENGTH = 50;<br />
<br />
int main(int argc, char** argv)<br />
{<br />
int fd = open(argv[1], O_RDWR | O_CREAT); <br />
char* shared_mem = mmap(NULL, MAX_INPUT_LENGTH, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); <br />
close(fd); <br />
<br />
if (!strcmp(argv[2], "read")) { <br />
// continously listens to text messages from the 'write' process and writes to the terminal<br />
while (1) { <br />
shared_mem[MAX_INPUT_LENGTH-1] = '\0'; <br />
printf("%s", shared_mem); <br />
sleep(1); <br />
} <br />
} <br />
else if (!strcmp(argv[2], "write")) {<br />
// continuously sends the input from the terminal to the 'read' process<br />
while (1) {<br />
fgets(shared_mem, MAX_INPUT_LENGTH, stdin);<br />
}<br />
}<br />
else {<br />
printf("Unsupported command\n"); <br />
}<br />
}<br />
</pre><br />
<br />
To learn more about memory mapped files, refer to the man page<br />
<pre class="terminal"><br />
man mmap<br />
</pre><br />
<br /><br />
<br />
== Pipes ==<br />
Pipes are another IPC mechanism where one process can send messages to another.<br />
<pre class="code"><br />
#include <stdio.h><br />
#include <stdlib.h> <br />
#include <errno.h> <br />
#include <sys/types.h> <br />
#include <unistd.h> <br />
<br />
int main(void)<br />
{ <br />
int pipeDescriptor[2]; <br />
<br />
pipe(pipeDescriptor); // writing to pipeDescriptor[0], reading from pipeDescriptor[1]<br />
<br />
if (!fork())<br />
{ <br />
printf(" CHILD: writing to pipe and exiting\n"); <br />
write(pipeDescriptor[1], "test", 5); <br />
}<br />
else<br />
{ <br />
char buffer[5]; <br />
printf("PARENT: reading from pipe\n"); <br />
read(pipeDescriptor[0], buffer, 5); <br />
printf("PARENT: read \"%s\"\n", buf); <br />
wait(NULL); <br />
} <br />
return 0; <br />
}<br />
</pre><br />
<br /><br />
To learn more about pipes, refer to the man page<br />
<pre class="terminal"><br />
man pipe<br />
</pre><br />
<br /><br />
<br />
= D-Bus and dmesg =<br />
<br /><br />
<br />
= GUI-less Mode =<br />
<br />
== Switching to GUI-less (Multi-User) Mode with Systemd ==<br />
On a Linux system that uses systemd, we can control whether the graphical user interface is loaded and shown by specifying a suitable systemd target. To turn off the graphical desktop immediately, enter<br />
<pre class="terminal"><br />
sudo systemctl isolate multi-user.target<br />
</pre><br />
To prevent the GUI from being loaded during the system startup, type<br />
<pre class="terminal"><br />
sudo systemctl set-default multi-user.target<br />
</pre><br />
To return to the graphical desktop, type<br />
<br/><br />
<pre class="terminal"><br />
sudo systemctl isolate graphical.target<br />
</pre><br />
and to make the graphical desktop the default again, type<br />
<pre class="terminal"><br />
sudo systemctl set-default graphical.target<br />
</pre><br />
<br /><br />
<br />
== Setting the Screen Resolution for GUI-less Mode ==<br />
* Restart the machine to the Grub boot menu.<br />
* Press 'c' to get into the Grub command console.<br />
* Run the command 'vbeinfo' to list possible resolutions.<br />
* Note down the desired resolution. For example, ''1024x768x32'', where ''32'' is the color mode.<br />
* Type ''exit'' to return to the Grub boot menu and boot into Ubuntu.<br />
* Open '''/etc/default/grub''' in an editor to add the line<br />
<pre class="code"><br />
GRUB_GFXPAYLOAD_LINUX=1024x768x32<br />
</pre><br />
* Optionally, add the line<br />
<pre class="code"><br />
GRUB_GFXMODE=1024x768<br />
</pre><br />
to set the screen resolution for the GRUB boot menu itself.<br />
* Finally, run the Grub updater<br />
<pre class="terminal"><br />
sudo update-grub<br />
</pre><br />
<br /><br />
<br />
= Message of the Day (MOTD) =<br />
For users that open simultaneous terminal sessions to different Linux machines, it is helpful to see a distinct ''message of the day'' (''MOTD'') on each terminal. The MOTD can be customized by editing the shell scripts located in '''/etc/update-motd.d/'''. The shell scripts are executed in alphabetical order, their output is the MOTD. The names of the script files start with a number between 1 and 99, which makes ordering of the scripts immediately visible. Script files can be deleted or their execution bit flipped via ''chmod'' in order to disable the corresponding output. New script files can be added, and their file names chosen according to the desired position of their output.<br />
<br /><br />
<br /><br />
Additionally, it is possible to create the '''/etc/motd''' file with static content, whose output will be appended to the dynamically generated MOTD. With ''/etc/motd'', the MOTD can be embellished with ASCII art, like the Robo.Fish logo below<br />
<br /><br />
<br /><br />
<pre class="code"><br />
.';cldxxkkkxxdolc;,..<br />
.;oOXWWMMMMMMMMMMMMMMWWXKOxo:,.<br />
'o0WMMMMMMMMMMMMMMMMMMMMMMMMMMMWX0xl:'.<br />
.;xXMMMMMMMMMMMMMMMMMMMMMMMMMWWWNNXXKKK0kd:.<br />
.:ONMMMMMMMMMMMMMMMMMMWXKOxdoc:;;,'..........<br />
. 'o0WMMMMMMMMMMMMMMWN0xl:,..<br />
Xx:. .:kXWMMMMMMMMMMMMMN0d:'.<br />
MMWKxc'. .'cxXWMMMMMMMMMMMMNOo:,.<br />
MMMMMMN0xc,. .,cd0NWMMMMMMMMMMMMN0o,.<br />
MMMMMMWWNX0d:;ckKNWMMMMMMMMMMWN0xl,.<br />
lllcc:;,'.. ..,;:clloollc:,..<br />
</pre><br />
<br /><br />
The MOTD can be previewed without needing to start a new shell session:<br />
<pre class="terminal"><br />
sudo run-parts /etc/update-motd.d/<br />
</pre><br />
<br /><br />
<br />
= SSH Logins Without Typing The Password =<br />
If you connect to a remote computer via ''ssh'' or copy files via ''scp'' frequently, you should consider using ''ssh-agent'', which saves you from typing your login password each time.<br />
<br /><br />
<br /><br />
First, you create an RSA public/private key pair that identifies your local machine. You may already have created such a key in your SSH keychain. It is good security practice, however, to use a separate key for each device you want to connect to. Let us assume you want to connect to a [[Raspberry Pi]]. The command to create a new SSH key would be<br />
<pre class="terminal"><br />
ssh-keygen -t rsa -b 2048 -C "for Raspberry Pi"<br />
</pre><br />
where '-b 2048' specifies the key length in bits. You will be prompted to enter the path and name of the file in which the key will be saved. Choose a name that makes it clear that it was created for connecting to the Raspberry Pi. Next, you will be prompted for a password. Just press the Enter key for no password.<br />
<br /><br />
<br /><br />
Now that the SSH key is created, you need to copy the generated key ('''public''') into the folder ''/home/pi/.ssh/'' on the Raspberry Pi:<br />
<pre class="terminal"><br />
scp ~/.ssh/for-raspberry-pi_rsa.pub pi@192.168.1.10:/home/pi/.ssh/authorized_keys<br />
</pre><br />
The copied file is renamed to '''authorized_keys''', which is the expected file name for the SSH server to look up the public keys of trusted clients.<br />
<br /><br />
If ''authorized_keys'' is to hold multiple keys, you should use '''ssh-copy-id''' instead of ''scp'':<br />
<pre class="terminal"><br />
ssh-copy-id -i ~/.ssh/for-raspberry-pi_rsa.pub pi@192.168.1.10<br />
</pre><br />
<br /><br />
Now use ''ssh-agent'' on your local machine to start a special shell session that uses the new SSH key to automatically authenticate any SSH connection from your machine to the Raspberry Pi:<br />
<pre class="terminal"><br />
eval "$(ssh-agent -s)" # starting a new shell session<br />
ssh-add ~/.ssh/for-raspberry-pi_rsa<br />
</pre><br />
Done! This was the last time you had to enter the password for user ''pi''.<br />
<br /><br />
<br /><br />
By the way, you can list all the keys that were added to the SSH agent by entering<br />
<pre class="terminal"><br />
ssh-add -l<br />
</pre><br />
<br /><br />
<br />
<br />
= Bluetooth =<br />
On most Linux systems, Bluetooth functionality is provided by the kernel module, libraries and utilities of the [http://www.bluez.org BlueZ] project. So, make sure that BlueZ is installed.<br />
<pre class="terminal"><br />
sudo apt install bluez<br />
</pre><br />
<br /><br />
<br />
== Bluetooth Low Energy (BLE) Control in Terminal ==<br />
Set the Bluetooth controller to operate in BLE mode only by editing '''/etc/bluetooth/main.conf''' to make sure that the value of ''ControllerMode'' is set to ''le''.<br />
<pre class="code"><br />
ControllerMode = le<br />
</pre><br />
If a change had to be made, you need to reboot the system.<br />
<br /><br />
<br /><br />
Now issue the command <br />
<pre class="terminal"><br />
sudo systemctl start bluetooth<br />
</pre><br />
to start the ''bluetooth'' service. You can also stop, restart and query the status with by replacing ''start'' with ''stop'', ''restart'', ''status'', respectively.<br />
<br /><br />
<br /><br />
With the bluetooth service running, enter the command<br />
<pre class="terminal"><br />
bluetoothctl<br />
</pre><br />
which runs a Bluetooth control program in the terminal. In this program you can, for example, display the list of commands, query the controller, power on the controller, scan for devices with RSSI 80 or better, advertise with the local name ''RPi3'' and, finally, power off and quit the program with the following commands: <br />
<pre class="terminal"><br />
help<br />
show<br />
power on<br />
menu scan<br />
rssi 80<br />
back<br />
scan on<br />
...<br />
scan off<br />
discoverable on<br />
advertise on<br />
menu advertise<br />
name RPi3<br />
back<br />
...<br />
advertise off<br />
power off<br />
quit<br />
</pre><br />
<br />
<br />
== Bluetooth Programming with D-Bus ==<br />
Here is an (incomplete!) example of programming D-Bus in C++ using the [https://github.com/Kistler-Group/sdbus-cpp/blob/master/docs/using-sdbus-c++.md sdbus-c++] C++ binding, for which you need to install ''libsdbus-c++-dev''.<br />
<pre class="terminal"><br />
sudo apt install libbluetooth-dev libsdbus-c++-dev<br />
</pre><br />
<br /><br />
<br />
Inspired by [https://punchthrough.com/creating-a-ble-peripheral-with-bluez/ this article from PunchThrough's Andy Lee], I have created a basic BLE peripheral.<br />
<pre class="code"><br />
#include <sdbus-c++/sdbus-c++.h><br />
#include <iostream><br />
<br />
/**<br />
* Names of D-Bus system services can be looked up with the terminal command<br />
*<br />
* busctl list<br />
*<br />
* We see that the name of the D-Bus system service of the bluetooth daemon is 'org.bluez'.<br />
* The D-Bus object path for a given system service can be queried with the terminal command<br />
*<br />
* busctl tree <service name><br />
*<br />
* For 'org.bluez' let us assume the object path is '/org/bluez/hci0'.<br />
* We can now introspect the interfaces available in the D-Bus object via<br />
*<br />
* busctl introspect org.bluez /org/bluez/hci0<br />
*<br />
* or<br />
*<br />
* gdbus introspect -y -d "org.bluez" -o "/org/bluez/hci0"<br />
* <br />
* We will use to the methods and properties in the published interfaces<br />
* to create a BLE peripheral which advertises a service named 'Test'.<br />
* Additional information on the methods and their parameters can be looked up from<br />
* the BlueZ documentation at https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc<br />
*/<br />
int main(int numargs, char* args[])<br />
{<br />
const char* bluezServiceName = "org.bluez";<br />
const char* bluezObjectPath = "/org/bluez/hci0";<br />
const char* interface_adapter = "org.bluez.Adapter1";<br />
const char* interface_advertisingManager = "org.bluez.LEAdvertisingManager1";<br />
auto bluezProxy = sdbus::createProxy(bluezServiceName, bluezObjectPath);<br />
if (bluezProxy == nullptr)<br />
{<br />
std::cerr << "Error while creating proxy to BlueZ D-Bus service." << std::endl;<br />
return EXIT_FAILURE;<br />
}<br />
bluezProxy->setProperty("Powered").onInterface(interface_adapter).toValue(true);<br />
bluezProxy->setProperty("Alias").onInterface(interface_adapter).toValue("Test");<br />
<br />
// TO BE DONE<br />
<br />
bluezProxy->finishRegistration();<br />
std::cout << "BLE Peripheral Example" << std::endl;<br />
<br />
return EXIT_SUCCESS;<br />
}<br />
<br />
</pre><br />
<br /><br />
<br />
build with<br />
<pre class="terminal"><br />
my_arch=`uname -i`<br />
g++ -o ble-peripheral main.cpp -L/usr/lib/${my_arch}-linux-gnu -lsdbus-c++<br />
</pre><br />
<br /><br />
<br />
= Video4Linux =<br />
Video4Linux is the video pipeline control system in Linux. Start by installing the required packages. On a Debian distribution, type<br />
<pre class="terminal"><br />
sudo apt install libv4l-0 v4l-utils v4l-conf libv4lconvert0<br />
<br />
v4l2-ctl --list-devices<br />
</pre><br />
<br /><br />
<br />
<br />
= C++ programming notes =<br />
== Platform detection ==<br />
To detect whether code is compiled for the Linux platform you can check if ''__linux__'' is defined.<br />
<pre class="code"><br />
#ifdef __linux__<br />
</pre><br />
(here you can find [https://sourceforge.net/p/predef/wiki/OperatingSystems preprocessor definitions for many operating systems])<br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Yocto&diff=3136Yocto2022-12-23T22:14:13Z<p>Kai: </p>
<hr />
<div>= Prerequisites =<br />
<pre class=terminal><br />
sudo apt install gcc g++ \<br />
python3-distutils python-is-python3<br />
</pre><br />
<br /><br />
<br />
= Images =<br />
<br />
Images are recipes that ultimately inherit from '''meta/classes/image.bbclass''' and set the global variable '''IMAGE_INSTALL'''. Most images, however, will inherit from ''meta/classes/core-image.bbclass'' which inherits directly from ''image.bbclass'', provides a mapping from ''IMAGE_FEATURES'' to package groups, and adds the two package groups ''packagegroup-core-boot'' and ''packagegroup-base-extended'' to ''IMAGE_INSTALL''.<br />
<br />
Images are defined in recipe files with the file extension 'bb'. In order to separate them from package recipes, there is a convention to put image recipes into a folder named ''images''. Making use of this, we can list all images defined by all layers via<br />
<pre class="terminal"><br />
cd poky<br />
ls meta*/recipes*/images/*.bb<br />
</pre><br />
<br /><br />
<br />
=== ''IMAGE_FEATURES'' ===<br />
The ''IMAGE_FEATURES'' variable is defined in ''meta/classes/image.bbclass'' with an empty value. It accepts only a predefined set of features (e.g., ''x11'', ''debug-tweaks'', ''dev-pkgs'', ''dbg-pkgs''). This affects how recipes will execute their tasks and which packages will be selected to go into the image. The image recipe ''meta/recipes-core/images/core-image-base.bb'', for example, adds the ''splash'' feature.<br />
<br /><br />
<br />
=== ''IMAGE_INSTALL'' ===<br />
Holds a list of package groups whose packages (from the package feed area) will go into the filesystem image.<br />
<br /><br />
<br />
== Reference images ==<br />
The following reference images are defined in the ''meta'' layer:<br />
{| style="padding: 10px;"<br />
! style="width: 20px" | || || <br />
|-<br />
| || ''core-image-minimal'' || small image that just boots the target device<br />
|-<br />
| || ''core-image-minimal-dev'' || ''core-image-minimal'' with headers and libraries allowing development work<br />
|-<br />
| || style="padding-right: 10px" | ''core-image-minimal-initramfs'' || ''core-image-minimal'' with kernel support for in-RAM filesystem<br />
|-<br />
| || '''core-image-base''' || '''console-only system fully supporting the target hardware'''<br />
|-<br />
| || ''core-image-full-cmdline'' || console-only image that includes many system tools<br />
|-<br />
| || ''core-image-x11'' || image with basic X11 and a terminal<br />
|-<br />
|}<br />
<br />
These image definitions are provided as a starting point for creating project-specific, custom image definitions.<br />
<br /><br />
<br /><br />
<br />
== Creating a Custom Image ==<br />
* In your custom layer, create the ''images'' subdirectory in one of your ''recipes-...' directory.<br />
* In the ''images'' directory, create two image recipe files that inherit from ''core-image'':<br />
<pre class="code"><br />
SUMMARY = "My deployment image"<br />
LICENSE = "MIT"<br />
<br />
inherit core-image<br />
IMAGE_FEATURES += "splash"<br />
</pre><br />
and<br />
<pre class="code"><br />
SUMMARY = "My development image"<br />
<br />
inherit core-image<br />
require my-image.bb<br />
<br />
IMAGE_FEATURES += "ssh-server-dropbear tools-debug debug-tweaks"<br />
<br />
CORE_IMAGE_EXTRA_INSTALL += "i2c-tools "<br />
</pre><br />
where the first image recipe is for deployment and the second is for development. Note that the development version includes the deployment version with the ''require'' statement, and adds to IMAGE_FEATURES and CORE_IMAGE_EXTRA_INSTALL.<br />
<br /><br />
<br />
== Image Filesystem Packaging ==<br />
The system image generated by Bitbake can be packaged in the form of an image file, whose contents can be transferred on a boot medium (SD card or eMMC) such that the primary boot loader of the target device can discover the system and boot it.<br />
<br />
Unless you restrict the type of packaging used for the image file, Yocto will generate multiple rootfs packages, each with a large footprint. To restrict the generated image files to a desired type, edit ''conf/local.conf'' of your project build directory and set the type.<br />
<pre class="code"><br />
#IMAGE_FSTYPES = "tar.gz"<br />
#IMAGE_FSTYPES = "tar.bz2"<br />
IMAGE_FSTYPES = "wic.bz2 wic.bmap"<br />
</pre><br />
The wic ([https://pykickstart.readthedocs.io/en/latest/kickstart-docs.html kickstart]) format with accompanying [https://github.com/intel/bmap-tools bmap] is recommended.<br />
<br /><br />
<br />
== Installing the Rootfs Image ==<br />
Using [https://github.com/intel/bmap-tools bmaptool] we can copy the generated ''wic'' image (with matching bmap file) to a mounted SD card or eMMC storage.<br />
<pre class="terminal"><br />
sudo bmaptool copy tmp/deploy/images/raspberrypi4-64/<wic.bz2 file> <drive><br />
</pre><br />
where ''<wic.bz2 file>'' is the root filesystem image wic.bz2 file, and ''<drive>'' is the drive at which the storage is mounted (for example, ''/dev/sdb'').<br />
<br /><br />
<br /><br />
<br />
= Package Groups =<br />
Package groups are recipes that inherit from '''meta/classes/packagegroup.bbclass''' and set the content of the global variable '''PACKAGES'''. Package groups are defined in recipe files with the file extension 'bb'.<br />
<br /><br />
<br /><br />
Note that the ''packagegroup'' must be inherited before ''PACKAGES is defined.<br />
<pre class="code"><br />
inherit packagegroup<br />
<br />
PACKAGES = '...'<br />
</pre><br />
<br /><br />
<br />
= Useful Image Features =<br />
<br /><br />
<br />
== Distro Features ==<br />
Distro features are system features that affect multiple recipes. '''Large parts of the Poky image may need to be rebaked after making changes to the distro features!'''<br />
<br /><br />
<br />
=== systemd ===<br />
In the ''conf/local.conf'' file of your project build directory (or ''layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " systemd"<br />
</pre><br />
<br /><br />
<br />
=== NFS ===<br />
In Embedded Linux projects, NFS is often included in development images to enable faster code-deploy turnaround times.<br />
<br /><br />
In the ''conf/local.conf'' file of your Yocto build directory (or ''conf/layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " nfs"<br />
</pre><br />
<br /><br />
On your Debian-based Yocto machine, [[Ubuntu#Setting_up_an_NFS_Server|set up an SSH server]].<br />
<br /><br />
<br /><br />
In Yocto, use the directory<br />
<br /><br />
: '''{YOCTO_BUILD_DIR}/tmp/work/{TARGET}-poky-linux/{IMAGE}/1.0-r0/rootfs'''<br />
as the root directory provided by the NFS server. For example,<br />
: ''build-robofish-core/tmp/work/raspberrypi4_64-poky-linux/robofish-core-image-dev/1.0-r0/rootfs''<br />
<br /><br />
<br /><br />
<br />
=== [https://vulkan.org Vulkan] and [https://opengl.org OpenGL] ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " vulkan opengl x11 wayland"<br />
</pre><br />
<br /><br />
<br />
=== Bluetooth and NFC ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " bluetooth nfc"<br />
</pre><br />
<br /><br />
<br />
= Accessing the OpenEmbedded recipe collection =<br />
The OpenEmbedded project provides recipes for many useful programs that are not included with Yocto, like tmux, VLC, Gnome, various multimedia codecs, more filesystems, gRPC and much more.<br />
<br /><br />
To access the recipes for those software packages, clone the OpenEmbedded layers repository into your third-party layers directory: <br />
<pre class="terminal"><br />
git clone git://git.openembedded.org/meta-openembedded<br />
</pre><br />
<br /><br />
<br />
= devtool =<br />
<br />
Use '''devtool''' to make changes to an existing recipe and automatically generate an append recipe from those changes.<br />
<br /><br />
<br /><br />
<br />
== Initialization Manager ==<br />
After the kernel is done with its basic booting tasks, it passes control to the initialization manager. To use the ''systemd'' initialization manager (used by the Linux distributions Debian and Ubuntu) instead of ''SysVinit'', make the following entries in ''${TOPDIR}/conf/distro/distro.conf''<br />
<pre class="code"><br />
DISTRO_FEATURES_append = " systemd"<br />
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"<br />
VIRTUAL-RUNTIME_init_manager = "systemd"<br />
VIRTUAL-RUNTIME_initscripts = ""<br />
</pre><br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Yocto&diff=3135Yocto2022-12-22T01:25:03Z<p>Kai: /* NFS */</p>
<hr />
<div>= Prerequisites =<br />
<pre class=terminal><br />
sudo apt install gcc g++ \<br />
python3-distutils python-is-python3<br />
</pre><br />
<br /><br />
<br />
= Images =<br />
<br />
Images are recipes that ultimately inherit from '''meta/classes/image.bbclass''' and set the global variable '''IMAGE_INSTALL'''. Most images, however, will inherit from ''meta/classes/core-image.bbclass'' which inherits directly from ''image.bbclass'', provides a mapping from ''IMAGE_FEATURES'' to package groups, and adds the two package groups ''packagegroup-core-boot'' and ''packagegroup-base-extended'' to ''IMAGE_INSTALL''.<br />
<br />
Images are defined in recipe files with the file extension 'bb'. In order to separate them from package recipes, there is a convention to put image recipes into a folder named ''images''. Making use of this, we can list all images defined by all layers via<br />
<pre class="terminal"><br />
cd poky<br />
ls meta*/recipes*/images/*.bb<br />
</pre><br />
<br /><br />
<br />
=== ''IMAGE_FEATURES'' ===<br />
The ''IMAGE_FEATURES'' variable is defined in ''meta/classes/image.bbclass'' with an empty value. It accepts only a predefined set of features (e.g., ''x11'', ''debug-tweaks'', ''dev-pkgs'', ''dbg-pkgs''). This affects how recipes will execute their tasks and which packages will be selected to go into the image. The image recipe ''meta/recipes-core/images/core-image-base.bb'', for example, adds the ''splash'' feature.<br />
<br /><br />
<br />
=== ''IMAGE_INSTALL'' ===<br />
Holds a list of package groups whose packages (from the package feed area) will go into the filesystem image.<br />
<br /><br />
<br />
== Reference images ==<br />
The following reference images are defined in the ''meta'' layer:<br />
{| style="padding: 10px;"<br />
! style="width: 20px" | || || <br />
|-<br />
| || ''core-image-minimal'' || small image that just boots the target device<br />
|-<br />
| || ''core-image-minimal-dev'' || ''core-image-minimal'' with headers and libraries allowing development work<br />
|-<br />
| || style="padding-right: 10px" | ''core-image-minimal-initramfs'' || ''core-image-minimal'' with kernel support for in-RAM filesystem<br />
|-<br />
| || '''core-image-base''' || '''console-only system fully supporting the target hardware'''<br />
|-<br />
| || ''core-image-full-cmdline'' || console-only image that includes many system tools<br />
|-<br />
| || ''core-image-x11'' || image with basic X11 and a terminal<br />
|-<br />
|}<br />
<br />
These image definitions are provided as a starting point for creating project-specific, custom image definitions.<br />
<br /><br />
<br /><br />
<br />
== Creating a Custom Image ==<br />
* In your custom layer, create the ''images'' subdirectory in one of your ''recipes-...' directory.<br />
* In the ''images'' directory, create two image recipe files that inherit from ''core-image'':<br />
<pre class="code"><br />
SUMMARY = "My deployment image"<br />
LICENSE = "MIT"<br />
<br />
inherit core-image<br />
IMAGE_FEATURES += "splash"<br />
</pre><br />
and<br />
<pre class="code"><br />
SUMMARY = "My development image"<br />
<br />
inherit core-image<br />
require my-image.bb<br />
<br />
IMAGE_FEATURES += "ssh-server-dropbear tools-debug debug-tweaks"<br />
<br />
CORE_IMAGE_EXTRA_INSTALL += "i2c-tools "<br />
</pre><br />
where the first image recipe is for deployment and the second is for development. Note that the development version includes the deployment version with the ''require'' statement, and adds to IMAGE_FEATURES and CORE_IMAGE_EXTRA_INSTALL.<br />
<br /><br />
<br />
== Image Filesystem Packaging ==<br />
The system image generated by Bitbake can be packaged in the form of an image file, whose contents can be transferred on a boot medium (SD card or eMMC) such that the primary boot loader of the target device can discover the system and boot it.<br />
<br />
Unless you restrict the type of packaging used for the image file, Yocto will generate multiple rootfs packages, each with a large footprint. To restrict the generated image files to a desired type, edit ''conf/local.conf'' of your project build directory and set the type.<br />
<pre class="code"><br />
#IMAGE_FSTYPES = "tar.gz"<br />
#IMAGE_FSTYPES = "tar.bz2"<br />
IMAGE_FSTYPES = "wic.bz2 wic.bmap"<br />
</pre><br />
The wic ([https://pykickstart.readthedocs.io/en/latest/kickstart-docs.html kickstart]) format with accompanying [https://github.com/intel/bmap-tools bmap] is recommended.<br />
<br /><br />
<br />
== Installing the Rootfs Image ==<br />
Using [https://github.com/intel/bmap-tools bmaptool] we can copy the generated ''wic'' image (with matching bmap file) to a mounted SD card or eMMC storage.<br />
<pre class="terminal"><br />
sudo bmaptool copy tmp/deploy/images/raspberrypi4-64/<wic.bz2 file> <drive><br />
</pre><br />
where ''<wic.bz2 file>'' is the root filesystem image wic.bz2 file, and ''<drive>'' is the drive at which the storage is mounted (for example, ''/dev/sdb'').<br />
<br /><br />
<br /><br />
<br />
= Package Groups =<br />
Package groups are recipes that inherit from '''meta/classes/packagegroup.bbclass''' and set the content of the global variable '''PACKAGES'''. Package groups are defined in recipe files with the file extension 'bb'.<br />
<br /><br />
<br /><br />
Note that the ''packagegroup'' must be inherited before ''PACKAGES is defined.<br />
<pre class="code"><br />
inherit packagegroup<br />
<br />
PACKAGES = '...'<br />
</pre><br />
<br /><br />
<br />
= Useful Image Features =<br />
<br /><br />
<br />
== Distro Features ==<br />
Distro features are system features that affect multiple recipes. '''Large parts of the Poky image may need to be rebaked after making changes to the distro features!'''<br />
<br /><br />
<br />
=== systemd ===<br />
In the ''conf/local.conf'' file of your project build directory (or ''layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " systemd"<br />
</pre><br />
<br /><br />
<br />
=== NFS ===<br />
In Embedded Linux projects, NFS is often included in development images to enable faster code-deploy turnaround times.<br />
<br /><br />
In the ''conf/local.conf'' file of your Yocto build directory (or ''conf/layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " nfs"<br />
</pre><br />
<br /><br />
On your Debian-based Yocto machine, [[Ubuntu#Setting_up_an_NFS_Server|set up an SSH server]].<br />
<br /><br />
<br /><br />
In Yocto, use the directory<br />
<br /><br />
: '''{YOCTO_BUILD_DIR}/tmp/work/{TARGET}-poky-linux/{IMAGE}/1.0-r0/rootfs'''<br />
as the root directory provided by the NFS server. For example,<br />
: ''build-robofish-core/tmp/work/raspberrypi4_64-poky-linux/robofish-core-image-dev/1.0-r0/rootfs''<br />
<br /><br />
<br /><br />
<br />
=== [https://vulkan.org Vulkan] and [https://opengl.org OpenGL] ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " vulkan opengl x11 wayland"<br />
</pre><br />
<br /><br />
<br />
=== Bluetooth and NFC ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " bluetooth nfc"<br />
</pre><br />
<br /><br />
<br />
= devtool =<br />
<br />
Use '''devtool''' to make changes to an existing recipe and automatically generate an append recipe from those changes.<br />
<br /><br />
<br /><br />
<br />
== Initialization Manager ==<br />
After the kernel is done with its basic booting tasks, it passes control to the initialization manager. To use the ''systemd'' initialization manager (used by the Linux distributions Debian and Ubuntu) instead of ''SysVinit'', make the following entries in ''${TOPDIR}/conf/distro/distro.conf''<br />
<pre class="code"><br />
DISTRO_FEATURES_append = " systemd"<br />
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"<br />
VIRTUAL-RUNTIME_init_manager = "systemd"<br />
VIRTUAL-RUNTIME_initscripts = ""<br />
</pre><br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Yocto&diff=3134Yocto2022-12-21T08:19:22Z<p>Kai: /* Installing the Rootfs Image */</p>
<hr />
<div>= Prerequisites =<br />
<pre class=terminal><br />
sudo apt install gcc g++ \<br />
python3-distutils python-is-python3<br />
</pre><br />
<br /><br />
<br />
= Images =<br />
<br />
Images are recipes that ultimately inherit from '''meta/classes/image.bbclass''' and set the global variable '''IMAGE_INSTALL'''. Most images, however, will inherit from ''meta/classes/core-image.bbclass'' which inherits directly from ''image.bbclass'', provides a mapping from ''IMAGE_FEATURES'' to package groups, and adds the two package groups ''packagegroup-core-boot'' and ''packagegroup-base-extended'' to ''IMAGE_INSTALL''.<br />
<br />
Images are defined in recipe files with the file extension 'bb'. In order to separate them from package recipes, there is a convention to put image recipes into a folder named ''images''. Making use of this, we can list all images defined by all layers via<br />
<pre class="terminal"><br />
cd poky<br />
ls meta*/recipes*/images/*.bb<br />
</pre><br />
<br /><br />
<br />
=== ''IMAGE_FEATURES'' ===<br />
The ''IMAGE_FEATURES'' variable is defined in ''meta/classes/image.bbclass'' with an empty value. It accepts only a predefined set of features (e.g., ''x11'', ''debug-tweaks'', ''dev-pkgs'', ''dbg-pkgs''). This affects how recipes will execute their tasks and which packages will be selected to go into the image. The image recipe ''meta/recipes-core/images/core-image-base.bb'', for example, adds the ''splash'' feature.<br />
<br /><br />
<br />
=== ''IMAGE_INSTALL'' ===<br />
Holds a list of package groups whose packages (from the package feed area) will go into the filesystem image.<br />
<br /><br />
<br />
== Reference images ==<br />
The following reference images are defined in the ''meta'' layer:<br />
{| style="padding: 10px;"<br />
! style="width: 20px" | || || <br />
|-<br />
| || ''core-image-minimal'' || small image that just boots the target device<br />
|-<br />
| || ''core-image-minimal-dev'' || ''core-image-minimal'' with headers and libraries allowing development work<br />
|-<br />
| || style="padding-right: 10px" | ''core-image-minimal-initramfs'' || ''core-image-minimal'' with kernel support for in-RAM filesystem<br />
|-<br />
| || '''core-image-base''' || '''console-only system fully supporting the target hardware'''<br />
|-<br />
| || ''core-image-full-cmdline'' || console-only image that includes many system tools<br />
|-<br />
| || ''core-image-x11'' || image with basic X11 and a terminal<br />
|-<br />
|}<br />
<br />
These image definitions are provided as a starting point for creating project-specific, custom image definitions.<br />
<br /><br />
<br /><br />
<br />
== Creating a Custom Image ==<br />
* In your custom layer, create the ''images'' subdirectory in one of your ''recipes-...' directory.<br />
* In the ''images'' directory, create two image recipe files that inherit from ''core-image'':<br />
<pre class="code"><br />
SUMMARY = "My deployment image"<br />
LICENSE = "MIT"<br />
<br />
inherit core-image<br />
IMAGE_FEATURES += "splash"<br />
</pre><br />
and<br />
<pre class="code"><br />
SUMMARY = "My development image"<br />
<br />
inherit core-image<br />
require my-image.bb<br />
<br />
IMAGE_FEATURES += "ssh-server-dropbear tools-debug debug-tweaks"<br />
<br />
CORE_IMAGE_EXTRA_INSTALL += "i2c-tools "<br />
</pre><br />
where the first image recipe is for deployment and the second is for development. Note that the development version includes the deployment version with the ''require'' statement, and adds to IMAGE_FEATURES and CORE_IMAGE_EXTRA_INSTALL.<br />
<br /><br />
<br />
== Image Filesystem Packaging ==<br />
The system image generated by Bitbake can be packaged in the form of an image file, whose contents can be transferred on a boot medium (SD card or eMMC) such that the primary boot loader of the target device can discover the system and boot it.<br />
<br />
Unless you restrict the type of packaging used for the image file, Yocto will generate multiple rootfs packages, each with a large footprint. To restrict the generated image files to a desired type, edit ''conf/local.conf'' of your project build directory and set the type.<br />
<pre class="code"><br />
#IMAGE_FSTYPES = "tar.gz"<br />
#IMAGE_FSTYPES = "tar.bz2"<br />
IMAGE_FSTYPES = "wic.bz2 wic.bmap"<br />
</pre><br />
The wic ([https://pykickstart.readthedocs.io/en/latest/kickstart-docs.html kickstart]) format with accompanying [https://github.com/intel/bmap-tools bmap] is recommended.<br />
<br /><br />
<br />
== Installing the Rootfs Image ==<br />
Using [https://github.com/intel/bmap-tools bmaptool] we can copy the generated ''wic'' image (with matching bmap file) to a mounted SD card or eMMC storage.<br />
<pre class="terminal"><br />
sudo bmaptool copy tmp/deploy/images/raspberrypi4-64/<wic.bz2 file> <drive><br />
</pre><br />
where ''<wic.bz2 file>'' is the root filesystem image wic.bz2 file, and ''<drive>'' is the drive at which the storage is mounted (for example, ''/dev/sdb'').<br />
<br /><br />
<br /><br />
<br />
= Package Groups =<br />
Package groups are recipes that inherit from '''meta/classes/packagegroup.bbclass''' and set the content of the global variable '''PACKAGES'''. Package groups are defined in recipe files with the file extension 'bb'.<br />
<br /><br />
<br /><br />
Note that the ''packagegroup'' must be inherited before ''PACKAGES is defined.<br />
<pre class="code"><br />
inherit packagegroup<br />
<br />
PACKAGES = '...'<br />
</pre><br />
<br /><br />
<br />
= Useful Image Features =<br />
<br /><br />
<br />
== Distro Features ==<br />
Distro features are system features that affect multiple recipes. '''Large parts of the Poky image may need to be rebaked after making changes to the distro features!'''<br />
<br /><br />
<br />
=== systemd ===<br />
In the ''conf/local.conf'' file of your project build directory (or ''layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " systemd"<br />
</pre><br />
<br /><br />
<br />
=== NFS ===<br />
In Embedded Linux projects, NFS is often included in development images to enable faster code-deploy turnaround times.<br />
<br /><br />
In the ''conf/local.conf'' file of your project build directory (or ''layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " nfs"<br />
</pre><br />
<br /><br />
<br />
=== [https://vulkan.org Vulkan] and [https://opengl.org OpenGL] ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " vulkan opengl x11 wayland"<br />
</pre><br />
<br /><br />
<br />
=== Bluetooth and NFC ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " bluetooth nfc"<br />
</pre><br />
<br /><br />
<br />
= devtool =<br />
<br />
Use '''devtool''' to make changes to an existing recipe and automatically generate an append recipe from those changes.<br />
<br /><br />
<br /><br />
<br />
== Initialization Manager ==<br />
After the kernel is done with its basic booting tasks, it passes control to the initialization manager. To use the ''systemd'' initialization manager (used by the Linux distributions Debian and Ubuntu) instead of ''SysVinit'', make the following entries in ''${TOPDIR}/conf/distro/distro.conf''<br />
<pre class="code"><br />
DISTRO_FEATURES_append = " systemd"<br />
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"<br />
VIRTUAL-RUNTIME_init_manager = "systemd"<br />
VIRTUAL-RUNTIME_initscripts = ""<br />
</pre><br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Yocto&diff=3133Yocto2022-12-21T08:02:02Z<p>Kai: /* Image Filesystem Packaging */</p>
<hr />
<div>= Prerequisites =<br />
<pre class=terminal><br />
sudo apt install gcc g++ \<br />
python3-distutils python-is-python3<br />
</pre><br />
<br /><br />
<br />
= Images =<br />
<br />
Images are recipes that ultimately inherit from '''meta/classes/image.bbclass''' and set the global variable '''IMAGE_INSTALL'''. Most images, however, will inherit from ''meta/classes/core-image.bbclass'' which inherits directly from ''image.bbclass'', provides a mapping from ''IMAGE_FEATURES'' to package groups, and adds the two package groups ''packagegroup-core-boot'' and ''packagegroup-base-extended'' to ''IMAGE_INSTALL''.<br />
<br />
Images are defined in recipe files with the file extension 'bb'. In order to separate them from package recipes, there is a convention to put image recipes into a folder named ''images''. Making use of this, we can list all images defined by all layers via<br />
<pre class="terminal"><br />
cd poky<br />
ls meta*/recipes*/images/*.bb<br />
</pre><br />
<br /><br />
<br />
=== ''IMAGE_FEATURES'' ===<br />
The ''IMAGE_FEATURES'' variable is defined in ''meta/classes/image.bbclass'' with an empty value. It accepts only a predefined set of features (e.g., ''x11'', ''debug-tweaks'', ''dev-pkgs'', ''dbg-pkgs''). This affects how recipes will execute their tasks and which packages will be selected to go into the image. The image recipe ''meta/recipes-core/images/core-image-base.bb'', for example, adds the ''splash'' feature.<br />
<br /><br />
<br />
=== ''IMAGE_INSTALL'' ===<br />
Holds a list of package groups whose packages (from the package feed area) will go into the filesystem image.<br />
<br /><br />
<br />
== Reference images ==<br />
The following reference images are defined in the ''meta'' layer:<br />
{| style="padding: 10px;"<br />
! style="width: 20px" | || || <br />
|-<br />
| || ''core-image-minimal'' || small image that just boots the target device<br />
|-<br />
| || ''core-image-minimal-dev'' || ''core-image-minimal'' with headers and libraries allowing development work<br />
|-<br />
| || style="padding-right: 10px" | ''core-image-minimal-initramfs'' || ''core-image-minimal'' with kernel support for in-RAM filesystem<br />
|-<br />
| || '''core-image-base''' || '''console-only system fully supporting the target hardware'''<br />
|-<br />
| || ''core-image-full-cmdline'' || console-only image that includes many system tools<br />
|-<br />
| || ''core-image-x11'' || image with basic X11 and a terminal<br />
|-<br />
|}<br />
<br />
These image definitions are provided as a starting point for creating project-specific, custom image definitions.<br />
<br /><br />
<br /><br />
<br />
== Creating a Custom Image ==<br />
* In your custom layer, create the ''images'' subdirectory in one of your ''recipes-...' directory.<br />
* In the ''images'' directory, create two image recipe files that inherit from ''core-image'':<br />
<pre class="code"><br />
SUMMARY = "My deployment image"<br />
LICENSE = "MIT"<br />
<br />
inherit core-image<br />
IMAGE_FEATURES += "splash"<br />
</pre><br />
and<br />
<pre class="code"><br />
SUMMARY = "My development image"<br />
<br />
inherit core-image<br />
require my-image.bb<br />
<br />
IMAGE_FEATURES += "ssh-server-dropbear tools-debug debug-tweaks"<br />
<br />
CORE_IMAGE_EXTRA_INSTALL += "i2c-tools "<br />
</pre><br />
where the first image recipe is for deployment and the second is for development. Note that the development version includes the deployment version with the ''require'' statement, and adds to IMAGE_FEATURES and CORE_IMAGE_EXTRA_INSTALL.<br />
<br /><br />
<br />
== Image Filesystem Packaging ==<br />
The system image generated by Bitbake can be packaged in the form of an image file, whose contents can be transferred on a boot medium (SD card or eMMC) such that the primary boot loader of the target device can discover the system and boot it.<br />
<br />
Unless you restrict the type of packaging used for the image file, Yocto will generate multiple rootfs packages, each with a large footprint. To restrict the generated image files to a desired type, edit ''conf/local.conf'' of your project build directory and set the type.<br />
<pre class="code"><br />
#IMAGE_FSTYPES = "tar.gz"<br />
#IMAGE_FSTYPES = "tar.bz2"<br />
IMAGE_FSTYPES = "wic.bz2 wic.bmap"<br />
</pre><br />
The wic ([https://pykickstart.readthedocs.io/en/latest/kickstart-docs.html kickstart]) format with accompanying [https://github.com/intel/bmap-tools bmap] is recommended.<br />
<br /><br />
<br />
== Installing the Rootfs Image ==<br />
Using Yocto's '''bmaptool''' we can copy the generated ''wic'' image (with matching bmap file) to a mounted SD card or eMMC storage.<br />
<pre class="terminal"><br />
sudo bmaptool copy tmp/deploy/images/raspberrypi4-64/<wic.bz2 file> <drive><br />
</pre><br />
where ''<wic.bz2 file>'' is the root filesystem image wic.bz2 file, and ''<drive>'' is the drive at which the storage is mounted (for example, ''/dev/sdb'').<br />
<br /><br />
<br /><br />
<br />
= Package Groups =<br />
Package groups are recipes that inherit from '''meta/classes/packagegroup.bbclass''' and set the content of the global variable '''PACKAGES'''. Package groups are defined in recipe files with the file extension 'bb'.<br />
<br /><br />
<br /><br />
Note that the ''packagegroup'' must be inherited before ''PACKAGES is defined.<br />
<pre class="code"><br />
inherit packagegroup<br />
<br />
PACKAGES = '...'<br />
</pre><br />
<br /><br />
<br />
= Useful Image Features =<br />
<br /><br />
<br />
== Distro Features ==<br />
Distro features are system features that affect multiple recipes. '''Large parts of the Poky image may need to be rebaked after making changes to the distro features!'''<br />
<br /><br />
<br />
=== systemd ===<br />
In the ''conf/local.conf'' file of your project build directory (or ''layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " systemd"<br />
</pre><br />
<br /><br />
<br />
=== NFS ===<br />
In Embedded Linux projects, NFS is often included in development images to enable faster code-deploy turnaround times.<br />
<br /><br />
In the ''conf/local.conf'' file of your project build directory (or ''layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " nfs"<br />
</pre><br />
<br /><br />
<br />
=== [https://vulkan.org Vulkan] and [https://opengl.org OpenGL] ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " vulkan opengl x11 wayland"<br />
</pre><br />
<br /><br />
<br />
=== Bluetooth and NFC ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " bluetooth nfc"<br />
</pre><br />
<br /><br />
<br />
= devtool =<br />
<br />
Use '''devtool''' to make changes to an existing recipe and automatically generate an append recipe from those changes.<br />
<br /><br />
<br /><br />
<br />
== Initialization Manager ==<br />
After the kernel is done with its basic booting tasks, it passes control to the initialization manager. To use the ''systemd'' initialization manager (used by the Linux distributions Debian and Ubuntu) instead of ''SysVinit'', make the following entries in ''${TOPDIR}/conf/distro/distro.conf''<br />
<pre class="code"><br />
DISTRO_FEATURES_append = " systemd"<br />
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"<br />
VIRTUAL-RUNTIME_init_manager = "systemd"<br />
VIRTUAL-RUNTIME_initscripts = ""<br />
</pre><br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Yocto&diff=3132Yocto2022-12-20T21:48:29Z<p>Kai: /* Useful Image Features */</p>
<hr />
<div>= Prerequisites =<br />
<pre class=terminal><br />
sudo apt install gcc g++ \<br />
python3-distutils python-is-python3<br />
</pre><br />
<br /><br />
<br />
= Images =<br />
<br />
Images are recipes that ultimately inherit from '''meta/classes/image.bbclass''' and set the global variable '''IMAGE_INSTALL'''. Most images, however, will inherit from ''meta/classes/core-image.bbclass'' which inherits directly from ''image.bbclass'', provides a mapping from ''IMAGE_FEATURES'' to package groups, and adds the two package groups ''packagegroup-core-boot'' and ''packagegroup-base-extended'' to ''IMAGE_INSTALL''.<br />
<br />
Images are defined in recipe files with the file extension 'bb'. In order to separate them from package recipes, there is a convention to put image recipes into a folder named ''images''. Making use of this, we can list all images defined by all layers via<br />
<pre class="terminal"><br />
cd poky<br />
ls meta*/recipes*/images/*.bb<br />
</pre><br />
<br /><br />
<br />
=== ''IMAGE_FEATURES'' ===<br />
The ''IMAGE_FEATURES'' variable is defined in ''meta/classes/image.bbclass'' with an empty value. It accepts only a predefined set of features (e.g., ''x11'', ''debug-tweaks'', ''dev-pkgs'', ''dbg-pkgs''). This affects how recipes will execute their tasks and which packages will be selected to go into the image. The image recipe ''meta/recipes-core/images/core-image-base.bb'', for example, adds the ''splash'' feature.<br />
<br /><br />
<br />
=== ''IMAGE_INSTALL'' ===<br />
Holds a list of package groups whose packages (from the package feed area) will go into the filesystem image.<br />
<br /><br />
<br />
== Reference images ==<br />
The following reference images are defined in the ''meta'' layer:<br />
{| style="padding: 10px;"<br />
! style="width: 20px" | || || <br />
|-<br />
| || ''core-image-minimal'' || small image that just boots the target device<br />
|-<br />
| || ''core-image-minimal-dev'' || ''core-image-minimal'' with headers and libraries allowing development work<br />
|-<br />
| || style="padding-right: 10px" | ''core-image-minimal-initramfs'' || ''core-image-minimal'' with kernel support for in-RAM filesystem<br />
|-<br />
| || '''core-image-base''' || '''console-only system fully supporting the target hardware'''<br />
|-<br />
| || ''core-image-full-cmdline'' || console-only image that includes many system tools<br />
|-<br />
| || ''core-image-x11'' || image with basic X11 and a terminal<br />
|-<br />
|}<br />
<br />
These image definitions are provided as a starting point for creating project-specific, custom image definitions.<br />
<br /><br />
<br /><br />
<br />
== Creating a Custom Image ==<br />
* In your custom layer, create the ''images'' subdirectory in one of your ''recipes-...' directory.<br />
* In the ''images'' directory, create two image recipe files that inherit from ''core-image'':<br />
<pre class="code"><br />
SUMMARY = "My deployment image"<br />
LICENSE = "MIT"<br />
<br />
inherit core-image<br />
IMAGE_FEATURES += "splash"<br />
</pre><br />
and<br />
<pre class="code"><br />
SUMMARY = "My development image"<br />
<br />
inherit core-image<br />
require my-image.bb<br />
<br />
IMAGE_FEATURES += "ssh-server-dropbear tools-debug debug-tweaks"<br />
<br />
CORE_IMAGE_EXTRA_INSTALL += "i2c-tools "<br />
</pre><br />
where the first image recipe is for deployment and the second is for development. Note that the development version includes the deployment version with the ''require'' statement, and adds to IMAGE_FEATURES and CORE_IMAGE_EXTRA_INSTALL.<br />
<br /><br />
<br />
== Image Filesystem Packaging ==<br />
The system image generated by Bitbake can be packaged in the form of an image file, whose contents can be transferred on a boot medium (SD card or eMMC) such that the primary boot loader of the target device can discover the system and boot it.<br />
<br />
Unless you restrict the type of packaging used for the image file, Yocto will generate multiple To restrict the generated image files (these are large files) to a certain <br />
<pre class="code"><br />
# Multiple types of image files are created by default.<br />
# Uncomment the desired lines below to prevent the<br />
# corresponding type of image file from being generated.<br />
#IMAGE_FSTYPES::remove = "tar.gz"<br />
#IMAGE_FSTYPES::remove = "tar.bz"<br />
#IMAGE_FSTYPES::remove = "wic.bz2 wic.bmap"<br />
</pre><br />
<br /><br />
<br />
== Installing the Rootfs Image ==<br />
Using Yocto's '''bmaptool''' we can copy the generated ''wic'' image (with matching bmap file) to a mounted SD card or eMMC storage.<br />
<pre class="terminal"><br />
sudo bmaptool copy tmp/deploy/images/raspberrypi4-64/<wic.bz2 file> <drive><br />
</pre><br />
where ''<wic.bz2 file>'' is the root filesystem image wic.bz2 file, and ''<drive>'' is the drive at which the storage is mounted (for example, ''/dev/sdb'').<br />
<br /><br />
<br /><br />
<br />
= Package Groups =<br />
Package groups are recipes that inherit from '''meta/classes/packagegroup.bbclass''' and set the content of the global variable '''PACKAGES'''. Package groups are defined in recipe files with the file extension 'bb'.<br />
<br /><br />
<br /><br />
Note that the ''packagegroup'' must be inherited before ''PACKAGES is defined.<br />
<pre class="code"><br />
inherit packagegroup<br />
<br />
PACKAGES = '...'<br />
</pre><br />
<br /><br />
<br />
= Useful Image Features =<br />
<br /><br />
<br />
== Distro Features ==<br />
Distro features are system features that affect multiple recipes. '''Large parts of the Poky image may need to be rebaked after making changes to the distro features!'''<br />
<br /><br />
<br />
=== systemd ===<br />
In the ''conf/local.conf'' file of your project build directory (or ''layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " systemd"<br />
</pre><br />
<br /><br />
<br />
=== NFS ===<br />
In Embedded Linux projects, NFS is often included in development images to enable faster code-deploy turnaround times.<br />
<br /><br />
In the ''conf/local.conf'' file of your project build directory (or ''layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " nfs"<br />
</pre><br />
<br /><br />
<br />
=== [https://vulkan.org Vulkan] and [https://opengl.org OpenGL] ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " vulkan opengl x11 wayland"<br />
</pre><br />
<br /><br />
<br />
=== Bluetooth and NFC ===<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " bluetooth nfc"<br />
</pre><br />
<br /><br />
<br />
= devtool =<br />
<br />
Use '''devtool''' to make changes to an existing recipe and automatically generate an append recipe from those changes.<br />
<br /><br />
<br /><br />
<br />
== Initialization Manager ==<br />
After the kernel is done with its basic booting tasks, it passes control to the initialization manager. To use the ''systemd'' initialization manager (used by the Linux distributions Debian and Ubuntu) instead of ''SysVinit'', make the following entries in ''${TOPDIR}/conf/distro/distro.conf''<br />
<pre class="code"><br />
DISTRO_FEATURES_append = " systemd"<br />
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"<br />
VIRTUAL-RUNTIME_init_manager = "systemd"<br />
VIRTUAL-RUNTIME_initscripts = ""<br />
</pre><br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Yocto&diff=3131Yocto2022-12-20T21:32:53Z<p>Kai: </p>
<hr />
<div>= Prerequisites =<br />
<pre class=terminal><br />
sudo apt install gcc g++ \<br />
python3-distutils python-is-python3<br />
</pre><br />
<br /><br />
<br />
= Images =<br />
<br />
Images are recipes that ultimately inherit from '''meta/classes/image.bbclass''' and set the global variable '''IMAGE_INSTALL'''. Most images, however, will inherit from ''meta/classes/core-image.bbclass'' which inherits directly from ''image.bbclass'', provides a mapping from ''IMAGE_FEATURES'' to package groups, and adds the two package groups ''packagegroup-core-boot'' and ''packagegroup-base-extended'' to ''IMAGE_INSTALL''.<br />
<br />
Images are defined in recipe files with the file extension 'bb'. In order to separate them from package recipes, there is a convention to put image recipes into a folder named ''images''. Making use of this, we can list all images defined by all layers via<br />
<pre class="terminal"><br />
cd poky<br />
ls meta*/recipes*/images/*.bb<br />
</pre><br />
<br /><br />
<br />
=== ''IMAGE_FEATURES'' ===<br />
The ''IMAGE_FEATURES'' variable is defined in ''meta/classes/image.bbclass'' with an empty value. It accepts only a predefined set of features (e.g., ''x11'', ''debug-tweaks'', ''dev-pkgs'', ''dbg-pkgs''). This affects how recipes will execute their tasks and which packages will be selected to go into the image. The image recipe ''meta/recipes-core/images/core-image-base.bb'', for example, adds the ''splash'' feature.<br />
<br /><br />
<br />
=== ''IMAGE_INSTALL'' ===<br />
Holds a list of package groups whose packages (from the package feed area) will go into the filesystem image.<br />
<br /><br />
<br />
== Reference images ==<br />
The following reference images are defined in the ''meta'' layer:<br />
{| style="padding: 10px;"<br />
! style="width: 20px" | || || <br />
|-<br />
| || ''core-image-minimal'' || small image that just boots the target device<br />
|-<br />
| || ''core-image-minimal-dev'' || ''core-image-minimal'' with headers and libraries allowing development work<br />
|-<br />
| || style="padding-right: 10px" | ''core-image-minimal-initramfs'' || ''core-image-minimal'' with kernel support for in-RAM filesystem<br />
|-<br />
| || '''core-image-base''' || '''console-only system fully supporting the target hardware'''<br />
|-<br />
| || ''core-image-full-cmdline'' || console-only image that includes many system tools<br />
|-<br />
| || ''core-image-x11'' || image with basic X11 and a terminal<br />
|-<br />
|}<br />
<br />
These image definitions are provided as a starting point for creating project-specific, custom image definitions.<br />
<br /><br />
<br /><br />
<br />
== Creating a Custom Image ==<br />
* In your custom layer, create the ''images'' subdirectory in one of your ''recipes-...' directory.<br />
* In the ''images'' directory, create two image recipe files that inherit from ''core-image'':<br />
<pre class="code"><br />
SUMMARY = "My deployment image"<br />
LICENSE = "MIT"<br />
<br />
inherit core-image<br />
IMAGE_FEATURES += "splash"<br />
</pre><br />
and<br />
<pre class="code"><br />
SUMMARY = "My development image"<br />
<br />
inherit core-image<br />
require my-image.bb<br />
<br />
IMAGE_FEATURES += "ssh-server-dropbear tools-debug debug-tweaks"<br />
<br />
CORE_IMAGE_EXTRA_INSTALL += "i2c-tools "<br />
</pre><br />
where the first image recipe is for deployment and the second is for development. Note that the development version includes the deployment version with the ''require'' statement, and adds to IMAGE_FEATURES and CORE_IMAGE_EXTRA_INSTALL.<br />
<br /><br />
<br />
== Image Filesystem Packaging ==<br />
The system image generated by Bitbake can be packaged in the form of an image file, whose contents can be transferred on a boot medium (SD card or eMMC) such that the primary boot loader of the target device can discover the system and boot it.<br />
<br />
Unless you restrict the type of packaging used for the image file, Yocto will generate multiple To restrict the generated image files (these are large files) to a certain <br />
<pre class="code"><br />
# Multiple types of image files are created by default.<br />
# Uncomment the desired lines below to prevent the<br />
# corresponding type of image file from being generated.<br />
#IMAGE_FSTYPES::remove = "tar.gz"<br />
#IMAGE_FSTYPES::remove = "tar.bz"<br />
#IMAGE_FSTYPES::remove = "wic.bz2 wic.bmap"<br />
</pre><br />
<br /><br />
<br />
== Installing the Rootfs Image ==<br />
Using Yocto's '''bmaptool''' we can copy the generated ''wic'' image (with matching bmap file) to a mounted SD card or eMMC storage.<br />
<pre class="terminal"><br />
sudo bmaptool copy tmp/deploy/images/raspberrypi4-64/<wic.bz2 file> <drive><br />
</pre><br />
where ''<wic.bz2 file>'' is the root filesystem image wic.bz2 file, and ''<drive>'' is the drive at which the storage is mounted (for example, ''/dev/sdb'').<br />
<br /><br />
<br /><br />
<br />
= Package Groups =<br />
Package groups are recipes that inherit from '''meta/classes/packagegroup.bbclass''' and set the content of the global variable '''PACKAGES'''. Package groups are defined in recipe files with the file extension 'bb'.<br />
<br /><br />
<br /><br />
Note that the ''packagegroup'' must be inherited before ''PACKAGES is defined.<br />
<pre class="code"><br />
inherit packagegroup<br />
<br />
PACKAGES = '...'<br />
</pre><br />
<br /><br />
<br />
= Useful Image Features =<br />
<br />
== systemd ==<br />
In the ''conf/local.conf'' file of your project build directory (or ''layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " systemd"<br />
</pre><br />
<br /><br />
<br />
== NFS ==<br />
In Embedded Linux projects, NFS is often included in development images to enable faster code-deploy turnaround times.<br />
<br /><br />
In the ''conf/local.conf'' file of your project build directory (or ''layer.conf'' file of your layer) add <br />
<pre class="code"><br />
DISTRO_FEATURES:append = " nfs"<br />
</pre><br />
<br /><br />
<br />
== Vulkan and OpenGL ==<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " vulkan opengl x11 wayland"<br />
</pre><br />
<br /><br />
<br />
== Bluetooth and NFC ==<br />
<pre class="code"><br />
DISTRO_FEATURES:append = " bluetooth nfc"<br />
</pre><br />
<br /><br />
<br />
= devtool =<br />
<br />
Use '''devtool''' to make changes to an existing recipe and automatically generate an append recipe from those changes.<br />
<br /><br />
<br /><br />
<br />
== Initialization Manager ==<br />
After the kernel is done with its basic booting tasks, it passes control to the initialization manager. To use the ''systemd'' initialization manager (used by the Linux distributions Debian and Ubuntu) instead of ''SysVinit'', make the following entries in ''${TOPDIR}/conf/distro/distro.conf''<br />
<pre class="code"><br />
DISTRO_FEATURES_append = " systemd"<br />
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"<br />
VIRTUAL-RUNTIME_init_manager = "systemd"<br />
VIRTUAL-RUNTIME_initscripts = ""<br />
</pre><br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Yocto&diff=3130Yocto2022-12-20T09:05:12Z<p>Kai: </p>
<hr />
<div>= Prerequisites =<br />
<pre class=terminal><br />
sudo apt install gcc g++ \<br />
python3-distutils python-is-python3<br />
</pre><br />
<br /><br />
<br />
= Images =<br />
<br />
Images are recipes that ultimately inherit from '''meta/classes/image.bbclass''' and set the global variable '''IMAGE_INSTALL'''. Most images, however, will inherit from ''meta/classes/core-image.bbclass'' which inherits directly from ''image.bbclass'', provides a mapping from ''IMAGE_FEATURES'' to package groups, and adds the two package groups ''packagegroup-core-boot'' and ''packagegroup-base-extended'' to ''IMAGE_INSTALL''.<br />
<br />
Images are defined in recipe files with the file extension 'bb'. In order to separate them from package recipes, there is a convention to put image recipes into a folder named ''images''. Making use of this, we can list all images defined by all layers via<br />
<pre class="terminal"><br />
cd poky<br />
ls meta*/recipes*/images/*.bb<br />
</pre><br />
<br /><br />
<br />
=== ''IMAGE_FEATURES'' ===<br />
The ''IMAGE_FEATURES'' variable is defined in ''meta/classes/image.bbclass'' with an empty value. It accepts only a predefined set of features (e.g., ''x11'', ''debug-tweaks'', ''dev-pkgs'', ''dbg-pkgs''). This affects how recipes will execute their tasks and which packages will be selected to go into the image. The image recipe ''meta/recipes-core/images/core-image-base.bb'', for example, adds the ''splash'' feature.<br />
<br /><br />
<br />
=== ''IMAGE_INSTALL'' ===<br />
Holds a list of package groups whose packages (from the package feed area) will go into the filesystem image.<br />
<br /><br />
<br />
== Reference images ==<br />
The following reference images are defined in the ''meta'' layer:<br />
{| style="padding: 10px;"<br />
! style="width: 20px" | || || <br />
|-<br />
| || ''core-image-minimal'' || small image that just boots the target device<br />
|-<br />
| || ''core-image-minimal-dev'' || ''core-image-minimal'' with headers and libraries allowing development work<br />
|-<br />
| || style="padding-right: 10px" | ''core-image-minimal-initramfs'' || ''core-image-minimal'' with kernel support for in-RAM filesystem<br />
|-<br />
| || '''core-image-base''' || '''console-only system fully supporting the target hardware'''<br />
|-<br />
| || ''core-image-full-cmdline'' || console-only image that includes many system tools<br />
|-<br />
| || ''core-image-x11'' || image with basic X11 and a terminal<br />
|-<br />
|}<br />
<br />
These image definitions are provided as a starting point for creating project-specific, custom image definitions.<br />
<br /><br />
<br /><br />
<br />
== Creating a Custom Image ==<br />
* In your custom layer, create the ''images'' subdirectory in one of your ''recipes-...' directory.<br />
* In the ''images'' directory, create two image recipe files that inherit from ''core-image'':<br />
<pre class="code"><br />
SUMMARY = "My deployment image"<br />
LICENSE = "MIT"<br />
<br />
inherit core-image<br />
IMAGE_FEATURES += "splash"<br />
</pre><br />
and<br />
<pre class="code"><br />
SUMMARY = "My development image"<br />
<br />
inherit core-image<br />
require my-image.bb<br />
<br />
IMAGE_FEATURES += "ssh-server-dropbear tools-debug debug-tweaks"<br />
<br />
CORE_IMAGE_EXTRA_INSTALL += "i2c-tools "<br />
</pre><br />
where the first image recipe is for deployment and the second is for development. Note that the development version includes the deployment version with the ''require'' statement, and adds to IMAGE_FEATURES and CORE_IMAGE_EXTRA_INSTALL.<br />
<br /><br />
<br />
== Image Filesystem Packaging ==<br />
The system image generated by Bitbake can be packaged in the form of an image file, whose contents can be transferred on a boot medium (SD card or eMMC) such that the primary boot loader of the target device can discover the system and boot it.<br />
<br />
Unless you restrict the type of packaging used for the image file, Yocto will generate multiple To restrict the generated image files (these are large files) to a certain <br />
<pre class="code"><br />
# Multiple types of image files are created by default.<br />
# Uncomment the desired lines below to prevent the<br />
# corresponding type of image file from being generated.<br />
#IMAGE_FSTYPES::remove = "tar.gz"<br />
#IMAGE_FSTYPES::remove = "tar.bz"<br />
#IMAGE_FSTYPES::remove = "wic.bz2 wic.bmap"<br />
</pre><br />
<br /><br />
<br />
== Installing the Rootfs Image ==<br />
Using Yocto's '''bmaptool''' we can copy the generated ''wic'' image (with matching bmap file) to a mounted SD card or eMMC storage.<br />
<pre class="terminal"><br />
sudo bmaptool copy tmp/deploy/images/raspberrypi4-64/<wic.bz2 file> <drive><br />
</pre><br />
where ''<wic.bz2 file>'' is the root filesystem image wic.bz2 file, and ''<drive>'' is the drive at which the storage is mounted (for example, ''/dev/sdb'').<br />
<br /><br />
<br /><br />
<br />
= Package Groups =<br />
Package groups are recipes that inherit from '''meta/classes/packagegroup.bbclass''' and set the content of the global variable '''PACKAGES'''. Package groups are defined in recipe files with the file extension 'bb'.<br />
<br /><br />
<br /><br />
Note that the ''packagegroup'' must be inherited before ''PACKAGES is defined.<br />
<pre class="code"><br />
inherit packagegroup<br />
<br />
PACKAGES = '...'<br />
</pre><br />
<br /><br />
<br />
= devtool =<br />
<br />
Use '''devtool''' to make changes to an existing recipe and automatically generate an append recipe from those changes.<br />
<br /><br />
<br /><br />
<br />
== Initialization Manager ==<br />
After the kernel is done with its basic booting tasks, it passes control to the initialization manager. To use the ''systemd'' initialization manager (used by the Linux distributions Debian and Ubuntu) instead of ''SysVinit'', make the following entries in ''${TOPDIR}/conf/distro/distro.conf''<br />
<pre class="code"><br />
DISTRO_FEATURES_append = " systemd"<br />
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"<br />
VIRTUAL-RUNTIME_init_manager = "systemd"<br />
VIRTUAL-RUNTIME_initscripts = ""<br />
</pre><br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Nvidia_Jetson&diff=3129Nvidia Jetson2022-12-11T11:40:10Z<p>Kai: /* Camera */</p>
<hr />
<div>=== The Jetson Family ===<br />
Nvidia's Jetson family of products are compact [https://www.nvidia.com/object/tegra.html Tegra] computers, which feature a large number of parallel computation units that are suitable for hardware-accelerated machine learning applications. The various models differ in their computational performance.<br />
<br /><br />
<br /><br />
=== JetPack ===<br />
JetPack is Nvidia's name for a software bundle that contains development software and a modified version of Ubuntu Linux with a custom kernel for the Tegra hardware, called ''Linux For Tegra'' or ''L4T''.<br />
<br /><br />
* [https://developer.nvidia.com/embedded/jetpack JetPack download page]<br />
<br /><br />
==== Figuring out the JetPack Version ====<br />
The [https://developer.nvidia.com/embedded/jetpack-archive JetPack Archive] shows a list of JetPack download packages with corresponding versions of L4T (Linux for Tegra).<br />
<br />
<br />
In a running L4T installation, the version can be looked up via the Debian package manager utility:<br />
<pre class="terminal"><br />
dpkg-query --show nvidia-l4t-core<br />
</pre><br />
<br /><br />
<br />
Some JetPack and L4T versions are listed below for convenience.<br />
<br />
{|<br />
! style="width:6em; font-weight:bold; text-align: left" | L4T<br />
! style="width:6em; font-weight:bold; text-align: left" | JetPack<br />
! style="width:8em; font-weight:bold; text-align: left" | release date<br />
! style="font-weight:bold; text-align: left" | Ubuntu base &nbsp;&nbsp;&nbsp;&nbsp;<br />
! style="font-weight:bold; text-align: left" | Remark<br />
|-<br />
| 35.1 || 5.0.2 || 2022-08-15 || 20.04 || 5.x drops support for Jetson Nano<br />
|-<br />
| 32.7.1 || 4.6.1 || 2022-02-23 || 18.04 || <br />
|-<br />
| 32.5 || 4.5.0 || 2021-01-22 || 18.04 ||<br />
|-<br />
| 32.4.3 || 4.4.0 || 2020-07-06 || 18.04 ||<br />
|-<br />
| 32.2.0 || 4.2.1 || 2019-07-16 || 18.04 ||<br />
|}<br />
<br /><br />
<br />
=== Assigning a Fixed Ethernet IP Address ===<br />
You can either use the old ''ifconfig'' tool<br />
<pre class="terminal"><br />
ifconfig eth0 192.168.0.10 netmask 255.255.255.0 up<br />
</pre><br />
or the newer ''ip'' tool (the example below is incomplete)<br />
<pre class="terminal"><br />
ip addr show<br />
ip link set eth0 up<br />
</pre><br />
<br /><br />
To make the IP address permanent, the easy way is to open the System Settings window from the Ubuntu GUI. Then<br />
* open the Network settings,<br />
* select the wired connection from the left hand list,<br />
* click on the "Options..." button in the bottom right corner,<br />
* open the "IPv4 Settings" tab,<br />
* change the value of the "Method:" field to "Manual",<br />
* enter the desired address (192.168.0.10) into the "Addresses" list.<br />
<br /><br />
<br />
=== Setting up WiFi ===<br />
First, make sure that the WLAN hardware (maybe a USB stick) is operational. Check the availability of the '''wlan0''' interface among all network interfaces:<br />
<pre class="terminal"><br />
ifconfig<br />
</pre><br />
<br ><br />
Also, make sure that '''wpasupplicant''' is installed. <br />
<pre class="terminal"><br />
sudo apt-get install wpasupplicant<br />
</pre><br />
Now edit the file '''/etc/wpa_supplicant.conf''' to replace the "ssid" and "psk" values in the network example that starts with the line '''# Simple case: WPA-PSK''':<br />
<pre class="code"><br />
network={<br />
ssid="ssid_name"<br />
psk="password"<br />
priority=5<br />
}<br />
</pre><br />
where ''ssid_name'' and ''password'' need to be replaced with the WiFi name (SSID) and the password of your router, respectively. <br />
<br /><br />
Finally, connect to the router:<br />
<pre class="terminal"><br />
sudo killall wpa_supplicant<br />
sudo wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant.conf -D wext<br />
sudo dhclient wlan0<br />
</pre><br />
<br /><br />
=== Setting up SSH ===<br />
The developer kit features HDMI and DisplayPort outputs for connecting to a display. In a robot, the control interface for the Jetson Nano will be a terminal session via SSH. To set up the SSH service on the Nano first make sure that the ssh package is installed:<br />
<pre class="terminal"><br />
sudo apt install openssh-client openssh-server<br />
</pre><br />
<br /><br />
You can now start the SSH service like this:<br />
<pre class="terminal"><br />
sudo service ssh start<br />
</pre><br />
and stop it like this:<br />
<pre class="terminal"><br />
sudo service ssh stop<br />
</pre><br />
<br /><br />
To make the SSH service start automatically at each boot, type<br />
<pre class="terminal"><br />
sudo systemctl enable ssh<br />
sudo systemctl enable ssh.service<br />
sudo systemctl start ssh<br />
</pre><br />
To prevent the system from starting the SSH service at each boot, type<br />
<pre class="terminal"><br />
sudo systemctl stop ssh<br />
sudo systemctl disable ssh<br />
sudo systemctl disable ssh.service<br />
</pre><br />
<br /><br />
<br />
=== SSH Login Over WiFi Connection ===<br />
The Jetson Nano and the Jetson Xavier developer kit boards come without WiFi connectivity. You can use a USB WiFi adaptor stick (e.g., Edimax ) to add WiFi connectivity. On Ubuntu, you will need to give permission to the system to make the WiFi connection available to all other users, which includes the SSH daemon, in order to enable remote logins over WiFi without requiring an active local login session (via connected peripherals or Ethernet connection).<br />
<br /><br />
To give permission,<br />
* open the "System Settings" application,<br />
* go to "Network",<br />
* make sure "Wireless" is selected on the left panel,<br />
* on the right side panel, next to the SSID of the WLAN server, click on the arrow icon,<br />
* click on the "Settings..." button on the bottom right corner,<br />
* in the window that opens, go to the tab "General",<br />
* check the "All users may connect to this network" option<br />
<br /><br />
=== Camera ===<br />
Cameras can be connected to Jetson Nano over USB or over the CSI connector. In case of a CSI camera, the image sensor must be a '''Sony IMX219''', such as the [https://www.raspberrypi.org/products/camera-module-v2/ Raspberry Pi Camera v2].<br />
<br /><br />
Use the ''Video4Linux'' command-line tool '''v4l2-ctl''' to list all video inputs that are available to the system and what type of image frames they provide.<br />
<pre class="terminal"><br />
sudo apt install v4l-utils<br />
v4l2-ctl --list-devices<br />
v4l2-ctl --list-formats<br />
</pre><br />
<br /><br />
You can view the video stream from the CSI camera using [[GStreamer]] via<br />
<pre class="terminal"><br />
gst-launch-1.0 nvarguscamerasrc ! 'video/x-raw(memory:NVMM), width=1920, height=1080, format=NV12, framerate=(fraction)30/1' ! nvoverlaysink<br />
</pre><br />
for a full-screen view, or<br />
<pre class="terminal"><br />
gst-launch-1.0 nvarguscamerasrc ! 'video/x-raw(memory:NVMM), width=1920, height=1080, framerate=30/1' ! nvvidconv flip-method=0 ! nvegltransform ! nveglglessink -e<br />
</pre><br />
for an OpenGL window view.<br />
<br /><br />
<br /><br />
''nvarguscamerasrc'' is a Gstreamer plugin for Nvidia's proprietary [https://docs.nvidia.com/jetson/l4t-multimedia/group__LibargusAPI.html Argus Camera API] for Linux on Tegra devices, and ''nveglglessink'' is a better-performing OpenGL sink than ''glimagesink''. Curiously, ''nvarguscamerasrc'' will show up in the GStreamer element list when searching for elements of type ''video'' but not when searching for ''source/video''.<br />
<pre class="terminal"><br />
gst-inspect-1.0 -t video<br />
</pre><br />
<br /><br />
==== Streaming Images Over The Network ====<br />
To stream the camera images over the network via UDP, run the following script on the Jetson<br />
<pre class="code"><br />
#!/bin/bash<br />
STREAM_RECEIVER_ADDRESS=$1<br />
STREAM_RECEIVER_PORT=$2<br />
GST_LAUNCH="gst-launch-1.0 -v"<br />
GST_DEBUG="--gst-debug=3"<br />
INPUT="nvarguscamerasrc ! 'video/x-raw(memory:NVMM),width=1280,height=720,framerate=30/1,format=(string)NV12' ! nvvidconv ! 'video/x-raw(memory:NVMM),format=(string)I420'"<br />
<br />
# Stream via RTP over UDP<br />
STREAM_OUTPUT="omxh264enc bitrate=8000000 ! 'video/x-h264, stream-format=byte-stream' ! h264parse ! rtph264pay config-interval=10 pt=96 ! udpsink host=<host address> port=<port number>"<br />
<br />
# Show in local GL window<br />
VIEW_OUTPUT="nvegltransform ! nveglglessink -e"<br />
<br />
if [ $# == 0 ]; then<br />
eval $GST_LAUNCH $INPUT ! $VIEW_OUTPUT<br />
elif [ $# == 2 ]; then<br />
eval $GST_LAUNCH $INPUT ! $STREAM_OUTPUT<br />
fi<br />
</pre><br />
where the client IP address and the client port number need to be supplied as arguments 1 and 2, respectively.<br />
<br/><br />
<br/><br />
Run the following script on the client machine to receive and display the video stream in a GStreamer pipeline.<br />
<pre class="code"><br />
UNPACK_RTP_H264_PAYLOAD="'application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=H264, payload=96' ! rtph264depay ! avdec_h264"<br />
GST_UDPSRC="gst-launch-1.0 -v --gst-debug=3 udpsrc port=<port number>"<br />
VIDEO_SINK="videoconvert ! autovideosink"<br />
<br />
eval $GST_UDPSRC ! $UNPACK_RTP_H264_PAYLOAD ! $VIDEO_SINK<br />
</pre><br />
where you need to replace ''<port number>'' with the same port number used by the sender. '''Check the receiver's firewall settings''' to make sure the port is not blocked! On macOS you can do so by opening the Firewall settings and first add ''Terminal'' to the list of applications for which incoming connections are allowed. Upon launching the script, you will be prompted to allow incoming connections for ''gst-launch-1.0'' as well.<br />
<br /><br />
<br /><br />
The order in which the Gstreamer pipelines are launched is irrelevant because of the connectionless data transmission via UDP. The receiver will be continuously waiting for incoming UDP packets, and the sender will be sending out packets even if there is no receiver.<br />
<br /><br />
<br /><br />
Resources<br />
* [https://developer.ridgerun.com/wiki/index.php?title=Xavier/GStreamer_Pipelines example GStreamer pipelines] (RidgeRun)<br />
<br /><br />
<br />
=== Power Modes ===<br />
Use the '''nvpmodel''' command line tool for selecting or configuring the performance level of a Jetson device.<br />
You can query the current mode via<br />
<pre class="terminal"><br />
sudo nvpmodel -q --verbose<br />
</pre><br />
and switch between modes with the "-m" option like this<br />
<pre class="terminal"><br />
sudo nvpmodel -m <mode_number><br />
</pre><br />
<br /><br />
where ''<mode_number>'' is one of the mode numbers (e.g., 0 or 1) which the tool reads from the default configuration file "/etc/nvpmodel.conf" and which you can edit to create a custom mode:<br />
<pre class="terminal"><br />
sudo vim /etc/nvpmodel.conf<br />
</pre><br />
<br /><br />
<br />
=== Disabling USB Autosuspend ===<br />
If you are operating your Jetson with an attached USB mass storage device you will need to disable USB autosuspend. Otherwise the device will become unavailable after a while, and your applications will report an I/O error.<br />
<br /><br />
<br /><br />
Edit the file '''/boot/extlinux/extlinux.conf''' by adding the following boot argument to the line starting with '''APPEND''':<br />
<pre class="code"><br />
usbcore.autosuspend=-1<br />
</pre><br />
This will disable autosuspend upon the next reboot.<br />
<br /><br />
<br /><br />
To check that the autosuspend mode changed from active (2) to disabled (-1), enter<br />
<pre class="terminal"><br />
cat /sys/module/usbcore/parameters/autosuspend<br />
</pre><br />
<br /><br />
<br />
=== GPIO Programming ===<br />
[[File:Nvidia_Jetson_GPIO.jpg | 500px]]<br />
<br />
<br />
==== Jetson Nano Pinout ====<br />
Based on the [https://jetsonhacks.com/nvidia-jetson-nano-j41-header-pinout/ JetsonHacks] pinout table.<br />
<br />
{| class="wikitable"<br />
|-<br />
! Sysfs GPIO !! Name !! Pin !! &nbsp; !! Pin !! Name !! Sysfs GPIO<br />
|-<br />
| || 3.3 V Power out || 1 || || 2 || 5.0 V Power in ||<br />
|-<br />
| || I2C_2_SDA || 3 || || 4 || 5.0 V Power in ||<br />
|-<br />
| || I2C_2_SCL || 5 || || 6 || GND ||<br />
|-<br />
| gpio216 || AUDIO_MCLK || 7 || || 8 || UART_2_TX ||<br />
|-<br />
| || GND || 9 || || 10 || UART_2_RX ||<br />
|-<br />
| gpio50 || UART_2_RTS || 11 || || 12 || I2S_4_SCLK || gpio79<br />
|-<br />
| gpio14 || SPI_2_SCK || 13 || || 14 || GND ||<br />
|-<br />
| gpio194 || LCD_TE || 15 || || 16 || SPI_2_CS1 || gpio232<br />
|-<br />
| || 3.3 V || 17 || || 18 || SPI_2_CS0 || gpio15<br />
|- <br />
| gpio16 || SPI_1_COPI || 19 || || 20 || GND ||<br />
|-<br />
| gpio17 || SPI_1_CIPO || 21 || || 22 || SPI_2_CIPO || gpio13<br />
|-<br />
| gpio18 || SPI_1_SCK || 23 || || 24 || SPI_1_CS0 || gpio19<br />
|-<br />
| || GND || 25 || || 26 || SPI_1_CS1 || gpio20<br />
|-<br />
| || I2C_1_SDA || 27 || || 28 || I2C_1_SCL ||<br />
|-<br />
| gpio149 || CAM_AF_EN || 29 || || 30 || GND ||<br />
|-<br />
| gpio200 || GPIO_PZ0 || 31 || || 32 || LCD_BL_PWM || gpio168<br />
|-<br />
| gpio38 || GPIO_PE6 || 33 || || 34 || GND ||<br />
|-<br />
| gpio76 || I2S_4_LRCK || 35 || || 36 || UART_2_CTS || gpio51<br />
|-<br />
| gpio12 || SPI_2_COPI || 37 || || 38 || I2S_4_SDIN || gpio77<br />
|-<br />
| || GND || 39 || || 40 || I2S_4_SDOUT || gpio78<br />
|}<br />
<br />
==== Using SYSFS ====<br />
The old, deprecated way of GPIO programming on Linux is to write to the ''sysfs'' virtual files that are managed by the kernel. For GPIO, the Linux kernel provides the '''/sys/class/gpio''' virtual directory. GPIO commands, like creating an output pin and writing a value, are performed by writing to or reading from specific files in that directory.<br />
<br />
Since sysfs is a filesystem-based interface, GPIO state can be easily manipulated with a shell script. Here is an example bash code for blinking an LED connected to GPIO pin 11:<br />
<pre class="code"><br />
echo 50 > /sys/class/gpio/export <br />
sleep 0.1<br />
echo out > /sys/class/gpio/gpio50/direction<br />
sleep 0.1<br />
for n in {0..2}<br />
do<br />
echo 1 > /sys/class/gpio/gpio50/value<br />
sleep 1<br />
echo 0 > /sys/class/gpio/gpio50/value<br />
sleep 1<br />
done<br />
echo 50 > /sys/class/gpio/unexport<br />
</pre><br />
<br /><br />
<br />
==== Using Libgpiod ====<br />
The best way for programming GPIO without having to mess with the inefficient sysfs, is to use the C library ''libgpiod'' or a binding to another programming language.<br />
First, make sure libgpiod, the C header, and the related command-line tools are installed<br />
<pre class="terminal"><br />
sudo apt install gpiod libgpiod-dev<br />
</pre><br />
<br /><br />
<br />
''gpiodetect'' gives us information about the available GPIO banks. Typing<br />
<pre class="terminal"><br />
sudo gpiodetect<br />
</pre><br />
returns<br />
<pre class="terminal"><br />
gpiochip0 [tegra-gpio] (256 lines)<br />
gpiochip1 [max77620-gpio] (8 lines)<br />
</pre><br />
where ''gpiochip0'' is the GPIO bank exposed by the J41 header.<br />
<br /><br />
<br />
Drilling down into GPIO bank 0 with ''gpioinfo''<br />
<pre class="terminal"><br />
gpioinfo gpiochip0<br />
</pre><br />
we can see the pin functions of J41 GPIO bank:<br />
<pre class="terminal"><br />
gpiochip0 - 256 lines:<br />
line 0: unnamed unused input active-high<br />
line 1: unnamed unused input active-high<br />
line 2: unnamed "pcie_wake" input active-high [used]<br />
line 3: unnamed unused input active-high<br />
line 4: unnamed unused input active-high<br />
line 5: unnamed unused input active-high<br />
line 6: unnamed "vdd-usb-hub-en" output active-high [used]<br />
line 7: unnamed unused input active-high<br />
line 8: unnamed unused input active-high<br />
line 9: unnamed unused input active-high<br />
line 10: unnamed unused input active-high<br />
line 11: unnamed unused input active-high<br />
line 12: "SPI1_MOSI" unused input active-high<br />
line 13: "SPI1_MISO" unused input active-high<br />
line 14: "SPI1_SCK" unused input active-high<br />
line 15: "SPI1_CS0" unused input active-high<br />
.<br />
.<br />
.<br />
line 252: unnamed unused input active-high<br />
line 253: unnamed unused input active-high<br />
line 254: unnamed unused input active-high<br />
line 255: unnamed unused input active-high <br />
</pre><br />
<br /><br />
<br />
Using the ''gpioset'' shell command we can set the output level of a GPIO pin:<br />
<pre class="terminal"><br />
sudo gpioset gpiochip0 50=1<br />
</pre><br />
If the LED does not light up, check if line 50 is still being used by sysfs.<br />
<br /><br />
<br /><br />
<br />
Back to programming the GPIO in C++. Create the file ''libgpiod_test.cpp'' containing the following C++ code: <br />
<pre class="code"><br />
#include <gpiod.h><br />
#include <cstdlib><br />
#include <thread><br />
#include <chrono><br />
<br />
int main(int numarg, char** args)<br />
{<br />
gpiod_chip* const gpio0 = gpiod_chip_open_by_name("gpiochip0");<br />
if (gpio0 == NULL) {<br />
return EXIT_FAILURE;<br />
}<br />
gpiod_line* const line50 = gpiod_chip_get_line(gpio0, 50);<br />
if (line50 == NULL) {<br />
gpiod_chip_close(gpio0);<br />
return EXIT_FAILURE;<br />
}<br />
if (gpiod_line_request_output(line50, "LED", 0) != 0) {<br />
gpiod_line_release(line50);<br />
gpiod_chip_close(gpio0);<br />
return EXIT_FAILURE;<br />
}<br />
for (int i = 1; i <= 6; i++)<br />
{<br />
gpiod_line_set_value(line50, i%2);<br />
std::this_thread::sleep_for(std::chrono::milliseconds(1000));<br />
}<br />
gpiod_line_release(line50);<br />
gpiod_chip_close(gpio0);<br />
return EXIT_SUCCESS;<br />
}<br />
</pre><br />
<br /><br />
<br />
Compile and run.<br />
<pre class="terminal"><br />
g++ -o libgpiod_test libgpiod_test.cpp -lgpiod<br />
sudo ./libgpiod_test<br />
</pre><br />
<br />
<br />
==== Debug ====<br />
To view the state of all the available GPIO pins type<br />
<pre class="terminal"><br />
sudo cat /sys/kernel/debug/tegra_gpio<br />
</pre><br />
<br /><br />
<br />
=== Jetson Model Specifics ===<br />
==== Jetson Nano ====<br />
The Nano is the Jetson with the smallest footprint and lowest performance. It features 128 compute units based on the Maxwell architecture. The developer kit comes with host circuit board that provides connection ports like USB, Ethernet, HDMI and DisplayPort. <br />
* [https://developer.download.nvidia.com/assets/embedded/secure/jetson/Nano/docs/Jetson_Nano_Developer_Kit_User_Guide.pdf Jetson Nano Developer Kit User Guide]<br />
<br /><br />
===== Power Supply and OS Installation =====<br />
The Nano Developer Kit requires a power supply that can deliver 5 V and at least 2 A, either over the micro USB port, or via a standard 5.5/2.1mm barrel power jack, which requires '''bridging the J48 header pins with a jumper'''. When operated via the power jack, the micro USB port can be used to install the Nano operating system from an external computer. Otherwise, the OS image needs to be written to a micro-SD card that is inserted into the card slot of the developer kit.<br />
<br /><br />
<br /><br />
===== Preconfigured Power Modes =====<br />
* mode '''0''' (MAXN) <br />the default mode with maximum performance and up to 10 W power consumption<br />
* mode '''1''' (5 W) <br />low-power mode where only two out of four CPU cores are working and the GPU clock frequency is constrained to keep power consumption under 5 W.<br />
<br/><br />
<br />
{| style="width: 24em"<br />
! style="font-weight:bold" |<br />
! style="font-weight:bold" | MAXN<br />
! style="font-weight:bold" | 5 W<br />
|-<br />
| power budget || 10 Watts || 5 Watts<br />
|-<br />
| CPUs in use || 4 || 2<br />
|-<br />
| CPU max freq. || 1479 MHz || 918 MHz<br />
|-<br />
| GPU max freq. || 921 MHz || 640 MHz<br />
|}<br />
<br/></div>Kaihttps://Robo.Fish/wiki/index.php?title=Linux&diff=3128Linux2022-12-09T13:33:34Z<p>Kai: Adds section about Videl4Linux.</p>
<hr />
<div>== Boot Procedure ==<br />
# The primary bootloader, which is usually a fixed part of the hardware recognizes bootable media.<br />
#* On PC compatible systems, [https://en.wikipedia.org/wiki/UEFI UEFI] or BIOS are the primary bootloaders.<br />
#* On BIOS systems, the Master Boot Record (MBR) area of a connected storage device is searched for a boot executable. The MBR is a special area, separate from the actual data storage area. BIOS is an old system, dating back to the early 1980s, but not yet obsolete.<br />
#* On a UEFI system, which supports storage media with much larger capacity, the ''GPT'' partition table is used to determine if the storage device provides an ''EFI System Partition'' containing the folder ''/efi'' with a subfolder that contains the secondary boot loader. ''/efi/microsoft'' or ''/efi/grub'', for example. After a Linux system is booted by UEFI hardware, you can open a terminal and inspect the partition table by typing <span class="terminal">sudo gdisk /dev/sda</span>.<br />
# If a secondary bootloader is found on the bootable media, it is loaded.<br />
#* On PC compatibles the secondary bootloader is usually [https://www.gnu.org/software/grub GRUB2].<br />
#* On [[Arm Cortex-A]] based systems, this is often [https://u-boot.readthedocs.io/en/latest/ U-Boot].<br />
#* Some systems have proprietary bootloaders. Raspberry Pi, for example.<br />
#* To support the bootloader, a standard interface called LBA (linear block access) exists for storage media. This interface is not optimized for the capabilities of the storage device but is sufficient for the bootloader to search for a bootable operating system, which will later load the appropriate driver for the storage media.<br />
# The secondary bootloader loads the [https://www.kernel.org Linux kernel].<br />
#* In the case of GRUB2, the boot media is searched for the boot partition using LBA mode, stage 2 is loaded from a separate data area of the boot media, the module for working with the boot partitions filesystem is loaded, the GRUB config file (''/boot/grub/grub.cfg'') is loaded from the boot partition, the user is optionally shown a GRUB menu, the kernel is loaded with the user parameters.<br />
# The kernel optionally loads an initial root file system into memory (often [https://en.wikipedia.org/wiki/Initial_ramdisk initramfs]), which includes the device drivers specific for the target hardware. For example, display drivers for showing graphical output during the boot sequence.<br />
#* Technically, all hardware-specific device drivers can be compiled into the kernel itself. In order to keep the kernel generic, however, and to avoid mixing components with incompatible distribution licenses (the GPL 2.0 license used by Linux prevents distributing a kernel with built-in proprietary drivers), certain drivers are placed into initramfs, from where they are loaded when needed.<br />
#* After the hardware is initialized, the kernel switches from initramfs to the real filesystem.<br />
# The kernel starts the first process, the '''init''' process. The ''init'' process starts all the system processes (a.k.a. ''services'') configured to run when the system launches.<br />
#* ''init'' used to be a shell script located in the filesystem at ''/sbin/init''. Nowadays, many Linux distributions use the '''[https://wiki.debian.org/systemd systemd]''' initialization method, where a binary executable is called instead of a shell script.<br />
<br /><br />
<br />
== systemd ==<br />
=== Systemd Unit Files ===<br />
Unit files determine what kind of task is being started. The types of tasks are<br />
* '''service''' for running daemons<br />
* '''mount''' for mounting storage media, etc<br />
* '''automount''' for mounting directories when needed<br />
* '''timer''' for starting jobs at specific times<br />
* '''target''' (a group of unit files, or a state that the machine should be in after booting)<br />
* '''path''' (monitoring filesystem events)<br />
<br />
The original unit files that are installed by the package manager are placed in ''/usr/lib/systemd/system'' and should not be modified.<br />
If modifications to unit files are to be made, the modified unit files should be placed into ''/etc/systemd/system''.<br />
<br /><br />
<br />
==== Unit Relationships (Dependencies) ====<br />
There are various relationships between two units:<br />
* '''requires''': The dependent unit must be loaded in order to load the current unit.<br />
* '''wants''': The dependent unit is not critical<br />
* '''requisite''': the dependent unit must be loaded and already active.<br />
* '''conflicts''': the unit must not be loaded for the current to be loaded<br />
* '''before''': the current unit must be activated before the given units<br />
* '''after''': the current unit must be activated after the given units<br />
<br /><br />
The dependency graph can be displayed on the terminal via<br />
<pre class="terminal"><br />
sudo systemctl list-dependencies<br />
</pre><br />
<br /><br />
<br />
=== Systemd Services ===<br />
Here is an example of using ''systemctl'' to query the status of the SSH server.<br />
<pre class="terminal"><br />
systemctl status sshd<br />
</pre><br />
<br /><br />
To start or stop the server, you would type<br />
<pre class="terminal"><br />
sudo systemctl start sshd<br />
sudo systemctl stop sshd<br />
</pre><br />
<br /><br />
To configure a service, edit its configuration file located in '''/etc/systemd/system'''.<br />
<br /><br />
<br /><br />
<br />
=== Systemd Targets ===<br />
Targets are groups of unit files. If a target includes the statement <span class="code">AllowIsolate = yes</span> the target becomes an initialization endpoint at which systemd stops executing other units. Isolate targets are therefore similar to System V runlevels that were used for initialization before systemd.<br />
<br /><br />
<br /><br />
For a custom target (or service), the relationship to the unit files that are ''WantedBy'' or ''RequiredBy'' the target (or service) will be established by systemd through symbolic links to the wanted or required unit files. These symbolic links are placed in ''/etc/systemd/system'', within a subdirectory whose name starts with the name of the unit file and ends with the name of the type of relationship.<br />
<br /><br />
<br /><br />
=== Systemd Analysis ===<br />
Systemd can plot a chart that shows how the units are launched over time.<br />
<pre class="terminal"><br />
systemd-analyze plot > analysis.html<br />
</pre><br />
generates an HTML page with a chart like this<br />
<br /><br />
<br /><br />
[[File:systemd-analysis.png | x300px ]]<br />
<br /><br />
<br /><br />
<br />
== Which Linux distro and version am I running? ==<br />
<pre class="terminal"><br />
cat /etc/os-release<br />
</pre><br />
<br /><br />
<br />
== Dynamic Shared Objects (DSO) ==<br />
Ulrich Drepper's [https://www.akkadia.org/drepper/dsohowto.pdf How To Write Shared Libraries] is a good resource for learning more about the ELF format, about optimizing your shared objects, and how to control the visibility of program symbols in the generated binaries.<br />
<br /><br />
<br /><br />
<br />
== Tracing system calls ==<br />
<br />
'''strace''' is a command that lets you trace the system calls made by the command that is passed as the argument. For example,<br />
<pre class="terminal"><br />
strace echo "hello"<br />
</pre><br />
prints<br />
<pre class="terminal"><br />
execve("/usr/bin/echo", ["echo", "hello"], 0x7ffefa8f4928 /* 42 vars */) = 0<br />
brk(NULL) = 0x561cf6532000<br />
arch_prctl(0x3001 /* ARCH_??? */, 0x7fff61293910) = -1 EINVAL (Invalid argument)<br />
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf85c44000<br />
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)<br />
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=53267, ...}, AT_EMPTY_PATH) = 0<br />
mmap(NULL, 53267, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7faf85c36000<br />
close(3) = 0<br />
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3<br />
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\237\2\0\0\0\0\0"..., 832) = 832<br />
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784<br />
pread64(3, "\4\0\0\0 \0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0"..., 48, 848) = 48<br />
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0i8\235HZ\227\223\333\350s\360\352,\223\340."..., 68, 896) = 68<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=2216304, ...}, AT_EMPTY_PATH) = 0<br />
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784<br />
mmap(NULL, 2260560, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7faf85a0e000<br />
mmap(0x7faf85a36000, 1658880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x28000) = 0x7faf85a36000<br />
mmap(0x7faf85bcb000, 360448, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x7faf85bcb000<br />
mmap(0x7faf85c23000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x214000) = 0x7faf85c23000<br />
mmap(0x7faf85c29000, 52816, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7faf85c29000<br />
close(3) = 0<br />
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf85a0b000<br />
arch_prctl(ARCH_SET_FS, 0x7faf85a0b740) = 0<br />
set_tid_address(0x7faf85a0ba10) = 1874<br />
set_robust_list(0x7faf85a0ba20, 24) = 0<br />
rseq(0x7faf85a0c0e0, 0x20, 0, 0x53053053) = 0<br />
mprotect(0x7faf85c23000, 16384, PROT_READ) = 0<br />
mprotect(0x561cf5067000, 4096, PROT_READ) = 0<br />
mprotect(0x7faf85c7e000, 8192, PROT_READ) = 0<br />
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0<br />
munmap(0x7faf85c36000, 53267) = 0<br />
getrandom("\x01\x62\x8d\xf4\xec\xea\xd8\x4e", 8, GRND_NONBLOCK) = 8<br />
brk(NULL) = 0x561cf6532000<br />
brk(0x561cf6553000) = 0x561cf6553000<br />
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=6070224, ...}, AT_EMPTY_PATH) = 0<br />
mmap(NULL, 6070224, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7faf85441000<br />
close(3) = 0<br />
newfstatat(1, "", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}, AT_EMPTY_PATH) = 0<br />
write(1, "hello\n", 6) = 6<br />
close(1) = 0<br />
close(2) = 0<br />
exit_group(0) = ?<br />
+++ exited with 0 +++<br />
</pre><br />
lists system calls made by ''echo'' as they are made.<br />
<br /><br />
<br /><br />
Instead of printing system calls as they are made, ''strace'' can print a short summary of which system calls were how many times and the time spent.<br />
<pre class="terminal"><br />
strace -c echo "hello"<br />
</pre><br />
prints<br />
<pre class="terminal"><br />
hello<br />
% time seconds usecs/call calls errors syscall<br />
------ ----------- ----------- --------- --------- ----------------<br />
0,00 0,000000 0 1 read<br />
0,00 0,000000 0 1 write<br />
0,00 0,000000 0 5 close<br />
0,00 0,000000 0 9 mmap<br />
0,00 0,000000 0 3 mprotect<br />
0,00 0,000000 0 1 munmap<br />
0,00 0,000000 0 3 brk<br />
0,00 0,000000 0 4 pread64<br />
0,00 0,000000 0 1 1 access<br />
0,00 0,000000 0 1 execve<br />
0,00 0,000000 0 2 1 arch_prctl<br />
0,00 0,000000 0 1 set_tid_address<br />
0,00 0,000000 0 3 openat<br />
0,00 0,000000 0 4 newfstatat<br />
0,00 0,000000 0 1 set_robust_list<br />
0,00 0,000000 0 1 prlimit64<br />
0,00 0,000000 0 1 getrandom<br />
0,00 0,000000 0 1 rseq<br />
------ ----------- ----------- --------- --------- ----------------<br />
100,00 0,000000 0 43 2 total<br />
</pre><br />
<br /><br />
<br /><br />
<br />
Similarly, '''ltrace''' will list the calls to library functions made by the command that was passed as the argument to ''ltrace''.<br />
<pre class="terminal"><br />
sudo apt install ltrace<br />
</pre><br />
<br /><br />
<br />
== Signals ==<br />
Signals are software interrupts that the the kernel can send an executable. The executable may react to the signal or choose to ignore it. The two signals SIGKILL and SIGTERM, however, can not be ignored by executable and must be handled.<br />
<br /><br />
An overview of the signals can be found in the man pages entry about signals<br />
<pre class="terminal"><br />
man 7 signal<br />
</pre><br />
<br /><br />
Some command-line tools do useful stuff when certain signals are sent to them. For example, the ''dd'' tool prints the progress of the copying task when the SIGUSR1 signal is sent to it via the ''kill'' command.<br />
<pre class="terminal"><br />
dd if=${HOME}/image.iso of=/dev/sdb &<br />
kill -s USR1 $(pidof dd)<br />
</pre><br />
<br /><br />
<br />
== Interprocess Communication Mechanisms ==<br />
<br />
=== Shared Memory ===<br />
Linux offers creating System V shared memory segments, which can be used for interprocess communication.<br />
<pre class="code"><br />
#include <sys/types.h><br />
#include <sys/ipc.h><br />
#include <sys/shm.h><br />
<br />
// creating an IPC key<br />
key_t segmentKey = ftok(”path_to_some_existing_file", 'R')<br />
if (segmentKey == -1) {<br />
perror("could not create IPC key");<br />
exit(1);<br />
}<br />
// accessing the shared memory segment, creating it if it doesn't exist<br />
int sharedMemoryID = shmget(segmentKey, SHM_SIZE, 0644 | IPC_CREAT)<br />
if (sharedMemoryID == -1) {<br />
perror("could not access (or create) the shared memory segment");<br />
exit(1);<br />
}<br />
// attaching a pointer<br />
void* memoryPtr = shmat(sharedMemoryID, NULL, 0);<br />
if (*((char*)memoryPtr) == -1) {<br />
perror("could not attach a pointer to the shared memory segment");<br />
exit(1);<br />
}<br />
</pre><br />
To learn more about shared memory segments, type<br />
<pre class="terminal"><br />
man ftok<br />
man shmget<br />
man shmat<br />
</pre><br />
<br /><br />
<br />
=== Memory Mapped Files ===<br />
Linux offers mapping files to memory regions, which enables working on the file contents much more efficiently, as if it is a memory region. For example, pointers can be used in a C/C++ program to edit the contents. The memory mapped region can be shared between processes. This allows the processes to operate on large files, for example in a writer-subscriber architecture, while preserving memory. Unlike the shared memory method described above, the contents of the shared memory region are written to a file and thus persist between sessions and even system reboots.<br />
<pre class="code"><br />
#include <stdlib.h> <br />
#include <stdio.h> <br />
#include <unistd.h><br />
#include <errno.h> <br />
#include <string.h> <br />
#include <fcntl.h> <br />
#include <sys/types.h> <br />
#include <sys/stat.h> <br />
#include <sys/mman.h> <br />
<br />
static const int MAX_INPUT_LENGTH = 50;<br />
<br />
int main(int argc, char** argv)<br />
{<br />
int fd = open(argv[1], O_RDWR | O_CREAT); <br />
char* shared_mem = mmap(NULL, MAX_INPUT_LENGTH, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); <br />
close(fd); <br />
<br />
if (!strcmp(argv[2], "read")) { <br />
// continously listens to text messages from the 'write' process and writes to the terminal<br />
while (1) { <br />
shared_mem[MAX_INPUT_LENGTH-1] = '\0'; <br />
printf("%s", shared_mem); <br />
sleep(1); <br />
} <br />
} <br />
else if (!strcmp(argv[2], "write")) {<br />
// continuously sends the input from the terminal to the 'read' process<br />
while (1) {<br />
fgets(shared_mem, MAX_INPUT_LENGTH, stdin);<br />
}<br />
}<br />
else {<br />
printf("Unsupported command\n"); <br />
}<br />
}<br />
</pre><br />
<br />
To learn more about memory mapped files, refer to the man page<br />
<pre class="terminal"><br />
man mmap<br />
</pre><br />
<br /><br />
<br />
=== Pipes ===<br />
Pipes are another IPC mechanism where one process can send messages to another.<br />
<pre class="code"><br />
#include <stdio.h><br />
#include <stdlib.h> <br />
#include <errno.h> <br />
#include <sys/types.h> <br />
#include <unistd.h> <br />
<br />
int main(void)<br />
{ <br />
int pipeDescriptor[2]; <br />
<br />
pipe(pipeDescriptor); // writing to pipeDescriptor[0], reading from pipeDescriptor[1]<br />
<br />
if (!fork())<br />
{ <br />
printf(" CHILD: writing to pipe and exiting\n"); <br />
write(pipeDescriptor[1], "test", 5); <br />
}<br />
else<br />
{ <br />
char buffer[5]; <br />
printf("PARENT: reading from pipe\n"); <br />
read(pipeDescriptor[0], buffer, 5); <br />
printf("PARENT: read \"%s\"\n", buf); <br />
wait(NULL); <br />
} <br />
return 0; <br />
}<br />
</pre><br />
<br /><br />
To learn more about pipes, refer to the man page<br />
<pre class="terminal"><br />
man pipe<br />
</pre><br />
<br /><br />
<br />
== dmesg ==<br />
<br /><br />
<br />
== D-Bus ==<br />
<br /><br />
<br />
== GUI-less Mode ==<br />
<br />
=== Switching to GUI-less (Multi-User) Mode with Systemd ===<br />
On a Linux system that uses systemd, we can control whether the graphical user interface is loaded and shown by specifying a suitable systemd target. To turn off the graphical desktop immediately, enter<br />
<pre class="terminal"><br />
sudo systemctl isolate multi-user.target<br />
</pre><br />
To prevent the GUI from being loaded during the system startup, type<br />
<pre class="terminal"><br />
sudo systemctl set-default multi-user.target<br />
</pre><br />
To return to the graphical desktop, type<br />
<br/><br />
<pre class="terminal"><br />
sudo systemctl isolate graphical.target<br />
</pre><br />
and to make the graphical desktop the default again, type<br />
<pre class="terminal"><br />
sudo systemctl set-default graphical.target<br />
</pre><br />
<br /><br />
<br />
=== Setting the Screen Resolution for GUI-less Mode ===<br />
* Restart the machine to the Grub boot menu.<br />
* Press 'c' to get into the Grub command console.<br />
* Run the command 'vbeinfo' to list possible resolutions.<br />
* Note down the desired resolution. For example, ''1024x768x32'', where ''32'' is the color mode.<br />
* Type ''exit'' to return to the Grub boot menu and boot into Ubuntu.<br />
* Open '''/etc/default/grub''' in an editor to add the line<br />
<pre class="code"><br />
GRUB_GFXPAYLOAD_LINUX=1024x768x32<br />
</pre><br />
* Optionally, add the line<br />
<pre class="code"><br />
GRUB_GFXMODE=1024x768<br />
</pre><br />
to set the screen resolution for the GRUB boot menu itself.<br />
* Finally, run the Grub updater<br />
<pre class="terminal"><br />
sudo update-grub<br />
</pre><br />
<br /><br />
<br />
== Message of the Day (MOTD) ==<br />
For users that open simultaneous terminal sessions to different Linux machines, it is helpful to see a distinct ''message of the day'' (''MOTD'') on each terminal. The MOTD can be customized by editing the shell scripts located in '''/etc/update-motd.d/'''. The shell scripts are executed in alphabetical order, their output is the MOTD. The names of the script files start with a number between 1 and 99, which makes ordering of the scripts immediately visible. Script files can be deleted or their execution bit flipped via ''chmod'' in order to disable the corresponding output. New script files can be added, and their file names chosen according to the desired position of their output.<br />
<br /><br />
<br /><br />
Additionally, it is possible to create the '''/etc/motd''' file with static content, whose output will be appended to the dynamically generated MOTD. With ''/etc/motd'', the MOTD can be embellished with ASCII art, like the Robo.Fish logo below<br />
<br /><br />
<br /><br />
<pre class="code"><br />
.';cldxxkkkxxdolc;,..<br />
.;oOXWWMMMMMMMMMMMMMMWWXKOxo:,.<br />
'o0WMMMMMMMMMMMMMMMMMMMMMMMMMMMWX0xl:'.<br />
.;xXMMMMMMMMMMMMMMMMMMMMMMMMMWWWNNXXKKK0kd:.<br />
.:ONMMMMMMMMMMMMMMMMMMWXKOxdoc:;;,'..........<br />
. 'o0WMMMMMMMMMMMMMMWN0xl:,..<br />
Xx:. .:kXWMMMMMMMMMMMMMN0d:'.<br />
MMWKxc'. .'cxXWMMMMMMMMMMMMNOo:,.<br />
MMMMMMN0xc,. .,cd0NWMMMMMMMMMMMMN0o,.<br />
MMMMMMWWNX0d:;ckKNWMMMMMMMMMMWN0xl,.<br />
lllcc:;,'.. ..,;:clloollc:,..<br />
</pre><br />
<br /><br />
The MOTD can be previewed without needing to start a new shell session:<br />
<pre class="terminal"><br />
sudo run-parts /etc/update-motd.d/<br />
</pre><br />
<br /><br />
<br />
== SSH Logins Without Typing The Password ==<br />
If you connect to a remote computer via ''ssh'' or copy files via ''scp'' frequently, you should consider using ''ssh-agent'', which saves you from typing your login password each time.<br />
<br /><br />
<br /><br />
First, you create an RSA public/private key pair that identifies your local machine. You may already have created such a key in your SSH keychain. It is good security practice, however, to use a separate key for each device you want to connect to. Let us assume you want to connect to a [[Raspberry Pi]]. The command to create a new SSH key would be<br />
<pre class="terminal"><br />
ssh-keygen -t rsa -b 2048 -C "for Raspberry Pi"<br />
</pre><br />
where '-b 2048' specifies the key length in bits. You will be prompted to enter the path and name of the file in which the key will be saved. Choose a name that makes it clear that it was created for connecting to the Raspberry Pi. Next, you will be prompted for a password. Just press the Enter key for no password.<br />
<br /><br />
<br /><br />
Now that the SSH key is created, you need to copy the generated key ('''public''') into the folder ''/home/pi/.ssh/'' on the Raspberry Pi:<br />
<pre class="terminal"><br />
scp ~/.ssh/for-raspberry-pi_rsa.pub pi@192.168.1.10:/home/pi/.ssh/authorized_keys<br />
</pre><br />
The copied file is renamed to '''authorized_keys''', which is the expected file name for the SSH server to look up the public keys of trusted clients.<br />
<br /><br />
If ''authorized_keys'' is to hold multiple keys, you should use '''ssh-copy-id''' instead of ''scp'':<br />
<pre class="terminal"><br />
ssh-copy-id -i ~/.ssh/for-raspberry-pi_rsa.pub pi@192.168.1.10<br />
</pre><br />
<br /><br />
Now use ''ssh-agent'' on your local machine to start a special shell session that uses the new SSH key to automatically authenticate any SSH connection from your machine to the Raspberry Pi:<br />
<pre class="terminal"><br />
eval "$(ssh-agent -s)" # starting a new shell session<br />
ssh-add ~/.ssh/for-raspberry-pi_rsa<br />
</pre><br />
Done! This was the last time you had to enter the password for user ''pi''.<br />
<br /><br />
<br /><br />
By the way, you can list all the keys that were added to the SSH agent by entering<br />
<pre class="terminal"><br />
ssh-add -l<br />
</pre><br />
<br /><br />
<br />
<br />
== Bluetooth ==<br />
On most Linux systems, Bluetooth functionality is provided by the kernel module, libraries and utilities of the [http://www.bluez.org BlueZ] project. So, make sure that BlueZ is installed.<br />
<pre class="terminal"><br />
sudo apt install bluez<br />
</pre><br />
<br /><br />
<br />
=== Bluetooth Low Energy (BLE) Control in Terminal ===<br />
Set the Bluetooth controller to operate in BLE mode only by editing '''/etc/bluetooth/main.conf''' to make sure that the value of ''ControllerMode'' is set to ''le''.<br />
<pre class="code"><br />
ControllerMode = le<br />
</pre><br />
If a change had to be made, you need to reboot the system.<br />
<br /><br />
<br /><br />
Now issue the command <br />
<pre class="terminal"><br />
sudo systemctl start bluetooth<br />
</pre><br />
to start the ''bluetooth'' service. You can also stop, restart and query the status with by replacing ''start'' with ''stop'', ''restart'', ''status'', respectively.<br />
<br /><br />
<br /><br />
With the bluetooth service running, enter the command<br />
<pre class="terminal"><br />
bluetoothctl<br />
</pre><br />
which runs a Bluetooth control program in the terminal. In this program you can, for example, display the list of commands, query the controller, power on the controller, scan for devices with RSSI 80 or better, advertise with the local name ''RPi3'' and, finally, power off and quit the program with the following commands: <br />
<pre class="terminal"><br />
help<br />
show<br />
power on<br />
menu scan<br />
rssi 80<br />
back<br />
scan on<br />
...<br />
scan off<br />
discoverable on<br />
advertise on<br />
menu advertise<br />
name RPi3<br />
back<br />
...<br />
advertise off<br />
power off<br />
quit<br />
</pre><br />
<br />
<br />
=== Bluetooth Programming with D-Bus ===<br />
Here is an (incomplete!) example of programming D-Bus in C++ using the [https://github.com/Kistler-Group/sdbus-cpp/blob/master/docs/using-sdbus-c++.md sdbus-c++] C++ binding, for which you need to install ''libsdbus-c++-dev''.<br />
<pre class="terminal"><br />
sudo apt install libbluetooth-dev libsdbus-c++-dev<br />
</pre><br />
<br /><br />
<br />
Inspired by [https://punchthrough.com/creating-a-ble-peripheral-with-bluez/ this article from PunchThrough's Andy Lee], I have created a basic BLE peripheral.<br />
<pre class="code"><br />
#include <sdbus-c++/sdbus-c++.h><br />
#include <iostream><br />
<br />
/**<br />
* Names of D-Bus system services can be looked up with the terminal command<br />
*<br />
* busctl list<br />
*<br />
* We see that the name of the D-Bus system service of the bluetooth daemon is 'org.bluez'.<br />
* The D-Bus object path for a given system service can be queried with the terminal command<br />
*<br />
* busctl tree <service name><br />
*<br />
* For 'org.bluez' let us assume the object path is '/org/bluez/hci0'.<br />
* We can now introspect the interfaces available in the D-Bus object via<br />
*<br />
* busctl introspect org.bluez /org/bluez/hci0<br />
*<br />
* or<br />
*<br />
* gdbus introspect -y -d "org.bluez" -o "/org/bluez/hci0"<br />
* <br />
* We will use to the methods and properties in the published interfaces<br />
* to create a BLE peripheral which advertises a service named 'Test'.<br />
* Additional information on the methods and their parameters can be looked up from<br />
* the BlueZ documentation at https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc<br />
*/<br />
int main(int numargs, char* args[])<br />
{<br />
const char* bluezServiceName = "org.bluez";<br />
const char* bluezObjectPath = "/org/bluez/hci0";<br />
const char* interface_adapter = "org.bluez.Adapter1";<br />
const char* interface_advertisingManager = "org.bluez.LEAdvertisingManager1";<br />
auto bluezProxy = sdbus::createProxy(bluezServiceName, bluezObjectPath);<br />
if (bluezProxy == nullptr)<br />
{<br />
std::cerr << "Error while creating proxy to BlueZ D-Bus service." << std::endl;<br />
return EXIT_FAILURE;<br />
}<br />
bluezProxy->setProperty("Powered").onInterface(interface_adapter).toValue(true);<br />
bluezProxy->setProperty("Alias").onInterface(interface_adapter).toValue("Test");<br />
<br />
// TO BE DONE<br />
<br />
bluezProxy->finishRegistration();<br />
std::cout << "BLE Peripheral Example" << std::endl;<br />
<br />
return EXIT_SUCCESS;<br />
}<br />
<br />
</pre><br />
<br /><br />
<br />
build with<br />
<pre class="terminal"><br />
my_arch=`uname -i`<br />
g++ -o ble-peripheral main.cpp -L/usr/lib/${my_arch}-linux-gnu -lsdbus-c++<br />
</pre><br />
<br /><br />
<br />
== Video4Linux ==<br />
Video4Linux is the video pipeline control system in Linux. Start by installing the required packages. On a Debian distribution, type<br />
<pre class="terminal"><br />
sudo apt install libv4l-0 v4l-utils v4l-conf libv4lconvert0<br />
<br />
v4l2-ctl --list-devices<br />
</pre><br />
<br /><br />
<br />
<br />
== C++ Notes ==<br />
=== Platform detection ===<br />
To detect whether code is compiled for the Linux platform you can check if ''__linux__'' is defined.<br />
<pre class="code"><br />
#ifdef __linux__<br />
</pre><br />
(here you can find [https://sourceforge.net/p/predef/wiki/OperatingSystems preprocessor definitions for many operating systems])<br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Linux&diff=3127Linux2022-12-09T13:17:55Z<p>Kai: Adds section about using ssh-agent.</p>
<hr />
<div>== Boot Procedure ==<br />
# The primary bootloader, which is usually a fixed part of the hardware recognizes bootable media.<br />
#* On PC compatible systems, [https://en.wikipedia.org/wiki/UEFI UEFI] or BIOS are the primary bootloaders.<br />
#* On BIOS systems, the Master Boot Record (MBR) area of a connected storage device is searched for a boot executable. The MBR is a special area, separate from the actual data storage area. BIOS is an old system, dating back to the early 1980s, but not yet obsolete.<br />
#* On a UEFI system, which supports storage media with much larger capacity, the ''GPT'' partition table is used to determine if the storage device provides an ''EFI System Partition'' containing the folder ''/efi'' with a subfolder that contains the secondary boot loader. ''/efi/microsoft'' or ''/efi/grub'', for example. After a Linux system is booted by UEFI hardware, you can open a terminal and inspect the partition table by typing <span class="terminal">sudo gdisk /dev/sda</span>.<br />
# If a secondary bootloader is found on the bootable media, it is loaded.<br />
#* On PC compatibles the secondary bootloader is usually [https://www.gnu.org/software/grub GRUB2].<br />
#* On [[Arm Cortex-A]] based systems, this is often [https://u-boot.readthedocs.io/en/latest/ U-Boot].<br />
#* Some systems have proprietary bootloaders. Raspberry Pi, for example.<br />
#* To support the bootloader, a standard interface called LBA (linear block access) exists for storage media. This interface is not optimized for the capabilities of the storage device but is sufficient for the bootloader to search for a bootable operating system, which will later load the appropriate driver for the storage media.<br />
# The secondary bootloader loads the [https://www.kernel.org Linux kernel].<br />
#* In the case of GRUB2, the boot media is searched for the boot partition using LBA mode, stage 2 is loaded from a separate data area of the boot media, the module for working with the boot partitions filesystem is loaded, the GRUB config file (''/boot/grub/grub.cfg'') is loaded from the boot partition, the user is optionally shown a GRUB menu, the kernel is loaded with the user parameters.<br />
# The kernel optionally loads an initial root file system into memory (often [https://en.wikipedia.org/wiki/Initial_ramdisk initramfs]), which includes the device drivers specific for the target hardware. For example, display drivers for showing graphical output during the boot sequence.<br />
#* Technically, all hardware-specific device drivers can be compiled into the kernel itself. In order to keep the kernel generic, however, and to avoid mixing components with incompatible distribution licenses (the GPL 2.0 license used by Linux prevents distributing a kernel with built-in proprietary drivers), certain drivers are placed into initramfs, from where they are loaded when needed.<br />
#* After the hardware is initialized, the kernel switches from initramfs to the real filesystem.<br />
# The kernel starts the first process, the '''init''' process. The ''init'' process starts all the system processes (a.k.a. ''services'') configured to run when the system launches.<br />
#* ''init'' used to be a shell script located in the filesystem at ''/sbin/init''. Nowadays, many Linux distributions use the '''[https://wiki.debian.org/systemd systemd]''' initialization method, where a binary executable is called instead of a shell script.<br />
<br /><br />
<br />
== systemd ==<br />
=== Systemd Unit Files ===<br />
Unit files determine what kind of task is being started. The types of tasks are<br />
* '''service''' for running daemons<br />
* '''mount''' for mounting storage media, etc<br />
* '''automount''' for mounting directories when needed<br />
* '''timer''' for starting jobs at specific times<br />
* '''target''' (a group of unit files, or a state that the machine should be in after booting)<br />
* '''path''' (monitoring filesystem events)<br />
<br />
The original unit files that are installed by the package manager are placed in ''/usr/lib/systemd/system'' and should not be modified.<br />
If modifications to unit files are to be made, the modified unit files should be placed into ''/etc/systemd/system''.<br />
<br /><br />
<br />
==== Unit Relationships (Dependencies) ====<br />
There are various relationships between two units:<br />
* '''requires''': The dependent unit must be loaded in order to load the current unit.<br />
* '''wants''': The dependent unit is not critical<br />
* '''requisite''': the dependent unit must be loaded and already active.<br />
* '''conflicts''': the unit must not be loaded for the current to be loaded<br />
* '''before''': the current unit must be activated before the given units<br />
* '''after''': the current unit must be activated after the given units<br />
<br /><br />
The dependency graph can be displayed on the terminal via<br />
<pre class="terminal"><br />
sudo systemctl list-dependencies<br />
</pre><br />
<br /><br />
<br />
=== Systemd Services ===<br />
Here is an example of using ''systemctl'' to query the status of the SSH server.<br />
<pre class="terminal"><br />
systemctl status sshd<br />
</pre><br />
<br /><br />
To start or stop the server, you would type<br />
<pre class="terminal"><br />
sudo systemctl start sshd<br />
sudo systemctl stop sshd<br />
</pre><br />
<br /><br />
To configure a service, edit its configuration file located in '''/etc/systemd/system'''.<br />
<br /><br />
<br /><br />
<br />
=== Systemd Targets ===<br />
Targets are groups of unit files. If a target includes the statement <span class="code">AllowIsolate = yes</span> the target becomes an initialization endpoint at which systemd stops executing other units. Isolate targets are therefore similar to System V runlevels that were used for initialization before systemd.<br />
<br /><br />
<br /><br />
For a custom target (or service), the relationship to the unit files that are ''WantedBy'' or ''RequiredBy'' the target (or service) will be established by systemd through symbolic links to the wanted or required unit files. These symbolic links are placed in ''/etc/systemd/system'', within a subdirectory whose name starts with the name of the unit file and ends with the name of the type of relationship.<br />
<br /><br />
<br /><br />
=== Systemd Analysis ===<br />
Systemd can plot a chart that shows how the units are launched over time.<br />
<pre class="terminal"><br />
systemd-analyze plot > analysis.html<br />
</pre><br />
generates an HTML page with a chart like this<br />
<br /><br />
<br /><br />
[[File:systemd-analysis.png | x300px ]]<br />
<br /><br />
<br /><br />
<br />
== Which Linux distro and version am I running? ==<br />
<pre class="terminal"><br />
cat /etc/os-release<br />
</pre><br />
<br /><br />
<br />
== Dynamic Shared Objects (DSO) ==<br />
Ulrich Drepper's [https://www.akkadia.org/drepper/dsohowto.pdf How To Write Shared Libraries] is a good resource for learning more about the ELF format, about optimizing your shared objects, and how to control the visibility of program symbols in the generated binaries.<br />
<br /><br />
<br /><br />
<br />
== Tracing system calls ==<br />
<br />
'''strace''' is a command that lets you trace the system calls made by the command that is passed as the argument. For example,<br />
<pre class="terminal"><br />
strace echo "hello"<br />
</pre><br />
prints<br />
<pre class="terminal"><br />
execve("/usr/bin/echo", ["echo", "hello"], 0x7ffefa8f4928 /* 42 vars */) = 0<br />
brk(NULL) = 0x561cf6532000<br />
arch_prctl(0x3001 /* ARCH_??? */, 0x7fff61293910) = -1 EINVAL (Invalid argument)<br />
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf85c44000<br />
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)<br />
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=53267, ...}, AT_EMPTY_PATH) = 0<br />
mmap(NULL, 53267, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7faf85c36000<br />
close(3) = 0<br />
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3<br />
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\237\2\0\0\0\0\0"..., 832) = 832<br />
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784<br />
pread64(3, "\4\0\0\0 \0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0"..., 48, 848) = 48<br />
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0i8\235HZ\227\223\333\350s\360\352,\223\340."..., 68, 896) = 68<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=2216304, ...}, AT_EMPTY_PATH) = 0<br />
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784<br />
mmap(NULL, 2260560, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7faf85a0e000<br />
mmap(0x7faf85a36000, 1658880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x28000) = 0x7faf85a36000<br />
mmap(0x7faf85bcb000, 360448, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x7faf85bcb000<br />
mmap(0x7faf85c23000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x214000) = 0x7faf85c23000<br />
mmap(0x7faf85c29000, 52816, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7faf85c29000<br />
close(3) = 0<br />
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf85a0b000<br />
arch_prctl(ARCH_SET_FS, 0x7faf85a0b740) = 0<br />
set_tid_address(0x7faf85a0ba10) = 1874<br />
set_robust_list(0x7faf85a0ba20, 24) = 0<br />
rseq(0x7faf85a0c0e0, 0x20, 0, 0x53053053) = 0<br />
mprotect(0x7faf85c23000, 16384, PROT_READ) = 0<br />
mprotect(0x561cf5067000, 4096, PROT_READ) = 0<br />
mprotect(0x7faf85c7e000, 8192, PROT_READ) = 0<br />
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0<br />
munmap(0x7faf85c36000, 53267) = 0<br />
getrandom("\x01\x62\x8d\xf4\xec\xea\xd8\x4e", 8, GRND_NONBLOCK) = 8<br />
brk(NULL) = 0x561cf6532000<br />
brk(0x561cf6553000) = 0x561cf6553000<br />
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=6070224, ...}, AT_EMPTY_PATH) = 0<br />
mmap(NULL, 6070224, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7faf85441000<br />
close(3) = 0<br />
newfstatat(1, "", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}, AT_EMPTY_PATH) = 0<br />
write(1, "hello\n", 6) = 6<br />
close(1) = 0<br />
close(2) = 0<br />
exit_group(0) = ?<br />
+++ exited with 0 +++<br />
</pre><br />
lists system calls made by ''echo'' as they are made.<br />
<br /><br />
<br /><br />
Instead of printing system calls as they are made, ''strace'' can print a short summary of which system calls were how many times and the time spent.<br />
<pre class="terminal"><br />
strace -c echo "hello"<br />
</pre><br />
prints<br />
<pre class="terminal"><br />
hello<br />
% time seconds usecs/call calls errors syscall<br />
------ ----------- ----------- --------- --------- ----------------<br />
0,00 0,000000 0 1 read<br />
0,00 0,000000 0 1 write<br />
0,00 0,000000 0 5 close<br />
0,00 0,000000 0 9 mmap<br />
0,00 0,000000 0 3 mprotect<br />
0,00 0,000000 0 1 munmap<br />
0,00 0,000000 0 3 brk<br />
0,00 0,000000 0 4 pread64<br />
0,00 0,000000 0 1 1 access<br />
0,00 0,000000 0 1 execve<br />
0,00 0,000000 0 2 1 arch_prctl<br />
0,00 0,000000 0 1 set_tid_address<br />
0,00 0,000000 0 3 openat<br />
0,00 0,000000 0 4 newfstatat<br />
0,00 0,000000 0 1 set_robust_list<br />
0,00 0,000000 0 1 prlimit64<br />
0,00 0,000000 0 1 getrandom<br />
0,00 0,000000 0 1 rseq<br />
------ ----------- ----------- --------- --------- ----------------<br />
100,00 0,000000 0 43 2 total<br />
</pre><br />
<br /><br />
<br /><br />
<br />
Similarly, '''ltrace''' will list the calls to library functions made by the command that was passed as the argument to ''ltrace''.<br />
<pre class="terminal"><br />
sudo apt install ltrace<br />
</pre><br />
<br /><br />
<br />
== Signals ==<br />
Signals are software interrupts that the the kernel can send an executable. The executable may react to the signal or choose to ignore it. The two signals SIGKILL and SIGTERM, however, can not be ignored by executable and must be handled.<br />
<br /><br />
An overview of the signals can be found in the man pages entry about signals<br />
<pre class="terminal"><br />
man 7 signal<br />
</pre><br />
<br /><br />
Some command-line tools do useful stuff when certain signals are sent to them. For example, the ''dd'' tool prints the progress of the copying task when the SIGUSR1 signal is sent to it via the ''kill'' command.<br />
<pre class="terminal"><br />
dd if=${HOME}/image.iso of=/dev/sdb &<br />
kill -s USR1 $(pidof dd)<br />
</pre><br />
<br /><br />
<br />
== Interprocess Communication Mechanisms ==<br />
<br />
=== Shared Memory ===<br />
Linux offers creating System V shared memory segments, which can be used for interprocess communication.<br />
<pre class="code"><br />
#include <sys/types.h><br />
#include <sys/ipc.h><br />
#include <sys/shm.h><br />
<br />
// creating an IPC key<br />
key_t segmentKey = ftok(”path_to_some_existing_file", 'R')<br />
if (segmentKey == -1) {<br />
perror("could not create IPC key");<br />
exit(1);<br />
}<br />
// accessing the shared memory segment, creating it if it doesn't exist<br />
int sharedMemoryID = shmget(segmentKey, SHM_SIZE, 0644 | IPC_CREAT)<br />
if (sharedMemoryID == -1) {<br />
perror("could not access (or create) the shared memory segment");<br />
exit(1);<br />
}<br />
// attaching a pointer<br />
void* memoryPtr = shmat(sharedMemoryID, NULL, 0);<br />
if (*((char*)memoryPtr) == -1) {<br />
perror("could not attach a pointer to the shared memory segment");<br />
exit(1);<br />
}<br />
</pre><br />
To learn more about shared memory segments, type<br />
<pre class="terminal"><br />
man ftok<br />
man shmget<br />
man shmat<br />
</pre><br />
<br /><br />
<br />
=== Memory Mapped Files ===<br />
Linux offers mapping files to memory regions, which enables working on the file contents much more efficiently, as if it is a memory region. For example, pointers can be used in a C/C++ program to edit the contents. The memory mapped region can be shared between processes. This allows the processes to operate on large files, for example in a writer-subscriber architecture, while preserving memory. Unlike the shared memory method described above, the contents of the shared memory region are written to a file and thus persist between sessions and even system reboots.<br />
<pre class="code"><br />
#include <stdlib.h> <br />
#include <stdio.h> <br />
#include <unistd.h><br />
#include <errno.h> <br />
#include <string.h> <br />
#include <fcntl.h> <br />
#include <sys/types.h> <br />
#include <sys/stat.h> <br />
#include <sys/mman.h> <br />
<br />
static const int MAX_INPUT_LENGTH = 50;<br />
<br />
int main(int argc, char** argv)<br />
{<br />
int fd = open(argv[1], O_RDWR | O_CREAT); <br />
char* shared_mem = mmap(NULL, MAX_INPUT_LENGTH, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); <br />
close(fd); <br />
<br />
if (!strcmp(argv[2], "read")) { <br />
// continously listens to text messages from the 'write' process and writes to the terminal<br />
while (1) { <br />
shared_mem[MAX_INPUT_LENGTH-1] = '\0'; <br />
printf("%s", shared_mem); <br />
sleep(1); <br />
} <br />
} <br />
else if (!strcmp(argv[2], "write")) {<br />
// continuously sends the input from the terminal to the 'read' process<br />
while (1) {<br />
fgets(shared_mem, MAX_INPUT_LENGTH, stdin);<br />
}<br />
}<br />
else {<br />
printf("Unsupported command\n"); <br />
}<br />
}<br />
</pre><br />
<br />
To learn more about memory mapped files, refer to the man page<br />
<pre class="terminal"><br />
man mmap<br />
</pre><br />
<br /><br />
<br />
=== Pipes ===<br />
Pipes are another IPC mechanism where one process can send messages to another.<br />
<pre class="code"><br />
#include <stdio.h><br />
#include <stdlib.h> <br />
#include <errno.h> <br />
#include <sys/types.h> <br />
#include <unistd.h> <br />
<br />
int main(void)<br />
{ <br />
int pipeDescriptor[2]; <br />
<br />
pipe(pipeDescriptor); // writing to pipeDescriptor[0], reading from pipeDescriptor[1]<br />
<br />
if (!fork())<br />
{ <br />
printf(" CHILD: writing to pipe and exiting\n"); <br />
write(pipeDescriptor[1], "test", 5); <br />
}<br />
else<br />
{ <br />
char buffer[5]; <br />
printf("PARENT: reading from pipe\n"); <br />
read(pipeDescriptor[0], buffer, 5); <br />
printf("PARENT: read \"%s\"\n", buf); <br />
wait(NULL); <br />
} <br />
return 0; <br />
}<br />
</pre><br />
<br /><br />
To learn more about pipes, refer to the man page<br />
<pre class="terminal"><br />
man pipe<br />
</pre><br />
<br /><br />
<br />
== dmesg ==<br />
<br /><br />
<br />
== D-Bus ==<br />
<br /><br />
<br />
== GUI-less Mode ==<br />
<br />
=== Switching to GUI-less (Multi-User) Mode with Systemd ===<br />
On a Linux system that uses systemd, we can control whether the graphical user interface is loaded and shown by specifying a suitable systemd target. To turn off the graphical desktop immediately, enter<br />
<pre class="terminal"><br />
sudo systemctl isolate multi-user.target<br />
</pre><br />
To prevent the GUI from being loaded during the system startup, type<br />
<pre class="terminal"><br />
sudo systemctl set-default multi-user.target<br />
</pre><br />
To return to the graphical desktop, type<br />
<br/><br />
<pre class="terminal"><br />
sudo systemctl isolate graphical.target<br />
</pre><br />
and to make the graphical desktop the default again, type<br />
<pre class="terminal"><br />
sudo systemctl set-default graphical.target<br />
</pre><br />
<br /><br />
<br />
=== Setting the Screen Resolution for GUI-less Mode ===<br />
* Restart the machine to the Grub boot menu.<br />
* Press 'c' to get into the Grub command console.<br />
* Run the command 'vbeinfo' to list possible resolutions.<br />
* Note down the desired resolution. For example, ''1024x768x32'', where ''32'' is the color mode.<br />
* Type ''exit'' to return to the Grub boot menu and boot into Ubuntu.<br />
* Open '''/etc/default/grub''' in an editor to add the line<br />
<pre class="code"><br />
GRUB_GFXPAYLOAD_LINUX=1024x768x32<br />
</pre><br />
* Optionally, add the line<br />
<pre class="code"><br />
GRUB_GFXMODE=1024x768<br />
</pre><br />
to set the screen resolution for the GRUB boot menu itself.<br />
* Finally, run the Grub updater<br />
<pre class="terminal"><br />
sudo update-grub<br />
</pre><br />
<br /><br />
<br />
== Message of the Day (MOTD) ==<br />
For users that open simultaneous terminal sessions to different Linux machines, it is helpful to see a distinct ''message of the day'' (''MOTD'') on each terminal. The MOTD can be customized by editing the shell scripts located in '''/etc/update-motd.d/'''. The shell scripts are executed in alphabetical order, their output is the MOTD. The names of the script files start with a number between 1 and 99, which makes ordering of the scripts immediately visible. Script files can be deleted or their execution bit flipped via ''chmod'' in order to disable the corresponding output. New script files can be added, and their file names chosen according to the desired position of their output.<br />
<br /><br />
<br /><br />
Additionally, it is possible to create the '''/etc/motd''' file with static content, whose output will be appended to the dynamically generated MOTD. With ''/etc/motd'', the MOTD can be embellished with ASCII art, like the Robo.Fish logo below<br />
<br /><br />
<br /><br />
<pre class="code"><br />
.';cldxxkkkxxdolc;,..<br />
.;oOXWWMMMMMMMMMMMMMMWWXKOxo:,.<br />
'o0WMMMMMMMMMMMMMMMMMMMMMMMMMMMWX0xl:'.<br />
.;xXMMMMMMMMMMMMMMMMMMMMMMMMMWWWNNXXKKK0kd:.<br />
.:ONMMMMMMMMMMMMMMMMMMWXKOxdoc:;;,'..........<br />
. 'o0WMMMMMMMMMMMMMMWN0xl:,..<br />
Xx:. .:kXWMMMMMMMMMMMMMN0d:'.<br />
MMWKxc'. .'cxXWMMMMMMMMMMMMNOo:,.<br />
MMMMMMN0xc,. .,cd0NWMMMMMMMMMMMMN0o,.<br />
MMMMMMWWNX0d:;ckKNWMMMMMMMMMMWN0xl,.<br />
lllcc:;,'.. ..,;:clloollc:,..<br />
</pre><br />
<br /><br />
The MOTD can be previewed without needing to start a new shell session:<br />
<pre class="terminal"><br />
sudo run-parts /etc/update-motd.d/<br />
</pre><br />
<br /><br />
<br />
== SSH Logins Without Typing The Password ==<br />
If you connect to a remote computer via ''ssh'' or copy files via ''scp'' frequently, you should consider using ''ssh-agent'', which saves you from typing your login password each time.<br />
<br /><br />
<br /><br />
First, you create an RSA public/private key pair that identifies your local machine. You may already have created such a key in your SSH keychain. It is good security practice, however, to use a separate key for each device you want to connect to. Let us assume you want to connect to a [[Raspberry Pi]]. The command to create a new SSH key would be<br />
<pre class="terminal"><br />
ssh-keygen -t rsa -b 2048 -C "for Raspberry Pi"<br />
</pre><br />
where '-b 2048' specifies the key length in bits. You will be prompted to enter the path and name of the file in which the key will be saved. Choose a name that makes it clear that it was created for connecting to the Raspberry Pi. Next, you will be prompted for a password. Just press the Enter key for no password.<br />
<br /><br />
<br /><br />
Now that the SSH key is created, you need to copy the generated key ('''public''') into the folder ''/home/pi/.ssh/'' on the Raspberry Pi:<br />
<pre class="terminal"><br />
scp ~/.ssh/for-raspberry-pi_rsa.pub pi@192.168.1.10:/home/pi/.ssh/authorized_keys<br />
</pre><br />
The copied file is renamed to '''authorized_keys''', which is the expected file name for the SSH server to look up the public keys of trusted clients.<br />
<br /><br />
If ''authorized_keys'' is to hold multiple keys, you should use '''ssh-copy-id''' instead of ''scp'':<br />
<pre class="terminal"><br />
ssh-copy-id -i ~/.ssh/for-raspberry-pi_rsa.pub pi@192.168.1.10<br />
</pre><br />
<br /><br />
Now use ''ssh-agent'' on your local machine to start a special shell session that uses the new SSH key to automatically authenticate any SSH connection from your machine to the Raspberry Pi:<br />
<pre class="terminal"><br />
eval "$(ssh-agent -s)" # starting a new shell session<br />
ssh-add ~/.ssh/for-raspberry-pi_rsa<br />
</pre><br />
Done! This was the last time you had to enter the password for user ''pi''.<br />
<br /><br />
<br /><br />
By the way, you can list all the keys that were added to the SSH agent by entering<br />
<pre class="terminal"><br />
ssh-add -l<br />
</pre><br />
<br /><br />
<br />
<br />
== Bluetooth ==<br />
On most Linux systems, Bluetooth functionality is provided by the kernel module, libraries and utilities of the [http://www.bluez.org BlueZ] project. So, make sure that BlueZ is installed.<br />
<pre class="terminal"><br />
sudo apt install bluez<br />
</pre><br />
<br /><br />
<br />
=== Bluetooth Low Energy (BLE) Control in Terminal ===<br />
Set the Bluetooth controller to operate in BLE mode only by editing '''/etc/bluetooth/main.conf''' to make sure that the value of ''ControllerMode'' is set to ''le''.<br />
<pre class="code"><br />
ControllerMode = le<br />
</pre><br />
If a change had to be made, you need to reboot the system.<br />
<br /><br />
<br /><br />
Now issue the command <br />
<pre class="terminal"><br />
sudo systemctl start bluetooth<br />
</pre><br />
to start the ''bluetooth'' service. You can also stop, restart and query the status with by replacing ''start'' with ''stop'', ''restart'', ''status'', respectively.<br />
<br /><br />
<br /><br />
With the bluetooth service running, enter the command<br />
<pre class="terminal"><br />
bluetoothctl<br />
</pre><br />
which runs a Bluetooth control program in the terminal. In this program you can, for example, display the list of commands, query the controller, power on the controller, scan for devices with RSSI 80 or better, advertise with the local name ''RPi3'' and, finally, power off and quit the program with the following commands: <br />
<pre class="terminal"><br />
help<br />
show<br />
power on<br />
menu scan<br />
rssi 80<br />
back<br />
scan on<br />
...<br />
scan off<br />
discoverable on<br />
advertise on<br />
menu advertise<br />
name RPi3<br />
back<br />
...<br />
advertise off<br />
power off<br />
quit<br />
</pre><br />
<br />
<br />
=== Bluetooth Programming with D-Bus ===<br />
Here is an (incomplete!) example of programming D-Bus in C++ using the [https://github.com/Kistler-Group/sdbus-cpp/blob/master/docs/using-sdbus-c++.md sdbus-c++] C++ binding, for which you need to install ''libsdbus-c++-dev''.<br />
<pre class="terminal"><br />
sudo apt install libbluetooth-dev libsdbus-c++-dev<br />
</pre><br />
<br /><br />
<br />
Inspired by [https://punchthrough.com/creating-a-ble-peripheral-with-bluez/ this article from PunchThrough's Andy Lee], I have created a basic BLE peripheral.<br />
<pre class="code"><br />
#include <sdbus-c++/sdbus-c++.h><br />
#include <iostream><br />
<br />
/**<br />
* Names of D-Bus system services can be looked up with the terminal command<br />
*<br />
* busctl list<br />
*<br />
* We see that the name of the D-Bus system service of the bluetooth daemon is 'org.bluez'.<br />
* The D-Bus object path for a given system service can be queried with the terminal command<br />
*<br />
* busctl tree <service name><br />
*<br />
* For 'org.bluez' let us assume the object path is '/org/bluez/hci0'.<br />
* We can now introspect the interfaces available in the D-Bus object via<br />
*<br />
* busctl introspect org.bluez /org/bluez/hci0<br />
*<br />
* or<br />
*<br />
* gdbus introspect -y -d "org.bluez" -o "/org/bluez/hci0"<br />
* <br />
* We will use to the methods and properties in the published interfaces<br />
* to create a BLE peripheral which advertises a service named 'Test'.<br />
* Additional information on the methods and their parameters can be looked up from<br />
* the BlueZ documentation at https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc<br />
*/<br />
int main(int numargs, char* args[])<br />
{<br />
const char* bluezServiceName = "org.bluez";<br />
const char* bluezObjectPath = "/org/bluez/hci0";<br />
const char* interface_adapter = "org.bluez.Adapter1";<br />
const char* interface_advertisingManager = "org.bluez.LEAdvertisingManager1";<br />
auto bluezProxy = sdbus::createProxy(bluezServiceName, bluezObjectPath);<br />
if (bluezProxy == nullptr)<br />
{<br />
std::cerr << "Error while creating proxy to BlueZ D-Bus service." << std::endl;<br />
return EXIT_FAILURE;<br />
}<br />
bluezProxy->setProperty("Powered").onInterface(interface_adapter).toValue(true);<br />
bluezProxy->setProperty("Alias").onInterface(interface_adapter).toValue("Test");<br />
<br />
// TO BE DONE<br />
<br />
bluezProxy->finishRegistration();<br />
std::cout << "BLE Peripheral Example" << std::endl;<br />
<br />
return EXIT_SUCCESS;<br />
}<br />
<br />
</pre><br />
<br /><br />
<br />
build with<br />
<pre class="terminal"><br />
my_arch=`uname -i`<br />
g++ -o ble-peripheral main.cpp -L/usr/lib/${my_arch}-linux-gnu -lsdbus-c++<br />
</pre><br />
<br /><br />
<br />
<br />
== C++ Notes ==<br />
=== Platform detection ===<br />
To detect whether code is compiled for the Linux platform you can check if ''__linux__'' is defined.<br />
<pre class="code"><br />
#ifdef __linux__<br />
</pre><br />
(here you can find [https://sourceforge.net/p/predef/wiki/OperatingSystems preprocessor definitions for many operating systems])<br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Linux&diff=3126Linux2022-12-09T13:05:15Z<p>Kai: Adds section about customizing the Message of the Day (MOTD).</p>
<hr />
<div>== Boot Procedure ==<br />
# The primary bootloader, which is usually a fixed part of the hardware recognizes bootable media.<br />
#* On PC compatible systems, [https://en.wikipedia.org/wiki/UEFI UEFI] or BIOS are the primary bootloaders.<br />
#* On BIOS systems, the Master Boot Record (MBR) area of a connected storage device is searched for a boot executable. The MBR is a special area, separate from the actual data storage area. BIOS is an old system, dating back to the early 1980s, but not yet obsolete.<br />
#* On a UEFI system, which supports storage media with much larger capacity, the ''GPT'' partition table is used to determine if the storage device provides an ''EFI System Partition'' containing the folder ''/efi'' with a subfolder that contains the secondary boot loader. ''/efi/microsoft'' or ''/efi/grub'', for example. After a Linux system is booted by UEFI hardware, you can open a terminal and inspect the partition table by typing <span class="terminal">sudo gdisk /dev/sda</span>.<br />
# If a secondary bootloader is found on the bootable media, it is loaded.<br />
#* On PC compatibles the secondary bootloader is usually [https://www.gnu.org/software/grub GRUB2].<br />
#* On [[Arm Cortex-A]] based systems, this is often [https://u-boot.readthedocs.io/en/latest/ U-Boot].<br />
#* Some systems have proprietary bootloaders. Raspberry Pi, for example.<br />
#* To support the bootloader, a standard interface called LBA (linear block access) exists for storage media. This interface is not optimized for the capabilities of the storage device but is sufficient for the bootloader to search for a bootable operating system, which will later load the appropriate driver for the storage media.<br />
# The secondary bootloader loads the [https://www.kernel.org Linux kernel].<br />
#* In the case of GRUB2, the boot media is searched for the boot partition using LBA mode, stage 2 is loaded from a separate data area of the boot media, the module for working with the boot partitions filesystem is loaded, the GRUB config file (''/boot/grub/grub.cfg'') is loaded from the boot partition, the user is optionally shown a GRUB menu, the kernel is loaded with the user parameters.<br />
# The kernel optionally loads an initial root file system into memory (often [https://en.wikipedia.org/wiki/Initial_ramdisk initramfs]), which includes the device drivers specific for the target hardware. For example, display drivers for showing graphical output during the boot sequence.<br />
#* Technically, all hardware-specific device drivers can be compiled into the kernel itself. In order to keep the kernel generic, however, and to avoid mixing components with incompatible distribution licenses (the GPL 2.0 license used by Linux prevents distributing a kernel with built-in proprietary drivers), certain drivers are placed into initramfs, from where they are loaded when needed.<br />
#* After the hardware is initialized, the kernel switches from initramfs to the real filesystem.<br />
# The kernel starts the first process, the '''init''' process. The ''init'' process starts all the system processes (a.k.a. ''services'') configured to run when the system launches.<br />
#* ''init'' used to be a shell script located in the filesystem at ''/sbin/init''. Nowadays, many Linux distributions use the '''[https://wiki.debian.org/systemd systemd]''' initialization method, where a binary executable is called instead of a shell script.<br />
<br /><br />
<br />
== systemd ==<br />
=== Systemd Unit Files ===<br />
Unit files determine what kind of task is being started. The types of tasks are<br />
* '''service''' for running daemons<br />
* '''mount''' for mounting storage media, etc<br />
* '''automount''' for mounting directories when needed<br />
* '''timer''' for starting jobs at specific times<br />
* '''target''' (a group of unit files, or a state that the machine should be in after booting)<br />
* '''path''' (monitoring filesystem events)<br />
<br />
The original unit files that are installed by the package manager are placed in ''/usr/lib/systemd/system'' and should not be modified.<br />
If modifications to unit files are to be made, the modified unit files should be placed into ''/etc/systemd/system''.<br />
<br /><br />
<br />
==== Unit Relationships (Dependencies) ====<br />
There are various relationships between two units:<br />
* '''requires''': The dependent unit must be loaded in order to load the current unit.<br />
* '''wants''': The dependent unit is not critical<br />
* '''requisite''': the dependent unit must be loaded and already active.<br />
* '''conflicts''': the unit must not be loaded for the current to be loaded<br />
* '''before''': the current unit must be activated before the given units<br />
* '''after''': the current unit must be activated after the given units<br />
<br /><br />
The dependency graph can be displayed on the terminal via<br />
<pre class="terminal"><br />
sudo systemctl list-dependencies<br />
</pre><br />
<br /><br />
<br />
=== Systemd Services ===<br />
Here is an example of using ''systemctl'' to query the status of the SSH server.<br />
<pre class="terminal"><br />
systemctl status sshd<br />
</pre><br />
<br /><br />
To start or stop the server, you would type<br />
<pre class="terminal"><br />
sudo systemctl start sshd<br />
sudo systemctl stop sshd<br />
</pre><br />
<br /><br />
To configure a service, edit its configuration file located in '''/etc/systemd/system'''.<br />
<br /><br />
<br /><br />
<br />
=== Systemd Targets ===<br />
Targets are groups of unit files. If a target includes the statement <span class="code">AllowIsolate = yes</span> the target becomes an initialization endpoint at which systemd stops executing other units. Isolate targets are therefore similar to System V runlevels that were used for initialization before systemd.<br />
<br /><br />
<br /><br />
For a custom target (or service), the relationship to the unit files that are ''WantedBy'' or ''RequiredBy'' the target (or service) will be established by systemd through symbolic links to the wanted or required unit files. These symbolic links are placed in ''/etc/systemd/system'', within a subdirectory whose name starts with the name of the unit file and ends with the name of the type of relationship.<br />
<br /><br />
<br /><br />
=== Systemd Analysis ===<br />
Systemd can plot a chart that shows how the units are launched over time.<br />
<pre class="terminal"><br />
systemd-analyze plot > analysis.html<br />
</pre><br />
generates an HTML page with a chart like this<br />
<br /><br />
<br /><br />
[[File:systemd-analysis.png | x300px ]]<br />
<br /><br />
<br /><br />
<br />
== Which Linux distro and version am I running? ==<br />
<pre class="terminal"><br />
cat /etc/os-release<br />
</pre><br />
<br /><br />
<br />
== Dynamic Shared Objects (DSO) ==<br />
Ulrich Drepper's [https://www.akkadia.org/drepper/dsohowto.pdf How To Write Shared Libraries] is a good resource for learning more about the ELF format, about optimizing your shared objects, and how to control the visibility of program symbols in the generated binaries.<br />
<br /><br />
<br /><br />
<br />
== Tracing system calls ==<br />
<br />
'''strace''' is a command that lets you trace the system calls made by the command that is passed as the argument. For example,<br />
<pre class="terminal"><br />
strace echo "hello"<br />
</pre><br />
prints<br />
<pre class="terminal"><br />
execve("/usr/bin/echo", ["echo", "hello"], 0x7ffefa8f4928 /* 42 vars */) = 0<br />
brk(NULL) = 0x561cf6532000<br />
arch_prctl(0x3001 /* ARCH_??? */, 0x7fff61293910) = -1 EINVAL (Invalid argument)<br />
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf85c44000<br />
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)<br />
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=53267, ...}, AT_EMPTY_PATH) = 0<br />
mmap(NULL, 53267, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7faf85c36000<br />
close(3) = 0<br />
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3<br />
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\237\2\0\0\0\0\0"..., 832) = 832<br />
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784<br />
pread64(3, "\4\0\0\0 \0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0"..., 48, 848) = 48<br />
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0i8\235HZ\227\223\333\350s\360\352,\223\340."..., 68, 896) = 68<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=2216304, ...}, AT_EMPTY_PATH) = 0<br />
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784<br />
mmap(NULL, 2260560, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7faf85a0e000<br />
mmap(0x7faf85a36000, 1658880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x28000) = 0x7faf85a36000<br />
mmap(0x7faf85bcb000, 360448, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x7faf85bcb000<br />
mmap(0x7faf85c23000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x214000) = 0x7faf85c23000<br />
mmap(0x7faf85c29000, 52816, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7faf85c29000<br />
close(3) = 0<br />
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf85a0b000<br />
arch_prctl(ARCH_SET_FS, 0x7faf85a0b740) = 0<br />
set_tid_address(0x7faf85a0ba10) = 1874<br />
set_robust_list(0x7faf85a0ba20, 24) = 0<br />
rseq(0x7faf85a0c0e0, 0x20, 0, 0x53053053) = 0<br />
mprotect(0x7faf85c23000, 16384, PROT_READ) = 0<br />
mprotect(0x561cf5067000, 4096, PROT_READ) = 0<br />
mprotect(0x7faf85c7e000, 8192, PROT_READ) = 0<br />
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0<br />
munmap(0x7faf85c36000, 53267) = 0<br />
getrandom("\x01\x62\x8d\xf4\xec\xea\xd8\x4e", 8, GRND_NONBLOCK) = 8<br />
brk(NULL) = 0x561cf6532000<br />
brk(0x561cf6553000) = 0x561cf6553000<br />
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=6070224, ...}, AT_EMPTY_PATH) = 0<br />
mmap(NULL, 6070224, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7faf85441000<br />
close(3) = 0<br />
newfstatat(1, "", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}, AT_EMPTY_PATH) = 0<br />
write(1, "hello\n", 6) = 6<br />
close(1) = 0<br />
close(2) = 0<br />
exit_group(0) = ?<br />
+++ exited with 0 +++<br />
</pre><br />
lists system calls made by ''echo'' as they are made.<br />
<br /><br />
<br /><br />
Instead of printing system calls as they are made, ''strace'' can print a short summary of which system calls were how many times and the time spent.<br />
<pre class="terminal"><br />
strace -c echo "hello"<br />
</pre><br />
prints<br />
<pre class="terminal"><br />
hello<br />
% time seconds usecs/call calls errors syscall<br />
------ ----------- ----------- --------- --------- ----------------<br />
0,00 0,000000 0 1 read<br />
0,00 0,000000 0 1 write<br />
0,00 0,000000 0 5 close<br />
0,00 0,000000 0 9 mmap<br />
0,00 0,000000 0 3 mprotect<br />
0,00 0,000000 0 1 munmap<br />
0,00 0,000000 0 3 brk<br />
0,00 0,000000 0 4 pread64<br />
0,00 0,000000 0 1 1 access<br />
0,00 0,000000 0 1 execve<br />
0,00 0,000000 0 2 1 arch_prctl<br />
0,00 0,000000 0 1 set_tid_address<br />
0,00 0,000000 0 3 openat<br />
0,00 0,000000 0 4 newfstatat<br />
0,00 0,000000 0 1 set_robust_list<br />
0,00 0,000000 0 1 prlimit64<br />
0,00 0,000000 0 1 getrandom<br />
0,00 0,000000 0 1 rseq<br />
------ ----------- ----------- --------- --------- ----------------<br />
100,00 0,000000 0 43 2 total<br />
</pre><br />
<br /><br />
<br /><br />
<br />
Similarly, '''ltrace''' will list the calls to library functions made by the command that was passed as the argument to ''ltrace''.<br />
<pre class="terminal"><br />
sudo apt install ltrace<br />
</pre><br />
<br /><br />
<br /><br />
<br />
== Signals ==<br />
Signals are software interrupts that the the kernel can send an executable. The executable may react to the signal or choose to ignore it. The two signals SIGKILL and SIGTERM, however, can not be ignored by executable and must be handled.<br />
<br /><br />
An overview of the signals can be found in the man pages entry about signals<br />
<pre class="terminal"><br />
man 7 signal<br />
</pre><br />
<br /><br />
Some command-line tools do useful stuff when certain signals are sent to them. For example, the ''dd'' tool prints the progress of the copying task when the SIGUSR1 signal is sent to it via the ''kill'' command.<br />
<pre class="terminal"><br />
dd if=${HOME}/image.iso of=/dev/sdb &<br />
kill -s USR1 $(pidof dd)<br />
</pre><br />
<br /><br />
<br />
== Interprocess Communication Mechanisms ==<br />
<br />
=== Shared Memory ===<br />
Linux offers creating System V shared memory segments, which can be used for interprocess communication.<br />
<pre class="code"><br />
#include <sys/types.h><br />
#include <sys/ipc.h><br />
#include <sys/shm.h><br />
<br />
// creating an IPC key<br />
key_t segmentKey = ftok(”path_to_some_existing_file", 'R')<br />
if (segmentKey == -1) {<br />
perror("could not create IPC key");<br />
exit(1);<br />
}<br />
// accessing the shared memory segment, creating it if it doesn't exist<br />
int sharedMemoryID = shmget(segmentKey, SHM_SIZE, 0644 | IPC_CREAT)<br />
if (sharedMemoryID == -1) {<br />
perror("could not access (or create) the shared memory segment");<br />
exit(1);<br />
}<br />
// attaching a pointer<br />
void* memoryPtr = shmat(sharedMemoryID, NULL, 0);<br />
if (*((char*)memoryPtr) == -1) {<br />
perror("could not attach a pointer to the shared memory segment");<br />
exit(1);<br />
}<br />
</pre><br />
To learn more about shared memory segments, type<br />
<pre class="terminal"><br />
man ftok<br />
man shmget<br />
man shmat<br />
</pre><br />
<br /><br />
<br />
=== Memory Mapped Files ===<br />
Linux offers mapping files to memory regions, which enables working on the file contents much more efficiently, as if it is a memory region. For example, pointers can be used in a C/C++ program to edit the contents. The memory mapped region can be shared between processes. This allows the processes to operate on large files, for example in a writer-subscriber architecture, while preserving memory. Unlike the shared memory method described above, the contents of the shared memory region are written to a file and thus persist between sessions and even system reboots.<br />
<pre class="code"><br />
#include <stdlib.h> <br />
#include <stdio.h> <br />
#include <unistd.h><br />
#include <errno.h> <br />
#include <string.h> <br />
#include <fcntl.h> <br />
#include <sys/types.h> <br />
#include <sys/stat.h> <br />
#include <sys/mman.h> <br />
<br />
static const int MAX_INPUT_LENGTH = 50;<br />
<br />
int main(int argc, char** argv)<br />
{<br />
int fd = open(argv[1], O_RDWR | O_CREAT); <br />
char* shared_mem = mmap(NULL, MAX_INPUT_LENGTH, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); <br />
close(fd); <br />
<br />
if (!strcmp(argv[2], "read")) { <br />
// continously listens to text messages from the 'write' process and writes to the terminal<br />
while (1) { <br />
shared_mem[MAX_INPUT_LENGTH-1] = '\0'; <br />
printf("%s", shared_mem); <br />
sleep(1); <br />
} <br />
} <br />
else if (!strcmp(argv[2], "write")) {<br />
// continuously sends the input from the terminal to the 'read' process<br />
while (1) {<br />
fgets(shared_mem, MAX_INPUT_LENGTH, stdin);<br />
}<br />
}<br />
else {<br />
printf("Unsupported command\n"); <br />
}<br />
}<br />
</pre><br />
<br />
To learn more about memory mapped files, refer to the man page<br />
<pre class="terminal"><br />
man mmap<br />
</pre><br />
<br /><br />
<br />
=== Pipes ===<br />
Pipes are another IPC mechanism where one process can send messages to another.<br />
<pre class="code"><br />
#include <stdio.h><br />
#include <stdlib.h> <br />
#include <errno.h> <br />
#include <sys/types.h> <br />
#include <unistd.h> <br />
<br />
int main(void)<br />
{ <br />
int pipeDescriptor[2]; <br />
<br />
pipe(pipeDescriptor); // writing to pipeDescriptor[0], reading from pipeDescriptor[1]<br />
<br />
if (!fork())<br />
{ <br />
printf(" CHILD: writing to pipe and exiting\n"); <br />
write(pipeDescriptor[1], "test", 5); <br />
}<br />
else<br />
{ <br />
char buffer[5]; <br />
printf("PARENT: reading from pipe\n"); <br />
read(pipeDescriptor[0], buffer, 5); <br />
printf("PARENT: read \"%s\"\n", buf); <br />
wait(NULL); <br />
} <br />
return 0; <br />
}<br />
</pre><br />
<br /><br />
To learn more about pipes, refer to the man page<br />
<pre class="terminal"><br />
man pipe<br />
</pre><br />
<br /><br />
<br />
== dmesg ==<br />
<br /><br />
<br />
== D-Bus ==<br />
<br /><br />
<br />
== GUI-less Mode ==<br />
<br />
=== Switching to GUI-less (Multi-User) Mode with Systemd ===<br />
On a Linux system that uses systemd, we can control whether the graphical user interface is loaded and shown by specifying a suitable systemd target. To turn off the graphical desktop immediately, enter<br />
<pre class="terminal"><br />
sudo systemctl isolate multi-user.target<br />
</pre><br />
To prevent the GUI from being loaded during the system startup, type<br />
<pre class="terminal"><br />
sudo systemctl set-default multi-user.target<br />
</pre><br />
To return to the graphical desktop, type<br />
<br/><br />
<pre class="terminal"><br />
sudo systemctl isolate graphical.target<br />
</pre><br />
and to make the graphical desktop the default again, type<br />
<pre class="terminal"><br />
sudo systemctl set-default graphical.target<br />
</pre><br />
<br /><br />
<br />
=== Setting the Screen Resolution for GUI-less Mode ===<br />
* Restart the machine to the Grub boot menu.<br />
* Press 'c' to get into the Grub command console.<br />
* Run the command 'vbeinfo' to list possible resolutions.<br />
* Note down the desired resolution. For example, ''1024x768x32'', where ''32'' is the color mode.<br />
* Type ''exit'' to return to the Grub boot menu and boot into Ubuntu.<br />
* Open '''/etc/default/grub''' in an editor to add the line<br />
<pre class="code"><br />
GRUB_GFXPAYLOAD_LINUX=1024x768x32<br />
</pre><br />
* Optionally, add the line<br />
<pre class="code"><br />
GRUB_GFXMODE=1024x768<br />
</pre><br />
to set the screen resolution for the GRUB boot menu itself.<br />
* Finally, run the Grub updater<br />
<pre class="terminal"><br />
sudo update-grub<br />
</pre><br />
<br /><br />
<br /><br />
<br />
<br />
== Message of the Day (MOTD) ==<br />
For users that open simultaneous terminal sessions to different Linux machines, it is helpful to see a distinct ''message of the day'' (''MOTD'') on each terminal. The MOTD can be customized by editing the shell scripts located in '''/etc/update-motd.d/'''. The shell scripts are executed in alphabetical order, their output is the MOTD. The names of the script files start with a number between 1 and 99, which makes ordering of the scripts immediately visible. Script files can be deleted or their execution bit flipped via ''chmod'' in order to disable the corresponding output. New script files can be added, and their file names chosen according to the desired position of their output.<br />
<br /><br />
<br /><br />
Additionally, it is possible to create the '''/etc/motd''' file with static content, whose output will be appended to the dynamically generated MOTD. With ''/etc/motd'', the MOTD can be embellished with ASCII art, like the Robo.Fish logo below<br />
<br /><br />
<br /><br />
<pre class="code"><br />
.';cldxxkkkxxdolc;,..<br />
.;oOXWWMMMMMMMMMMMMMMWWXKOxo:,.<br />
'o0WMMMMMMMMMMMMMMMMMMMMMMMMMMMWX0xl:'.<br />
.;xXMMMMMMMMMMMMMMMMMMMMMMMMMWWWNNXXKKK0kd:.<br />
.:ONMMMMMMMMMMMMMMMMMMWXKOxdoc:;;,'..........<br />
. 'o0WMMMMMMMMMMMMMMWN0xl:,..<br />
Xx:. .:kXWMMMMMMMMMMMMMN0d:'.<br />
MMWKxc'. .'cxXWMMMMMMMMMMMMNOo:,.<br />
MMMMMMN0xc,. .,cd0NWMMMMMMMMMMMMN0o,.<br />
MMMMMMWWNX0d:;ckKNWMMMMMMMMMMWN0xl,.<br />
lllcc:;,'.. ..,;:clloollc:,..<br />
</pre><br />
<br /><br />
The MOTD can be previewed without needing to start a new shell session:<br />
<pre class="terminal"><br />
sudo run-parts /etc/update-motd.d/<br />
</pre><br />
<br /><br />
<br /><br />
<br />
<br />
== Bluetooth ==<br />
On most Linux systems, Bluetooth functionality is provided by the kernel module, libraries and utilities of the [http://www.bluez.org BlueZ] project. So, make sure that BlueZ is installed.<br />
<pre class="terminal"><br />
sudo apt install bluez<br />
</pre><br />
<br /><br />
<br />
=== Bluetooth Low Energy (BLE) Control in Terminal ===<br />
Set the Bluetooth controller to operate in BLE mode only by editing '''/etc/bluetooth/main.conf''' to make sure that the value of ''ControllerMode'' is set to ''le''.<br />
<pre class="code"><br />
ControllerMode = le<br />
</pre><br />
If a change had to be made, you need to reboot the system.<br />
<br /><br />
<br /><br />
Now issue the command <br />
<pre class="terminal"><br />
sudo systemctl start bluetooth<br />
</pre><br />
to start the ''bluetooth'' service. You can also stop, restart and query the status with by replacing ''start'' with ''stop'', ''restart'', ''status'', respectively.<br />
<br /><br />
<br /><br />
With the bluetooth service running, enter the command<br />
<pre class="terminal"><br />
bluetoothctl<br />
</pre><br />
which runs a Bluetooth control program in the terminal. In this program you can, for example, display the list of commands, query the controller, power on the controller, scan for devices with RSSI 80 or better, advertise with the local name ''RPi3'' and, finally, power off and quit the program with the following commands: <br />
<pre class="terminal"><br />
help<br />
show<br />
power on<br />
menu scan<br />
rssi 80<br />
back<br />
scan on<br />
...<br />
scan off<br />
discoverable on<br />
advertise on<br />
menu advertise<br />
name RPi3<br />
back<br />
...<br />
advertise off<br />
power off<br />
quit<br />
</pre><br />
<br />
<br />
=== Bluetooth Programming with D-Bus ===<br />
Here is an (incomplete!) example of programming D-Bus in C++ using the [https://github.com/Kistler-Group/sdbus-cpp/blob/master/docs/using-sdbus-c++.md sdbus-c++] C++ binding, for which you need to install ''libsdbus-c++-dev''.<br />
<pre class="terminal"><br />
sudo apt install libbluetooth-dev libsdbus-c++-dev<br />
</pre><br />
<br /><br />
<br />
Inspired by [https://punchthrough.com/creating-a-ble-peripheral-with-bluez/ this article from PunchThrough's Andy Lee], I have created a basic BLE peripheral.<br />
<pre class="code"><br />
#include <sdbus-c++/sdbus-c++.h><br />
#include <iostream><br />
<br />
/**<br />
* Names of D-Bus system services can be looked up with the terminal command<br />
*<br />
* busctl list<br />
*<br />
* We see that the name of the D-Bus system service of the bluetooth daemon is 'org.bluez'.<br />
* The D-Bus object path for a given system service can be queried with the terminal command<br />
*<br />
* busctl tree <service name><br />
*<br />
* For 'org.bluez' let us assume the object path is '/org/bluez/hci0'.<br />
* We can now introspect the interfaces available in the D-Bus object via<br />
*<br />
* busctl introspect org.bluez /org/bluez/hci0<br />
*<br />
* or<br />
*<br />
* gdbus introspect -y -d "org.bluez" -o "/org/bluez/hci0"<br />
* <br />
* We will use to the methods and properties in the published interfaces<br />
* to create a BLE peripheral which advertises a service named 'Test'.<br />
* Additional information on the methods and their parameters can be looked up from<br />
* the BlueZ documentation at https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc<br />
*/<br />
int main(int numargs, char* args[])<br />
{<br />
const char* bluezServiceName = "org.bluez";<br />
const char* bluezObjectPath = "/org/bluez/hci0";<br />
const char* interface_adapter = "org.bluez.Adapter1";<br />
const char* interface_advertisingManager = "org.bluez.LEAdvertisingManager1";<br />
auto bluezProxy = sdbus::createProxy(bluezServiceName, bluezObjectPath);<br />
if (bluezProxy == nullptr)<br />
{<br />
std::cerr << "Error while creating proxy to BlueZ D-Bus service." << std::endl;<br />
return EXIT_FAILURE;<br />
}<br />
bluezProxy->setProperty("Powered").onInterface(interface_adapter).toValue(true);<br />
bluezProxy->setProperty("Alias").onInterface(interface_adapter).toValue("Test");<br />
<br />
// TO BE DONE<br />
<br />
bluezProxy->finishRegistration();<br />
std::cout << "BLE Peripheral Example" << std::endl;<br />
<br />
return EXIT_SUCCESS;<br />
}<br />
<br />
</pre><br />
<br /><br />
<br />
build with<br />
<pre class="terminal"><br />
my_arch=`uname -i`<br />
g++ -o ble-peripheral main.cpp -L/usr/lib/${my_arch}-linux-gnu -lsdbus-c++<br />
</pre><br />
<br /><br />
<br />
<br />
== C++ Notes ==<br />
=== Platform detection ===<br />
To detect whether code is compiled for the Linux platform you can check if ''__linux__'' is defined.<br />
<pre class="code"><br />
#ifdef __linux__<br />
</pre><br />
(here you can find [https://sourceforge.net/p/predef/wiki/OperatingSystems preprocessor definitions for many operating systems])<br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Linux&diff=3125Linux2022-12-09T12:40:40Z<p>Kai: Adds section about Bluetooth wireless communication.</p>
<hr />
<div>== Boot Procedure ==<br />
# The primary bootloader, which is usually a fixed part of the hardware recognizes bootable media.<br />
#* On PC compatible systems, [https://en.wikipedia.org/wiki/UEFI UEFI] or BIOS are the primary bootloaders.<br />
#* On BIOS systems, the Master Boot Record (MBR) area of a connected storage device is searched for a boot executable. The MBR is a special area, separate from the actual data storage area. BIOS is an old system, dating back to the early 1980s, but not yet obsolete.<br />
#* On a UEFI system, which supports storage media with much larger capacity, the ''GPT'' partition table is used to determine if the storage device provides an ''EFI System Partition'' containing the folder ''/efi'' with a subfolder that contains the secondary boot loader. ''/efi/microsoft'' or ''/efi/grub'', for example. After a Linux system is booted by UEFI hardware, you can open a terminal and inspect the partition table by typing <span class="terminal">sudo gdisk /dev/sda</span>.<br />
# If a secondary bootloader is found on the bootable media, it is loaded.<br />
#* On PC compatibles the secondary bootloader is usually [https://www.gnu.org/software/grub GRUB2].<br />
#* On [[Arm Cortex-A]] based systems, this is often [https://u-boot.readthedocs.io/en/latest/ U-Boot].<br />
#* Some systems have proprietary bootloaders. Raspberry Pi, for example.<br />
#* To support the bootloader, a standard interface called LBA (linear block access) exists for storage media. This interface is not optimized for the capabilities of the storage device but is sufficient for the bootloader to search for a bootable operating system, which will later load the appropriate driver for the storage media.<br />
# The secondary bootloader loads the [https://www.kernel.org Linux kernel].<br />
#* In the case of GRUB2, the boot media is searched for the boot partition using LBA mode, stage 2 is loaded from a separate data area of the boot media, the module for working with the boot partitions filesystem is loaded, the GRUB config file (''/boot/grub/grub.cfg'') is loaded from the boot partition, the user is optionally shown a GRUB menu, the kernel is loaded with the user parameters.<br />
# The kernel optionally loads an initial root file system into memory (often [https://en.wikipedia.org/wiki/Initial_ramdisk initramfs]), which includes the device drivers specific for the target hardware. For example, display drivers for showing graphical output during the boot sequence.<br />
#* Technically, all hardware-specific device drivers can be compiled into the kernel itself. In order to keep the kernel generic, however, and to avoid mixing components with incompatible distribution licenses (the GPL 2.0 license used by Linux prevents distributing a kernel with built-in proprietary drivers), certain drivers are placed into initramfs, from where they are loaded when needed.<br />
#* After the hardware is initialized, the kernel switches from initramfs to the real filesystem.<br />
# The kernel starts the first process, the '''init''' process. The ''init'' process starts all the system processes (a.k.a. ''services'') configured to run when the system launches.<br />
#* ''init'' used to be a shell script located in the filesystem at ''/sbin/init''. Nowadays, many Linux distributions use the '''[https://wiki.debian.org/systemd systemd]''' initialization method, where a binary executable is called instead of a shell script.<br />
<br /><br />
<br />
== systemd ==<br />
=== Systemd Unit Files ===<br />
Unit files determine what kind of task is being started. The types of tasks are<br />
* '''service''' for running daemons<br />
* '''mount''' for mounting storage media, etc<br />
* '''automount''' for mounting directories when needed<br />
* '''timer''' for starting jobs at specific times<br />
* '''target''' (a group of unit files, or a state that the machine should be in after booting)<br />
* '''path''' (monitoring filesystem events)<br />
<br />
The original unit files that are installed by the package manager are placed in ''/usr/lib/systemd/system'' and should not be modified.<br />
If modifications to unit files are to be made, the modified unit files should be placed into ''/etc/systemd/system''.<br />
<br /><br />
<br />
==== Unit Relationships (Dependencies) ====<br />
There are various relationships between two units:<br />
* '''requires''': The dependent unit must be loaded in order to load the current unit.<br />
* '''wants''': The dependent unit is not critical<br />
* '''requisite''': the dependent unit must be loaded and already active.<br />
* '''conflicts''': the unit must not be loaded for the current to be loaded<br />
* '''before''': the current unit must be activated before the given units<br />
* '''after''': the current unit must be activated after the given units<br />
<br /><br />
The dependency graph can be displayed on the terminal via<br />
<pre class="terminal"><br />
sudo systemctl list-dependencies<br />
</pre><br />
<br /><br />
<br />
=== Systemd Services ===<br />
Here is an example of using ''systemctl'' to query the status of the SSH server.<br />
<pre class="terminal"><br />
systemctl status sshd<br />
</pre><br />
<br /><br />
To start or stop the server, you would type<br />
<pre class="terminal"><br />
sudo systemctl start sshd<br />
sudo systemctl stop sshd<br />
</pre><br />
<br /><br />
To configure a service, edit its configuration file located in '''/etc/systemd/system'''.<br />
<br /><br />
<br /><br />
<br />
=== Systemd Targets ===<br />
Targets are groups of unit files. If a target includes the statement <span class="code">AllowIsolate = yes</span> the target becomes an initialization endpoint at which systemd stops executing other units. Isolate targets are therefore similar to System V runlevels that were used for initialization before systemd.<br />
<br /><br />
<br /><br />
For a custom target (or service), the relationship to the unit files that are ''WantedBy'' or ''RequiredBy'' the target (or service) will be established by systemd through symbolic links to the wanted or required unit files. These symbolic links are placed in ''/etc/systemd/system'', within a subdirectory whose name starts with the name of the unit file and ends with the name of the type of relationship.<br />
<br /><br />
<br /><br />
=== Systemd Analysis ===<br />
Systemd can plot a chart that shows how the units are launched over time.<br />
<pre class="terminal"><br />
systemd-analyze plot > analysis.html<br />
</pre><br />
generates an HTML page with a chart like this<br />
<br /><br />
<br /><br />
[[File:systemd-analysis.png | x300px ]]<br />
<br /><br />
<br /><br />
<br />
== Which Linux distro and version am I running? ==<br />
<pre class="terminal"><br />
cat /etc/os-release<br />
</pre><br />
<br /><br />
<br />
== Dynamic Shared Objects (DSO) ==<br />
Ulrich Drepper's [https://www.akkadia.org/drepper/dsohowto.pdf How To Write Shared Libraries] is a good resource for learning more about the ELF format, about optimizing your shared objects, and how to control the visibility of program symbols in the generated binaries.<br />
<br /><br />
<br /><br />
<br />
== Tracing system calls ==<br />
<br />
'''strace''' is a command that lets you trace the system calls made by the command that is passed as the argument. For example,<br />
<pre class="terminal"><br />
strace echo "hello"<br />
</pre><br />
prints<br />
<pre class="terminal"><br />
execve("/usr/bin/echo", ["echo", "hello"], 0x7ffefa8f4928 /* 42 vars */) = 0<br />
brk(NULL) = 0x561cf6532000<br />
arch_prctl(0x3001 /* ARCH_??? */, 0x7fff61293910) = -1 EINVAL (Invalid argument)<br />
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf85c44000<br />
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)<br />
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=53267, ...}, AT_EMPTY_PATH) = 0<br />
mmap(NULL, 53267, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7faf85c36000<br />
close(3) = 0<br />
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3<br />
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\237\2\0\0\0\0\0"..., 832) = 832<br />
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784<br />
pread64(3, "\4\0\0\0 \0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0"..., 48, 848) = 48<br />
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0i8\235HZ\227\223\333\350s\360\352,\223\340."..., 68, 896) = 68<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=2216304, ...}, AT_EMPTY_PATH) = 0<br />
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784<br />
mmap(NULL, 2260560, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7faf85a0e000<br />
mmap(0x7faf85a36000, 1658880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x28000) = 0x7faf85a36000<br />
mmap(0x7faf85bcb000, 360448, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x7faf85bcb000<br />
mmap(0x7faf85c23000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x214000) = 0x7faf85c23000<br />
mmap(0x7faf85c29000, 52816, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7faf85c29000<br />
close(3) = 0<br />
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf85a0b000<br />
arch_prctl(ARCH_SET_FS, 0x7faf85a0b740) = 0<br />
set_tid_address(0x7faf85a0ba10) = 1874<br />
set_robust_list(0x7faf85a0ba20, 24) = 0<br />
rseq(0x7faf85a0c0e0, 0x20, 0, 0x53053053) = 0<br />
mprotect(0x7faf85c23000, 16384, PROT_READ) = 0<br />
mprotect(0x561cf5067000, 4096, PROT_READ) = 0<br />
mprotect(0x7faf85c7e000, 8192, PROT_READ) = 0<br />
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0<br />
munmap(0x7faf85c36000, 53267) = 0<br />
getrandom("\x01\x62\x8d\xf4\xec\xea\xd8\x4e", 8, GRND_NONBLOCK) = 8<br />
brk(NULL) = 0x561cf6532000<br />
brk(0x561cf6553000) = 0x561cf6553000<br />
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=6070224, ...}, AT_EMPTY_PATH) = 0<br />
mmap(NULL, 6070224, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7faf85441000<br />
close(3) = 0<br />
newfstatat(1, "", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}, AT_EMPTY_PATH) = 0<br />
write(1, "hello\n", 6) = 6<br />
close(1) = 0<br />
close(2) = 0<br />
exit_group(0) = ?<br />
+++ exited with 0 +++<br />
</pre><br />
lists system calls made by ''echo'' as they are made.<br />
<br /><br />
<br /><br />
Instead of printing system calls as they are made, ''strace'' can print a short summary of which system calls were how many times and the time spent.<br />
<pre class="terminal"><br />
strace -c echo "hello"<br />
</pre><br />
prints<br />
<pre class="terminal"><br />
hello<br />
% time seconds usecs/call calls errors syscall<br />
------ ----------- ----------- --------- --------- ----------------<br />
0,00 0,000000 0 1 read<br />
0,00 0,000000 0 1 write<br />
0,00 0,000000 0 5 close<br />
0,00 0,000000 0 9 mmap<br />
0,00 0,000000 0 3 mprotect<br />
0,00 0,000000 0 1 munmap<br />
0,00 0,000000 0 3 brk<br />
0,00 0,000000 0 4 pread64<br />
0,00 0,000000 0 1 1 access<br />
0,00 0,000000 0 1 execve<br />
0,00 0,000000 0 2 1 arch_prctl<br />
0,00 0,000000 0 1 set_tid_address<br />
0,00 0,000000 0 3 openat<br />
0,00 0,000000 0 4 newfstatat<br />
0,00 0,000000 0 1 set_robust_list<br />
0,00 0,000000 0 1 prlimit64<br />
0,00 0,000000 0 1 getrandom<br />
0,00 0,000000 0 1 rseq<br />
------ ----------- ----------- --------- --------- ----------------<br />
100,00 0,000000 0 43 2 total<br />
</pre><br />
<br /><br />
<br /><br />
<br />
Similarly, '''ltrace''' will list the calls to library functions made by the command that was passed as the argument to ''ltrace''.<br />
<pre class="terminal"><br />
sudo apt install ltrace<br />
</pre><br />
<br /><br />
<br /><br />
<br />
== Signals ==<br />
Signals are software interrupts that the the kernel can send an executable. The executable may react to the signal or choose to ignore it. The two signals SIGKILL and SIGTERM, however, can not be ignored by executable and must be handled.<br />
<br /><br />
An overview of the signals can be found in the man pages entry about signals<br />
<pre class="terminal"><br />
man 7 signal<br />
</pre><br />
<br /><br />
Some command-line tools do useful stuff when certain signals are sent to them. For example, the ''dd'' tool prints the progress of the copying task when the SIGUSR1 signal is sent to it via the ''kill'' command.<br />
<pre class="terminal"><br />
dd if=${HOME}/image.iso of=/dev/sdb &<br />
kill -s USR1 $(pidof dd)<br />
</pre><br />
<br /><br />
<br />
== Interprocess Communication Mechanisms ==<br />
<br />
=== Shared Memory ===<br />
Linux offers creating System V shared memory segments, which can be used for interprocess communication.<br />
<pre class="code"><br />
#include <sys/types.h><br />
#include <sys/ipc.h><br />
#include <sys/shm.h><br />
<br />
// creating an IPC key<br />
key_t segmentKey = ftok(”path_to_some_existing_file", 'R')<br />
if (segmentKey == -1) {<br />
perror("could not create IPC key");<br />
exit(1);<br />
}<br />
// accessing the shared memory segment, creating it if it doesn't exist<br />
int sharedMemoryID = shmget(segmentKey, SHM_SIZE, 0644 | IPC_CREAT)<br />
if (sharedMemoryID == -1) {<br />
perror("could not access (or create) the shared memory segment");<br />
exit(1);<br />
}<br />
// attaching a pointer<br />
void* memoryPtr = shmat(sharedMemoryID, NULL, 0);<br />
if (*((char*)memoryPtr) == -1) {<br />
perror("could not attach a pointer to the shared memory segment");<br />
exit(1);<br />
}<br />
</pre><br />
To learn more about shared memory segments, type<br />
<pre class="terminal"><br />
man ftok<br />
man shmget<br />
man shmat<br />
</pre><br />
<br /><br />
<br />
=== Memory Mapped Files ===<br />
Linux offers mapping files to memory regions, which enables working on the file contents much more efficiently, as if it is a memory region. For example, pointers can be used in a C/C++ program to edit the contents. The memory mapped region can be shared between processes. This allows the processes to operate on large files, for example in a writer-subscriber architecture, while preserving memory. Unlike the shared memory method described above, the contents of the shared memory region are written to a file and thus persist between sessions and even system reboots.<br />
<pre class="code"><br />
#include <stdlib.h> <br />
#include <stdio.h> <br />
#include <unistd.h><br />
#include <errno.h> <br />
#include <string.h> <br />
#include <fcntl.h> <br />
#include <sys/types.h> <br />
#include <sys/stat.h> <br />
#include <sys/mman.h> <br />
<br />
static const int MAX_INPUT_LENGTH = 50;<br />
<br />
int main(int argc, char** argv)<br />
{<br />
int fd = open(argv[1], O_RDWR | O_CREAT); <br />
char* shared_mem = mmap(NULL, MAX_INPUT_LENGTH, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); <br />
close(fd); <br />
<br />
if (!strcmp(argv[2], "read")) { <br />
// continously listens to text messages from the 'write' process and writes to the terminal<br />
while (1) { <br />
shared_mem[MAX_INPUT_LENGTH-1] = '\0'; <br />
printf("%s", shared_mem); <br />
sleep(1); <br />
} <br />
} <br />
else if (!strcmp(argv[2], "write")) {<br />
// continuously sends the input from the terminal to the 'read' process<br />
while (1) {<br />
fgets(shared_mem, MAX_INPUT_LENGTH, stdin);<br />
}<br />
}<br />
else {<br />
printf("Unsupported command\n"); <br />
}<br />
}<br />
</pre><br />
<br />
To learn more about memory mapped files, refer to the man page<br />
<pre class="terminal"><br />
man mmap<br />
</pre><br />
<br /><br />
<br />
=== Pipes ===<br />
Pipes are another IPC mechanism where one process can send messages to another.<br />
<pre class="code"><br />
#include <stdio.h><br />
#include <stdlib.h> <br />
#include <errno.h> <br />
#include <sys/types.h> <br />
#include <unistd.h> <br />
<br />
int main(void)<br />
{ <br />
int pipeDescriptor[2]; <br />
<br />
pipe(pipeDescriptor); // writing to pipeDescriptor[0], reading from pipeDescriptor[1]<br />
<br />
if (!fork())<br />
{ <br />
printf(" CHILD: writing to pipe and exiting\n"); <br />
write(pipeDescriptor[1], "test", 5); <br />
}<br />
else<br />
{ <br />
char buffer[5]; <br />
printf("PARENT: reading from pipe\n"); <br />
read(pipeDescriptor[0], buffer, 5); <br />
printf("PARENT: read \"%s\"\n", buf); <br />
wait(NULL); <br />
} <br />
return 0; <br />
}<br />
</pre><br />
<br /><br />
To learn more about pipes, refer to the man page<br />
<pre class="terminal"><br />
man pipe<br />
</pre><br />
<br /><br />
<br />
== dmesg ==<br />
<br /><br />
<br />
== D-Bus ==<br />
<br /><br />
<br />
== GUI-less Mode ==<br />
<br />
=== Switching to GUI-less (Multi-User) Mode with Systemd ===<br />
On a Linux system that uses systemd, we can control whether the graphical user interface is loaded and shown by specifying a suitable systemd target. To turn off the graphical desktop immediately, enter<br />
<pre class="terminal"><br />
sudo systemctl isolate multi-user.target<br />
</pre><br />
To prevent the GUI from being loaded during the system startup, type<br />
<pre class="terminal"><br />
sudo systemctl set-default multi-user.target<br />
</pre><br />
To return to the graphical desktop, type<br />
<br/><br />
<pre class="terminal"><br />
sudo systemctl isolate graphical.target<br />
</pre><br />
and to make the graphical desktop the default again, type<br />
<pre class="terminal"><br />
sudo systemctl set-default graphical.target<br />
</pre><br />
<br /><br />
<br />
=== Setting the Screen Resolution for GUI-less Mode ===<br />
* Restart the machine to the Grub boot menu.<br />
* Press 'c' to get into the Grub command console.<br />
* Run the command 'vbeinfo' to list possible resolutions.<br />
* Note down the desired resolution. For example, ''1024x768x32'', where ''32'' is the color mode.<br />
* Type ''exit'' to return to the Grub boot menu and boot into Ubuntu.<br />
* Open '''/etc/default/grub''' in an editor to add the line<br />
<pre class="code"><br />
GRUB_GFXPAYLOAD_LINUX=1024x768x32<br />
</pre><br />
* Optionally, add the line<br />
<pre class="code"><br />
GRUB_GFXMODE=1024x768<br />
</pre><br />
to set the screen resolution for the GRUB boot menu itself.<br />
* Finally, run the Grub updater<br />
<pre class="terminal"><br />
sudo update-grub<br />
</pre><br />
<br /><br />
<br /><br />
<br />
== Bluetooth ==<br />
On most Linux systems, Bluetooth functionality is provided by the kernel module, libraries and utilities of the [http://www.bluez.org BlueZ] project. So, make sure that BlueZ is installed.<br />
<pre class="terminal"><br />
sudo apt install bluez<br />
</pre><br />
<br /><br />
<br />
=== Bluetooth Low Energy (BLE) Control in Terminal ===<br />
Set the Bluetooth controller to operate in BLE mode only by editing '''/etc/bluetooth/main.conf''' to make sure that the value of ''ControllerMode'' is set to ''le''.<br />
<pre class="code"><br />
ControllerMode = le<br />
</pre><br />
If a change had to be made, you need to reboot the system.<br />
<br /><br />
<br /><br />
Now issue the command <br />
<pre class="terminal"><br />
sudo systemctl start bluetooth<br />
</pre><br />
to start the ''bluetooth'' service. You can also stop, restart and query the status with by replacing ''start'' with ''stop'', ''restart'', ''status'', respectively.<br />
<br /><br />
<br /><br />
With the bluetooth service running, enter the command<br />
<pre class="terminal"><br />
bluetoothctl<br />
</pre><br />
which runs a Bluetooth control program in the terminal. In this program you can, for example, display the list of commands, query the controller, power on the controller, scan for devices with RSSI 80 or better, advertise with the local name ''RPi3'' and, finally, power off and quit the program with the following commands: <br />
<pre class="terminal"><br />
help<br />
show<br />
power on<br />
menu scan<br />
rssi 80<br />
back<br />
scan on<br />
...<br />
scan off<br />
discoverable on<br />
advertise on<br />
menu advertise<br />
name RPi3<br />
back<br />
...<br />
advertise off<br />
power off<br />
quit<br />
</pre><br />
<br />
<br />
=== Bluetooth Programming with D-Bus ===<br />
Here is an (incomplete!) example of programming D-Bus in C++ using the [https://github.com/Kistler-Group/sdbus-cpp/blob/master/docs/using-sdbus-c++.md sdbus-c++] C++ binding, for which you need to install ''libsdbus-c++-dev''.<br />
<pre class="terminal"><br />
sudo apt install libbluetooth-dev libsdbus-c++-dev<br />
</pre><br />
<br /><br />
<br />
Inspired by [https://punchthrough.com/creating-a-ble-peripheral-with-bluez/ this article from PunchThrough's Andy Lee], I have created a basic BLE peripheral.<br />
<pre class="code"><br />
#include <sdbus-c++/sdbus-c++.h><br />
#include <iostream><br />
<br />
/**<br />
* Names of D-Bus system services can be looked up with the terminal command<br />
*<br />
* busctl list<br />
*<br />
* We see that the name of the D-Bus system service of the bluetooth daemon is 'org.bluez'.<br />
* The D-Bus object path for a given system service can be queried with the terminal command<br />
*<br />
* busctl tree <service name><br />
*<br />
* For 'org.bluez' let us assume the object path is '/org/bluez/hci0'.<br />
* We can now introspect the interfaces available in the D-Bus object via<br />
*<br />
* busctl introspect org.bluez /org/bluez/hci0<br />
*<br />
* or<br />
*<br />
* gdbus introspect -y -d "org.bluez" -o "/org/bluez/hci0"<br />
* <br />
* We will use to the methods and properties in the published interfaces<br />
* to create a BLE peripheral which advertises a service named 'Test'.<br />
* Additional information on the methods and their parameters can be looked up from<br />
* the BlueZ documentation at https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc<br />
*/<br />
int main(int numargs, char* args[])<br />
{<br />
const char* bluezServiceName = "org.bluez";<br />
const char* bluezObjectPath = "/org/bluez/hci0";<br />
const char* interface_adapter = "org.bluez.Adapter1";<br />
const char* interface_advertisingManager = "org.bluez.LEAdvertisingManager1";<br />
auto bluezProxy = sdbus::createProxy(bluezServiceName, bluezObjectPath);<br />
if (bluezProxy == nullptr)<br />
{<br />
std::cerr << "Error while creating proxy to BlueZ D-Bus service." << std::endl;<br />
return EXIT_FAILURE;<br />
}<br />
bluezProxy->setProperty("Powered").onInterface(interface_adapter).toValue(true);<br />
bluezProxy->setProperty("Alias").onInterface(interface_adapter).toValue("Test");<br />
<br />
// TO BE DONE<br />
<br />
bluezProxy->finishRegistration();<br />
std::cout << "BLE Peripheral Example" << std::endl;<br />
<br />
return EXIT_SUCCESS;<br />
}<br />
<br />
</pre><br />
<br /><br />
<br />
build with<br />
<pre class="terminal"><br />
my_arch=`uname -i`<br />
g++ -o ble-peripheral main.cpp -L/usr/lib/${my_arch}-linux-gnu -lsdbus-c++<br />
</pre><br />
<br /><br />
<br />
<br />
== C++ Notes ==<br />
=== Platform detection ===<br />
To detect whether code is compiled for the Linux platform you can check if ''__linux__'' is defined.<br />
<pre class="code"><br />
#ifdef __linux__<br />
</pre><br />
(here you can find [https://sourceforge.net/p/predef/wiki/OperatingSystems preprocessor definitions for many operating systems])<br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Linux&diff=3124Linux2022-12-09T12:36:04Z<p>Kai: Adds subsection on controlling systemd services.</p>
<hr />
<div>== Boot Procedure ==<br />
# The primary bootloader, which is usually a fixed part of the hardware recognizes bootable media.<br />
#* On PC compatible systems, [https://en.wikipedia.org/wiki/UEFI UEFI] or BIOS are the primary bootloaders.<br />
#* On BIOS systems, the Master Boot Record (MBR) area of a connected storage device is searched for a boot executable. The MBR is a special area, separate from the actual data storage area. BIOS is an old system, dating back to the early 1980s, but not yet obsolete.<br />
#* On a UEFI system, which supports storage media with much larger capacity, the ''GPT'' partition table is used to determine if the storage device provides an ''EFI System Partition'' containing the folder ''/efi'' with a subfolder that contains the secondary boot loader. ''/efi/microsoft'' or ''/efi/grub'', for example. After a Linux system is booted by UEFI hardware, you can open a terminal and inspect the partition table by typing <span class="terminal">sudo gdisk /dev/sda</span>.<br />
# If a secondary bootloader is found on the bootable media, it is loaded.<br />
#* On PC compatibles the secondary bootloader is usually [https://www.gnu.org/software/grub GRUB2].<br />
#* On [[Arm Cortex-A]] based systems, this is often [https://u-boot.readthedocs.io/en/latest/ U-Boot].<br />
#* Some systems have proprietary bootloaders. Raspberry Pi, for example.<br />
#* To support the bootloader, a standard interface called LBA (linear block access) exists for storage media. This interface is not optimized for the capabilities of the storage device but is sufficient for the bootloader to search for a bootable operating system, which will later load the appropriate driver for the storage media.<br />
# The secondary bootloader loads the [https://www.kernel.org Linux kernel].<br />
#* In the case of GRUB2, the boot media is searched for the boot partition using LBA mode, stage 2 is loaded from a separate data area of the boot media, the module for working with the boot partitions filesystem is loaded, the GRUB config file (''/boot/grub/grub.cfg'') is loaded from the boot partition, the user is optionally shown a GRUB menu, the kernel is loaded with the user parameters.<br />
# The kernel optionally loads an initial root file system into memory (often [https://en.wikipedia.org/wiki/Initial_ramdisk initramfs]), which includes the device drivers specific for the target hardware. For example, display drivers for showing graphical output during the boot sequence.<br />
#* Technically, all hardware-specific device drivers can be compiled into the kernel itself. In order to keep the kernel generic, however, and to avoid mixing components with incompatible distribution licenses (the GPL 2.0 license used by Linux prevents distributing a kernel with built-in proprietary drivers), certain drivers are placed into initramfs, from where they are loaded when needed.<br />
#* After the hardware is initialized, the kernel switches from initramfs to the real filesystem.<br />
# The kernel starts the first process, the '''init''' process. The ''init'' process starts all the system processes (a.k.a. ''services'') configured to run when the system launches.<br />
#* ''init'' used to be a shell script located in the filesystem at ''/sbin/init''. Nowadays, many Linux distributions use the '''[https://wiki.debian.org/systemd systemd]''' initialization method, where a binary executable is called instead of a shell script.<br />
<br /><br />
<br />
== systemd ==<br />
=== Systemd Unit Files ===<br />
Unit files determine what kind of task is being started. The types of tasks are<br />
* '''service''' for running daemons<br />
* '''mount''' for mounting storage media, etc<br />
* '''automount''' for mounting directories when needed<br />
* '''timer''' for starting jobs at specific times<br />
* '''target''' (a group of unit files, or a state that the machine should be in after booting)<br />
* '''path''' (monitoring filesystem events)<br />
<br />
The original unit files that are installed by the package manager are placed in ''/usr/lib/systemd/system'' and should not be modified.<br />
If modifications to unit files are to be made, the modified unit files should be placed into ''/etc/systemd/system''.<br />
<br /><br />
<br />
==== Unit Relationships (Dependencies) ====<br />
There are various relationships between two units:<br />
* '''requires''': The dependent unit must be loaded in order to load the current unit.<br />
* '''wants''': The dependent unit is not critical<br />
* '''requisite''': the dependent unit must be loaded and already active.<br />
* '''conflicts''': the unit must not be loaded for the current to be loaded<br />
* '''before''': the current unit must be activated before the given units<br />
* '''after''': the current unit must be activated after the given units<br />
<br /><br />
The dependency graph can be displayed on the terminal via<br />
<pre class="terminal"><br />
sudo systemctl list-dependencies<br />
</pre><br />
<br /><br />
<br />
=== Systemd Services ===<br />
Here is an example of using ''systemctl'' to query the status of the SSH server.<br />
<pre class="terminal"><br />
systemctl status sshd<br />
</pre><br />
<br /><br />
To start or stop the server, you would type<br />
<pre class="terminal"><br />
sudo systemctl start sshd<br />
sudo systemctl stop sshd<br />
</pre><br />
<br /><br />
To configure a service, edit its configuration file located in '''/etc/systemd/system'''.<br />
<br /><br />
<br /><br />
<br />
=== Systemd Targets ===<br />
Targets are groups of unit files. If a target includes the statement <span class="code">AllowIsolate = yes</span> the target becomes an initialization endpoint at which systemd stops executing other units. Isolate targets are therefore similar to System V runlevels that were used for initialization before systemd.<br />
<br /><br />
<br /><br />
For a custom target (or service), the relationship to the unit files that are ''WantedBy'' or ''RequiredBy'' the target (or service) will be established by systemd through symbolic links to the wanted or required unit files. These symbolic links are placed in ''/etc/systemd/system'', within a subdirectory whose name starts with the name of the unit file and ends with the name of the type of relationship.<br />
<br /><br />
<br /><br />
=== Systemd Analysis ===<br />
Systemd can plot a chart that shows how the units are launched over time.<br />
<pre class="terminal"><br />
systemd-analyze plot > analysis.html<br />
</pre><br />
generates an HTML page with a chart like this<br />
<br /><br />
<br /><br />
[[File:systemd-analysis.png | x300px ]]<br />
<br /><br />
<br /><br />
<br />
== Which Linux distro and version am I running? ==<br />
<pre class="terminal"><br />
cat /etc/os-release<br />
</pre><br />
<br /><br />
<br />
== Dynamic Shared Objects (DSO) ==<br />
Ulrich Drepper's [https://www.akkadia.org/drepper/dsohowto.pdf How To Write Shared Libraries] is a good resource for learning more about the ELF format, about optimizing your shared objects, and how to control the visibility of program symbols in the generated binaries.<br />
<br /><br />
<br /><br />
<br />
== Tracing system calls ==<br />
<br />
'''strace''' is a command that lets you trace the system calls made by the command that is passed as the argument. For example,<br />
<pre class="terminal"><br />
strace echo "hello"<br />
</pre><br />
prints<br />
<pre class="terminal"><br />
execve("/usr/bin/echo", ["echo", "hello"], 0x7ffefa8f4928 /* 42 vars */) = 0<br />
brk(NULL) = 0x561cf6532000<br />
arch_prctl(0x3001 /* ARCH_??? */, 0x7fff61293910) = -1 EINVAL (Invalid argument)<br />
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf85c44000<br />
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)<br />
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=53267, ...}, AT_EMPTY_PATH) = 0<br />
mmap(NULL, 53267, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7faf85c36000<br />
close(3) = 0<br />
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3<br />
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\237\2\0\0\0\0\0"..., 832) = 832<br />
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784<br />
pread64(3, "\4\0\0\0 \0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0"..., 48, 848) = 48<br />
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0i8\235HZ\227\223\333\350s\360\352,\223\340."..., 68, 896) = 68<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=2216304, ...}, AT_EMPTY_PATH) = 0<br />
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784<br />
mmap(NULL, 2260560, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7faf85a0e000<br />
mmap(0x7faf85a36000, 1658880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x28000) = 0x7faf85a36000<br />
mmap(0x7faf85bcb000, 360448, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x7faf85bcb000<br />
mmap(0x7faf85c23000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x214000) = 0x7faf85c23000<br />
mmap(0x7faf85c29000, 52816, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7faf85c29000<br />
close(3) = 0<br />
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf85a0b000<br />
arch_prctl(ARCH_SET_FS, 0x7faf85a0b740) = 0<br />
set_tid_address(0x7faf85a0ba10) = 1874<br />
set_robust_list(0x7faf85a0ba20, 24) = 0<br />
rseq(0x7faf85a0c0e0, 0x20, 0, 0x53053053) = 0<br />
mprotect(0x7faf85c23000, 16384, PROT_READ) = 0<br />
mprotect(0x561cf5067000, 4096, PROT_READ) = 0<br />
mprotect(0x7faf85c7e000, 8192, PROT_READ) = 0<br />
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0<br />
munmap(0x7faf85c36000, 53267) = 0<br />
getrandom("\x01\x62\x8d\xf4\xec\xea\xd8\x4e", 8, GRND_NONBLOCK) = 8<br />
brk(NULL) = 0x561cf6532000<br />
brk(0x561cf6553000) = 0x561cf6553000<br />
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=6070224, ...}, AT_EMPTY_PATH) = 0<br />
mmap(NULL, 6070224, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7faf85441000<br />
close(3) = 0<br />
newfstatat(1, "", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}, AT_EMPTY_PATH) = 0<br />
write(1, "hello\n", 6) = 6<br />
close(1) = 0<br />
close(2) = 0<br />
exit_group(0) = ?<br />
+++ exited with 0 +++<br />
</pre><br />
lists system calls made by ''echo'' as they are made.<br />
<br /><br />
<br /><br />
Instead of printing system calls as they are made, ''strace'' can print a short summary of which system calls were how many times and the time spent.<br />
<pre class="terminal"><br />
strace -c echo "hello"<br />
</pre><br />
prints<br />
<pre class="terminal"><br />
hello<br />
% time seconds usecs/call calls errors syscall<br />
------ ----------- ----------- --------- --------- ----------------<br />
0,00 0,000000 0 1 read<br />
0,00 0,000000 0 1 write<br />
0,00 0,000000 0 5 close<br />
0,00 0,000000 0 9 mmap<br />
0,00 0,000000 0 3 mprotect<br />
0,00 0,000000 0 1 munmap<br />
0,00 0,000000 0 3 brk<br />
0,00 0,000000 0 4 pread64<br />
0,00 0,000000 0 1 1 access<br />
0,00 0,000000 0 1 execve<br />
0,00 0,000000 0 2 1 arch_prctl<br />
0,00 0,000000 0 1 set_tid_address<br />
0,00 0,000000 0 3 openat<br />
0,00 0,000000 0 4 newfstatat<br />
0,00 0,000000 0 1 set_robust_list<br />
0,00 0,000000 0 1 prlimit64<br />
0,00 0,000000 0 1 getrandom<br />
0,00 0,000000 0 1 rseq<br />
------ ----------- ----------- --------- --------- ----------------<br />
100,00 0,000000 0 43 2 total<br />
</pre><br />
<br /><br />
<br /><br />
<br />
Similarly, '''ltrace''' will list the calls to library functions made by the command that was passed as the argument to ''ltrace''.<br />
<pre class="terminal"><br />
sudo apt install ltrace<br />
</pre><br />
<br /><br />
<br /><br />
<br />
== Signals ==<br />
Signals are software interrupts that the the kernel can send an executable. The executable may react to the signal or choose to ignore it. The two signals SIGKILL and SIGTERM, however, can not be ignored by executable and must be handled.<br />
<br /><br />
An overview of the signals can be found in the man pages entry about signals<br />
<pre class="terminal"><br />
man 7 signal<br />
</pre><br />
<br /><br />
Some command-line tools do useful stuff when certain signals are sent to them. For example, the ''dd'' tool prints the progress of the copying task when the SIGUSR1 signal is sent to it via the ''kill'' command.<br />
<pre class="terminal"><br />
dd if=${HOME}/image.iso of=/dev/sdb &<br />
kill -s USR1 $(pidof dd)<br />
</pre><br />
<br /><br />
<br />
== Interprocess Communication Mechanisms ==<br />
<br />
=== Shared Memory ===<br />
Linux offers creating System V shared memory segments, which can be used for interprocess communication.<br />
<pre class="code"><br />
#include <sys/types.h><br />
#include <sys/ipc.h><br />
#include <sys/shm.h><br />
<br />
// creating an IPC key<br />
key_t segmentKey = ftok(”path_to_some_existing_file", 'R')<br />
if (segmentKey == -1) {<br />
perror("could not create IPC key");<br />
exit(1);<br />
}<br />
// accessing the shared memory segment, creating it if it doesn't exist<br />
int sharedMemoryID = shmget(segmentKey, SHM_SIZE, 0644 | IPC_CREAT)<br />
if (sharedMemoryID == -1) {<br />
perror("could not access (or create) the shared memory segment");<br />
exit(1);<br />
}<br />
// attaching a pointer<br />
void* memoryPtr = shmat(sharedMemoryID, NULL, 0);<br />
if (*((char*)memoryPtr) == -1) {<br />
perror("could not attach a pointer to the shared memory segment");<br />
exit(1);<br />
}<br />
</pre><br />
To learn more about shared memory segments, type<br />
<pre class="terminal"><br />
man ftok<br />
man shmget<br />
man shmat<br />
</pre><br />
<br /><br />
<br />
=== Memory Mapped Files ===<br />
Linux offers mapping files to memory regions, which enables working on the file contents much more efficiently, as if it is a memory region. For example, pointers can be used in a C/C++ program to edit the contents. The memory mapped region can be shared between processes. This allows the processes to operate on large files, for example in a writer-subscriber architecture, while preserving memory. Unlike the shared memory method described above, the contents of the shared memory region are written to a file and thus persist between sessions and even system reboots.<br />
<pre class="code"><br />
#include <stdlib.h> <br />
#include <stdio.h> <br />
#include <unistd.h><br />
#include <errno.h> <br />
#include <string.h> <br />
#include <fcntl.h> <br />
#include <sys/types.h> <br />
#include <sys/stat.h> <br />
#include <sys/mman.h> <br />
<br />
static const int MAX_INPUT_LENGTH = 50;<br />
<br />
int main(int argc, char** argv)<br />
{<br />
int fd = open(argv[1], O_RDWR | O_CREAT); <br />
char* shared_mem = mmap(NULL, MAX_INPUT_LENGTH, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); <br />
close(fd); <br />
<br />
if (!strcmp(argv[2], "read")) { <br />
// continously listens to text messages from the 'write' process and writes to the terminal<br />
while (1) { <br />
shared_mem[MAX_INPUT_LENGTH-1] = '\0'; <br />
printf("%s", shared_mem); <br />
sleep(1); <br />
} <br />
} <br />
else if (!strcmp(argv[2], "write")) {<br />
// continuously sends the input from the terminal to the 'read' process<br />
while (1) {<br />
fgets(shared_mem, MAX_INPUT_LENGTH, stdin);<br />
}<br />
}<br />
else {<br />
printf("Unsupported command\n"); <br />
}<br />
}<br />
</pre><br />
<br />
To learn more about memory mapped files, refer to the man page<br />
<pre class="terminal"><br />
man mmap<br />
</pre><br />
<br /><br />
<br />
=== Pipes ===<br />
Pipes are another IPC mechanism where one process can send messages to another.<br />
<pre class="code"><br />
#include <stdio.h><br />
#include <stdlib.h> <br />
#include <errno.h> <br />
#include <sys/types.h> <br />
#include <unistd.h> <br />
<br />
int main(void)<br />
{ <br />
int pipeDescriptor[2]; <br />
<br />
pipe(pipeDescriptor); // writing to pipeDescriptor[0], reading from pipeDescriptor[1]<br />
<br />
if (!fork())<br />
{ <br />
printf(" CHILD: writing to pipe and exiting\n"); <br />
write(pipeDescriptor[1], "test", 5); <br />
}<br />
else<br />
{ <br />
char buffer[5]; <br />
printf("PARENT: reading from pipe\n"); <br />
read(pipeDescriptor[0], buffer, 5); <br />
printf("PARENT: read \"%s\"\n", buf); <br />
wait(NULL); <br />
} <br />
return 0; <br />
}<br />
</pre><br />
<br /><br />
To learn more about pipes, refer to the man page<br />
<pre class="terminal"><br />
man pipe<br />
</pre><br />
<br /><br />
<br />
== dmesg ==<br />
<br /><br />
<br />
== D-Bus ==<br />
<br /><br />
<br />
== GUI-less Mode ==<br />
<br />
=== Switching to GUI-less (Multi-User) Mode with Systemd ===<br />
On a Linux system that uses systemd, we can control whether the graphical user interface is loaded and shown by specifying a suitable systemd target. To turn off the graphical desktop immediately, enter<br />
<pre class="terminal"><br />
sudo systemctl isolate multi-user.target<br />
</pre><br />
To prevent the GUI from being loaded during the system startup, type<br />
<pre class="terminal"><br />
sudo systemctl set-default multi-user.target<br />
</pre><br />
To return to the graphical desktop, type<br />
<br/><br />
<pre class="terminal"><br />
sudo systemctl isolate graphical.target<br />
</pre><br />
and to make the graphical desktop the default again, type<br />
<pre class="terminal"><br />
sudo systemctl set-default graphical.target<br />
</pre><br />
<br /><br />
<br />
=== Setting the Screen Resolution for GUI-less Mode ===<br />
* Restart the machine to the Grub boot menu.<br />
* Press 'c' to get into the Grub command console.<br />
* Run the command 'vbeinfo' to list possible resolutions.<br />
* Note down the desired resolution. For example, ''1024x768x32'', where ''32'' is the color mode.<br />
* Type ''exit'' to return to the Grub boot menu and boot into Ubuntu.<br />
* Open '''/etc/default/grub''' in an editor to add the line<br />
<pre class="code"><br />
GRUB_GFXPAYLOAD_LINUX=1024x768x32<br />
</pre><br />
* Optionally, add the line<br />
<pre class="code"><br />
GRUB_GFXMODE=1024x768<br />
</pre><br />
to set the screen resolution for the GRUB boot menu itself.<br />
* Finally, run the Grub updater<br />
<pre class="terminal"><br />
sudo update-grub<br />
</pre><br />
<br /><br />
<br /><br />
<br />
<br />
== C++ Notes ==<br />
=== Platform detection ===<br />
To detect whether code is compiled for the Linux platform you can check if ''__linux__'' is defined.<br />
<pre class="code"><br />
#ifdef __linux__<br />
</pre><br />
(here you can find [https://sourceforge.net/p/predef/wiki/OperatingSystems preprocessor definitions for many operating systems])<br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Ubuntu&diff=3123Ubuntu2022-12-09T12:23:05Z<p>Kai: Adds section about using Netplan to set up WLAN access.</p>
<hr />
<div><br /><br />
== <br /> Introduction ==<br />
[https://ubuntu.com Ubuntu] is a [[Linux]] distribution with excellent support and a broad user community. Many technical projects use this distribution as their target platform. Ubuntu is based on [http://debian.org Debian] Linux. The package management tools are therefore [https://www.debian.org/doc/manuals/debian-faq/ch-pkgtools.en.html ''dpkg'' and ''apt-get''].<br />
<br /><br />
<br /><br />
<br />
== Determining the Version of Ubuntu Running ==<br />
Use the '''lsb_release''' command to view version information about the running [https://en.wikipedia.org/wiki/Linux_Standard_Base LSB-compliant] Linux system.<br />
<pre class="terminal"><br />
sudo apt install lsb-release<br />
lsb_release -a<br />
</pre><br />
generates the example output<br />
<pre class="terminal"><br />
No LSB modules are available.<br />
Distributor ID: Ubuntu<br />
Description: Ubuntu 22.04.1 LTS<br />
Release: 22.04<br />
Codename: jammy<br />
</pre><br />
<br /><br />
<br />
== Upgrading To A New Release ==<br />
First of all, check you current version by typing<br />
<pre class="terminal"><br />
lsb_release -a<br />
</pre><br />
To upgrade to a new major release (for example, 16.04 to 16.10) type the command<br />
<pre class="terminal"><br />
do-release-upgrade<br />
</pre><br />
If there is no major release available but a point release has been issued, you can upgrade by typing<br />
<pre class="terminal"><br />
sudo apt-get update<br />
sudo apt-get dist-upgrade<br />
</pre><br />
<br /><br />
== Working With Repositories ==<br />
=== Repository Sources ===<br />
Third-party repositories can be added to the list of source repositories with the command<br />
<pre class="terminal"><br />
sudo apt-add-repository <repository URL><br />
</pre><br />
<br /><br />
Source repositories that are provided by Ubuntu can be found in the file ''/etc/apt/sources.list''. Third-party repositories that have been added afterwards can be found in the directory ''/etc/apt/sources.list.d/''.<br />
<br /><br />
<br /><br />
=== Querying Installed Packages ===<br />
To find out which package a given file belongs to:<br />
<pre class="terminal"><br />
apt contains <file path><br />
</pre><br />
<br/><br />
To find out which files are included in a package use the Debian utility ''dpgk'':<br />
<pre class="terminal"><br />
dpkg -L <package name><br />
</pre><br />
<br/><br />
<br/><br />
<br />
== Setting up WLAN with Netplan ==<br />
[https://netplan.io Netplan] is a network configuration system created by Canonical. YAML files are used to describe the desired network configurations. Netplan command-line tools are used to apply a given network configuration.<br />
<br /><br />
<br /><br />
To set up WLAN access using Netplan In the '''/etc/netplan''' folder, find the network configuration definition file (most likely '''50-cloud-init.yaml'''). Open the file in an editor. You should find an existing ethernet configuration:<br />
<pre class="code"><br />
network:<br />
ethernets:<br />
eth0:<br />
dhcp4: true<br />
optional: true<br />
version: 2<br />
</pre><br />
where ''eth0'' is an example ethernet interface. To add a WiFi configuration, add the lines<br />
<pre class="code"><br />
wifis:<br />
<wlan>:<br />
optional: true<br />
access-points:<br />
"<ssid>":<br />
password: "<password>"<br />
dhcp4: true<br />
</pre><br />
where ''<wlan>'' is usually ''wlan0'', and ''<ssid>'' and ''<password>'' need to be replaced with the actual WiFi SSID and password.<br />
<br/><br />
<br/><br />
As this is a YAML file, make sure that indentation levels are correct and only whitespace (no tab characters) is used.<br />
<br/><br />
<br/><br />
Now activate the new configuration via<br />
<pre class="terminal"><br />
sudo netplan generate<br />
sudo netplan apply<br />
</pre><br />
and check with<br />
<pre class="terminal"><br />
ip a<br />
</pre><br />
<br/><br />
<br/><br />
<br/><br />
<br />
== NFS (Network File System) ==<br />
=== Setting up an NFS Server ===<br />
<pre class="terminal"><br />
sudo apt install nfs-kernel-server<br />
</pre><br />
then edit '''/etc/exports''' to add lines in the following format:<br />
<pre class="code"><br />
<directory> <hostname>(<options>) [<hostname>(<options>)]*<br />
</pre><br />
where ''<directory>'' is the directory that you want to make available over NFS, followed by one or more pairs of client host names and access options. ''<hostname>'' can be an IP address, a domain name with wildcards, or a subnet. of the allowed client machine, ''<options>'' is a list of options that determine whether the directory is, e.g., writable. The file format is better explained in this [https://www.thegeekdiary.com/understanding-the-etc-exports-file/ article]. Examples are<br />
<pre class="code"><br />
/home/james/photos 192.168.178.62(r,async) 192.168.178.55(r, async)<br />
/mnt/storage2 192.168.178.0/24(rw,sync,no_subtree_check)<br />
</pre><br />
After editing ''/etc/exports'', apply the NFS configuration via '''/usr/sbin/exportfs''':<br />
<pre class="terminal"><br />
sudo exportfs -ar<br />
</pre><br />
<br /><br />
Query the allowed NFS protocol versions for the clients via<br />
<pre class="terminal"><br />
sudo cat /proc/fs/nfsd/versions<br />
</pre><br />
<br /><br />
<br />
=== Mounting an NFS Drive ===<br />
<pre class="terminal"><br />
sudo apt install nfs-common<br />
</pre><br />
and mount the NFS with the usual ''/usr/bin/mount'' command using the '''-t nfs''' option like in this example:<br />
<pre class="terminal"> <br />
sudo mount -t nfs -o vers=4 192.168.178.8:/storage /backups<br />
</pre><br />
where ''vers=4'' indicates the NFS protocol version, ''192.168.178.8'' is the address of the NFS server, ''/storage'' is the path of the served directory on the NFS server (in NFS version 4 the path is relative to the served NFS root directory), and ''/backups'' is the mount point on the client machine<br />
<br /><br />
<br /><br />
<br />
== Installing NVIDIA Drivers ==<br />
Follow the [https://help.ubuntu.com/community/BinaryDriverHowto/Nvidia instructions from Ubuntu] to install device drivers for NVIDIA graphics cards and configure for your system. There are also instructions for [https://help.ubuntu.com/community/NvidiaManual manually installing a driver] downloaded from NVIDIA, which is not recommended.<br />
<br /><br />
<br /><br />
Alternative packages with newer drivers are available via Launchpad after adding the ''graphics-drivers'' repository by typing <br />
<pre class="terminal"><br />
sudo add-apt-repository ppa:graphics-drivers/ppa<br />
sudo apt update<br />
</pre><br />
<br /><br />
If your monitor cable (HDMI, DisplayPort, etc.) is connected to the output of the integrated graphics solution of your computer (e.g., Intel Skylake Graphics) you should shut down your computer and your monitor, unplug the monitor cable from the integrated graphics port and plug it into one of the ports of the NVIDIA card. Restart your computer, boot into the BIOS utility provided by your motherboard and check that Secure Boot is disabled, otherwise it will prevent kernel modules from being loaded.<br />
<br /><br />
<br /><br />
Make sure ''nvidia-prime'' is installed and use it to select the NVIDIA card as the prime graphics output:<br />
<pre class="terminal"><br />
sudo apt install nvidia-prime<br />
sudo prime-select nvidia<br />
</pre><br />
This modifies ''/etc/ld.so.conf.d/x86_64-linux-gnu_GL.conf'' and ''/etc/ld.so.conf.d/x86_64-linux-gnu_EGL.conf'' to use the latest installed nvidia driver. To check the status of the graphics card and the driver assigned to it you can enter<br />
<pre class="terminal"><br />
inxi -G<br />
</pre><br />
The output should look like this:<br />
<pre class="terminal"><br />
Graphics: Card: NVIDIA Device 1b81<br />
Display Server: X.Org 1.18.4 drivers: nvidia (unloaded: fbdev,vesa,nouveau)<br />
Resolution: 3840x2160@60.00hz<br />
GLX Renderer: GeForce GTX 1070/PCIe/SSE2 GLX Version: 4.5.0 NVIDIA 370.28<br />
</pre><br />
Note that ''nvidia'' is the selected driver in the line that starts with ''Display Server:''.<br />
<br /><br />
<br /><br />
You may have to add the string ''nomodeset'' to the line that starts with ''GRUB_CMDLINE_LINUX_DEFAULT='' in the file ''/etc/default/grub''. For example,<br />
<pre class="code"><br />
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash nomodeset"<br />
</pre><br />
where ''quiet'' and ''splash'' were the default options on my system. Be sure to run<br />
<pre class="terminal"><br />
sudo update-grub<br />
</pre><br />
so that the change to ''/etc/default/grub'' has an effect on ''/boot/grub/grub.cfg''. Beware, however, that adding ''nomodeset'' will also prevent your display mode from being detected and set automatically if anything should go wrong. Finally, if your boot disk contains multiple bootable Linux system partitions, make sure that the bootloader that you just updated is the one installed in the Master Boot Record (MBR). You can install a Grub bootloader in the MBR via<br />
<pre class="terminal"><br />
$ sudo grub-install --boot-directory=/boot /dev/sda<br />
$ sudo update-grub <br />
</pre><br />
where ''/dev/sda'' is an example and needs to be replaced with your specific boot disk device file.<br />
<br /><br />
<br /><br />
Other useful commands to check the device status are:<br />
<pre class="terminal"><br />
ubuntu-drivers devices<br />
</pre><br />
for showing a list of packages from the Ubuntu repository that are drivers for the installed hardware,<br />
<pre class="terminal"><br />
sudo lshw -c display<br />
</pre><br />
for showing information about installed hardware in the ''display'' category,<br />
<pre class="terminal"><br />
lspci -nnk | grep -iA3 vga<br />
</pre><br />
for showing information about graphics cards connected to the PCI bus, and<br />
<pre class="terminal"><br />
xrandr<br />
</pre><br />
for showing a list of possible display modes in which the connected screen can operate.<br />
<br /><br />
<br /></div>Kaihttps://Robo.Fish/wiki/index.php?title=Linux&diff=3122Linux2022-12-09T12:06:26Z<p>Kai: Adds section about switching to gui-less mode.</p>
<hr />
<div>== Boot Procedure ==<br />
# The primary bootloader, which is usually a fixed part of the hardware recognizes bootable media.<br />
#* On PC compatible systems, [https://en.wikipedia.org/wiki/UEFI UEFI] or BIOS are the primary bootloaders.<br />
#* On BIOS systems, the Master Boot Record (MBR) area of a connected storage device is searched for a boot executable. The MBR is a special area, separate from the actual data storage area. BIOS is an old system, dating back to the early 1980s, but not yet obsolete.<br />
#* On a UEFI system, which supports storage media with much larger capacity, the ''GPT'' partition table is used to determine if the storage device provides an ''EFI System Partition'' containing the folder ''/efi'' with a subfolder that contains the secondary boot loader. ''/efi/microsoft'' or ''/efi/grub'', for example. After a Linux system is booted by UEFI hardware, you can open a terminal and inspect the partition table by typing <span class="terminal">sudo gdisk /dev/sda</span>.<br />
# If a secondary bootloader is found on the bootable media, it is loaded.<br />
#* On PC compatibles the secondary bootloader is usually [https://www.gnu.org/software/grub GRUB2].<br />
#* On [[Arm Cortex-A]] based systems, this is often [https://u-boot.readthedocs.io/en/latest/ U-Boot].<br />
#* Some systems have proprietary bootloaders. Raspberry Pi, for example.<br />
#* To support the bootloader, a standard interface called LBA (linear block access) exists for storage media. This interface is not optimized for the capabilities of the storage device but is sufficient for the bootloader to search for a bootable operating system, which will later load the appropriate driver for the storage media.<br />
# The secondary bootloader loads the [https://www.kernel.org Linux kernel].<br />
#* In the case of GRUB2, the boot media is searched for the boot partition using LBA mode, stage 2 is loaded from a separate data area of the boot media, the module for working with the boot partitions filesystem is loaded, the GRUB config file (''/boot/grub/grub.cfg'') is loaded from the boot partition, the user is optionally shown a GRUB menu, the kernel is loaded with the user parameters.<br />
# The kernel optionally loads an initial root file system into memory (often [https://en.wikipedia.org/wiki/Initial_ramdisk initramfs]), which includes the device drivers specific for the target hardware. For example, display drivers for showing graphical output during the boot sequence.<br />
#* Technically, all hardware-specific device drivers can be compiled into the kernel itself. In order to keep the kernel generic, however, and to avoid mixing components with incompatible distribution licenses (the GPL 2.0 license used by Linux prevents distributing a kernel with built-in proprietary drivers), certain drivers are placed into initramfs, from where they are loaded when needed.<br />
#* After the hardware is initialized, the kernel switches from initramfs to the real filesystem.<br />
# The kernel starts the first process, the '''init''' process. The ''init'' process starts all the system processes (a.k.a. ''services'') configured to run when the system launches.<br />
#* ''init'' used to be a shell script located in the filesystem at ''/sbin/init''. Nowadays, many Linux distributions use the '''[https://wiki.debian.org/systemd systemd]''' initialization method, where a binary executable is called instead of a shell script.<br />
<br /><br />
<br />
== systemd ==<br />
=== Systemd Unit Files ===<br />
Unit files determine what kind of task is being started. The types of tasks are<br />
* '''service''' for running daemons<br />
* '''mount''' for mounting storage media, etc<br />
* '''automount''' for mounting directories when needed<br />
* '''timer''' for starting jobs at specific times<br />
* '''target''' (a group of unit files, or a state that the machine should be in after booting)<br />
* '''path''' (monitoring filesystem events)<br />
<br />
The original unit files that are installed by the package manager are placed in ''/usr/lib/systemd/system'' and should not be modified.<br />
If modifications to unit files are to be made, the modified unit files should be placed into ''/etc/systemd/system''.<br />
<br /><br />
<br />
==== Unit Relationships (Dependencies) ====<br />
There are various relationships between two units:<br />
* '''requires''': The dependent unit must be loaded in order to load the current unit.<br />
* '''wants''': The dependent unit is not critical<br />
* '''requisite''': the dependent unit must be loaded and already active.<br />
* '''conflicts''': the unit must not be loaded for the current to be loaded<br />
* '''before''': the current unit must be activated before the given units<br />
* '''after''': the current unit must be activated after the given units<br />
<br /><br />
The dependency graph can be displayed on the terminal via<br />
<pre class="terminal"><br />
sudo systemctl list-dependencies<br />
</pre><br />
<br /><br />
<br />
=== Systemd Targets ===<br />
Targets are groups of unit files. If a target includes the statement <span class="code">AllowIsolate = yes</span> the target becomes an initialization endpoint at which systemd stops executing other units. Isolate targets are therefore similar to System V runlevels that were used for initialization before systemd.<br />
<br /><br />
<br /><br />
For a custom target (or service), the relationship to the unit files that are ''WantedBy'' or ''RequiredBy'' the target (or service) will be established by systemd through symbolic links to the wanted or required unit files. These symbolic links are placed in ''/etc/systemd/system'', within a subdirectory whose name starts with the name of the unit file and ends with the name of the type of relationship.<br />
<br /><br />
<br /><br />
=== Systemd Analysis ===<br />
Systemd can plot a chart that shows how the units are launched over time.<br />
<pre class="terminal"><br />
systemd-analyze plot > analysis.html<br />
</pre><br />
generates an HTML page with a chart like this<br />
<br /><br />
<br /><br />
[[File:systemd-analysis.png | x300px ]]<br />
<br /><br />
<br /><br />
<br />
== Which Linux distro and version am I running? ==<br />
<pre class="terminal"><br />
cat /etc/os-release<br />
</pre><br />
<br /><br />
<br />
== Dynamic Shared Objects (DSO) ==<br />
Ulrich Drepper's [https://www.akkadia.org/drepper/dsohowto.pdf How To Write Shared Libraries] is a good resource for learning more about the ELF format, about optimizing your shared objects, and how to control the visibility of program symbols in the generated binaries.<br />
<br /><br />
<br /><br />
<br />
== Tracing system calls ==<br />
<br />
'''strace''' is a command that lets you trace the system calls made by the command that is passed as the argument. For example,<br />
<pre class="terminal"><br />
strace echo "hello"<br />
</pre><br />
prints<br />
<pre class="terminal"><br />
execve("/usr/bin/echo", ["echo", "hello"], 0x7ffefa8f4928 /* 42 vars */) = 0<br />
brk(NULL) = 0x561cf6532000<br />
arch_prctl(0x3001 /* ARCH_??? */, 0x7fff61293910) = -1 EINVAL (Invalid argument)<br />
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf85c44000<br />
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)<br />
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=53267, ...}, AT_EMPTY_PATH) = 0<br />
mmap(NULL, 53267, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7faf85c36000<br />
close(3) = 0<br />
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3<br />
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\237\2\0\0\0\0\0"..., 832) = 832<br />
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784<br />
pread64(3, "\4\0\0\0 \0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0"..., 48, 848) = 48<br />
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0i8\235HZ\227\223\333\350s\360\352,\223\340."..., 68, 896) = 68<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=2216304, ...}, AT_EMPTY_PATH) = 0<br />
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784<br />
mmap(NULL, 2260560, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7faf85a0e000<br />
mmap(0x7faf85a36000, 1658880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x28000) = 0x7faf85a36000<br />
mmap(0x7faf85bcb000, 360448, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x7faf85bcb000<br />
mmap(0x7faf85c23000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x214000) = 0x7faf85c23000<br />
mmap(0x7faf85c29000, 52816, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7faf85c29000<br />
close(3) = 0<br />
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf85a0b000<br />
arch_prctl(ARCH_SET_FS, 0x7faf85a0b740) = 0<br />
set_tid_address(0x7faf85a0ba10) = 1874<br />
set_robust_list(0x7faf85a0ba20, 24) = 0<br />
rseq(0x7faf85a0c0e0, 0x20, 0, 0x53053053) = 0<br />
mprotect(0x7faf85c23000, 16384, PROT_READ) = 0<br />
mprotect(0x561cf5067000, 4096, PROT_READ) = 0<br />
mprotect(0x7faf85c7e000, 8192, PROT_READ) = 0<br />
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0<br />
munmap(0x7faf85c36000, 53267) = 0<br />
getrandom("\x01\x62\x8d\xf4\xec\xea\xd8\x4e", 8, GRND_NONBLOCK) = 8<br />
brk(NULL) = 0x561cf6532000<br />
brk(0x561cf6553000) = 0x561cf6553000<br />
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3<br />
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=6070224, ...}, AT_EMPTY_PATH) = 0<br />
mmap(NULL, 6070224, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7faf85441000<br />
close(3) = 0<br />
newfstatat(1, "", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}, AT_EMPTY_PATH) = 0<br />
write(1, "hello\n", 6) = 6<br />
close(1) = 0<br />
close(2) = 0<br />
exit_group(0) = ?<br />
+++ exited with 0 +++<br />
</pre><br />
lists system calls made by ''echo'' as they are made.<br />
<br /><br />
<br /><br />
Instead of printing system calls as they are made, ''strace'' can print a short summary of which system calls were how many times and the time spent.<br />
<pre class="terminal"><br />
strace -c echo "hello"<br />
</pre><br />
prints<br />
<pre class="terminal"><br />
hello<br />
% time seconds usecs/call calls errors syscall<br />
------ ----------- ----------- --------- --------- ----------------<br />
0,00 0,000000 0 1 read<br />
0,00 0,000000 0 1 write<br />
0,00 0,000000 0 5 close<br />
0,00 0,000000 0 9 mmap<br />
0,00 0,000000 0 3 mprotect<br />
0,00 0,000000 0 1 munmap<br />
0,00 0,000000 0 3 brk<br />
0,00 0,000000 0 4 pread64<br />
0,00 0,000000 0 1 1 access<br />
0,00 0,000000 0 1 execve<br />
0,00 0,000000 0 2 1 arch_prctl<br />
0,00 0,000000 0 1 set_tid_address<br />
0,00 0,000000 0 3 openat<br />
0,00 0,000000 0 4 newfstatat<br />
0,00 0,000000 0 1 set_robust_list<br />
0,00 0,000000 0 1 prlimit64<br />
0,00 0,000000 0 1 getrandom<br />
0,00 0,000000 0 1 rseq<br />
------ ----------- ----------- --------- --------- ----------------<br />
100,00 0,000000 0 43 2 total<br />
</pre><br />
<br /><br />
<br /><br />
<br />
Similarly, '''ltrace''' will list the calls to library functions made by the command that was passed as the argument to ''ltrace''.<br />
<pre class="terminal"><br />
sudo apt install ltrace<br />
</pre><br />
<br /><br />
<br /><br />
<br />
== Signals ==<br />
Signals are software interrupts that the the kernel can send an executable. The executable may react to the signal or choose to ignore it. The two signals SIGKILL and SIGTERM, however, can not be ignored by executable and must be handled.<br />
<br /><br />
An overview of the signals can be found in the man pages entry about signals<br />
<pre class="terminal"><br />
man 7 signal<br />
</pre><br />
<br /><br />
Some command-line tools do useful stuff when certain signals are sent to them. For example, the ''dd'' tool prints the progress of the copying task when the SIGUSR1 signal is sent to it via the ''kill'' command.<br />
<pre class="terminal"><br />
dd if=${HOME}/image.iso of=/dev/sdb &<br />
kill -s USR1 $(pidof dd)<br />
</pre><br />
<br /><br />
<br />
== Interprocess Communication Mechanisms ==<br />
<br />
=== Shared Memory ===<br />
Linux offers creating System V shared memory segments, which can be used for interprocess communication.<br />
<pre class="code"><br />
#include <sys/types.h><br />
#include <sys/ipc.h><br />
#include <sys/shm.h><br />
<br />
// creating an IPC key<br />
key_t segmentKey = ftok(”path_to_some_existing_file", 'R')<br />
if (segmentKey == -1) {<br />
perror("could not create IPC key");<br />
exit(1);<br />
}<br />
// accessing the shared memory segment, creating it if it doesn't exist<br />
int sharedMemoryID = shmget(segmentKey, SHM_SIZE, 0644 | IPC_CREAT)<br />
if (sharedMemoryID == -1) {<br />
perror("could not access (or create) the shared memory segment");<br />
exit(1);<br />
}<br />
// attaching a pointer<br />
void* memoryPtr = shmat(sharedMemoryID, NULL, 0);<br />
if (*((char*)memoryPtr) == -1) {<br />
perror("could not attach a pointer to the shared memory segment");<br />
exit(1);<br />
}<br />
</pre><br />
To learn more about shared memory segments, type<br />
<pre class="terminal"><br />
man ftok<br />
man shmget<br />
man shmat<br />
</pre><br />
<br /><br />
<br />
=== Memory Mapped Files ===<br />
Linux offers mapping files to memory regions, which enables working on the file contents much more efficiently, as if it is a memory region. For example, pointers can be used in a C/C++ program to edit the contents. The memory mapped region can be shared between processes. This allows the processes to operate on large files, for example in a writer-subscriber architecture, while preserving memory. Unlike the shared memory method described above, the contents of the shared memory region are written to a file and thus persist between sessions and even system reboots.<br />
<pre class="code"><br />
#include <stdlib.h> <br />
#include <stdio.h> <br />
#include <unistd.h><br />
#include <errno.h> <br />
#include <string.h> <br />
#include <fcntl.h> <br />
#include <sys/types.h> <br />
#include <sys/stat.h> <br />
#include <sys/mman.h> <br />
<br />
static const int MAX_INPUT_LENGTH = 50;<br />
<br />
int main(int argc, char** argv)<br />
{<br />
int fd = open(argv[1], O_RDWR | O_CREAT); <br />
char* shared_mem = mmap(NULL, MAX_INPUT_LENGTH, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); <br />
close(fd); <br />
<br />
if (!strcmp(argv[2], "read")) { <br />
// continously listens to text messages from the 'write' process and writes to the terminal<br />
while (1) { <br />
shared_mem[MAX_INPUT_LENGTH-1] = '\0'; <br />
printf("%s", shared_mem); <br />
sleep(1); <br />
} <br />
} <br />
else if (!strcmp(argv[2], "write")) {<br />
// continuously sends the input from the terminal to the 'read' process<br />
while (1) {<br />
fgets(shared_mem, MAX_INPUT_LENGTH, stdin);<br />
}<br />
}<br />
else {<br />
printf("Unsupported command\n"); <br />
}<br />
}<br />
</pre><br />
<br />
To learn more about memory mapped files, refer to the man page<br />
<pre class="terminal"><br />
man mmap<br />
</pre><br />
<br /><br />
<br />
=== Pipes ===<br />
Pipes are another IPC mechanism where one process can send messages to another.<br />
<pre class="code"><br />
#include <stdio.h><br />
#include <stdlib.h> <br />
#include <errno.h> <br />
#include <sys/types.h> <br />
#include <unistd.h> <br />
<br />
int main(void)<br />
{ <br />
int pipeDescriptor[2]; <br />
<br />
pipe(pipeDescriptor); // writing to pipeDescriptor[0], reading from pipeDescriptor[1]<br />
<br />
if (!fork())<br />
{ <br />
printf(" CHILD: writing to pipe and exiting\n"); <br />
write(pipeDescriptor[1], "test", 5); <br />
}<br />
else<br />
{ <br />
char buffer[5]; <br />
printf("PARENT: reading from pipe\n"); <br />
read(pipeDescriptor[0], buffer, 5); <br />
printf("PARENT: read \"%s\"\n", buf); <br />
wait(NULL); <br />
} <br />
return 0; <br />
}<br />
</pre><br />
<br /><br />
To learn more about pipes, refer to the man page<br />
<pre class="terminal"><br />
man pipe<br />
</pre><br />
<br /><br />
<br />
== dmesg ==<br />
<br /><br />
<br />
== D-Bus ==<br />
<br /><br />
<br />
== GUI-less Mode ==<br />
<br />
=== Switching to GUI-less (Multi-User) Mode with Systemd ===<br />
On a Linux system that uses systemd, we can control whether the graphical user interface is loaded and shown by specifying a suitable systemd target. To turn off the graphical desktop immediately, enter<br />
<pre class="terminal"><br />
sudo systemctl isolate multi-user.target<br />
</pre><br />
To prevent the GUI from being loaded during the system startup, type<br />
<pre class="terminal"><br />
sudo systemctl set-default multi-user.target<br />
</pre><br />
To return to the graphical desktop, type<br />
<br/><br />
<pre class="terminal"><br />
sudo systemctl isolate graphical.target<br />
</pre><br />
and to make the graphical desktop the default again, type<br />
<pre class="terminal"><br />
sudo systemctl set-default graphical.target<br />
</pre><br />
<br /><br />
<br />
=== Setting the Screen Resolution for GUI-less Mode ===<br />
* Restart the machine to the Grub boot menu.<br />
* Press 'c' to get into the Grub command console.<br />
* Run the command 'vbeinfo' to list possible resolutions.<br />
* Note down the desired resolution. For example, ''1024x768x32'', where ''32'' is the color mode.<br />
* Type ''exit'' to return to the Grub boot menu and boot into Ubuntu.<br />
* Open '''/etc/default/grub''' in an editor to add the line<br />
<pre class="code"><br />
GRUB_GFXPAYLOAD_LINUX=1024x768x32<br />
</pre><br />
* Optionally, add the line<br />
<pre class="code"><br />
GRUB_GFXMODE=1024x768<br />
</pre><br />
to set the screen resolution for the GRUB boot menu itself.<br />
* Finally, run the Grub updater<br />
<pre class="terminal"><br />
sudo update-grub<br />
</pre><br />
<br /><br />
<br /><br />
<br />
<br />
== C++ Notes ==<br />
=== Platform detection ===<br />
To detect whether code is compiled for the Linux platform you can check if ''__linux__'' is defined.<br />
<pre class="code"><br />
#ifdef __linux__<br />
</pre><br />
(here you can find [https://sourceforge.net/p/predef/wiki/OperatingSystems preprocessor definitions for many operating systems])<br />
<br /></div>Kai