Skip to main content
.NETFramework4.8net8.0net9.0net10.0.NETStandard2.0.NETStandard2.1

This package contains a library that allows you .net app to communicate to a FTDI USB chip. It wraps the D2XX API into a nice OO .net library. The Library can also be used on Linux and MacOS.

Published
Nov 14, 2025
11mo ago
Total Downloads
21.6K
21,574

Install

dotnet add package Essy.FTDIWrapper --version 7.0.1
ProductVersions
.NET
net10.0net8.0net9.0
.NET Standard
netstandard2.0netstandard2.1
Other
.NETFramework4.8

README

Essy.FTDIWrapper

A small, opinionated .NET wrapper around the FTDI D2XX (ftd2xx) native library.
It lets you enumerate FTDI devices, open them by serial number, configure the UART, read/write data, work with events, and access EEPROM/user area – all from managed C# code.

Namespace: Essy.FTDIWrapper


Features

  • Enumerate all connected FTDI devices (with description, serial number, IDs, flags).
  • Open a device by serial number and manage its lifetime via IDisposable.
  • Synchronous read/write of raw bytes with full‑length checks.
  • Query and purge RX/TX buffers.
  • Configure baud rate, data bits, parity, stop bits, and flow control.
  • Wait for incoming data or modem/pin changes via OS events (sync + async helpers).
  • Access user area EEPROM (read/write string or binary, query capacity).
  • Read and modify the device Product ID in the EEPROM while preserving user area.
  • Reset / cycle port / tweak latency and USB buffer sizes (where supported by the OS).
  • Strongly-typed enums for parity, stop bits, data length, flow control, and status pins.
  • Rich exception hierarchy for low-level and enumeration errors.

The native interop is centralized in a single internal FTDIFunctions class that P/Invokes into ftd2xx.


Installation

Once published to NuGet:

dotnet add package Essy.FTDIWrapper

Or via the NuGet Package Manager UI in Visual Studio: search for Essy.FTDIWrapper.


Requirements

  • .NET (classic Framework or modern .NET) with support for P/Invoke.
  • The FTDI D2XX driver installed on the system.
  • The ftd2xx native library (ftd2xx.dll / libftd2xx.so / libftd2xx.dylib) available on the library load path.

Some features (port cycling, driver version, reset pipe retry count) are only supported on Windows and are no-ops or short‑circuit on Unix-like platforms.


Getting started

1. Enumerate devices

using System;
using System.Collections.Generic;
using Essy.FTDIWrapper;

class Program
{
    static void Main()
    {
        List<FTDI_DeviceInfo> devices = FTDI_DeviceInfo.EnumerateDevices();

        if (devices.Count == 0)
        {
            Console.WriteLine("No FTDI devices found.");
            return;
        }

        foreach (var dev in devices)
        {
            Console.WriteLine(dev.ToString());
        }
    }
}

FTDI_DeviceInfo.EnumerateDevices() calls FT_CreateDeviceInfoList and FT_GetDeviceInfoDetail under the hood and converts the C strings to managed strings.


2. Open a device and configure the port

A device is opened by serial number via FT_OpenEx and wrapped in FTDI_Device, which is IDisposable.

using System;
using System.Text;
using Essy.FTDIWrapper;

class Program
{
    static void Main()
    {
        var devices = FTDI_DeviceInfo.EnumerateDevices();

        if (devices.Count == 0)
        {
            Console.WriteLine("No FTDI devices found.");
            return;
        }

        var info = devices[0];

        using var dev = new FTDI_Device(info);

        // Basic UART configuration
        dev.SetBaudrate(115200);
        dev.SetParameters(DataLength.EightBits, Parity.None, StopBits.OneStopBit);
        dev.SetFlowControl(FlowControl.None);

        // Clear buffers (optional)
        dev.ClearReceiveBuffer();
        dev.ClearSendBuffer();

        // Send some data
        var payload = Encoding.ASCII.GetBytes("Hello FTDI!");
        dev.WriteBytes(payload);

        // Read back anything available
        uint available = dev.NumberOfBytesInReceiveBuffer();
        if (available > 0)
        {
            byte[] response = dev.ReadBytes(available);
            Console.WriteLine("Read: " + BitConverter.ToString(response));
        }
    }
}

The WriteBytes and ReadBytes methods validate that the requested number of bytes were actually transmitted/received, and throw a FTDIDeviceNotAllBytesTransmittedException otherwise.


3. Waiting for incoming data

