// File: 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 %rbp
movq %rsp, %rbp
subq $0x160, %rsp            # imm = 0x160
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq %rdx, -0x20(%rbp)
movq %rcx, -0x28(%rbp)
cmpq $0x0, -0x10(%rbp)
jne 0x665f
movq $-0x16, -0x8(%rbp)
jmp 0x689f
cmpq $0x0, -0x20(%rbp)
jne 0x6673
movq $0x0, -0x8(%rbp)
jmp 0x689f
cmpq $0x0, -0x18(%rbp)
jne 0x6687
movq $-0x16, -0x8(%rbp)
jmp 0x689f
movq $0x0, -0x30(%rbp)
leaq -0xb0(%rbp), %rax
movq %rax, -0x150(%rbp)
movl $0x0, -0x144(%rbp)
movl -0x144(%rbp), %eax
cmpq $0x10, %rax
jae 0x66d9
movq -0x150(%rbp), %rax
movl -0x144(%rbp), %ecx
movq $0x0, (%rax,%rcx,8)
movl -0x144(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x144(%rbp)
jmp 0x66a7
jmp 0x66db
movq -0x10(%rbp), %rax
movl (%rax), %eax
movl $0x40, %ecx
cltd
idivl %ecx
movl %edx, %eax
movl %eax, %ecx
movl $0x1, %eax
shlq %cl, %rax
movq %rax, %rcx
movq -0x10(%rbp), %rax
movl (%rax), %eax
movl $0x40, %esi
cltd
idivl %esi
cltq
orq -0xb0(%rbp,%rax,8), %rcx
movq %rcx, -0xb0(%rbp,%rax,8)
leaq -0x130(%rbp), %rax
movq %rax, -0x160(%rbp)
movl $0x0, -0x154(%rbp)
movl -0x154(%rbp), %eax
cmpq $0x10, %rax
jae 0x6762
movq -0x160(%rbp), %rax
movl -0x154(%rbp), %ecx
movq $0x0, (%rax,%rcx,8)
movl -0x154(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x154(%rbp)
jmp 0x6730
jmp 0x6764
movq -0x10(%rbp), %rax
movl (%rax), %eax
movl $0x40, %ecx
cltd
idivl %ecx
movl %edx, %eax
movl %eax, %ecx
movl $0x1, %eax
shlq %cl, %rax
movq %rax, %rcx
movq -0x10(%rbp), %rax
movl (%rax), %eax
movl $0x40, %esi
cltd
idivl %esi
cltq
orq -0x130(%rbp,%rax,8), %rcx
movq %rcx, -0x130(%rbp,%rax,8)
movq -0x28(%rbp), %rax
movl $0x3e8, %ecx            # imm = 0x3E8
xorl %edx, %edx
divq %rcx
movq %rax, -0x140(%rbp)
movq -0x28(%rbp), %rax
movl $0x3e8, %ecx            # imm = 0x3E8
xorl %edx, %edx
divq %rcx
imulq $0x3e8, %rdx, %rax      # imm = 0x3E8
movq %rax, -0x138(%rbp)
movq -0x10(%rbp), %rax
movl (%rax), %edi
addl $0x1, %edi
leaq -0xb0(%rbp), %rsi
xorl %eax, %eax
movl %eax, %edx
leaq -0x130(%rbp), %rcx
leaq -0x140(%rbp), %r8
callq 0x2270
cltq
movq %rax, -0x30(%rbp)
cmpq $0x0, -0x30(%rbp)
jge 0x681d
callq 0x2050
movq %rax, %rcx
xorl %eax, %eax
subl (%rcx), %eax
cltq
movq %rax, -0x8(%rbp)
jmp 0x689f
cmpq $0x0, -0x30(%rbp)
jne 0x682e
movq $-0x6e, -0x8(%rbp)
jmp 0x689f
movq -0x10(%rbp), %rax
movl (%rax), %edi
movq -0x18(%rbp), %rsi
movq -0x20(%rbp), %rdx
callq 0x21c0
movq %rax, -0x30(%rbp)
cmpq $0x0, -0x30(%rbp)
jge 0x685e
callq 0x2050
movq %rax, %rcx
xorl %eax, %eax
subl (%rcx), %eax
cltq
movq %rax, -0x30(%rbp)
cmpq $0x0, -0x30(%rbp)
jle 0x6897
movq -0x10(%rbp), %rax
cmpq $0x0, 0x8(%rax)
je 0x6897
movq -0x18(%rbp), %rdi
movq -0x30(%rbp), %rsi
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rcx
movl $0x1, %edx
callq 0x2370
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdi
callq 0x2290
movq -0x30(%rbp), %rax
movq %rax, -0x8(%rbp)
movq -0x8(%rbp), %rax
addq $0x160, %rsp            # imm = 0x160
popq %rbp
retq
nopl (%rax)