Skip to content

Commit 68c933f

Browse files
authored
PTP-P1.5: complete portable runtime and ESP control bridge
Complete the portable PTP publisher runtime/control layer, refactor ESP32-P4 into a hardware timestamp adapter, add runtime config/status APIs and full publisher profile controls, and preserve fail-safe smpSynch=0 pending PTP-P2 clock discipline evidence.
1 parent e7742eb commit 68c933f

9 files changed

Lines changed: 1466 additions & 238 deletions

File tree

‎.github/workflows/esp32p4-ptp-lab.yml‎

Lines changed: 40 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -36,42 +36,51 @@ jobs:
3636
- name: Select ESP32-P4 target
3737
run: source /opt/esp/idf/export.sh && idf.py set-target esp32p4
3838

39-
- name: Enable guarded non-default PTP lab profile
39+
- name: Enable guarded non-default PTP-P1.5 runtime profile
4040
shell: bash
4141
run: |
42-
if grep -q '^# CONFIG_AR_PTP_LAB_TX is not set$' sdkconfig; then
43-
sed -i 's/^# CONFIG_AR_PTP_LAB_TX is not set$/CONFIG_AR_PTP_LAB_TX=y/' sdkconfig
44-
elif ! grep -q '^CONFIG_AR_PTP_LAB_TX=y$' sdkconfig; then
45-
echo 'CONFIG_AR_PTP_LAB_TX=y' >> sdkconfig
46-
fi
42+
set_config() {
43+
local key="$1"
44+
local value="$2"
45+
if grep -q "^${key}=" sdkconfig; then
46+
sed -i "s|^${key}=.*|${key}=${value}|" sdkconfig
47+
elif grep -q "^# ${key} is not set$" sdkconfig && [ "$value" = "y" ]; then
48+
sed -i "s|^# ${key} is not set$|${key}=y|" sdkconfig
49+
else
50+
echo "${key}=${value}" >> sdkconfig
51+
fi
52+
}
4753
48-
if grep -q '^CONFIG_AR_PTP_TRANSPORT_SPECIFIC=' sdkconfig; then
49-
sed -i 's/^CONFIG_AR_PTP_TRANSPORT_SPECIFIC=.*/CONFIG_AR_PTP_TRANSPORT_SPECIFIC=1/' sdkconfig
50-
else
51-
echo 'CONFIG_AR_PTP_TRANSPORT_SPECIFIC=1' >> sdkconfig
52-
fi
53-
54-
if grep -q '^# CONFIG_AR_PTP_VLAN is not set$' sdkconfig; then
55-
sed -i 's/^# CONFIG_AR_PTP_VLAN is not set$/CONFIG_AR_PTP_VLAN=y/' sdkconfig
56-
elif ! grep -q '^CONFIG_AR_PTP_VLAN=y$' sdkconfig; then
57-
echo 'CONFIG_AR_PTP_VLAN=y' >> sdkconfig
58-
fi
59-
60-
if grep -q '^CONFIG_AR_PTP_VLAN_ID=' sdkconfig; then
61-
sed -i 's/^CONFIG_AR_PTP_VLAN_ID=.*/CONFIG_AR_PTP_VLAN_ID=100/' sdkconfig
62-
else
63-
echo 'CONFIG_AR_PTP_VLAN_ID=100' >> sdkconfig
64-
fi
65-
66-
if grep -q '^CONFIG_AR_PTP_VLAN_PRIORITY=' sdkconfig; then
67-
sed -i 's/^CONFIG_AR_PTP_VLAN_PRIORITY=.*/CONFIG_AR_PTP_VLAN_PRIORITY=4/' sdkconfig
68-
else
69-
echo 'CONFIG_AR_PTP_VLAN_PRIORITY=4' >> sdkconfig
70-
fi
54+
set_config CONFIG_AR_PTP_LAB_TX y
55+
set_config CONFIG_AR_PTP_DOMAIN 0
56+
set_config CONFIG_AR_PTP_TRANSPORT_SPECIFIC 1
57+
set_config CONFIG_AR_PTP_PORT_NUMBER 2
58+
set_config CONFIG_AR_PTP_VLAN y
59+
set_config CONFIG_AR_PTP_VLAN_ID 100
60+
set_config CONFIG_AR_PTP_VLAN_PRIORITY 4
61+
set_config CONFIG_AR_PTP_ANNOUNCE_INTERVAL_MS 1000
62+
set_config CONFIG_AR_PTP_SYNC_INTERVAL_MS 250
63+
set_config CONFIG_AR_PTP_RESPOND_PDELAY y
64+
set_config CONFIG_AR_PTP_PRIORITY1 120
65+
set_config CONFIG_AR_PTP_PRIORITY2 121
66+
set_config CONFIG_AR_PTP_CLOCK_CLASS 248
67+
set_config CONFIG_AR_PTP_CLOCK_ACCURACY 254
68+
set_config CONFIG_AR_PTP_OFFSET_SCALED_LOG_VARIANCE 65535
69+
set_config CONFIG_AR_PTP_TIME_SOURCE 160
70+
set_config CONFIG_AR_PTP_CURRENT_UTC_OFFSET 37
7171
7272
source /opt/esp/idf/export.sh
7373
idf.py reconfigure
74-
grep -E '^CONFIG_AR_PTP_(LAB_TX|DOMAIN|TRANSPORT_SPECIFIC|VLAN|VLAN_ID|VLAN_PRIORITY|ANNOUNCE_INTERVAL_MS|SYNC_INTERVAL_MS)=' sdkconfig
7574
76-
- name: Build PTP-enabled firmware
75+
grep -E '^CONFIG_AR_PTP_(LAB_TX|DOMAIN|TRANSPORT_SPECIFIC|PORT_NUMBER|VLAN|VLAN_ID|VLAN_PRIORITY|ANNOUNCE_INTERVAL_MS|SYNC_INTERVAL_MS|RESPOND_PDELAY|PRIORITY1|PRIORITY2|CLOCK_CLASS|CLOCK_ACCURACY|OFFSET_SCALED_LOG_VARIANCE|TIME_SOURCE|CURRENT_UTC_OFFSET)=' sdkconfig
76+
77+
grep -q '^CONFIG_AR_PTP_LAB_TX=y$' sdkconfig
78+
grep -q '^CONFIG_AR_PTP_TRANSPORT_SPECIFIC=1$' sdkconfig
79+
grep -q '^CONFIG_AR_PTP_PORT_NUMBER=2$' sdkconfig
80+
grep -q '^CONFIG_AR_PTP_VLAN_ID=100$' sdkconfig
81+
grep -q '^CONFIG_AR_PTP_PRIORITY1=120$' sdkconfig
82+
grep -q '^CONFIG_AR_PTP_PRIORITY2=121$' sdkconfig
83+
grep -q '^CONFIG_AR_PTP_RESPOND_PDELAY=y$' sdkconfig
84+
85+
- name: Build PTP-P1.5 enabled firmware
7786
run: source /opt/esp/idf/export.sh && idf.py build

