- STACK.md - Technologies and dependencies (.NET 4.7.2, NuGet, Costura.Fody) - ARCHITECTURE.md - Layered CLI with ICncMachine factory pattern - STRUCTURE.md - Directory layout and where to add new code - CONVENTIONS.md - C# style, naming, result wrapper pattern - TESTING.md - NUnit 3 + Moq, stubs, ignored FOCAS tests - INTEGRATIONS.md - FOCAS, LSV2, FTP, RSA licensing - CONCERNS.md - Blocking async, silent catch, no logging, Windows-only Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
156 lines
5.9 KiB
Markdown
156 lines
5.9 KiB
Markdown
# Architecture
|
|
|
|
**Analysis Date:** 2026-05-18
|
|
|
|
## Pattern Overview
|
|
|
|
**Overall:** Layered CLI console application with abstract machine interface, factory dispatch, and offline license gate.
|
|
|
|
**Key Characteristics:**
|
|
- Single Windows EXE (all dependencies embedded via Costura.Fody)
|
|
- Polymorphic multi-vendor CNC support via `ICncMachine` interface
|
|
- Factory pattern for manufacturer selection at runtime
|
|
- Async/await throughout (Task-based), but blocked at CLI boundary via `.GetAwaiter().GetResult()`
|
|
- Result-wrapper pattern (`CncResult<T>`) instead of exceptions for CNC operations
|
|
- RSA license validation gate on every startup
|
|
|
|
## Layers
|
|
|
|
**CLI Entry Layer:**
|
|
- Purpose: Parse args, validate license, dispatch to action (Scarica/Invia)
|
|
- Contains: `Program.cs` (main orchestration), `ArgParser.cs` (regex arg parsing), `InputArgs.cs` (config object)
|
|
- Depends on: Licensing layer, CNC abstraction layer
|
|
- Error output: Negative exit codes (-100 to -208) mapped to Italian user messages
|
|
|
|
**Licensing Layer:**
|
|
- Purpose: Prevent execution on unlicensed machines
|
|
- Contains: `Licensing/LicenseValidator.cs`, `Licensing/MachineFingerprint.cs`, `Licensing/LicenseFile.cs`
|
|
- Depends on: WMI (System.Management), RSA crypto
|
|
- Used by: CLI entry layer (startup check only)
|
|
|
|
**CNC Abstraction Layer:**
|
|
- Purpose: Uniform interface over 4 different CNC protocols
|
|
- Contains: `Cnc/ICncMachine.cs`, `Cnc/IFanucMachine.cs`, `Cnc/CncMachineFactory.cs`, `Cnc/Models/`
|
|
- Key types: `CncResult<T>`, `CncError`, `CncManufacturer`, `ConnectionState`, `CncProgram`
|
|
- Used by: CLI entry layer
|
|
|
|
**Manufacturer Implementations:**
|
|
- Purpose: Protocol-specific CNC communication
|
|
- Contains: `Cnc/Fanuc/`, `Cnc/Heidenhain/`, `Cnc/Siemens/`, `Cnc/Mitsubishi/`
|
|
- Each implements `ICncMachine` (Fanuc also implements `IFanucMachine`)
|
|
- Depends on: Protocol libraries (FOCAS DLL, TCP socket, FtpWebRequest)
|
|
|
|
**Validation Layer:**
|
|
- Purpose: Pre-upload NC program syntax checking
|
|
- Contains: `Cnc/INcProgramValidator.cs`, `Cnc/NcProgramValidator.cs`
|
|
- Injected into machine implementations; upload blocked on Error severity
|
|
- Depends on: Nothing external
|
|
|
|
**NC Program Parsing:**
|
|
- Purpose: Parse/format Fanuc composite NC file format
|
|
- Contains: `FanucProgram.cs` (program + tooloffset + workzero sections)
|
|
- Used by: CLI entry layer post-download
|
|
|
|
## Data Flow
|
|
|
|
**Scarica (Download from CNC):**
|
|
```
|
|
CLI args
|
|
→ ArgParser.Parse() → InputArgs
|
|
→ LicenseValidator.Validate() [exit -1xx on failure]
|
|
→ CncMachineFactory.Create(InputArgs) → ICncMachine
|
|
→ machine.ConnectAsync() → CncResult<bool>
|
|
→ machine.ReadProgramAsync(path) → CncResult<string>
|
|
→ [IFanucMachine cast] ReadToolDataAsync / ReadWorkZeroDataAsync
|
|
→ FanucProgram.Format() → composite file string
|
|
→ File.WriteAllText(localPath)
|
|
```
|
|
|
|
**Invia (Upload to CNC):**
|
|
```
|
|
CLI args
|
|
→ ArgParser.Parse() → InputArgs
|
|
→ LicenseValidator.Validate() [exit -1xx on failure]
|
|
→ CncMachineFactory.Create(InputArgs) → ICncMachine
|
|
→ File.ReadAllText(localPath)
|
|
→ NcProgramValidator.Validate() [exit on Error severity]
|
|
→ machine.ConnectAsync()
|
|
→ machine.WriteProgramAsync(path, content) → CncResult<bool>
|
|
```
|
|
|
|
**State Management:**
|
|
- No persistent in-memory state between invocations (each run is independent)
|
|
- Machine state tracked per-instance: `ConnectionState` enum + `StateChanged` event
|
|
- Thread safety: `SemaphoreSlim` gate per machine instance
|
|
|
|
## Key Abstractions
|
|
|
|
**ICncMachine:**
|
|
- Purpose: Uniform contract for all CNC machines
|
|
- Location: `Cnc/ICncMachine.cs`
|
|
- Methods: `ConnectAsync`, `DisconnectAsync`, `ReadProgramAsync`, `WriteProgramAsync`, `ReadAsync`, `DeleteProgramAsync`, `ReadActiveProgramAsync`, `SelectMainProgramAsync`
|
|
- Pattern: Interface + factory dispatch
|
|
|
|
**IFanucMachine:**
|
|
- Purpose: Fanuc-specific extensions (tool offsets, work zero)
|
|
- Location: `Cnc/IFanucMachine.cs`
|
|
- Extends: `ICncMachine`
|
|
- Pattern: Interface specialization
|
|
|
|
**CncResult<T>:**
|
|
- Purpose: Typed result wrapper replaces exception-based control flow
|
|
- Location: `Cnc/Models/CncResult.cs`
|
|
- Factories: `Ok()`, `Fail()`, `Cancelled()`, `OkWithWarnings()`
|
|
- Properties: `Success`, `Errors`, `WasCancelled`, `Value`
|
|
|
|
**IFocasDialect:**
|
|
- Purpose: Abstract FOCAS version differences (Legacy vs Modern API)
|
|
- Location: `Cnc/Fanuc/IFocasDialect.cs`
|
|
- Implementations: `LegacyFocasDialect.cs`, `ModernFocasDialect.cs`
|
|
- Detection: `FanucDialectDetector.cs` at connect time
|
|
|
|
**CncMachineFactory:**
|
|
- Purpose: Create correct ICncMachine from InputArgs
|
|
- Location: `Cnc/CncMachineFactory.cs`
|
|
- Dispatches on: `CncManufacturer` enum (Fanuc, Heidenhain, Siemens, Mitsubishi)
|
|
|
|
## Entry Points
|
|
|
|
**CLI Entry:**
|
|
- Location: `Program.cs` (Main method)
|
|
- Triggers: Process execution from command line or calling application
|
|
- Responsibilities: Arg parsing → license check → machine factory → action dispatch → exit code
|
|
|
|
**Argument Parser:**
|
|
- Location: `ArgParser.cs` (static `Parse(string[])`)
|
|
- Returns: `InputArgs` with all 16 CLI parameters normalized
|
|
|
|
## Error Handling
|
|
|
|
**Strategy:** Result wrapper at CNC layer, exit codes at CLI boundary, ArgumentNullException for null guards
|
|
|
|
**Patterns:**
|
|
- `CncResult<T>.Fail(errors)` for CNC operation failures
|
|
- `ArgumentNullException` for constructor null guards (`Cnc/Fanuc/FanucMachine.cs`)
|
|
- Exit codes -100 to -208 in `Program.cs` for user-facing errors
|
|
- `try/finally` with `connected` flag for connection leak prevention (`Program.cs`)
|
|
- `catch { }` (silent) on disconnect cleanup paths — known weakness (see CONCERNS.md)
|
|
|
|
## Cross-Cutting Concerns
|
|
|
|
**Logging:**
|
|
- `Console.WriteLine` only — no structured logging framework
|
|
- Debug mode (`-debug=` arg): keeps terminal open after operation
|
|
|
|
**Validation:**
|
|
- `NcProgramValidator` injected into machine constructors
|
|
- Runs before upload; blocked on `ValidationSeverity.Error`
|
|
|
|
**Cancellation:**
|
|
- `CancellationToken` passed through all async methods
|
|
- CLI does not currently expose cancellation to user
|
|
|
|
---
|
|
|
|
*Architecture analysis: 2026-05-18*
|
|
*Update when major patterns change*
|