News:

Let's find out together what makes a PIC Tick!

Main Menu

USB Sniffer

Started by JonW, Sep 28, 2024, 06:47 PM

Previous topic - Next topic

JonW

I just received the USB dev boards from China and finally got the hardware up and running, including packet monitoring hardware.  I know some users here have been working with USB and are also actively developing stacks, so I thought I would share what I have learnt from a hardware perspective to get started and save time.  USB is vast, and you can waste weeks of work if you can't "SEE" what is happening.  I spent quite a while looking for hardware to help with development, and it can be extremely expensive. I bought a Logic 8 as a general tool, but this is also fairly pricey, so I looked for a low-cost alternative.

I have already talked about Alex Tardov's analyser, available on Aliexpress, fully assembled and programmed, but never had the chance to test it all out.  You can buy them for as little as $30 without an enclosure.  I opted for this one Click Here

This hardware works like a dream with Wireshark and is unreal for the money. Below is a screenshot of the transfers + the end of the enumeration.  I masked the empty frames because it's tedious to sift through them to find data.
In this example, I am sending a full 64-byte packet using HID (packed with nulls to give a fixed packet size).  You can see the enumeration, with the decoded packet sent from the host and the reply from the device.  Seriously, this is a nice bit of kit for the money and a testament to Alex for releasing this open source; I wish he had manufactured it so he could benefit rather than a Chinese manufacturer reaping his deserved reward!


In addition, I wanted to get a simple HID send-and-receive routine running on a PC to test out the hardware. This can also be pretty complex to code and can easily consume a crap load of time and create an endless loop of disaster as you don't know which end is broken.  So, I am sharing a working and tested Python script that connects to a VID/PID with HID; it packs out the packet to 64 bytes, it also has a thread-driven interrupt receive routine that also strips null bytes (keeping the same 64-byte packet size,which has to be fixed in the code as it's defined in the initial enumeration).  This script helps send and receive N-byte packets for testing purposes.  The sniffer is in line and independent of the host and the device.

Python script
import hid
import time
import threading
import queue

VENDOR_ID = 0x1234  #  vendor ID
PRODUCT_ID = 0x5678  #  product ID
SEND_SIZE = 64      # NUMBER OF BYTES TO SEND

# Global queue for received messages
message_queue = queue.Queue()

def send_data(device, data):
    # Ensure the data is 64 bytes long, pad with null terminators
    padded_data = b'\x00' + data.encode('utf-8').ljust(SEND_SIZE -1, b'\x00')
    device.write(padded_data)
    time.sleep(0.5)  # Wait a bit before trying again

def receive_data(device):
    try:
        # Read 64 bytes from the device
        data = device.read(SEND_SIZE, timeout_ms=100)  # 100ms timeout
        if data:
            # Convert list of integers to bytes
            byte_data = bytes(data)
            # Decode bytes to string and strip null terminators
            message = byte_data.decode('utf-8').split('\x00')[0]
            return message
       
    except Exception as e:
        print(f"Error in receive_data: {e}")
    return None

def receive_thread(device):
    while True:
        try:
            message = receive_data(device)
            if message:
                message_queue.put(message)
                print(f"Interrupt Fired: PC Received message:> {message}")
        except Exception as e:
            print(f"Error in receive_thread: {e}")
            time.sleep(0.1)  # Wait a bit before trying again

def main():
    try:
        # Open the HID device
        device = hid.device()
        device.open(VENDOR_ID, PRODUCT_ID)
        print(f"Connected to device: {device.get_manufacturer_string()} {device.get_product_string()}")

        # Start the receive thread
        thread = threading.Thread(target=receive_thread, args=(device,), daemon=True)
        thread.start()

        while True:
            time.sleep(0.5)  # Wait a bit before trying again
            command = input("Enter a command (send/exit): ").strip().lower()
           
            if command == "send":
                message_to_send = input("Enter message to send:> ")
                print(f"PC Sending message:> {message_to_send}")
                send_data(device, message_to_send)
            elif command == "exit":
                break
            else:
                print("Invalid command. Please enter 'send' or 'exit'.")

            # Process any received messages
            while not message_queue.empty():
                received_message = message_queue.get()
                #print(f"Processed received message: {received_message}")

    except IOError as e:
        print(f"Error: {e}")
    finally:
        if 'device' in locals():
            device.close()

if __name__ == "__main__":
    main()

You will need to install the libraries if you don't have them.  I run Phython via VS code, make sure you have coderunner set to 'run in the terminal' so you can type responses.  Please don't pick faults in the script, it's not perfect, I have only been coding Python for a week or so.

I've attached a screenshot of the PY script running and sending/receiving the packets, the MCU returning the same packet (64 bytes packed), and Wireshark decoding the USB packets. 

Edit: I just added the MCU application's screen dump, shadowing the received data (less null bytes) to the serial port via a CP2102.  If you do a demo board, add a separate known USB to the serial IC so you can sanity-check it all and use it as a debug terminal. Low cost emulators will struggle/not work with full speed USB, especially polled stacks. A HW uart can be a godsend
Edit: Dont ask for the MCU code, its in CCS C, I have a customer requesting this specific compiler, but it will work with Positron too :-), hence why I am posting this on this forum and not CCS!!
Hope this is of use to other users! 

J
 

JonW

#1
I've ordered you a Sniffer, Les  ;D
You should get it in a couple of weeks  ;) 

J


JonW

I'll keep you posted via PM on the delivery.