// File: /workspace/github_cpp_makefile_star2_O3/AndreRenaud[P]simple_uart/simple_uart.c
// Function: simple_uart_describe
int simple_uart_describe(const char *uart, char *description, size_t max_desc_len)
{
    if (!uart || !description || max_desc_len == 0)
        return -EINVAL;

#if defined(_WIN32) || defined(__linux__)
    char chrBuf[256]; // help buffer
#endif

    description[0] = '\0'; // empty string

// Windows Implementation
#if defined(_WIN32)
    int intMatchUart = 0; // device on machine matched
    HDEVINFO deviceInfoSet;
    DWORD i;

    /*  Get handle of device information
     *    @see https://learn.microsoft.com/en-us/windows/win32/api/setupapi/nf-setupapi-setupdigetclassdevsa
     *    *A: Ansi Function, *W: Unicode function
     */
    deviceInfoSet = SetupDiGetClassDevsA((const GUID *)&GUID_DEVCLASS_PORTS, NULL, NULL, DIGCF_PRESENT);
    if (INVALID_HANDLE_VALUE == deviceInfoSet) {
        return -1;
    }
    /* get device info */
    SP_DEVINFO_DATA deviceInfoData;
    deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
    /*  iterate over DEVCLASS_PORTS elements
     *    @see
     * https://learn.microsoft.com/en-us/windows/win32/api/setupapi/nf-setupapi-setupdigetdeviceregistrypropertya
     */
    i = 0;
    while (SetupDiEnumDeviceInfo(deviceInfoSet, i, &deviceInfoData)) {
        /* get user friendly name */
        if (SetupDiGetDeviceRegistryPropertyA(deviceInfoSet, &deviceInfoData, SPDRP_FRIENDLYNAME, NULL, (PBYTE)chrBuf,
                                              sizeof(chrBuf), NULL)) {
            /* match by name */
            if (strstr(chrBuf, uart) != NULL) { // mark as name hit and leave
                intMatchUart = 1;
                break;
            }
        } else {
            return win32_errno();
        }
        ++i;
    }
    /* no match by name */
    if (0 == intMatchUart)
        return 0;
    /*  acquire HW ID
     *    f.e. USB\VID_04D8&PID_FFEE&REV_0100
     */
    if (SetupDiGetDeviceRegistryPropertyA(deviceInfoSet, &deviceInfoData, SPDRP_HARDWAREID, NULL, (PBYTE)chrBuf,
                                          sizeof(chrBuf), NULL)) {
        /* help */
        char chrId[5];     // extract VID/PID from HWID string
        const char *pHelp; // string matching
        /* PID */
        pHelp = strstr(chrBuf, "PID_"); // search for string
        if (NULL != pHelp) {
            strncpy(chrId, pHelp + 4, 4); // copy ID
            chrId[4] = '\0';
            snprintf(description + strlen(description), max_desc_len - strlen(description), "PID=%s,", chrId);
        }
        /* VID */
        pHelp = strstr(chrBuf, "VID_"); // search for string
        if (NULL != pHelp) {
            strncpy(chrId, pHelp + 4, 4); // copy ID
            chrId[4] = '\0';
            snprintf(description + strlen(description), max_desc_len - strlen(description), "VID=%s,", chrId);
        }
    }
    // Append next required property here
// Linux Implementation
#elif defined(__linux__)
    char unresolvedPath[PATH_MAX]; // symbolic path to TTY device
    char basePath[PATH_MAX];       // path to read out file
    char pathUp[32];               // number of hierarchy level ups
    char *ptrHelp;                 // help pointer
    int intCnt = 0;                // counts occurrence of device name
    /* assemble real path */
    snprintf(unresolvedPath, sizeof(unresolvedPath), "/sys/class/tty/%s", basename((char *)uart));
    if (!(NULL != realpath(unresolvedPath, basePath))) { // resolve symbolic link
        return -1;
    }
    // result: /sys/devices/pci0000:00/0000:00:06.0/usb2/2-2/2-2:1.0/tty/ttyACM0
    //         /sys/devices/pci0000:00/0000:00:06.0/usb2/2-2/2-2:1.0/ttyUSB0/tty/ttyUSB0
    /* determine number of dropped subdirs */
    ptrHelp = strstr(basePath, basename((char *)uart));
    while (NULL != ptrHelp) {
        ++intCnt;
        ptrHelp = strstr(ptrHelp + 1, basename((char *)uart));
    }
    strncpy(pathUp, "/../../", sizeof(pathUp));
    for (int i = 0; i < intCnt; i++) {
        strncpy(pathUp + strlen(pathUp), "../", sizeof(pathUp) - strlen(pathUp)); // append '../' for going up
    }
    /* drop counted number of subdirs */
    strncpy(unresolvedPath, basePath, sizeof(unresolvedPath));
    strncpy(unresolvedPath + strlen(unresolvedPath), pathUp, sizeof(unresolvedPath) - strlen(unresolvedPath));
    if (!(NULL != realpath(unresolvedPath, basePath))) { // resolve relative path
        return -1;
    }
    // result: /sys/devices/pci0000:00/0000:00:06.0/usb2/2-2
    /* acquire device specific info */
    if (readfile(basePath, "manufacturer", chrBuf, sizeof(chrBuf))) {
        snprintf(description + strlen(description), max_desc_len - strlen(description), "manufacturer='%s',", chrBuf);
    }
    if (readfile(basePath, "product", chrBuf, sizeof(chrBuf))) {
        snprintf(description + strlen(description), max_desc_len - strlen(description), "product='%s',", chrBuf);
    }
    if (readfile(basePath, "idProduct", chrBuf, sizeof(chrBuf))) {
        snprintf(description + strlen(description), max_desc_len - strlen(description), "PID=%s,", chrBuf);
    }
    if (readfile(basePath, "idVendor", chrBuf, sizeof(chrBuf))) {
        snprintf(description + strlen(description), max_desc_len - strlen(description), "VID=%s,", chrBuf);
    }
    if (readfile(basePath, "serial", chrBuf, sizeof(chrBuf))) {
        snprintf(description + strlen(description), max_desc_len - strlen(description), "serial=%s,", chrBuf);
    }
// MacOS
#else // Volunteers for MacOS wanted

#endif
    /* drop last ',' */
    if (0 < strlen(description)) {
        description[strlen(description) - 1] = '\0';
    }
    /* normal end */
    return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x2128, %rsp           # imm = 0x2128
testq %rdi, %rdi
sete %al
testq %rsi, %rsi
sete %cl
orb %al, %cl
testq %rdx, %rdx
sete %al
orb %cl, %al
movl $0xffffffea, %ebp       # imm = 0xFFFFFFEA
jne 0x64d0
movq %rdx, %r14
movq %rsi, %rbx
movq %rdi, %r15
movb $0x0, (%rsi)
callq 0x2280
leaq 0x217d(%rip), %rdx      # 0x83bd
leaq 0x1120(%rsp), %r12
movl $0x1000, %esi           # imm = 0x1000
movq %r12, %rdi
movq %rax, %rcx
xorl %eax, %eax
callq 0x2190
leaq 0x120(%rsp), %rsi
movq %r12, %rdi
callq 0x2260
movl $0xffffffff, %ebp       # imm = 0xFFFFFFFF
testq %rax, %rax
je 0x64d0
movq %r15, %rdi
callq 0x2280
leaq 0x120(%rsp), %rdi
movq %rax, %rsi
callq 0x23d0
testq %rax, %rax
je 0x6300
movq %rax, %r12
xorl %r13d, %r13d
incl %r13d
incq %r12
movq %r15, %rdi
callq 0x2280
movq %r12, %rdi
movq %rax, %rsi
callq 0x23d0
movq %rax, %r12
testq %rax, %rax
jne 0x629b
movups 0x20ad(%rip), %xmm0     # 0x8370
movq %rsp, %r15
movaps %xmm0, 0x10(%r15)
movups 0x208e(%rip), %xmm0     # 0x8360
movaps %xmm0, (%r15)
leaq 0x20f2(%rip), %r12      # 0x83cf
movq %r15, %rdi
callq 0x2150
leaq (%rsp,%rax), %rdi
movl $0x20, %edx
subq %rax, %rdx
movq %r12, %rsi
callq 0x2080
decl %r13d
jne 0x62dd
jmp 0x6317
movups 0x2069(%rip), %xmm0     # 0x8370
movaps %xmm0, 0x10(%rsp)
movups 0x204d(%rip), %xmm0     # 0x8360
movaps %xmm0, (%rsp)
leaq 0x1120(%rsp), %r15
leaq 0x120(%rsp), %r12
movl $0x1000, %r13d          # imm = 0x1000
movl $0x1000, %edx           # imm = 0x1000
movq %r15, %rdi
movq %r12, %rsi
callq 0x2080
movq %r15, %rdi
callq 0x2150
leaq (%rsp,%rax), %rdi
addq $0x1120, %rdi           # imm = 0x1120
subq %rax, %r13
movq %rsp, %rsi
movq %r13, %rdx
callq 0x2080
movq %r15, %rdi
movq %r12, %rsi
callq 0x2260
testq %rax, %rax
je 0x64d0
leaq 0x205a(%rip), %rsi      # 0x83d3
leaq 0x120(%rsp), %rdi
leaq 0x20(%rsp), %rdx
callq 0x64e4
testb %al, %al
je 0x63b4
movq %rbx, %rdi
callq 0x2150
leaq (%rbx,%rax), %rdi
movq %r14, %rsi
subq %rax, %rsi
leaq 0x2038(%rip), %rdx      # 0x83e0
leaq 0x20(%rsp), %rcx
xorl %eax, %eax
callq 0x2190
leaq 0x2038(%rip), %rsi      # 0x83f3
leaq 0x120(%rsp), %rdi
leaq 0x20(%rsp), %rdx
callq 0x64e4
testb %al, %al
je 0x63f6
movq %rbx, %rdi
callq 0x2150
leaq (%rbx,%rax), %rdi
movq %r14, %rsi
subq %rax, %rsi
leaq 0x2011(%rip), %rdx      # 0x83fb
leaq 0x20(%rsp), %rcx
xorl %eax, %eax
callq 0x2190
leaq 0x200c(%rip), %rsi      # 0x8409
leaq 0x120(%rsp), %rdi
leaq 0x20(%rsp), %rdx
callq 0x64e4
testb %al, %al
je 0x6438
movq %rbx, %rdi
callq 0x2150
leaq (%rbx,%rax), %rdi
movq %r14, %rsi
subq %rax, %rsi
leaq 0x1fe7(%rip), %rdx      # 0x8413
leaq 0x20(%rsp), %rcx
xorl %eax, %eax
callq 0x2190
leaq 0x1fdc(%rip), %rsi      # 0x841b
leaq 0x120(%rsp), %rdi
leaq 0x20(%rsp), %rdx
callq 0x64e4
testb %al, %al
je 0x647a
movq %rbx, %rdi
callq 0x2150
leaq (%rbx,%rax), %rdi
movq %r14, %rsi
subq %rax, %rsi
leaq 0x1fb6(%rip), %rdx      # 0x8424
leaq 0x20(%rsp), %rcx
xorl %eax, %eax
callq 0x2190
leaq 0x1fab(%rip), %rsi      # 0x842c
leaq 0x120(%rsp), %rdi
leaq 0x20(%rsp), %rdx
callq 0x64e4
testb %al, %al
je 0x64bc
movq %rbx, %rdi
callq 0x2150
leaq (%rbx,%rax), %rdi
subq %rax, %r14
leaq 0x1f86(%rip), %rdx      # 0x8433
leaq 0x20(%rsp), %rcx
movq %r14, %rsi
xorl %eax, %eax
callq 0x2190
movq %rbx, %rdi
callq 0x2150
xorl %ebp, %ebp
testq %rax, %rax
je 0x64d0
movb $0x0, -0x1(%rbx,%rax)
movl %ebp, %eax
addq $0x2128, %rsp           # imm = 0x2128
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq