/* * Author: Brendan Le Foll * Author: Longwei Su * Copyright (c) 2015 Intel Corporation. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define IMRAA_CONF_FILE "/etc/imraa.conf" typedef struct mraa_io_objects_t { const char* type; int index; bool raw; const char* label; } mraa_io_objects_t; const char* imraa_list_serialport() { struct udev* udev; struct udev_enumerate* enumerate; struct udev_list_entry *devices, *dev_list_entry; struct udev_device* dev; const char* ret = NULL; udev = udev_new(); if (!udev) { printf("Can't create udev, check libudev\n"); exit(1); } enumerate = udev_enumerate_new(udev); udev_enumerate_add_match_subsystem(enumerate, "tty"); udev_enumerate_add_match_property(enumerate, "ID_VENDOR_ID", "8087"); udev_enumerate_add_match_property(enumerate, "ID_MODEL_ID", "0ab6"); //udev_enumerate_add_match_property(enumerate, "ID_SERIAL", "Intel_ARDUINO_101_AE6642SQ55000RS"); udev_enumerate_scan_devices(enumerate); devices = udev_enumerate_get_list_entry(enumerate); udev_list_entry_foreach(dev_list_entry, devices) { const char* path; path = udev_list_entry_get_name(dev_list_entry); dev = udev_device_new_from_syspath(udev, path); ret = udev_device_get_devnode(dev); } udev_enumerate_unref(enumerate); udev_unref(udev); if(ret) { printf("Ardunio 101 Device Node Path: %s\n", ret); } else { printf("Can't detect any Ardunio 101 Device on tty\n"); } return ret; } mraa_result_t imraa_reset_arduino(const char* modem) { mraa_uart_context uart; uart = mraa_uart_init_raw(modem); mraa_uart_set_baudrate(uart, 1200); if (uart == NULL) { fprintf(stderr, "UART failed to setup\n"); return MRAA_ERROR_UNSPECIFIED; } mraa_uart_stop(uart); mraa_deinit(); return MRAA_SUCCESS; } int imraa_flash_101(const char* bin_path, const char* bin_file_name, const char* tty) { if (imraa_reset_arduino(tty) != MRAA_SUCCESS) { fprintf(stderr, "Failed to reset arduino on %s for unknown reason, carrying on...\n", tty); } char* ln = NULL; size_t len = 0; bool board_found = false; const char* dfu_list = "/dfu-util -d ,8087:0ABA -l"; size_t bin_path_len = strlen(bin_path); char* full_dfu_list = (char*) calloc((bin_path_len + strlen(dfu_list) + 1), sizeof(char)); if(!full_dfu_list){ printf("imraa_flash_101 can't allocate string buffer for dfu list\n"); exit(1); } strncat(full_dfu_list, bin_path, strlen(bin_path)); strncat(full_dfu_list, dfu_list, strlen(dfu_list)); int i; // dfu list is still needed, as the time for reset and recognized is varies from platform to // platform. // once dfu able to query available devices, then it is ready to flash for (i = 0; i < 10 && board_found == false; i++) { printf("Waiting for device...\n"); // dfu-util -d,8087:0ABA -l FILE* dfu_result = popen(full_dfu_list, "r"); if (dfu_result == NULL) { printf("Failed to run command\n"); exit(1); } if (i == 4) { printf("Flashing is taking longer than expected\n"); printf("Try pressing MASTER_RESET button\n"); } while (getline(&ln, &len, dfu_result) != -1) { if (strstr(ln, "sensor_core")) { board_found = true; printf("Device found!\n"); break; } } sleep(1); if (pclose(dfu_result) != 0) { printf("Failed to close command\n"); exit(1); } } free(ln); if (board_found == false) { printf("ERROR: Device is not responding.\n"); exit(1); } const char* dfu_upload = "/dfu-util -d ,8087:0ABA -D "; const char* dfu_option = " -v -a 7 -R"; int buffersize = bin_path_len + strlen(dfu_upload) + strlen(bin_file_name) + strlen(dfu_option) + 1; char* full_dfu_upload = calloc(buffersize, sizeof(char)); if(!full_dfu_upload){ printf("imraa_flash_101 can't allocate string buffer for dfu flash\n"); exit(1); } strncat(full_dfu_upload, bin_path, strlen(bin_path)); strncat(full_dfu_upload, dfu_upload, strlen(dfu_upload)); strncat(full_dfu_upload, bin_file_name, strlen(bin_file_name)); strncat(full_dfu_upload, dfu_option, strlen(dfu_option)); printf("flash cmd: %s\n", full_dfu_upload); int status = system(full_dfu_upload); if (status != 0) { printf("ERROR: Upload failed on %s\n", tty); exit(1); } printf("SUCCESS: Sketch will execute in about 5 seconds.\n"); free(full_dfu_list); free(full_dfu_upload); sleep(5); return 0; } void imraa_write_lockfile(const char* lock_file_location, const char* serialport) { FILE* fh; char str[10]; json_object* platform1 = json_object_new_object(); snprintf(str, 10, "%d", MRAA_NULL_PLATFORM); json_object_object_add(platform1, "id", json_object_new_string(str)); json_object* platform2 = json_object_new_object(); snprintf(str, 10, "%d", MRAA_GENERIC_FIRMATA); json_object_object_add(platform2, "id", json_object_new_string(str)); json_object_object_add(platform2, "uart", json_object_new_string(serialport)); json_object* platfroms = json_object_new_array(); json_object_array_add(platfroms, platform1); json_object_array_add(platfroms, platform2); json_object* lock_file = json_object_new_object(); json_object_object_add(lock_file, "Platform", platfroms); fh = fopen(lock_file_location, "w"); if (fh != NULL) { fputs(json_object_to_json_string_ext(lock_file, JSON_C_TO_STRING_PRETTY), fh); fclose(fh); } else { fprintf(stderr, "can't write to lock file\n"); } json_object_put(lock_file); } void imraa_handle_subplatform(struct json_object* jobj, bool force_update) { struct json_object* platform; int i, ionum; const char* dfu_loc; const char* lockfile_loc; const char* flash_loc; const char* usbserial; struct json_object* dfu_location; if (json_object_object_get_ex(jobj, "dfu-utils-location", &dfu_location) == true) { if (json_object_is_type(dfu_location, json_type_string)) { printf("dfu location: %s\n", json_object_get_string(dfu_location)); dfu_loc = json_object_get_string(dfu_location); } else { fprintf(stderr, "dfu location string incorrectly parsed\n"); } } struct json_object* lockfile_location; if (json_object_object_get_ex(jobj, "lockfile-location", &lockfile_location) == true) { if (json_object_is_type(lockfile_location, json_type_string)) { printf("lock file location: %s\n", json_object_get_string(lockfile_location)); lockfile_loc = json_object_get_string(lockfile_location); } else { fprintf(stderr, "lock file string incorrectly parsed\n"); } } if (json_object_object_get_ex(jobj, "Platform", &platform) == true) { if (json_object_is_type(platform, json_type_array)) { ionum = json_object_array_length(platform); for (i = 0; i < ionum; i++) { struct json_object* ioobj = json_object_array_get_idx(platform, i); json_object_object_foreach(ioobj, key, val) { if (strcmp(key, "flash") == 0) { flash_loc = json_object_get_string(val); } if (strcmp(key, "usbserial") == 0) { usbserial = json_object_get_string(val); } } } } else { fprintf(stderr, "platform string incorrectly parsed\n"); } } // got flash? do flash if (access(lockfile_loc, F_OK) != -1 && force_update == false) { printf("already exist a lock file, skip flashing\n"); printf("force upgrade? remove the lockfile or run with force\n", lockfile_loc); return; } else { fprintf(stdout, "Starting to flash board\n"); if(force_update) { fprintf(stdout, "**Caution: force update mode**\n"); } // dfu_loc = "/usr/bin"; //TODO flash img checksum, and serialport validation? const char* detected_serialport = imraa_list_serialport(); if (detected_serialport == NULL) { printf("No subplatform detected, skip flashing\n"); return; } if (strcmp(usbserial, "auto") != 0 && strcmp(usbserial, detected_serialport) != 0) { printf("given serial port didn't match detected serial port, skip flashing\n"); return; } detected_serialport = "/dev/ttyACM0"; if ( dfu_loc != NULL && flash_loc != NULL && usbserial != NULL) { if (imraa_flash_101(dfu_loc, flash_loc, detected_serialport) == 0) { imraa_write_lockfile(lockfile_loc, detected_serialport); } else { fprintf(stderr, "Flash failed, push master reset and try again\n"); } } else { fprintf(stderr, "invalid flashing paramenters, please check agian\n"); fprintf(stderr, "DFU Util location: %s\n", dfu_loc); fprintf(stderr, "Flash Img location: %s\n", dfu_loc); fprintf(stderr, "USB Serial: %s\n", usbserial); } } } void imraa_handle_IO(struct json_object* jobj) { struct mraa_io_objects_t* mraa_io_obj; struct json_object* ioarray; int ionum = 0; int i; if (json_object_object_get_ex(jobj, "IO", &ioarray) == true) { ionum = json_object_array_length(ioarray); printf("Length of IO array is %d\n", ionum); mraa_io_obj = (mraa_io_objects_t*) malloc( ionum * sizeof(mraa_io_objects_t)); if (!mraa_io_obj) { printf("imraa_handle_IO malloc failed\n"); exit(1); } int index2 = -1;;//optional index for io configuration; if (json_object_is_type(ioarray, json_type_array)) { for (i = 0; i < ionum; i++) { struct json_object* ioobj = json_object_array_get_idx(ioarray, i); struct json_object* x; if (json_object_object_get_ex(ioobj, "type", &x) == true) { mraa_io_obj[i].type = json_object_get_string(x); } if (json_object_object_get_ex(ioobj, "index", &x) == true) { mraa_io_obj[i].index = json_object_get_int(x); } if (json_object_object_get_ex(ioobj, "raw", &x) == true) { mraa_io_obj[i].raw = json_object_get_boolean(x); } if (json_object_object_get_ex(ioobj, "label", &x) == true) { mraa_io_obj[i].label = json_object_get_string(x); } if (json_object_object_get_ex(ioobj, "index2", &x) == true) { index2 = json_object_get_int(x); } //starting io configuration if(strcmp(mraa_io_obj[i].type, "gpio") == 0){ mraa_gpio_context gpio = NULL; if(mraa_io_obj[i].raw){ printf("gpio raw init\n"); gpio = mraa_gpio_init_raw(mraa_io_obj[i].index); } else { printf("gpio init\n"); gpio = mraa_gpio_init(mraa_io_obj[i].index); } mraa_result_t r = mraa_gpio_owner(gpio, 0); if (r != MRAA_SUCCESS) { mraa_result_print(r); } } else if (strcmp(mraa_io_obj[i].type, "i2c") == 0) { mraa_i2c_context i2c = NULL; if(mraa_io_obj[i].raw){ printf("i2c raw init\n"); i2c = mraa_i2c_init_raw(mraa_io_obj[i].index); } else { printf("i2c init\n"); i2c = mraa_i2c_init(mraa_io_obj[i].index); } } else if (strcmp(mraa_io_obj[i].type, "pwm") == 0) { mraa_pwm_context pwm = NULL; if(mraa_io_obj[i].raw){ printf("pwm raw init\n"); pwm = mraa_pwm_init_raw(index2,mraa_io_obj[i].index); } else { printf("pwm init\n"); pwm = mraa_pwm_init(mraa_io_obj[i].index); } mraa_result_t r = mraa_pwm_owner(pwm, 0); if (r != MRAA_SUCCESS) { mraa_result_print(r); } } else if (strcmp(mraa_io_obj[i].type, "spi") == 0) { mraa_spi_context spi = NULL; if(mraa_io_obj[i].raw){ printf("spi raw init\n"); spi = mraa_spi_init_raw(mraa_io_obj[i].index, index2); } else { printf("spi init\n"); spi = mraa_spi_init(mraa_io_obj[i].index); } } else if (strcmp(mraa_io_obj[i].type, "uart") == 0) { mraa_uart_context uart = NULL; if(mraa_io_obj[i].raw){ printf("uart raw init\n"); uart = mraa_uart_init_raw(mraa_io_obj[i].label); } else { printf("uart init\n"); uart = mraa_uart_init(mraa_io_obj[i].index); } } } } else { fprintf(stderr, "IO array incorrectly parsed\n"); } free(mraa_io_obj); } } int check_version(struct json_object* jobj) { struct json_object* imraa_version; if (json_object_object_get_ex(jobj, "version", &imraa_version) == true) { if (json_object_is_type(imraa_version, json_type_string)) { printf("imraa version is %s good\n", json_object_get_string(imraa_version)); // TODO check version? } else { fprintf(stderr, "version string incorrectly parsed\n"); return -1; } } else { fprintf(stderr, "no version specified\n"); } return 0; } void print_version() { fprintf(stdout, "Version %s on %s\n", mraa_get_version(), mraa_get_platform_name()); } void print_help() { fprintf(stdout, "version Get mraa version and board name\n"); fprintf(stdout, "force Force update subplatform\n"); fprintf(stdout, "conf_path Force update with override configuration\n"); } void print_command_error() { fprintf(stdout, "Invalid command, options are:\n"); print_help(); exit(EXIT_FAILURE); } int main(int argc, char** argv) { char* buffer = NULL; char* imraa_conf_file = IMRAA_CONF_FILE; long fsize; bool force_update = false; int i = 0; uint32_t ionum = 0; if (argc > 2) { print_command_error(); } if (argc > 1) { if (strcmp(argv[1], "help") == 0) { print_help(); return; } else if (strcmp(argv[1], "version") == 0) { print_version(); return; } else if (strcmp(argv[1], "force") == 0) { force_update = true; } else { imraa_conf_file = argv[1]; force_update = true; } } FILE* fh = fopen(imraa_conf_file, "r"); if (fh == NULL) { fprintf(stderr, "Failed to open configuration file\n"); return EXIT_FAILURE; } fseek(fh, 0, SEEK_END); fsize = ftell(fh) + 1; fseek(fh, 0, SEEK_SET); buffer = calloc(fsize, sizeof(char)); if (buffer != NULL) { fread(buffer, sizeof(char), fsize, fh); } else { printf("imraa read_conf buffer can't allocated\n"); exit(1); } imraa_init(); json_object* jobj = json_tokener_parse(buffer); if (check_version(jobj) != 0) { printf("version of configuration file is not compatible, please check again\n"); } else { mraa_platform_t type = mraa_get_platform_type(); imraa_handle_subplatform(jobj, force_update); if( type == MRAA_NULL_PLATFORM || type == MRAA_UNKNOWN_PLATFORM) { printf("imraa: Failed to do IO pinmuxing on null/unkown platform\n"); } else { imraa_handle_IO(jobj); } } fclose(fh); json_object_put(jobj); free(buffer); return EXIT_SUCCESS; }