Add HID-tool
This commit is contained in:
parent
5345404a70
commit
f36ddb271c
6 changed files with 294 additions and 0 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -3,3 +3,4 @@ tmp
|
|||
flash.uf2
|
||||
flash.bin
|
||||
|
||||
built/
|
||||
|
|
|
|||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
[submodule "hidapi"]
|
||||
path = hidapi
|
||||
url = ../../signal11/hidapi
|
||||
1
hidapi
Submodule
1
hidapi
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit a6a622ffb680c55da0de787ff93b80280498330f
|
||||
3
uf2tool/Makefile
Normal file
3
uf2tool/Makefile
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
all:
|
||||
mkdir -p ../built
|
||||
$(CC) -g -Wall tool.c ../hidapi/mac/hid.c -I../hidapi/hidapi -I. -framework IOKit -framework CoreFoundation -o ../built/uf2tool
|
||||
257
uf2tool/tool.c
Normal file
257
uf2tool/tool.c
Normal file
|
|
@ -0,0 +1,257 @@
|
|||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include "hidapi.h"
|
||||
#include "uf2hid.h"
|
||||
|
||||
#define FLASH_ROW_SIZE 4096
|
||||
|
||||
typedef struct {
|
||||
hid_device *dev;
|
||||
uint16_t size;
|
||||
uint8_t serial;
|
||||
uint16_t seqNo;
|
||||
uint16_t pageSize;
|
||||
uint8_t buf[FLASH_ROW_SIZE + 64];
|
||||
} HID_Dev;
|
||||
|
||||
uint64_t millis() {
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, 0);
|
||||
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||||
}
|
||||
|
||||
void fatal(const char *msg) {
|
||||
fprintf(stderr, "Fatal error: %s\n", msg);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void write16(uint8_t *ptr, uint16_t v) {
|
||||
ptr[0] = v;
|
||||
ptr[1] = v >> 8;
|
||||
}
|
||||
|
||||
void write32(uint8_t *ptr, uint32_t v) {
|
||||
ptr[0] = v;
|
||||
ptr[1] = v >> 8;
|
||||
ptr[2] = v >> 16;
|
||||
ptr[3] = v >> 24;
|
||||
}
|
||||
|
||||
uint32_t read32(uint8_t *ptr) { return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24); }
|
||||
|
||||
uint32_t read16(uint8_t *ptr) { return ptr[0] | (ptr[1] << 8); }
|
||||
|
||||
int recv_hid(HID_Dev *pkt, int timeout) {
|
||||
uint8_t buf0[65];
|
||||
uint8_t *buf;
|
||||
|
||||
pkt->size = 0;
|
||||
memset(pkt->buf, 0, sizeof(pkt->buf));
|
||||
|
||||
for (;;) {
|
||||
int sz = hid_read_timeout(pkt->dev, buf0, 65, timeout);
|
||||
if (sz <= 0) {
|
||||
if (timeout < 0)
|
||||
fatal("read error");
|
||||
return 0;
|
||||
}
|
||||
buf = buf0;
|
||||
if (!*buf)
|
||||
buf++; // skip report number if passed
|
||||
|
||||
uint8_t tag = buf[0];
|
||||
if (pkt->size && !(tag & 0x80))
|
||||
fatal("invalid serial transfer");
|
||||
uint32_t newsize = pkt->size + (tag & HF2_SIZE_MASK);
|
||||
if (newsize > sizeof(pkt->buf))
|
||||
fatal("too large packet");
|
||||
memcpy(pkt->buf + pkt->size, buf + 1, tag & HF2_SIZE_MASK);
|
||||
pkt->size = newsize;
|
||||
if (tag & 0x40) {
|
||||
pkt->serial = (tag & HF2_FLAG_MASK) == HF2_FLAG_SERIAL;
|
||||
return 1;
|
||||
}
|
||||
timeout = -1; // next read is blocking
|
||||
}
|
||||
}
|
||||
|
||||
void send_hid(hid_device *dev, const void *data, int size) {
|
||||
uint8_t buf[65] = {0};
|
||||
const uint8_t *ptr = data;
|
||||
|
||||
for (;;) {
|
||||
int s;
|
||||
if (size <= 63) {
|
||||
s = size;
|
||||
buf[1] = HF2_FLAG_PKT_LAST | size;
|
||||
} else {
|
||||
s = 63;
|
||||
buf[1] = HF2_FLAG_PKT_BODY | 63;
|
||||
}
|
||||
memcpy(buf + 2, ptr, s);
|
||||
int sz = hid_write(dev, buf, 65);
|
||||
if (sz != 65)
|
||||
fatal("write error");
|
||||
ptr += s;
|
||||
size -= s;
|
||||
if (!size)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void talk_hid(HID_Dev *pkt, int cmd, const void *data, uint32_t len) {
|
||||
if (len >= sizeof(pkt->buf) - 4)
|
||||
fatal("buffer overflow");
|
||||
if (data)
|
||||
memcpy(pkt->buf + 4, data, len);
|
||||
write16(pkt->buf, cmd);
|
||||
write16(pkt->buf + 2, ++pkt->seqNo);
|
||||
uint32_t saved = read32(pkt->buf);
|
||||
send_hid(pkt->dev, pkt->buf, 4 + len);
|
||||
recv_hid(pkt, -1);
|
||||
if (read32(pkt->buf) != saved)
|
||||
fatal("invalid sequence number");
|
||||
if (read32(pkt->buf + 4) != 0)
|
||||
fatal("invalid status");
|
||||
}
|
||||
|
||||
uint8_t flashbuf[64 * 1024];
|
||||
|
||||
unsigned short add_crc(char ptr, unsigned short crc) {
|
||||
unsigned short cmpt;
|
||||
crc = crc ^ (int)ptr << 8;
|
||||
for (cmpt = 0; cmpt < 8; cmpt++) {
|
||||
if (crc & 0x8000)
|
||||
crc = crc << 1 ^ 0x1021;
|
||||
else
|
||||
crc = crc << 1;
|
||||
}
|
||||
return (crc & 0xFFFF);
|
||||
}
|
||||
|
||||
void verify(HID_Dev *cmd, uint8_t *buf, int size, int offset) {
|
||||
int maxSize = (cmd->pageSize / 2 - 8) * cmd->pageSize;
|
||||
while (size > maxSize) {
|
||||
verify(cmd, buf, maxSize, offset);
|
||||
buf += maxSize;
|
||||
offset += maxSize;
|
||||
size -= maxSize;
|
||||
}
|
||||
int numpages = size / cmd->pageSize;
|
||||
write32(cmd->buf + 4, offset);
|
||||
write32(cmd->buf + 8, numpages);
|
||||
talk_hid(cmd, HF2_CMD_CHKSUM_PAGES, 0, 8);
|
||||
for (int i = 0; i < numpages; ++i) {
|
||||
int sum = read16(cmd->buf + 8 + i * 2);
|
||||
uint16_t crc = 0;
|
||||
for (int j = 0; j < cmd->pageSize; ++j) {
|
||||
crc = add_crc(buf[j], crc);
|
||||
}
|
||||
if (sum != crc)
|
||||
fatal("verification failed");
|
||||
buf += cmd->pageSize;
|
||||
}
|
||||
}
|
||||
|
||||
int stdinHasData() {
|
||||
struct pollfd fds;
|
||||
fds.fd = 0;
|
||||
fds.events = POLLIN;
|
||||
fds.revents = 0;
|
||||
return poll(&fds, 1, 0) > 0;
|
||||
}
|
||||
|
||||
void serial(HID_Dev *cmd) {
|
||||
uint8_t buf[65];
|
||||
for (;;) {
|
||||
while (stdinHasData()) {
|
||||
memset(buf, 0, 65);
|
||||
int sz = read(0, buf + 2, 63);
|
||||
if (sz > 0) {
|
||||
buf[1] = HF2_FLAG_SERIAL | sz;
|
||||
hid_write(cmd->dev, buf, 65);
|
||||
}
|
||||
}
|
||||
if (recv_hid(cmd, 10)) {
|
||||
if (cmd->serial)
|
||||
write(1, cmd->buf, cmd->size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int res;
|
||||
HID_Dev cmd = {0};
|
||||
|
||||
// Initialize the hidapi library
|
||||
res = hid_init();
|
||||
|
||||
struct hid_device_info *devs = hid_enumerate(0, 0);
|
||||
for (struct hid_device_info *p = devs; p; p = p->next) {
|
||||
if ((p->release_number & 0xff00) == 0x4200) {
|
||||
printf("DEV: %04x:%04x %s\n", p->vendor_id, p->product_id, p->path);
|
||||
cmd.dev = hid_open_path(p->path);
|
||||
}
|
||||
}
|
||||
hid_free_enumeration(devs);
|
||||
if (!cmd.dev) {
|
||||
printf("no devices\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
talk_hid(&cmd, HF2_CMD_INFO, 0, 0);
|
||||
printf("INFO: %s\n", cmd.buf + 8);
|
||||
|
||||
serial(&cmd);
|
||||
|
||||
talk_hid(&cmd, HF2_CMD_BININFO, 0, 0);
|
||||
if (read32(cmd.buf + 8) != HF2_MODE_BOOTLOADER)
|
||||
fatal("not bootloader");
|
||||
|
||||
cmd.pageSize = read32(cmd.buf + 12);
|
||||
printf("page size: %d\n", cmd.pageSize);
|
||||
|
||||
srand(millis());
|
||||
int i;
|
||||
for (i = 0; i < sizeof(flashbuf); ++i)
|
||||
flashbuf[i] = rand();
|
||||
|
||||
uint64_t start = millis();
|
||||
|
||||
for (i = 0; i < sizeof(flashbuf); i += cmd.pageSize) {
|
||||
write32(cmd.buf + 4, i + 0x2000);
|
||||
memcpy(cmd.buf + 8, flashbuf + i, cmd.pageSize);
|
||||
talk_hid(&cmd, HF2_CMD_WRITE_FLASH_PAGE, 0, cmd.pageSize + 4);
|
||||
}
|
||||
|
||||
printf("time: %d\n", (int)(millis() - start));
|
||||
start = millis();
|
||||
|
||||
#if 0
|
||||
|
||||
for (i = 0; i < sizeof(flashbuf); i += cmd.pageSize) {
|
||||
write32(cmd.buf + 4, i + 0x2000);
|
||||
talk_hid(&cmd, HF2_CMD_MEM_READ_PAGE, 0, 4);
|
||||
if (memcmp(cmd.buf + 8, 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
|
||||
verify(&cmd, flashbuf, sizeof(flashbuf), 0x2000);
|
||||
#endif
|
||||
|
||||
printf("verify time: %d\n", (int)(millis() - start));
|
||||
|
||||
// Finalize the hidapi library
|
||||
res = hid_exit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
29
uf2tool/uf2hid.h
Normal file
29
uf2tool/uf2hid.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef UF2_HID_H
|
||||
#define UF2_HID_H 1
|
||||
|
||||
#define HF2_FLAG_PKT_LAST 0xC0
|
||||
#define HF2_FLAG_PKT_BODY 0x80
|
||||
#define HF2_FLAG_SERIAL 0x40
|
||||
#define HF2_FLAG_MASK 0xC0
|
||||
#define HF2_FLAG_RESERVED 0x00
|
||||
#define HF2_SIZE_MASK 63
|
||||
|
||||
#define HF2_CMD_INFO 0x0001
|
||||
#define HF2_CMD_RESET_INTO_APP 0x0002
|
||||
#define HF2_CMD_RESET_INTO_BOOTLOADER 0x0003
|
||||
#define HF2_CMD_WRITE_FLASH_PAGE 0x0004
|
||||
#define HF2_CMD_MEM_WRITE_PAGE 0x0005
|
||||
#define HF2_CMD_MEM_READ_PAGE 0x0006
|
||||
#define HF2_CMD_START_FLASH 0x0007
|
||||
#define HF2_CMD_BININFO 0x0008
|
||||
#define HF2_CMD_CHKSUM_PAGES 0x0009
|
||||
|
||||
#define HF2_MODE_BOOTLOADER 0x01
|
||||
#define HF2_MODE_USERSPACE 0x02
|
||||
|
||||
#define HF2_STATUS_OK 0x00000000
|
||||
#define HF2_STATUS_INVALID_CMD 0x00000001
|
||||
#define HF2_STATUS_WRONG_MODE 0x00000002
|
||||
|
||||
|
||||
#endif
|
||||
Loading…
Reference in a new issue