Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ automatically. That's packaging, not a fork.
- Upstream moved the `v0.2.0` protocol tag (from `9c21d6e` to `1c008bc`)
after tinclib v0.2.0 shipped. The files are identical; only the history
was rewritten.
- **v0.4.1 (branch `win-serial-patch`): PC host fix.** With the calculator
plugged straight into a PC, `tinc_init()` gave up after 600 ms, before
Windows' usbser was loaded and the PC app had the port open.
`tinc_init()` now retries HELLO on `NO_REPLY` until `TINC_DEVICE_WAIT_MS`,
and a repeat `tinc_init()` keeps USB up instead of re-enumerating (which
made COM9 vanish on every retry). While the calculator is idle nothing
answers USB, so the PC's open blocks until the next tinclib call. Whether
2 s is enough on a first plug-in is not yet measured.
- **Real firmware, from a PC:** `make pc-link` builds `tools/pc_link.c`
(the real `src/`, with srldrvce swapped for Win32 serial) and runs it
against a board on a COM port. Against the v0.1 firmware on COM5, HELLO,
Expand Down
29 changes: 19 additions & 10 deletions src/tinc_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -219,25 +219,34 @@ tinc_err_t tinc_init(const tinc_config_t *cfg)
tinc_err_t setup, err;
clock_t start;

tinc_shutdown();
if (tinc_g.ready)
tinc_abort();
memset(&tinc_g, 0, sizeof tinc_g);
tinc_g.cfg = cfg ? *cfg : defaults;
tinc_parser_init(&tinc_g.parser, tinc_g.frame, sizeof tinc_g.frame);

setup = tinc_takeSetupResult();

if (usb_Init(on_usb, NULL, srl_GetCDCStandardDescriptors(), USB_DEFAULT_INIT_FLAGS)
!= USB_SUCCESS) {
usb_Cleanup();
return setup ? setup : TINC_ERR_NO_DEVICE;
/* A retry keeps USB up: tearing it down makes a PC host re-enumerate
* the calculator, and its COM port goes away with it. */
if (!usb_up) {
if (usb_Init(on_usb, NULL, srl_GetCDCStandardDescriptors(),
USB_DEFAULT_INIT_FLAGS) != USB_SUCCESS) {
usb_Cleanup();
return setup ? setup : TINC_ERR_NO_DEVICE;
}
usb_up = true;
}
usb_up = true;

/* A PC host is "connected" as soon as it configures us, but its app
* can only open the port while we pump USB events, so keep saying
* HELLO until the deadline. */
start = clock();
while (!has_srl && !tinc_elapsed(start, TINC_DEVICE_WAIT_MS))
usb_HandleEvents();

err = has_srl ? hello() : TINC_ERR_NO_DEVICE;
do {
while (!has_srl && !tinc_elapsed(start, TINC_DEVICE_WAIT_MS))
usb_HandleEvents();
err = has_srl ? hello() : TINC_ERR_NO_DEVICE;
} while (err == TINC_ERR_NO_REPLY && !tinc_elapsed(start, TINC_DEVICE_WAIT_MS));
tinc_g.ready = err == TINC_OK;
return setup ? setup : err;
}
Expand Down
7 changes: 5 additions & 2 deletions src/tinclib.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ extern "C" {
* X.Y, and the board's firmware must too. PATCH counts library-only releases
* on the same protocol; reset it to 0 when the protocol submodule moves.
*/
#define TINC_VERSION_PATCH 0
#define TINC_VERSION_PATCH 1

#define TINC_STR_(x) #x
#define TINC_STR(x) TINC_STR_(x)
Expand All @@ -57,7 +57,10 @@ extern "C" {
#define TINC_RX_BUF_SIZE 256
#endif

/** How long tinc_init() waits for the ESP board to show up on USB. */
/**
* How long tinc_init() waits for the board (or a PC host) to show up on USB
* and answer HELLO.
*/
#ifndef TINC_DEVICE_WAIT_MS
#define TINC_DEVICE_WAIT_MS 2000u
#endif
Expand Down
21 changes: 21 additions & 0 deletions tests/test_tinclib.c
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,26 @@ static void test_lost_reply_is_not_rerun(void)
CHECK(strcmp(body, "0123456789") == 0);
}

/* A PC host answers only once its app has the port open: HELLO keeps
* being retried until TINC_DEVICE_WAIT_MS, then gives up. */
static void test_hello_late_reply(void)
{
unsigned long start, elapsed_ms;

setup();
fake.drop_replies = TINC_RETRY_MAX * 2;
CHECK(tinc_init(NULL) == TINC_OK);
CHECK(fake.frames_in == TINC_RETRY_MAX * 2 + 1);

setup();
fake.drop_replies = 255;
start = fake_now;
CHECK(tinc_init(NULL) == TINC_ERR_NO_REPLY);
elapsed_ms = (fake_now - start) / 1000;
CHECK(elapsed_ms >= TINC_DEVICE_WAIT_MS);
CHECK(elapsed_ms < TINC_DEVICE_WAIT_MS + TINC_RETRY_MAX * TINC_REPLY_TIMEOUT_MS + 100);
}

static void test_board_gone_quiet(void)
{
tinc_request_t req = get("http://x/");
Expand Down Expand Up @@ -561,6 +581,7 @@ int main(void)
RUN(test_last_chunk_held_until_read);
RUN(test_is_active_mid_chunk);
RUN(test_lost_reply_is_not_rerun);
RUN(test_hello_late_reply);
RUN(test_board_gone_quiet);
RUN(test_esp_reset_mid_request);
RUN(test_request_errors);
Expand Down
Loading