‎.github/workflows/ptp-core-ci.yml‎

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ on:
1010
- 'src/capture/pcap.cpp'
1111
- 'tools/ptp_analyze.cpp'
1212
- 'tests/test_ptp.cpp'
13+
- 'tests/test_ptp_runtime.cpp'
1314
- 'tests/ptp_profile/**'
1415
- '.github/workflows/ptp-core-ci.yml'
1516
pull_request:
@@ -21,6 +22,7 @@ on:
2122
- 'src/capture/pcap.cpp'
2223
- 'tools/ptp_analyze.cpp'
2324
- 'tests/test_ptp.cpp'
25+
- 'tests/test_ptp_runtime.cpp'
2426
- 'tests/ptp_profile/**'
2527
- '.github/workflows/ptp-core-ci.yml'
2628

@@ -59,36 +61,54 @@ jobs:
5961
tests/test_ptp.cpp \
6062
-o ptp-core-tests \
6163
>ptp-build.log 2>&1
62-
status=$?
64+
core_status=$?
65+
66+
"$CXX" \
67+
-std=c++20 \
68+
-Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Werror \
69+
-pthread \
70+
-Iinclude \
71+
src/ethernet/ethernet.cpp \
72+
src/time_sync/ptp.cpp \
73+
tests/test_ptp_runtime.cpp \
74+
-o ptp-runtime-tests \
75+
>ptp-runtime-build.log 2>&1
76+
runtime_status=$?
6377
set -e
6478
6579
cat ptp-build.log
66-
if [ "$status" -ne 0 ]; then
67-
grep -Ei 'error:|fatal error:|undefined reference|collect2: error|ld: error' ptp-build.log | while IFS= read -r line; do
80+
cat ptp-runtime-build.log
81+
if [ "$core_status" -ne 0 ] || [ "$runtime_status" -ne 0 ]; then
82+
cat ptp-build.log ptp-runtime-build.log | grep -Ei 'error:|fatal error:|undefined reference|collect2: error|ld: error' | while IFS= read -r line; do
6883
escaped=${line//'%'/'%25'}
6984
escaped=${escaped//$'\r'/'%0D'}
7085
escaped=${escaped//$'\n'/'%0A'}
7186
echo "::error::$escaped"
7287
done || true
73-
exit "$status"
88+
[ "$core_status" -ne 0 ] && exit "$core_status"
89+
exit "$runtime_status"
7490
fi
7591
7692
- name: Run PTP regression tests
7793
shell: bash
7894
run: |
7995
set +e
8096
./ptp-core-tests >ptp-test.log 2>&1
81-
status=$?
97+
core_status=$?
98+
./ptp-runtime-tests >ptp-runtime-test.log 2>&1
99+
runtime_status=$?
82100
set -e
83101
cat ptp-test.log
84-
if [ "$status" -ne 0 ]; then
85-
grep -E '\[FAIL\]|CHECK failed|error' ptp-test.log | while IFS= read -r line; do
102+
cat ptp-runtime-test.log
103+
if [ "$core_status" -ne 0 ] || [ "$runtime_status" -ne 0 ]; then
104+
cat ptp-test.log ptp-runtime-test.log | grep -E '\[FAIL\]|CHECK failed|error' | while IFS= read -r line; do
86105
escaped=${line//'%'/'%25'}
87106
escaped=${escaped//$'\r'/'%0D'}
88107
escaped=${escaped//$'\n'/'%0A'}
89108
echo "::error::$escaped"
90109
done || true
91-
exit "$status"
110+
[ "$core_status" -ne 0 ] && exit "$core_status"
111+
exit "$runtime_status"
92112
fi
93113
94114
portable-ptp-msvc:
@@ -127,6 +147,7 @@ jobs:
127147
128148
Build-Target 'ptp_profile_core'
129149
Build-Target 'ptp_profile_tests'
150+
Build-Target 'ptp_runtime_tests'
130151
Build-Target 'ptp_profile_analyze'
131152
132153
- name: Run PTP regression and analyzer smoke tests on MSVC

‎docs/PTP_RUNTIME_P1_5.md‎

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
# PTP-P1.5 Runtime Completion
2+
3+
PTP-P1.5 turns the PTP-P1 wire engine into a reusable runtime/control layer while preserving the ESP32-P4 hardware timestamp path.
4+
5+
This remains a laboratory timing companion for troubleshooting and interoperability. It is not a GPS-backed clock, a certified grandmaster, or a formal IEC/IEEE 61850-9-3 conformance claim.
6+
7+
## Portable runtime
8+
9+
`include/ariec61850/time_sync/ptp_runtime.hpp` provides a platform-neutral PTP publisher runtime on top of the existing codec.
10+
11+
The runtime owns:
12+
13+
- publisher profile/configuration
14+
- ClockIdentity parse/format and EUI-64-style MAC derivation
15+
- lifecycle (`start`, `stop`, stopped-only `reconfigure`)
16+
- Announce/Sync due scheduling
17+
- per-message sequence counters
18+
- Announce, Sync, Follow_Up, Pdelay_Resp and Pdelay_Resp_Follow_Up frame preparation
19+
- publisher status and send/error accounting
20+
21+
The runtime intentionally does not own:
22+
23+
- an operating-system thread
24+
- a NIC or transport driver
25+
- a PTP clock servo
26+
- absolute UTC traceability
27+
- lock/holdover state
28+
- `smpSynch` promotion
29+
30+
Those boundaries keep the core portable across desktop, embedded and analyzer applications.
31+
32+
## Portable publisher options
33+
34+
`PtpPublisherOptions` covers the relevant ARIEC61850 publisher profile:
35+
36+
- `transport_specific`
37+
- `domain_number`
38+
- source MAC
39+
- optional VLAN ID / PCP
40+
- ClockIdentity and port number
41+
- Announce / Sync intervals
42+
- two-step policy
43+
- peer-delay response policy
44+
- priority1 / priority2
45+
- clockClass / clockAccuracy
46+
- offsetScaledLogVariance
47+
- timeSource
48+
- currentUtcOffset
49+
- stepsRemoved
50+
51+
Reconfiguration is deliberately rejected while the runtime is running. A control plane must perform a safe `stop -> reconfigure -> start` transaction instead of mutating live publisher state.
52+
53+
## Publisher status
54+
55+
`PtpPublisherStatus` exposes:
56+
57+
- running state
58+
- start time
59+
- last send time
60+
- Announce sent
61+
- Sync sent
62+
- Follow_Up sent
63+
- peer-delay response frames sent
64+
- last runtime error
65+
66+
This is the reusable status contract for future GUI and analyzer integrations.
67+
68+
## ESP32-P4 hardware adapter
69+
70+
`embedded/esp32p4_smv_injector/main/ptp_lab_task.cpp` is now an adapter around `PtpPublisherRuntime` rather than a second PTP runtime implementation.
71+
72+
The adapter remains responsible only for ESP-specific work:
73+
74+
- FreeRTOS task scheduling on CPU0, separate from the realtime SV task
75+
- ESP-IDF Ethernet transport
76+
- enabling the ESP32-P4 IEEE1588 hardware clock
77+
- hardware TX descriptor timestamp capture for Sync and Pdelay_Resp
78+
- hardware RX descriptor timestamp capture for Pdelay_Req
79+
- RX queueing and task notification
80+
81+
Two-step timestamp evidence remains:
82+
83+
- Sync carries zero originTimestamp
84+
- actual Sync hardware TX timestamp becomes Follow_Up preciseOriginTimestamp
85+
- Pdelay_Req hardware RX timestamp becomes Pdelay_Resp requestReceiptTimestamp (`t2`)
86+
- Pdelay_Resp hardware TX timestamp becomes Pdelay_Resp_Follow_Up responseOriginTimestamp (`t3`)
87+
88+
The hardware implementation therefore remains stronger than the original desktop ARIEC61850 software-timestamped publisher.
89+
90+
## ESP runtime control bridge
91+
92+
The C-compatible adapter API is designed so a future GUI, USB/RPC control task, or embedded application can control PTP without recompiling the PTP core.
93+
94+
Available operations:
95+
96+
- `ar_ptp_lab_get_default_config`
97+
- `ar_ptp_lab_configure`
98+
- `ar_ptp_lab_get_config`
99+
- `ar_ptp_lab_start`
100+
- `ar_ptp_lab_stop`
101+
- `ar_ptp_lab_is_running`
102+
- `ar_ptp_lab_get_status`
103+
104+
Runtime configuration is accepted only while PTP is stopped. The live status bridge exposes lock-free counters for Announce, Sync, Follow_Up, peer-delay response frames and TX failures.
105+
106+
Kconfig remains the firmware default profile. A runtime configuration override can replace it before the task is started.
107+
108+
## ESP Kconfig defaults
109+
110+
The ESP32-P4 profile now exposes:
111+
112+
- PTP enable
113+
- domain
114+
- transportSpecific
115+
- optional ClockIdentity override
116+
- port number
117+
- optional VLAN / VID / PCP
118+
- Announce interval
119+
- Sync interval
120+
- Pdelay response enable
121+
- priority1 / priority2
122+
- clockClass
123+
- clockAccuracy
124+
- offsetScaledLogVariance
125+
- timeSource
126+
- currentUtcOffset
127+
128+
Defaults remain intentionally conservative: clockClass 248, clockAccuracy Unknown, variance `0xFFFF`, timeSource Internal Oscillator.
129+
130+
## Validation
131+
132+
PTP-P1.5 has dedicated portable regression coverage for:
133+
134+
- ClockIdentity parsing/formatting
135+
- profile validation
136+
- stopped-only reconfiguration
137+
- due scheduling
138+
- per-message sequence behavior
139+
- status accounting
140+
- two-step Sync/Follow_Up
141+
- one-step suppression of Follow_Up
142+
- Pdelay request sequence/log interval preservation
143+
- supplied `t2` / `t3` timestamp placement
144+
145+
The strict PTP profile is built on GCC, Clang and MSVC with warnings treated as errors. The ESP workflow builds a non-default PTP profile on ESP-IDF 5.5.4, while the normal ESP32-P4 SMV firmware build verifies that PTP remains default-off and does not regress the injector.
146+
147+
## Safety boundary
148+
149+
PTP-P1.5 does **not** change Sampled Values synchronization claims. The generic SV default remains `smpSynch=0`, and the ESP injector must not promote it merely because PTP frames are being transmitted or observed.
150+
151+
Promotion to `smpSynch=1/2` belongs to PTP-P2 after measured clock discipline, offset/delay qualification, lock/holdover state, and explicit policy evidence exist.

0 commit comments

Comments
 (0)