FTDI_Device can use event notifications to wait for RX data. On EnableWaitForDataEvent, it sets up an event with FT_SetEventNotification and waits on it via EventWaitHandle. īˆ€fileciteīˆ‚turn0file0īˆ‚L168-L191īˆ‚turn0file3īˆ‚L60-L73

using System;
using System.Text;
using System.Threading.Tasks;
using Essy.FTDIWrapper;

class Program
{
    static async Task Main()
    {
        var devInfo = FTDI_DeviceInfo.EnumerateDevices()[0];

        using var dev = new FTDI_Device(devInfo);

        dev.SetBaudrate(115200);
        dev.EnableWaitForDataEvent();

        Console.WriteLine("Waiting for data...");

        // Asynchronously wait until the RXCHAR event is signalled
        await dev.WaitForDataAsync();

        uint available = dev.NumberOfBytesInReceiveBuffer();
        if (available > 0)
        {
            byte[] data = dev.ReadBytes(available);
            Console.WriteLine("Received: " + BitConverter.ToString(data));
        }
    }
}

There is also a synchronous WaitForData(int timeoutMs) plus equivalent methods for modem/pin‑change events (EnableWaitForPinChangeEvent, WaitForPinChange, WaitForPinChangeAsync).


4. Working with the user EEPROM area

The library exposes helpers to read/write the user area (UA) EEPROM as either text or raw bytes:

using System;
using Essy.FTDIWrapper;

class Program
{
    static void Main()
    {
        var info = FTDI_DeviceInfo.EnumerateDevices()[0];

        using var dev = new FTDI_Device(info);

        // Get capacity
        uint capacity = dev.GetSizeOfUAEEProm();
        Console.WriteLine($"User EEPROM size: {capacity} bytes");

        // Store a label
        dev.WriteToUAEEProm("My FTDI Device");

        // Read it back as string
        string label = dev.ReadFromUAEEProm();
        Console.WriteLine($"Label: {label}");

        // Or as raw bytes
        byte[] raw = dev.ReadBinaryFromUAEEProm(16);
        Console.WriteLine("Raw: " + BitConverter.ToString(raw));
    }
}

The implementation ensures that the requested size fits within the available user area and throws an FTDIDeviceLowLevelException if not.


5. Error handling

Most failures wrap the FT_STATUS code returned from ftd2xx in a typed exception:

  • FTDIException – base type, exposes the Status property.
  • FTDIEnumerationException – for enumeration problems.
  • FTDIDeviceException and its children:
    • FTDIDeviceLowLevelException
    • FTDIDeviceNotAllBytesTransmittedException

Example:

try
{
    using var dev = new FTDI_Device(info);
    dev.SetBaudrate(9600);
    dev.WriteBytes(new byte[] { 0x01, 0x02, 0x03 });
}
catch (FTDIException ex)
{
    Console.Error.WriteLine($"FTDI error: {ex.Message}");
    Console.Error.WriteLine($"Status: {ex.Status}");
}

Advanced operations

Some additional APIs you can call on FTDI_Device:

  • Reset() / TryReset() – reset the device.
  • ResetPort(), TryResetPort() – reset the USB port (Windows only).
  • CyclePort(), TryCyclePort() – cycle the USB port (Windows only).
  • SetResetPipeRetryCount(uint) – configure retry behaviour when resetting pipes.
  • SetBufferFlushTimer(byte) – configure latency timer.
  • SetBufferSizes(uint tx, uint rx) – change USB transfer sizes.
  • GetStatusPins() – read modem pins (CTS, DSR, RI, DCD).
  • SetRTS(bool) – assert/deassert RTS.
  • GetDriverVersion() – retrieve FTDI driver version (Windows only).
  • GetDeviceProductID() / SetDeviceProductID(ushort) – read or reprogram the Product ID in EEPROM, preserving the user area data.

Design notes

  • The wrapper is intentionally thin: all P/Invoke declarations live in FTDIFunctions, while public, user‑friendly APIs live in FTDI_Device and FTDI_DeviceInfo.
  • The library does not hide the FT_STATUS codes; instead it surfaces them via exceptions so advanced users can still reason about exact driver failures.
  • Device opening is based on serial numbers for deterministic device selection; if you need a different strategy you can select a device from the enumeration list by description or ID.

License

This library is licensed under the MIT License See the source files for the full license text.

Changes from Previous Version

No structural changes between v7.0.0 and v7.0.1.

Adoption Assessment

Assess this package against its supported frameworks, license, maintenance signals and dependency graph before making it a project standard.

Compatibility metadata lists 6 target frameworks; confirm the exact target used by your application.

Related Guides & Workflows

Learn how to evaluate, integrate, or audit this package in your .NET project.