ckb-next  v0.2.8 at branch master
ckb-next driver for corsair devices
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
dpi.c
Go to the documentation of this file.
1 #include "dpi.h"
2 #include "usb.h"
3 
4 void cmd_dpi(usbdevice* kb, usbmode* mode, int dummy, const char* stages, const char* values){
5  (void)kb;
6  (void)dummy;
7 
8  int disable = 0;
9  ushort x, y;
10  // Try to scan X,Y values
11  if(sscanf(values, "%hu,%hu", &x, &y) != 2){
12  // If that doesn't work, scan single number
13  if(sscanf(values, "%hu", &x) == 1)
14  y = x;
15  else if(!strncmp(values, "off", 3))
16  // If the right side says "off", disable the level(s)
17  disable = 1;
18  else
19  // Otherwise, quit
20  return;
21  }
22  if((x == 0 || y == 0) && !disable)
23  return;
24  // Scan the left side for stage numbers (comma-separated)
25  int left = strlen(stages);
26  int position = 0, field = 0;
27  char stagename[3];
28  while(position < left && sscanf(stages + position, "%2[^,]%n", stagename, &field) == 1){
29  uchar stagenum;
30  if(sscanf(stagename, "%hhu", &stagenum) && stagenum < DPI_COUNT){
31  // Set DPI for this stage
32  if(disable){
33  mode->dpi.enabled &= ~(1 << stagenum);
34  mode->dpi.x[stagenum] = 0;
35  mode->dpi.y[stagenum] = 0;
36  } else {
37  mode->dpi.enabled |= 1 << stagenum;
38  mode->dpi.x[stagenum] = x;
39  mode->dpi.y[stagenum] = y;
40  }
41  }
42  if(stages[position += field] == ',')
43  position++;
44  }
45 }
46 
47 void cmd_dpisel(usbdevice* kb, usbmode* mode, int dummy1, int dummy2, const char* stage){
48  (void)kb;
49  (void)dummy1;
50  (void)dummy2;
51 
52  uchar stagenum;
53  if(sscanf(stage, "%hhu", &stagenum) != 1)
54  return;
55  if(stagenum > DPI_COUNT)
56  return;
57  mode->dpi.current = stagenum;
58 }
59 
60 void cmd_lift(usbdevice* kb, usbmode* mode, int dummy1, int dummy2, const char* height){
61  (void)kb;
62  (void)dummy1;
63  (void)dummy2;
64 
65  uchar heightnum;
66  if(sscanf(height, "%hhu", &heightnum) != 1)
67  return;
68  if(heightnum > LIFT_MAX || heightnum < LIFT_MIN)
69  return;
70  mode->dpi.lift = heightnum;
71 }
72 
73 void cmd_snap(usbdevice* kb, usbmode* mode, int dummy1, int dummy2, const char* enable){
74  (void)kb;
75  (void)dummy1;
76  (void)dummy2;
77 
78  if(!strcmp(enable, "on"))
79  mode->dpi.snap = 1;
80  if(!strcmp(enable, "off"))
81  mode->dpi.snap = 0;
82 }
83 
84 char* printdpi(const dpiset* dpi, const usbdevice* kb){
85  (void)kb;
86 
87  // Print all DPI settings
88  const int BUFFER_LEN = 100;
89  char* buffer = malloc(BUFFER_LEN);
90  int length = 0;
91  for(int i = 0; i < DPI_COUNT; i++){
92  // Print the stage number
93  int newlen = 0;
94  snprintf(buffer + length, BUFFER_LEN - length, length == 0 ? "%d%n" : " %d%n", i, &newlen);
95  length += newlen;
96  // Print the DPI settings
97  if(!(dpi->enabled & (1 << i)))
98  snprintf(buffer + length, BUFFER_LEN - length, ":off%n", &newlen);
99  else
100  snprintf(buffer + length, BUFFER_LEN - length, ":%u,%u%n", dpi->x[i], dpi->y[i], &newlen);
101  length += newlen;
102  }
103  return buffer;
104 }
105 
106 int updatedpi(usbdevice* kb, int force){
107  if(!kb->active)
108  return 0;
109  dpiset* lastdpi = &kb->profile->lastdpi;
110  dpiset* newdpi = &kb->profile->currentmode->dpi;
111  // Don't do anything if the settings haven't changed
112  if(!force && !lastdpi->forceupdate && !newdpi->forceupdate
113  && !memcmp(lastdpi, newdpi, sizeof(dpiset)))
114  return 0;
115  lastdpi->forceupdate = newdpi->forceupdate = 0;
116 
117  if (newdpi->current != lastdpi->current) {
118  // Before we switch the current DPI stage, make sure the stage we are
119  // switching to is both enabled and configured to the correct DPI.
120 
121  // Enable the stage if necessary.
122  if ((lastdpi->enabled & 1 << newdpi->current) == 0) {
123  uchar newenabled;
124  // If the new enabled flags contain both the current and previous
125  // stages, use it.
126  if (newdpi->enabled & 1 << newdpi->current &&
127  newdpi->enabled & 1 << lastdpi->current) {
128  newenabled = newdpi->enabled;
129  } else {
130  // Otherwise just enable the new stage. We'll write the actual
131  // requested flags after switching stages.
132  newenabled = lastdpi->enabled | 1 << newdpi->current;
133  }
134  uchar data_pkt[MSG_SIZE] = { 0x07, 0x13, 0x05, 0, newenabled };
135  if(!usbsend(kb, data_pkt, 1))
136  return -2;
137  // Cache the flags we wrote.
138  lastdpi->enabled = newenabled;
139  }
140  // Set the DPI for the new stage if necessary.
141  if (newdpi->x[newdpi->current] != lastdpi->x[newdpi->current] ||
142  newdpi->y[newdpi->current] != lastdpi->y[newdpi->current]) {
143  uchar data_pkt[MSG_SIZE] = { 0x07, 0x13, 0xd0, 0 };
144  data_pkt[2] |= newdpi->current;
145  *(ushort*)(data_pkt + 5) = newdpi->x[newdpi->current];
146  *(ushort*)(data_pkt + 7) = newdpi->y[newdpi->current];
147  if(!usbsend(kb, data_pkt, 1))
148  return -1;
149  // Set these values in the cache so we don't rewrite them.
150  lastdpi->x[newdpi->current] = newdpi->x[newdpi->current];
151  lastdpi->y[newdpi->current] = newdpi->y[newdpi->current];
152  }
153  // Set current DPI stage.
154  uchar data_pkt[MSG_SIZE] = { 0x07, 0x13, 0x02, 0, newdpi->current };
155  if(!usbsend(kb, data_pkt, 1))
156  return -2;
157  }
158 
159  // Send X/Y DPIs. We've changed to the new stage already so these can be set
160  // safely.
161  for(int i = 0; i < DPI_COUNT; i++){
162  if (newdpi->x[i] == lastdpi->x[i] && newdpi->y[i] == lastdpi->y[i])
163  continue;
164  uchar data_pkt[MSG_SIZE] = { 0x07, 0x13, 0xd0, 0 };
165  data_pkt[2] |= i;
166  *(ushort*)(data_pkt + 5) = newdpi->x[i];
167  *(ushort*)(data_pkt + 7) = newdpi->y[i];
168  if(!usbsend(kb, data_pkt, 1))
169  return -1;
170  }
171 
172  // Send settings
173  if (newdpi->enabled != lastdpi->enabled) {
174  uchar data_pkt[MSG_SIZE] = { 0x07, 0x13, 0x05, 0, newdpi->enabled };
175  if(!usbsend(kb, data_pkt, 1))
176  return -2;
177  }
178  if (newdpi->lift != lastdpi->lift) {
179  uchar data_pkt[MSG_SIZE] = { 0x07, 0x13, 0x03, 0, newdpi->lift };
180  if(!usbsend(kb, data_pkt, 1))
181  return -2;
182  }
183  if (newdpi->snap != lastdpi->snap) {
184  uchar data_pkt[MSG_SIZE] = { 0x07, 0x13, 0x04, 0, newdpi->snap, 0x05 };
185  if(!usbsend(kb, data_pkt, 1))
186  return -2;
187  }
188 
189  // Finished
190  memcpy(lastdpi, newdpi, sizeof(dpiset));
191  return 0;
192 }
193 
194 int savedpi(usbdevice* kb, dpiset* dpi, lighting* light){
195  // Send X/Y DPIs
196  for(int i = 0; i < DPI_COUNT; i++){
197  uchar data_pkt[MSG_SIZE] = { 0x07, 0x13, 0xd0, 1 };
198  data_pkt[2] |= i;
199  *(ushort*)(data_pkt + 5) = dpi->x[i];
200  *(ushort*)(data_pkt + 7) = dpi->y[i];
201  // Save the RGB value for this setting too
202  data_pkt[9] = light->r[LED_MOUSE + N_MOUSE_ZONES + i];
203  data_pkt[10] = light->g[LED_MOUSE + N_MOUSE_ZONES + i];
204  data_pkt[11] = light->b[LED_MOUSE + N_MOUSE_ZONES + i];
205  if(!usbsend(kb, data_pkt, 1))
206  return -1;
207  }
208 
209  // Send settings
210  uchar data_pkt[4][MSG_SIZE] = {
211  { 0x07, 0x13, 0x05, 1, dpi->enabled },
212  { 0x07, 0x13, 0x02, 1, dpi->current },
213  { 0x07, 0x13, 0x03, 1, dpi->lift },
214  { 0x07, 0x13, 0x04, 1, dpi->snap, 0x05 }
215  };
216  if(!usbsend(kb, data_pkt[0], 4))
217  return -2;
218  // Finished
219  return 0;
220 }
221 
222 int loaddpi(usbdevice* kb, dpiset* dpi, lighting* light){
223  // Ask for settings
224  uchar data_pkt[4][MSG_SIZE] = {
225  { 0x0e, 0x13, 0x05, 1, },
226  { 0x0e, 0x13, 0x02, 1, },
227  { 0x0e, 0x13, 0x03, 1, },
228  { 0x0e, 0x13, 0x04, 1, }
229  };
230  uchar in_pkt[4][MSG_SIZE];
231  for(int i = 0; i < 4; i++){
232  if(!usbrecv(kb, data_pkt[i], in_pkt[i]))
233  return -2;
234  if(memcmp(in_pkt[i], data_pkt[i], 4)){
235  ckb_err("Bad input header\n");
236  return -3;
237  }
238  }
239  // Copy data from device
240  dpi->enabled = in_pkt[0][4];
241  dpi->enabled &= (1 << DPI_COUNT) - 1;
242  dpi->current = in_pkt[1][4];
243  if(dpi->current >= DPI_COUNT)
244  dpi->current = 0;
245  dpi->lift = in_pkt[2][4];
246  if(dpi->lift < LIFT_MIN || dpi->lift > LIFT_MAX)
247  dpi->lift = LIFT_MIN;
248  dpi->snap = !!in_pkt[3][4];
249 
250  // Get X/Y DPIs
251  for(int i = 0; i < DPI_COUNT; i++){
252  uchar data_pkt[MSG_SIZE] = { 0x0e, 0x13, 0xd0, 1 };
253  uchar in_pkt[MSG_SIZE];
254  data_pkt[2] |= i;
255  if(!usbrecv(kb, data_pkt, in_pkt))
256  return -2;
257  if(memcmp(in_pkt, data_pkt, 4)){
258  ckb_err("Bad input header\n");
259  return -3;
260  }
261  // Copy to profile
262  dpi->x[i] = *(ushort*)(in_pkt + 5);
263  dpi->y[i] = *(ushort*)(in_pkt + 7);
264  light->r[LED_MOUSE + N_MOUSE_ZONES + i] = in_pkt[9];
265  light->g[LED_MOUSE + N_MOUSE_ZONES + i] = in_pkt[10];
266  light->b[LED_MOUSE + N_MOUSE_ZONES + i] = in_pkt[11];
267  }
268  // Finished. Set SW DPI light to the current hardware level
269  light->r[LED_MOUSE + 2] = light->r[LED_MOUSE + N_MOUSE_ZONES + dpi->current];
270  light->g[LED_MOUSE + 2] = light->g[LED_MOUSE + N_MOUSE_ZONES + dpi->current];
271  light->b[LED_MOUSE + 2] = light->b[LED_MOUSE + N_MOUSE_ZONES + dpi->current];
272  return 0;
273 }
#define MSG_SIZE
Definition: structures.h:176
void cmd_dpi(usbdevice *kb, usbmode *mode, int dummy, const char *stages, const char *values)
Definition: dpi.c:4
float y
Definition: main.c:66
usbprofile * profile
Definition: structures.h:221
uchar enabled
Definition: structures.h:63
void cmd_lift(usbdevice *kb, usbmode *mode, int dummy1, int dummy2, const char *height)
Definition: dpi.c:60
#define LED_MOUSE
Definition: keymap.h:39
usbmode * currentmode
Definition: structures.h:105
int savedpi(usbdevice *kb, dpiset *dpi, lighting *light)
Definition: dpi.c:194
#define ckb_err(fmt, args...)
Definition: includes.h:49
float x
Definition: main.c:66
#define N_MOUSE_ZONES
Definition: keymap.h:40
char * buffer
Definition: devnode.c:336
char active
Definition: structures.h:231
int updatedpi(usbdevice *kb, int force)
Definition: dpi.c:106
dpiset lastdpi
Definition: structures.h:108
dpiset dpi
Definition: structures.h:86
ushort x[6]
Definition: structures.h:59
unsigned char uchar
Definition: includes.h:24
void cmd_snap(usbdevice *kb, usbmode *mode, int dummy1, int dummy2, const char *enable)
Definition: dpi.c:73
#define LIFT_MIN
Definition: structures.h:55
uchar snap
Definition: structures.h:67
uchar lift
Definition: structures.h:65
double left
Definition: main.c:51
unsigned short ushort
Definition: includes.h:25
#define DPI_COUNT
Definition: structures.h:54
#define LIFT_MAX
Definition: structures.h:56
void cmd_dpisel(usbdevice *kb, usbmode *mode, int dummy1, int dummy2, const char *stage)
Definition: dpi.c:47
uchar g[152+12]
Definition: structures.h:75
uchar current
Definition: structures.h:61
#define usbrecv(kb, out_msg, in_msg)
usbrecv macro is used to wrap _usbrecv() with debugging information (file and lineno) ...
Definition: usb.h:288
Definitions for using USB interface.
char * printdpi(const dpiset *dpi, const usbdevice *kb)
Definition: dpi.c:84
ushort y[6]
Definition: structures.h:60
uchar b[152+12]
Definition: structures.h:76
#define usbsend(kb, messages, count)
usbsend macro is used to wrap _usbsend() with debugging information (file and lineno) ...
Definition: usb.h:271
uchar forceupdate
Definition: structures.h:69
uchar r[152+12]
Definition: structures.h:74
int loaddpi(usbdevice *kb, dpiset *dpi, lighting *light)
Definition: dpi.c:222