* Port Artic Fan Controller code * Fixed misspelling and added improvements - Fixed thread not starting (added _thread.Start()) - Added control sensor activation - Added PWM initialization from device - Improved PWM value reading for fast updates * Slight refactor Extract message response * Create README.MD * Code review * Add license header * Make readonly fields * Remove redundant const * format * Remove redundant index check in Update() * add missing control lock in close() * add missing hid lock in update loop for array access * join thread (wait for exit) on cose() * Proper Hardware type * File scoped namespaces * Update ArcticFanController.cs --------- Co-authored-by: aureopvh <aureoserrano@hotmail.com>
5.1 KiB
5.1 KiB
Fan Controller Device Integration Guide
Arctic Fan Controller USB Custom HID device that accepts 10 PWM commands (0–100%) via OUT reports and returns current PWM values plus 10 RPM sensor readings (0–65535) via IN reports every ~1 second, using 32-byte reports.
Protocol
Interface: USB Custom HID
Vendor ID (VID): 0x3904 (14596 decimal)
Product ID (PID): 0xF001 (61441 decimal)
Report Size: 32 bytes
Report ID: 0x01 (byte 0)
PWM Control (OUT Report)
Format:
- Byte 0: Report ID =
0x01 - Bytes 1-10: PWM duty cycle for channels 1-10 (0-100)
- Bytes 11-31: Ignored
Specifications:
- 10 channels (1-10)
- Range: 0-100 (percentage)
Example: Set channel 1 to 50%, channel 2 to 75%
[0x01, 50, 75, ...]
RPM Reading (IN Report)
Format:
- Byte 0: Report ID =
0x01 - Bytes 1-10: Current PWM values
- Bytes 11-30: RPM values for sensors 1-10 (uint16, little-endian)
- Sensor 1: bytes 11-12
- Sensor 2: bytes 13-14
- ... (2 bytes per sensor)
- Byte 31: Padding
Specifications:
- 10 sensors (1-10)
- Range: 0-65535 RPM
- Update rate: ~1 second
Example: Read sensor 1 RPM
RPM = buffer[11] + (buffer[12] << 8)
Notes
- Report ID
0x01required in all reports - RPM updates every ~1 second
- PWM values take effect immediately
- All multi-byte values are little-endian
Complete Transaction Examples
OUT Transaction (PC → Device)
Setting PWM: Channel 1 = 50%, Channels 2-10 = 75%
Byte: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
Hex: 0x01 0x32 0x4B 0x4B 0x4B 0x4B 0x4B 0x4B 0x4B 0x4B 0x4B 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
Dec: 1 50 75 75 75 75 75 75 75 75 75 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
└─┘ └────────────────────────────────────────────────────────┘ └────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
ID PWM Channels 1-10 (duty cycle %) Ignored
Explanation:
- Byte 0: Report ID = 1 (0x01)
- Bytes 1-10: PWM duty cycles = 50%, 75%, 75%, 75%, 75%, 75%, 75%, 75%, 75%, 75%
- Bytes 11-31: Ignored (all zeros)
IN Transaction (Device → PC)
Reading current PWM and RPM values
Byte: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
Hex: 0x01 0x32 0x4B 0x4B 0x4B 0x4B 0x4B 0x4B 0x4B 0x4B 0x4B 0xDC 0x05 0xD0 0x07 0xD0 0x07 0xD0 0x07 0xD0 0x07 0xD0 0x07 0xD0 0x07 0xD0 0x07 0xD0 0x07 0xD0 0x07 0x00
Dec: 1 50 75 75 75 75 75 75 75 75 75 220 5 208 7 208 7 208 7 208 7 208 7 208 7 208 7 208 7 208 7 0
└─┘ └────────────────────────────────────────────────────────┘ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ └┘
ID Current PWM values (Channels 1-10) RPM values (Sensors 1-10, uint16 little-endian) Padding
Explanation:
- Byte 0: Report ID = 1 (0x01)
- Bytes 1-10: Current PWM values = 50%, 75%, 75%, 75%, 75%, 75%, 75%, 75%, 75%, 75%
- Bytes 11-12: Sensor 1 RPM = 0x05DC = 1500 RPM (220 + 5×256)
- Bytes 13-14: Sensor 2 RPM = 0x07D0 = 2000 RPM (208 + 7×256)
- Bytes 15-16: Sensor 3 RPM = 0x07D0 = 2000 RPM (208 + 7×256)
- Bytes 17-18: Sensor 4 RPM = 0x07D0 = 2000 RPM (208 + 7×256)
- Bytes 19-20: Sensor 5 RPM = 0x07D0 = 2000 RPM (208 + 7×256)
- Bytes 21-22: Sensor 6 RPM = 0x07D0 = 2000 RPM (208 + 7×256)
- Bytes 23-24: Sensor 7 RPM = 0x07D0 = 2000 RPM (208 + 7×256)
- Bytes 25-26: Sensor 8 RPM = 0x07D0 = 2000 RPM (208 + 7×256)
- Bytes 27-28: Sensor 9 RPM = 0x07D0 = 2000 RPM (208 + 7×256)
- Bytes 29-30: Sensor 10 RPM = 0x07D0 = 2000 RPM (208 + 7×256)
- Byte 31: Padding = 0