Skip to content

Support for CH9350L module #13

Closed

Description

@sjmf

EDIT: This issue originally concerned the CH9328 USB HID keyboard module, but work pivoted to compatibility with the CH9350L. The issue has been re-named. I'm leaving the original first post here in-place for future reference. Readers may raise a future issue if CH9328 compatibility is still desirable.


The "sister" module to the CH9329, the CH9328, appears to be better supported and more widely available, including from reliable distributors such as Adafruit: https://www.adafruit.com/product/5973

I have purchased a CH9328 module and will test with this code to see if it works, as is.

If so, we can update the documentation to include it.

If not, I will investigate supporting it (e.g. based on an options menu drop-down in the GUI client).

Activity

  1. vladyst commented on Oct 14, 2025

    @vladyst

    CH9328 does not support mouse emulation.
    A better candidate is CH9350L.
    https://www.electrodragon.com/product/usb-hid-to-uart-rs-485-extension-board/

  2. changed the title [-]Test CH9328 module[/-] [+]Test CH9328/CH9350L module[/+] on Oct 14, 2025
  3. changed the title [-]Test CH9328/CH9350L module[/-] [+]Test CH9328 / CH9350L module[/+] on Oct 14, 2025
  4. changed the title [-]Test CH9328 / CH9350L module[/-] [+]Test CH9328 / CH9350L modules[/+] on Oct 14, 2025
  5. added this to the 1.6.0 milestone on Feb 3, 2026
  6. sjmf commented on Feb 3, 2026

    @sjmf
    OwnerAuthor

    I looked into this today to purchase the necessary test hardware.

    From my understanding of CH9350L, it appears to be designed to capture input from USB-HID peripherals, and convert their signals to RS485 Serial to transmit?

    Here's the linked device on electrodragon, and another module I found on AliExpress:

    ElectroDragon module

    AliExpress module

    The device contains a USB-A female port to plug peripherals into. To my understanding, this is the opposite of the functionality provided by the KVM Serial application, which transmits input over serial which is output as USB-HID signals by CH9329 & friends.

    Module Receive Output
    CH9329 RS232 Serial USB-HID protocol messages
    CH9350L USB-HID protocol messages RS485 Serial

    Please correct me if I am wrong, as this would mean that the suggested candidate isn't suitable to this application?

  7. jpmorrison commented on Mar 8, 2026

    @jpmorrison

    CH9350 mode depends on dip switches - you can plug it into a PC or connect keyboard/mouse to it.

    Image

    The 9350 is a TTL UART. It has a transmit signal so you can use it with an RS485 driver/IC in a KVM application.

    https://github.com/aotebai/esp32-kvm-usb-mouse-keyboard-switcher/blob/main/PDF_drawing/Pin_connection_diagram_e.pdf

  8. sjmf commented on Mar 8, 2026

    @sjmf
    OwnerAuthor

    Thanks for the comment @jpmorrison and for linking to the diagram. Sounds like CH9350 does actually support the required functionality after all.

    So for use with this application, I'd need the following test hardware:

    • a USB-A to USB-A cable
      • between Computer or other USB hosts and CH9350L Chip SEL#0
    • wired to a USB RS485 TTL Serial Converter Adapter e.g. FT232RL / CP2102 / CH343G
      • connected to sending host

    This looks achievable. It requires some code refactoring for an alternative protocol implementation to be supported, and appropriate command line switches and GUI options to be added.

    The work breakdown is more or less (updated 05-05-2026):

    • Refactor CH9329 DataComm class such that DataComm becomes an abstract base class (ABC)
    • Create two implementations of this class: CH9329Comm and CH9350Comm
    • Pass through the selected implementation to hardware initialisation: probably a default in the __init__() function of BaseOp
    • Figure out how the application determines which import to use. Probably:
      • CH9329Comm: default, preserve existing functionality
      • CH9350Comm: add command line switch to kvm-control, e.g. --ch9350 (and probably add redundant switch --ch9329 for imperative declaration)
      • GUI: Add item to Options menu for Protocol to switch device, persist in .kvm-settings.ini file.
    • Update documentation to reflect code changes (README.md)
    • Update driver installation instructions to include common RS485 modules

    A final note here is that the protocol documentation for CH9350L is not especially comprehensive. It provides some sample packets but not the full protocol spec (mouse data packets specifically are absent). However, as the hardware can send packets it would be very much possible to sniff the packet format with a RS485 TTL adapter, and use the captured information create a more comprehensive protocol guide.

    This won't be especially quick for me to implement in the short-term, but I'll get the hardware ordered and keep it on my projects radar.

  9. self-assigned this
    on Mar 8, 2026
  10. changed the title [-]Test CH9328 / CH9350L modules[/-] [+]Implement support for CH9328 / CH9350L modules[/+] on Mar 9, 2026
  11. changed the title [-]Implement support for CH9328 / CH9350L modules[/-] [+]Support for CH9328 / CH9350L modules[/+] on Mar 9, 2026
  12. sjmf commented on Mar 9, 2026

    @sjmf
    OwnerAuthor

    Parts ordered for testing and implementation.

    Testing Hardware Order Screenshot

  13. sjmf commented on Mar 18, 2026

    @sjmf
    OwnerAuthor

    Hardware received. I think my first step will be to add a CH9350 protocol spec document to this repo based on real device data.

    Test setup:

    Mouse &     USB HID    CH9350 Module    RS485 BUS   CH9350 Module    USB HID     Test
    Keyboard    ======>      (TX mode)       ======>      (RX mode)      ======>   Computer
                                                |
                                                V
                                              RS485
                                             Receiver
                                             (inline)
                                                |
                                                V
                                          Serial Capture
                                          on Receiving PC
    

    Plan is to capture data (should be unidirectional) from original hardware in TX mode, while testing the device I've bought functions correctly in RX mode.

    I don't currently have much time to work on this, so if this is a feature you would strongly like to see implemented in this package, do +1 this message and I'll see if I can prioritise it.

  14. vladyst commented on Mar 19, 2026

    @vladyst

    I tried to use the CH9350 (lower computer mode) for 2 different projects. First attempt was to bridge a CH9350 to CH9329. Keyboard strait forward but mouse HID reports unresolved. Second attempt was to use the CH9350 to remote a keyboard and mouse to a computer via serial interface. The idea was to parse HID data and send keyboard/mouse events to the OS. Keyboard works fine but mouse, each device seems to have a different report structure ( data packet ).
    CH9350 appears to be a CH559 with custom firmware. ( Assumption not fact )
    This project needs upper computer mode. Serious reverse engineering of the communications between the 2 CH9350 devices is needed.
    The CH9350 RS485 boards I have in my hands needed the RS485 jumpers in cross. The receive signal from CH340 can be wired to Rx/Tx for monitoring.
    For testing is easier to bridge the 2 boards via USB and have a man in the middle computer to log communications.

  15. 34 remaining items

  16. changed the title [-]Support for CH9350L/CH9328 modules[/-] [+]Support for CH9350L module[/+] on May 10, 2026
  17. sjmf commented on May 10, 2026

    @sjmf
    OwnerAuthor

    Complete: CH9350L support on feature/13-ch9350L-support

    End-to-end implementation merged-and-ready on the branch. Working summary plus the empirical findings worth recording.

    All four CH9350L working states are implemented and verified against real hardware:

    State Mode Status
    0/1 Descriptor handshake (paired) ✅ Verified — keyboard, relative mouse, attach/reattach, LED echo, all 309 unit tests pass
    2 BIOS keyboard + relative mouse ✅ Verified
    3 BIOS keyboard + absolute mouse ✅ Verified
    4 BIOS keyboard + HID Digitizers ✅ Verified against a single-monitor target. Multi-monitor (the canonical state-4 use case) untested — needs a Windows multi-monitor host to exercise the digitizer routing. Functionally identical to state 3 at the UART layer; the difference is in what descriptor the UC presents to the target

    Wire-up is via --ch9350 / --ch9350-state on the CLI, and protocol + state selectors in the GUI (settings persisted across runs).

    Empirical findings (worth surfacing)

    A few non-obvious things came out of testing that aren't in the datasheet:

    • State 0/1 cannot send absolute mouse reports, despite datasheet §4.3 documenting LEN=0x0A as a valid LC→UC frame. The UC accepts the descriptor handshake, the target enumerates, but the chip's frame-forwarder silently drops 0x0A reports. Verified with synthetic frames and with a real CH9329 chip plugged into the LC's USB-host port as the report source — even the genuine article's RID 5 absolute frames don't reach the target's input pipeline. State 0/1/2 emulate absolute via translate-to-relative-deltas (Wacom-style); for true absolute, use state 3 or 4.
    • State 3/4's 0x04 X/Y range is 10-bit (0..1023), not 16-bit. The chip's USB-side descriptor declares an 11-bit signed field; the wire field is 16-bit, but the upper 6 bits are unused / Const padding. Sending values >1023 produces a periodic clip-sweep-clip pattern with period 2048 — diagnostic signature recorded in CH9350L_PROTO.md §Divergences. Notably different from the CH9329's 12-bit (0..4095) range despite the matching wire format — the chips declare different USB-side ranges even though the UART framing is byte-identical.
    • State 0/1/2 inherit target-side pointer acceleration as a property of relative-mouse-over-anything. Slow drags track faithfully, fast drags overshoot. Mitigations (disabling Enhance pointer precision / equivalent on macOS / Linux) and the alternative (state 3) are documented in the user guide.

    Documentation

    • docs/CH9350L_PROTO.md — protocol spec covering all four states, attach sequence, state machine, frame formats, and a §Divergences section logging where the V2.3 datasheet contradicts what real hardware emits
    • docs/CH9350L_GUIDE.md — user guide: hardware sourcing, dipswitch configuration, physical setup, state-selection guidance, GUI/CLI usage, troubleshooting
    • docs/CH9329_GUIDE.md and docs/CH9329_PROTO.md — for parity, since the chip family now has two members
    • Updated README.md and SUPPORTED_DEVICES.md

    Tests

    309 passing across all groups (tests/utils/, tests/backend/, tests/kvm/, tests/test_control.py). CH9350Comm is covered including the descriptor-announce protocol, state transitions, LED echo, and the wire-format edge cases (signed-byte clamps, multi-frame fan-out, drag preserves held-button state, etc.).

    Reference materials

    • ch9350_poc.py gist — bidirectional sniffer + LC emulator, kept up to date alongside the in-tree implementation. This is a public-domain
      reference implementation which I'm releasing for anyone who wishes to implement the LC protocol.
    • Captures from this investigation referenced inline in CH9350L_PROTO.md

    Note on CH9328

    This issue originally also covered the CH9328, the Adafruit-stocked sister chip. Investigation pivoted entirely to CH9350L during the work. CH9328 has not been tested with this codebase. Anyone interested in CH9328 support should open a fresh issue rather than reopening this one — it's likely a small change (CH9328 may "just work" with CH9329Comm) but needs hardware to verify.

    Raising a PR next! This one will land on PyPI as v1.5.6. I'd originally targeted 1.6, but this deserves an intermediate release for immediate use rather than waiting on closing other issues.

  18. linked a pull request that will close this issueImplement CH9350L UART protocol into kvm-serial #40on May 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions