int main()

in uf2tool/tool.c [204:359]


int main(int argc, char *argv[]) {
    int res;
    HID_Dev cmd = {0};

    if (argc != 2) {
        printf("usage: %s COMMAND [ARGUMENTS...]\n", argv[0]);
        printf("Commands include:\n");
        printf("   serial           - run 'serial' port forwarding\n");
        printf("   list             - list devices\n");
        printf("   dmesg            - dump internal runtime logs from the device\n");
        printf("   info             - dump information about the device\n");
        printf("   FILE             - write specified BIN or UF2 file\n");
        printf("   random           - write randomly generated bin file\n");
        return 1;
    }

    const char *filename = argv[1];

    // Initialize the hidapi library
    res = hid_init();

    bool listMode = strcmp(filename, "list") == 0;

    struct hid_device_info *devs = hid_enumerate(0, 0);
    for (struct hid_device_info *p = devs; p; p = p->next) {
        int isOK = (p->release_number & 0xff00) == 0x4200;
        const char *path = strstr(p->path, "@1400");
        if (!path)
            path = p->path;
        if (listMode) {
            // exclude Apple devices
            if (p->vendor_id != 0x05ac)
                printf("%s: %04x:%04x %04x %s\n", isOK ? "HF2" : "...", p->vendor_id, p->product_id,
                       p->release_number, path);
        }
        if (isOK) {
            cmd.dev = hid_open_path(p->path);
        }
    }
    hid_free_enumeration(devs);
    if (listMode)
        return 0;
    if (!cmd.dev) {
        printf("no devices\n");
        return 1;
    }

    if (strcmp(filename, "serial") == 0) {
        serial(&cmd);
        return 0;
    }

    if (strcmp(filename, "dmesg") == 0) {
        talk_hid(&cmd, HF2_CMD_DMESG, 0, 0);
        printf("%s\n", cmd.buf + 4);
        return 0;
    }

    talk_hid(&cmd, HF2_CMD_INFO, 0, 0);
    printf("INFO: %s\n", cmd.buf + 4);

    talk_hid(&cmd, HF2_CMD_START_FLASH, 0, 0);

    talk_hid(&cmd, HF2_CMD_BININFO, 0, 0);
    if (cmd.buf[4] != HF2_MODE_BOOTLOADER)
        fatal("not bootloader");

    cmd.pageSize = read32(cmd.buf + 8);
    cmd.flashSize = read32(cmd.buf + 12) * cmd.pageSize;
    cmd.msgSize = read32(cmd.buf + 16);
    printf("page size: %d, total: %dkB\n", cmd.pageSize, cmd.flashSize / 1024);

    if (strcmp(filename, "info") == 0) {
        return 0;
    }

    int i;
    size_t filesize;
    int isUF2 = 0;

    if (strcmp(filename, "random") == 0) {
        srand(millis());
        filesize = 230 * 1024;
        for (i = 0; i < filesize; ++i)
            flashbuf[i] = rand();
    } else {
        FILE *f = fopen(filename, "rb");
        if (!f) {
            fatal("cannot open file");
        }
        int len = 1;
        filesize = 0;
        while (len) {
            len = fread(flashbuf + filesize, 1, sizeof(flashbuf) - filesize, f);
            filesize += len;
        }
        if (strncmp((const char *)flashbuf, "UF2\nWQ]\x9E", 8) == 0) {
            printf("detected UF2 file\n");
            if (cmd.pageSize != 256)
                fatal("wrong page size");
            isUF2 = 1;
        } else {
            filesize = (filesize + (cmd.pageSize - 1)) / cmd.pageSize * cmd.pageSize;
        }
        printf("read %ld bytes from %s\n", filesize, filename);
        fclose(f);
    }

    uint64_t start = millis();
    uint32_t addr = 0x2000;
    uint32_t blockSize = cmd.pageSize;

    if (isUF2)
        blockSize = 512;

    for (i = 0; i < filesize; i += blockSize) {
        if (isUF2) {
            addr = read32(flashbuf + i + 12);
            memcpy(cmd.buf + 12, flashbuf + i + 32, cmd.pageSize);
        } else {
            memcpy(cmd.buf + 12, flashbuf + i, cmd.pageSize);
        }
        write32(cmd.buf + 8, addr);
        talk_hid(&cmd, HF2_CMD_WRITE_FLASH_PAGE, 0, cmd.pageSize + 4);
        addr += cmd.pageSize;
    }

    printf("time: %d\n", (int)(millis() - start));
    start = millis();

#if 0
    for (i = 0; i < filesize; i += cmd.pageSize) {
        write32(cmd.buf + 8, i + 0x2000);
        write32(cmd.buf + 12, cmd.pageSize / 4);
        talk_hid(&cmd, HF2_CMD_MEM_READ_WORDS, 0, 8);
        if (memcmp(cmd.buf + 4, flashbuf + i, cmd.pageSize)) {
            printf("%d,%d,%d != %d?\n", cmd.buf[8], cmd.buf[9], cmd.buf[10], flashbuf[i]);
            fatal("verification failed");
        }
    }
#else
    if (!isUF2)
        verify(&cmd, flashbuf, filesize, 0x2000);
#endif

    printf("verify time: %d\n", (int)(millis() - start));

    talk_hid(&cmd, HF2_CMD_RESET_INTO_APP, 0, 0);

    printf("device reset.\n");

    // Finalize the hidapi library
    res = hid_exit();

    return 0;
}