[chbot] Help with Python/HID
Synco Reynders
synco.reynders at gmail.com
Wed Dec 25 08:47:01 GMT 2024
Hey Mark, are you still stuck on the issue. The old "have you tried
googling it?" is now "have you tried AI?"....
Here is what Claude tells me:
Let me help you debug this UART over HID communication issue with the
FT260. I notice a few potential issues and have some suggestions for
improvement.
First, let's analyze the issue:
1. The main problem appears to be with the `handle.write()` call failing
(returning -1)
2. You're correctly using feature reports for configuration (0xA1 commands)
3. The data transmission format looks correct according to the protocol
(0xF0 header)
Here are some potential fixes:
1. First, for HID writes, you typically need to prepend a Report ID byte of
0x00. Try modifying your write call:
```python
bytes_written = handle.write([0x00, 0xF0, 0x01, 0x55])
```
2. The FT260 might need some time to initialize after configuration. Add a
small delay:
```python
import time
# After configuration
time.sleep(0.1) # 100ms delay
```
3. You might want to add error checking and verification. Here's an
improved version of your code:
```python
import hid
import time
FT260_VID = 0x0403
FT260_PID = 0x6030
def check_ft260_status(handle, command):
bytes_read = handle.get_feature_report(0xA1, 64)
status = bytes_read[1] if len(bytes_read) > 1 else 0
return status == 0
try:
# Find and open device
handle = hid.device()
handle.open(FT260_VID, FT260_PID)
# Reset UART
bytes_written = handle.send_feature_report([0xA1, 0x40])
if not check_ft260_status(handle, 0x40):
raise Exception("UART reset failed")
# Wait for reset to complete
time.sleep(0.1)
# Configure UART
config = [0xA1, 0x41, 0x04, 0x80, 0x25, 0x00, 0x00, 0x08, 0x00, 0x00,
0x00]
bytes_written = handle.send_feature_report(config)
if not check_ft260_status(handle, 0x41):
raise Exception("UART configuration failed")
# Set non-blocking mode
handle.set_nonblocking(True)
# Send data with report ID
bytes_written = handle.write([0x00, 0xF0, 0x01, 0x55])
if bytes_written <= 0:
raise Exception(f"Data write failed: {bytes_written}")
print(f"Successfully wrote {bytes_written} bytes")
except Exception as e:
print(f"Error: {str(e)}")
finally:
handle.close()
print("FT260 device closed.")
```
4. Also verify your UART configuration parameters:
- 0x04: UART interface
- 0x80, 0x25: Baud rate (9600)
- 0x00: Data bits (8)
- 0x00: Parity (None)
- 0x08: Stop bits (1)
- 0x00, 0x00: Flow control (None)
If these changes don't resolve the issue, you might want to:
1. Check if the device is in the correct mode after reset using:
```python
mode_report = handle.get_feature_report(0xA1, 64)
print(f"Mode status: {[hex(x) for x in mode_report]}")
```
2. Verify the USB permissions if you're on Linux (you might need to run
with sudo or add udev rules)
3. Try different data lengths to see if there's a minimum payload size
requirement
Let me know if you need any clarification or if you'd like to try other
troubleshooting approaches.
On Tue, 24 Dec 2024 at 19:06, Mark Atherton <markaren1 at xtra.co.nz> wrote:
> Hi all,
>
> Help requested from Python newbie
>
> I am working on a simple code fragment to drive a UART over HID using
> the FT260 in Python, but am having issues with writing data.
>
> Code snip below has had it's layout messed with, but is normally
> indented OK.
>
> send_feature_report and get_feature_report appear to configure the FT260
> using Report IDs which are off type 'Feature'
>
> I don't appear to be able to send data using Report ID of type 'Output'
> with handle.write, it returns returns -1 which is a failure.
>
> The payload is configured
> 0xF0 (send 1..4 bytes)
> 0x01 (payload length 1 byte)
> 0x55 (payload data)
>
> See AN_394_User_Guide_for_FT260.pdf
>
> help(hid) is also included below.
>
> Any help appreciated.
>
> -Mark
>
>
> --------
>
> import hid
> #import struct
>
> FT260_VID = 0x0403 # Default Vendor ID for FTDI
> FT260_PID = 0x6030 # Default Product ID for FT260
>
> for device in hid.enumerate():
> if device['vendor_id'] == FT260_VID and device['product_id'] ==
> FT260_PID:
> print(f"FT260 device found: {device['product_string']}")
>
> print("Opening FT260 device...")
> handle = hid.device()
> handle.open(FT260_VID, FT260_PID)
>
> bytes_written = handle.send_feature_report([0xA1,0x40])
> # Reset UART
>
> bytes_read = handle.get_feature_report(report_num = 0xA1, max_length = 64)
> print(["%02x" % (each) for each in bytes_read]);
>
> handle.set_nonblocking(True);
>
> bytes_written =
>
> handle.send_feature_report([0xA1,0x41,0x04,0x80,0x25,0x00,0x00,0x08,0x00,0x00,0x00])
> print("wrote config ", bytes_written);
>
> bytes_written = handle.write([0xF0, 0x01, 0x55])
> print("wrote data ", bytes_written);
>
> handle.close()
> print("FT260 device closed.")
>
> ----
>
> >>> help(hid)
> Help on module hid:
>
> NAME
> hid
>
> CLASSES
> builtins.object
> device
>
> class device(builtins.object)
> | Device class.
> |
> | A device instance can be used to read from and write to a HID
> device.
> |
> | Methods defined here:
> |
> | __reduce__ = __reduce_cython__(...)
> |
> | __setstate__ = __setstate_cython__(...)
> |
> | close(self)
> | Close connection.
> |
> | This should always be called after opening a connection.
> |
> | error(self)
> | Get error from device, or global error if no device is opened.
> |
> | :return:
> | :rtype: str
> | :raises IOError:
> |
> | get_feature_report(self, report_num, max_length)
> | Receive feature report.
> |
> | :param report_num:
> | :type report_num: int
> | :param max_length:
> | :type max_length: int
> | :return: Incoming feature report
> | :rtype: List[int]
> | :raises ValueError: If connection is not opened.
> | :raises IOError:
> |
> | get_indexed_string(self, index)
> | Return indexed string.
> |
> | :return:
> | :rtype: str
> | :raises ValueError: If connection is not opened.
> | :raises IOError:
> |
> | get_input_report(self, report_num, max_length)
> | Get input report
> |
> | :param report_num:
> | :type report_num: int
> | :param max_length:
> | :type max_length: int
> | :return:
> | :rtype: List[int]
> | :raises ValueError: If connection is not opened.
> | :raises IOError:
> |
> | get_manufacturer_string(self)
> | Return manufacturer string (e.g. vendor name).
> |
> | :return:
> | :rtype: str
> | :raises ValueError: If connection is not opened.
> | :raises IOError:
> |
> | get_product_string(self)
> | Return product string (e.g. device description).
> |
> | :return:
> | :rtype: str
> | :raises ValueError: If connection is not opened.
> | :raises IOError:
> |
> | get_report_descriptor(self, max_length=4096)
> | Return the report descriptor up to max_length bytes.
> | If max_length is bigger than the actual descriptor, the
> full descriptor will be returned.
> |
> | :param max_length: Maximum number of bytes to read, must be
> positive
> | :type max_length: int
> |
> | :return:
> | :rtype: List[int]
> | :raises ValueError: If connection is not opened.
> | :raises IOError: If read error
> |
> | get_serial_number_string(self)
> | Return serial number.
> |
> | :return:
> | :rtype: str
> | :raises ValueError: If connection is not opened.
> | :raises IOError:
> |
> | open(self, vendor_id=0, product_id=0, serial_number=None)
> | Open the connection.
> |
> | :param vendor_id: Vendor id to connect to, default = 0
> | :type vendor_id: int, optional
> | :param product_id: Product id to connect to, default = 0
> | :type product_id: int, optional
> | :param serial_number:
> | :type serial_number: unicode, optional
> | :raises IOError:
> |
> | open_path(self, path)
> | Open connection by path.
> |
> | :param path: Path to device
> | :type path: bytes
> | :raises IOError:
> |
> | read(self, max_length, timeout_ms=0)
> | Return a list of integers (0-255) from the device up to
> max_length bytes.
> |
> | :param max_length: Maximum number of bytes to read
> | :type max_length: int
> | :param timeout_ms: Number of milliseconds until timeout
> (default: no timeout)
> | :type timeout_ms: int, optional
> | :return: Read bytes
> | :rtype: List[int]
> |
> | send_feature_report(self, buff)
> | Accept a list of integers (0-255) and send them to the device.
> |
> | :param buff: Data to send (must be convertible into bytes)
> | :type buff: any
> | :return: Send result
> | :rtype: int
> |
> | set_nonblocking(self, v)
> | Set the nonblocking flag.
> |
> | :param v: Flag value (1 or 0, True or False)
> | :type v: int, bool
> | :return: Flag result
> | :rtype: int
> |
> | write(self, buff)
> | Accept a list of integers (0-255) and send them to the device.
> |
> | :param buff: Data to write (must be convertible to `bytes`)
> | :type buff: Any
> | :return: Write result
> | :rtype: int
> |
> |
> ----------------------------------------------------------------------
> | Static methods defined here:
> |
> | __new__(*args, **kwargs) from builtins.type
> | Create and return a new object. See help(type) for
> accurate signature.
>
> FUNCTIONS
> __reduce_cython__(self)
>
> __setstate_cython__(self, __pyx_state)
>
> enumerate(vendor_id=0, product_id=0)
> Return a list of discovered HID devices.
>
> The fields of dict are:
>
> - 'path'
> - 'vendor_id'
> - 'product_id'
> - 'serial_number'
> - 'release_number'
> - 'manufacturer_string'
> - 'product_string'
> - 'usage_page'
> - 'usage'
> - 'interface_number'
>
> :param vendor_id: Vendor id to look for, default = 0
> :type vendor_id: int, optional
> :param product_id: Product id to look for, default = 0
> :type product_id: int, optional
> :return: List of device dictionaries
> :rtype: List[Dict]
>
> version_str()
> Return a runtime version string of the hidapi C library.
>
> :return: version string of library
> :rtype: str
>
> DATA
> __test__ = {}
>
> VERSION
> 0.14.0.post4
>
> FILE
>
>
> c:\users\user\appdata\local\programs\python\python37\lib\site-packages\hid.cp37-win_amd64.pyd
>
> _______________________________________________
> Chchrobotics mailing list Chchrobotics at lists.ourshack.com
> https://lists.ourshack.com/mailman/listinfo/chchrobotics
> Mail Archives: http://lists.ourshack.com/pipermail/chchrobotics/
> Meetings usually 3rd Monday each month. See http://kiwibots.org for
> venue, directions and dates.
> When replying, please edit your Subject line to reflect new subjects.
--
Synco Reynders
m: +64 21 1825332
e: synco.reynders at gmail.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ourshack.com/pipermail/chchrobotics/attachments/20241225/5c8b5a28/attachment-0001.html>
More information about the Chchrobotics
mailing list