Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .ci/build-kit/docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@
# && cd ${EVEREST_CMAKE_PATH} \
# && git checkout ${EVEREST_CMAKE_VERSION} \
# && rm -r .git

# FIXME(kai): Install libsystemd-dev as a dependency of sdbus-c++
RUN apt-get update && apt-get -y install libsystemd-dev

Check warning on line 15 in .ci/build-kit/docker/Dockerfile

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

.ci/build-kit/docker/Dockerfile#L15

Avoid additional packages by specifying `--no-install-recommends`

Check warning on line 15 in .ci/build-kit/docker/Dockerfile

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

.ci/build-kit/docker/Dockerfile#L15

Delete the apt-get lists after installing something

Check warning on line 15 in .ci/build-kit/docker/Dockerfile

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

.ci/build-kit/docker/Dockerfile#L15

Pin versions in apt get install. Instead of `apt-get install <package>` use `apt-get install <package>=<version>`
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ if(NOT DISABLE_EDM)

# FIXME (aw): we need to set this by hand due to edm
set(EVEREST_SCHEMA_DIR ${everest-framework_SOURCE_DIR}/schemas)

if(NOT TARGET SDBusCpp::sdbus-c++)
add_library(SDBusCpp::sdbus-c++ ALIAS sdbus-c++)
endif()
else()
find_package(everest-framework REQUIRED)
find_package(everest-ocpp REQUIRED)
Expand All @@ -115,6 +119,8 @@ else()
find_package(nlohmann_json REQUIRED)

find_package(ftxui 5 QUIET) # optional, if not available BringUp module will not be built

find_package(sdbus-c++ REQUIRED)
endif()


Expand Down
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,18 @@ minimum requirements:
* PLC GreenPhy
* RFID

### Ubuntu 22.04
### Ubuntu 24.04

> [!WARNING]
> Ubuntu 20.04 is not supported anymore. Please use Ubuntu 22.04 or newer.
> Ubuntu 20.04 and Ubuntu 22.04 are not supported anymore. Please use Ubuntu 24.04 or newer.

```bash
sudo apt update
sudo apt install -y python3-pip python3-venv git rsync wget cmake doxygen \
graphviz build-essential clang-tidy cppcheck openjdk-17-jdk npm docker \
graphviz build-essential clang-tidy cppcheck openjdk-17-jdk npm docker.io \
docker-compose libboost-all-dev nodejs libssl-dev libsqlite3-dev \
clang-format curl rfkill libpcap-dev libevent-dev pkg-config libcap-dev
clang-format curl rfkill libpcap-dev libevent-dev pkg-config libcap-dev \
libsystemd-dev
```

