Add extracted tools: CitrineOS, OpenOCPP, ShapeShifter

- CitrineOS core extracted (CSMS OCPP 2.0.1)
- OpenOCPP extracted (firmware OCPP 1.6J/2.0.1)
- ShapeShifter library installed (pip install -e)
- ShapeShifter specification extracted
- EVerest extracted

TODO updated with progress
This commit is contained in:
Eric F
2026-06-08 00:38:27 -04:00
parent 468cfeaa50
commit d398a6ced2
7326 changed files with 1177561 additions and 7 deletions

View File

@@ -0,0 +1,19 @@
.. _exp_linux_yocto:
#########################
Linux / Yocto
#########################
You will find different explanations about using EVerest with
Linux and Yocto in the following sections:
.. toctree::
:maxdepth: 1
setting-up-linux-os
building-yocto
ota-updates
partitioning-schemes-for-rauc-ota
Make sure to check out the :doc:`How-to-guide on cross-compilation </how-to-guides/yocto-cross-compilation>`
for a step-by-step guide on how to cross-compile EVerest for a Yocto-based Linux system.

View File

@@ -0,0 +1,248 @@
.. _exp_linux_yocto_ota_updates:
##########################
Over-the-air-updates (OTA)
##########################
One of the most important (and often underestimated) features of a
charging station is the ability to remotely update the software when the
charger is installed. Updates can provide:
- General bug fixes
- Fixing compatibility issues with new EVs (or old EVs with new
firmware versions)
- Fixing compatibility issues with OCPP backends (or new versions
deployed on the backend side)
- Security issues
- New features
Updates may be delivered remotely over a network, called Over-the-Air (OTA),
or may be provided locally where supported by the charging station.
EVerest supports *RAUC* as an update tool, which has the following advantages:
- Open source project with a large community:
https://rauc.io
- Secure by design: The update files are cryptographically signed (and
optionally encrypted). Signature is checked during installation, so
the source of the update file can be trusted. This simplifies the
update delivery process a lot compared to other tools that only rely
on transport mechanism security. Updates can be downloaded from a
simple unencrypted HTTP server or even a local USB flash drive
without compromising security.
- Robust: Uses A/B partitioning and does full image updating
- Atomic switching between A/B slots can be implemented
- Support partial downloads by HTTP streaming: Block based partial
downloads reduce the bandwidth needed
There are some considerations to make when choosing an update system:
+-----------------------------------+-----------------------------------+
| Full image updates | Partial component / individual |
| | file updating |
+===================================+===================================+
| Very robust. The complete image | Risk of producing an installed |
| always has the correct | combination where one component |
| dependencies built in. | is too old to work with the other |
| | recently updated component. |
| | Requires careful tracking of |
| | compatibility between components. |
+-----------------------------------+-----------------------------------+
| Writing full images to A/B slots | Often quite complex |
| is straightforward. Combined with | implementations. That can |
| an atomic switch between the | introduce a lot of room for bugs |
| boot slots, there is no critical | which brick devices during failed |
| time where e.g. a power loss | updates, power losses during |
| could brick a device. | updates or upgrading to |
| | incompatible updater software |
| | versions. |
+-----------------------------------+-----------------------------------+
| Simple versioning: a single | Complex versioning: Always a |
| version number is enough to | combination of the different |
| specify which software image | components / files. |
| version is installed. | |
+-----------------------------------+-----------------------------------+
| Recovers from file system errors | Relies entirely on the filesystem |
| in the root partition: It writes | implementation to repair itself |
| a new clean FS on every update | and may brick if that fails. |
+-----------------------------------+-----------------------------------+
| Updates everything: rootfs, | Often limited to e.g. application |
| kernel, bootloader, … | update. It may e.g. not update |
| | kernel or base system. |
+-----------------------------------+-----------------------------------+
| Downside: Full image updates | Advantage: only download changed |
| require more download | files and thus have the smallest |
| bandwidth/data. Can be mitigated | possible download. |
| to some extent by block based | |
| partial download. | |
+-----------------------------------+-----------------------------------+
An update process should consider the bootloader, loading the Linux kernel, and
the root file system. A root file system can be a standard Linux partition (ext4).
Other solutions are available including: squashfs, file system snapshots, and
bundle based solutions (NixOS, Snap). The root file system is usually read-only
and an overlay file system is used to support charger specific updates.
An OTA solution needs to consider how configuration information is maintained
across root file system updates.
EVerest has chosen RAUC as the most suitable update system, mainly due to its
robust, brick-free mechanisms and its inherent security features.
RAUC can support adaptive updates that use HTTP streaming to only download
blocks that have changed between releases. This can reduce the overheads of using
full images.
Security is provided on a block-based level, so there is no need to
first download the complete image and validate signature etc. It is done
on the fly.
This also means that no extra disk space is needed to store the update
image: It will be directly streamed from the source into the inactive
slot partition.
RAUC implementation in EVerest
------------------------------
EVerest interacts with RAUC via its D-Bus interface. This is provided by the
`Linux Systemd Rauc module </reference/modules/Linux_Systemd_Rauc>`_.
In EVerest the update process is fully integrated with OCPP.
In the OCPP use case, the CPO will need to provide storage for the
update file that is accessible via HTTP with range requests. The CSMS
then sends this URL in the update request to EVerest, and EVerest will
trigger RAUC on the D-Bus to actually perform the update.
You will need to implement the following in your Yocto system as this is
very system dependent:
- A partitioning setup that provides A/B slots for rootfs, A/B boot and
data partitions (more details about this is covered in the appendix!)
- RAUC configuration file for your setup (system.conf)
- RAUC backend that performs switching slots/marking good/bad. RAUC
already comes with backend support for many bootloaders such as
U-Boot and Barebox etc.
- PKI to be used for signing / optionally encrypting the update files
- A recipe that builds RAUC bundles (update files) directly in Yocto
If you use PHYTEC SoMs: Their *ampliPHY* distribution already has working
examples for all of the above in *ampliphy-rauc* or *ampliphy-secure*
distributions.
Refer to RAUC's integration documentation for more information:
https://rauc.readthedocs.io/en/latest/integration.html
RAUC has support for atomic switching between slots and uses features from
the bootloader. It is important to understand this interaction since the
bootloader may be able to automatically rollback if an update is not successful.
Some processors also support secure and encrypted boot options which can ensure
that only valid images are loaded. They may also provide mechanisms to support
dual boot loaders.
.. tip::
Look at the documentation for your processor and chosen bootloader to
understand what options are provided for slot switching and automatic boot
failure recovery.
Test your integration locally first using RAUC on the command line:
.. tip::
rauc install http://myudateserver.com/version1.raucb
RAUC should perform a successful installation on the currently unused
slot. Once that is done, issue a reboot and verify it cleanly boots into
the new slot.
Once booted successfully into the new slot, you need to mark the slot as
“good”, otherwise it may fall back to the previous one on the next
boot.
Some implementations do this in a *systemd* service that runs at the end
of the boot process. This is not recommended in production. EVerest
will take care of marking the slot as "good" when EVerest starts up
successfully. It will then also report the status to the OCPP backend
automatically etc.
To mark it "good", manually use:
.. code-block:: bash
rauc status mark-good
You also may want to check RAUC's status before and after the update to
verify it is configured correctly. It shows an output like this:
.. code-block:: bash
root@mysystem:~# rauc status
=== System Info ===
Compatible: mysystem-v1
Variant:
Booted from: rootfs.0 (system0)
=== Bootloader ===
Activated: rootfs.0 (system0)
=== Slot States ===
[bootloader.0] (/dev/mmcblk1, boot-emmc, inactive)
o [rootfs.1] (/dev/mmcblk1p6, ext4, inactive)
bootname: system1
boot status: good
[boot.1] (/dev/mmcblk1p2, vfat, inactive)
x [rootfs.0] (/dev/mmcblk1p5, ext4, booted)
bootname: system0
mounted: /
boot status: good
[boot.0] (/dev/mmcblk1p1, vfat, active)
Also try to use *mark-bad* and test if it falls back to the previous one
on the next boot.
EVerest interacts with RAUC via D-Bus, so make sure it is running as a
D-Bus service. The D-Bus interface is also the boundary between
EVerest and the underlying Linux system here.
Once you verified that RAUC performs updating and fall-backs in manually
controlled command line mode, you should be all set up for EVerest
updates.
Custom Update Mechanism
------------------------
In case you do not want to use RAUC and/or integrate your custom update
mechanism into EVerest, you can also implement the
`EVerest System API <../../reference/api/system_API/index.html>`_.
This would still allow you to update EVerest via OCPP, but you would need to handle
the actual update process yourself and provide status updates to EVerest via the
System API.
Optimize the base system
------------------------
If you have a lot of processes running in the Linux system and a very
high CPU load (which easily happens on small embedded systems), take
some time to select the correct nice levels for all services running on
the system. You can set the nice level in the systemd unit files.
.. tip::
Being "nicer" means getting CPU less often if lots of processes are scheduled.
Especially for high-level communication (aka ISO 15118), run EVerest at
e.g. a nice level of -20 to ensure it is getting enough CPU slices
during the charging process. If you have other tasks outside of
EVerest, make sure they have a higher nice level.
Using a preemptive kernel is also a good idea to ensure low latencies in
user space. Check *CONF_PREEMT* documentation in the Linux kernel.
--------------------------------
**Authors**: Cornelius Claussen, Manuel Ziegler, Piet Gömpel

