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