Skip to content
Draft
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
38 changes: 38 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Pinned style for OALS. Tuned to match what's already in the tree
# (4-space indent, K&R braces, ref/pointer attached to the variable,
# no hard column cap). Apply to new code via editor-on-save; do NOT
# mass-format existing files in a single sweep.
---
BasedOnStyle: LLVM
Language: Cpp
Standard: c++20

IndentWidth: 4
TabWidth: 4
UseTab: Never
ColumnLimit: 100

BreakBeforeBraces: Attach
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
SpaceAfterCStyleCast: false
PointerAlignment: Left
ReferenceAlignment: Left
DerivePointerAlignment: false

AccessModifierOffset: -4
NamespaceIndentation: None
FixNamespaceComments: true

IncludeBlocks: Preserve
SortIncludes: false

AlignAfterOpenBracket: Align
BinPackParameters: false
BinPackArguments: true
AllowAllParametersOfDeclarationOnNextLine: true
ConstructorInitializerAllOnOneLineOrOnePerLine: true

EmptyLineBeforeAccessModifier: LogicalBlock
SeparateDefinitionBlocks: Leave
47 changes: 47 additions & 0 deletions .github/workflows/ci.yml

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice addition. We should check for embedded platforms that it still compiles though. e.g. trying to cross-compile the lib with gcc-arm-none-eabi or in a Zephyr context.

Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: CI

on:
push:
branches: ['**']
pull_request:
branches: ['**']

jobs:
build:
name: ${{ matrix.os }} (host=${{ matrix.host_backends }})
strategy:
fail-fast: false
matrix:
include:
# Linux: default Zephyr-firmware-shaped build (no host backends) is
# the path the firmware repos consume — keep it green.
- os: ubuntu-latest
host_backends: OFF
# Host-dev build path used by OALSEngine + sim_switch.
- os: ubuntu-latest
host_backends: ON
- os: macos-latest
host_backends: ON
runs-on: ${{ matrix.os }}

steps:
- uses: actions/checkout@v4

- name: Install deps (Linux)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends cmake ninja-build

- name: Install deps (macOS)
if: runner.os == 'macOS'
run: brew install cmake ninja

- name: Configure
run: |
cmake -G Ninja -B build \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DOAN_HOST_BACKENDS=${{ matrix.host_backends }}

- name: Build
run: cmake --build build
19 changes: 19 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# pre-commit hooks for OpenAudioNetwork. Install once per clone:
# pip install pre-commit && pre-commit install
repos:
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v17.0.6
hooks:
- id: clang-format
types_or: [c++, c]
exclude: '^build/'

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-merge-conflict
- id: check-yaml
- id: check-added-large-files
args: ['--maxkb=512']
13 changes: 13 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,18 @@ if(NO_THREADS)
add_compile_definitions(NO_THREADS)
endif (NO_THREADS)

# OAN_HOST_BACKENDS: switches in the host-side transport seam (SimTransport,
# RawLinuxTransport, RawMacTransport). The define is normally injected by
# the parent OALS build; mirror the logic here so OAN is self-buildable
# (e.g. for CI of OAN-only changes). Forced ON on macOS — there is no
# other working transport on Apple at the moment.
option(OAN_HOST_BACKENDS "Build host dev transports + RT shim" OFF)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The RT shim is a good idea, I think we should use it for all platforms and leave it on permanently

if(APPLE)
set(OAN_HOST_BACKENDS ON CACHE BOOL "Build host dev transports + RT shim" FORCE)
endif()
if(OAN_HOST_BACKENDS)
add_compile_definitions(OAN_HOST_BACKENDS)
endif()

