Skip to content

Commit cdd3eb8

Browse files
Initial version
1 parent 88de52e commit cdd3eb8

File tree

7 files changed

+239
-80
lines changed

7 files changed

+239
-80
lines changed

MODULE.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,8 @@ use_repo(car_window_sim_crate, "car_window_sim_crate")
229229
# ============================================================================
230230
# Rules for Foreign/C/C++/CMake integration
231231
bazel_dep(name = "rules_foreign_cc", version = "0.15.1")
232+
bazel_dep(name = "nlohmann_json", version = "3.11.3")
233+
232234
single_version_override(
233235
module_name = "rules_foreign_cc",
234236
patch_strip = 1,

src/someipd/BUILD.bazel

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,22 @@ This daemon contains the SOME/IP communication stack and is QM
1616
"""
1717

1818
load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
19+
load("@rules_cc//cc:cc_library.bzl", "cc_library")
1920
load("@score_communication//bazel/tools:json_schema_validator.bzl", "validate_json_schema_test")
2021

22+
# ============================================================================
23+
# Config Reader Library
24+
# ============================================================================
25+
cc_library(
26+
name = "vsomeip_config_reader",
27+
srcs = ["vsomeip_config_reader.cpp"],
28+
hdrs = ["vsomeip_config_reader.h"],
29+
deps = [
30+
"@nlohmann_json//:json",
31+
"@vsomeip",
32+
],
33+
)
34+
2135
# ============================================================================
2236
# Main Binary
2337
# ============================================================================
@@ -27,12 +41,16 @@ cc_binary(
2741
args = [
2842
"-service_instance_manifest",
2943
"$(rootpath etc/mw_com_config.json)",
44+
"-someipd_config",
45+
"$(rootpath etc/someipd_config.json)",
3046
],
3147
data = [
3248
"etc/mw_com_config.json",
49+
"etc/someipd_config.json",
3350
],
3451
visibility = ["//visibility:public"],
3552
deps = [
53+
":vsomeip_config_reader",
3654
"//src/network_service:provider",
3755
"@score_baselibs//score/language/futurecpp",
3856
"@score_communication//score/mw/com",
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"offered_services": [
3+
{
4+
"service_id": "0x1234",
5+
"instance_id": "0x5678",
6+
"unreliable_port": 31000,
7+
"events": [
8+
{
9+
"event_id": "0x8778",
10+
"eventgroup_id": "0x4465"
11+
}
12+
]
13+
}
14+
],
15+
"subscribed_services": [
16+
{
17+
"service_id": "0x4321",
18+
"instance_id": "0x5678",
19+
"events": [
20+
{
21+
"event_id": "0x8778",
22+
"eventgroup_id": "0x4465"
23+
}
24+
]
25+
}
26+
]
27+
}

src/someipd/main.cpp

Lines changed: 72 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <csignal>
1616
#include <cstdlib>
1717
#include <iostream>
18+
#include <set>
1819
#include <thread>
1920
#include <vsomeip/defines.hpp>
2021
#include <vsomeip/primitive_types.hpp>
@@ -23,34 +24,15 @@
2324
#include "score/mw/com/runtime.h"
2425
#include "score/span.hpp"
2526
#include "src/network_service/interfaces/message_transfer.h"
26-
27-
const char* someipd_name = "someipd";
28-
29-
static const vsomeip::service_t service_id = 0x1111;
30-
static const vsomeip::instance_t service_instance_id = 0x2222;
31-
static const vsomeip::method_t service_method_id = 0x3333;
27+
#include "src/someipd/vsomeip_config_reader.h"
3228

3329
static const std::size_t max_sample_count = 10;
3430

35-
#define SAMPLE_SERVICE_ID 0x1234
36-
#define RESPONSE_SAMPLE_SERVICE_ID 0x4321
37-
#define SAMPLE_INSTANCE_ID 0x5678
38-
#define SAMPLE_METHOD_ID 0x0421
39-
40-
#define SAMPLE_EVENT_ID 0x8778
41-
#define SAMPLE_GET_METHOD_ID 0x0001
42-
#define SAMPLE_SET_METHOD_ID 0x0002
43-
44-
#define SAMPLE_EVENTGROUP_ID 0x4465
45-
46-
#define OTHER_SAMPLE_SERVICE_ID 0x0248
47-
#define OTHER_SAMPLE_INSTANCE_ID 0x5422
48-
#define OTHER_SAMPLE_METHOD_ID 0x1421
49-
5031
using score::someip_gateway::network_service::interfaces::message_transfer::
5132
SomeipMessageTransferProxy;
5233
using score::someip_gateway::network_service::interfaces::message_transfer::
5334
SomeipMessageTransferSkeleton;
35+
using score::someip_gateway::someipd::SomeipDConfig;
5436

5537
// Global flag to control application shutdown
5638
static std::atomic<bool> shutdown_requested{false};
@@ -66,16 +48,32 @@ int main(int argc, const char* argv[]) {
6648
std::signal(SIGTERM, termination_handler);
6749
std::signal(SIGINT, termination_handler);
6850

51+
std::string someipd_config_path = "etc/someipd_config.json";
52+
for (int i = 1; i < argc - 1; ++i) {
53+
if (std::string(argv[i]) == "-someipd_config") {
54+
someipd_config_path = argv[i + 1];
55+
break;
56+
}
57+
}
58+
59+
SomeipDConfig config{};
60+
try {
61+
config = score::someip_gateway::someipd::ReadSomeipDConfig(someipd_config_path);
62+
} catch (const std::exception& ex) {
63+
std::cerr << "Failed to load someipd config: " << ex.what() << std::endl;
64+
return 1;
65+
}
66+
6967
score::mw::com::runtime::InitializeRuntime(argc, argv);
7068

7169
auto runtime = vsomeip::runtime::get();
72-
auto application = runtime->create_application(someipd_name);
70+
auto application = runtime->create_application("someipd");
7371
if (!application->init()) {
7472
std::cerr << "App init failed";
7573
return 1;
7674
}
7775

78-
std::thread([application]() {
76+
std::thread([application, config]() {
7977
auto handles =
8078
SomeipMessageTransferProxy::FindService(
8179
score::mw::com::InstanceSpecifier::Create(std::string("someipd/gatewayd_messages"))
@@ -94,39 +92,56 @@ int main(int argc, const char* argv[]) {
9492
auto skeleton = std::move(create_result).value();
9593
(void)skeleton.OfferService();
9694

97-
application->register_message_handler(
98-
RESPONSE_SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_EVENT_ID,
99-
[&skeleton](const std::shared_ptr<vsomeip::message>& msg) {
100-
auto maybe_message = skeleton.message_.Allocate();
101-
if (!maybe_message.has_value()) {
102-
std::cerr << "Failed to allocate SOME/IP message:"
103-
<< maybe_message.error().Message() << std::endl;
104-
return;
105-
}
106-
auto message_sample = std::move(maybe_message).value();
107-
memcpy(message_sample->data + VSOMEIP_FULL_HEADER_SIZE,
108-
msg->get_payload()->get_data(), msg->get_payload()->get_length());
109-
message_sample->size =
110-
msg->get_payload()->get_length() + VSOMEIP_FULL_HEADER_SIZE;
111-
skeleton.message_.Send(std::move(message_sample));
112-
});
113-
114-
application->request_service(RESPONSE_SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID);
115-
std::set<vsomeip::eventgroup_t> its_groups;
116-
its_groups.insert(SAMPLE_EVENTGROUP_ID);
117-
application->request_event(RESPONSE_SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID,
118-
SAMPLE_EVENT_ID, its_groups,
119-
vsomeip::event_type_e::ET_EVENT);
120-
application->subscribe(RESPONSE_SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID,
121-
SAMPLE_EVENTGROUP_ID);
122-
123-
std::set<vsomeip::eventgroup_t> groups{SAMPLE_EVENTGROUP_ID};
124-
application->offer_event(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_EVENT_ID,
125-
groups);
126-
application->offer_service(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID);
127-
128-
// application->update_service_configuration(
129-
// SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, 12345u, true, true, true);
95+
// Register message handlers for all subscribed services
96+
for (const auto& svc : config.subscribed_services) {
97+
for (const auto& ev : svc.events) {
98+
application->register_message_handler(
99+
svc.service_id, svc.instance_id, ev.event_id,
100+
[&skeleton](const std::shared_ptr<vsomeip::message>& msg) {
101+
auto maybe_message = skeleton.message_.Allocate();
102+
if (!maybe_message.has_value()) {
103+
std::cerr << "Failed to allocate SOME/IP message:"
104+
<< maybe_message.error().Message() << std::endl;
105+
return;
106+
}
107+
auto message_sample = std::move(maybe_message).value();
108+
memcpy(message_sample->data + VSOMEIP_FULL_HEADER_SIZE,
109+
msg->get_payload()->get_data(),
110+
msg->get_payload()->get_length());
111+
message_sample->size =
112+
msg->get_payload()->get_length() + VSOMEIP_FULL_HEADER_SIZE;
113+
skeleton.message_.Send(std::move(message_sample));
114+
});
115+
}
116+
117+
application->request_service(svc.service_id, svc.instance_id);
118+
for (const auto& ev : svc.events) {
119+
std::set<vsomeip::eventgroup_t> groups{ev.eventgroup_id};
120+
application->request_event(svc.service_id, svc.instance_id, ev.event_id, groups,
121+
vsomeip::event_type_e::ET_EVENT);
122+
application->subscribe(svc.service_id, svc.instance_id, ev.eventgroup_id);
123+
}
124+
}
125+
126+
// Offer all configured local services to the SOME/IP network.
127+
// Order matters: offer_event → offer_service (local) → update_service_configuration
128+
// (promote to network). update_service_configuration requires the service to already
129+
// be offered locally — see vsomeip application.hpp docs.
130+
for (const auto& svc : config.offered_services) {
131+
for (const auto& ev : svc.events) {
132+
std::set<vsomeip::eventgroup_t> groups{ev.eventgroup_id};
133+
application->offer_event(svc.service_id, svc.instance_id, ev.event_id, groups);
134+
}
135+
application->offer_service(svc.service_id, svc.instance_id);
136+
if (svc.unreliable_port != 0) {
137+
// Expose the locally offered service on the network via UDP.
138+
// This replaces the "services" section in vsomeip.json.
139+
application->update_service_configuration(
140+
svc.service_id, svc.instance_id, svc.unreliable_port,
141+
/*reliable=*/false, /*magic_cookies_enabled=*/false, /*offer=*/true);
142+
}
143+
}
144+
130145
auto payload = vsomeip::runtime::get()->create_payload();
131146

132147
std::cout << "SOME/IP daemon started, waiting for messages..." << std::endl;
@@ -136,7 +151,6 @@ int main(int argc, const char* argv[]) {
136151
// TODO: Use ReceiveHandler + async runtime instead of polling
137152
proxy.message_.GetNewSamples(
138153
[&](auto message_sample) {
139-
// TODO: Check if size is larger than capacity of data
140154
score::cpp::span<const std::byte> message(message_sample->data,
141155
message_sample->size);
142156

@@ -155,8 +169,7 @@ int main(int argc, const char* argv[]) {
155169
payload->set_data(
156170
reinterpret_cast<const vsomeip_v3::byte_t*>(payload_data.data()),
157171
payload_data.size());
158-
application->notify(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_EVENT_ID,
159-
payload);
172+
application->notify(service_id, instance_id, event_id, payload);
160173
},
161174
max_sample_count);
162175
std::this_thread::sleep_for(std::chrono::milliseconds(100));
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/********************************************************************************
2+
* Copyright (c) 2025 Contributors to the Eclipse Foundation
3+
*
4+
* See the NOTICE file(s) distributed with this work for additional
5+
* information regarding copyright ownership.
6+
*
7+
* This program and the accompanying materials are made available under the
8+
* terms of the Apache License Version 2.0 which is available at
9+
* https://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* SPDX-License-Identifier: Apache-2.0
12+
********************************************************************************/
13+
14+
#include "src/someipd/vsomeip_config_reader.h"
15+
16+
#include <fstream>
17+
#include <nlohmann/json.hpp>
18+
#include <stdexcept>
19+
#include <string>
20+
21+
namespace score::someip_gateway::someipd {
22+
23+
namespace {
24+
25+
vsomeip::service_t ParseHex16(const std::string& value) {
26+
return static_cast<vsomeip::service_t>(std::stoul(value, nullptr, 16));
27+
}
28+
29+
ServiceEventConfig ParseEvent(const nlohmann::json& obj) {
30+
return ServiceEventConfig{
31+
ParseHex16(obj.at("event_id").get<std::string>()),
32+
ParseHex16(obj.at("eventgroup_id").get<std::string>()),
33+
};
34+
}
35+
36+
ServiceConfig ParseService(const nlohmann::json& obj) {
37+
ServiceConfig svc{};
38+
svc.service_id = ParseHex16(obj.at("service_id").get<std::string>());
39+
svc.instance_id = ParseHex16(obj.at("instance_id").get<std::string>());
40+
if (obj.contains("unreliable_port")) {
41+
svc.unreliable_port =
42+
static_cast<std::uint16_t>(obj.at("unreliable_port").get<std::uint16_t>());
43+
}
44+
for (const auto& ev : obj.at("events")) {
45+
svc.events.push_back(ParseEvent(ev));
46+
}
47+
return svc;
48+
}
49+
50+
} // namespace
51+
52+
SomeipDConfig ReadSomeipDConfig(const std::string& config_path) {
53+
std::ifstream file(config_path);
54+
if (!file.is_open()) {
55+
throw std::runtime_error("Cannot open someipd config file: " + config_path);
56+
}
57+
58+
const nlohmann::json root = nlohmann::json::parse(file);
59+
60+
SomeipDConfig config{};
61+
for (const auto& svc : root.at("offered_services")) {
62+
config.offered_services.push_back(ParseService(svc));
63+
}
64+
for (const auto& svc : root.at("subscribed_services")) {
65+
config.subscribed_services.push_back(ParseService(svc));
66+
}
67+
return config;
68+
}
69+
70+
} // namespace score::someip_gateway::someipd
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/********************************************************************************
2+
* Copyright (c) 2025 Contributors to the Eclipse Foundation
3+
*
4+
* See the NOTICE file(s) distributed with this work for additional
5+
* information regarding copyright ownership.
6+
*
7+
* This program and the accompanying materials are made available under the
8+
* terms of the Apache License Version 2.0 which is available at
9+
* https://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* SPDX-License-Identifier: Apache-2.0
12+
********************************************************************************/
13+
14+
#pragma once
15+
16+
#include <string>
17+
#include <vector>
18+
#include <vsomeip/vsomeip.hpp>
19+
20+
namespace score::someip_gateway::someipd {
21+
22+
/// A single event/eventgroup pair within a SOME/IP service.
23+
struct ServiceEventConfig {
24+
vsomeip::event_t event_id;
25+
vsomeip::eventgroup_t eventgroup_id;
26+
};
27+
28+
/// Transport-level configuration for one SOME/IP service instance.
29+
struct ServiceConfig {
30+
vsomeip::service_t service_id;
31+
vsomeip::instance_t instance_id;
32+
/// UDP port for unreliable (UDP) transport. 0 means no external transport configured.
33+
std::uint16_t unreliable_port{0};
34+
std::vector<ServiceEventConfig> events;
35+
};
36+
37+
/// Full someipd service configuration.
38+
struct SomeipDConfig {
39+
/// Services that someipd offers to the SOME/IP network (outbound: IPC → network).
40+
std::vector<ServiceConfig> offered_services;
41+
/// Services that someipd subscribes to from the SOME/IP network (inbound: network → IPC).
42+
std::vector<ServiceConfig> subscribed_services;
43+
};
44+
45+
/// @brief Parse the someipd service configuration from a JSON file.
46+
/// @param config_path Absolute or relative path to the someipd config JSON file.
47+
/// @throws std::runtime_error if the file cannot be opened or parsed.
48+
SomeipDConfig ReadSomeipDConfig(const std::string& config_path);
49+
50+
} // namespace score::someip_gateway::someipd

0 commit comments

Comments
 (0)