Skip to content

Commit

Permalink
feat: create SOME/IP provider service
Browse files Browse the repository at this point in the history
- Create a service based on https://github.com/COVESA/test-someip-service
and respective config files;
- Also, add a .md with simple instructions on how to generate CommonAPI
files and run the service inside the emulator;
  • Loading branch information
MaironLucas committed Jan 28, 2025
1 parent e28b360 commit 4777f73
Show file tree
Hide file tree
Showing 20 changed files with 1,176 additions and 6 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,18 @@ This repository contains the code to build an emulator image containing some ser
* `target`: contains files related to the emulator that will be created. Instead of creating a new device, we just modified the `sdk_car_x86_64.mk` and `car_generic_system.mk` to include our add-on.


We supply a shell script `add_to_aosp.sh` to automatically copy all code to the correct place in the AOSP source tree. Pass to the script the path to where the AOSP repo is:
We supply two different shell scripts. The first one, `fetch_someip_libs.sh`, is responsible for cloning all the necessary libraries to work with SOME/IP and CommonAPI. The second one called `add_to_aosp.sh` will automatically copy all code to the correct place in the AOSP source tree. Run these two scripts one after the other, changing `/pathTo/aosp` for the path to your AOSP source tree:

```bash
./fetch_someip_libs.sh
./add_to_aosp.sh /pathTo/aosp
```