add_subdirectory(common)
add_subdirectory(netutils)
6 changes: 6 additions & 0 deletions common/ClockMaster.h

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK we are already using the system to wait for new data, so technically we are not doing busy polling. The timeout is a good idea though.

Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ class ClockMaster {
void begin_sync_process();
void sync_process();

// Block until a sync packet arrives or timeout_ms elapses.
// Lets the clock thread on host backends stop busy-polling the async recv.
int wait_sync_readable(int timeout_ms) const {
return m_sync_socket->wait_readable(timeout_ms);
}

private:
void start_clock_sync(PeerInfos& slave);
void process_packet(ClockSyncPacket& csp, uint16_t originator);
Expand Down
6 changes: 6 additions & 0 deletions common/ClockSlave.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ class ClockSlave {
void sync_process();
int64_t get_ck_offset();

// Block until a sync packet arrives or timeout_ms elapses. Lets the
// slave's clock thread on host backends stop busy-polling the async recv.
int wait_sync_readable(int timeout_ms) const {
return m_sync_socket->wait_readable(timeout_ms);
}

private:
void send_delay_req(uint16_t dest);
void calc_ck_offset();
Expand Down
49 changes: 35 additions & 14 deletions common/NetworkMapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@

#include "NetworkMapper.h"

#ifndef __linux__
extern void _delay(uint32_t ms);
#if defined(__linux__) || defined(OAN_HOST_BACKENDS)
#include <unistd.h>
#endif

#if !defined(__linux__) && !defined(OAN_HOST_BACKENDS)
extern uint32_t _now_ms();
extern uint64_t _now_us();
extern "C" IfaceMeta _fetch_iface_meta(const std::string&);
#endif // __linux__
#endif

NetworkMapper::NetworkMapper(const PeerConf& pconf) {
m_peer_change_callback = [](PeerInfos&, bool) {};
Expand All @@ -24,16 +27,36 @@ NetworkMapper::~NetworkMapper() {
bool NetworkMapper::init_mapper(const std::string& iface) {
m_map_socket = std::make_unique<LowLatSocket>(m_packet.packet_data.self_uid, std::shared_ptr<NetworkMapper>{});
bool res = m_map_socket->init_socket(iface, EthProtocol::ETH_PROTO_OANDISCO);
if (!res) return false;

#ifdef OAN_HOST_BACKENDS
// On the host-backend path, the transport (sim/raw-mac) supplies the
// device MAC — there is no real interface to query. The MAC in
// m_packet was zero-filled by update_packet() at construction; fill it
// now from the socket whose transport just learned it.
m_packet.packet_data.self_address = 0;
memcpy(&m_packet.packet_data.self_address, m_map_socket->get_self_mac(), 6);
#endif

return res;
return true;
}

void NetworkMapper::update_packet(const PeerConf &pconf) {
#ifdef __linux__
#if defined(__linux__)
auto iface_meta = get_iface_meta(pconf.iface);
#elif defined(OAN_HOST_BACKENDS)
// Skip the iface lookup entirely: pconf.iface may be a transport prefix
// (sim:default, raw:en0) for which no real OS-level lookup makes sense.
IfaceMeta iface_meta{};
// If we already have a socket (i.e. update_packet is being re-run after
// init_mapper), preserve the MAC the transport learned. Otherwise leave
// zero and let init_mapper fill it in once the socket is bound.
if (m_map_socket) {
memcpy(iface_meta.mac, m_map_socket->get_self_mac(), 6);
}
#else
auto iface_meta = _fetch_iface_meta(pconf.iface);
#endif // __linux__
#endif

m_packet.header.type = PacketType::MAPPING;
m_packet.packet_data.topo = pconf.topo;
Expand Down Expand Up @@ -113,11 +136,9 @@ void NetworkMapper::packet_send_update() {
void NetworkMapper::packet_sender() {
while(true) {
packet_send_update();
#ifdef __linux__
#if defined(__linux__) || defined(OAN_HOST_BACKENDS)
usleep(5000000);
#else

#endif // __linux__
#endif
}
}

Expand All @@ -136,9 +157,9 @@ void NetworkMapper::mapper_process() {
mapper_update();
}

#ifdef __linux__
#if defined(__linux__) || defined(OAN_HOST_BACKENDS)
usleep(1000000);
#endif // __linux__
#endif
}
}

Expand Down Expand Up @@ -244,7 +265,7 @@ std::optional<uint8_t> NetworkMapper::first_free_processing_channel(uint16_t uid
}

uint64_t NetworkMapper::local_now() {
#if defined(__linux__) || defined(__ZEPHYR__)
#if defined(__linux__) || defined(__ZEPHYR__) || defined(OAN_HOST_BACKENDS)
return std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now().time_since_epoch()
).count();
Expand All @@ -254,7 +275,7 @@ uint64_t NetworkMapper::local_now() {
}

uint64_t NetworkMapper::local_now_us() {
#if defined(__linux__) || defined(__ZEPHYR__)
#if defined(__linux__) || defined(__ZEPHYR__) || defined(OAN_HOST_BACKENDS)
return std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::high_resolution_clock::now().time_since_epoch()
).count();
Expand Down
39 changes: 38 additions & 1 deletion netutils/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,47 @@ set(OAN_UTILS_SOURCES
LowLatSocket.h
)

if(NOT EMBEDDED_BUILD)
list(APPEND OAN_UTILS_SOURCES
platform/rt.h
platform/rt.cpp
)
endif()

if(OAN_HOST_BACKENDS)
list(APPEND OAN_UTILS_SOURCES
transport/ITransport.h
transport/ITransport.cpp
transport/SimTransport.h
transport/SimTransport.cpp
transport/RawMacTransport.h
transport/RawMacTransport.cpp
)
if(NOT APPLE)
list(APPEND OAN_UTILS_SOURCES
transport/RawLinuxTransport.h
transport/RawLinuxTransport.cpp
)
endif()
endif()

if(EMBEDDED_BUILD)
add_library(oannetutils STATIC ${OAN_UTILS_SOURCES})
else ()
add_library(oannetutils SHARED ${OAN_UTILS_SOURCES})
endif (EMBEDDED_BUILD)

target_include_directories(oannetutils PUBLIC ${PROJECT_SOURCE_DIR})
target_include_directories(oannetutils PUBLIC ${PROJECT_SOURCE_DIR})

# oannetutils and oancommon have a mutual symbol dependency:
# LowLatSocket (in netutils) calls NetworkMapper::get_mac_by_uid
# (in common), and common's ClockMaster/ClockSlave/AudioRouter all
# instantiate LowLatSocket. CMake forbids cyclic target_link_libraries
# on shared libs, so we relax each library's own link step (the symbol
# is unresolved in the .so but always resolved at exe link time when
# both .so's appear on the line — see executables that link them).
if(APPLE)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should not be necessary. If it is, the architecture of the code must change so that it is not a problem anymore on the linking stage.

target_link_options(oannetutils PRIVATE LINKER:-undefined,dynamic_lookup)
elseif(UNIX)
target_link_options(oannetutils PRIVATE LINKER:-z,undefs)
endif()
Loading
Loading