1
+ // Based on hyperx_cflight.c
2
+ // Most requests taken off https://github.com/lehnification/hyperx-cloud-alpha-wireless-tray unless stated otherwise
3
+
4
+ // This file is part of HeadsetControl.
5
+
6
+ #include "../device.h"
7
+ #include "../utility.h"
8
+
9
+ #include <hidapi.h>
10
+ #include <math.h>
11
+ #include <stdlib.h>
12
+ #include <string.h>
13
+ #include <unistd.h>
14
+
15
+ // #define DEBUG
16
+
17
+ #ifdef DEBUG
18
+ #include <stdio.h>
19
+ #endif
20
+
21
+ static struct device device_calphaw ;
22
+
23
+ // timeout for hidapi requests in milliseconds
24
+ #define TIMEOUT 2000
25
+
26
+ #define VENDOR_HP 0x03f0 // cloud alpha sold with HP, Inc vendor id
27
+ #define ID_CALPHAW 0x098d
28
+
29
+ static const uint16_t PRODUCT_IDS [] = { ID_CALPHAW };
30
+
31
+ static int calphaw_request_battery (hid_device * device_handle );
32
+ static int calphaw_send_inactive_time (hid_device * device_handle , uint8_t num );
33
+ static int calphaw_send_sidetone (hid_device * device_handle , uint8_t num );
34
+ static int calphaw_switch_voice_prompts (hid_device * device_handle , uint8_t on );
35
+
36
+ void calphaw_init (struct device * * device )
37
+ {
38
+ device_calphaw .idVendor = VENDOR_HP ;
39
+ device_calphaw .idProductsSupported = PRODUCT_IDS ;
40
+ device_calphaw .numIdProducts = sizeof (PRODUCT_IDS ) / sizeof (PRODUCT_IDS [0 ]);
41
+ strncpy (device_calphaw .device_name , "HyperX Cloud Alpha Wireless" , sizeof (device_calphaw .device_name ));
42
+
43
+ device_calphaw .capabilities = B (CAP_BATTERY_STATUS ) | B (CAP_INACTIVE_TIME ) | B (CAP_SIDETONE ) | B (CAP_VOICE_PROMPTS );
44
+ device_calphaw .request_battery = & calphaw_request_battery ;
45
+ device_calphaw .send_inactive_time = & calphaw_send_inactive_time ;
46
+ device_calphaw .send_sidetone = & calphaw_send_sidetone ;
47
+ device_calphaw .switch_voice_prompts = & calphaw_switch_voice_prompts ;
48
+
49
+ * device = & device_calphaw ;
50
+ }
51
+
52
+ int calphaw_request_charge (hid_device * device_handle )
53
+ {
54
+ int r = 0 ;
55
+ // request charge info
56
+ uint8_t data_request [31 ] = { 0x21 , 0xbb , 0x0c };
57
+
58
+ r = hid_write (device_handle , data_request , sizeof (data_request ) / sizeof (data_request [0 ]));
59
+ if (r < 0 )
60
+ return r ;
61
+
62
+ uint8_t data_read [31 ];
63
+ r = hid_read_timeout (device_handle , data_read , 20 , TIMEOUT );
64
+ if (r < 0 )
65
+ return r ;
66
+ if (r == 0 ) // timeout
67
+ return HSC_ERROR ;
68
+
69
+ if (r == 0xf || r == 0x14 ) {
70
+ if (data_read [3 ] == 0x01 )
71
+ return 1 ;
72
+
73
+ return 0 ;
74
+ }
75
+
76
+ return HSC_ERROR ;
77
+ }
78
+
79
+ static int calphaw_request_battery (hid_device * device_handle )
80
+ {
81
+ if (calphaw_request_charge (device_handle ) == 1 )
82
+ return BATTERY_CHARGING ;
83
+
84
+ int r = 0 ;
85
+ // request battery info
86
+ uint8_t data_request [31 ] = { 0x21 , 0xbb , 0x0b }; // Data request reverse engineered by using USBPcap and Wireshark by @InfiniteLoop
87
+
88
+ r = hid_write (device_handle , data_request , sizeof (data_request ) / sizeof (data_request [0 ]));
89
+ if (r < 0 )
90
+ return r ;
91
+
92
+ uint8_t data_read [31 ];
93
+ r = hid_read_timeout (device_handle , data_read , 20 , TIMEOUT );
94
+ if (r < 0 )
95
+ return r ;
96
+ if (r == 0 ) // timeout
97
+ return HSC_ERROR ;
98
+
99
+ if (r == 0xf || r == 0x14 ) {
100
+
101
+ #ifdef DEBUG
102
+ printf ("calphaw_request_battery data_read 3: 0x%02x 4: 0x%02x 5: 0x%02x\n" , data_read [3 ], data_read [4 ], data_read [5 ]);
103
+ #endif
104
+
105
+ uint8_t batteryPercentage = data_read [3 ];
106
+
107
+ #ifdef DEBUG
108
+ uint32_t batteryVoltage = (data_read [4 ] << 8 ) | data_read [5 ]; // best assumtion this is voltage in mV
109
+ printf ("batteryVoltage: %d mV\n" , batteryVoltage );
110
+ #endif
111
+ return (int )(batteryPercentage );
112
+ }
113
+
114
+ return HSC_ERROR ;
115
+ }
116
+
117
+ static int calphaw_send_inactive_time (hid_device * device_handle , uint8_t num )
118
+ {
119
+ // taken from steelseries_arctis_7.c
120
+
121
+ uint8_t data_request [31 ] = { 0x21 , 0xbb , 0x12 , num };
122
+
123
+ int ret = hid_write (device_handle , data_request , sizeof (data_request ) / sizeof (data_request [0 ]));
124
+
125
+ return ret ;
126
+ }
127
+
128
+ int calphaw_toggle_sidetone (hid_device * device_handle , uint8_t num )
129
+ {
130
+ uint8_t data_request [31 ] = { 0x21 , 0xbb , 0x10 , num };
131
+
132
+ return hid_write (device_handle , data_request , sizeof (data_request ) / sizeof (data_request [0 ]));
133
+ ;
134
+ }
135
+
136
+ static int calphaw_send_sidetone (hid_device * device_handle , uint8_t num )
137
+ {
138
+ if (num == 0 ) {
139
+ return calphaw_toggle_sidetone (device_handle , 0 );
140
+ } else {
141
+ calphaw_toggle_sidetone (device_handle , 1 );
142
+ uint8_t data_request [31 ] = { 0x21 , 0xbb , 0x11 , num };
143
+
144
+ int ret = hid_write (device_handle , data_request , sizeof (data_request ) / sizeof (data_request [0 ]));
145
+
146
+ // looks to be a binary setting but I'm not sure
147
+
148
+ return ret ;
149
+ }
150
+
151
+ return HSC_ERROR ;
152
+ }
153
+
154
+ static int calphaw_switch_voice_prompts (hid_device * device_handle , uint8_t on )
155
+ {
156
+ uint8_t data_request [31 ] = { 0x21 , 0xbb , 0x13 , on };
157
+
158
+ return hid_write (device_handle , data_request , sizeof (data_request ) / sizeof (data_request [0 ]));
159
+ ;
160
+ }
0 commit comments