// File: /workspace/github_cpp_makefile_star2_O2/AndreRenaud[P]simple_uart/simple_uart.c
// Function: simple_uart_read_timeout
ssize_t simple_uart_read_timeout(struct simple_uart *sc, void *buffer, size_t max_len, uint64_t timeout_ms)
{
    if (!sc)
        return -EINVAL;
    if (max_len == 0)
        return 0; // Nothing to read, but not an error
    if (!buffer)
        return -EINVAL;

    ssize_t r = 0;
#ifdef _WIN32
    COMMTIMEOUTS commTimeout;
    DWORD bytes_read = 0;

    /* Get the comm timeouts */
    if (GetCommTimeouts(sc->port, &commTimeout)) {
        if (timeout_ms == 0) {
            /* Non-blocking: return immediately with whatever data is there */
            commTimeout.ReadIntervalTimeout = MAXDWORD;
            commTimeout.ReadTotalTimeoutMultiplier = MAXDWORD;
            commTimeout.ReadTotalTimeoutConstant = 1;
        } else {
            /* Blocking with timeout */
            commTimeout.ReadIntervalTimeout = 0;
            commTimeout.ReadTotalTimeoutMultiplier = 0;
            commTimeout.ReadTotalTimeoutConstant = (DWORD)timeout_ms;
        }
        SetCommTimeouts(sc->port, &commTimeout);
    }
    if (max_len > ULONG_MAX)
        max_len = ULONG_MAX; // avoid overflow at typecast
    if (!ReadFile(sc->port, buffer, (DWORD)max_len, &bytes_read, NULL))
        return win32_errno();
    r = (ssize_t)bytes_read;
#else
    fd_set readfds, exceptfds;
    struct timeval t;

    FD_ZERO(&readfds);
    FD_SET(sc->fd, &readfds);
    FD_ZERO(&exceptfds);
    FD_SET(sc->fd, &exceptfds);
    t.tv_sec = timeout_ms / 1000;
    t.tv_usec = (timeout_ms % 1000) * 1000;

    r = select(sc->fd + 1, &readfds, NULL, &exceptfds, &t);
    if (r < 0)
        return -errno;
    if (r == 0)
        return -ETIMEDOUT; // Timeout occurred
    r = read(sc->fd, buffer, max_len);
    if (r < 0)
        r = -errno;
#endif
    if (r > 0 && sc->logfile) {
        fwrite(buffer, (size_t)r, 1, sc->logfile);
        fflush(sc->logfile);
    }
    return r;
}

// Assembly:
pushq %r15
pushq %r14
pushq %r12
pushq %rbx
subq $0x118, %rsp            # imm = 0x118
pushq $-0x16
popq %r12
testq %rdi, %rdi
je 0x53ce
movq %rdx, %r15
testq %rdx, %rdx
je 0x53b8
movq %rsi, %r14
testq %rsi, %rsi
je 0x53ce
movq %rcx, %r8
movq %rdi, %rbx
xorl %eax, %eax
cmpq $0x10, %rax
je 0x52fb
andq $0x0, 0x98(%rsp,%rax,8)
incq %rax
jmp 0x52e7
movl (%rbx), %edi
pushq $0x40
popq %rcx
movl %edi, %eax
cltd
idivl %ecx
movslq %eax, %rdx
shll $0x6, %eax
movl %edi, %ecx
subl %eax, %ecx
pushq $0x1
popq %rax
shlq %cl, %rax
orq %rax, 0x98(%rsp,%rdx,8)
xorl %ecx, %ecx
cmpq $0x10, %rcx
je 0x5330
andq $0x0, 0x18(%rsp,%rcx,8)
incq %rcx
jmp 0x531f
orq %rax, 0x18(%rsp,%rdx,8)
movl $0x3e8, %ecx            # imm = 0x3E8
movq %r8, %rax
xorl %edx, %edx
divq %rcx
leaq 0x8(%rsp), %r8
movq %rax, (%r8)
imulq $0x3e8, %rdx, %rax      # imm = 0x3E8
movq %rax, 0x8(%r8)
incl %edi
leaq 0x98(%rsp), %rsi
leaq 0x18(%rsp), %rcx
xorl %edx, %edx
callq 0x2290
testl %eax, %eax
js 0x53bd
je 0x53ca
movl (%rbx), %edi
movq %r14, %rsi
movq %r15, %rdx
callq 0x21f0
movq %rax, %r12
testq %rax, %rax
jns 0x5391
callq 0x2060
movslq (%rax), %r12
negq %r12
testq %r12, %r12
jle 0x53ce
movq 0x8(%rbx), %rcx
testq %rcx, %rcx
je 0x53ce
pushq $0x1
popq %rdx
movq %r14, %rdi
movq %r12, %rsi
callq 0x2390
movq 0x8(%rbx), %rdi
callq 0x22a0
jmp 0x53ce
xorl %r12d, %r12d
jmp 0x53ce
callq 0x2060
movslq (%rax), %r12
negq %r12
jmp 0x53ce
pushq $-0x6e
popq %r12
movq %r12, %rax
addq $0x118, %rsp            # imm = 0x118
popq %rbx
popq %r12
popq %r14
popq %r15
retq