Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
e6ff785
feat: add sbp2 address space manager and userclient selectors
gly11 Feb 13, 2026
04748c8
feat: add async read response sender and packet routing for sbp2
gly11 Feb 13, 2026
bd72eea
fix: use full generation for async tx response matching
gly11 Feb 13, 2026
6d9d754
fix: normalize OHCI ACK semantics and handle OUTPUT_MORE precursors f…
gly11 Mar 20, 2026
92a7c29
Merge remote-tracking branch 'origin/main' into feature/sbp2-e2e-asfw
gly11 Apr 13, 2026
46ff416
feat: wire EnsureSbp2Deps into driver startup flow
gly11 Apr 13, 2026
11f972f
fix: correct SBP2 wiring in EnsureSbp2Deps and add Swift SBP2 API
gly11 Apr 13, 2026
47f70e0
debug: add nikon bring-up diagnostics
gly11 Apr 15, 2026
e37f682
fix: isolate nikon bring-up from shipped defaults
gly11 Apr 15, 2026
4440622
fix: always enable PHY contender bit to match Linux/Apple defaults
gly11 Apr 15, 2026
5fd1149
fix: make driver status text copyable in overview
gly11 Apr 21, 2026
778ceea
feat(sbp2): add wire formats and login state machine
gly11 Apr 21, 2026
a5c8837
fix(sbp2): fix status FIFO addressing, login timing, and wire up time…
gly11 Apr 22, 2026
e32fd63
feat(sbp2): add ORB submission, page table, and fetch agent infrastru…
gly11 Apr 22, 2026
9bd36ff
chore: remove backup files and stale fixlog script
gly11 Apr 22, 2026
9298911
fix(async): use generation16 instead of generation8 for bus generation
gly11 Apr 22, 2026
52da8b1
fix: re-assert cycleMaster after cycleTooLong and bus reset, implemen…
gly11 Apr 22, 2026
6dcd358
feat(diagnostics): add DiagnosticsHandler for bus state, PHY, and bus…
gly11 Apr 22, 2026
284104d
Merge remote-tracking branch 'origin/main' into feature/sbp2-e2e-asfw
gly11 Apr 22, 2026
5f732e8
feat(sbp2): add management ORB, fetch agent reset, unsolicited status…
gly11 Apr 22, 2026
923a951
docs(sbp2): add SBP-2 development roadmap with current progress
gly11 Apr 22, 2026
60936a7
Fix SBP-2 session allocation and timer handling
gly11 Apr 22, 2026
35b6711
fix(sbp2): make inProgress_/timerActive_ atomic to eliminate data races
gly11 Apr 22, 2026
21d4b0c
feat(sbp2): complete INQUIRY debug flow
gly11 Apr 22, 2026
e363b8c
docs(sbp2): 更新路线图状态
gly11 Apr 22, 2026
e0d5431
feat: Implement SBP-2 command handling and metadata structures
gly11 Apr 22, 2026
1225219
fix: probe Nikon root directory after minimal ROM
gly11 Apr 22, 2026
77448d9
fix: recognize SBP-2 units by spec and sw version
gly11 Apr 22, 2026
4bb5dd4
fix(sbp2): update test callbacks to match SBP2CommandORB two-paramete…
gly11 Apr 22, 2026
639c4c8
chore(debug): improve debug install workflow
gly11 Apr 22, 2026
afb869c
docs(sbp2): record Nikon smoke blockers
gly11 Apr 22, 2026
98b52a0
fix(sbp2): correct Management_Agent_Offset key, AR DMA byte order, an…
gly11 Apr 22, 2026
0d4b330
fix(sbp2): fix pre-login path for scanner-first SBP-2 bring-up
gly11 Apr 23, 2026
e20f165
fix(sbp2): replace blocking delays and harden async lifetimes
gly11 Apr 23, 2026
69d2c10
fix(sbp2): fix orb layout and tighten submit validation
gly11 Apr 23, 2026
36d0cb6
test(sbp2): add orb failure-path regression coverage
gly11 Apr 23, 2026
76d37aa
fix(sbp2): eliminate timer callback lifetime races
gly11 Apr 23, 2026
74260f0
feat(sbp2): add debug labels for address space management and enhance…
gly11 Apr 24, 2026
0594248
feat(nikon): add Nikon 4000ED diagnostic slice script and documentation
gly11 Apr 24, 2026
0c949c0
feat(tests): add unit tests for TransactionStorage and DiscoveryConve…
gly11 Apr 24, 2026
e0422c3
fix(install): enhance cleanup logic for ASFW system extensions during…
gly11 Apr 24, 2026
beb3710
feat(diagnostics): enhance bus reset diagnostics with detailed recove…
gly11 Apr 24, 2026
aed77c6
feat(sbp2): add SBP-2 unit detection and enhance ConfigROM logging fo…
gly11 Apr 24, 2026
62084b8
merge: sync main into feature/sbp2-e2e-asfw
gly11 Apr 30, 2026
db0d3d6
merge: sync main (PR #10 SBP-2 ORB primitives) into feature/sbp2-e2e-…
gly11 May 6, 2026
f7e2cf4
chore: remove local debug artifacts and internal docs from PR
gly11 May 6, 2026
13e3527
fix: remove duplicate SBP2 facade definitions from merge conflict
gly11 May 6, 2026
51a900e
fix: remove duplicate CMake test targets from merge conflict
gly11 May 6, 2026
362adc8
fix(swift): resolve Swift 6 concurrency errors in MetricsView and Deb…
gly11 May 6, 2026
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: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ Plugins/VersionGeneratorPlugin
# LLM Tools

.claude/
.zread/
opencode.json

# Xcode per-user state
Expand Down
24 changes: 15 additions & 9 deletions ASFW.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
3A1693F02E808765000BD368 /* DriverKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A1693EF2E808765000BD368 /* DriverKit.framework */; };
3A1693F92E808765000BD368 /* net.mrmidi.ASFW.ASFWDriver.dext in Embed System Extensions */ = {isa = PBXBuildFile; fileRef = 3A1693ED2E808765000BD368 /* net.mrmidi.ASFW.ASFWDriver.dext */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
3A1694002E8087BD000BD368 /* PCIDriverKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A1693FF2E8087BD000BD368 /* PCIDriverKit.framework */; };
3A27C5302ECDE045009CA664 /* bump.sh in Resources */ = {isa = PBXBuildFile; fileRef = 3A27C52E2ECDE045009CA664 /* bump.sh */; };
3A27C5322ECDE045009CA664 /* bump.sh in Resources */ = {isa = PBXBuildFile; fileRef = 3A27C52E2ECDE045009CA664 /* bump.sh */; };
3ABA31132EF8564A0046405D /* AudioDriverKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3ABA31122EF8564A0046405D /* AudioDriverKit.framework */; };
/* End PBXBuildFile section */

