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
1 change: 0 additions & 1 deletion Bdd/features/structured_data.feature
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
@udp
@freertoswip
Feature: Structured data — meta SD-ELEMENT
The library populates the IANA-registered "meta" SD-ELEMENT with
sequenceId, sysUpTime, and language per RFC 5424 §7.3.
Expand Down
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ live under `Core/Interface/`; platform-specific helpers (the `SolidSyslogPosix*`
| `SolidSyslogWindowsHostname.h` | String callback implementor using Windows hostname | `SolidSyslogWindowsHostname_Get` (writes into `SolidSyslogFormatter*`) |
| `SolidSyslogWindowsProcessId.h` | String callback implementor using Windows process ID | `SolidSyslogWindowsProcessId_Get` (writes into `SolidSyslogFormatter*`) |
| `SolidSyslogWindowsSysUpTime.h` | SysUpTime callback implementor using `GetTickCount64` | `SolidSyslogWindowsSysUpTime_Get` (returns `uint32_t` hundredths since boot), `WindowsSysUpTime_GetTickCount64` (function-pointer seam for unit tests) |
| `SolidSyslogFreeRtosSysUpTime.h` | SysUpTime callback implementor using `xTaskGetTickCount` on FreeRTOS targets | `SolidSyslogFreeRtosSysUpTime_Get` (returns `uint32_t` hundredths since boot, wraps per RFC 3418 `TimeTicks`; uint64 intermediate so the result is correct at any `configTICK_RATE_HZ`) |
| `SolidSyslogWindowsSleep.h` | System setup code wiring a `SolidSyslogSleepFunction` on Windows targets | `SolidSyslogWindowsSleep` (wraps `Sleep`) |
| `SolidSyslogSleep.h` | Any code passing or implementing a sleep callback | `SolidSyslogSleepFunction` typedef (used by `SolidSyslogTlsStreamConfig.sleep` for the bounded handshake retry) |
| `SolidSyslogStructuredData.h` | Library internals (SD dispatch) | `SolidSyslogStructuredData_Format` (writes into `SolidSyslogFormatter*`) |
Expand Down
91 changes: 91 additions & 0 deletions DEVLOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,96 @@
# Dev Log

## 2026-05-10 — S08.03 slice 8 — Meta SD wiring + FreeRtosSysUpTime adapter (#310)

Slice 7 wired the first SD-ELEMENT (Origin) and brought the FreeRTOS
BDD runner to 5 features / 14 scenarios green. Slice 8 adds the meta
SD-ELEMENT — sequenceId, sysUpTime, language — to
`Example/FreeRtos/SingleTask/main.c`, introduces a new
`SolidSyslogFreeRtosSysUpTime` platform adapter, and untags
`structured_data.feature`. The runner is now at **6 features / 17
scenarios green** (slice-7 baseline 5 / 14; +1 feature, +3 scenarios).

### Decisions

- **StdAtomicOps on Cortex-M3, no new platform adapter.** Cross-toolchain
compiled `Platform/Atomics/Source/SolidSyslogStdAtomicOps.c` for
Cortex-M3 already (`build/freertos-cross/.../*.obj` was present),
so the question was whether linkage would succeed. It does — the
cross build links the new ELF cleanly. On Cortex-M3 + Thumb-2 GCC
inlines `_Atomic uint32_t` operations to LDREX/STREX with no
libatomic runtime, and the SolidSyslog counter is incremented only
inside `SolidSyslog_Log` (task context only on this single-task
example, never from an ISR), so the ARM exclusive monitor is
sufficient. No `SolidSyslogFreeRtosAtomicOps` adapter was needed;
if a future MultiTask example needs ISR-vs-task atomicity that
adapter is the natural extension.
- **Tick width stayed 32-bit.** The original handoff floated
`configTICK_TYPE_WIDTH_IN_BITS = TICK_TYPE_WIDTH_64_BITS` to keep
the SysUpTime arithmetic trivially overflow-safe, but the upstream
`ARM_CM3` portmacro hard-errors on 64-bit ticks (`portmacro.h:73`,
`#error configTICK_TYPE_WIDTH_IN_BITS set to unsupported tick type
width.`). Patching the vendor port wasn't worth it; instead the
adapter does `(uint64_t)xTaskGetTickCount() * 100 / configTICK_RATE_HZ`
with a uint64 intermediate so the formula stays correct at any
HZ, then casts to `uint32_t` for RFC 3418 `TimeTicks` wrap
semantics. Mirrors `SolidSyslogPosixSysUpTime` which already uses
the same uint64-inside / uint32-out shape.
- **Language string reuses `Example/Common/ExampleLanguage`.** The
Linux/Windows examples already use `ExampleLanguage_Get` returning
`en-GB`; reusing the same source on FreeRTOS keeps the BDD
assertion target-agnostic. One-line CMakeLists addition. No
divergent local getter.
- **Untagged `structured_data.feature` at feature level.** All three
scenarios pass (sequenceId 1, sequential sequenceId values,
sysUpTime + language). `time_quality.feature` stays tagged because
both its scenarios assert `tzKnown` (timeQuality SD — slice 9), and
`origin.feature::All standard structured data present` stays
tagged because it asserts sequenceId AND tzKnown together.
- **Kept SysUpTimeTest outside the Plus-TCP guard** in
`Tests/FreeRtos/CMakeLists.txt`. The adapter only needs FreeRTOS
kernel headers (`FreeRTOS.h`, `task.h` for `TickType_t`); the
existing comment in that file explicitly flags this scope split
("a minimal `FREERTOS_KERNEL_PATH`-only environment can still
build the UART test"). The SysUpTime test now sits with
`CmsdkUartTest` in that same kernel-only scope. `FreeRtosTaskFake`
picked up a stubbable `xTaskGetTickCount` + `_SetTickCount`
accessor alongside the existing `vTaskDelay` stub.

### Local verification

- `cmake --build --preset debug` — full host build clean. All 6 host
test executables pass (1 + 4 FreeRTOS + 1 OpenSSL integration),
including the new `SolidSyslogFreeRtosSysUpTimeTest` (4 tests:
zero, one, mid-range, `UINT32_MAX` boundary).
- `cmake --build --preset freertos-cross --target
SolidSyslogFreeRtosSingleTask` — clean. **StdAtomicOps linked into
the Cortex-M3 ELF** without needing a FreeRTOS-specific adapter.
- `behave --tags='not @wip and not @freertoswip and @udp'
Bdd/features/structured_data.feature` against `syslog-ng-freertos`:
3 of 3 scenarios pass.
- Full FreeRTOS BDD sweep: 6 features / 17 scenarios pass / 29
skipped (slice 7 baseline 5 / 14 / 32; +1 feature, +3 scenarios,
-3 skipped).
- `clang-format --dry-run --Werror` on touched C / C++ files: clean.
- cppcheck / tidy / iwyu / sanitize / coverage / Windows: not run
locally (cross-only devcontainer); CI's responsibility.

### Deferred

- timeQuality SD wiring on FreeRTOS — slice 9. Will untag
`time_quality.feature` and the remaining
`origin.feature::All standard structured data present` scenario.
- The `udp_mtu.feature::Oversize` scenario — UDP path-MTU EMSGSIZE
on FreeRTOS-Plus-TCP, its own slice.
- `SolidSyslogFreeRtosAtomicOps` adapter wrapping
`taskENTER_CRITICAL` / `taskEXIT_CRITICAL` — not needed for the
single-task example (StdAtomicOps suffices); will be the right
primitive when a MultiTask example arrives in S08.04.

### Open questions

- None for this slice.

## 2026-05-10 — S08.03 slice 7 — Origin SD wiring in FreeRTOS example (#308)

Slice 6 closed the cmdline→`set` translation gap so the FreeRTOS BDD
Expand Down
2 changes: 2 additions & 0 deletions Example/FreeRtos/SingleTask/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,10 @@ add_executable(SolidSyslogFreeRtosSingleTask
${CMAKE_SOURCE_DIR}/Platform/FreeRtos/Source/SolidSyslogAddress.c
${CMAKE_SOURCE_DIR}/Platform/FreeRtos/Source/SolidSyslogFreeRtosDatagram.c
${CMAKE_SOURCE_DIR}/Platform/FreeRtos/Source/SolidSyslogFreeRtosStaticResolver.c
${CMAKE_SOURCE_DIR}/Platform/FreeRtos/Source/SolidSyslogFreeRtosSysUpTime.c
${CMAKE_SOURCE_DIR}/Example/Common/ExampleInteractive.c
${CMAKE_SOURCE_DIR}/Example/Common/ExampleIps.c
${CMAKE_SOURCE_DIR}/Example/Common/ExampleLanguage.c
$<TARGET_OBJECTS:solid_syslog_freertos_upstream>
)

Expand Down
29 changes: 22 additions & 7 deletions Example/FreeRtos/SingleTask/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,21 @@
#include "ExampleEnterpriseId.h"
#include "ExampleInteractive.h"
#include "ExampleIps.h"
#include "ExampleLanguage.h"
#include "SolidSyslog.h"
#include "SolidSyslogAtomicCounter.h"
#include "SolidSyslogConfig.h"
#include "SolidSyslogEndpoint.h"
#include "SolidSyslogFormatter.h"
#include "SolidSyslogFreeRtosDatagram.h"
#include "SolidSyslogFreeRtosStaticResolver.h"
#include "SolidSyslogFreeRtosSysUpTime.h"
#include "SolidSyslogMetaSd.h"
#include "SolidSyslogNullBuffer.h"
#include "SolidSyslogNullStore.h"
#include "SolidSyslogOriginSd.h"
#include "SolidSyslogPrival.h"
#include "SolidSyslogStdAtomicOps.h"
#include "SolidSyslogTimestamp.h"
#include "SolidSyslogUdpSender.h"

Expand Down Expand Up @@ -334,15 +339,22 @@ static void InteractiveTask(void* argument)
struct SolidSyslogBuffer* buffer = SolidSyslogNullBuffer_Create(sender);
struct SolidSyslogStore* store = SolidSyslogNullStore_Create();

struct SolidSyslogOriginSdConfig originConfig = {
.software = "SolidSyslogExample",
.swVersion = "0.7.0",
.enterpriseId = EXAMPLE_ENTERPRISE_ID,
.getIpCount = ExampleIps_Count,
.getIpAt = ExampleIps_At,
struct SolidSyslogAtomicCounter* counter = SolidSyslogAtomicCounter_Create(SolidSyslogStdAtomicOps_Create());
struct SolidSyslogMetaSdConfig metaConfig = {
.counter = counter,
.getSysUpTime = SolidSyslogFreeRtosSysUpTime_Get,
.getLanguage = ExampleLanguage_Get,
};
struct SolidSyslogStructuredData* metaSd = SolidSyslogMetaSd_Create(&metaConfig);
struct SolidSyslogOriginSdConfig originConfig = {
.software = "SolidSyslogExample",
.swVersion = "0.7.0",
.enterpriseId = EXAMPLE_ENTERPRISE_ID,
.getIpCount = ExampleIps_Count,
.getIpAt = ExampleIps_At,
};
struct SolidSyslogStructuredData* originSd = SolidSyslogOriginSd_Create(&originConfig);
struct SolidSyslogStructuredData* sdList[] = {originSd};
struct SolidSyslogStructuredData* sdList[] = {metaSd, originSd};

struct SolidSyslogConfig config = {
.buffer = buffer,
Expand All @@ -361,6 +373,9 @@ static void InteractiveTask(void* argument)

SolidSyslog_Destroy();
SolidSyslogOriginSd_Destroy();
SolidSyslogMetaSd_Destroy();
SolidSyslogAtomicCounter_Destroy();
SolidSyslogStdAtomicOps_Destroy();
SolidSyslogNullStore_Destroy();
SolidSyslogNullBuffer_Destroy();
SolidSyslogUdpSender_Destroy();
Expand Down
14 changes: 14 additions & 0 deletions Platform/FreeRtos/Interface/SolidSyslogFreeRtosSysUpTime.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#ifndef SOLIDSYSLOGFREERTOSSYSUPTIME_H
#define SOLIDSYSLOGFREERTOSSYSUPTIME_H

#include "ExternC.h"

#include <stdint.h>

EXTERN_C_BEGIN

uint32_t SolidSyslogFreeRtosSysUpTime_Get(void); // NOLINT(modernize-redundant-void-arg) -- C idiom

EXTERN_C_END

#endif /* SOLIDSYSLOGFREERTOSSYSUPTIME_H */
17 changes: 17 additions & 0 deletions Platform/FreeRtos/Source/SolidSyslogFreeRtosSysUpTime.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include "SolidSyslogFreeRtosSysUpTime.h"

#include "FreeRTOS.h"
#include "task.h"

enum
{
HUNDREDTHS_PER_SECOND = 100
};

uint32_t SolidSyslogFreeRtosSysUpTime_Get(void)
{
/* uint64 intermediate so the formula stays correct at any
* configTICK_RATE_HZ; the cast wraps per RFC 3418 TimeTicks. */
uint64_t hundredths = ((uint64_t) xTaskGetTickCount() * HUNDREDTHS_PER_SECOND) / configTICK_RATE_HZ;
return (uint32_t) hundredths;
}
25 changes: 25 additions & 0 deletions Tests/FreeRtos/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,31 @@ else()
add_test(NAME SolidSyslogFreeRtosStaticResolverTest COMMAND SolidSyslogFreeRtosStaticResolverTest)
endif()

# SolidSyslogFreeRtosSysUpTime — kernel-only adapter; needs FREERTOS_KERNEL_PATH
# but not Plus-TCP. Sits outside the Plus-TCP guard for the same reason the
# UART test does: a minimal kernel-only environment must still build it.
add_executable(SolidSyslogFreeRtosSysUpTimeTest
SolidSyslogFreeRtosSysUpTimeTest.cpp
main.cpp
${CMAKE_SOURCE_DIR}/Platform/FreeRtos/Source/SolidSyslogFreeRtosSysUpTime.c
${CMAKE_SOURCE_DIR}/Tests/Support/FreeRtosFakes/Source/FreeRtosTaskFake.c
)

target_link_libraries(SolidSyslogFreeRtosSysUpTimeTest PRIVATE
${PROJECT_NAME}
CppUTest
CppUTestExt
)

target_include_directories(SolidSyslogFreeRtosSysUpTimeTest PRIVATE
${CMAKE_SOURCE_DIR}/Platform/FreeRtos/Interface
${CMAKE_SOURCE_DIR}/Core/Interface
${CMAKE_SOURCE_DIR}/Tests/Support/FreeRtosFakes/Interface
$ENV{FREERTOS_KERNEL_PATH}/include
)

add_test(NAME SolidSyslogFreeRtosSysUpTimeTest COMMAND SolidSyslogFreeRtosSysUpTimeTest)

# CMSDK UART driver host tests — recompiles the driver source from the
# Example/FreeRtos/Common board glue against an in-memory fake register
# block. No FreeRTOS-Plus-TCP involvement, so the include path is intentionally
Expand Down
45 changes: 45 additions & 0 deletions Tests/FreeRtos/SolidSyslogFreeRtosSysUpTimeTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#include "CppUTest/TestHarness.h"

#include "FreeRtosTaskFake.h"
#include "SolidSyslogFreeRtosSysUpTime.h"

#include "FreeRTOS.h"

// clang-format off
TEST_GROUP(SolidSyslogFreeRtosSysUpTime)
{
void setup() override
{
FreeRtosTaskFake_Reset();
}
};

// clang-format on

TEST(SolidSyslogFreeRtosSysUpTime, ReturnsZeroWhenTicksAreZero)
{
FreeRtosTaskFake_SetTickCount(0);

UNSIGNED_LONGS_EQUAL(0U, SolidSyslogFreeRtosSysUpTime_Get());
}

TEST(SolidSyslogFreeRtosSysUpTime, ReturnsOneWhenTicksAreOne)
{
FreeRtosTaskFake_SetTickCount(1);

UNSIGNED_LONGS_EQUAL(1U, SolidSyslogFreeRtosSysUpTime_Get());
}

TEST(SolidSyslogFreeRtosSysUpTime, ReturnsTickCountAtMidRange)
{
FreeRtosTaskFake_SetTickCount(12345U);

UNSIGNED_LONGS_EQUAL(12345U, SolidSyslogFreeRtosSysUpTime_Get());
}

TEST(SolidSyslogFreeRtosSysUpTime, ReturnsUint32MaxWhenTicksAreUint32Max)
{
FreeRtosTaskFake_SetTickCount(UINT32_MAX);

UNSIGNED_LONGS_EQUAL(UINT32_MAX, SolidSyslogFreeRtosSysUpTime_Get());
}
3 changes: 3 additions & 0 deletions Tests/Support/FreeRtosFakes/Interface/FreeRtosTaskFake.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ EXTERN_C_BEGIN
unsigned FreeRtosTaskFake_VTaskDelayCallCount(void);
TickType_t FreeRtosTaskFake_LastVTaskDelayTicks(void);

/* xTaskGetTickCount stub */
void FreeRtosTaskFake_SetTickCount(TickType_t ticks);

EXTERN_C_END

#endif /* FREERTOSTASKFAKE_H */
12 changes: 12 additions & 0 deletions Tests/Support/FreeRtosFakes/Source/FreeRtosTaskFake.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

static unsigned vTaskDelayCallCount = 0;
static TickType_t lastVTaskDelayTicks = 0;
static TickType_t tickCount = 0;

void FreeRtosTaskFake_Reset(void)
{
vTaskDelayCallCount = 0;
lastVTaskDelayTicks = 0;
tickCount = 0;
}

unsigned FreeRtosTaskFake_VTaskDelayCallCount(void)
Expand All @@ -19,8 +21,18 @@ TickType_t FreeRtosTaskFake_LastVTaskDelayTicks(void)
return lastVTaskDelayTicks;
}

void FreeRtosTaskFake_SetTickCount(TickType_t ticks)
{
tickCount = ticks;
}

void vTaskDelay(const TickType_t xTicksToDelay)
{
++vTaskDelayCallCount;
lastVTaskDelayTicks = xTicksToDelay;
}

TickType_t xTaskGetTickCount(void)
{
return tickCount;
}
Loading