DIF.slnx
├── src/
│ ├── DIF.Transport/ .NET 10 class library (no dependencies)
│ ├── DIF.Core/ .NET 10 class library (depends on DIF.Transport)
│ ├── DIF.Simulator/ .NET 10 class library (depends on DIF.Transport, DIF.Core)
│ └── DIF.Maui/ .NET 10 MAUI executable (depends on all above)
├── tests/
│ ├── DIF.Core.Tests/ xUnit 2.9.3 (depends on DIF.Core, DIF.Transport)
│ ├── DIF.Integration.Tests/ xUnit 2.9.3 (depends on DIF.Core, DIF.Transport, DIF.Simulator)
│ └── DIF.Transport.Tests/ xUnit 2.9.3 (depends on DIF.Transport)
└── tools/
└── DIF.MessageRecorder/ .NET 10 console exe (depends on DIF.Transport, DIF.Core)
┌──────────────────────────────────────────────────────────────────────┐
│ DIF.Maui (UI Layer) │
│ App.xaml / AppShell.xaml │
│ Views: MainPage, SettingsPage, DiagnosticCodesPage, │
│ GovernorGainPage, VsgPage, RatingPage, │
│ InjectorCalibrationPage, SlewingPage │
│ ViewModels: MainViewModel, SettingsViewModel, etc. │
│ Services: TransportFactory, AppSettings │
└─────────────────────────────────┬────────────────────────────────────┘
│ Events / Method calls
┌─────────────────────────────────▼────────────────────────────────────┐
│ DIF.Core (Business Logic) │
│ Services/ EcmCommunicationService │
│ Protocol/ J1587Parser, PidUpdate │
│ Tasks/ TaskManager, IEcmTask, 9 task implementations │
│ Models/ EcmData, PidInfo, PidData, FaultCode, J1708Message │
│ Config/ PidDefinitionLoader, EdmsParameterLoader, │
│ FaultCodeLoader, ChannelLoader │
└─────────────────────────────────┬────────────────────────────────────┘
│ IEcmTransport interface
┌─────────────────────────────────▼────────────────────────────────────┐
│ DIF.Transport (Abstraction Layer) │
│ IEcmTransport interface │
│ TransportConfig, ReadResult, TransportType │
│ J1587Constants │
│ MessageReceivedEventArgs, ConnectionStateEventArgs │
└──────────────┬────────────────────────────┬──────────────────────────┘
│ │
┌──────────────▼──────────┐ ┌──────────────▼──────────────────────────┐
│ DIF.Simulator │ │ (Future) Rp1210Transport │
│ SimulatorTransport │ │ P/Invoke to RP1210 DLLs │
│ EcmSimulator │ │ Real hardware communication │
│ EcmState │ │ │
│ MessageRecorder │ └─────────────────────────────────────────┘
│ MessagePlayer │
└─────────────────────────┘
DIF.Transport (leaf - no project dependencies)
↑
DIF.Core (depends on DIF.Transport)
↑
DIF.Simulator (depends on DIF.Transport, DIF.Core)
↑
DIF.Maui (depends on DIF.Core, DIF.Transport, DIF.Simulator)
NuGet dependencies:
IEcmTransport defines the communication contract. Implementations:
SimulatorTransport - Software ECM simulation (testing)MessagePlayer - Recorded session replay (debugging)Rp1210Transport - Real RP1210 hardware (production, future)IEcmTask defines a single ECM operation. The TaskManager executes tasks with retry and timeout logic. Each task encapsulates its request/response protocol:
public interface IEcmTask
{
Task<bool> SendRequestAsync(IEcmTransport transport, byte toMid);
bool ProcessResponse(int pid, int fromMid, byte[] data);
bool IsComplete { get; }
TaskResult? Result { get; }
}
Task implementations: DiagnosticCodesTask, GovernorGainTask, HpAdjustTask, InjectorCalibrationTask, RatingTask, ResetTask, SetChannelTask, SlewTask, VsgTask.
TransportFactory creates the appropriate IEcmTransport based on AppSettingsTaskManager convenience methods create task instances internallyEcmCommunicationService.PidUpdated event notifies ViewModels of data changesIEcmTransport.MessageReceived event for transport-level monitoringTaskManager.TaskCompleted event for task completion notificationsJ1708 Bus (or Simulator)
│
▼
IEcmTransport.ReadMessageAsync()
│ Returns ReadResult(Success, Data[], Mid, RetryCount)
▼
EcmCommunicationService.RunLoop()
│ Increments MessagesReceived
▼
J1587Parser.ProcessJ1587(data, length, fromMid)
│ Returns List<PidUpdate>
│
├──► Task responses (IsTaskResponse=true)
│ └──► TaskManager.ProcessIncomingPid()
│ └──► IEcmTask.ProcessResponse()
│
└──► PID value updates
└──► PidUpdated event
└──► MainViewModel.OnPidUpdated()
├──► Update top-level properties (Rpm, OilPressure, etc.)
└──► Update Parameters collection (grid display)
Raw bytes from J1708 message
│
▼
Extract by PidDataType (Uns8, Int16, Uns32, Bit, etc.)
│ Uses BitSize and BitOffset for bit-field PIDs
▼
RawValue (long)
│
▼ × PidInfo.ScaleFactor
ScaledValue (float)
│
▼ × PidInfo.ConvMult + PidInfo.ConvAdd
DisplayValue (float)
│
▼
PidData updated, PidUpdate event fired
ViewModel initiates task
│ e.g., GovernorGainViewModel.ReadGainAsync()
▼
TaskManager.ExecuteTaskAsync(task, toMid, timeout, retries)
│ Acquires SemaphoreSlim
│
├──► task.SendRequestAsync(transport, toMid)
│ └──► IEcmTransport.SendRawMessageAsync(bytes)
│
├──► Wait for response (loop with timeout)
│ └──► transport.ReadMessageAsync()
│ └──► task.ProcessResponse(pid, fromMid, data)
│
├──► On timeout: retry (up to MaxRetries=3)
│
└──► Return TaskResult (Success/TimedOut/Cancelled/Failed)
└──► ViewModel updates UI
TaskManager.ExecuteSequenceAsync([step1, step2, step3], toMid)
│
├──► step1: Password submission
│ SendRequest: [254, 14, subPid, 0x30×12]
│ ProcessResponse: ACK byte = 0x00
│
├──► step2: Get/Set operation
│ SendRequest: [254, length, subPid, ...data]
│ ProcessResponse: data bytes
│
└──► step3: Complete confirmation
SendRequest: [254, length, subPid, ...]
ProcessResponse: final ACK
EcmCommunicationService.RunLoop() (async Task)No explicit thread management. The async/await model handles thread pool scheduling automatically. UI updates are marshaled by MAUI's data binding infrastructure.
Registration in MauiProgram.cs:
// Transport layer
services.AddSingleton<TransportFactory>();
services.AddSingleton<IEcmTransport>(sp => sp.GetRequiredService<TransportFactory>().Create());
// ECM data (3 ECMs: Master, Receiver1, Receiver2)
services.AddSingleton<EcmData[]>(sp => {
var ecmData = new EcmData[3];
// Load PID definitions from CSV, assign MIDs
return ecmData;
});
// Protocol and services
services.AddSingleton<J1587Parser>(sp => new J1587Parser(sp.GetRequiredService<EcmData[]>()));
services.AddSingleton<TaskManager>(sp => new TaskManager(sp.GetRequiredService<IEcmTransport>()));
services.AddSingleton<EcmCommunicationService>(...);
services.AddSingleton<AppSettings>();
// ViewModels
services.AddSingleton<MainViewModel>();
services.AddTransient<SettingsViewModel>();
services.AddTransient<DiagnosticCodesViewModel>();
// ... all 8 ViewModels
// Pages
services.AddSingleton<MainPage>();
services.AddTransient<SettingsPage>();
// ... all 8 Pages
| Constant | Value | Source |
|---|---|---|
| AppMid | 180 | DIF application MID on J1708 bus |
| MidMaster | 128 | Master ECM |
| MidReceiver1 | 175 | Receiver 1 ECM |
| MidReceiver2 | 183 | Receiver 2 ECM |
| MaxRetries | 3 | Task retry limit |
| TaskTimeoutDefault | 12000ms | Standard task timeout |
| TaskTimeoutCco | 2000ms | Cylinder cutout timeout |
| ReadSleepTimeMs | 20ms | Transport read polling interval |
| MaxJ1708FrameSize | 26 bytes | Maximum J1708 data payload |
| MaxCylindersPerEcm | 8 | Injector calibration limit |
| MaxEcms | 3 | Supported ECM count |