Expand Down Expand Up @@ -51,7 +49,6 @@
3A1693ED2E808765000BD368 /* net.mrmidi.ASFW.ASFWDriver.dext */ = {isa = PBXFileReference; explicitFileType = "wrapper.driver-extension"; includeInIndex = 0; path = net.mrmidi.ASFW.ASFWDriver.dext; sourceTree = BUILT_PRODUCTS_DIR; };
3A1693EF2E808765000BD368 /* DriverKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DriverKit.framework; path = System/Library/Frameworks/DriverKit.framework; sourceTree = SDKROOT; };
3A1693FF2E8087BD000BD368 /* PCIDriverKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PCIDriverKit.framework; path = Platforms/DriverKit.platform/Developer/SDKs/DriverKit25.0.sdk/System/DriverKit/System/Library/Frameworks/PCIDriverKit.framework; sourceTree = DEVELOPER_DIR; };
3A27C52E2ECDE045009CA664 /* bump.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = bump.sh; sourceTree = "<group>"; };
3AB4713F2EE31CF0003A4E2A /* ASFWTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ASFWTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3AB471482EE31E7A003A4E2A /* ASFW.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = ASFW.xctestplan; sourceTree = "<group>"; };
3ABA31122EF8564A0046405D /* AudioDriverKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioDriverKit.framework; path = Platforms/DriverKit.platform/Developer/SDKs/DriverKit25.1.sdk/System/DriverKit/System/Library/Frameworks/AudioDriverKit.framework; sourceTree = DEVELOPER_DIR; };
Expand Down Expand Up @@ -129,7 +126,6 @@
3A1693D92E808727000BD368 /* Products */,
ASFWAPPENTITLEMENTS /* App.entitlements */,
ASFWDRIVERENTITLEMENTS /* ASFWDriver.entitlements */,
3A27C52E2ECDE045009CA664 /* bump.sh */,
);
sourceTree = "<group>";
};
Expand Down Expand Up @@ -283,15 +279,13 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
3A27C5302ECDE045009CA664 /* bump.sh in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
3A1693EB2E808765000BD368 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
3A27C5322ECDE045009CA664 /* bump.sh in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -339,7 +333,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "ls ${SRCROOT}\n$SRCROOT/bump.sh\n";
shellScript = "\"${SRCROOT}/bump.sh\" refresh\n";
};
/* End PBXShellScriptBuildPhase section */

