internal void Read(int deviceAddress, Span <byte> buffer) { if (deviceAddress < 0 || deviceAddress > ushort.MaxValue) { throw new ArgumentOutOfRangeException(nameof(deviceAddress)); } if (buffer.Length > ushort.MaxValue) { throw new ArgumentOutOfRangeException(nameof(buffer), $"Buffer is too large. Maximum length is {ushort.MaxValue}."); } ushort bytesRead; var ftStatus = FtFunction.FT4222_I2CMaster_Read(_ftHandle, (ushort)deviceAddress, in MemoryMarshal.GetReference(buffer), (ushort)buffer.Length, out bytesRead); if (ftStatus != FtStatus.Ok) { throw new IOException($"{nameof(Read)} failed to read, error: {ftStatus}"); } if (bytesRead != buffer.Length) { throw new IOException($"Number of bytes read ({bytesRead}) doesn't match length of the buffer ({buffer.Length})."); } }
/// <summary> /// Create an SPI FT4222 class /// </summary> /// <param name="settings">SPI Connection Settings</param> public Ft4222Spi(SpiConnectionSettings settings) { _settings = settings; // Check device var devInfos = FtCommon.GetDevices(); if (devInfos.Count == 0) { throw new IOException("No FTDI device available"); } // Select the one from bus Id // FT4222 propose depending on the mode multiple interfaces. Only the A is available for SPI or where there is none as it's the only interface var devInfo = devInfos.Where(m => m.Description == "FT4222 A" || m.Description == "FT4222").ToArray(); if ((devInfo.Length == 0) || (devInfo.Length < _settings.BusId)) { throw new IOException($"Can't find a device to open SPI on index {_settings.BusId}"); } DeviceInformation = devInfo[_settings.BusId]; // Open device var ftStatus = FtFunction.FT_OpenEx(DeviceInformation.LocId, FtOpenType.OpenByLocation, out _ftHandle); if (ftStatus != FtStatus.Ok) { throw new IOException($"Failed to open device {DeviceInformation.Description} with error: {ftStatus}"); } // Set the clock but we need some math var(ft4222Clock, tfSpiDiv) = CalculateBestClockRate(); ftStatus = FtFunction.FT4222_SetClock(_ftHandle, ft4222Clock); if (ftStatus != FtStatus.Ok) { throw new IOException($"Failed set clock rate {ft4222Clock} on device: {DeviceInformation.Description}with error: {ftStatus}"); } SpiClockPolarity pol = SpiClockPolarity.ClockIdleLow; if ((_settings.Mode == SpiMode.Mode2) || (_settings.Mode == SpiMode.Mode3)) { pol = SpiClockPolarity.ClockIdelHigh; } SpiClockPhase pha = SpiClockPhase.ClockLeading; if ((_settings.Mode == SpiMode.Mode1) || (_settings.Mode == SpiMode.Mode3)) { pha = SpiClockPhase.ClockTailing; } // Configure the SPI ftStatus = FtFunction.FT4222_SPIMaster_Init(_ftHandle, SpiOperatingMode.Single, tfSpiDiv, pol, pha, (byte)_settings.ChipSelectLine); if (ftStatus != FtStatus.Ok) { throw new IOException($"Failed setup SPI on device: {DeviceInformation.Description} with error: {ftStatus}"); } }
private void InitializeGpio(Ft4222Device device) { DeviceInformation = device; // Open device var ftStatus = FtFunction.FT_OpenEx(DeviceInformation.LocId, FtOpenType.OpenByLocation, out _ftHandle); if (ftStatus != FtStatus.Ok) { throw new IOException($"Failed to open device {DeviceInformation.Description}, status: {ftStatus}"); } ftStatus = FtFunction.FT4222_SetSuspendOut(_ftHandle, false); if (ftStatus != FtStatus.Ok) { throw new IOException($"Can't initialize GPIO for device {DeviceInformation.Description} changing Suspend out mode, status: {ftStatus}"); } ftStatus = FtFunction.FT4222_SetWakeUpInterrupt(_ftHandle, false); if (ftStatus != FtStatus.Ok) { throw new IOException($"Can't initialize GPIO for device {DeviceInformation.Description} removing wake up interrupt, status: {ftStatus}"); } for (int i = 0; i < PinCountConst; i++) { _gpioDirections[i] = GpioPinMode.Output; } ftStatus = FtFunction.FT4222_GPIO_Init(_ftHandle, _gpioDirections); if (ftStatus != FtStatus.Ok) { throw new IOException($"Can't initialize GPIO for device {DeviceInformation.Description}, status: {ftStatus}"); } }
protected override bool ReleaseHandle() { var ftStatus = FtFunction.FT4222_UnInitialize(this); ftStatus = FtFunction.FT_Close(this); return(ftStatus == FtStatus.Ok); }
/// <inheritdoc/> protected override void Write(int pinNumber, PinValue value) { var status = FtFunction.FT4222_GPIO_Write(_ftHandle, (GpioPort)pinNumber, value == PinValue.High ? GpioPinValue.High : GpioPinValue.Low); if (status != FtStatus.Ok) { throw new IOException($"{nameof(Write)}: failed to write GPIO, status: {status}"); } }
/// <inheritdoc/> public override void Read(Span <byte> buffer) { ushort byteRead; var ftStatus = FtFunction.FT4222_I2CMaster_Read(_ftHandle, (ushort)_settings.DeviceAddress, in MemoryMarshal.GetReference(buffer), (ushort)buffer.Length, out byteRead); if (ftStatus != FtStatus.Ok) { throw new IOException($"{nameof(Read)} failed to read, error: {ftStatus}"); } }
/// <inheritdoc/> protected override void SetPinMode(int pinNumber, PinMode mode) { _gpioDirections[pinNumber] = mode == PinMode.Output ? GpioPinMode.Output : GpioPinMode.Input; var status = FtFunction.FT4222_GPIO_Init(_ftHandle, _gpioDirections); if (status != FtStatus.Ok) { throw new IOException($"{nameof(SetPinMode)}: failed to set pin number {pinNumber} to {mode}, status: {status}"); } }
/// <summary> /// Get the versions of the chipset and dll /// </summary> /// <returns>Both the chipset and dll versions</returns> public static (Version?Chip, Version?Dll) GetVersions() { // First, let's find a device var devices = GetDevices(); if (devices.Count == 0) { return(null, null); } // Check if the first not open device int idx = 0; for (idx = 0; idx < devices.Count; idx++) { if ((devices[idx].Flags & FtFlag.PortOpened) != FtFlag.PortOpened) { break; } } if (idx == devices.Count) { throw new InvalidOperationException($"Can't find any open device to check the versions"); } SafeFtHandle ftHandle = new SafeFtHandle(); var ftStatus = FtFunction.FT_OpenEx(devices[idx].LocId, FtOpenType.OpenByLocation, out ftHandle); if (ftStatus != FtStatus.Ok) { throw new IOException($"Can't open the device to check chipset version, status: {ftStatus}"); } FtVersion ftVersion; ftStatus = FtFunction.FT4222_GetVersion(ftHandle, out ftVersion); if (ftStatus != FtStatus.Ok) { throw new IOException($"Can't find versions of chipset and FT4222, status: {ftStatus}"); } ftStatus = FtFunction.FT_Close(ftHandle); if (ftStatus != FtStatus.Ok) { throw new IOException($"Can't close the device to check chipset version, status: {ftStatus}"); } Version chip = new Version((int)(ftVersion.ChipVersion >> 24), (int)((ftVersion.ChipVersion >> 16) & 0xFF), (int)((ftVersion.ChipVersion >> 8) & 0xFF), (int)(ftVersion.ChipVersion & 0xFF)); Version dll = new Version((int)(ftVersion.DllVersion >> 24), (int)((ftVersion.DllVersion >> 16) & 0xFF), (int)((ftVersion.DllVersion >> 8) & 0xFF), (int)(ftVersion.DllVersion & 0xFF)); return(chip, dll); }
/// <inheritdoc/> protected override PinValue Read(int pinNumber) { GpioPinValue pinVal; var status = FtFunction.FT4222_GPIO_Read(_ftHandle, (GpioPort)pinNumber, out pinVal); if (status != FtStatus.Ok) { throw new IOException($"{nameof(Read)}: failed to write GPIO, status: {status}"); } return(pinVal == GpioPinValue.High ? PinValue.High : PinValue.Low); }
/// <summary> /// Create a FT4222 GPIO driver /// </summary> /// <param name="deviceNumber">Number of the device in the device list, default 0</param> public Ft4222Gpio(int deviceNumber = 0) { // Check device var devInfos = FtCommon.GetDevices(); if (devInfos.Count == 0) { throw new IOException("No FTDI device available"); } // Select the deviceNumber, only the last one in Mode 0 and Mode 1 can be open. // The last one is either B if in Mode 0 or D in mode 1. string strMode = devInfos[0].Type == FtDevice.Ft4222HMode1or2With4Interfaces ? "FT4222 D" : "FT4222 B"; var devInfo = devInfos.Where(m => m.Description == strMode).ToArray(); if ((devInfo.Length == 0) || (devInfo.Length < deviceNumber)) { throw new IOException($"Can't find a device to open GPIO on index {deviceNumber}"); } DeviceInformation = devInfo[deviceNumber]; // Open device var ftStatus = FtFunction.FT_OpenEx(DeviceInformation.LocId, FtOpenType.OpenByLocation, out _ftHandle); if (ftStatus != FtStatus.Ok) { throw new IOException($"Failed to open device {DeviceInformation.Description}, status: {ftStatus}"); } ftStatus = FtFunction.FT4222_SetSuspendOut(_ftHandle, false); if (ftStatus != FtStatus.Ok) { throw new IOException($"Can't initialize GPIO for device {DeviceInformation.Description} changing Suspend out mode, status: {ftStatus}"); } ftStatus = FtFunction.FT4222_SetWakeUpInterrupt(_ftHandle, false); if (ftStatus != FtStatus.Ok) { throw new IOException($"Can't initialize GPIO for device {DeviceInformation.Description} removing wake up interrupt, status: {ftStatus}"); } for (int i = 0; i < PinCountConst; i++) { _gpioDirections[i] = GpioPinMode.Output; } ftStatus = FtFunction.FT4222_GPIO_Init(_ftHandle, _gpioDirections); if (ftStatus != FtStatus.Ok) { throw new IOException($"Can't initialize GPIO for device {DeviceInformation.Description}, status: {ftStatus}"); } }
/// <inheritdoc/> protected override void RemoveCallbackForPinValueChangedEvent(int pinNumber, PinChangeEventHandler callback) { _pinFallingHandlers[pinNumber] -= callback; _pinRisingHandlers[pinNumber] -= callback; if (_pinFallingHandlers == null) { _gpioTriggers[pinNumber] &= ~GpioTrigger.Falling; } if (_pinRisingHandlers == null) { _gpioTriggers[pinNumber] &= ~GpioTrigger.Rising; } FtFunction.FT4222_GPIO_SetInputTrigger(_ftHandle, (GpioPort)pinNumber, _gpioTriggers[pinNumber]); }
/// <summary> /// Get the version of the chip and dll /// </summary> /// <returns>version</returns> public (Version chip, Version dll) GetVersions() { var ftStatus = FtFunction.FT4222_GetVersion(_ftHandle, out var ftVersion); if (ftStatus != FtStatus.Ok) { throw new IOException($"Can't find versions of chipset and FT4222, status: {ftStatus}"); } var chip = new Version((int)(ftVersion.ChipVersion >> 24), (int)((ftVersion.ChipVersion >> 16) & 0xFF), (int)((ftVersion.ChipVersion >> 8) & 0xFF), (int)(ftVersion.ChipVersion & 0xFF)); var dll = new Version((int)(ftVersion.DllVersion >> 24), (int)((ftVersion.DllVersion >> 16) & 0xFF), (int)((ftVersion.DllVersion >> 8) & 0xFF), (int)(ftVersion.DllVersion & 0xFF)); return(chip, dll); }
/// <summary> /// Create a FT4222 I2C Device /// </summary> /// <param name="settings">I2C Connection Settings</param> /// <param name="frequencyKbps">The speed of I2C transmission.</param> public Ft4222I2cEx(I2cConnectionSettings settings, uint frequencyKbps = I2cMasterFrequencyKbps) { _settings = settings ?? throw new ArgumentNullException(nameof(settings)); FrequencyKbps = frequencyKbps; // Check device var devInfos = FtCommon.GetDevices(); if (devInfos.Count == 0) { throw new IOException("No FTDI device available"); } // Select the one from bus Id // FT4222 propose depending on the mode multiple interfaces. Only the A is available for I2C or where there is none as it's the only interface var devInfo = devInfos.Where(m => m.Description == "FT4222 A" || m.Description == "FT4222").ToArray(); if ((devInfo.Length == 0) || (devInfo.Length < _settings.BusId)) { throw new IOException($"Can't find a device to open I2C on index {_settings.BusId}"); } DeviceInformation = devInfo[_settings.BusId]; // Open device var ftStatus = FtFunction.FT_OpenEx(DeviceInformation.LocId, FtOpenType.OpenByLocation, out _ftHandle); if (ftStatus != FtStatus.Ok) { throw new IOException($"Failed to open device {DeviceInformation.Description}, status: {ftStatus}"); } // Set the clock FtClockRate ft4222Clock = FtClockRate.Clock24MHz; ftStatus = FtFunction.FT4222_SetClock(_ftHandle, ft4222Clock); if (ftStatus != FtStatus.Ok) { throw new IOException($"Failed set clock rate {ft4222Clock} on device: {DeviceInformation.Description}, status: {ftStatus}"); } // Set the device as I2C Master ftStatus = FtFunction.FT4222_I2CMaster_Init(_ftHandle, frequencyKbps); if (ftStatus != FtStatus.Ok) { throw new IOException($"Failed to initialize I2C Master mode on device: {DeviceInformation.Description}, status: {ftStatus}"); } }
/// <summary> /// Returns the list of FT4222 connected /// </summary> /// <returns>A list of devices connected</returns> public static List <DeviceInformation> GetDevices() { List <DeviceInformation> devInfos = new List <DeviceInformation>(); FtStatus ftStatus = 0; // Check device uint numOfDevices; ftStatus = FtFunction.FT_CreateDeviceInfoList(out numOfDevices); Debug.WriteLine($"Number of devices: {numOfDevices}"); if (numOfDevices == 0) { throw new IOException($"No device found"); } Span <byte> sernum = stackalloc byte[16]; Span <byte> desc = stackalloc byte[64]; for (uint i = 0; i < numOfDevices; i++) { uint flags = 0; FtDevice ftDevice; uint id; uint locId; IntPtr handle; ftStatus = FtFunction.FT_GetDeviceInfoDetail(i, out flags, out ftDevice, out id, out locId, in MemoryMarshal.GetReference(sernum), in MemoryMarshal.GetReference(desc), out handle); if (ftStatus != FtStatus.Ok) { throw new IOException($"Can't read device information on device index {i}, error {ftStatus}"); } var devInfo = new DeviceInformation( (FtFlag)flags, ftDevice, id, locId, Encoding.ASCII.GetString(sernum.ToArray(), 0, FindFirstZero(sernum)), Encoding.ASCII.GetString(desc.ToArray(), 0, FindFirstZero(desc))); devInfos.Add(devInfo); } return(devInfos); }
/// <inheritdoc/> protected override void AddCallbackForPinValueChangedEvent(int pinNumber, PinEventTypes eventTypes, PinChangeEventHandler callback) { if (eventTypes == PinEventTypes.None) { throw new ArgumentException($"{PinEventTypes.None} is an invalid value.", nameof(eventTypes)); } if (eventTypes.HasFlag(PinEventTypes.Falling)) { _gpioTriggers[pinNumber] |= GpioTrigger.Falling; _pinFallingHandlers[pinNumber] += callback; } if (eventTypes.HasFlag(PinEventTypes.Rising)) { _gpioTriggers[pinNumber] |= GpioTrigger.Rising; _pinRisingHandlers[pinNumber] += callback; } FtFunction.FT4222_GPIO_SetInputTrigger(_ftHandle, (GpioPort)pinNumber, _gpioTriggers[pinNumber]); }
internal void Write(int deviceAddress, ReadOnlySpan <byte> buffer) { if (deviceAddress < 0 || deviceAddress > ushort.MaxValue) { throw new ArgumentOutOfRangeException(nameof(deviceAddress)); } if (buffer.Length > ushort.MaxValue) { throw new ArgumentOutOfRangeException(nameof(buffer), $"Buffer is too large. Maximum length is {ushort.MaxValue}."); } ushort bytesSent; var ftStatus = FtFunction.FT4222_I2CMaster_Write(_ftHandle, (ushort)deviceAddress, in MemoryMarshal.GetReference(buffer), (ushort)buffer.Length, out bytesSent); if (ftStatus != FtStatus.Ok) { throw new IOException($"{nameof(Write)} failed to write, error: {ftStatus}"); } }
/// <summary> /// Create a FT4222 I2C Device /// </summary> /// <param name="deviceInformation">Device information. Use FtCommon.GetDevices to get it.</param> public Ft4222I2cBus(FtDevice deviceInformation) { switch (deviceInformation.Type) { case FtDeviceType.Ft4222HMode0or2With2Interfaces: case FtDeviceType.Ft4222HMode1or2With4Interfaces: case FtDeviceType.Ft4222HMode3With1Interface: break; default: throw new ArgumentException($"Unknown device type: {deviceInformation.Type}"); } DeviceInformation = deviceInformation; // Open device var ftStatus = FtFunction.FT_OpenEx(DeviceInformation.LocId, FtOpenType.OpenByLocation, out _ftHandle); if (ftStatus != FtStatus.Ok) { throw new IOException($"Failed to open device {DeviceInformation.Description}, status: {ftStatus}"); } // Set the clock FtClockRate ft4222Clock = FtClockRate.Clock24MHz; ftStatus = FtFunction.FT4222_SetClock(_ftHandle, ft4222Clock); if (ftStatus != FtStatus.Ok) { throw new IOException($"Failed set clock rate {ft4222Clock} on device: {DeviceInformation.Description}, status: {ftStatus}"); } // Set the device as I2C Master ftStatus = FtFunction.FT4222_I2CMaster_Init(_ftHandle, I2cMasterFrequencyKbps); if (ftStatus != FtStatus.Ok) { throw new IOException($"Failed to initialize I2C Master mode on device: {DeviceInformation.Description}, status: {ftStatus}"); } }
/// <inheritdoc/> protected override WaitForEventResult WaitForEvent(int pinNumber, PinEventTypes eventTypes, CancellationToken cancellationToken) { while (!cancellationToken.IsCancellationRequested) { ushort queueSize; var ftStatus = FtFunction.FT4222_GPIO_GetTriggerStatus(_ftHandle, (GpioPort)pinNumber, out queueSize); if (ftStatus != FtStatus.Ok) { throw new IOException($"Can't get trigger status, error {ftStatus}"); } if (queueSize > 0) { Span <GpioTrigger> gpioTriggers = stackalloc GpioTrigger[queueSize]; ushort readTrigger; ftStatus = FtFunction.FT4222_GPIO_ReadTriggerQueue(_ftHandle, (GpioPort)pinNumber, in MemoryMarshal.GetReference(gpioTriggers), queueSize, out readTrigger); if (ftStatus != FtStatus.Ok) { throw new IOException($"Can't read trigger status, error {ftStatus}"); } switch (eventTypes) { case PinEventTypes.Rising: if (_gpioTriggers[pinNumber].HasFlag(GpioTrigger.Rising)) { if (gpioTriggers.ToArray().Where(m => m == GpioTrigger.Rising).Count() > 0) { return(new WaitForEventResult() { EventTypes = PinEventTypes.Rising, TimedOut = false }); } } break; case PinEventTypes.Falling: if (_gpioTriggers[pinNumber].HasFlag(GpioTrigger.Falling)) { if (gpioTriggers.ToArray().Where(m => m == GpioTrigger.Falling).Count() > 0) { return(new WaitForEventResult() { EventTypes = PinEventTypes.Falling, TimedOut = false }); } } break; case PinEventTypes.None: default: break; } } } return(new WaitForEventResult() { EventTypes = PinEventTypes.None, TimedOut = true }); }