Skip to content

Commit f36ddb2

Browse files
committed
Add HID-tool
1 parent 5345404 commit f36ddb2

File tree

6 files changed

+294
-0
lines changed

6 files changed

+294
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ tmp
33
flash.uf2
44
flash.bin
55

6+
built/

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "hidapi"]
2+
path = hidapi
3+
url = ../../signal11/hidapi

hidapi

Submodule hidapi added at a6a622f

uf2tool/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
all:
2+
mkdir -p ../built
3+
$(CC) -g -Wall tool.c ../hidapi/mac/hid.c -I../hidapi/hidapi -I. -framework IOKit -framework CoreFoundation -o ../built/uf2tool

uf2tool/tool.c

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
#ifdef WIN32
2+
#include <windows.h>
3+
#endif
4+
#include <stdio.h>
5+
#include <stdlib.h>
6+
#include <string.h>
7+
#include <poll.h>
8+
#include <unistd.h>
9+
#include <sys/time.h>
10+
#include "hidapi.h"
11+
#include "uf2hid.h"
12+
13+
#define FLASH_ROW_SIZE 4096
14+
15+
typedef struct {
16+
hid_device *dev;
17+
uint16_t size;
18+
uint8_t serial;
19+
uint16_t seqNo;
20+
uint16_t pageSize;
21+
uint8_t buf[FLASH_ROW_SIZE + 64];
22+
} HID_Dev;
23+
24+
uint64_t millis() {
25+
struct timeval tv;
26+
gettimeofday(&tv, 0);
27+
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
28+
}
29+
30+
void fatal(const char *msg) {
31+
fprintf(stderr, "Fatal error: %s\n", msg);
32+
exit(1);
33+
}
34+
35+
void write16(uint8_t *ptr, uint16_t v) {
36+
ptr[0] = v;
37+
ptr[1] = v >> 8;
38+
}
39+
40+
void write32(uint8_t *ptr, uint32_t v) {
41+
ptr[0] = v;
42+
ptr[1] = v >> 8;
43+
ptr[2] = v >> 16;
44+
ptr[3] = v >> 24;
45+
}
46+
47+
uint32_t read32(uint8_t *ptr) { return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24); }
48+
49+
uint32_t read16(uint8_t *ptr) { return ptr[0] | (ptr[1] << 8); }
50+
51+
int recv_hid(HID_Dev *pkt, int timeout) {
52+
uint8_t buf0[65];
53+
uint8_t *buf;
54+
55+
pkt->size = 0;
56+
memset(pkt->buf, 0, sizeof(pkt->buf));
57+
58+
for (;;) {
59+
int sz = hid_read_timeout(pkt->dev, buf0, 65, timeout);
60+
if (sz <= 0) {
61+
if (timeout < 0)
62+
fatal("read error");
63+
return 0;
64+
}
65+
buf = buf0;
66+
if (!*buf)
67+
buf++; // skip report number if passed
68+
69+
uint8_t tag = buf[0];
70+
if (pkt->size && !(tag & 0x80))
71+
fatal("invalid serial transfer");
72+
uint32_t newsize = pkt->size + (tag & HF2_SIZE_MASK);
73+
if (newsize > sizeof(pkt->buf))
74+
fatal("too large packet");
75+
memcpy(pkt->buf + pkt->size, buf + 1, tag & HF2_SIZE_MASK);
76+
pkt->size = newsize;
77+
if (tag & 0x40) {
78+
pkt->serial = (tag & HF2_FLAG_MASK) == HF2_FLAG_SERIAL;
79+
return 1;
80+
}
81+
timeout = -1; // next read is blocking
82+
}
83+
}
84+
85+
void send_hid(hid_device *dev, const void *data, int size) {
86+
uint8_t buf[65] = {0};
87+
const uint8_t *ptr = data;
88+
89+
for (;;) {
90+
int s;
91+
if (size <= 63) {
92+
s = size;
93+
buf[1] = HF2_FLAG_PKT_LAST | size;
94+
} else {
95+
s = 63;
96+
buf[1] = HF2_FLAG_PKT_BODY | 63;
97+
}
98+
memcpy(buf + 2, ptr, s);
99+
int sz = hid_write(dev, buf, 65);
100+
if (sz != 65)
101+
fatal("write error");
102+
ptr += s;
103+
size -= s;
104+
if (!size)
105+
break;
106+
}
107+
}
108+
109+
void talk_hid(HID_Dev *pkt, int cmd, const void *data, uint32_t len) {
110+
if (len >= sizeof(pkt->buf) - 4)
111+
fatal("buffer overflow");
112+
if (data)
113+
memcpy(pkt->buf + 4, data, len);
114+
write16(pkt->buf, cmd);
115+
write16(pkt->buf + 2, ++pkt->seqNo);
116+
uint32_t saved = read32(pkt->buf);
117+
send_hid(pkt->dev, pkt->buf, 4 + len);
118+
recv_hid(pkt, -1);
119+
if (read32(pkt->buf) != saved)
120+
fatal("invalid sequence number");
121+
if (read32(pkt->buf + 4) != 0)
122+
fatal("invalid status");
123+
}
124+
125+
uint8_t flashbuf[64 * 1024];
126+
127+
unsigned short add_crc(char ptr, unsigned short crc) {
128+
unsigned short cmpt;
129+
crc = crc ^ (int)ptr << 8;
130+
for (cmpt = 0; cmpt < 8; cmpt++) {
131+
if (crc & 0x8000)
132+
crc = crc << 1 ^ 0x1021;
133+
else
134+
crc = crc << 1;
135+
}
136+
return (crc & 0xFFFF);
137+
}
138+
139+
void verify(HID_Dev *cmd, uint8_t *buf, int size, int offset) {
140+
int maxSize = (cmd->pageSize / 2 - 8) * cmd->pageSize;
141+
while (size > maxSize) {
142+
verify(cmd, buf, maxSize, offset);
143+
buf += maxSize;
144+
offset += maxSize;
145+
size -= maxSize;
146+
}
147+
int numpages = size / cmd->pageSize;
148+
write32(cmd->buf + 4, offset);
149+
write32(cmd->buf + 8, numpages);
150+
talk_hid(cmd, HF2_CMD_CHKSUM_PAGES, 0, 8);
151+
for (int i = 0; i < numpages; ++i) {
152+
int sum = read16(cmd->buf + 8 + i * 2);
153+
uint16_t crc = 0;
154+
for (int j = 0; j < cmd->pageSize; ++j) {
155+
crc = add_crc(buf[j], crc);
156+
}
157+
if (sum != crc)
158+
fatal("verification failed");
159+
buf += cmd->pageSize;
160+
}
161+
}
162+
163+
int stdinHasData() {
164+
struct pollfd fds;
165+
fds.fd = 0;
166+
fds.events = POLLIN;
167+
fds.revents = 0;
168+
return poll(&fds, 1, 0) > 0;
169+
}
170+
171+
void serial(HID_Dev *cmd) {
172+
uint8_t buf[65];
173+
for (;;) {
174+
while (stdinHasData()) {
175+
memset(buf, 0, 65);
176+
int sz = read(0, buf + 2, 63);
177+
if (sz > 0) {
178+
buf[1] = HF2_FLAG_SERIAL | sz;
179+
hid_write(cmd->dev, buf, 65);
180+
}
181+
}
182+
if (recv_hid(cmd, 10)) {
183+
if (cmd->serial)
184+
write(1, cmd->buf, cmd->size);
185+
}
186+
}
187+
}
188+
189+
int main(int argc, char *argv[]) {
190+
int res;
191+
HID_Dev cmd = {0};
192+
193+
// Initialize the hidapi library
194+
res = hid_init();
195+
196+
struct hid_device_info *devs = hid_enumerate(0, 0);
197+
for (struct hid_device_info *p = devs; p; p = p->next) {
198+
if ((p->release_number & 0xff00) == 0x4200) {
199+
printf("DEV: %04x:%04x %s\n", p->vendor_id, p->product_id, p->path);
200+
cmd.dev = hid_open_path(p->path);
201+
}
202+
}
203+
hid_free_enumeration(devs);
204+
if (!cmd.dev) {
205+
printf("no devices\n");
206+
return 0;
207+
}
208+
209+
talk_hid(&cmd, HF2_CMD_INFO, 0, 0);
210+
printf("INFO: %s\n", cmd.buf + 8);
211+
212+
serial(&cmd);
213+
214+
talk_hid(&cmd, HF2_CMD_BININFO, 0, 0);
215+
if (read32(cmd.buf + 8) != HF2_MODE_BOOTLOADER)
216+
fatal("not bootloader");
217+
218+
cmd.pageSize = read32(cmd.buf + 12);
219+
printf("page size: %d\n", cmd.pageSize);
220+
221+
srand(millis());
222+
int i;
223+
for (i = 0; i < sizeof(flashbuf); ++i)
224+
flashbuf[i] = rand();
225+
226+
uint64_t start = millis();
227+
228+
for (i = 0; i < sizeof(flashbuf); i += cmd.pageSize) {
229+
write32(cmd.buf + 4, i + 0x2000);
230+
memcpy(cmd.buf + 8, flashbuf + i, cmd.pageSize);
231+
talk_hid(&cmd, HF2_CMD_WRITE_FLASH_PAGE, 0, cmd.pageSize + 4);
232+
}
233+
234+
printf("time: %d\n", (int)(millis() - start));
235+
start = millis();
236+
237+
#if 0
238+
239+
for (i = 0; i < sizeof(flashbuf); i += cmd.pageSize) {
240+
write32(cmd.buf + 4, i + 0x2000);
241+
talk_hid(&cmd, HF2_CMD_MEM_READ_PAGE, 0, 4);
242+
if (memcmp(cmd.buf + 8, flashbuf + i, cmd.pageSize)) {
243+
printf("%d,%d,%d != %d?\n", cmd.buf[8], cmd.buf[9], cmd.buf[10], flashbuf[i]);
244+
fatal("verification failed");
245+
}
246+
}
247+
#else
248+
verify(&cmd, flashbuf, sizeof(flashbuf), 0x2000);
249+
#endif
250+
251+
printf("verify time: %d\n", (int)(millis() - start));
252+
253+
// Finalize the hidapi library
254+
res = hid_exit();
255+
256+
return 0;
257+
}

