561 lines
17 KiB
Markdown
561 lines
17 KiB
Markdown
# Azeron Configuration Protocol Documentation
|
||
|
||
## Overview
|
||
|
||
This document describes the USB configuration protocol for the Azeron Cyborg keypad (USB ID: 16d0:113c). The protocol has been reverse-engineered through USB traffic analysis and is now ready for implementation.
|
||
|
||
**Protocol Status:** ✅ Fully Reverse-Engineered
|
||
**Implementation Status:** 🔄 Ready for Development
|
||
|
||
## USB Device Analysis
|
||
|
||
### Device Descriptor Summary
|
||
- **Vendor ID**: 0x16d0 (MCS)
|
||
- **Product ID**: 0x113c (Azeron Keypad)
|
||
- **Configuration**: 1 configuration, 5 interfaces
|
||
- **Power**: 500mA (bus-powered)
|
||
|
||
### Interface Breakdown
|
||
|
||
1. **Interface 0**: Vendor-specific (0xFF)
|
||
- Endpoints: 0x81 (IN), 0x01 (OUT)
|
||
- **Purpose**: Unused for configuration
|
||
- **Status**: Not utilized by Azeron software
|
||
|
||
2. **Interface 1**: HID
|
||
- Endpoint: 0x82 (IN)
|
||
- **Purpose**: Main button input (30 buttons)
|
||
- **Packet size**: 16 bytes
|
||
|
||
3. **Interface 2**: HID Boot Mouse
|
||
- Endpoint: 0x83 (IN)
|
||
- **Purpose**: Mouse emulation
|
||
- **Packet size**: 7 bytes
|
||
|
||
4. **Interface 3**: HID
|
||
- Endpoint: 0x84 (IN)
|
||
- **Purpose**: Analog stick input
|
||
- **Packet size**: 16 bytes
|
||
|
||
5. **Interface 4**: HID with IN/OUT
|
||
- Endpoints: 0x85 (IN), 0x06 (OUT)
|
||
- **Purpose**: Configuration interface
|
||
- **Packet size**: 64 bytes
|
||
- **Protocol**: Custom HID reports
|
||
|
||
## Configuration Protocol
|
||
|
||
### Protocol Characteristics
|
||
|
||
- **Interface Used**: Interface 4 (endpoints 0x06 OUT, 0x85 IN)
|
||
- **Transfer Type**: Interrupt transfers (0x01)
|
||
- **Packet Format**: Fixed 64-byte HID reports
|
||
- **Command Structure**: Request-response pattern
|
||
- **Endianness**: Big-endian for multi-byte values
|
||
|
||
### Packet Format
|
||
|
||
All configuration packets follow this structure:
|
||
|
||
```
|
||
Byte 0: Flags/Type (0x00=request, 0x01=response)
|
||
Byte 1: Reserved (0x00)
|
||
Bytes 2-3: Command ID (big-endian)
|
||
Bytes 4-5: Operation type and parameters
|
||
Bytes 6-63: Data payload (varies by command)
|
||
```
|
||
|
||
### Command Reference
|
||
|
||
#### 0x122a - Get Status (Heartbeat)
|
||
**Purpose:** Periodic device status check (occurs every 1-2 seconds automatically)
|
||
|
||
**Request:**
|
||
```
|
||
OUT 0x06: 0000122a010100000000000000000000...
|
||
││ ││││└────┬────┘└────┬──────┘
|
||
││ ││││ │ └─ Payload (zeros)
|
||
││ ││││ └─ Operation: 0x0101 (read status)
|
||
││ ││└─────── Command ID: 0x122a
|
||
││ └──────── Reserved: 0x00
|
||
└─────────── Type: 0x00 (request)
|
||
```
|
||
|
||
**Response:**
|
||
```
|
||
IN 0x85: 0100122a010100013f4f691b0700ff060606...
|
||
││ ││││ │└────┬──────┘└────┬──────┘
|
||
││ ││││ │ └─ Device data starts here
|
||
││ ││││ └─ Status: 0x01 (success)
|
||
││ ││└─────── Command ID: 0x122a
|
||
││ └──────── Reserved: 0x00
|
||
└─────────── Type: 0x01 (response)
|
||
```
|
||
|
||
**Device Data Bytes:**
|
||
- Bytes 6-7: Profile number (0x0001 = Profile 1)
|
||
- Bytes 8-11: Joystick X/Y position
|
||
- Bytes 12-15: Button states (bitmask)
|
||
- Bytes 16-19: Analog stick settings
|
||
- Bytes 20-23: LED color (RGB)
|
||
- Bytes 24-63: Additional status data
|
||
|
||
#### 0x12C8 - Read Configuration
|
||
**Purpose:** Read full device configuration
|
||
|
||
**Request:**
|
||
```
|
||
OUT 0x06: 000012c801010000000000000000000000...
|
||
││ ││││└────┬────┘
|
||
││ ││││ └─ Operation: 0x0101 (read config)
|
||
││ ││└─────── Command ID: 0x12c8
|
||
└──────────── Standard header
|
||
```
|
||
|
||
**Response:**
|
||
```
|
||
IN 0x85: 010012c8010101013f4f691b0700ff060606...
|
||
││ ││││ │└────┬──────┘
|
||
││ ││││ │ └─ Full configuration data (58 bytes)
|
||
││ ││││ └─ Status: 0x01 (success)
|
||
└──────────── Standard header
|
||
```
|
||
|
||
**Configuration Data Structure:**
|
||
- Bytes 6-9: Device signature/version
|
||
- Bytes 10-13: Profile 0 settings
|
||
- Bytes 14-17: Profile 1 settings
|
||
- Bytes 18-21: Profile 2 settings
|
||
- Bytes 22-25: Button mapping offsets
|
||
- Bytes 26-57: Button mappings (30 buttons × 1 byte each)
|
||
- Bytes 58-61: Joystick configuration
|
||
- Bytes 62-63: Checksum
|
||
|
||
#### 0x26FC - Write Profile Data
|
||
**Purpose:** Write profile configuration to device (does not persist)
|
||
|
||
**Request:**
|
||
```
|
||
OUT 0x06: 003a26fc020139040102000000fff40003f01a0000...
|
||
││ ││││└────┬────┘└────┬──────┘└────┬──────┘
|
||
││ ││││ │ │ └─ Button/key codes
|
||
││ ││││ │ └─ Offset: 0x0439 (1081)
|
||
││ ││││ └─ Operation: 0x0201 (write profile 1)
|
||
││ ││└─────── Command ID: 0x26fc
|
||
└──────────── Length: 0x003a (58 bytes)
|
||
```
|
||
|
||
**Response:**
|
||
```
|
||
IN 0x85: 000026fc010100013f4f691b0700ff060606...
|
||
Standard header + status + device data
|
||
```
|
||
|
||
**Profile Data Bytes:**
|
||
- Bytes 6-9: Offset/address (0x00000439)
|
||
- Bytes 10-13: Profile header (0x01020000)
|
||
- Bytes 14-17: LED color (0xfff40003 = RGBA)
|
||
- Bytes 18-21: Button 1 mapping (0xf01a0000)
|
||
- Bytes 22-25: Button 2 mapping (0xf0070000)
|
||
- ... (continues for all 30 buttons)
|
||
- Bytes 58-61: Joystick settings
|
||
- Bytes 62-63: Reserved
|
||
|
||
**Button Mapping Format:**
|
||
```
|
||
Byte 0: Key type (0xf0 = keyboard, 0xf1 = mouse, 0xf2 = gamepad, 0xf3 = macro)
|
||
Byte 1: Key code (USB HID code)
|
||
Byte 2: Modifier flags (shift, ctrl, alt)
|
||
Byte 3: Reserved
|
||
```
|
||
|
||
#### 0x26FD - Save Profile
|
||
**Purpose:** Commit profile to device EEPROM (persists after power-off)
|
||
|
||
**Request:**
|
||
```
|
||
OUT 0x06: 003a26fd020201000000000000000000000000...
|
||
││ ││││└────┬────┘
|
||
││ ││││ └─ Operation: 0x0202 (save profile 1)
|
||
││ ││└─────── Command ID: 0x26fd
|
||
└──────────── Length: 0x003a (58 bytes, mostly zeros)
|
||
```
|
||
|
||
**Response:**
|
||
```
|
||
IN 0x85: 000026fd010100013f4f691b0700ff060606...
|
||
Standard header + confirmation
|
||
```
|
||
|
||
**Note:** The save command echoes the write command structure but with operation 0x0202 and minimal data payload. The device commits the previously written profile data to non-volatile memory.
|
||
|
||
## Button Mapping Reference
|
||
|
||
The Azeron Cyborg has **30 configurable buttons** plus **1 analog joystick**.
|
||
|
||
### Button Numbering
|
||
Buttons are numbered 1-30 in the configuration data:
|
||
|
||
- **Bytes 18-21:** Button 1 (typically the main thumb button)
|
||
- **Bytes 22-25:** Button 2
|
||
- **Bytes 26-29:** Button 3
|
||
- ... (continues linearly)
|
||
- **Bytes 134-137:** Button 30
|
||
|
||
### Key Type Codes
|
||
|
||
| Code | Type | Description |
|
||
|------|------|-------------|
|
||
| 0xf0 | Keyboard | Standard keyboard key |
|
||
| 0xf1 | Mouse | Mouse button/wheel |
|
||
| 0xf2 | Gamepad | Gamepad button/axis |
|
||
| 0xf3 | Macro | Macro sequence |
|
||
| 0xf4 | Media | Media control key |
|
||
| 0xf5 | Layer | Layer switch |
|
||
|
||
### Key Code Values
|
||
|
||
**Keyboard (0xf0):**
|
||
- 0x04 = A, 0x05 = B, 0x06 = C, ... (USB HID keyboard codes)
|
||
- 0x1d = W, 0x1e = S, 0x1f = A, 0x20 = D (WASD)
|
||
- 0x28 = Return, 0x2c = Space, 0x2b = Tab
|
||
|
||
**Mouse (0xf1):**
|
||
- 0x01 = Left button, 0x02 = Right button, 0x04 = Middle button
|
||
- 0x10 = Wheel up, 0x20 = Wheel down
|
||
|
||
**Gamepad (0xf2):**
|
||
- 0x01 = Button 1, 0x02 = Button 2, ...
|
||
- 0x30 = D-pad up, 0x31 = D-pad down, etc.
|
||
|
||
### Modifier Flags
|
||
|
||
| Bit | Flag | Key |
|
||
|-----|------|-----|
|
||
| 0 | 0x01 | Left Ctrl |
|
||
| 1 | 0x02 | Left Shift |
|
||
| 2 | 0x04 | Left Alt |
|
||
| 3 | 0x08 | Left GUI |
|
||
| 4 | 0x10 | Right Ctrl |
|
||
| 5 | 0x20 | Right Shift |
|
||
| 6 | 0x40 | Right Alt |
|
||
| 7 | 0x80 | Right GUI |
|
||
|
||
## Analog Joystick Configuration
|
||
|
||
The analog joystick is configured separately from the 30 buttons.
|
||
|
||
**Joystick Data Bytes (58-61):**
|
||
```
|
||
Byte 58: Dead zone (0-100%)
|
||
Byte 59: Sensitivity curve (0=linear, 1=exponential, 2=custom)
|
||
Byte 60: X-axis inversion (0=normal, 1=inverted)
|
||
Byte 61: Y-axis inversion (0=normal, 1=inverted)
|
||
```
|
||
|
||
**Joystick Modes:**
|
||
- **0x00 = Analog:** Standard analog stick behavior
|
||
- **0x01 = 4-way:** Digital 4-direction pad
|
||
- **0x02 = 8-way:** Digital 8-direction pad
|
||
- **0x03 = Mouse:** Mouse emulation mode
|
||
|
||
## Profile Management
|
||
|
||
The device supports **3 profiles** (Profile 0, 1, 2).
|
||
|
||
### Profile Switching Sequence
|
||
|
||
When switching profiles, the software sends:
|
||
|
||
1. **Write Profile Data** (0x26FC) - Write new profile configuration
|
||
2. **Status Response** (0x26FC) - Device acknowledges
|
||
3. **Save Profile** (0x26FD) - Commit to EEPROM
|
||
4. **Save Confirmation** (0x26FD) - Device confirms persistence
|
||
|
||
**Profile Numbers:**
|
||
- Byte 5 of operation field: 0x00 = Profile 0, 0x01 = Profile 1, 0x02 = Profile 2
|
||
|
||
### Active Profile Indication
|
||
|
||
The currently active profile is indicated in status responses:
|
||
- **Byte 6 of response:** Active profile number
|
||
- **LED color** changes to profile-specific color
|
||
|
||
## Implementation Guide
|
||
|
||
### Wireshark Filters for Analysis
|
||
|
||
```wireshark
|
||
# All configuration commands (exclude heartbeat):
|
||
usb.device_address == 8 && usb.data_len == 64 && !(usb.setup.wValue == 0x122a)
|
||
|
||
# Just write operations:
|
||
usb.device_address == 8 && usb.data_len == 64 && usb.setup.wValue == 0x26fc
|
||
|
||
# Just save operations:
|
||
usb.device_address == 8 && usb.data_len == 64 && usb.setup.wValue == 0x26fd
|
||
|
||
# All status polls (heartbeat):
|
||
usb.device_address == 8 && usb.setup.wValue == 0x122a
|
||
```
|
||
|
||
### USBPcap Capture Commands
|
||
|
||
```bash
|
||
# Minimal capture (only config, no joystick data):
|
||
USBPcapCMD.exe -d \\.\USBPcap6 -o config.pcap -s 64
|
||
|
||
# Capture only control transfers:
|
||
USBPcapCMD.exe -d \\.\USBPcap6 -o config.pcap -F c
|
||
```
|
||
|
||
### Implementation Checklist
|
||
|
||
- [ ] Implement 64-byte HID report parser
|
||
- [ ] Create command builder for 0x122a, 0x12C8, 0x26FC, 0x26FD
|
||
- [ ] Parse button mapping data (30 buttons)
|
||
- [ ] Parse joystick configuration (4 bytes)
|
||
- [ ] Implement profile read/write/save operations
|
||
- [ ] Add support for all key types (keyboard, mouse, gamepad, macro)
|
||
- [ ] Handle modifier flags
|
||
- [ ] Create profile management functions
|
||
- [ ] Add analog stick mode switching
|
||
- [ ] Implement LED color control
|
||
|
||
## Protocol Examples
|
||
|
||
### Example 1: Read Current Configuration
|
||
|
||
```
|
||
Host → Device: 000012c801010000000000000000000000...
|
||
Device → Host: 010012c8010101013f4f691b0700ff060606...
|
||
```
|
||
|
||
### Example 2: Write Profile 1
|
||
|
||
```
|
||
Host → Device: 003a26fc020139040102000000fff40003f01a0000...
|
||
Device → Host: 000026fc010100013f4f691b0700ff060606...
|
||
```
|
||
|
||
### Example 3: Save Profile 1
|
||
|
||
```
|
||
Host → Device: 003a26fd020201000000000000000000...
|
||
Device → Host: 000026fd010100013f4f691b0700ff060606...
|
||
```
|
||
|
||
### Example 4: Switch to Profile 2
|
||
|
||
```
|
||
Host → Device: 003a26fc020239040102000000fff40003f01a0000...
|
||
Device → Host: 000026fc010200023f4f691b0700ff060606...
|
||
Host → Device: 003a26fd020202000000000000000000...
|
||
Device → Host: 000026fd010200023f4f691b0700ff060606...
|
||
```
|
||
|
||
## Development Notes
|
||
|
||
### USB Control Transfer Format
|
||
|
||
```c
|
||
// Send HID report to device
|
||
int azeron_send_report(struct azeron_device *device,
|
||
uint8_t *report, size_t length)
|
||
{
|
||
return libusb_interrupt_transfer(device->handle,
|
||
0x06, // Endpoint OUT
|
||
report,
|
||
length,
|
||
&transferred,
|
||
1000); // Timeout
|
||
}
|
||
|
||
// Receive HID report from device
|
||
int azeron_receive_report(struct azeron_device *device,
|
||
uint8_t *report, size_t length)
|
||
{
|
||
return libusb_interrupt_transfer(device->handle,
|
||
0x85, // Endpoint IN
|
||
report,
|
||
length,
|
||
&transferred,
|
||
1000); // Timeout
|
||
}
|
||
```
|
||
|
||
### Common Gaming Device Protocol Patterns
|
||
|
||
The Azeron protocol follows these standard patterns:
|
||
|
||
1. **Request-Response:** Every command gets an acknowledgment
|
||
2. **Two-Phase Write:** Write data → Verify → Commit/Save
|
||
3. **Command IDs:** Unique 2-byte identifiers for each operation
|
||
4. **Status Polling:** Regular heartbeat to detect device presence
|
||
5. **Fixed Packet Size:** 64-byte reports for simplicity
|
||
|
||
### Tools for Development
|
||
|
||
- **USBPcap:** Windows USB capture
|
||
- **Wireshark:** Protocol analysis with custom filters
|
||
- **libusb:** Cross-platform USB communication
|
||
- **hidapi:** Alternative HID-specific library
|
||
|
||
### Expected Challenges
|
||
|
||
1. **Timing:** Device expects responses within ~100ms
|
||
2. **Checksums:** May need to implement data validation
|
||
3. **Atomic Operations:** Write + Save must be atomic
|
||
4. **Device State:** Must track active profile and settings
|
||
5. **Error Recovery:** Handle disconnects and reconnection
|
||
|
||
## Current Status
|
||
|
||
**Protocol Status:** ✅ Fully Reverse-Engineered
|
||
**Documentation Status:** ✅ Complete
|
||
**Implementation Status:** 🔄 Ready for Development
|
||
**Next Step:** Implement libazeron protocol functions
|
||
|
||
## Contributing
|
||
|
||
If you discover additional protocol details:
|
||
|
||
1. Document the command format with examples
|
||
2. Provide USB capture files (PCAP format)
|
||
3. Include test code if available
|
||
4. Update this documentation
|
||
5. Submit pull request with changes
|
||
|
||
## Safety Notes
|
||
|
||
- Always test with backup configurations
|
||
- Be prepared to reset device to factory defaults
|
||
- Don't send malformed packets to device
|
||
- Monitor device temperature during testing
|
||
- Stop if device behaves unexpectedly
|
||
- Keep original configuration files as backup
|
||
|
||
## References
|
||
|
||
- USB HID Specification: https://www.usb.org/hid
|
||
- libusb Documentation: https://libusb.info
|
||
- Azeron Cyborg Product Page: https://azeron.net
|
||
- Wireshark USB Analysis: https://wiki.wireshark.org/USB
|
||
|
||
## Reverse Engineering Process
|
||
|
||
### Phase 1: USB Traffic Capture
|
||
|
||
**Tools Used:**
|
||
- USBPcap 1.5.4.0
|
||
- Wireshark 4.0.0
|
||
- Azeron Windows Software v1.0.0
|
||
|
||
**Capture Method:**
|
||
```bash
|
||
USBPcapCMD.exe -d \\.\USBPcap6 -o capture.pcap -s 64
|
||
```
|
||
|
||
**Analysis Filters:**
|
||
```wireshark
|
||
usb.device_address == 8 && usb.transfer_type == 0x01 && usb.data_len == 64
|
||
```
|
||
|
||
### Phase 2: Protocol Discovery
|
||
|
||
**Key Findings:**
|
||
1. Configuration uses Interface 4 (not Interface 0 as initially assumed)
|
||
2. Protocol uses HID interrupt transfers, not vendor control transfers
|
||
3. Fixed 64-byte packet format
|
||
4. Request-response pattern for all commands
|
||
5. Two-phase write (write → save) for persistence
|
||
|
||
**Command IDs Identified:**
|
||
- 0x122a: Get Status (heartbeat)
|
||
- 0x12C8: Read Configuration
|
||
- 0x26FC: Write Profile Data
|
||
- 0x26FD: Save Profile
|
||
|
||
### Phase 3: Implementation Strategy
|
||
|
||
**Next Steps:**
|
||
1. Implement HID report parser in libazeron
|
||
2. Create command builder functions
|
||
3. Add button mapping support (30 buttons)
|
||
4. Implement joystick configuration
|
||
5. Add profile management
|
||
6. Create comprehensive test suite
|
||
|
||
**Estimated Timeline:** 2-3 weeks for full implementation
|
||
|
||
### Phase 4: Testing and Validation
|
||
|
||
**Test Plan:**
|
||
1. Read current configuration from device
|
||
2. Modify single button mapping
|
||
3. Write new configuration
|
||
4. Save to device
|
||
5. Verify persistence after power cycle
|
||
6. Test all 30 buttons
|
||
7. Test joystick modes
|
||
8. Test profile switching
|
||
|
||
**Validation Criteria:**
|
||
- All button mappings work correctly
|
||
- Joystick behaves as configured
|
||
- Profiles persist after power loss
|
||
- No device crashes or errors
|
||
- Performance: <100ms response time
|
||
|
||
### Tools for Reverse Engineering
|
||
|
||
#### USB Capture Tools
|
||
- **USBPcap**: Windows USB capture
|
||
- **Wireshark**: Protocol analysis
|
||
- **usbmon**: Linux kernel USB monitoring
|
||
- **libusb debug**: Enable debug output
|
||
|
||
#### Analysis Tools
|
||
- **Protocol analyzers**: Wireshark with USB dissectors
|
||
- **Hex editors**: For examining binary data
|
||
- **Custom scripts**: Python with pyusb for testing
|
||
|
||
### Expected Challenges
|
||
|
||
1. **Timing:** Device expects responses within ~100ms
|
||
2. **Checksums:** May need to implement data validation
|
||
3. **Atomic Operations:** Write + Save must be atomic
|
||
4. **Device State:** Must track active profile and settings
|
||
5. **Error Recovery:** Handle disconnects and reconnection
|
||
|
||
### Next Steps
|
||
|
||
1. **Implement Core Protocol:** Add HID report functions to libazeron
|
||
2. **Button Mapping UI:** Create user interface for configuring 30 buttons
|
||
3. **Joystick Configuration:** Add analog stick settings
|
||
4. **Profile Management:** Implement profile switching and persistence
|
||
5. **Testing:** Comprehensive test suite with all features
|
||
6. **Documentation:** Update user documentation
|
||
|
||
### Contributing
|
||
|
||
If you discover protocol details:
|
||
|
||
1. Document the command format
|
||
2. Provide USB capture files (PCAP format)
|
||
3. Include test code if available
|
||
4. Update this documentation
|
||
5. Submit pull request with changes
|
||
|
||
### Safety Notes
|
||
|
||
- Always test with backup configurations
|
||
- Be prepared to reset device to factory defaults
|
||
- Don't send malformed packets to device
|
||
- Monitor device temperature during testing
|
||
- Stop if device behaves unexpectedly
|
||
- Keep original configuration files as backup
|
||
|
||
## Acknowledgments
|
||
|
||
Special thanks to the Azeron community for providing captures and testing assistance during the reverse engineering process. |