1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "vehicle-hal-tool" 18 19 #include <inttypes.h> 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <string.h> 23 24 #include <log/log.h> 25 26 #include <hardware/hardware.h> 27 #include <hardware/vehicle.h> 28 29 void usage() { 30 printf("Usage: " 31 "./vehicle-hal-tool [-l] [-m -p -t [-v]]\n" 32 "-l - List properties\n" 33 "-m - Mode (cannot be used with -l). Accepted strings: get, set or sub.\n" 34 "-p - Property (only used with -m)\n" 35 "-t - Type (only used with -m)\n" 36 "-w - Wait time in seconds (only used with -m set to sub)\n" 37 "-v - Value to which vehicle_prop_value is set\n" 38 "Depending on the type pass the value:\n" 39 "Int: pass a quoted integer\n" 40 "Float: pass a quoted float\n" 41 "Int array: pass a quoted space delimited int array, eg: \"1 2 3 4\" for\n:" 42 "setting int32_array's all 4 elements (see VEHICLE_VALUE_TYPE_INT32_VEC4\n" 43 "String: pass a normal string\n\n" 44 "The configurations to use the tool are as follows:\n" 45 "List Properties\n" 46 "---------------\n" 47 "./vehicle-hal-tool -l \n" 48 "Lists the various properties defined in HAL implementation. Use this to check if " 49 "the HAL implementation is correctly set up and exposing the capabilities correctly.\n" 50 51 "Get Properties\n" 52 "---------------\n" 53 "./vehicle-hal-tool -m get -p <prop> -t <type> [-v <vehicle_prop_value>]\n" 54 "Example: ./vehicle-hal-tool -m get -p 1028 -t 3 # VEHICLE_PROPERTY_DRIVING_STATUS\n" 55 "./vehicle-hal-tool -m get -p 257 -t 1 # VEHICLE_PROPERTY_INFO_MAKE\n" 56 "./vehicle-hal-tool -m get -p 2049 -t 19 -v \"3 0 0 0\"\n" 57 " # VEHICLE_PROPERTY_RADIO_PRESET\n" 58 "with preset value set to 3.\n\n" 59 "Set properties\n" 60 "--------------\n" 61 "./vehicle-hal-tool -m set -p 10 -t 1 -v random_property\n" 62 "Set properties may not be applicable to most properties\n\n" 63 "Subscribe properties\n" 64 "--------------------\n" 65 "Subscribes to be notified about a property change (depending on whether\n" 66 "it is a on change property or a continuous property) for seconds provided\n" 67 "as -w paramter.\n" 68 "./vehicle-hal-tool -m sub -p 1028 -w 10\n" 69 ); 70 } 71 72 void list_all_properties(vehicle_hw_device_t *device) { 73 int num_configs = -1; 74 const vehicle_prop_config_t *configs = device->list_properties(device, &num_configs); 75 if (num_configs < 0) { 76 printf("List configs error. %d", num_configs); 77 exit(1); 78 } 79 80 printf("Listing configs\n--------------------\n"); 81 int i = 0; 82 for (i = 0; i < num_configs; i++) { 83 const vehicle_prop_config_t *config_temp = configs + i; 84 printf("Property ID: %d\n" 85 "Property config_flags: %d\n" 86 "Property change mode: %d\n" 87 "Property min sample rate: %f\n" 88 "Property max sample rate: %f\n", 89 config_temp->prop, config_temp->config_flags, config_temp->change_mode, 90 config_temp->min_sample_rate, config_temp->max_sample_rate); 91 } 92 } 93 94 static void print_property(const vehicle_prop_value_t *data) { 95 switch (data->value_type) { 96 case VEHICLE_VALUE_TYPE_STRING: 97 printf("Value type: STRING\n Size: %d\n", data->value.str_value.len); 98 // This implementation only supports ASCII. 99 char *ascii_out = (char *) malloc((data->value.str_value.len + 1) * sizeof(char)); 100 memcpy(ascii_out, data->value.str_value.data, data->value.str_value.len); 101 ascii_out[data->value.str_value.len] = '\0'; 102 printf("Value Type: STRING %s\n", ascii_out); 103 free(ascii_out); 104 break; 105 case VEHICLE_VALUE_TYPE_BYTES: 106 printf("Value type: BYTES\n Size: %d", data->value.bytes_value.len); 107 for (int i = 0; i < data->value.bytes_value.len; i++) { 108 if ((i % 16) == 0) { 109 printf("\n %04X: ", i); 110 } 111 printf("%02X ", data->value.bytes_value.data[i]); 112 } 113 printf("\n"); 114 break; 115 case VEHICLE_VALUE_TYPE_BOOLEAN: 116 printf("Value type: BOOLEAN\nValue: %d\n", data->value.boolean_value); 117 break; 118 case VEHICLE_VALUE_TYPE_ZONED_BOOLEAN: 119 printf("Value type: ZONED_BOOLEAN\nZone: %d\n", data->zone); 120 printf("Value: %d\n", data->value.boolean_value); 121 break; 122 case VEHICLE_VALUE_TYPE_INT64: 123 printf("Value type: INT64\nValue: %" PRId64 "\n", data->value.int64_value); 124 break; 125 case VEHICLE_VALUE_TYPE_FLOAT: 126 printf("Value type: FLOAT\nValue: %f\n", data->value.float_value); 127 break; 128 case VEHICLE_VALUE_TYPE_FLOAT_VEC2: 129 printf("Value type: FLOAT_VEC2\nValue[0]: %f ", data->value.float_array[0]); 130 printf("Value[1]: %f\n", data->value.float_array[1]); 131 break; 132 case VEHICLE_VALUE_TYPE_FLOAT_VEC3: 133 printf("Value type: FLOAT_VEC3\nValue[0]: %f ", data->value.float_array[0]); 134 printf("Value[1]: %f ", data->value.float_array[1]); 135 printf("Value[2]: %f\n", data->value.float_array[2]); 136 break; 137 case VEHICLE_VALUE_TYPE_FLOAT_VEC4: 138 printf("Value type: FLOAT_VEC4\nValue[0]: %f ", data->value.float_array[0]); 139 printf("Value[1]: %f ", data->value.float_array[1]); 140 printf("Value[2]: %f ", data->value.float_array[2]); 141 printf("Value[3]: %f\n", data->value.float_array[3]); 142 break; 143 case VEHICLE_VALUE_TYPE_INT32: 144 printf("Value type: INT32\nValue: %d\n", data->value.int32_value); 145 break; 146 case VEHICLE_VALUE_TYPE_INT32_VEC2: 147 printf("Value type: INT32_VEC2\nValue[0]: %d ", data->value.int32_array[0]); 148 printf("Value[1]: %d\n", data->value.int32_array[1]); 149 break; 150 case VEHICLE_VALUE_TYPE_INT32_VEC3: 151 printf("Value type: INT32_VEC3\nValue[0]: %d ", data->value.int32_array[0]); 152 printf("Value[1]: %d ", data->value.int32_array[1]); 153 printf("Value[2]: %d\n", data->value.int32_array[2]); 154 break; 155 case VEHICLE_VALUE_TYPE_INT32_VEC4: 156 printf("Value type: INT32_VEC4\nValue[0]: %d ", data->value.int32_array[0]); 157 printf("Value[1]: %d ", data->value.int32_array[1]); 158 printf("Value[2]: %d ", data->value.int32_array[2]); 159 printf("Value[3]: %d\n", data->value.int32_array[3]); 160 break; 161 case VEHICLE_VALUE_TYPE_ZONED_FLOAT: 162 printf("Value type: ZONED_FLOAT\nZone: %d ", data->zone); 163 printf("Value: %f\n", data->value.float_value); 164 break; 165 case VEHICLE_VALUE_TYPE_ZONED_FLOAT_VEC2: 166 printf("Value type: ZONED_FLOAT_VEC2\nZone: %d ", data->zone); 167 printf("Value[0]: %f", data->value.float_array[0]); 168 printf("Value[1]: %f\n", data->value.float_array[1]); 169 break; 170 case VEHICLE_VALUE_TYPE_ZONED_FLOAT_VEC3: 171 printf("Value type: ZONED_FLOAT_VEC3\nZone: %d ", data->zone); 172 printf("Value[0]: %f ", data->value.float_array[0]); 173 printf("Value[1]: %f ", data->value.float_array[1]); 174 printf("Value[2]: %f\n", data->value.float_array[2]); 175 break; 176 case VEHICLE_VALUE_TYPE_ZONED_FLOAT_VEC4: 177 printf("Value type: ZONED_FLOAT_VEC4\nZone: %d ", data->zone); 178 printf("Value[0]: %f ", data->value.float_array[0]); 179 printf("Value[1]: %f ", data->value.float_array[1]); 180 printf("Value[2]: %f ", data->value.float_array[2]); 181 printf("Value[3]: %f\n", data->value.float_array[3]); 182 break; 183 case VEHICLE_VALUE_TYPE_ZONED_INT32: 184 printf("Value type: ZONED_INT32\nZone: %d ", data->zone); 185 printf("Value: %d\n", data->value.int32_value); 186 break; 187 case VEHICLE_VALUE_TYPE_ZONED_INT32_VEC2: 188 printf("Value type: ZONED_INT32_VEC2\nZone: %d ", data->zone); 189 printf("Value[0]: %d ", data->value.int32_array[0]); 190 printf("Value[1]: %d\n", data->value.int32_array[1]); 191 break; 192 case VEHICLE_VALUE_TYPE_ZONED_INT32_VEC3: 193 printf("Value type: ZONED_INT32_VEC3\nZone: %d ", data->zone); 194 printf("Value[0]: %d ", data->value.int32_array[0]); 195 printf("Value[1]: %d ", data->value.int32_array[1]); 196 printf("Value[2]: %d\n", data->value.int32_array[2]); 197 break; 198 case VEHICLE_VALUE_TYPE_ZONED_INT32_VEC4: 199 printf("Value type: ZONED_INT32_VEC4\nZone: %d ", data->zone); 200 printf("Value[0]: %d ", data->value.int32_array[0]); 201 printf("Value[1]: %d ", data->value.int32_array[1]); 202 printf("Value[2]: %d ", data->value.int32_array[2]); 203 printf("Value[3]: %d\n", data->value.int32_array[3]); 204 break; 205 default: 206 printf("Value type not yet handled: %d.\n", data->value_type); 207 } 208 } 209 210 void get_property( 211 vehicle_hw_device_t *device, int32_t property, int32_t type, char *value_string) { 212 vehicle_prop_value_t *data = (vehicle_prop_value_t *) malloc (sizeof(vehicle_prop_value_t)); 213 214 // Parse the string according to type. 215 if (value_string != NULL && strlen(value_string) > 0) { 216 switch (type) { 217 case VEHICLE_VALUE_TYPE_INT32: 218 sscanf(value_string, "%d", &(data->value.int32_value)); 219 break; 220 case VEHICLE_VALUE_TYPE_INT32_VEC4: 221 { 222 int32_t vec[4]; 223 sscanf(value_string, "%d %d %d %d", &vec[0], &vec[1], &vec[2], &vec[3]); 224 memcpy(data->value.int32_array, vec, sizeof(vec)); 225 break; 226 } 227 default: 228 printf("%s Setting value type not supported: %d\n", __func__, type); 229 exit(1); 230 } 231 } 232 233 data->prop = property; 234 int ret_code = device->get(device, data); 235 if (ret_code != 0) { 236 printf("Cannot get property: %d\n", ret_code); 237 exit(1); 238 } 239 240 // We simply convert the data into the type mentioned by the result of the 241 // get call. 242 printf("Get output\n------------\n"); 243 print_property(data); 244 free(data); 245 } 246 247 void set_property(vehicle_hw_device_t *device, 248 int32_t property, 249 int32_t type, 250 char *data) { 251 vehicle_prop_value_t vehicle_data; 252 vehicle_data.prop = property; 253 vehicle_data.value_type = type; 254 int32_t zone = 0; 255 float value = 0.0; 256 switch (type) { 257 case VEHICLE_VALUE_TYPE_STRING: 258 // TODO: Make the code generic to UTF8 characters. 259 vehicle_data.value.str_value.len = strlen(data); 260 vehicle_data.value.str_value.data = 261 (uint8_t *) malloc (strlen(data) * sizeof(uint8_t)); 262 memcpy(vehicle_data.value.str_value.data, data, strlen(data) + 1); 263 break; 264 case VEHICLE_VALUE_TYPE_BYTES: { 265 int len = strlen(data); 266 int numBytes = (len + 1) / 3; 267 uint8_t *buf = calloc(numBytes, sizeof(uint8_t)); 268 char *byte = strtok(data, " "); 269 for (int i = 0; byte != NULL && i < numBytes; i++) { 270 buf[i] = strtol(data, NULL, 16); 271 byte = strtok(NULL, " "); 272 } 273 vehicle_data.value.bytes_value.len = numBytes; 274 vehicle_data.value.bytes_value.data = buf; 275 } 276 break; 277 case VEHICLE_VALUE_TYPE_BOOLEAN: 278 vehicle_data.value.boolean_value = atoi(data); 279 break; 280 case VEHICLE_VALUE_TYPE_ZONED_BOOLEAN: 281 sscanf(data, "%d %d", &vehicle_data.zone, 282 &vehicle_data.value.boolean_value); 283 break; 284 case VEHICLE_VALUE_TYPE_INT64: 285 vehicle_data.value.int64_value = atoi(data); 286 break; 287 case VEHICLE_VALUE_TYPE_FLOAT: 288 vehicle_data.value.float_value = atof(data); 289 break; 290 case VEHICLE_VALUE_TYPE_FLOAT_VEC2: 291 sscanf(data, "%f %f", &vehicle_data.value.float_array[0], 292 &vehicle_data.value.float_array[1]); 293 break; 294 case VEHICLE_VALUE_TYPE_FLOAT_VEC3: 295 sscanf(data, "%f %f %f", &vehicle_data.value.float_array[0], 296 &vehicle_data.value.float_array[1], 297 &vehicle_data.value.float_array[2]); 298 break; 299 case VEHICLE_VALUE_TYPE_FLOAT_VEC4: 300 sscanf(data, "%f %f %f %f", &vehicle_data.value.float_array[0], 301 &vehicle_data.value.float_array[1], 302 &vehicle_data.value.float_array[2], 303 &vehicle_data.value.float_array[3]); 304 break; 305 case VEHICLE_VALUE_TYPE_INT32: 306 vehicle_data.value.int32_value = atoi(data); 307 break; 308 case VEHICLE_VALUE_TYPE_INT32_VEC2: 309 sscanf(data, "%d %d", &vehicle_data.value.int32_array[0], 310 &vehicle_data.value.int32_array[1]); 311 break; 312 case VEHICLE_VALUE_TYPE_INT32_VEC3: 313 sscanf(data, "%d %d %d", &vehicle_data.value.int32_array[0], 314 &vehicle_data.value.int32_array[1], 315 &vehicle_data.value.int32_array[2]); 316 break; 317 case VEHICLE_VALUE_TYPE_INT32_VEC4: 318 sscanf(data, "%d %d %d %d", &vehicle_data.value.int32_array[0], 319 &vehicle_data.value.int32_array[1], 320 &vehicle_data.value.int32_array[2], 321 &vehicle_data.value.int32_array[3]); 322 break; 323 case VEHICLE_VALUE_TYPE_ZONED_FLOAT: 324 sscanf(data, "%d %f", &zone, &value); 325 vehicle_data.zone = zone; 326 vehicle_data.value.float_value = value; 327 break; 328 case VEHICLE_VALUE_TYPE_ZONED_FLOAT_VEC2: 329 sscanf(data, "%d %f %f", &vehicle_data.zone, 330 &vehicle_data.value.float_array[0], 331 &vehicle_data.value.float_array[1]); 332 break; 333 case VEHICLE_VALUE_TYPE_ZONED_FLOAT_VEC3: 334 sscanf(data, "%d %f %f %f", &vehicle_data.zone, 335 &vehicle_data.value.float_array[0], 336 &vehicle_data.value.float_array[1], 337 &vehicle_data.value.float_array[2]); 338 break; 339 case VEHICLE_VALUE_TYPE_ZONED_FLOAT_VEC4: 340 sscanf(data, "%d %f %f %f %f", &vehicle_data.zone, 341 &vehicle_data.value.float_array[0], 342 &vehicle_data.value.float_array[1], 343 &vehicle_data.value.float_array[2], 344 &vehicle_data.value.float_array[3]); 345 break; 346 case VEHICLE_VALUE_TYPE_ZONED_INT32: 347 sscanf(data, "%d %d", &vehicle_data.zone, 348 &vehicle_data.value.int32_value); 349 break; 350 case VEHICLE_VALUE_TYPE_ZONED_INT32_VEC2: 351 sscanf(data, "%d %d %d", &vehicle_data.zone, 352 &vehicle_data.value.int32_array[0], 353 &vehicle_data.value.int32_array[1]); 354 break; 355 case VEHICLE_VALUE_TYPE_ZONED_INT32_VEC3: 356 sscanf(data, "%d %d %d %d", &vehicle_data.zone, 357 &vehicle_data.value.int32_array[0], 358 &vehicle_data.value.int32_array[1], 359 &vehicle_data.value.int32_array[2]); 360 break; 361 case VEHICLE_VALUE_TYPE_ZONED_INT32_VEC4: 362 sscanf(data, "%d %d %d %d %d", &vehicle_data.zone, 363 &vehicle_data.value.int32_array[0], 364 &vehicle_data.value.int32_array[1], 365 &vehicle_data.value.int32_array[2], 366 &vehicle_data.value.int32_array[3]); 367 break; 368 default: 369 printf("set_property: Value type not yet handled: %d\n", type); 370 exit(1); 371 } 372 printf("Setting Property id: %d\n", vehicle_data.prop); 373 print_property(&vehicle_data); 374 375 int ret_code = device->set(device, &vehicle_data); 376 if (ret_code != 0) { 377 printf("Cannot set property: %d\n", ret_code); 378 exit(1); 379 } 380 } 381 382 int vehicle_event_callback(const vehicle_prop_value_t *event_data) { 383 // Print what we got. 384 printf("Got some value from callback property: %d\n", event_data->prop); 385 printf("Timestamp: %" PRId64 "\n", event_data->timestamp); 386 print_property(event_data); 387 return 0; 388 } 389 390 int vehicle_error_callback(int32_t error_code, int32_t property, int32_t operation) { 391 // Print what we got. 392 printf("Error code obtained: %d\n", error_code); 393 return 0; 394 } 395 396 void subscribe_to_property( 397 vehicle_hw_device_t *device, 398 int32_t prop, 399 float sample_rate, 400 uint32_t wait_in_seconds) { 401 // Init the device with a callback. 402 int ret_code = device->subscribe(device, prop, 0, 0); 403 if (ret_code != 0) { 404 printf("Could not subscribe: %d\n", ret_code); 405 exit(1); 406 } 407 408 // Callbacks will happen on one of the threads created by the HAL hence we 409 // can simply sleep here and see the output. 410 sleep(wait_in_seconds); 411 412 // Unsubscribe and uninit. 413 ret_code = device->unsubscribe(device, prop); 414 if (ret_code != 0) { 415 printf("Error unsubscribing the HAL, still continuining to uninit HAL ..."); 416 } 417 } 418 419 int main(int argc, char* argv[]) { 420 // Open the vehicle module and just ask for the list of properties. 421 const hw_module_t *hw_module = NULL; 422 int ret_code = hw_get_module(VEHICLE_HARDWARE_MODULE_ID, &hw_module); 423 if (ret_code != 0) { 424 printf("Cannot open the hw module. Does the HAL exist? %d\n", ret_code); 425 return -1; 426 } 427 428 vehicle_module_t *vehicle_module = (vehicle_module_t *)(hw_module); 429 hw_device_t *device = NULL; 430 ret_code = vehicle_module->common.methods->open(hw_module, NULL, &device); 431 if (!device) { 432 printf("Cannot open the hw device: %d\n", ret_code); 433 return -1; 434 } 435 vehicle_hw_device_t *vehicle_device = (vehicle_hw_device_t *) (device); 436 printf("HAL Loaded!\n"); 437 438 vehicle_device->init(vehicle_device, vehicle_event_callback, vehicle_error_callback); 439 440 // If this is a list properties command - we check for -l command. 441 int list_properties = 0; 442 // Type of the property (see #defines in vehicle.h). 443 int property = -1; 444 // Type of the value of the property (see enum vehicle_value_type). 445 int type = -1; 446 // Whether the mode is "get" or "set". 447 char mode[100] = ""; 448 // Actual value as a string representation (supports only PODs for now). 449 // TODO: Support structures and complex types in the tool. 450 char value[100] = ""; 451 // Wait time for the subscribe type of calls. 452 // We keep a default in case the user does not specify one. 453 int wait_time_in_sec = 10; 454 // Sample rate for subscribe type of calls. 455 // Default value is 0 for onchange type of properties. 456 int sample_rate = 0; 457 // Int array string which represents the vehicle_value_t in array of 458 // numbers. See vehicle_prop_value_t.value.int32_array. 459 char int_array_string[1000]; int_array_string[0] = '\0'; 460 461 int opt; 462 while ((opt = getopt(argc, argv, "lm:p:t:v:w:s:")) != -1) { 463 switch (opt) { 464 case 'l': 465 list_properties = 1; 466 break; 467 case 'm': 468 strcpy(mode, optarg); 469 break; 470 case 'p': 471 property = atoi(optarg); 472 break; 473 case 't': 474 type = atoi(optarg); 475 break; 476 case 'v': 477 strcpy(value, optarg); 478 break; 479 case 'w': 480 wait_time_in_sec = atoi(optarg); 481 break; 482 case 's': 483 sample_rate = atoi(optarg); 484 break; 485 } 486 } 487 488 // We should have atleast one of list properties or mode (for get or set). 489 if (!list_properties && 490 !(!strcmp(mode, "get") || !strcmp(mode, "set") || !strcmp(mode, "sub"))) { 491 usage(); 492 exit(1); 493 } 494 495 if (list_properties) { 496 printf("Listing properties...\n"); 497 list_all_properties(vehicle_device); 498 } else if (!strcmp(mode, "get")) { 499 printf("Getting property ...\n"); 500 if (property == -1) { 501 printf("Use -p to pass a valid Property.\n"); 502 usage(); 503 exit(1); 504 } 505 506 int32_t int_array_list[4]; 507 int count = -1; 508 if (strlen(int_array_string) > 0) { 509 count = sscanf(int_array_string, "%d%d%d%d", 510 &int_array_list[0], &int_array_list[1], &int_array_list[2], &int_array_list[3]); 511 } 512 513 get_property(vehicle_device, property, type, value); 514 } else if (!strcmp(mode, "set")) { 515 printf("Setting property ...\n"); 516 if (property == -1 || type == -1) { 517 printf("Use -p to pass a valid Property and -t to pass a valid Type.\n"); 518 usage(); 519 exit(1); 520 } 521 set_property(vehicle_device, property, type, value); 522 } else if (!strcmp(mode, "sub")) { 523 printf("Subscribing property ...\n"); 524 if (property == -1 || wait_time_in_sec <= 0) { 525 printf("Use -p to pass a valid property and -w to pass a valid wait time(s)\n"); 526 usage(); 527 exit(1); 528 } 529 subscribe_to_property(vehicle_device, property, sample_rate, wait_time_in_sec); 530 } 531 532 ret_code = vehicle_device->release(vehicle_device); 533 if (ret_code != 0) { 534 printf("Error uniniting HAL, exiting anyways."); 535 } 536 return 0; 537 } 538