int PX4IO_Uploader::upload(const char *filenames[]) { int ret; const char *filename = NULL; size_t fw_size; #ifndef PX4IO_SERIAL_DEVICE #error Must define PX4IO_SERIAL_DEVICE in board configuration to support firmware upload #endif /* allow an early abort and look for file first */ for (unsigned i = 0; filenames[i] != nullptr; i++) { _fw_fd = open(filenames[i], O_RDONLY); if (_fw_fd < 0) { log("failed to open %s", filenames[i]); continue; } log("using firmware from %s", filenames[i]); filename = filenames[i]; break; } if (filename == NULL) { log("no firmware found"); close(_io_fd); _io_fd = -1; return -ENOENT; } _io_fd = open(PX4IO_SERIAL_DEVICE, O_RDWR); if (_io_fd < 0) { log("could not open interface"); return -errno; } /* save initial uart configuration to reset after the update */ struct termios t_original; tcgetattr(_io_fd, &t_original); /* adjust line speed to match bootloader */ struct termios t; tcgetattr(_io_fd, &t); cfsetspeed(&t, 115200); tcsetattr(_io_fd, TCSANOW, &t); /* look for the bootloader for 150 ms */ for (int i = 0; i < 15; i++) { ret = sync(); if (ret == OK) { break; } else { usleep(10000); } } if (ret != OK) { /* this is immediately fatal */ log("bootloader not responding"); tcsetattr(_io_fd, TCSANOW, &t_original); close(_io_fd); _io_fd = -1; return -EIO; } struct stat st; if (stat(filename, &st) != 0) { log("Failed to stat %s - %d\n", filename, (int)errno); tcsetattr(_io_fd, TCSANOW, &t_original); close(_io_fd); _io_fd = -1; return -errno; } fw_size = st.st_size; if (_fw_fd == -1) { tcsetattr(_io_fd, TCSANOW, &t_original); close(_io_fd); _io_fd = -1; return -ENOENT; } /* do the usual program thing - allow for failure */ for (unsigned retries = 0; retries < 1; retries++) { if (retries > 0) { log("retrying update..."); ret = sync(); if (ret != OK) { /* this is immediately fatal */ log("bootloader not responding"); tcsetattr(_io_fd, TCSANOW, &t_original); close(_io_fd); _io_fd = -1; return -EIO; } } ret = get_info(INFO_BL_REV, bl_rev); if (ret == OK) { if (bl_rev <= BL_REV) { log("found bootloader revision: %d", bl_rev); } else { log("found unsupported bootloader revision %d, exiting", bl_rev); tcsetattr(_io_fd, TCSANOW, &t_original); close(_io_fd); _io_fd = -1; return OK; } } ret = erase(); if (ret != OK) { log("erase failed"); continue; } ret = program(fw_size); if (ret != OK) { log("program failed"); continue; } if (bl_rev <= 2) { ret = verify_rev2(fw_size); } else { /* verify rev 3 and higher. Every version *needs* to be verified. */ ret = verify_rev3(fw_size); } if (ret != OK) { log("verify failed"); continue; } ret = reboot(); if (ret != OK) { log("reboot failed"); tcsetattr(_io_fd, TCSANOW, &t_original); close(_io_fd); _io_fd = -1; return ret; } log("update complete"); ret = OK; break; } /* reset uart to previous/default baudrate */ tcsetattr(_io_fd, TCSANOW, &t_original); close(_fw_fd); close(_io_fd); _io_fd = -1; // sleep for enough time for the IO chip to boot. This makes // forceupdate more reliably startup IO again after update up_udelay(100*1000); return ret; }
/* upload a firmware to the IOMCU */ bool AP_IOMCU::upload_fw(void) { // set baudrate for bootloader uart.begin(115200, 256, 256); bool ret = false; /* look for the bootloader for 150 ms */ for (uint8_t i = 0; i < 15; i++) { ret = sync(); if (ret) { break; } hal.scheduler->delay(10); } if (!ret) { debug("IO update failed sync"); return false; } uint32_t bl_rev; ret = get_info(INFO_BL_REV, bl_rev); if (!ret) { debug("Err: failed to contact bootloader"); return false; } if (bl_rev > BL_REV) { debug("Err: unsupported bootloader revision %u", unsigned(bl_rev)); return false; } debug("found bootloader revision: %u", unsigned(bl_rev)); ret = erase(); if (!ret) { debug("erase failed"); return false; } ret = program(fw_size); if (!ret) { debug("program failed"); return false; } if (bl_rev <= 2) { ret = verify_rev2(fw_size); } else { ret = verify_rev3(fw_size); } if (!ret) { debug("verify failed"); return false; } ret = reboot(); if (!ret) { debug("reboot failed"); return false; } debug("update complete"); // sleep for enough time for the IO chip to boot hal.scheduler->delay(100); return true; }