If you use VSCode, you can use [Run on Save](https://marketplace.visualstudio.com/items?itemName=emeraldwalk.RunOnSave) to automatically update the files with this script on save.

#### Sample HAL implementation

This repository also contains an example of how to develop a HAL and use it through the SDK-Addon. First, focus on how the **hello-world-service** example is described here. Then, take a look at the [HAL Documentation](doc/HAL.md).
This repository also contains an example of how to develop a HAL and use it through the SDK-Addon. First, focus on how the **hello-world-service** example is described here. Then, take a look at the [HAL Documentation](doc/HAL.md).And then, if you are comfortable going further, take a look at the [HAL using SOME/IP](doc/SOME-IP-HAL.md), which is a more complex example involving a HAL that uses SOME/IP to communicate with a provider service.

## Hello World System Service

Expand Down
6 changes: 2 additions & 4 deletions device/profusion/profusion_sdk_addon/profusion_sdk_addon.mk
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,12 @@ PRODUCT_SDK_ADDON_NAME := profusion_sdk_addon
INTERNAL_SDK_HOST_OS_NAME := $(HOST_OS)

PRODUCT_PACKAGES := \
libvsomeip \
libvsomeip_cfg \
libvsomeip_sd \
libvsomeip_e2e \
libvsomeip3 \
libCommonAPI \
libCommonAPI-SomeIP \
helloworld \
profusion.hardware.dummy_car_info_hal-service \
some_ip_playground-service \
DummyCarInfoManager

# Copy the manifest and hardware files for the SDK add-on.
Expand Down
1 change: 1 addition & 0 deletions device/profusion/sepolicy/daemon/file_contexts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/vendor/bin/hw/profusion.hardware.dummy_car_info_hal-service u:object_r:dummy_car_info_hal_exec:s0
/vendor/bin/some_ip_playground-service u:object_r:some_ip_playground-service_exec:s0
12 changes: 12 additions & 0 deletions device/profusion/sepolicy/daemon/someip.te
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
type some_ip_playground-service, domain;
type some_ip_playground-service_exec, exec_type, file_type, vendor_file_type;

init_daemon_domain(some_ip_playground-service)

allow some_ip_playground-service sysfs:file { open read };
allow some_ip_playground-service vendor_data_file:dir { add_name remove_name write };
allow some_ip_playground-service vendor_data_file:file { create open read write lock };
allow some_ip_playground-service vendor_data_file:sock_file { create setattr read write unlink};
allow some_ip_playground-service self:netlink_route_socket { create bind shutdown nlmsg_read nlmsg_readpriv read write };
allow some_ip_playground-service self:tcp_socket create;
allow some_ip_playground-service self:udp_socket { create ioctl };
81 changes: 81 additions & 0 deletions doc/SOME-IP-HAL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# HAL with SOME/IP and CommonAPI
This repository also contains a HAL implementation using SOME/IP. The HAL is implemented in the `hardware/implementations/some_ip_hal` directory. In addition to the HAL, this repository also has files related to the PlaygroundService, which will provide some mocked data through SOME/IP.
The SOME/IP service of this implementation is based on the implementation that can be found at [test-someip-service](https://github.com/COVESA/test-someip-service).

## CommonAPI Files
At this documentation, I will not go deeper into CommonAPI framework concepts. If you want to know more about it, please refer to the [CommonAPI documentation](https://covesa.github.io/capicxx-core-tools/).

#### `hardware/implementation/some_ip_hal/franca`
This directory contains the Franca files that will be used to generate the CommonAPI files. The `.fdepl` and `.fidl` files here are strictly the same as the ones used in [test-someip-service](https://github.com/COVESA/test-someip-service). These files define how CommonAPI should generate files to provide information about a vehicle, such as speed, gear, fuel level, etc.

#### `hardware/implementation/some_ip_hal/default/mock`
This directory contains the mock values that will be used by the PlaygroundService to provide information about the vehicle.

#### `hardware/implementation/some_ip_hal/default/include`
This directory will contain the generated CommonAPI files. Commands to generate these files are shown below.

#### `hardware/implementation/some_ip_hal/default/PlaygroundStubImpl.cpp` and `hardware/implementation/some_ip_hal/default/PlaygroundStubImpl.hpp`
These files contain the implementation to `PlaygroundStubDefault`, which is basically the class that will provide the information about the vehicle to the PlaygroundService. Note that in `PlaygroundStubImpl.hpp` all the attributes come from the `Mock` class.

#### `hardware/implementation/some_ip_hal/default/PlaygroundService.cpp`
```cpp
...
using namespace std;

int main() {
std::cout << "SOMEIPPlayground: Successfully Registered Service!" << std::endl;
std::shared_ptr<CommonAPI::Runtime> runtime = CommonAPI::Runtime::get();
std::shared_ptr<PlaygroundStubImpl> playgroundService =
std::make_shared<PlaygroundStubImpl>();
runtime->registerService("local", "1", playgroundService);
std::cout << "SOMEIPPlayground: Successfully Registered Service!" << std::endl;

while (true) {
playgroundService->updateTankVolume();
playgroundService->monitorTankLevel();
std::cout << "SOMEIPPlayground: Waiting for calls..." << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
return 0;
}
```
This file contains the main function of the PlaygroundService. The principal responsibility of this file is to register a service using the `PlaygroundStubImpl`. Also, this main function will loop indefinitely simulating the vehicle use, and updating the tank volume.
### Generating CommonAPI Files
Since you already cloned the necessary libs using `fetch_someip_libs.sh`, generate CommonAPI is very simple. To generate core files run:
```bash
./libs/someip-generators/commonapi_core_generator/commonapi-core-generator-linux-x86 -nv -sk \
--dest "hardware/implementations/some_ip_hal/default/include" \
hardware/implementations/some_ip_hal/franca/instances/org.genivi.vehicle.playground.fdepl
```

And to generate SOME/IP files run:

```bash
./libs/someip-generators/commonapi_someip_generator/commonapi-someip-generator-linux-x86 -nv \
--dest "hardware/implementations/some_ip_hal/default/include" \
hardware/implementations/some_ip_hal/franca/instances/org.genivi.vehicle.playground.fdepl
```

### Its necessary to start the service manualy?
No, the service will be started automatically through the some_ip_playground-init.rc file at Android boot:

```
service some_ip_playground-service /vendor/bin/some_ip_playground-service
class main
user root
group root
disabled
setenv VSOMEIP_APPLICATION_NAME playground-service
setenv VSOMEIP_CONFIGURATION /vendor/etc/some_ip_playground/vsomeip.json
setenv VSOMEIP_BASE_PATH /data/vendor/vsomeip/
on property:sys.boot_completed=1
mkdir /data/vendor/vsomeip 0771 root root
start some_ip_playground-service
```

This file defines the necessary environment variables to start the service and also starts the service when the property `sys.boot_completed` is set to 1. Another important part is to create the directory `/data/vendor/vsomeip` where the vsomeip files will be located. This path will also be important when starting our HAL.
1 change: 1 addition & 0 deletions hardware/implementations/some_ip_hal/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
default/include/*
55 changes: 55 additions & 0 deletions hardware/implementations/some_ip_hal/default/Android.bp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
cc_defaults {
name: "some_ip_playground-defaults",
vendor: true,
rtti: true,
cppflags: [
"-fexceptions",
"-Wall",
"-Werror",
"-Wno-ignored-attributes",
"-Wno-unused-parameter",
"-Wno-overloaded-virtual",
"-DCOMMONAPI_INTERNAL_COMPILATION",
],

shared_libs: [
"libvsomeip3-cfg",
"libvsomeip3",
"libCommonAPI",
"libCommonAPI-SomeIP",
"libbase",
],
}

runtime_required = [
"some_ip_playground-vsomeip.json",
]

prebuilt_etc {
name: "some_ip_playground-vsomeip.json",
vendor: true,
sub_dir: "some_ip_playground",
src: "vsomeip.json",
filename:"vsomeip.json"
}

cc_binary {
name: "some_ip_playground-service",
defaults: [
"some_ip_playground-defaults",
],
init_rc: ["playground_service/some_ip_playground-init.rc"],
local_include_dirs: [
"playground_service/mock",
"include",
],
srcs: [
"playground_service/PlaygroundService.cpp",
"playground_service/PlaygroundStubImpl.cpp",
"include/v1/org/genivi/vehicle/playground/PlaygroundSomeIPDeployment.cpp",
"include/v1/org/genivi/vehicle/playground/PlaygroundSomeIPStubAdapter.cpp",
"playground_service/mock/MockedAttributes.cpp",
],
required: runtime_required,
vendor: true,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (C) 2021, Bayerische Motoren Werke Aktiengesellschaft (BMW AG),
* Author: Alexander Domin (Alexander.Domin@bmw.de)
* Copyright (C) 2021, ProFUSION Sistemas e Soluções LTDA,
* Author: Leandro Ferlin (leandroferlin@profusion.mobi)
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the
* Mozilla Public License, v. 2.0. If a copy of the MPL was
* not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
*/

#include <iostream>
#include <thread>
#include <CommonAPI/CommonAPI.hpp>
#include "PlaygroundStubImpl.hpp"

using namespace std;

int main() {
std::cout << "SOMEIPPlayground: Successfully Registered Service!" << std::endl;
std::shared_ptr<CommonAPI::Runtime> runtime = CommonAPI::Runtime::get();
std::shared_ptr<PlaygroundStubImpl> playgroundService =
std::make_shared<PlaygroundStubImpl>();
runtime->registerService("local", "1", playgroundService);
std::cout << "SOMEIPPlayground: Successfully Registered Service!" << std::endl;

while (true) {
playgroundService->updateTankVolume();
playgroundService->monitorTankLevel();
std::cout << "SOMEIPPlayground: Waiting for calls..." << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
return 0;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* Copyright (C) 2021, Bayerische Motoren Werke Aktiengesellschaft (BMW AG),
* Author: Alexander Domin (Alexander.Domin@bmw.de)
* Copyright (C) 2021, ProFUSION Sistemas e Soluções LTDA,
* Author: Leandro Ferlin (leandroferlin@profusion.mobi)
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the
* Mozilla Public License, v. 2.0. If a copy of the MPL was
* not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
*/

#include "PlaygroundStubImpl.hpp"
#include "mock/MockedAttributes.hpp"
#include <cstdint>
#include <csignal>
#include <iostream>
#include <iterator>
#include <stdexcept>
#include <sys/types.h>

typedef v1_0::org::genivi::vehicle::playground::PlaygroundStubDefault
PlaygroundStubDefault;

PlaygroundStubImpl::PlaygroundStubImpl()
: consumption{}, capacity{}, volume{}, engineSpeed{}, currentGear{},
isReverseGearOn{}, drivePowerTransmission{}, doorsOpeningStatus{},
seatHeatingStatus{}, seatHeatingLevel{} {
initializeAttributes();
}
PlaygroundStubImpl::~PlaygroundStubImpl() {}

void PlaygroundStubImpl::initializeAttributes() {
PlaygroundStubDefault::setConsumptionAttribute(consumption.getValue());
PlaygroundStubDefault::setCapacityAttribute(capacity.getValue());
PlaygroundStubDefault::setVolumeAttribute(volume.getValue());
PlaygroundStubDefault::setEngineSpeedAttribute(engineSpeed.getValue());
PlaygroundStubDefault::setCurrentGearAttribute(currentGear.getValue());
PlaygroundStubDefault::setIsReverseGearOnAttribute(
isReverseGearOn.getValue());
PlaygroundStubDefault::setDrivePowerTransmissionAttribute(
drivePowerTransmission.getValue());
PlaygroundStubDefault::setDoorsOpeningStatusAttribute(
doorsOpeningStatus.getValue());
PlaygroundStubDefault::setSeatHeatingStatusAttribute(
seatHeatingStatus.getValue());
PlaygroundStubDefault::setSeatHeatingLevelAttribute(
seatHeatingLevel.getValue());
}

void PlaygroundStubImpl::updateTankVolume() {
const float currentVolume = PlaygroundStubDefault::getVolumeAttribute();
float updatedVolume;
if (currentVolume > 0.0) {
updatedVolume = currentVolume - 0.1;
} else {
updatedVolume = capacity.getCapacityInLiters();
}
PlaygroundStubDefault::setVolumeAttribute(updatedVolume);
}

void PlaygroundStubImpl::monitorTankLevel() {
const double capacityInLiters = capacity.getCapacityInLiters();
const int currentVolume = PlaygroundStubDefault::getVolumeAttribute();

const uint8_t &level = (uint8_t)(100 * currentVolume / capacityInLiters);
fireCurrentTankVolumeEvent(level);
}

void PlaygroundStubImpl::changeDoorsState(
const std::shared_ptr<CommonAPI::ClientId> _client,
CarDoorsCommand _commands, changeDoorsStateReply_t _reply) {

DoorsStatus lockedDoorsStatus =
PlaygroundStubDefault::getDoorsOpeningStatusAttribute();

const bool &currentFrontLeftState = lockedDoorsStatus.getFrontLeft();
const bool &currentFrontRightState = lockedDoorsStatus.getFrontRight();
const bool &currentRearLeftState = lockedDoorsStatus.getRearLeft();
const bool &currentRearRightState = lockedDoorsStatus.getRearRight();

const DoorCommand &frontLeftCommand = _commands.getFrontLeftDoor();
const DoorCommand &frontRightCommand = _commands.getFrontRightDoor();
const DoorCommand &rearLeftCommand = _commands.getRearLeftDoor();
const DoorCommand &rearRightCommand = _commands.getRearRightDoor();

const bool &nextFrontLeftState = doorsOpeningStatus.getNextStateFromCommand(
currentFrontLeftState, frontLeftCommand);
const bool &nextFrontRightState = doorsOpeningStatus.getNextStateFromCommand(
currentFrontRightState, frontRightCommand);
const bool &nextRearLeftState = doorsOpeningStatus.getNextStateFromCommand(
currentRearLeftState, rearLeftCommand);
const bool &nextRearRightState = doorsOpeningStatus.getNextStateFromCommand(
currentRearRightState, rearRightCommand);

const DoorsStatus &doorsStatus =
DoorsStatus(nextFrontLeftState, nextFrontRightState, nextRearLeftState,
nextRearRightState);

PlaygroundStubDefault::setDoorsOpeningStatusAttribute(doorsStatus);
_reply();
};
Loading

0 comments on commit 4777f73

Please sign in to comment.