View File

@@ -0,0 +1,61 @@
.. _partitioning-schemes-for-rauc-ota:
#################################
Partitioning schemes for RAUC OTA
#################################
As there are many ways to set up partitions on the storage device for
RAUC-based updates, this chapter will only provide a few ideas. Your
actual implementation may be different in the end.
As a target, we would like to have:
- two full-size A/B rootfs partitions
- two full-size A/B boot partitions for bootloader and FIT image
(containing kernel/initrd/device tree for secure boot)
- one/two user data partition(s)
- one small factory data partition that contains (read only) files that
are programmed once during production and will never change
(e.g. serial numbers, certification region config etc)
The user data partition can be mounted as overlayfs on specific folders
to store run time-generated data (e.g. log files, user configuration
files, certificates, ...).
A factory reset should be implemented that clears the overlayfs.
The most simple version of this is to use a single user data partition
and mount it as overlay (e.g. on */var*) both for slot A and B. Then all
changes in the overlay will survive an update of the underlying rootfs.
For an example on how to do this, refer to the BelayBox Yocto sources.
The Raspberry Pi uses three boot partitions, for most other boards only
two are needed.
.. code-block:: shell
part --source bootimg-partition --ondisk mmcblk0 --fstype=vfat --label boot --active --align 4096 --fixed-size 512
part --source bootimg-partition --ondisk mmcblk0 --fstype=ext4 --label boot_a --align 4096 --fixed-size 512
part --source bootimg-partition --ondisk mmcblk0 --fstype=ext4 --label boot_b --align 4096 --fixed-size 512
part --source rootfs --ondisk mmcblk0 --fstype=ext4 --label root_A --align 4096 --fixed-size 3000
part --source rootfs --ondisk mmcblk0 --fstype=ext4 --label root_B --align 4096 --fixed-size 3000
part --ondisk mmcblk0 --fstype=ext4 --label factory_data --align 4096 --fixed-size 128
part --ondisk mmcblk0 --fstype=ext4 --label overlay --align 4096 --fixed-size 7000
The disadvantage of this is the following: If the configuration file
format changes due to an update of the underlying rootfs, a separate job
may need to be run on the first boot into the new slot to transfer the
configuration files to the new format. If the boot into the new slot
fails, it will fall back to the old slot. The older version then is
maybe not compatible with the new config file format, so a full fallback
is not possible in this case.
To allow for better config file migration with fallback, consider to use
two user data partitions and a separate migration task (e.g. in initrd)
that transfers the files from the old user data partition to the new
one. It may adapt the file format in the process. In this case, falling
back to the old rootfs will work as it will also use the older overlay
user partition.
If you have an eMMC device, consider using the hardware boot partition
feature that eMMC offers for the bootloader. This will enable atomic
switching between the active boot slots.

