This repository contains the native macOS driver and Control Center for the OCP Time Card. It uses PCIDriverKit, packages the driver in a SwiftUI monitoring app, and provides a small command-line diagnostic client.
The current implementation provides:
- Exact PCI matching and board profiles for:
- Meta/Facebook Time Card (
1d9b:0400) - Celestica R4006 (
18d4:1008) - Orolia/Safran ART (
1ad7:a000) - upstream Linux ADVA Time Card (
ad5a:0400) - upstream Linux ADVA Time Card X1 (
ad5a:0410)
- Meta/Facebook Time Card (
- BAR0 discovery and per-profile bounds checking
- PCI-revision and MSI-X-signature selection of the classic and repository LitePCIe shifted maps
- Fixed ART and ADVA common-clock resource-map handling
- PHC time read and set operations
- Bracketed card/system cross timestamps
- Version-gated clock and TOD status reads
- Capability and field-validity reporting for absent or gated registers
- A versioned, size-checked user-client ABI v2
- A native SwiftUI Control Center with:
- driver activation, update, and removal
- live card discovery and explicit multi-card selection
- PCI identity, board profile, register-map, BAR, and capability views
- raw card time, clock status, ToD status, and cross-timestamp telemetry
- a rolling bracketed sampling-window chart
- clear user-client entitlement and restart diagnostics
timecardctlcommands forstatus,get, andset-card-from-system
The common PHC block is available on every matched profile. ART uses its own fixed layout and has no standard TOD block, so the driver never reads one. ADVA profiles use the fixed common clock/TOD addresses published by current upstream Linux, independent of their interrupt capability. The UTC, leap, GNSS, and satellite telemetry registers are synthesis-optional. They remain untouched until a future exact-image contract can prove that a specific FPGA image implements them.
Current upstream Linux defines the classic Meta/Celestica map and the fixed ART and ADVA maps. The shifted revision-02 map comes from this repository's LitePCIe gateware and Windows/Linux support; it is not currently in upstream Linux. The Meta/Facebook classic profile is hardware-validated on an Intel Mac Pro. Every other profile is covered by host-side layout and safety tests but still requires physical-card validation before a production release. Celestica cards programmed with the generic Meta PCI identity continue to receive safe common-PHC support, but board-specific R4006 identification will require the future EEPROM/I2C work.
App/ SwiftUI Control Center and driver lifecycle manager
CLI/ timecardctl diagnostic client, packaged as a macOS app
Driver/ PCIDriverKit extension and user client
Shared/ Stable C ABI and hardware register definitions
Tests/ Register-map, safety, bundle, and Swift model tests
Run the portable driver tests, build the CLI, and run the Swift Control Center model tests:
make checkOn macOS, CMake places the executable in the unsigned wrapper at
.build/cmake/timecardctl.app/Contents/MacOS/timecardctl. The wrapper gives
the diagnostic client a bundle identifier and a place for its development
provisioning profile.
Build the same unsigned CLI app with Xcode:
xcodebuild \
-project TimeCardMacOS.xcodeproj \
-scheme timecardctl \
-configuration Debug \
-derivedDataPath .build/xcode-cli \
ARCHS=x86_64 \
ONLY_ACTIVE_ARCH=NO \
CODE_SIGNING_ALLOWED=NO \
buildThe equivalent convenience command for the Intel Mac Pro build is
make build-cli-app ARCHS=x86_64.
Compile the complete app and DriverKit extension without installing them:
xcodebuild \
-project TimeCardMacOS.xcodeproj \
-scheme TimeCardMacOS \
-configuration Debug \
-derivedDataPath .build/xcode-app \
ARCHS=x86_64 \
ONLY_ACTIVE_ARCH=NO \
CODE_SIGNING_ALLOWED=NO \
buildThe equivalent convenience command for the Intel Mac Pro build is
make build-app ARCHS=x86_64. It also checks that the embedded extension is
named org.opentimeserver.timecard.macos.driver.dext. DriverKit requires the
DEXT filename, without the .dext suffix, to exactly match its bundle
identifier.
An unsigned build validates the Swift, C, C++, IIG, linking, plist, and bundle layout. It cannot activate the system extension.
Before installing the driver, configure one Apple development team for all three targets and request these capabilities from Apple:
- DriverKit
- DriverKit PCI Transport
- System Extension installation
- DriverKit user-client access
For macOS clients, request
com.apple.developer.driverkit.userclient-access through Apple's System
Extension or DriverKit entitlement form. Set UserClient Bundle IDs to
org.opentimeserver.timecard.macos.driver. The portal capability named
DriverKit Communicates with Drivers is for iPadOS and does not authorize
the macOS user-client entitlement. A development host can activate and bind
the DEXT without user-client access, but client commands cannot open the
DriverKit user client until Apple grants it and replacement profiles include
the entitlement.
The development DriverKit PCI profile authorizes Apple's wildcard
IOPCIPrimaryMatch value. Use that value only in development signing
entitlements. Driver/Info.plist remains restricted to the supported Time
Card PCI identifiers at runtime.
A distribution DriverKit profile must authorize every PCI primary match that will ship. Keep the entitlement and runtime personality synchronized with this exact list:
0x04001d9b 0x100818d4 0xa0001ad7 0x0400ad5a 0x0410ad5a
The build tests extract and compare the single IOPCIPrimaryMatch value in
each file against the canonical match set in Shared/TimeCardRegisters.h.
Extra matches, wildcards, and missing values fail the test. Using the primary
match key also prevents subsystem IDs with the same encoded value from entering
the runtime match set.
The configured identifiers are:
org.opentimeserver.timecard.macos
org.opentimeserver.timecard.macos.driver
org.opentimeserver.timecard.macos.cli
Change them consistently if the approved App IDs use a different prefix.
The signed CLI bundle uses CLI/timecardctl.entitlements; place its matching
development provisioning profile at
timecardctl.app/Contents/embedded.provisionprofile before signing.
- Verify the card and gateware on Linux using
ptp_ocp. - Install the card in a Mac Pro or a compatible Thunderbolt PCIe chassis.
- Confirm that macOS enumerates the expected PCI vendor and device ID.
- Build and activate the signed host app.
- Approve the extension in System Settings if prompted.
- Confirm activation with
systemextensionsctl list. - Open the Control Center and verify that the Overview, Precision Clock, and Hardware pages show the selected card.
- Run
timecardctl.app/Contents/MacOS/timecardctl status, followed by the same executable withget. - Compare the reported card time, core versions, and available status fields with the Linux reference setup.
Do not use set-card-from-system until read-only status and time access have
been validated on the target card. This command copies raw macOS
CLOCK_REALTIME seconds into the card. It does not set the macOS system clock,
and it does not yet apply a UTC/TAI correction.
- Cross timestamps currently bracket the MMIO clock read with macOS realtime samples. PCIe PTM support is not implemented.
- UARTs, PPS interrupts, external timestamp inputs, SMA routing, I2C, SPI flash, frequency counters, and signal generators are not implemented.
- Optional UTC, leap, GNSS, and satellite registers are deliberately gated until an exact per-card FPGA image contract is implemented.
- The Control Center labels card time as raw and does not calculate a card to macOS offset until the driver exposes a trusted UTC-to-TAI contract.
- The driver does not create a Linux-style
/dev/ptpNdevice. - No daemon currently disciplines the macOS system clock.
timecardctlrefuses ambiguous access when multiple cards are present; explicit per-card selection is not implemented yet.- Sleep, wake, Thunderbolt disconnect, all non-Meta profiles, and multiple-card behavior require physical hardware testing.
See ROADMAP.md for the staged implementation plan.