Files
DP44/enriched-qwen3-coder-next/DataPRO/CanFDApiProxy.md
2026-04-17 14:55:32 -04:00

216 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
source_files:
- DataPRO/CanFDApiProxy/Protocol.cs
- DataPRO/CanFDApiProxy/CanApiException.cs
- DataPRO/CanFDApiProxy/HttpClientFactory.cs
- DataPRO/CanFDApiProxy/CommandName.cs
- DataPRO/CanFDApiProxy/RESTWrapper.cs
- DataPRO/CanFDApiProxy/CANFD.cs
generated_at: "2026-04-16T03:47:56.020895+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "39cf8ff3a187bfe6"
---
# CANFDApiProxy Module Documentation
## 1. Purpose
This module provides a C# client-side API proxy for interacting with a remote CAN FD devices RESTful HTTP/HTTPS API. It encapsulates low-level HTTP communication, request/response serialization, and error handling to expose a strongly-typed, asynchronous interface for retrieving and setting device configuration, status, and diagnostic data (e.g., CAN bus state, LEDs, serial number, file operations). It serves as the primary integration point for applications needing programmatic access to the devices REST endpoints, abstracting away the underlying JSON/HTTP mechanics and enforcing consistent error handling via `CanApiException`.
## 2. Public Interface
### `CANFD` (Singleton Class)
The main public entry point. Exposes asynchronous methods for GET and POST operations against device endpoints.
#### Public Methods
- **`public static CANFD API { get; }`**
Gets the singleton instance of the `CANFD` class.
- **`public async Task<UsbTreeMessage> GetUsbTree(string deviceHost, CancellationToken cancellationToken)`**
Retrieves USB tree topology from the device via `GET /usb-tree`.
- **`public async Task<BatteryMessage> GetBattery(string deviceHost, CancellationToken cancellationToken)`**
Retrieves battery status via `GET /battery`.
- **`public async Task<DiagnosticMessageRow[]> GetBIST(string deviceHost, CancellationToken cancellationToken)`**
Retrieves Built-In Self-Test (BIST) results via `POST /diagnostics` with `{"format":"csv"}`; parses CSV response into `DiagnosticMessageRow[]`.
- **`public async Task<CalibrationMessage> GetCalibrationDate(string deviceHost, CancellationToken cancellationToken)`**
Retrieves calibration date via `GET /calibration-date`.
- **`public async Task<SerialMessage> GetSerial(string deviceHost, CancellationToken cancellationToken)`**
Retrieves device serial number via `GET /serial`.
- **`public async Task<LEDsMessage> GetLEDs(string deviceHost, CancellationToken cancellationToken)`**
Retrieves LED status (color, state) for CAN1CAN4 and device-level status flags (`Status`, `Battery`, `Pwr`, `Sts`) via `GET /leds`. Internally deserializes `CANInfoInternal` and constructs `LEDsMessage`.
- **`public async Task<CANInfoMessage> GetCANInfo(string deviceHost, CancellationToken cancellationToken)`**
Retrieves CAN interface info (e.g., mode, bitrate) for CAN1CAN4 via `GET /can-info`.
- **`public async Task<CANStateMessage> GetCANState(string deviceHost, CancellationToken cancellationToken)`**
Retrieves CAN interface state (e.g., active, error-active) and last update timestamp for CAN1CAN4 via `GET /can-state`.
- **`public async Task<CANStatsMessage> GetCANStats(string deviceHost, CancellationToken cancellationToken)`**
Retrieves CAN interface statistics (STD/EXT frames, errors, overruns, bus load) for CAN1CAN4 via `GET /can-stats`.
- **`public async Task<CANConfigMessage> GetCANConfig(string deviceHost, CancellationToken cancellationToken)`**
Retrieves CAN interface configuration (bitrates, SJW, FD flags, included status) for CAN1CAN4 and `Pipe` via `GET /can-config`.
- **`public async Task<DeviceInfoMessage> GetDeviceInfo(string deviceHost, CancellationToken cancellationToken)`**
Retrieves device hardware/software info via `GET /device-info`.
- **`public async Task<NtpMessage> GetNtp(string deviceHost, CancellationToken cancellationToken)`**
Retrieves NTP configuration/status via `GET /ntp`.
- **`public async Task<PowerMessage> GetPower(string deviceHost, CancellationToken cancellationToken)`**
Retrieves power state via `GET /power`.
- **`public async Task<ServicesMessage> GetServices(string deviceHost, CancellationToken cancellationToken)`**
Retrieves enabled services via `GET /services`.
- **`public async Task<NetworkMessage> GetNetwork(string deviceHost, CancellationToken cancellationToken)`**
Retrieves network configuration via `GET /network`.
- **`public async Task<ClocksMessage> GetClocks(string deviceHost, CancellationToken cancellationToken)`**
Retrieves clock/time info via `GET /clocks`.
- **`public async Task<EventPinMessage> GetEventPin(string deviceHost, CancellationToken cancellationToken)`**
Retrieves event pin configuration/status via `GET /event-pin`.
- **`public async Task<RecordingMessage> GetRecording(string deviceHost, CancellationToken cancellationToken)`**
Retrieves recording status via `GET /recording`.
- **`public async Task<UsbStatsMessage> GetUsbStats(string deviceHost, CancellationToken cancellationToken)`**
Retrieves USB statistics via `GET /usb-stats`.
- **`public async Task<SerialMessage> SetSerial(string deviceHost, SerialRequest serialRequest, CancellationToken cancellationToken)`**
Sets device serial number via `POST /serial`.
- **`public async Task<PowerMessage> SetPowerOff(string deviceHost, CancellationToken cancellationToken)`**
Powers off device via `POST /power` with `{"cmd":"off"}`.
- **`public async Task<PowerMessage> SetPowerReboot(string deviceHost, CancellationToken cancellationToken)`**
Reboots device via `POST /power` with `{"cmd":"reboot"}`.
- **`public async Task<CANConfigMessage> SetCANConfig(string deviceHost, CANConfigRequest canConfigRequest, CancellationToken cancellationToken)`**
Configures CAN interface(s) via `POST /can-config`.
- **`public async Task<LEDsPostMessage> SetLEDs(string deviceHost, LedName led, LedCmd cmd, LedColor color, CancellationToken cancellationToken)`**
Controls LED via `POST /leds` with `{"led":"...", "cmd":"...", "color":"..."}`.
- **`public async Task<ClocksMessage> SetClocks(string deviceHost, DateTime dateTime, CancellationToken cancellationToken)`**
Sets device clock via `POST /clocks` with `{"cmd":"set", "time":"yyyy-MM-dd HH:mm:ss"}`.
- **`public async Task<ClocksMessage> SyncClocks(string deviceHost, CancellationToken cancellationToken)`**
Syncs device clock via `POST /clocks` with `{"cmd":"sync"}`.
- **`public async Task<RecordingMessage> SetRecordingStart(string deviceHost, CancellationToken cancellationToken)`**
Starts recording via `POST /recording` with `{"cmd":"start"}`.
- **`public async Task<RecordingMessage> SetRecordingTriggerCheck_Quick(string deviceHost, CancellationToken cancellationToken)`**
Performs quick trigger check via `POST /recording` with `{"cmd":"triggercheck_quick"}`.
- **`public async Task<RecordingMessage> SetRecordingStop(string deviceHost, CancellationToken cancellationToken)`**
Stops recording via `POST /recording` with `{"cmd":"stop"}`.
- **`public async Task<NetworkMessage> SetNetwork(string deviceHost, NetworkRequest networkRequest, CancellationToken cancellationToken)`**
Sets network configuration via `POST /network`.
- **`public async Task<EventPinMessage> SetEventPinArm(string deviceHost, CancellationToken cancellationToken)`**
Arms event pin via `POST /event-pin` with `{"cmd":"arm"}`.
- **`public async Task<EventPinMessage> SetEventPinDisarm(string deviceHost, CancellationToken cancellationToken)`**
Disarms event pin via `POST /event-pin` with `{"cmd":"disarm"}`.
- **`public async Task<StatusMessage> Delete(string deviceHost, string usbPath, CancellationToken cancellationToken)`**
Deletes file/directory on device via `POST /file` with `{"cmd":"delete", "path":"..."}`. Validates `usbPath` is non-null/empty.
- **`public async Task Download(string deviceHost, string usbPath, string destinationDirectory, TimeSpan timeOut, CancellationToken cancellationToken)`**
Downloads file/directory (as `.zip` if directory) from device to local path. Validates `usbPath`, `destinationDirectory`, and that `destinationDirectory` exists. Uses `POST /file` with `{"cmd":"download", "path":"..."}` and reads response as stream.
- **`public async Task<StatusMessage> Upload(string deviceHost, string uploadUsbPath, string sourcefile, TimeSpan timeOut, CancellationToken cancellationToken)`**
Uploads local file to device via `POST /file` with multipart form data (`cmd=upload`, `path=uploadUsbPath`, `file=<bytes>`). Validates `uploadUsbPath`, `sourcefile`, and that `sourcefile` exists.
### Supporting Types (Internal)
- **`RESTWrapper` (internal static class)**
Encapsulates HTTP communication logic.
- `public static int Port { get; set; } = 5000`
Default port for API calls.
- `public static Protocol Protocol { get; set; } = Protocol.http`
Protocol used (`http` or `https`).
- `public static TimeSpan Timeout { get; set; } = 30s`
Default HTTP timeout.
- `public static async Task<string> GetResourceAsync(...)`
Performs GET request; throws `CanApiException` on non-2xx status (including deserialized error message).
- `public static async Task<string> PostResourceAsync<T>(...)`
Performs JSON POST request; throws `CanApiException` on non-2xx status.
- `public static async Task<Stream> SendResourceReadAsStreamAsync<T>(...)`
Performs POST request and returns response as `Stream` (for large downloads).
- `public static async Task<string> PostResourceReadAsStringAsync(...)`
Performs multipart form POST and returns response as `string`.
- `public static async Task WriteStreamToFileAsync(Stream inputStream, string filePath)`
Writes stream to file.
- **`HttpClientFactory` (internal static class)**
Creates configured `HttpClient` instances.
- `public static HttpClient CreateHttpClient()`
Returns a new `HttpClient` with `Accept: application/json` header and cleared default headers.
- **`CanApiException` (public class)**
Custom exception for API errors.
- `public int? StatusCode { get; set; }`
HTTP status code if available.
- Constructors: `(string, Exception)`, `(string, int)`.
- **`Protocol` (public enum)**
`http`, `https`.
- **`CommandName` (internal enum)**
Maps logical command names to REST endpoint paths (via `DescriptionAttribute`):
- `Serial`, `LEDs`, `Battery`, `CalibrationDate`, `CANInfo`, `CANState`, `CANStats`, `CANConfig`, `DeviceInfo`, `Ntp`, `Power`, `Services`, `Network`, `Clocks`, `EventPin`, `Recording`, `UsbStats`, `UsbTree`, `File`, `Diagnostics`.
## 3. Invariants
- **Host Validation**: All public methods in `CANFD` and `RESTWrapper` require `deviceHost` to be non-null/non-empty; otherwise, `ArgumentNullException` is thrown.
- **Path Validation**: `Delete`, `Download`, and `Upload` methods require `usbPath`/`sourcefile`/`destinationDirectory` to be non-null/non-empty and, where applicable, exist on the filesystem.
- **Timeout Isolation**: `Download` and `Upload` temporarily override `RESTWrapper.Timeout` and restore it in a `finally` block.
- **Error Handling**: Non-2xx HTTP responses trigger `CanApiException` with status code and deserialized error message (if available). Specific handling for `400`, `403`, `404`, `500`, `503`.
- **JSON Content-Type**: All POST requests use `application/json` or `multipart/form-data` as appropriate.
- **Protocol Consistency**: All endpoints use the same `Protocol` and `Port` (configurable at class level).
- **CancellationToken Propagation**: All async methods accept and propagate `CancellationToken`; cancellation results in `CanApiException` with message `"An API call was cancelled or timedout"`.
## 4. Dependencies
### External Dependencies
- **`Microsoft.Extensions.Http`**: Used via `IHttpClientFactory` in `HttpClientFactory`.
- **`Newtonsoft.Json`**: Used for JSON serialization/deserialization (`JsonConvert.DeserializeObject<T>`, `PostAsJsonAsync`).
- **`CsvHelper`**: Used in `GetBIST` to parse CSV responses.
- **`System.Net.Http`**: Core HTTP client functionality.
- **`System.IO`**: File/stream operations (`FileStream`, `File.ReadAllBytes`, `CopyToAsync`).
### Internal Dependencies
- **`CANFDApiProxy.Messages`**: Contains response message types (e.g., `UsbTreeMessage`, `BatteryMessage`, `StatusMessage`, `LEDsPostMessage`, `CANConfigMessage`, etc.).
- **`CANFDApiProxy.Requests`**: Contains request types (e.g., `SerialRequest`, `CANConfigRequest`, `LEDsRequest`, `FileRequest`, `NetworkRequest`, `ClocksRequest`, `CanPostRequest`).
- **`CANFDApiProxy.Interfaces`**: `ICANFDApi` interface implemented by `CANFD`.
### Inferred Consumers
- Any application or library requiring programmatic access to the CAN FD devices REST API (e.g., test harnesses, UI clients, logging services).
## 5. Gotchas
- **`RESTWrapper.Timeout` is global state**: Changing `RESTWrapper.Timeout` affects all subsequent calls until changed again. `Download`/`Upload` temporarily override it, but concurrent calls may interfere.
- **`CANInfoInternal` is an internal implementation detail**: `GetLEDs`, `GetCANInfo`, `GetCANState`, `GetCANStats`, and `GetCANConfig` all deserialize the same internal type (`CANInfoInternal`) and manually construct the public message types. Changes to the devices `/leds`, `/can-info`, etc., response structure may break these methods.
- **`IsDirectory` heuristic is flawed**: `CANFD.IsDirectory` uses `Path.GetExtension(fileOrDirectory)` to infer directory vs. file. This is unreliable (e.g., directories without extensions, files with no extension). The `BuildFilePath` logic assumes directories end with `/` or lack an extension, but this may not match the devices behavior.
- **`GetBIST` CSV parsing is fragile**: Uses `CsvHelper` with `PrepareHeaderForMatch` to lowercase headers. Assumes device CSV headers match `DiagnosticMessageRow` property names case-insensitively; any mismatch will cause silent failures or exceptions.
- **`PostAsJsonAsync` uses `PostAsJsonAsync` extension**: Relies on `System.Net.Http.Json` extension (not shown in source), which may not be available in all environments.
- **`WriteStreamToFileAsync` resets stream position**: Only resets if `inputStream.CanSeek`; otherwise, it may start from current position.
- **No retry logic**: Transient network errors or server overload are not retried; callers must implement retry policies.
- **`Protocol` enum is lowercase**: `Protocol.http``"http"` (via `ToString()`), but HTTP/HTTPS schemes are case-insensitive per RFC. This is consistent but non-standard (typically `"HTTP"`/`"HTTPS"`).
- **`CommandName.DescriptionAttr` is internal**: Only used internally; external consumers cannot leverage this enum mapping directly.