uf2tool/uf2hid.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#ifndef UF2_HID_H
2+
#define UF2_HID_H 1
3+
4+
#define HF2_FLAG_PKT_LAST 0xC0
5+
#define HF2_FLAG_PKT_BODY 0x80
6+
#define HF2_FLAG_SERIAL 0x40
7+
#define HF2_FLAG_MASK 0xC0
8+
#define HF2_FLAG_RESERVED 0x00
9+
#define HF2_SIZE_MASK 63
10+
11+
#define HF2_CMD_INFO 0x0001
12+
#define HF2_CMD_RESET_INTO_APP 0x0002
13+
#define HF2_CMD_RESET_INTO_BOOTLOADER 0x0003
14+
#define HF2_CMD_WRITE_FLASH_PAGE 0x0004
15+
#define HF2_CMD_MEM_WRITE_PAGE 0x0005
16+
#define HF2_CMD_MEM_READ_PAGE 0x0006
17+
#define HF2_CMD_START_FLASH 0x0007
18+
#define HF2_CMD_BININFO 0x0008
19+
#define HF2_CMD_CHKSUM_PAGES 0x0009
20+
21+
#define HF2_MODE_BOOTLOADER 0x01
22+
#define HF2_MODE_USERSPACE 0x02
23+
24+
#define HF2_STATUS_OK 0x00000000
25+
#define HF2_STATUS_INVALID_CMD 0x00000001
26+
#define HF2_STATUS_WRONG_MODE 0x00000002
27+
28+
29+
#endif

0 commit comments

Comments
 (0)