.. include:: ../defs.rst

:mod:`serialext` - UART API
---------------------------

There is no dedicated module for the UART API, as PyFtdi_ acts as a backend of
the well-known pyserial_ module.

The pyserial_ backend module is implemented as the `serialext.protocol_ftdi`
module. It is not documented here as no direct call to this module is required,
as the UART client should use the regular pyserial_ API.

Usage
~~~~~

To enable PyFtdi_ as a pyserial_ backend, use the following import:

.. code-block:: python

    import pyftdi.serialext

Then use

.. code-block:: python

    pyftdi.serialext.serial_for_url(url, **options)

to open a pyserial_ serial port instance.


Quickstart
~~~~~~~~~~

.. code-block:: python

    # Enable pyserial extensions
    import pyftdi.serialext

    # Open a serial port on the second FTDI device interface (IF/2) @ 3Mbaud
    port = pyftdi.serialext.serial_for_url('ftdi://ftdi:2232h/2', baudrate=3000000)

    # Send bytes
    port.write(b'Hello World')

    # Receive bytes
    data = port.read(1024)

.. _uart_gpio:

GPIO access
~~~~~~~~~~~

UART mode, the primary function of FTDI \*232\* devices, is somewhat limited
when it comes to GPIO management, as opposed to alternative mode such as |I2C|,
SPI and JTAG. It is not possible to assign the unused pins of an UART mode to
arbitrary GPIO functions.

All the 8 lower pins of an UART port are dedicated to the UART function,
although most of them are seldomely used, as dedicated to manage a modem or a
legacy DCE_ device. Upper pins (b\ :sub:`7`\ ..b\ :sub:`15`\ ), on devices that
have ones, cannot be driven while UART port is enabled.

It is nevertheless possible to have limited access to the lower pins as GPIO,
with many limitations:

- the GPIO direction of each pin is hardcoded and cannot be changed
- GPIO pins cannot be addressed atomically: it is possible to read the state
  of an input GPIO, or to change the state of an output GPIO, one after
  another. This means than obtaining the state of several input GPIOs or
  changing the state of several output GPIO at once is not possible.
- some pins cannot be used as GPIO is hardware flow control is enabled.
  Keep in mind However that HW flow control with FTDI is not reliable, see the
  :ref:`hardware_flow_control` section.

Accessing those GPIO pins is done through the UART extended pins, using their
UART assigned name, as PySerial port attributes. See the table below:

+---------------+------+-----------+-------------------------------+
| Bit           | UART | Direction | API                           |
+===============+======+===========+===============================+
| b\ :sub:`0`\  | TX   | Out       | ``port.write(buffer)``        |
+---------------+------+-----------+-------------------------------+
| b\ :sub:`1`\  | RX   | In        | ``buffer = port.read(count)`` |
+---------------+------+-----------+-------------------------------+
| b\ :sub:`2`\  | RTS  | Out       | ``port.rts = state``          |
+---------------+------+-----------+-------------------------------+
| b\ :sub:`3`\  | CTS  | In        | ``state = port.cts``          |
+---------------+------+-----------+-------------------------------+
| b\ :sub:`4`\  | DTR  | Out       | ``port.dtr = state``          |
+---------------+------+-----------+-------------------------------+
| b\ :sub:`5`\  | DSR  | In        | ``state = port.dsr``          |
+---------------+------+-----------+-------------------------------+
| b\ :sub:`6`\  | DCD  | In        | ``state = port.dcd``          |
+---------------+------+-----------+-------------------------------+
| b\ :sub:`7`\  | RI   | In        | ``state = port.ri``           |
+---------------+------+-----------+-------------------------------+

CBUS support
````````````

Some FTDI devices (FT232R, FT232H, FT230X, FT231X) support additional CBUS
pins, which can be used as regular GPIOs pins. See :ref:`CBUS GPIO<cbus_gpio>`
for details.


.. _pyterm:

Mini serial terminal
~~~~~~~~~~~~~~~~~~~~

``pyterm.py`` is a simple serial terminal that can be used to test the serial
port feature. See the :ref:`tools` chapter to locate this tool.

