Skip to content

[USBX Device Audio] _ux_device_class_audio_transmission_start logic prevents Microphone stream start on Isochronous IN #236

Description

@NicoCaldo

Describe the bug
A logic error in the _ux_device_class_audio_transmission_start function prevents the Microphone (Isochronous IN) stream from starting when the buffer is correctly primed. The function checks if (stream -> ux_device_class_audio_stream_transfer_pos -> ux_device_class_audio_frame_length == 0) and returns UX_BUFFER_OVERFLOW if true. However, because the microphone thread is suspended and hasn't processed its first frame yet, this condition often triggers even when data is waiting, or conversely, blocks the initial resume of the audio thread.

Inverting this logic or bypassing it allows the Host (Windows) to begin sending Isochronous IN tokens, which are otherwise never sent.

Hardware and Software Environment:

  • Target device: STM32U5A9J-DK (using USB OTG HS)
  • Version of Eclipse ThreadX: v6.2.1 or v6.3.0 (USBX Audio 2.0 Class)
  • Toolchain and environment: IAR Embedded Workbench for ARM / STM32CubeIDE
  • Diagnostics tried: - Verified USB Descriptors (Clock Source IDs, Terminal Links, and Endpoint addresses).
  • Monitored USB traffic via Wireshark; confirmed Windows never sends IN tokens for the Mic interface until the library was patched.
  • Traced ux_device_class_audio_write_thread_entry and found it permanently SUSPENDED due to the initialization failure in transmission_start.

To Reproduce
Steps to reproduce the behavior:

  1. Initialize a USBX Audio 2.0 device with both Speaker (OUT) and Microphone (IN) interfaces.
  2. Link the Microphone path to the same Clock Source as the Speaker.
  3. In the ux_device_class_audio_stream_change callback, attempt to prime the Mic buffer using ux_device_class_audio_write_frame_get and ux_device_class_audio_write_frame_commit.
  4. Call ux_device_class_audio_transmission_start.
  5. Observe that the function returns UX_BUFFER_OVERFLOW (0x5D) and the microphone thread never executes.

Expected behavior
The ux_device_class_audio_transmission_start function should successfully resume the audio write thread when a valid stream is configured, allowing the hardware to prepare for the first Host IN token.

Impact
Showstopper. Without the patch/inversion of the logic, it is impossible to implement a USB Audio Microphone or Loopback interface, as the Host fails to recognize the data stream and eventually returns a "Code 10" error in Device Manager.

Logs and console output

  • Wireshark: Shows SET_INTERFACE (Alt 1) for the Mic interface followed by zero Isochronous IN packets.
  • Debugger:stream->ux_device_class_audio_stream_transfer_pos->ux_device_class_audio_frame_length is observed as 0 at the moment of the failing check.

Additional context
The issue seems specifically tied to the initial state of the transfer_pos structure when the stream is transitioned from Alt Setting 0 to Alt Setting 1. Even if the buffer is primed with ux_device_class_audio_write_frame_commit immediately prior to the start call, the pointer/length state within the USBX internal structures does not always satisfy the == 0 check in the way the driver expects.

Workaround: Patching the USBX Library

File:ux_device_class_audio_transmission_start.c

Description: The original logic prevents the transmission thread from resuming if the frame length is 0. However, in many initialization sequences, the length remains 0 until the thread is actually running and the hardware starts its first transfer cycle. By inverting the logic, we allow the thread to resume and the Host to begin polling.

Modified Code:

/* Check if there is frame to send (underflow). *//* ORIGINAL: if (stream -> ux_device_class_audio_stream_transfer_pos -> ux_device_class_audio_frame_length == 0) *//* PATCHED: Invert logic to allow initial thread resumption */if (stream->ux_device_class_audio_stream_transfer_pos->ux_device_class_audio_frame_length>0)
{
return(UX_BUFFER_OVERFLOW);
}

Additional context

When using the original == 0 check, a "deadlock" occurs:

  1. The Host sends SET_INTERFACE to enable the Microphone.
  2. ux_device_class_audio_transmission_start() is called.
  3. The check fails (returns UX_BUFFER_OVERFLOW) because the internal transfer_pos hasn't been updated by an active transfer yet.
  4. The Microphone thread remains SUSPENDED.
  5. Because the thread is suspended, no data is ever moved to the FIFO.
  6. The Host (Windows) receives no data for its initial IN tokens, times out, and stops polling, resulting in Error Code 10.