Expand Down Expand Up @@ -584,7 +578,13 @@
DEVELOPMENT_TEAM = F6YA6B56LR;
DRIVERKIT_DEPLOYMENT_TARGET = 25.0;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
EXCLUDED_SOURCE_FILE_NAMES = "*.md";
EXCLUDED_SOURCE_FILE_NAMES = (
"*.md",
"*.bak",
"*.bak2",
"*.sh",
"*.txt",
);
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(SDKROOT)/System/DriverKit/System/Library/Frameworks",
Expand Down Expand Up @@ -618,7 +618,13 @@
DEVELOPMENT_TEAM = F6YA6B56LR;
DRIVERKIT_DEPLOYMENT_TARGET = 25.0;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
EXCLUDED_SOURCE_FILE_NAMES = "*.md";
EXCLUDED_SOURCE_FILE_NAMES = (
"*.md",
"*.bak",
"*.bak2",
"*.sh",
"*.txt",
);
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(SDKROOT)/System/DriverKit/System/Library/Frameworks",
Expand Down
5 changes: 4 additions & 1 deletion ASFW/ASFWApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@
//

import SwiftUI

@main
struct ASFWApp: App {
private let autoActivateDriverOnLaunch = ProcessInfo.processInfo.arguments.contains("--activate-driver")

var body: some Scene {
WindowGroup {
ModernContentView()
ModernContentView(autoActivateDriverOnLaunch: autoActivateDriverOnLaunch)
}
.defaultSize(width: 1000, height: 700)
}
Expand Down
16 changes: 15 additions & 1 deletion ASFW/ASFWDriverConnector.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,20 @@ final class ASFWDriverConnector: ObservableObject {
case setIsochTxVerifier = 41
case asyncBlockRead = 44
case asyncBlockWrite = 45
// SBP2 address space management
case allocateAddressRange = 46
case deallocateAddressRange = 47
case readIncomingData = 48
case writeLocalData = 49
// SBP-2 session management
case createSBP2Session = 53
case startSBP2Login = 54
case getSBP2SessionState = 55
case submitSBP2Inquiry = 56
case getSBP2InquiryResult = 57
case releaseSBP2Session = 58
case submitSBP2Command = 59
case getSBP2CommandResult = 60
}

// MARK: - Re-exported Models
Expand Down Expand Up @@ -210,4 +224,4 @@ final class ASFWDriverConnector: ObservableObject {
}

}


95 changes: 62 additions & 33 deletions ASFW/DriverConnector+Discovery.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,42 @@ extension ASFWDriverConnector {
print("[Connector] 📦 Received \(wireData.count) bytes of wire format data")

// Parse wire format
return parseDeviceDiscoveryWire(wireData)
return Self.parseDeviceDiscoveryWire(wireData)
}

/// Parse wire format data from driver
private func parseDeviceDiscoveryWire(_ data: Data) -> [FWDeviceInfo]? {
static func parseDeviceDiscoveryWire(_ data: Data) -> [FWDeviceInfo]? {
@inline(__always)
func readUInt8(at offset: Int) -> UInt8 {
data[data.startIndex + offset]
}

@inline(__always)
func readUInt32(at offset: Int) -> UInt32 {
var value: UInt32 = 0
for i in 0..<4 {
value |= UInt32(data[data.startIndex + offset + i]) << (i * 8)
}
return value
}

@inline(__always)
func readUInt64(at offset: Int) -> UInt64 {
var value: UInt64 = 0
for i in 0..<8 {
value |= UInt64(data[data.startIndex + offset + i]) << (i * 8)
}
return value
}

func readCString(at offset: Int, length: Int) -> String {
let start = data.startIndex + offset
let end = start + length
let bytes = data[start..<end]
let trimmed = bytes.prefix { $0 != 0 }
return String(decoding: trimmed, as: UTF8.self)
}

var offset = 0

// Read header
Expand All @@ -36,7 +67,7 @@ extension ASFWDriverConnector {
return nil
}

let deviceCount = data.withUnsafeBytes { $0.load(fromByteOffset: offset, as: UInt32.self) }
let deviceCount = readUInt32(at: offset)
offset += 8 // deviceCount + padding

print("[Connector] 📋 Device count: \(deviceCount)")
Expand All @@ -50,21 +81,16 @@ extension ASFWDriverConnector {
return nil
}

let guid = data.withUnsafeBytes { $0.load(fromByteOffset: offset, as: UInt64.self) }
let vendorId = data.withUnsafeBytes { $0.load(fromByteOffset: offset + 8, as: UInt32.self) }
let modelId = data.withUnsafeBytes { $0.load(fromByteOffset: offset + 12, as: UInt32.self) }
let generation = data.withUnsafeBytes { $0.load(fromByteOffset: offset + 16, as: UInt32.self) }
let nodeId = data.withUnsafeBytes { $0.load(fromByteOffset: offset + 20, as: UInt8.self) }
let stateRaw = data.withUnsafeBytes { $0.load(fromByteOffset: offset + 21, as: UInt8.self) }
let unitCount = data.withUnsafeBytes { $0.load(fromByteOffset: offset + 22, as: UInt8.self) }

// Read vendor name (64 bytes at offset 24)
let vendorNameData = data.subdata(in: (offset + 24)..<(offset + 88))
let vendorName = String(cString: vendorNameData.withUnsafeBytes { $0.bindMemory(to: CChar.self).baseAddress! })

// Read model name (64 bytes at offset 88)
let modelNameData = data.subdata(in: (offset + 88)..<(offset + 152))
let modelName = String(cString: modelNameData.withUnsafeBytes { $0.bindMemory(to: CChar.self).baseAddress! })
let guid = readUInt64(at: offset)
let vendorId = readUInt32(at: offset + 8)
let modelId = readUInt32(at: offset + 12)
let generation = readUInt32(at: offset + 16)
let nodeId = readUInt8(at: offset + 20)
let stateRaw = readUInt8(at: offset + 21)
let unitCount = readUInt8(at: offset + 22)
let deviceKind = readUInt8(at: offset + 23)
let vendorName = readCString(at: offset + 24, length: 64)
let modelName = readCString(at: offset + 88, length: 64)

let state = FWDeviceState(rawValue: stateRaw) ?? .created

Expand All @@ -73,23 +99,21 @@ extension ASFWDriverConnector {
// Read units
var units: [FWUnitInfo] = []
for _ in 0..<unitCount {
guard offset + 144 <= data.count else { // sizeof(FWUnitWire) = 144
guard offset + 160 <= data.count else { // sizeof(FWUnitWire) = 160
print("[Connector] ❌ Data truncated while reading unit")
return nil
}

let specId = data.withUnsafeBytes { $0.load(fromByteOffset: offset, as: UInt32.self) }
let swVersion = data.withUnsafeBytes { $0.load(fromByteOffset: offset + 4, as: UInt32.self) }
let romOffset = data.withUnsafeBytes { $0.load(fromByteOffset: offset + 8, as: UInt32.self) }
let unitStateRaw = data.withUnsafeBytes { $0.load(fromByteOffset: offset + 12, as: UInt8.self) }

// Read unit vendor name (64 bytes at offset 16)
let unitVendorData = data.subdata(in: (offset + 16)..<(offset + 80))
let unitVendorName = String(cString: unitVendorData.withUnsafeBytes { $0.bindMemory(to: CChar.self).baseAddress! })

// Read unit product name (64 bytes at offset 80)
let unitProductData = data.subdata(in: (offset + 80)..<(offset + 144))
let unitProductName = String(cString: unitProductData.withUnsafeBytes { $0.bindMemory(to: CChar.self).baseAddress! })
let specId = readUInt32(at: offset)
let swVersion = readUInt32(at: offset + 4)
let romOffset = readUInt32(at: offset + 8)
let unitStateRaw = readUInt8(at: offset + 12)
let managementAgentOffset = readUInt32(at: offset + 16)
let lun = readUInt32(at: offset + 20)
let unitCharacteristics = readUInt32(at: offset + 24)
let fastStart = readUInt32(at: offset + 28)
let unitVendorName = readCString(at: offset + 32, length: 64)
let unitProductName = readCString(at: offset + 96, length: 64)

let unitState = FWUnitState(rawValue: unitStateRaw) ?? .created

Expand All @@ -98,11 +122,15 @@ extension ASFWDriverConnector {
swVersion: swVersion,
state: unitState,
romOffset: romOffset,
managementAgentOffset: managementAgentOffset == 0 ? nil : managementAgentOffset,
lun: lun == 0 ? nil : lun,
unitCharacteristics: unitCharacteristics == 0 ? nil : unitCharacteristics,
fastStart: fastStart == 0 ? nil : fastStart,
vendorName: unitVendorName.isEmpty ? nil : unitVendorName,
productName: unitProductName.isEmpty ? nil : unitProductName
))

offset += 144 // sizeof(FWUnitWire)
offset += 160 // sizeof(FWUnitWire)
}

devices.append(FWDeviceInfo(
Expand All @@ -115,7 +143,8 @@ extension ASFWDriverConnector {
nodeId: nodeId,
generation: generation,
state: state,
units: units
units: units,
deviceKind: deviceKind
))
}

Expand Down
Loading
Loading