View File

@@ -0,0 +1,105 @@
.. _exp_linux_yocto_setup_linux_os:
#####################################
Setting up the Linux operating system
#####################################
In principle, you can use any Linux-based operating system as long as it
comes with the required dependencies to run EVerest.
We strongly recommend using Yocto as it has some advantages over other
distributions:
- It can be set up to do reproducible builds with versioning.
- Most CPUs and SoMs already come with Yocto board support packages
(BSP).
- EVerest comes with full support for selected Yocto long term support
releases (LTS) (scarthgap as of the time of writing).
- It can be nicely integrated with your CI/CD to build complete
production images and update packages.
- It provides a software bill of materials of all packages in the Linux
system for managing licenses.
- Broad community
- Automatic generation of cross-compile toolchains, that can be used
during the development phase.
You can find more information about the Yocto project here:
https://www.yoctoproject.org
.. warning::
Setting up the Linux base system for your product is a quite complex task
that should be performed by domain experts. In case you do not have experts
in your team, consider getting help from a company specialized on this.
The end product's reliability, security and user experience strongly depends
on a sound architecture, implementation and maintenance strategy of the base
Linux system. This should not be underestimated.
Covering all aspects of setting up a Linux base system is out of the
scope of this documentation, but we would like to give some examples and ideas
and point out some typical solutions to questions you will have on your
journey. Do not consider this complete!
Setup a Yocto build environment
-------------------------------
Yocto has comprehensive caching capabilities that mean build times are substantially
reduced for successive builds. However an initial build will take hours since initial
versions need to be fetched and built so that caches are populated. There is support
for sharing downloads and caches that can reduce build times and are worth
considering where you have a co-located team.
A good build machine will have lots of RAM, SSD storage and multi-core processor as
well as a fast Internet connection.
It is possible to use a high-performance laptop especially for incremental builds
once the initial build is complete.
.. warning::
Running this inside of a virtual machine is not recommended.
A full Yocto build easily requires 50-100 GB of disk space, and it will
use multiple cores. So, make sure you have enough RAM per core (e.g. 2-3
GB per (hyperthread) core).
Install a Linux distribution supported by Yocto and install all
necessary dependencies. See here for more information about that:
https://docs.yoctoproject.org/ref-manual/system-requirements.html
Alternatively, consider building in a container. Once you move to
production, a build container will probably be needed anyway to build
images in your CI/CD.
It is also recommended to archive the containers to be able to do fully
reproducible builds of older versions in the future.
Yocto itself can produce builds that are completely tagged (i.e. each
source package is tagged with a fixed version or Git hash), so they are
in principle reproducible.
There are - however - a few build dependencies to the host system that
may prevent you from building your released 1.0 version in ten years
from now. As an example, the Python version in ten years from now may
not run the old bitbake correctly anymore. Also, the Yocto recipes
contain only download URLs and version tags, but not the source packages
itself.
Let's start with an example and set up the Yocto build environment that
we use for EVerest on the BelayBox hardware.
Building the BelayBox Yocto image
---------------------------------
An example can be found here for the BelayBox:
https://github.com/PionixPublic/dev-hardware-yocto
Check out the *README* in this repository on how to build and install
this Yocto on the BelayBox.
--------------------------------
**Authors**: Cornelius Claussen, Manuel Ziegler