The open source OpenXR runtime
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

d/wmr: Cache controller configs

Store controller calibration block into a cache file and
use that if available, to save time on subsequent startups

Re-disable reading of extra firmware blocks, accidentally
left enabled during recent controller/connection splitup

authored by

Jan Schmidt and committed by
Jakob Bornecrantz
7009c643 ac84cd4d

+175 -48
+175 -48
src/xrt/drivers/wmr/wmr_controller_base.c
··· 17 17 #include "math/m_vec2.h" 18 18 #include "math/m_predict.h" 19 19 20 + #include "util/u_file.h" 20 21 #include "util/u_var.h" 21 22 #include "util/u_misc.h" 22 23 #include "util/u_time.h" ··· 28 29 #include "wmr_controller_base.h" 29 30 #include "wmr_config_key.h" 30 31 32 + #include <ctype.h> 31 33 #include <stdio.h> 32 34 #include <stdlib.h> 33 35 #include <string.h> ··· 48 50 WMR_DEBUG_HEX(wcb, buf, length); \ 49 51 } while (0); 50 52 51 - 52 - //! file path to store controller JSON configuration blocks that 53 - //! read from the firmware. 54 - DEBUG_GET_ONCE_OPTION(wmr_ctrl_config_path, "WMR_CONFIG_DUMP", NULL) 55 53 56 54 static inline struct wmr_controller_base * 57 55 wmr_controller_base(struct xrt_device *p) ··· 146 144 continue; 147 145 } 148 146 149 - WMR_TRACE(wcb, "Controller fw read returned %d bytes", size); 150 147 if (response->buf[0] == response_code) { 148 + WMR_TRACE(wcb, "Controller fw read returned %d bytes", size); 151 149 if (size != sizeof(response->buf) || (response->response.cmd_id_echo != fw_cmd->cmd.cmd_id)) { 152 150 WMR_DEBUG( 153 151 wcb, "Unexpected fw response - size %d (expected %zu), cmd_id_echo %u != cmd_id %u", ··· 239 237 * Config functions. 240 238 * 241 239 */ 242 - 243 240 static bool 244 - read_controller_config(struct wmr_controller_base *wcb) 241 + read_controller_fw_info(struct wmr_controller_base *wcb, 242 + uint32_t *fw_revision, 243 + uint16_t *calibration_size, 244 + char serial_no[16]) 245 245 { 246 - unsigned char *data = NULL; 247 - unsigned char *config_json_block; 246 + uint8_t *data = NULL; 248 247 size_t data_size; 249 248 int ret; 250 249 251 - #if 1 252 - // There are extra firmware blocks that can be read from 253 - // the controllers, like these. Serial numbers and 254 - // USB PID/VID are visible in them, but it's not clear 255 - // what the layout is and we don't use them currently, 256 - // so this if 0 code is just exemplary. 257 - 258 - // Read 0x00 block 250 + /* FW block 0 contains the FW revision (offset 0x14, size 4) and 251 + * calibration block size (offset 0x34 size 2) */ 259 252 ret = wmr_read_fw_block(wcb, 0x0, &data, &data_size); 260 - if (ret < 0 || data == NULL) 253 + if (ret < 0 || data == NULL) { 254 + WMR_ERROR(wcb, "Failed to read FW info block 0"); 261 255 return false; 256 + } 257 + if (data_size < 0x36) { 258 + WMR_ERROR(wcb, "Failed to read FW info block 0 - too short"); 259 + free(data); 260 + return false; 261 + } 262 + 263 + 264 + const unsigned char *tmp = data + 0x14; 265 + *fw_revision = read32(&tmp); 266 + tmp = data + 0x34; 267 + *calibration_size = read16(&tmp); 268 + 262 269 free(data); 263 - data = NULL; 264 270 265 - // Read serials 266 - ret = wmr_read_fw_block(wcb, 0x03, &data, &data_size); 267 - if (ret < 0 || data == NULL) 271 + /* FW block 3 contains the controller serial number at offset 272 + * 0x84, size 16 bytes */ 273 + ret = wmr_read_fw_block(wcb, 0x3, &data, &data_size); 274 + if (ret < 0 || data == NULL) { 275 + WMR_ERROR(wcb, "Failed to read FW info block 3"); 268 276 return false; 277 + } 278 + if (data_size < 0x94) { 279 + WMR_ERROR(wcb, "Failed to read FW info block 3 - too short"); 280 + free(data); 281 + return false; 282 + } 283 + 284 + memcpy(serial_no, data + 0x84, 0x10); 285 + serial_no[16] = '\0'; 286 + 269 287 free(data); 270 - data = NULL; 288 + return true; 289 + } 290 + 291 + char * 292 + build_cache_filename(char *serial_no) 293 + { 294 + int outlen = strlen("controller-") + strlen(serial_no) + strlen(".json") + 1; 295 + char *out = malloc(outlen); 296 + int ret = snprintf(out, outlen, "controller-%s.json", serial_no); 297 + 298 + assert(ret <= outlen); 299 + (void)ret; 300 + 301 + // Make sure the filename is valid 302 + for (char *cur = out; *cur != '\0'; cur++) { 303 + if (!isalnum(*cur) && *cur != '.') { 304 + *cur = '_'; 305 + } 306 + } 307 + 308 + return out; 309 + } 310 + 311 + static bool 312 + read_calibration_cache(struct wmr_controller_base *wcb, char *cache_filename) 313 + { 314 + FILE *f = u_file_open_file_in_config_dir_subpath("wmr", cache_filename, "r"); 315 + uint8_t *buffer = NULL; 316 + 317 + if (f == NULL) { 318 + WMR_DEBUG(wcb, "Failed to open wmr/%s cache file or it doesn't exist.", cache_filename); 319 + return false; 320 + } 321 + 322 + // Read the file size to allocate a read buffer 323 + fseek(f, 0L, SEEK_END); 324 + size_t file_size = ftell(f); 325 + 326 + // Reset and read the data 327 + fseek(f, 0L, SEEK_SET); 328 + 329 + buffer = calloc(file_size + 1, sizeof(uint8_t)); 330 + if (buffer == NULL) { 331 + goto fail; 332 + } 333 + buffer[file_size] = '\0'; 334 + 335 + size_t ret = fread(buffer, sizeof(char), file_size, f); 336 + if (ret != file_size) { 337 + WMR_WARN(wcb, "Cache file wmr/%s failed to read %u bytes (got %u)", cache_filename, (int)file_size, 338 + (int)ret); 339 + goto fail; 340 + } 341 + 342 + if (!wmr_controller_config_parse(&wcb->config, (char *)buffer, wcb->log_level)) { 343 + WMR_WARN(wcb, "Cache file wmr/%s contains invalid JSON. Ignoring", cache_filename); 344 + goto fail; 345 + } 346 + 347 + fclose(f); 348 + free(buffer); 349 + 350 + return true; 271 351 352 + fail: 353 + if (buffer) { 354 + free(buffer); 355 + } 356 + fclose(f); 357 + return false; 358 + } 359 + 360 + static void 361 + write_calibration_cache(struct wmr_controller_base *wcb, char *cache_filename, uint8_t *data, size_t data_size) 362 + { 363 + FILE *f = u_file_open_file_in_config_dir_subpath("wmr", cache_filename, "w"); 364 + if (f == NULL) { 365 + return; 366 + } 367 + 368 + size_t ret = fwrite(data, sizeof(char), data_size, f); 369 + if (ret != data_size) { 370 + fclose(f); 371 + return; 372 + } 373 + 374 + fclose(f); 375 + } 376 + 377 + static bool 378 + read_controller_config(struct wmr_controller_base *wcb) 379 + { 380 + unsigned char *config_json_block; 381 + int ret; 382 + uint32_t fw_revision; 383 + uint16_t calibration_size; 384 + char serial_no[16 + 1]; 385 + 386 + if (!read_controller_fw_info(wcb, &fw_revision, &calibration_size, serial_no)) { 387 + return false; 388 + } 389 + 390 + WMR_INFO(wcb, "Reading configuration for controller serial %s. FW revision %x", serial_no, fw_revision); 391 + 392 + #if 0 393 + /* WMR also reads block 0x14, which seems to have some FW revision info, 394 + * but we don't use it */ 272 395 // Read block 0x14 273 396 ret = wmr_read_fw_block(wcb, 0x14, &data, &data_size); 274 397 if (ret < 0 || data == NULL) ··· 278 401 #endif 279 402 280 403 // Read config block 281 - ret = wmr_read_fw_block(wcb, 0x02, &data, &data_size); 282 - if (ret < 0 || data == NULL || data_size < 2) 283 - return false; 404 + WMR_INFO(wcb, "Reading %s controller config", 405 + wcb->base.device_type == XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER ? "left" : "right"); 284 406 285 - /* De-obfuscate the JSON config */ 286 - config_json_block = data + sizeof(uint16_t); 287 - for (unsigned int i = 0; i < data_size - sizeof(uint16_t); i++) { 288 - config_json_block[i] ^= wmr_config_key[i % sizeof(wmr_config_key)]; 289 - } 407 + // Check if we have it cached already 408 + char *cache_filename = build_cache_filename(serial_no); 290 409 291 - #if 1 292 - // Option to dump config block to a path. Later, these will be 293 - // stored in a cache to save time on future startup 294 - const char *dump_dir = debug_get_option_wmr_ctrl_config_path(); 295 - if (dump_dir != NULL) { 296 - char fname[256]; 410 + if (!read_calibration_cache(wcb, cache_filename)) { 411 + unsigned char *data = NULL; 412 + size_t data_size; 297 413 298 - int device_id = (wcb->base.device_type == XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER) ? 0 : 1; 414 + ret = wmr_read_fw_block(wcb, 0x02, &data, &data_size); 415 + if (ret < 0 || data == NULL || data_size < 2) { 416 + free(cache_filename); 417 + return false; 418 + } 299 419 300 - sprintf(fname, "%s/controller-%d-fw.txt", dump_dir, device_id); 301 - WMR_INFO(wcb, "Storing controller config JSON to %s", fname); 420 + /* De-obfuscate the JSON config */ 421 + config_json_block = data + sizeof(uint16_t); 422 + for (unsigned int i = 0; i < data_size - sizeof(uint16_t); i++) { 423 + config_json_block[i] ^= wmr_config_key[i % sizeof(wmr_config_key)]; 424 + } 302 425 303 - FILE *f = fopen(fname, "w"); 304 - fwrite(config_json_block, data_size - 2, 1, f); 305 - fclose(f); 306 - } 307 - #endif 426 + if (!wmr_controller_config_parse(&wcb->config, (char *)config_json_block, wcb->log_level)) { 427 + free(cache_filename); 428 + free(data); 429 + return false; 430 + } 308 431 309 - if (!wmr_controller_config_parse(&wcb->config, (char *)config_json_block, wcb->log_level)) { 432 + /* Write to the cache file (if it fails, ignore it, it's just a cache) */ 433 + write_calibration_cache(wcb, cache_filename, config_json_block, data_size - sizeof(uint16_t)); 310 434 free(data); 311 - return false; 435 + } else { 436 + WMR_DEBUG(wcb, "Read %s controller config from cache %s", 437 + wcb->base.device_type == XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER ? "left" : "right", 438 + cache_filename); 312 439 } 440 + free(cache_filename); 313 441 314 442 WMR_DEBUG(wcb, "Parsed %d LED entries from controller calibration", wcb->config.led_count); 315 443 316 - free(data); 317 444 return true; 318 445 } 319 446