By changing the condition to > 0, the function returns UX_SUCCESS when the length is 0, successfully executing _ux_device_thread_resume(). This allows the USBX audio thread to wake up, interact with the hardware driver, and satisfy the Host's requests.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    , 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
     blocks
    (function() {
    function addCopyButtons() {
    document.querySelectorAll('pre code').forEach(function(codeBlock) {
    if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
    codeBlock.parentElement.setAttribute('data-copy-added', 'true');
    var btn = document.createElement('button');
    btn.textContent = 'Copy';
    btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
    btn.onmouseover = function() { this.style.opacity = '1'; };
    btn.onmouseout = function() { this.style.opacity = '0.7'; };
    btn.onclick = function() {
    navigator.clipboard.writeText(codeBlock.textContent).then(function() {
    btn.textContent = 'Copied!';
    setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
    });
    };
    codeBlock.parentElement.style.position = 'relative';
    codeBlock.parentElement.appendChild(btn);
    });
    }
    addCopyButtons();
    // Re-run on dynamic content
    var observer = new MutationObserver(addCopyButtons);
    observer.observe(document.body, { childList: true, subtree: true });
    })();
    }
    } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
    })();
    (function(){
    try {
    var __m = "github.com";
    var __re = new RegExp('^' + "github\\.com" + '
    [USBX Device Audio] _ux_device_class_audio_transmission_start logic prevents Microphone stream start on Isochronous IN · Issue #236 · eclipse-threadx/usbx · GitHub
    Skip to content

    [USBX Device Audio] _ux_device_class_audio_transmission_start logic prevents Microphone stream start on Isochronous IN #236

    Description

    @NicoCaldo

    Describe the bug
    A logic error in the _ux_device_class_audio_transmission_start function prevents the Microphone (Isochronous IN) stream from starting when the buffer is correctly primed. The function checks if (stream -> ux_device_class_audio_stream_transfer_pos -> ux_device_class_audio_frame_length == 0) and returns UX_BUFFER_OVERFLOW if true. However, because the microphone thread is suspended and hasn't processed its first frame yet, this condition often triggers even when data is waiting, or conversely, blocks the initial resume of the audio thread.

    Inverting this logic or bypassing it allows the Host (Windows) to begin sending Isochronous IN tokens, which are otherwise never sent.

    Hardware and Software Environment:

    • Target device: STM32U5A9J-DK (using USB OTG HS)
    • Version of Eclipse ThreadX: v6.2.1 or v6.3.0 (USBX Audio 2.0 Class)
    • Toolchain and environment: IAR Embedded Workbench for ARM / STM32CubeIDE
    • Diagnostics tried: - Verified USB Descriptors (Clock Source IDs, Terminal Links, and Endpoint addresses).
    • Monitored USB traffic via Wireshark; confirmed Windows never sends IN tokens for the Mic interface until the library was patched.
    • Traced ux_device_class_audio_write_thread_entry and found it permanently SUSPENDED due to the initialization failure in transmission_start.

    To Reproduce
    Steps to reproduce the behavior:

    1. Initialize a USBX Audio 2.0 device with both Speaker (OUT) and Microphone (IN) interfaces.
    2. Link the Microphone path to the same Clock Source as the Speaker.
    3. In the ux_device_class_audio_stream_change callback, attempt to prime the Mic buffer using ux_device_class_audio_write_frame_get and ux_device_class_audio_write_frame_commit.
    4. Call ux_device_class_audio_transmission_start.
    5. Observe that the function returns UX_BUFFER_OVERFLOW (0x5D) and the microphone thread never executes.

    Expected behavior
    The ux_device_class_audio_transmission_start function should successfully resume the audio write thread when a valid stream is configured, allowing the hardware to prepare for the first Host IN token.

    Impact
    Showstopper. Without the patch/inversion of the logic, it is impossible to implement a USB Audio Microphone or Loopback interface, as the Host fails to recognize the data stream and eventually returns a "Code 10" error in Device Manager.

    Logs and console output

    • Wireshark: Shows SET_INTERFACE (Alt 1) for the Mic interface followed by zero Isochronous IN packets.
    • Debugger:stream->ux_device_class_audio_stream_transfer_pos->ux_device_class_audio_frame_length is observed as 0 at the moment of the failing check.

    Additional context
    The issue seems specifically tied to the initial state of the transfer_pos structure when the stream is transitioned from Alt Setting 0 to Alt Setting 1. Even if the buffer is primed with ux_device_class_audio_write_frame_commit immediately prior to the start call, the pointer/length state within the USBX internal structures does not always satisfy the == 0 check in the way the driver expects.

    Workaround: Patching the USBX Library

    File:ux_device_class_audio_transmission_start.c

    Description: The original logic prevents the transmission thread from resuming if the frame length is 0. However, in many initialization sequences, the length remains 0 until the thread is actually running and the hardware starts its first transfer cycle. By inverting the logic, we allow the thread to resume and the Host to begin polling.

    Modified Code:

    /* Check if there is frame to send (underflow). *//* ORIGINAL: if (stream -> ux_device_class_audio_stream_transfer_pos -> ux_device_class_audio_frame_length == 0) *//* PATCHED: Invert logic to allow initial thread resumption */if (stream->ux_device_class_audio_stream_transfer_pos->ux_device_class_audio_frame_length>0)
    {
    return(UX_BUFFER_OVERFLOW);
    }

    Additional context

    When using the original == 0 check, a "deadlock" occurs:

    1. The Host sends SET_INTERFACE to enable the Microphone.
    2. ux_device_class_audio_transmission_start() is called.
    3. The check fails (returns UX_BUFFER_OVERFLOW) because the internal transfer_pos hasn't been updated by an active transfer yet.
    4. The Microphone thread remains SUSPENDED.
    5. Because the thread is suspended, no data is ever moved to the FIFO.
    6. The Host (Windows) receives no data for its initial IN tokens, times out, and stops polling, resulting in Error Code 10.

    By changing the condition to > 0, the function returns UX_SUCCESS when the length is 0, successfully executing _ux_device_thread_resume(). This allows the USBX audio thread to wake up, interact with the hardware driver, and satisfy the Host's requests.

    Metadata

    Metadata

    Assignees

    No one assigned

      Labels

      bugSomething isn't working

      Type

      No type

      Projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      , 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [USBX Device Audio] _ux_device_class_audio_transmission_start logic prevents Microphone stream start on Isochronous IN · Issue #236 · eclipse-threadx/usbx · GitHub
      Skip to content

      [USBX Device Audio] _ux_device_class_audio_transmission_start logic prevents Microphone stream start on Isochronous IN #236

      Description

      @NicoCaldo

      Describe the bug
      A logic error in the _ux_device_class_audio_transmission_start function prevents the Microphone (Isochronous IN) stream from starting when the buffer is correctly primed. The function checks if (stream -> ux_device_class_audio_stream_transfer_pos -> ux_device_class_audio_frame_length == 0) and returns UX_BUFFER_OVERFLOW if true. However, because the microphone thread is suspended and hasn't processed its first frame yet, this condition often triggers even when data is waiting, or conversely, blocks the initial resume of the audio thread.

      Inverting this logic or bypassing it allows the Host (Windows) to begin sending Isochronous IN tokens, which are otherwise never sent.

      Hardware and Software Environment:

      • Target device: STM32U5A9J-DK (using USB OTG HS)
      • Version of Eclipse ThreadX: v6.2.1 or v6.3.0 (USBX Audio 2.0 Class)
      • Toolchain and environment: IAR Embedded Workbench for ARM / STM32CubeIDE
      • Diagnostics tried: - Verified USB Descriptors (Clock Source IDs, Terminal Links, and Endpoint addresses).
      • Monitored USB traffic via Wireshark; confirmed Windows never sends IN tokens for the Mic interface until the library was patched.
      • Traced ux_device_class_audio_write_thread_entry and found it permanently SUSPENDED due to the initialization failure in transmission_start.

      To Reproduce
      Steps to reproduce the behavior:

      1. Initialize a USBX Audio 2.0 device with both Speaker (OUT) and Microphone (IN) interfaces.
      2. Link the Microphone path to the same Clock Source as the Speaker.
      3. In the ux_device_class_audio_stream_change callback, attempt to prime the Mic buffer using ux_device_class_audio_write_frame_get and ux_device_class_audio_write_frame_commit.
      4. Call ux_device_class_audio_transmission_start.
      5. Observe that the function returns UX_BUFFER_OVERFLOW (0x5D) and the microphone thread never executes.

      Expected behavior
      The ux_device_class_audio_transmission_start function should successfully resume the audio write thread when a valid stream is configured, allowing the hardware to prepare for the first Host IN token.

      Impact
      Showstopper. Without the patch/inversion of the logic, it is impossible to implement a USB Audio Microphone or Loopback interface, as the Host fails to recognize the data stream and eventually returns a "Code 10" error in Device Manager.

      Logs and console output

      • Wireshark: Shows SET_INTERFACE (Alt 1) for the Mic interface followed by zero Isochronous IN packets.
      • Debugger:stream->ux_device_class_audio_stream_transfer_pos->ux_device_class_audio_frame_length is observed as 0 at the moment of the failing check.

      Additional context
      The issue seems specifically tied to the initial state of the transfer_pos structure when the stream is transitioned from Alt Setting 0 to Alt Setting 1. Even if the buffer is primed with ux_device_class_audio_write_frame_commit immediately prior to the start call, the pointer/length state within the USBX internal structures does not always satisfy the == 0 check in the way the driver expects.

      Workaround: Patching the USBX Library

      File:ux_device_class_audio_transmission_start.c

      Description: The original logic prevents the transmission thread from resuming if the frame length is 0. However, in many initialization sequences, the length remains 0 until the thread is actually running and the hardware starts its first transfer cycle. By inverting the logic, we allow the thread to resume and the Host to begin polling.

      Modified Code:

      /* Check if there is frame to send (underflow). *//* ORIGINAL: if (stream -> ux_device_class_audio_stream_transfer_pos -> ux_device_class_audio_frame_length == 0) *//* PATCHED: Invert logic to allow initial thread resumption */if (stream->ux_device_class_audio_stream_transfer_pos->ux_device_class_audio_frame_length>0)
      {
      return(UX_BUFFER_OVERFLOW);
      }

      Additional context

      When using the original == 0 check, a "deadlock" occurs:

      1. The Host sends SET_INTERFACE to enable the Microphone.
      2. ux_device_class_audio_transmission_start() is called.
      3. The check fails (returns UX_BUFFER_OVERFLOW) because the internal transfer_pos hasn't been updated by an active transfer yet.
      4. The Microphone thread remains SUSPENDED.
      5. Because the thread is suspended, no data is ever moved to the FIFO.
      6. The Host (Windows) receives no data for its initial IN tokens, times out, and stops polling, resulting in Error Code 10.

      By changing the condition to > 0, the function returns UX_SUCCESS when the length is 0, successfully executing _ux_device_thread_resume(). This allows the USBX audio thread to wake up, interact with the hardware driver, and satisfy the Host's requests.

      Metadata

      Metadata

      Assignees

      No one assigned

        Labels

        bugSomething isn't working

        Type

        No type

        Projects

        Milestone

        No milestone

        Relationships

        None yet

        Development

        No branches or pull requests

        Issue actions

        , 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [USBX Device Audio] _ux_device_class_audio_transmission_start logic prevents Microphone stream start on Isochronous IN · Issue #236 · eclipse-threadx/usbx · GitHub
        Skip to content

        [USBX Device Audio] _ux_device_class_audio_transmission_start logic prevents Microphone stream start on Isochronous IN #236

        Description

        @NicoCaldo

        Describe the bug
        A logic error in the _ux_device_class_audio_transmission_start function prevents the Microphone (Isochronous IN) stream from starting when the buffer is correctly primed. The function checks if (stream -> ux_device_class_audio_stream_transfer_pos -> ux_device_class_audio_frame_length == 0) and returns UX_BUFFER_OVERFLOW if true. However, because the microphone thread is suspended and hasn't processed its first frame yet, this condition often triggers even when data is waiting, or conversely, blocks the initial resume of the audio thread.

        Inverting this logic or bypassing it allows the Host (Windows) to begin sending Isochronous IN tokens, which are otherwise never sent.

        Hardware and Software Environment:

        • Target device: STM32U5A9J-DK (using USB OTG HS)
        • Version of Eclipse ThreadX: v6.2.1 or v6.3.0 (USBX Audio 2.0 Class)
        • Toolchain and environment: IAR Embedded Workbench for ARM / STM32CubeIDE
        • Diagnostics tried: - Verified USB Descriptors (Clock Source IDs, Terminal Links, and Endpoint addresses).
        • Monitored USB traffic via Wireshark; confirmed Windows never sends IN tokens for the Mic interface until the library was patched.
        • Traced ux_device_class_audio_write_thread_entry and found it permanently SUSPENDED due to the initialization failure in transmission_start.

        To Reproduce
        Steps to reproduce the behavior:

        1. Initialize a USBX Audio 2.0 device with both Speaker (OUT) and Microphone (IN) interfaces.
        2. Link the Microphone path to the same Clock Source as the Speaker.
        3. In the ux_device_class_audio_stream_change callback, attempt to prime the Mic buffer using ux_device_class_audio_write_frame_get and ux_device_class_audio_write_frame_commit.
        4. Call ux_device_class_audio_transmission_start.
        5. Observe that the function returns UX_BUFFER_OVERFLOW (0x5D) and the microphone thread never executes.

        Expected behavior
        The ux_device_class_audio_transmission_start function should successfully resume the audio write thread when a valid stream is configured, allowing the hardware to prepare for the first Host IN token.

        Impact
        Showstopper. Without the patch/inversion of the logic, it is impossible to implement a USB Audio Microphone or Loopback interface, as the Host fails to recognize the data stream and eventually returns a "Code 10" error in Device Manager.

        Logs and console output

        • Wireshark: Shows SET_INTERFACE (Alt 1) for the Mic interface followed by zero Isochronous IN packets.
        • Debugger:stream->ux_device_class_audio_stream_transfer_pos->ux_device_class_audio_frame_length is observed as 0 at the moment of the failing check.

        Additional context
        The issue seems specifically tied to the initial state of the transfer_pos structure when the stream is transitioned from Alt Setting 0 to Alt Setting 1. Even if the buffer is primed with ux_device_class_audio_write_frame_commit immediately prior to the start call, the pointer/length state within the USBX internal structures does not always satisfy the == 0 check in the way the driver expects.

        Workaround: Patching the USBX Library

        File:ux_device_class_audio_transmission_start.c

        Description: The original logic prevents the transmission thread from resuming if the frame length is 0. However, in many initialization sequences, the length remains 0 until the thread is actually running and the hardware starts its first transfer cycle. By inverting the logic, we allow the thread to resume and the Host to begin polling.

        Modified Code:

        /* Check if there is frame to send (underflow). *//* ORIGINAL: if (stream -> ux_device_class_audio_stream_transfer_pos -> ux_device_class_audio_frame_length == 0) *//* PATCHED: Invert logic to allow initial thread resumption */if (stream->ux_device_class_audio_stream_transfer_pos->ux_device_class_audio_frame_length>0)
        {
        return(UX_BUFFER_OVERFLOW);
        }

        Additional context

        When using the original == 0 check, a "deadlock" occurs:

        1. The Host sends SET_INTERFACE to enable the Microphone.
        2. ux_device_class_audio_transmission_start() is called.
        3. The check fails (returns UX_BUFFER_OVERFLOW) because the internal transfer_pos hasn't been updated by an active transfer yet.
        4. The Microphone thread remains SUSPENDED.
        5. Because the thread is suspended, no data is ever moved to the FIFO.
        6. The Host (Windows) receives no data for its initial IN tokens, times out, and stops polling, resulting in Error Code 10.

        By changing the condition to > 0, the function returns UX_SUCCESS when the length is 0, successfully executing _ux_device_thread_resume(). This allows the USBX audio thread to wake up, interact with the hardware driver, and satisfy the Host's requests.

        Metadata

        Metadata

        Assignees

        No one assigned

          Labels

          bugSomething isn't working

          Type

          No type

          Projects

          Milestone

          No milestone

          Relationships

          None yet

          Development

          No branches or pull requests

          Issue actions

          , 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' [USBX Device Audio] _ux_device_class_audio_transmission_start logic prevents Microphone stream start on Isochronous IN · Issue #236 · eclipse-threadx/usbx · GitHub
          Skip to content

          [USBX Device Audio] _ux_device_class_audio_transmission_start logic prevents Microphone stream start on Isochronous IN #236

          Description

          @NicoCaldo

          Describe the bug
          A logic error in the _ux_device_class_audio_transmission_start function prevents the Microphone (Isochronous IN) stream from starting when the buffer is correctly primed. The function checks if (stream -> ux_device_class_audio_stream_transfer_pos -> ux_device_class_audio_frame_length == 0) and returns UX_BUFFER_OVERFLOW if true. However, because the microphone thread is suspended and hasn't processed its first frame yet, this condition often triggers even when data is waiting, or conversely, blocks the initial resume of the audio thread.

          Inverting this logic or bypassing it allows the Host (Windows) to begin sending Isochronous IN tokens, which are otherwise never sent.

          Hardware and Software Environment:

          • Target device: STM32U5A9J-DK (using USB OTG HS)
          • Version of Eclipse ThreadX: v6.2.1 or v6.3.0 (USBX Audio 2.0 Class)
          • Toolchain and environment: IAR Embedded Workbench for ARM / STM32CubeIDE
          • Diagnostics tried: - Verified USB Descriptors (Clock Source IDs, Terminal Links, and Endpoint addresses).
          • Monitored USB traffic via Wireshark; confirmed Windows never sends IN tokens for the Mic interface until the library was patched.
          • Traced ux_device_class_audio_write_thread_entry and found it permanently SUSPENDED due to the initialization failure in transmission_start.

          To Reproduce
          Steps to reproduce the behavior:

          1. Initialize a USBX Audio 2.0 device with both Speaker (OUT) and Microphone (IN) interfaces.
          2. Link the Microphone path to the same Clock Source as the Speaker.
          3. In the ux_device_class_audio_stream_change callback, attempt to prime the Mic buffer using ux_device_class_audio_write_frame_get and ux_device_class_audio_write_frame_commit.
          4. Call ux_device_class_audio_transmission_start.
          5. Observe that the function returns UX_BUFFER_OVERFLOW (0x5D) and the microphone thread never executes.

          Expected behavior
          The ux_device_class_audio_transmission_start function should successfully resume the audio write thread when a valid stream is configured, allowing the hardware to prepare for the first Host IN token.

          Impact
          Showstopper. Without the patch/inversion of the logic, it is impossible to implement a USB Audio Microphone or Loopback interface, as the Host fails to recognize the data stream and eventually returns a "Code 10" error in Device Manager.

          Logs and console output

          • Wireshark: Shows SET_INTERFACE (Alt 1) for the Mic interface followed by zero Isochronous IN packets.
          • Debugger:stream->ux_device_class_audio_stream_transfer_pos->ux_device_class_audio_frame_length is observed as 0 at the moment of the failing check.

          Additional context
          The issue seems specifically tied to the initial state of the transfer_pos structure when the stream is transitioned from Alt Setting 0 to Alt Setting 1. Even if the buffer is primed with ux_device_class_audio_write_frame_commit immediately prior to the start call, the pointer/length state within the USBX internal structures does not always satisfy the == 0 check in the way the driver expects.

          Workaround: Patching the USBX Library

          File:ux_device_class_audio_transmission_start.c

          Description: The original logic prevents the transmission thread from resuming if the frame length is 0. However, in many initialization sequences, the length remains 0 until the thread is actually running and the hardware starts its first transfer cycle. By inverting the logic, we allow the thread to resume and the Host to begin polling.

          Modified Code:

          /* Check if there is frame to send (underflow). *//* ORIGINAL: if (stream -> ux_device_class_audio_stream_transfer_pos -> ux_device_class_audio_frame_length == 0) *//* PATCHED: Invert logic to allow initial thread resumption */if (stream->ux_device_class_audio_stream_transfer_pos->ux_device_class_audio_frame_length>0)
          {
          return(UX_BUFFER_OVERFLOW);
          }

          Additional context

          When using the original == 0 check, a "deadlock" occurs:

          1. The Host sends SET_INTERFACE to enable the Microphone.
          2. ux_device_class_audio_transmission_start() is called.
          3. The check fails (returns UX_BUFFER_OVERFLOW) because the internal transfer_pos hasn't been updated by an active transfer yet.
          4. The Microphone thread remains SUSPENDED.
          5. Because the thread is suspended, no data is ever moved to the FIFO.
          6. The Host (Windows) receives no data for its initial IN tokens, times out, and stops polling, resulting in Error Code 10.

          By changing the condition to > 0, the function returns UX_SUCCESS when the length is 0, successfully executing _ux_device_thread_resume(). This allows the USBX audio thread to wake up, interact with the hardware driver, and satisfy the Host's requests.

          Metadata

          Metadata

          Assignees

          No one assigned

            Labels

            bugSomething isn't working

            Type

            No type

            Projects

            Milestone

            No milestone

            Relationships

            None yet

            Development

            No branches or pull requests

            Issue actions

            , 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [USBX Device Audio] _ux_device_class_audio_transmission_start logic prevents Microphone stream start on Isochronous IN · Issue #236 · eclipse-threadx/usbx · GitHub
            Skip to content

            [USBX Device Audio] _ux_device_class_audio_transmission_start logic prevents Microphone stream start on Isochronous IN #236

            Description

            @NicoCaldo

            Describe the bug
            A logic error in the _ux_device_class_audio_transmission_start function prevents the Microphone (Isochronous IN) stream from starting when the buffer is correctly primed. The function checks if (stream -> ux_device_class_audio_stream_transfer_pos -> ux_device_class_audio_frame_length == 0) and returns UX_BUFFER_OVERFLOW if true. However, because the microphone thread is suspended and hasn't processed its first frame yet, this condition often triggers even when data is waiting, or conversely, blocks the initial resume of the audio thread.

            Inverting this logic or bypassing it allows the Host (Windows) to begin sending Isochronous IN tokens, which are otherwise never sent.

            Hardware and Software Environment:

            • Target device: STM32U5A9J-DK (using USB OTG HS)
            • Version of Eclipse ThreadX: v6.2.1 or v6.3.0 (USBX Audio 2.0 Class)
            • Toolchain and environment: IAR Embedded Workbench for ARM / STM32CubeIDE
            • Diagnostics tried: - Verified USB Descriptors (Clock Source IDs, Terminal Links, and Endpoint addresses).
            • Monitored USB traffic via Wireshark; confirmed Windows never sends IN tokens for the Mic interface until the library was patched.
            • Traced ux_device_class_audio_write_thread_entry and found it permanently SUSPENDED due to the initialization failure in transmission_start.

            To Reproduce
            Steps to reproduce the behavior:

            1. Initialize a USBX Audio 2.0 device with both Speaker (OUT) and Microphone (IN) interfaces.
            2. Link the Microphone path to the same Clock Source as the Speaker.
            3. In the ux_device_class_audio_stream_change callback, attempt to prime the Mic buffer using ux_device_class_audio_write_frame_get and ux_device_class_audio_write_frame_commit.
            4. Call ux_device_class_audio_transmission_start.
            5. Observe that the function returns UX_BUFFER_OVERFLOW (0x5D) and the microphone thread never executes.

            Expected behavior
            The ux_device_class_audio_transmission_start function should successfully resume the audio write thread when a valid stream is configured, allowing the hardware to prepare for the first Host IN token.

            Impact
            Showstopper. Without the patch/inversion of the logic, it is impossible to implement a USB Audio Microphone or Loopback interface, as the Host fails to recognize the data stream and eventually returns a "Code 10" error in Device Manager.

            Logs and console output

            • Wireshark: Shows SET_INTERFACE (Alt 1) for the Mic interface followed by zero Isochronous IN packets.
            • Debugger:stream->ux_device_class_audio_stream_transfer_pos->ux_device_class_audio_frame_length is observed as 0 at the moment of the failing check.

            Additional context
            The issue seems specifically tied to the initial state of the transfer_pos structure when the stream is transitioned from Alt Setting 0 to Alt Setting 1. Even if the buffer is primed with ux_device_class_audio_write_frame_commit immediately prior to the start call, the pointer/length state within the USBX internal structures does not always satisfy the == 0 check in the way the driver expects.

            Workaround: Patching the USBX Library

            File:ux_device_class_audio_transmission_start.c

            Description: The original logic prevents the transmission thread from resuming if the frame length is 0. However, in many initialization sequences, the length remains 0 until the thread is actually running and the hardware starts its first transfer cycle. By inverting the logic, we allow the thread to resume and the Host to begin polling.

            Modified Code:

            /* Check if there is frame to send (underflow). *//* ORIGINAL: if (stream -> ux_device_class_audio_stream_transfer_pos -> ux_device_class_audio_frame_length == 0) *//* PATCHED: Invert logic to allow initial thread resumption */if (stream->ux_device_class_audio_stream_transfer_pos->ux_device_class_audio_frame_length>0)
            {
            return(UX_BUFFER_OVERFLOW);
            }

            Additional context

            When using the original == 0 check, a "deadlock" occurs:

            1. The Host sends SET_INTERFACE to enable the Microphone.
            2. ux_device_class_audio_transmission_start() is called.
            3. The check fails (returns UX_BUFFER_OVERFLOW) because the internal transfer_pos hasn't been updated by an active transfer yet.
            4. The Microphone thread remains SUSPENDED.
            5. Because the thread is suspended, no data is ever moved to the FIFO.
            6. The Host (Windows) receives no data for its initial IN tokens, times out, and stops polling, resulting in Error Code 10.

            By changing the condition to > 0, the function returns UX_SUCCESS when the length is 0, successfully executing _ux_device_thread_resume(). This allows the USBX audio thread to wake up, interact with the hardware driver, and satisfy the Host's requests.

            Metadata

            Metadata

            Assignees

            No one assigned

              Labels

              bugSomething isn't working

              Type

              No type

              Projects

              Milestone

              No milestone

              Relationships

              None yet

              Development

              No branches or pull requests

              Issue actions

              , 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [USBX Device Audio] _ux_device_class_audio_transmission_start logic prevents Microphone stream start on Isochronous IN · Issue #236 · eclipse-threadx/usbx · GitHub
              Skip to content

              [USBX Device Audio] _ux_device_class_audio_transmission_start logic prevents Microphone stream start on Isochronous IN #236

              Description

              @NicoCaldo

              Describe the bug
              A logic error in the _ux_device_class_audio_transmission_start function prevents the Microphone (Isochronous IN) stream from starting when the buffer is correctly primed. The function checks if (stream -> ux_device_class_audio_stream_transfer_pos -> ux_device_class_audio_frame_length == 0) and returns UX_BUFFER_OVERFLOW if true. However, because the microphone thread is suspended and hasn't processed its first frame yet, this condition often triggers even when data is waiting, or conversely, blocks the initial resume of the audio thread.

              Inverting this logic or bypassing it allows the Host (Windows) to begin sending Isochronous IN tokens, which are otherwise never sent.

              Hardware and Software Environment:

              • Target device: STM32U5A9J-DK (using USB OTG HS)
              • Version of Eclipse ThreadX: v6.2.1 or v6.3.0 (USBX Audio 2.0 Class)
              • Toolchain and environment: IAR Embedded Workbench for ARM / STM32CubeIDE
              • Diagnostics tried: - Verified USB Descriptors (Clock Source IDs, Terminal Links, and Endpoint addresses).
              • Monitored USB traffic via Wireshark; confirmed Windows never sends IN tokens for the Mic interface until the library was patched.
              • Traced ux_device_class_audio_write_thread_entry and found it permanently SUSPENDED due to the initialization failure in transmission_start.

              To Reproduce
              Steps to reproduce the behavior:

              1. Initialize a USBX Audio 2.0 device with both Speaker (OUT) and Microphone (IN) interfaces.
              2. Link the Microphone path to the same Clock Source as the Speaker.
              3. In the ux_device_class_audio_stream_change callback, attempt to prime the Mic buffer using ux_device_class_audio_write_frame_get and ux_device_class_audio_write_frame_commit.
              4. Call ux_device_class_audio_transmission_start.
              5. Observe that the function returns UX_BUFFER_OVERFLOW (0x5D) and the microphone thread never executes.

              Expected behavior
              The ux_device_class_audio_transmission_start function should successfully resume the audio write thread when a valid stream is configured, allowing the hardware to prepare for the first Host IN token.

              Impact
              Showstopper. Without the patch/inversion of the logic, it is impossible to implement a USB Audio Microphone or Loopback interface, as the Host fails to recognize the data stream and eventually returns a "Code 10" error in Device Manager.

              Logs and console output

              • Wireshark: Shows SET_INTERFACE (Alt 1) for the Mic interface followed by zero Isochronous IN packets.
              • Debugger:stream->ux_device_class_audio_stream_transfer_pos->ux_device_class_audio_frame_length is observed as 0 at the moment of the failing check.

              Additional context
              The issue seems specifically tied to the initial state of the transfer_pos structure when the stream is transitioned from Alt Setting 0 to Alt Setting 1. Even if the buffer is primed with ux_device_class_audio_write_frame_commit immediately prior to the start call, the pointer/length state within the USBX internal structures does not always satisfy the == 0 check in the way the driver expects.

              Workaround: Patching the USBX Library

              File:ux_device_class_audio_transmission_start.c

              Description: The original logic prevents the transmission thread from resuming if the frame length is 0. However, in many initialization sequences, the length remains 0 until the thread is actually running and the hardware starts its first transfer cycle. By inverting the logic, we allow the thread to resume and the Host to begin polling.

              Modified Code:

              /* Check if there is frame to send (underflow). *//* ORIGINAL: if (stream -> ux_device_class_audio_stream_transfer_pos -> ux_device_class_audio_frame_length == 0) *//* PATCHED: Invert logic to allow initial thread resumption */if (stream->ux_device_class_audio_stream_transfer_pos->ux_device_class_audio_frame_length>0)
              {
              return(UX_BUFFER_OVERFLOW);
              }

              Additional context

              When using the original == 0 check, a "deadlock" occurs:

              1. The Host sends SET_INTERFACE to enable the Microphone.
              2. ux_device_class_audio_transmission_start() is called.
              3. The check fails (returns UX_BUFFER_OVERFLOW) because the internal transfer_pos hasn't been updated by an active transfer yet.
              4. The Microphone thread remains SUSPENDED.
              5. Because the thread is suspended, no data is ever moved to the FIFO.
              6. The Host (Windows) receives no data for its initial IN tokens, times out, and stops polling, resulting in Error Code 10.

              By changing the condition to > 0, the function returns UX_SUCCESS when the length is 0, successfully executing _ux_device_thread_resume(). This allows the USBX audio thread to wake up, interact with the hardware driver, and satisfy the Host's requests.

              Metadata

              Metadata

              Assignees

              No one assigned

                Labels

                bugSomething isn't working

                Type

                No type

                Projects

                Milestone

                No milestone

                Relationships

                None yet

                Development

                No branches or pull requests

                Issue actions

                , 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); [USBX Device Audio] _ux_device_class_audio_transmission_start logic prevents Microphone stream start on Isochronous IN · Issue #236 · eclipse-threadx/usbx · GitHub
                Skip to content

                [USBX Device Audio] _ux_device_class_audio_transmission_start logic prevents Microphone stream start on Isochronous IN #236

                Description

                @NicoCaldo

                Describe the bug
                A logic error in the _ux_device_class_audio_transmission_start function prevents the Microphone (Isochronous IN) stream from starting when the buffer is correctly primed. The function checks if (stream -> ux_device_class_audio_stream_transfer_pos -> ux_device_class_audio_frame_length == 0) and returns UX_BUFFER_OVERFLOW if true. However, because the microphone thread is suspended and hasn't processed its first frame yet, this condition often triggers even when data is waiting, or conversely, blocks the initial resume of the audio thread.

                Inverting this logic or bypassing it allows the Host (Windows) to begin sending Isochronous IN tokens, which are otherwise never sent.

                Hardware and Software Environment:

                • Target device: STM32U5A9J-DK (using USB OTG HS)
                • Version of Eclipse ThreadX: v6.2.1 or v6.3.0 (USBX Audio 2.0 Class)
                • Toolchain and environment: IAR Embedded Workbench for ARM / STM32CubeIDE
                • Diagnostics tried: - Verified USB Descriptors (Clock Source IDs, Terminal Links, and Endpoint addresses).
                • Monitored USB traffic via Wireshark; confirmed Windows never sends IN tokens for the Mic interface until the library was patched.
                • Traced ux_device_class_audio_write_thread_entry and found it permanently SUSPENDED due to the initialization failure in transmission_start.

                To Reproduce
                Steps to reproduce the behavior:

                1. Initialize a USBX Audio 2.0 device with both Speaker (OUT) and Microphone (IN) interfaces.
                2. Link the Microphone path to the same Clock Source as the Speaker.
                3. In the ux_device_class_audio_stream_change callback, attempt to prime the Mic buffer using ux_device_class_audio_write_frame_get and ux_device_class_audio_write_frame_commit.
                4. Call ux_device_class_audio_transmission_start.
                5. Observe that the function returns UX_BUFFER_OVERFLOW (0x5D) and the microphone thread never executes.

                Expected behavior
                The ux_device_class_audio_transmission_start function should successfully resume the audio write thread when a valid stream is configured, allowing the hardware to prepare for the first Host IN token.

                Impact
                Showstopper. Without the patch/inversion of the logic, it is impossible to implement a USB Audio Microphone or Loopback interface, as the Host fails to recognize the data stream and eventually returns a "Code 10" error in Device Manager.

                Logs and console output

                • Wireshark: Shows SET_INTERFACE (Alt 1) for the Mic interface followed by zero Isochronous IN packets.
                • Debugger:stream->ux_device_class_audio_stream_transfer_pos->ux_device_class_audio_frame_length is observed as 0 at the moment of the failing check.

                Additional context
                The issue seems specifically tied to the initial state of the transfer_pos structure when the stream is transitioned from Alt Setting 0 to Alt Setting 1. Even if the buffer is primed with ux_device_class_audio_write_frame_commit immediately prior to the start call, the pointer/length state within the USBX internal structures does not always satisfy the == 0 check in the way the driver expects.

                Workaround: Patching the USBX Library

                File:ux_device_class_audio_transmission_start.c

                Description: The original logic prevents the transmission thread from resuming if the frame length is 0. However, in many initialization sequences, the length remains 0 until the thread is actually running and the hardware starts its first transfer cycle. By inverting the logic, we allow the thread to resume and the Host to begin polling.

                Modified Code:

                /* Check if there is frame to send (underflow). *//* ORIGINAL: if (stream -> ux_device_class_audio_stream_transfer_pos -> ux_device_class_audio_frame_length == 0) *//* PATCHED: Invert logic to allow initial thread resumption */if (stream->ux_device_class_audio_stream_transfer_pos->ux_device_class_audio_frame_length>0)
                {
                return(UX_BUFFER_OVERFLOW);
                }

                Additional context

                When using the original == 0 check, a "deadlock" occurs:

                1. The Host sends SET_INTERFACE to enable the Microphone.
                2. ux_device_class_audio_transmission_start() is called.
                3. The check fails (returns UX_BUFFER_OVERFLOW) because the internal transfer_pos hasn't been updated by an active transfer yet.
                4. The Microphone thread remains SUSPENDED.
                5. Because the thread is suspended, no data is ever moved to the FIFO.
                6. The Host (Windows) receives no data for its initial IN tokens, times out, and stops polling, resulting in Error Code 10.

                By changing the condition to > 0, the function returns UX_SUCCESS when the length is 0, successfully executing _ux_device_thread_resume(). This allows the USBX audio thread to wake up, interact with the hardware driver, and satisfy the Host's requests.

                Metadata

                Metadata

                Assignees

                No one assigned

                  Labels

                  bugSomething isn't working

                  Type

                  No type

                  Projects

                  Milestone

                  No milestone

                  Relationships

                  None yet

                  Development

                  No branches or pull requests

                  Issue actions