### OpenSuse
Expand All @@ -59,18 +60,18 @@ zypper install -y git rsync wget cmake doxygen graphviz clang-tools cppcheck \
libboost_program_options-devel libboost_system-devel libboost_thread-devel \
java-17-openjdk java-17-openjdk-devel nodejs nodejs-devel npm python3-pip \
gcc-c++ libopenssl-devel sqlite3-devel libpcap-devel libevent-devel \
libcap-devel
libcap-devel systemd-devel
```

### Fedora 40, 41 & 42
### Fedora 41 & 42

```bash
sudo dnf update
sudo dnf install make automake gcc gcc-c++ kernel-devel python3-pip \
python3-devel git rsync wget cmake doxygen graphviz clang-tools-extra \
cppcheck java-21-openjdk java-21-openjdk-devel boost-devel nodejs \
nodejs-devel npm openssl openssl-devel libsqlite3x-devel curl rfkill \
libpcap-devel libevent-devel libcap-devel
libpcap-devel libevent-devel libcap-devel systemd-devel
```

## Build & Install
Expand Down
5 changes: 5 additions & 0 deletions dependencies.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ mqttc:
git: https://github.com/LiamBindle/MQTT-C.git
git_tag: v1.1.6
options: ["MQTT_C_EXAMPLES OFF", "CMAKE_POSITION_INDEPENDENT_CODE ON"]
# Linux_Systemd_Rauc module
sdbus-cpp:
git: https://github.com/Kistler-Group/sdbus-cpp.git
git_tag: v2.1.0
cmake_condition: "EVEREST_DEPENDENCY_ENABLED_SDBUS_CPP"
# unit testing
gtest:
# GoogleTest now follows the Abseil Live at Head philosophy. We recommend updating to the latest commit in the main branch as often as possible.
Expand Down
1 change: 1 addition & 0 deletions lib/everest/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ add_subdirectory(everest_api_types)
add_subdirectory(external_energy_limits)
add_subdirectory(helpers)
add_subdirectory(run_application)
add_subdirectory(system)
add_subdirectory(tls)
add_subdirectory(util)
add_subdirectory(io)
Expand Down
39 changes: 39 additions & 0 deletions lib/everest/system/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
if(NOT DEFINED sdbus-c++_VERSION_MAJOR AND NOT DISABLE_EDM)
string(REPLACE "." ";" SDBUS_CPP_VERSION_SPLIT ${CPM_PACKAGE_sdbus-cpp_VERSION})
list(GET SDBUS_CPP_VERSION_SPLIT 0 sdbus-c++_VERSION_MAJOR)
endif()
message("Found sdbus-c++ major version: " ${sdbus-c++_VERSION_MAJOR})

add_library(everest_system STATIC)
add_library(everest::system ALIAS everest_system)
ev_register_library_target(everest_system)

target_sources(everest_system
PRIVATE
src/dbus_base.cpp
src/rauc_dbus_base.cpp
src/safe_system.cpp
)

target_include_directories(everest_system
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)

target_link_libraries(everest_system
PRIVATE
everest::log
PUBLIC
SDBusCpp::sdbus-c++
)

target_compile_definitions(everest_system
PRIVATE
SDBUSCPP_MAJOR_VERSION=${sdbus-c++_VERSION_MAJOR}
)

if (BUILD_TESTING)
target_compile_definitions(everest_system PUBLIC EVEREST_COVERAGE_ENABLED)
add_subdirectory(tests)
endif()
37 changes: 37 additions & 0 deletions lib/everest/system/include/everest/system/dbus_base.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest

/**
* \file sdbus-c++ version independent interfaces
*
* The sdbus-c++ library is used to provide a C++ interface to DBus.
* The functions defined here enable code to compile and run against
* version 1.4 or higher of sdbus-c++.
*/

#pragma once

#include <sdbus-c++/sdbus-c++.h>

namespace everest::lib::system::dbus {

using async_method_callback = std::function<void(sdbus::MethodReply reply, std::optional<sdbus::Error> error)>;
using async_property_callback = std::function<void(std::optional<sdbus::Error> error, sdbus::Variant value)>;

// library version independent functions
[[nodiscard]] std::unique_ptr<sdbus::IProxy> createProxy(const char* destination, const char* objectPath);
[[nodiscard]] std::unique_ptr<sdbus::IProxy> createProxy(const char* destination, const char* objectPath,
sdbus::dont_run_event_loop_thread_t);
[[nodiscard]] sdbus::MethodCall createMethodCall(const std::unique_ptr<sdbus::IProxy>& proxy, const char* interfaceName,
const char* methodName);
sdbus::PendingAsyncCall callMethodAsync(const std::unique_ptr<sdbus::IProxy>& proxy, sdbus::MethodCall& method,
async_method_callback handler, uint64_t timeout_us);
sdbus::PendingAsyncCall getPropertyAsync(const std::unique_ptr<sdbus::IProxy>& proxy, async_property_callback handler,
const char* property, const char* interface);
void registerSignalHandler(std::unique_ptr<sdbus::IProxy>& proxy, const char* interfaceName, const char* signalName,
sdbus::signal_handler signalHandler);

void initialise_handlers(const std::unique_ptr<sdbus::IProxy>& proxy, std::function<void(void)> init);
void process_pending(sdbus::IConnection& connection);

} // namespace everest::lib::system::dbus
223 changes: 223 additions & 0 deletions lib/everest/system/include/everest/system/rauc_dbus_base.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest

#pragma once

#include <sdbus-c++/sdbus-c++.h>

#include <everest/system/dbus_base.hpp>

#include <cstdint>
#include <string>
#include <string_view>

namespace everest::lib::system::rauc_dbus {

namespace defaults {
constexpr const char* service_domain = "de.pengutronix.rauc";
constexpr const char* object_path = "/";
} // namespace defaults

namespace interface {
constexpr const char* Installer = "de.pengutronix.rauc.Installer";
constexpr const char* DBus_Properties = "org.freedesktop.DBus.Properties";
} // namespace interface

namespace property {
constexpr const char* Progress = "Progress";
constexpr const char* Operation = "Operation";
constexpr const char* LastError = "LastError";
constexpr const char* BootSlot = "BootSlot";
} // namespace property

namespace signal {
constexpr const char* PropertiesChanged = "PropertiesChanged";
constexpr const char* Completed = "Completed";
} // namespace signal

namespace method {
constexpr const char* InstallBundle = "InstallBundle";
constexpr const char* InspectBundle = "InspectBundle";
constexpr const char* Mark = "Mark";
constexpr const char* GetSlotStatus = "GetSlotStatus";
constexpr const char* GetPrimary = "GetPrimary";
} // namespace method

namespace rauc_messages {
struct Progress {
int percent;
std::string description;
int level;
};

struct CmdResult {
bool success;
std::string error_msg;
};

enum class Operation {
Unknown,
Idle,
Installing
};

struct UpdateTransaction {
std::int32_t request_id;
std::string boot_slot;
std::string primary_slot;
};

enum class HealthCheckStatus {
ScriptExitedWithError,
ScriptNotExecutable,
ScriptNotSet,
ScriptTerminatedBySignal,
SetupFailed,
Success,
UnknownError
};

Operation string_to_operation(const std::string_view& s);
// Stream operators are needed for type conversion in sdbus
sdbus::Message& operator<<(sdbus::Message& msg, const Progress& items);
sdbus::Message& operator>>(sdbus::Message& msg, Progress& items);

} // namespace rauc_messages

// ----------------------------------------------------------------------------
// Base class

class RaucBase {
public:
using property_cb = dbus::async_property_callback;
using method_cb = dbus::async_method_callback;
using slot_info_t = std::map<std::string, std::map<std::string, std::string>>;

struct CurrentState {
rauc_messages::HealthCheckStatus system_health_rc;
std::string boot_slot;
std::string primary_slot;
};

RaucBase();
RaucBase(sdbus::dont_run_event_loop_thread_t);

void configure(const std::string& verify_update_script_path = "");
bool check_previous_transaction(const CurrentState& current, const rauc_messages::UpdateTransaction& saved);

// methods
sdbus::PendingAsyncCall install_bundle(method_cb handler, const std::string& filename, uint64_t timeout_us);
sdbus::PendingAsyncCall mark(method_cb handler, const std::string& mark, const std::string& slot,
uint64_t timeout_us);

// properties
sdbus::PendingAsyncCall get_boot_slot(property_cb handler) const;

protected:
std::unique_ptr<sdbus::IProxy> proxy;

using slots_t = std::vector<sdbus::Struct<std::string, std::map<std::string, sdbus::Variant>>>;
static slot_info_t convert(slots_t& slots);

rauc_messages::HealthCheckStatus check_system_health();

// methods
sdbus::PendingAsyncCall get_primary_slot(method_cb handler, uint64_t timeout_us);
sdbus::PendingAsyncCall get_slot_status(method_cb handler, uint64_t timeout_us);

// properties
sdbus::PendingAsyncCall get_last_error(property_cb handler) const;
sdbus::PendingAsyncCall get_operation(property_cb handler) const;
sdbus::PendingAsyncCall get_progress(property_cb handler) const;

virtual bool decide_if_good(const rauc_messages::UpdateTransaction& saved, const CurrentState& current);
virtual void configure_handlers() = 0;

private:
std::string verify_update_script_path;
};

// ----------------------------------------------------------------------------
// Synchronous base class

class RaucBaseSync : public RaucBase {
public:
using RaucBase::RaucBase;

rauc_messages::UpdateTransaction create_transaction(std::int32_t request_id, uint64_t timeout_us);
bool check_previous_transaction(const rauc_messages::UpdateTransaction& saved, uint64_t timeout_us);

// methods
rauc_messages::CmdResult install_bundle(const std::string& filename, uint64_t timeout_us);
void mark(const std::string& mark, const std::string& slot, uint64_t timeout_us);

// properties
std::string get_boot_slot() const;

protected:
// methods
std::string get_primary_slot(uint64_t timeout_us);
slot_info_t get_slot_status(uint64_t timeout_us);

// properties
std::string get_last_error() const;
rauc_messages::Operation get_operation() const;
rauc_messages::Progress get_progress() const;
};

// ----------------------------------------------------------------------------
// Asynchronous base class

class RaucBaseAsync : public RaucBase {
public:
using RaucBase::RaucBase;

// methods
bool install_bundle(const std::string& filename, uint64_t timeout_us);
bool mark(const std::string& mark, const std::string& slot, uint64_t timeout_us);

// properties
bool get_boot_slot();

protected:
sdbus::PendingAsyncCall active_request;

// methods
bool get_primary_slot(uint64_t timeout_us);
bool get_slot_status(uint64_t timeout_us);

// properties
bool get_last_error();
bool get_operation();
bool get_progress();

// callbacks
enum class error_t : std::uint8_t {
install_bundle,
mark,
boot_slot,
primary_slot,
slot_status,
last_error,
operation,
progress
};

virtual void cb_install_bundle() = 0;
virtual void cb_mark() = 0;
virtual void cb_boot_slot(const std::string_view& value) = 0;
virtual void cb_primary_slot(const std::string_view& value) = 0;
virtual void cb_slot_status(const slot_info_t& value) = 0;
virtual void cb_last_error(const std::string_view& value) = 0;
virtual void cb_operation(rauc_messages::Operation value) = 0;
virtual void cb_progress(const rauc_messages::Progress& value) = 0;
virtual void cb_error(error_t fn, const std::string_view& error) = 0;
};

} // namespace everest::lib::system::rauc_dbus

namespace sdbus {
template <>
struct signature_of<everest::lib::system::rauc_dbus::rauc_messages::Progress>
: signature_of<Struct<int, std::string, int>> {};
} // namespace sdbus
Loading