Embedded Linux Project (Sibyl)
Building
make
Installing
Kernel module
cd kernel
sudo insmod kmod.ko
Userspace
make install
# Start systemd services (kernel module must be loaded before services can be started)
sudo systemctl enable sibyl-*.service
sudo systemctl start sibyl-*.service
Communication
Userspace
The client programs that aggregate the desired system data are sending them to the daemon process.
This is done via a simple packet, measurement_t
which is defined in common/include/measurement.h
.
It holds the data of a measurement, which can be an integer, unsigned integer, float or double, the type of the data and an id that identifies the sender.
The id is an uint8_t
and should be unique for each client that sends data, so the maximum amount of clients is 256.
The packet is sent via a message queue, which is created by the daemon process.
Clients will wait until the message queue is created and then send their data to the daemon.
Key and project id for the message queue are defined in common/include/userspace_comm.h
.
The daemon caches the data and waits until one of three conditions are met to send the data to the kernel module (which then sends them over the GPIO pins):
- A measurement with an previously unknown measurement id is received
- A measurement with different data type for a known measurement id is received
- A measurement with different data for a known measurement id is received
If one of these conditions is met, the data is sent to the kernel module via the data_t
struct that is defined in common/include/measurement.h
.
It contains a field for the pre-defined sender id, the count of measurements and a pointer to an array that holds the measurements.
The sent data contains the latest received measurements for each measurement id.
Kernel module
To receive data from the userspace, the kernel creates a character device under /dev/sibyl
where the userspace daemon writes the data to.
The data that is written to the character device is a pointer to a data_t
struct, on write the kernel copies the data the pointer points to into kernel space.
When data_t
is copied, it checkes if the pointer to the measurements array is not NULL
and the count of measurements in data_t
is not zero.
If both applies, it also copies the data from the array pointer to the kernel space.
GPIO interface
Physical Layer
The protocol implements unidirectional serial communication over GPIO with the following characteristics:
- Transmission rate: 9600 baud (104.17 microseconds per bit)
- Signal levels:
- Logical 0: GPIO Low
- Logical 1: GPIO High
- Pin configuration: GPIO 575 as output
Bit Transmission
Bit transmission follows the UART-8N1 compatible format:
- Start bit: Logical 0 (Low)
- 8 data bits in LSB-first order
- Stop bit: Logical 1 (High)
- No parity checking
- No flow control
Packet Structure
A complete data packet_t
consists of a header, variable measurement payload, and a CRC32 checksum field:
Header (3 Bytes)
- Magic Number (1 byte)
- Fixed value: 0xAA
- Used for packet detection and synchronization
- Sender ID (1 byte)
- Identifies the sender
- Measurement Count (1 byte)
- Number of subsequent measurements
- Maximum value: 16 (MAX_MEASUREMENTS)
Measurement Payload (10 bytes per measurement)
For each measurement_t
, the following fields are transmitted:
-
Measurement Data (8 bytes)
- 64-bit measurement value
- The data is packed as a c-style union
-
Measurement Type (1 byte)
- Data type of the measurement
- The following data types are available for a measurement: INT8, UINT8, INT16, UINT16, INT32, UINT32, INT64, UINT64, FLOAT32, FLOAT64
-
Measurement ID (1 byte)
- Unique identifier for the measurement
Trailer (4 bytes)
- CRC32 checksum
- Calculated over all preceding packet fields
- Uses the Linux standard CRC32 algorithm