::

  Usage: pyterm.py [-h] [-f] [-b BAUDRATE] [-w] [-e] [-r] [-l] [-s] [-P VIDPID]
                   [-V VIRTUAL] [-v] [-d]
                   [device]

  Simple Python serial terminal

  positional arguments:
    device                serial port device name (default: ftdi:///1)

  optional arguments:
    -h, --help            show this help message and exit
    -f, --fullmode        use full terminal mode, exit with [Ctrl]+B
    -b BAUDRATE, --baudrate BAUDRATE
                          serial port baudrate (default: 115200)
    -w, --hwflow          hardware flow control
    -e, --localecho       local echo mode (print all typed chars)
    -r, --crlf            prefix LF with CR char, use twice to replace all LF
                          with CR chars
    -l, --loopback        loopback mode (send back all received chars)
    -s, --silent          silent mode
    -P VIDPID, --vidpid VIDPID
                          specify a custom VID:PID device ID, may be repeated
    -V VIRTUAL, --virtual VIRTUAL
                          use a virtual device, specified as YaML
    -v, --verbose         increase verbosity
    -d, --debug           enable debug mode

If the PyFtdi module is not yet installed and ``pyterm.py`` is run from the
archive directory, ``PYTHONPATH`` should be defined to the current directory::

    PYTHONPATH=$PWD pyftdi/bin/pyterm.py ftdi:///?

The above command lists all the available FTDI device ports.

To start up a serial terminal session, specify the FTDI port to use, for
example:

.. code-block:: shell

    # detect all FTDI connected devices
    PYTHONPATH=. python3 pyftdi/bin/ftdi_urls.py
    # use the first interface of the first FT2232H as a serial port
    PYTHONPATH=$PWD pyftdi/bin/pyterm.py ftdi://ftdi:2232/1


.. _uart-limitations:

Limitations
~~~~~~~~~~~

Although the FTDI H series are in theory capable of 12 MBps baudrate, baudrates
above 6 Mbps are barely usable.

See the following table for details.

+------------+-------------+------------+-------------+------------+--------+
|  Requ. bps |HW capability| 9-bit time |  Real bps   | Duty cycle | Stable |
+============+=============+============+=============+============+========+
| 115.2 Kbps |  115.2 Kbps |   78.08 µs | 115.26 Kbps |     49.9%  |  Yes   |
+------------+-------------+------------+-------------+------------+--------+
| 460.8 Kbps | 461.54 Kbps |   19.49 µs | 461.77 Kbps |     49.9%  |  Yes   |
+------------+-------------+------------+-------------+------------+--------+
|     1 Mbps |      1 Mbps |   8.98 µs  |  1.002 Mbps |     49.5%  |  Yes   |
+------------+-------------+------------+-------------+------------+--------+
|     4 Mbps |      4 Mbps |   2.24 µs  |  4.018 Mbps |       48%  |  Yes   |
+------------+-------------+------------+-------------+------------+--------+
|     5 Mbps |  5.052 Mbps |   1.78 µs  |  5.056 Mbps |       50%  |  Yes   |
+------------+-------------+------------+-------------+------------+--------+
|     6 Mbps |      6 Mbps |   1.49 µs  |  6.040 Mbps |     48.5%  |  Yes   |
+------------+-------------+------------+-------------+------------+--------+
|     7 Mbps |  6.857 Mbps |   1.11 µs  |  8.108 Mbps |       44%  |   No   |
+------------+-------------+------------+-------------+------------+--------+
|     8 Mbps |      8 Mbps |   1.11 µs  |  8.108 Mbps |   44%-48%  |   No   |
+------------+-------------+------------+-------------+------------+--------+
|   8.8 Mbps |  8.727 Mbps |   1.13 µs  |  7.964 Mbps |       44%  |   No   |
+------------+-------------+------------+-------------+------------+--------+
|   9.6 Mbps |    9.6 Mbps |   1.12 µs  |  8.036 Mbps |       48%  |   No   |
+------------+-------------+------------+-------------+------------+--------+
|  10.5 Mbps | 10.667 Mbps |   1.11 µs  |  8.108 Mbps |       44%  |   No   |
+------------+-------------+------------+-------------+------------+--------+
|    12 Mbps |     12 Mbps |   0.75 µs  |     12 Mbps |       43%  |  Yes   |
+------------+-------------+------------+-------------+------------+--------+

 * 9-bit time is the measured time @ FTDI output pins for a 8-bit character
   (start bit + 8 bit data)
 * Duty cycle is the ratio between a low-bit duration and a high-bit duration,
   a good UART should exhibit the same duration for low bits and high bits,
   *i.e.* a duty cycle close to 50%.
 * Stability reports whether subsequent runs, with the very same HW settings,
   produce the same timings.

Achieving a reliable connection over 6 Mbps has proven difficult, if not
impossible: Any baudrate greater than 6 Mbps (except the upper 12 Mbps limit)
results into an actual baudrate of about 8 Mbps, and suffer from clock
fluterring [7.95 .. 8.1Mbps].

.. _hardware_flow_control:

Hardware flow control
`````````````````````

Moreover, as the hardware flow control of the FTDI device is not a true HW
flow control. Quoting FTDI application note:

   *If CTS# is logic 1 it is indicating the external device cannot accept more
   data. the FTxxx will stop transmitting within 0~3 characters, depending on
   what is in the buffer.*
   **This potential 3 character overrun does occasionally present problems.**
   *Customers shoud be made aware the FTxxx is a USB device and not a "normal"
   RS232 device as seen on a PC. As such the device operates on a packet
   basis as opposed to a byte basis.*

