Skip to content
Open
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
2 changes: 2 additions & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,8 @@ use_repo(car_window_sim_crate, "car_window_sim_crate")
# ============================================================================
# Rules for Foreign/C/C++/CMake integration
bazel_dep(name = "rules_foreign_cc", version = "0.15.1")
bazel_dep(name = "nlohmann_json", version = "3.11.3")

single_version_override(
module_name = "rules_foreign_cc",
patch_strip = 1,
Expand Down
4 changes: 4 additions & 0 deletions src/gatewayd/etc/gatewayd_config.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
{
"local_service_instances": [
{
"someip_service_id": 4660,
"instance_specifier": "gatewayd/application_window_control",
"events": [
{
"someip_method_id": 34680,
"event_name": "window_control"
}
]
},
{
"someip_service_id": 4660,
"instance_specifier": "gatewayd/application_echo_request",
"events": [
{
"someip_method_id": 34680,
"event_name": "echo_request_tiny"
}
]
Expand Down
86 changes: 79 additions & 7 deletions src/someipd/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,99 @@ This daemon contains the SOME/IP communication stack and is QM
"""

load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@score_communication//bazel/tools:json_schema_validator.bzl", "validate_json_schema_test")

# ============================================================================
# Main Binary
# ============================================================================
# Export config files for deployment
exports_files(
[
"etc/mw_com_config.json",
"etc/someipd_config.json",
],
visibility = ["//visibility:public"],
)

# Core Types (stack-independent SOME/IP types and constants)
cc_library(
name = "someipd_types",
hdrs = ["someipd_types.h"],
)

cc_library(
name = "i_network_stack",
hdrs = ["i_network_stack.h"],
deps = [":someipd_types"],
)

cc_library(
name = "i_internal_ipc",
hdrs = ["i_internal_ipc.h"],
)

cc_library(
name = "someipd_config",
srcs = ["someipd_config_reader.cpp"],
hdrs = ["someipd_config.h"],
deps = [
":someipd_types",
"@nlohmann_json//:json",
],
)

cc_library(
name = "gateway_routing",
srcs = ["gateway_routing.cpp"],
hdrs = ["gateway_routing.h"],
deps = [
":i_internal_ipc",
":i_network_stack",
":someipd_config",
"@score_baselibs//score/mw/log",
],
)

cc_library(
name = "vsomeip_adapter",
srcs = ["vsomeip_adapter.cpp"],
hdrs = ["vsomeip_adapter.h"],
deps = [
":i_network_stack",
"@vsomeip",
],
)

cc_library(
name = "mwcom_adapter",
srcs = ["mwcom_adapter.cpp"],
hdrs = ["mwcom_adapter.h"],
deps = [
":i_internal_ipc",
"//src/network_service:provider",
"@score_baselibs//score/mw/log",
"@score_communication//score/mw/com",
],
)

cc_binary(
name = "someipd",
srcs = ["main.cpp"],
args = [
"-service_instance_manifest",
"$(rootpath etc/mw_com_config.json)",
"-someipd_config",
"$(rootpath etc/someipd_config.json)",
],
data = [
"etc/mw_com_config.json",
"etc/someipd_config.json",
],
visibility = ["//visibility:public"],
deps = [
"//src/network_service:provider",
"@score_baselibs//score/language/futurecpp",
"@score_communication//score/mw/com",
"@vsomeip",
":gateway_routing",
":mwcom_adapter",
":someipd_config",
":vsomeip_adapter",
"@score_baselibs//score/mw/log",
],
)

Expand Down
27 changes: 27 additions & 0 deletions src/someipd/etc/someipd_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"offered_services": [
{
"service_id": "0x1234",
"instance_id": "0x5678",
"unreliable_port": 31000,
"events": [
{
"event_id": "0x8778",
"eventgroup_id": "0x4465"
}
]
}
],
"subscribed_services": [
{
"service_id": "0x4321",
"instance_id": "0x5678",
"events": [
{
"event_id": "0x8778",
"eventgroup_id": "0x4465"
}
]
}
]
}
140 changes: 140 additions & 0 deletions src/someipd/gateway_routing.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/********************************************************************************
* Copyright (c) 2025 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/

#include "src/someipd/gateway_routing.h"

#include <cstring>
#include <thread>

#include "score/mw/log/logging.h"

namespace score::someip_gateway::someipd {

GatewayRouting::GatewayRouting(std::unique_ptr<INetworkStack> network_stack,
std::unique_ptr<IInternalIpc> internal_ipc, SomeipDConfig config)
: config_(std::move(config)),
internal_ipc_(std::move(internal_ipc)),
network_stack_(std::move(network_stack)) {}

void GatewayRouting::SetupSubscriptions() {
for (const auto& svc : config_.subscribed_services) {
for (const auto& ev : svc.events) {
score::mw::log::LogInfo() << "Registering message handler for service "
<< score::mw::log::LogHex16{svc.service_id} << ":"
<< score::mw::log::LogHex16{svc.instance_id} << " event "
<< score::mw::log::LogHex16{ev.event_id};

network_stack_->RegisterMessageHandler(
svc.service_id, svc.instance_id, ev.event_id,
[this](ServiceId /*service_id*/, InstanceId /*instance_id*/, EventId /*event_id*/,
const std::byte* payload_data, std::size_t payload_size) {
const std::size_t total_size = kSomeipFullHeaderSize + payload_size;
if (total_size > kMaxMessageSize) {
score::mw::log::LogError()
<< "Message too large (" << static_cast<std::uint32_t>(total_size)
<< " bytes). Dropping.";
return;
}
std::byte buffer[kMaxMessageSize] = {};
std::memcpy(buffer + kSomeipFullHeaderSize, payload_data, payload_size);
internal_ipc_->SendToGatewayd(buffer, total_size);
});
}

network_stack_->RequestService(svc.service_id, svc.instance_id);
for (const auto& ev : svc.events) {
network_stack_->SubscribeEvent(svc.service_id, svc.instance_id, ev.event_id,
ev.eventgroup_id);
}
}
}

void GatewayRouting::SetupOfferings() {
// Order matters: offer_event must come before offer_service.
for (const auto& svc : config_.offered_services) {
for (const auto& ev : svc.events) {
score::mw::log::LogInfo()
<< "Offering event " << score::mw::log::LogHex16{svc.service_id} << ":"
<< score::mw::log::LogHex16{svc.instance_id} << " event "
<< score::mw::log::LogHex16{ev.event_id} << " in event group "
<< score::mw::log::LogHex16{ev.eventgroup_id};
network_stack_->OfferEvent(svc.service_id, svc.instance_id, ev.event_id,
ev.eventgroup_id);
}
score::mw::log::LogInfo() << "Offering service " << score::mw::log::LogHex16{svc.service_id}
<< ":" << score::mw::log::LogHex16{svc.instance_id};
network_stack_->OfferService(svc.service_id, svc.instance_id);
}
}

InstanceId GatewayRouting::LookupInstanceId(ServiceId service_id) const {
for (const auto& svc : config_.offered_services) {
if (svc.service_id == service_id) {
return svc.instance_id;
}
}
return kAnyInstance;
}
// exchange event data
void GatewayRouting::ProcessMessages(std::atomic<bool>& shutdown_requested) {
static constexpr std::size_t kMaxSampleCount = 10;

score::mw::log::LogInfo() << "SOME/IP daemon started, waiting for messages...";

while (!shutdown_requested.load()) {
// TODO: Use ReceiveHandler + async runtime instead of polling
internal_ipc_->ReceiveFromGatewayd(
[this](const std::byte* data, std::size_t size) {
if (size < kSomeipFullHeaderSize) {
score::mw::log::LogError()
<< "Received too small sample (size: " << static_cast<std::uint32_t>(size)
<< ", expected at least: "
<< static_cast<std::uint32_t>(kSomeipFullHeaderSize)
<< "). Skipping message.";
return;
}

// Read service_id and event_id from the SOME/IP header (big-endian)
const auto service_id = static_cast<ServiceId>(
(std::to_integer<uint16_t>(data[0]) << 8) | std::to_integer<uint16_t>(data[1]));
const auto event_id = static_cast<EventId>(
(std::to_integer<uint16_t>(data[2]) << 8) | std::to_integer<uint16_t>(data[3]));

const auto instance_id = LookupInstanceId(service_id);
if (instance_id == kAnyInstance) {
score::mw::log::LogError()
<< "No offered service configured for service_id "
<< score::mw::log::LogHex16{service_id} << ". Dropping message.";
return;
}

const auto* payload = data + kSomeipFullHeaderSize;
const auto payload_size = size - kSomeipFullHeaderSize;
network_stack_->Notify(service_id, instance_id, event_id, payload, payload_size);
},
kMaxSampleCount);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}

score::mw::log::LogInfo() << "Shutting down SOME/IP daemon...";
}

void GatewayRouting::Run(std::atomic<bool>& shutdown_requested) {
network_stack_->StartProcessing();
SetupSubscriptions(); // once per service, not per message
SetupOfferings(); // once per service, not per message
ProcessMessages(shutdown_requested);
network_stack_->StopProcessing();
}

} // namespace score::someip_gateway::someipd
53 changes: 53 additions & 0 deletions src/someipd/gateway_routing.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/********************************************************************************
* Copyright (c) 2025 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/

#pragma once

#include <atomic>
#include <memory>

#include "src/someipd/i_internal_ipc.h"
#include "src/someipd/i_network_stack.h"
#include "src/someipd/someipd_config.h"

namespace score::someip_gateway::someipd {

/// Bridge abstraction that decouples the routing logic from both the SOME/IP
/// network stack and the internal IPC framework.
///
/// Abstraction:GatewayRouting
/// Implementor: IInternalIpc and INetworkStack (Abstract interfaces)
/// Concrete Implementor (A/B): MwcomAdapter and VsomeipAdapter.
/// Delegation: network_stack_->RequestService(...) or internal_ipc_->SendToGatewayd(...), ... etc
/// Client: main.cpp instantiates GatewayRouting() and calls Run()

class GatewayRouting {
public:
GatewayRouting(std::unique_ptr<INetworkStack> network_stack,
std::unique_ptr<IInternalIpc> internal_ipc, SomeipDConfig config);

/// Run the routing loop. Blocks until shutdown_requested becomes true.
void Run(std::atomic<bool>& shutdown_requested);

private:
void SetupSubscriptions();
void SetupOfferings();
void ProcessMessages(std::atomic<bool>& shutdown_requested);
InstanceId LookupInstanceId(ServiceId service_id) const;

SomeipDConfig config_;
std::unique_ptr<IInternalIpc> internal_ipc_;
std::unique_ptr<INetworkStack> network_stack_;
};

} // namespace score::someip_gateway::someipd
Loading
Loading