diff --git a/Source/Meadow.Foundation.Peripherals/ICs.ADC.Ad7768/Datasheet/ad7768-1.pdf b/Source/Meadow.Foundation.Peripherals/ICs.ADC.Ad7768/Datasheet/ad7768-1.pdf new file mode 100644 index 0000000000..314be518d1 Binary files /dev/null and b/Source/Meadow.Foundation.Peripherals/ICs.ADC.Ad7768/Datasheet/ad7768-1.pdf differ diff --git a/Source/Meadow.Foundation.Peripherals/ICs.ADC.Ad7768/Datasheet/ad7768-7768-4.pdf b/Source/Meadow.Foundation.Peripherals/ICs.ADC.Ad7768/Datasheet/ad7768-7768-4.pdf new file mode 100644 index 0000000000..7083712f6b Binary files /dev/null and b/Source/Meadow.Foundation.Peripherals/ICs.ADC.Ad7768/Datasheet/ad7768-7768-4.pdf differ diff --git a/Source/Meadow.Foundation.Peripherals/ICs.ADC.Ad7768/Driver/Ad7768.Registers.cs b/Source/Meadow.Foundation.Peripherals/ICs.ADC.Ad7768/Driver/Ad7768.Registers.cs new file mode 100644 index 0000000000..0ee9d16811 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.ADC.Ad7768/Driver/Ad7768.Registers.cs @@ -0,0 +1,126 @@ +namespace Meadow.Foundation.ICs.ADC +{ + public partial class Ad7768 + { + internal enum Mask : byte + { + SleepMode = 1 << 7, + MCLK = 0x03 << 0, + CRC_SEL = 0x03 << 2, + PWR_MODE = 0x03 << 5, + DCLK_DIV = 0x03 << 0, + OneShot = 1 << 4, + DecimationRate = 0x07 << 0, + SYNC_OFF = 0x7f, + SYNC_ON = 0x80 + } + + internal enum SleepMode : byte + { + Active = 0, + Sleep = 1 + } + + internal enum PowerMode : byte + { + Eco = 0, + Median = 2, + Fast = 3 + } + + internal enum MCLKDivisor : byte + { + Div32 = 0, + Div8 = 2, + Div4 = 3 + } + + internal enum DCLKDivisor : byte + { + Div8 = 0, + Div4 = 1, + Div2 = 2, + Div1 = 3, + } + + internal enum ConversionType : byte + { + Standard = 0, + OneShot = 1 + } + + internal enum ChannelState : byte + { + Enabled = 0, + StandBy = 1 + } + + internal enum ChannelMode : byte + { + A = 0, + B = 1 + } + + internal enum CrcSelection : byte + { + None = 0, + CRC_4, + CRC_16, + CRC_16_2ND + } + + internal enum FilterType : byte + { + Wideband, + Sinc + } + + internal enum DecimationRate : byte + { + X32, + X64, + X128, + X256, + X512, + X1024, + X1024_2ND, + X1024_3RD + } + + internal enum Registers : byte + { + CH_STANDBY = 0x00, + CH_MODE_A = 0x01, + CH_MODE_B = 0x02, + CH_MODE_SEL = 0x03, + PWR_MODE = 0x04, + GENERAL_CFG = 0x05, + DATA_CTRL = 0x06, + INTERFACE_CFG = 0x07, + BIST_CTRL = 0x08, + DEV_STATUS = 0x09, + REV_ID = 0x0A, + DEV_ID_MSB = 0x0B, + DEV_ID_LSB = 0x0C, + SW_REV_ID = 0x0D, + GPIO_CTRL = 0x0E, + GPIO_WR_DATA = 0x0F, + GPIO_RD_DATA = 0x10, + PRECHARGE_BUF_1 = 0x11, + PRECHARGE_BUF_2 = 0x12, + POS_REF_BUF = 0x13, + NEG_REF_BUF = 0x14, + //CH_OFFSET_1(ch) = (0x1E + (ch) * 3) , + //CH_OFFSET_2(ch) = (0x1F + (ch) * 3) , + //CH_OFFSET_3(ch) = (0x20 + (ch) * 3) , + //CH_GAIN_1(ch) = (0x36 + (ch) * 3) , + //CH_GAIN_2(ch) = (0x37 + (ch) * 3) , + //CH_GAIN_3(ch) = (0x38 + (ch) * 3) , + //CH_SYNC_OFFSET(ch) = (0x4E + (ch) * 3) , + DIAG_METER_RX = 0x56, + DIAG_CTRL = 0x57, + DIAG_MOD_DELAY_CTRL = 0x58, + DIAG_CHOP_CTRL = 0x59, + } + } +} \ No newline at end of file diff --git a/Source/Meadow.Foundation.Peripherals/ICs.ADC.Ad7768/Driver/Ad7768.cs b/Source/Meadow.Foundation.Peripherals/ICs.ADC.Ad7768/Driver/Ad7768.cs new file mode 100644 index 0000000000..c9d82013e0 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.ADC.Ad7768/Driver/Ad7768.cs @@ -0,0 +1,262 @@ +using Meadow.Hardware; +using Meadow.Units; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Meadow.Foundation.ICs.ADC +{ + public partial class Ad7768 : PollingSensorBase, ISpiPeripheral + { + private ISpiBus spiBus; + private bool portsCreated = false; + private IDigitalOutputPort? csPort; + private IDigitalOutputPort? resetPort; + private IDigitalInterruptPort? dataReadyPort; + private IDigitalInterruptPort? dataClockPort; + + /// + public SpiClockConfiguration.Mode DefaultSpiBusMode => SpiClockConfiguration.Mode.Mode3; + /// + public Frequency DefaultSpiBusSpeed => 40_000_000.Hertz(); + + public Ad7768( + ISpiBus spiBus, + IPin? chipSelectPin, + IPin? resetPin, + IPin? dataReadyPin, + IPin? dataClockPin) + { + this.spiBus = spiBus; + + if (chipSelectPin != null) + { + Resolver.Log.Info("Creating CS"); + csPort = chipSelectPin.CreateDigitalOutputPort(true); // start high (disabled) + } + if (resetPin != null) + { + Resolver.Log.Info("Creating RST"); + // this has an internal pull up. Drive it low to reset (> 2ms) + resetPort = resetPin.CreateDigitalOutputPort(true); + } + if (dataReadyPin != null) + { + Resolver.Log.Info("Creating DR"); + // also active low + dataReadyPort = dataReadyPin.CreateDigitalInterruptPort(InterruptMode.EdgeFalling, ResistorMode.InternalPullUp); + } + if (dataClockPin != null) + { + dataClockPort = dataClockPin.CreateDigitalInterruptPort(InterruptMode.EdgeRising, ResistorMode.Disabled); // active high + } + + portsCreated = true; + } + + public int ClockDataValue() + { + if (dataClockPort == null) return -1; + + // todo: clock in 24 bits(TODO: support channels) + + return 0; + } + + private void WriteRegisterByte(Registers register, byte data) + { + Span tx = stackalloc byte[2]; + Span rx = stackalloc byte[2]; + // high bit indicates read/write (off == write) + tx[0] = (byte)(0x7f & (byte)register); + tx[1] = data; + + Resolver.Log.Info($"WRITE: {BitConverter.ToString(tx.ToArray())}"); + spiBus.Exchange(csPort, tx, rx); + var reg = ReadRegisterByte(register); + } + + private void WriteRegisterByte(Registers register, Mask mask, byte data) + { + WriteRegisterByte(register, (byte)mask, data); + } + + private void WriteRegisterByte(Registers register, byte mask, byte data) + { + var value = ReadRegisterByte(register); + value &= (byte)~mask; + value |= data; + WriteRegisterByte(register, value); + } + + private byte ReadRegisterByte(Registers register) + { + Span buffer = stackalloc byte[2]; + + // high bit indicates read/write (on == read) + // dev note: we MUST send this twice. + // Page 51 of the data sheet explains. + // "The SPI control interface uses an off frame protocol" + var value = (byte)(0x80 | (0x7f & (byte)register)); + buffer[0] = value; + spiBus.Exchange(csPort, buffer, buffer); + buffer[0] = value; + spiBus.Exchange(csPort, buffer, buffer); + + Resolver.Log.Info($"READ: {buffer[1]:x2}"); + + return buffer[1]; + } + + private byte ReadRegisterByte(Registers register, byte mask) + { + var value = ReadRegisterByte(register); + return (byte)(value & mask); + } + + private void SetSleepMode(SleepMode sleepMode) + { + WriteRegisterByte(Registers.PWR_MODE, Mask.SleepMode, (byte)sleepMode); + SynchronizeAdc(); + } + + private void SynchronizeAdc() + { + WriteRegisterByte(Registers.DATA_CTRL, Mask.SYNC_OFF, 0x00); + WriteRegisterByte(Registers.DATA_CTRL, Mask.SYNC_ON, 0x80); + } + + public void Test() + { + Resolver.Log.Info("MCLK4"); + SetMClkDivisor(MCLKDivisor.Div4); + Thread.Sleep(1000); + Resolver.Log.Info("MCLK8"); + SetMClkDivisor(MCLKDivisor.Div8); + Thread.Sleep(1000); + Resolver.Log.Info("MCLK32"); + SetMClkDivisor(MCLKDivisor.Div32); + Thread.Sleep(1000); + } + + private void SetMClkDivisor(MCLKDivisor mclkDivisor) + { + WriteRegisterByte(Registers.PWR_MODE, Mask.MCLK, (byte)mclkDivisor); + SynchronizeAdc(); + } + + private void SetCrcSelection(CrcSelection crcSelection) + { + // the C# compiler is so stupid at times - especially when doing bitwise work. + WriteRegisterByte(Registers.INTERFACE_CFG, Mask.CRC_SEL, (byte)((byte)crcSelection << 0x03)); + } + + private void SetPowerMode(PowerMode powerMode) + { + WriteRegisterByte(Registers.PWR_MODE, Mask.PWR_MODE, (byte)((byte)powerMode << 0x05)); + SynchronizeAdc(); + } + + private void SetDClkDivisor(DCLKDivisor dclkDivisor) + { + WriteRegisterByte(Registers.INTERFACE_CFG, Mask.DCLK_DIV, (byte)((byte)dclkDivisor << 0)); + SynchronizeAdc(); + } + + private void SetConversionType(ConversionType conversionType) + { + WriteRegisterByte(Registers.DATA_CTRL, Mask.OneShot, (byte)((byte)conversionType << 4)); + SynchronizeAdc(); + } + + private void SetModeConfiguration(ChannelMode channelMode, FilterType filterType, DecimationRate decimationRate) + { + byte value = (byte)((filterType == FilterType.Sinc) ? 1 << 3 : 0); + value |= (byte)Mask.DecimationRate; + var register = channelMode == ChannelMode.A ? Registers.CH_MODE_A : Registers.CH_MODE_B; + WriteRegisterByte(register, value); + SynchronizeAdc(); + } + + private void SetChannelState(int channel, ChannelState state) + { + WriteRegisterByte(Registers.CH_STANDBY, (byte)(1 << channel), (byte)(state == ChannelState.Enabled ? 1 << channel : 0)); + SynchronizeAdc(); + } + + private void ResetChip() + { + if (resetPort != null) + { + resetPort.State = false; + Thread.Sleep(5); + resetPort.State = true; + Thread.Sleep(10); + } + } + + public void Initialize() + { + ResetChip(); + + if (csPort != null) + { + Resolver.Log.Info("CS HIGH"); + csPort.State = true; + Thread.Sleep(100); + Resolver.Log.Info("CS LOW"); + csPort.State = false; + Thread.Sleep(100); + } + + SetSleepMode(SleepMode.Active); + SetMClkDivisor(MCLKDivisor.Div32); + SetCrcSelection(CrcSelection.None); + SetPowerMode(PowerMode.Eco); + SetDClkDivisor(DCLKDivisor.Div8); + SetConversionType(ConversionType.Standard); + SetModeConfiguration(ChannelMode.A, FilterType.Sinc, DecimationRate.X1024); + + var channels = 4; + + for (var channel = 0; channel < channels; channel++) + { + SetChannelState(channel, ChannelState.Enabled); + } + } + + + /// + /// Enables of disables a specific ADC channel + /// + /// The channel to affect + /// True to enable, False to put the channel in standby + /// + public void EnableChannel(int channel, bool enabled) + { + if (channel < 0 || channel > 3) throw new ArgumentOutOfRangeException(nameof(channel)); + + SetChannelState(channel, enabled ? ChannelState.Enabled : ChannelState.StandBy); + } + + + /// + public Frequency SpiBusSpeed + { + get => throw new System.NotImplementedException(); + set => throw new System.NotImplementedException(); + } + + public SpiClockConfiguration.Mode SpiBusMode + { + get => spiBus.Configuration.SpiMode; + set => throw new NotSupportedException(); + } + + protected override Task ReadSensor() + { + return Task.FromResult(0.Volts()); + } + + } +} \ No newline at end of file diff --git a/Source/Meadow.Foundation.Peripherals/ICs.ADC.Ad7768/Driver/ICs.ADC.Ad7768.csproj b/Source/Meadow.Foundation.Peripherals/ICs.ADC.Ad7768/Driver/ICs.ADC.Ad7768.csproj new file mode 100644 index 0000000000..e689e8ddea --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.ADC.Ad7768/Driver/ICs.ADC.Ad7768.csproj @@ -0,0 +1,23 @@ + + + 1.11.0 + enable + 10.0 + Apache-2.0 + true + Wilderness Labs, Inc + netstandard2.1 + Library + Ad7768 + Wilderness Labs, Inc + http://developer.wildernesslabs.co/Meadow/Meadow.Foundation/ + Meadow.Foundation.ICs.ADC.Ad7768 + https://github.com/WildernessLabs/Meadow.Foundation + Meadow.Foundation,ADC,analog,digital,converter,Analog Devices, AD7768 + true + Analog Devices AD7768 SPI analog to digital converters (AD7768 / AD7768-4) + + + + + diff --git a/Source/Meadow.Foundation.Peripherals/ICs.ADC.Ad7768/Samples/Ad7768_Sample/Ad7768_Sample.csproj b/Source/Meadow.Foundation.Peripherals/ICs.ADC.Ad7768/Samples/Ad7768_Sample/Ad7768_Sample.csproj new file mode 100644 index 0000000000..d95db8e896 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.ADC.Ad7768/Samples/Ad7768_Sample/Ad7768_Sample.csproj @@ -0,0 +1,12 @@ + + + netstandard2.1 + true + Library + App + + + + + + diff --git a/Source/Meadow.Foundation.Peripherals/ICs.ADC.Ad7768/Samples/Ad7768_Sample/MeadowApp.cs b/Source/Meadow.Foundation.Peripherals/ICs.ADC.Ad7768/Samples/Ad7768_Sample/MeadowApp.cs new file mode 100644 index 0000000000..7fd87a89ea --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.ADC.Ad7768/Samples/Ad7768_Sample/MeadowApp.cs @@ -0,0 +1,37 @@ +using Meadow; +using Meadow.Devices; +using Meadow.Foundation.ICs.ADC; +using System.Threading.Tasks; + +namespace ADC.Ad7768_Sample +{ + public class MeadowApp : App + { + // + + private Ad7768 adc; + + public override async Task Initialize() + { + Resolver.Log.Info("Initialize..."); + + adc = new Ad7768( + Device.CreateSpiBus(), + Device.Pins.D05, + null, null, + Device.Pins.D06); + + Resolver.Log.Info("Reading..."); + + adc.Initialize(); + + while (true) + { + adc.Test(); + await Task.Delay(1000); + } + } + + // + } +} \ No newline at end of file diff --git a/Source/Meadow.Foundation.Peripherals/ICs.ADC.Ads1x15/Driver/Ads1x15Base.cs b/Source/Meadow.Foundation.Peripherals/ICs.ADC.Ads1x15/Driver/Ads1x15Base.cs index 187301dd18..44dcb304ba 100644 --- a/Source/Meadow.Foundation.Peripherals/ICs.ADC.Ads1x15/Driver/Ads1x15Base.cs +++ b/Source/Meadow.Foundation.Peripherals/ICs.ADC.Ads1x15/Driver/Ads1x15Base.cs @@ -86,7 +86,7 @@ private void SetConfigRegister(ushort value) /// /// Get or set the internal sample rate /// - internal protected int InternalSampleRate + protected internal int InternalSampleRate { get => (config >> RateShift) & 0b111; set diff --git a/Source/Meadow.Foundation.Peripherals/ICs.ADCs.Mcp3xxx/Driver/Drivers/Mcp3201.cs b/Source/Meadow.Foundation.Peripherals/ICs.ADCs.Mcp3xxx/Driver/Drivers/Mcp3201.cs index 3315a68302..6c811dc77a 100644 --- a/Source/Meadow.Foundation.Peripherals/ICs.ADCs.Mcp3xxx/Driver/Drivers/Mcp3201.cs +++ b/Source/Meadow.Foundation.Peripherals/ICs.ADCs.Mcp3xxx/Driver/Drivers/Mcp3201.cs @@ -20,7 +20,7 @@ public partial class Mcp3201 : Mcp3xxx /// /// The SPI bus /// Chip select pin - public Mcp3201(ISpiBus spiBus, IPin chipSelectPin) + public Mcp3201(ISpiBus spiBus, IPin? chipSelectPin) : base(spiBus, chipSelectPin, 1, 12) { Pins = new PinDefinitions(this); @@ -31,7 +31,7 @@ public Mcp3201(ISpiBus spiBus, IPin chipSelectPin) /// /// The SPI bus /// Chip select port - public Mcp3201(ISpiBus spiBus, IDigitalOutputPort chipSelectPort) + public Mcp3201(ISpiBus spiBus, IDigitalOutputPort? chipSelectPort) : base(spiBus, chipSelectPort, 1, 12) { Pins = new PinDefinitions(this); diff --git a/Source/Meadow.Foundation.Peripherals/ICs.ADCs.Mcp3xxx/Driver/Mcp3xxx.cs b/Source/Meadow.Foundation.Peripherals/ICs.ADCs.Mcp3xxx/Driver/Mcp3xxx.cs index 19ecad266c..0fb5d6e010 100644 --- a/Source/Meadow.Foundation.Peripherals/ICs.ADCs.Mcp3xxx/Driver/Mcp3xxx.cs +++ b/Source/Meadow.Foundation.Peripherals/ICs.ADCs.Mcp3xxx/Driver/Mcp3xxx.cs @@ -74,7 +74,7 @@ public SpiClockConfiguration.Mode SpiBusMode /// internal int AdcMaxValue { get; set; } - private IDigitalOutputPort chipSelectPort; + private IDigitalOutputPort? chipSelectPort = null; /// /// Mcp3xxx base class constructor @@ -84,9 +84,9 @@ public SpiClockConfiguration.Mode SpiBusMode /// The number of input channels /// The resolution in bits for the ADC protected Mcp3xxx(ISpiBus spiBus, - IPin chipSelectPin, + IPin? chipSelectPin, int channelCount, int adcResolutionInBits) : - this(spiBus, chipSelectPin.CreateDigitalOutputPort(), channelCount, adcResolutionInBits) + this(spiBus, chipSelectPin?.CreateDigitalOutputPort(), channelCount, adcResolutionInBits) { createdPort = true; } @@ -99,7 +99,7 @@ protected Mcp3xxx(ISpiBus spiBus, /// The number of input channels /// The resolution in bits for the ADC protected Mcp3xxx(ISpiBus spiBus, - IDigitalOutputPort chipSelectPort, + IDigitalOutputPort? chipSelectPort, int channelCount, int adcResolutionInBits) { AdcResolutionInBits = adcResolutionInBits; diff --git a/Source/Meadow.Foundation.Peripherals/ICs.DAC.Ad569x/Datasheet/AD5696R_5695R_5694R.pdf b/Source/Meadow.Foundation.Peripherals/ICs.DAC.Ad569x/Datasheet/AD5696R_5695R_5694R.pdf new file mode 100644 index 0000000000..74637ae726 Binary files /dev/null and b/Source/Meadow.Foundation.Peripherals/ICs.DAC.Ad569x/Datasheet/AD5696R_5695R_5694R.pdf differ diff --git a/Source/Meadow.Foundation.Peripherals/ICs.DAC.Ad569x/Driver/Ad569x.cs b/Source/Meadow.Foundation.Peripherals/ICs.DAC.Ad569x/Driver/Ad569x.cs new file mode 100644 index 0000000000..807c41fb19 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.DAC.Ad569x/Driver/Ad569x.cs @@ -0,0 +1,22 @@ +using Meadow.Hardware; + +namespace Meadow.Foundation.ICs.DAC +{ + public abstract partial class Ad569x : II2cPeripheral + { + public byte DefaultI2cAddress => throw new System.NotImplementedException(); + + public enum Addresses + { + Address_0C = 0b0001100, + Address_0D = 0b0001101, + Address_0E = 0b0001110, + Address_0F = 0b0001111, + Default = Address_0C, + } + + internal Ad569x(II2cBus bus) + { + } + } +} \ No newline at end of file diff --git a/Source/Meadow.Foundation.Peripherals/ICs.DAC.Ad569x/Driver/ICs.DAC.Ad569x.csproj b/Source/Meadow.Foundation.Peripherals/ICs.DAC.Ad569x/Driver/ICs.DAC.Ad569x.csproj new file mode 100644 index 0000000000..fa302d6a8f --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.DAC.Ad569x/Driver/ICs.DAC.Ad569x.csproj @@ -0,0 +1,23 @@ + + + 1.11.0 + enable + 10.0 + Apache-2.0 + true + Wilderness Labs, Inc + netstandard2.1 + Library + Ad569x + Wilderness Labs, Inc + http://developer.wildernesslabs.co/Meadow/Meadow.Foundation/ + Meadow.Foundation.ICs.DAC.Ad5696 + https://github.com/WildernessLabs/Meadow.Foundation + Meadow.Foundation,DAC,analog,digital,converter,Analog Devices,AD5696,AD5695,AD5694 + true + Analog Devices AD569x I2C digital to analog converters (AD5696,AD5695,AD5694) + + + + + diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/EEPROM_STRUCTURES/FT2232H_EEPROM_STRUCTURE.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/EEPROM_STRUCTURES/FT2232H_EEPROM_STRUCTURE.cs new file mode 100644 index 0000000000..899b70aafe --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/EEPROM_STRUCTURES/FT2232H_EEPROM_STRUCTURE.cs @@ -0,0 +1,123 @@ +namespace FTD2XX; + +/// +/// EEPROM structure specific to FT2232H devices. +/// Inherits from FT_EEPROM_DATA. +/// +internal class FT2232H_EEPROM_STRUCTURE : FT_EEPROM_DATA +{ + /// + /// Determines if IOs are pulled down when the device is in suspend + /// + public bool PullDownEnable = false; + + /// + /// Determines if the serial number is enabled + /// + public bool SerNumEnable = true; + + /// + /// Determines if AL pins have a slow slew rate + /// + public bool ALSlowSlew = false; + + /// + /// Determines if the AL pins have a Schmitt input + /// + public bool ALSchmittInput = false; + + /// + /// Determines the AL pins drive current in mA. Valid values are FT_DRIVE_CURRENT_4MA, FT_DRIVE_CURRENT_8MA, FT_DRIVE_CURRENT_12MA or FT_DRIVE_CURRENT_16MA + /// + public byte ALDriveCurrent = FT_DRIVE_CURRENT.FT_DRIVE_CURRENT_4MA; + + /// + /// Determines if AH pins have a slow slew rate + /// + public bool AHSlowSlew = false; + + /// + /// Determines if the AH pins have a Schmitt input + /// + public bool AHSchmittInput = false; + + /// + /// Determines the AH pins drive current in mA. Valid values are FT_DRIVE_CURRENT_4MA, FT_DRIVE_CURRENT_8MA, FT_DRIVE_CURRENT_12MA or FT_DRIVE_CURRENT_16MA + /// + public byte AHDriveCurrent = FT_DRIVE_CURRENT.FT_DRIVE_CURRENT_4MA; + + /// + /// Determines if BL pins have a slow slew rate + /// + public bool BLSlowSlew = false; + + /// + /// Determines if the BL pins have a Schmitt input + /// + public bool BLSchmittInput = false; + + /// + /// Determines the BL pins drive current in mA. Valid values are FT_DRIVE_CURRENT_4MA, FT_DRIVE_CURRENT_8MA, FT_DRIVE_CURRENT_12MA or FT_DRIVE_CURRENT_16MA + /// + public byte BLDriveCurrent = FT_DRIVE_CURRENT.FT_DRIVE_CURRENT_4MA; + + /// + /// Determines if BH pins have a slow slew rate + /// + public bool BHSlowSlew = false; + + /// + /// Determines if the BH pins have a Schmitt input + /// + public bool BHSchmittInput = false; + + /// + /// Determines the BH pins drive current in mA. Valid values are FT_DRIVE_CURRENT_4MA, FT_DRIVE_CURRENT_8MA, FT_DRIVE_CURRENT_12MA or FT_DRIVE_CURRENT_16MA + /// + public byte BHDriveCurrent = FT_DRIVE_CURRENT.FT_DRIVE_CURRENT_4MA; + + /// + /// Determines if channel A is in FIFO mode + /// + public bool IFAIsFifo = false; + + /// + /// Determines if channel A is in FIFO target mode + /// + public bool IFAIsFifoTar = false; + + /// + /// Determines if channel A is in fast serial mode + /// + public bool IFAIsFastSer = false; + + /// + /// Determines if channel A loads the VCP driver + /// + public bool AIsVCP = true; + + /// + /// Determines if channel B is in FIFO mode + /// + public bool IFBIsFifo = false; + + /// + /// Determines if channel B is in FIFO target mode + /// + public bool IFBIsFifoTar = false; + + /// + /// Determines if channel B is in fast serial mode + /// + public bool IFBIsFastSer = false; + + /// + /// Determines if channel B loads the VCP driver + /// + public bool BIsVCP = true; + + /// + /// For self-powered designs, keeps the FT2232H in low power state until BCBUS7 is high + /// + public bool PowerSaveEnable = false; +} diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/EEPROM_STRUCTURES/FT2232_EEPROM_STRUCTURE.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/EEPROM_STRUCTURES/FT2232_EEPROM_STRUCTURE.cs new file mode 100644 index 0000000000..ba4f732ef0 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/EEPROM_STRUCTURES/FT2232_EEPROM_STRUCTURE.cs @@ -0,0 +1,79 @@ +namespace FTD2XX; + +/// +/// EEPROM structure specific to FT2232 devices. +/// Inherits from FT_EEPROM_DATA. +/// +internal class FT2232_EEPROM_STRUCTURE : FT_EEPROM_DATA +{ + /// + /// Determines if IOs are pulled down when the device is in suspend + /// + public bool PullDownEnable = false; + + /// + /// Determines if the serial number is enabled + /// + public bool SerNumEnable = true; + + /// + /// Determines if the USB version number is enabled + /// + public bool USBVersionEnable = true; + + /// + /// The USB version number. Should be either 0x0110 (USB 1.1) or 0x0200 (USB 2.0) + /// + public short USBVersion = 0x0200; + + /// + /// Enables high current IOs on channel A + /// + public bool AIsHighCurrent = false; + + /// + /// Enables high current IOs on channel B + /// + public bool BIsHighCurrent = false; + + /// + /// Determines if channel A is in FIFO mode + /// + public bool IFAIsFifo = false; + + /// + /// Determines if channel A is in FIFO target mode + /// + public bool IFAIsFifoTar = false; + + /// + /// Determines if channel A is in fast serial mode + /// + public bool IFAIsFastSer = false; + + /// + /// Determines if channel A loads the VCP driver + /// + public bool AIsVCP = true; + + /// + /// Determines if channel B is in FIFO mode + /// + public bool IFBIsFifo = false; + + /// + /// Determines if channel B is in FIFO target mode + /// + public bool IFBIsFifoTar = false; + + /// + /// Determines if channel B is in fast serial mode + /// + public bool IFBIsFastSer = false; + + /// + /// Determines if channel B loads the VCP driver + /// + public bool BIsVCP = true; +} + diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/EEPROM_STRUCTURES/FT232B_EEPROM_STRUCTURE.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/EEPROM_STRUCTURES/FT232B_EEPROM_STRUCTURE.cs new file mode 100644 index 0000000000..d0093e8ef7 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/EEPROM_STRUCTURES/FT232B_EEPROM_STRUCTURE.cs @@ -0,0 +1,29 @@ +namespace FTD2XX; + +/// +/// EEPROM structure specific to FT232B and FT245B devices. +/// Inherits from FT_EEPROM_DATA. +/// +internal class FT232B_EEPROM_STRUCTURE : FT_EEPROM_DATA +{ + /// + /// Determines if IOs are pulled down when the device is in suspend + /// + public bool PullDownEnable = false; + + /// + /// Determines if the serial number is enabled + /// + public bool SerNumEnable = true; + + /// + /// Determines if the USB version number is enabled + /// + public bool USBVersionEnable = true; + + /// + /// The USB version number. Should be either 0x0110 (USB 1.1) or 0x0200 (USB 2.0) + /// + public short USBVersion = 0x0200; +} + diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/EEPROM_STRUCTURES/FT232H_EEPROM_STRUCTURE.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/EEPROM_STRUCTURES/FT232H_EEPROM_STRUCTURE.cs new file mode 100644 index 0000000000..d56c8fa781 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/EEPROM_STRUCTURES/FT232H_EEPROM_STRUCTURE.cs @@ -0,0 +1,169 @@ +namespace FTD2XX; + +/// +/// EEPROM structure specific to FT232H devices. +/// Inherits from FT_EEPROM_DATA. +/// +internal class FT232H_EEPROM_STRUCTURE : FT_EEPROM_DATA +{ + /// + /// Determines if IOs are pulled down when the device is in suspend + /// + public bool PullDownEnable = false; + + /// + /// Determines if the serial number is enabled + /// + public bool SerNumEnable = true; + + /// + /// Determines if AC pins have a slow slew rate + /// + public bool ACSlowSlew = false; + + /// + /// Determines if the AC pins have a Schmitt input + /// + public bool ACSchmittInput = false; + + /// + /// Determines the AC pins drive current in mA. Valid values are FT_DRIVE_CURRENT_4MA, FT_DRIVE_CURRENT_8MA, FT_DRIVE_CURRENT_12MA or FT_DRIVE_CURRENT_16MA + /// + public byte ACDriveCurrent = FT_DRIVE_CURRENT.FT_DRIVE_CURRENT_4MA; + + /// + /// Determines if AD pins have a slow slew rate + /// + public bool ADSlowSlew = false; + + /// + /// Determines if the AD pins have a Schmitt input + /// + public bool ADSchmittInput = false; + + /// + /// Determines the AD pins drive current in mA. Valid values are FT_DRIVE_CURRENT_4MA, FT_DRIVE_CURRENT_8MA, FT_DRIVE_CURRENT_12MA or FT_DRIVE_CURRENT_16MA + /// + public byte ADDriveCurrent = FT_DRIVE_CURRENT.FT_DRIVE_CURRENT_4MA; + + /// + /// Sets the function of the CBUS0 pin for FT232H devices. + /// Valid values are FT_CBUS_TRISTATE, FT_CBUS_RXLED, FT_CBUS_TXLED, FT_CBUS_TXRXLED, + /// FT_CBUS_PWREN, FT_CBUS_SLEEP, FT_CBUS_DRIVE_0, FT_CBUS_DRIVE_1, FT_CBUS_TXDEN, FT_CBUS_CLK30, + /// FT_CBUS_CLK15, FT_CBUS_CLK7_5 + /// + public byte Cbus0 = FT_232H_CBUS_OPTIONS.FT_CBUS_TRISTATE; + + /// + /// Sets the function of the CBUS1 pin for FT232H devices. + /// Valid values are FT_CBUS_TRISTATE, FT_CBUS_RXLED, FT_CBUS_TXLED, FT_CBUS_TXRXLED, + /// FT_CBUS_PWREN, FT_CBUS_SLEEP, FT_CBUS_DRIVE_0, FT_CBUS_DRIVE_1, FT_CBUS_TXDEN, FT_CBUS_CLK30, + /// FT_CBUS_CLK15, FT_CBUS_CLK7_5 + /// + public byte Cbus1 = FT_232H_CBUS_OPTIONS.FT_CBUS_TRISTATE; + + /// + /// Sets the function of the CBUS2 pin for FT232H devices. + /// Valid values are FT_CBUS_TRISTATE, FT_CBUS_RXLED, FT_CBUS_TXLED, FT_CBUS_TXRXLED, + /// FT_CBUS_PWREN, FT_CBUS_SLEEP, FT_CBUS_DRIVE_0, FT_CBUS_DRIVE_1, FT_CBUS_TXDEN + /// + public byte Cbus2 = FT_232H_CBUS_OPTIONS.FT_CBUS_TRISTATE; + + /// + /// Sets the function of the CBUS3 pin for FT232H devices. + /// Valid values are FT_CBUS_TRISTATE, FT_CBUS_RXLED, FT_CBUS_TXLED, FT_CBUS_TXRXLED, + /// FT_CBUS_PWREN, FT_CBUS_SLEEP, FT_CBUS_DRIVE_0, FT_CBUS_DRIVE_1, FT_CBUS_TXDEN + /// + public byte Cbus3 = FT_232H_CBUS_OPTIONS.FT_CBUS_TRISTATE; + + /// + /// Sets the function of the CBUS4 pin for FT232H devices. + /// Valid values are FT_CBUS_TRISTATE, FT_CBUS_RXLED, FT_CBUS_TXLED, FT_CBUS_TXRXLED, + /// FT_CBUS_PWREN, FT_CBUS_SLEEP, FT_CBUS_DRIVE_0, FT_CBUS_DRIVE_1, FT_CBUS_TXDEN + /// + public byte Cbus4 = FT_232H_CBUS_OPTIONS.FT_CBUS_TRISTATE; + + /// + /// Sets the function of the CBUS5 pin for FT232H devices. + /// Valid values are FT_CBUS_TRISTATE, FT_CBUS_RXLED, FT_CBUS_TXLED, FT_CBUS_TXRXLED, + /// FT_CBUS_PWREN, FT_CBUS_SLEEP, FT_CBUS_DRIVE_0, FT_CBUS_DRIVE_1, FT_CBUS_IOMODE, + /// FT_CBUS_TXDEN, FT_CBUS_CLK30, FT_CBUS_CLK15, FT_CBUS_CLK7_5 + /// + public byte Cbus5 = FT_232H_CBUS_OPTIONS.FT_CBUS_TRISTATE; + + /// + /// Sets the function of the CBUS6 pin for FT232H devices. + /// Valid values are FT_CBUS_TRISTATE, FT_CBUS_RXLED, FT_CBUS_TXLED, FT_CBUS_TXRXLED, + /// FT_CBUS_PWREN, FT_CBUS_SLEEP, FT_CBUS_DRIVE_0, FT_CBUS_DRIVE_1, FT_CBUS_IOMODE, + /// FT_CBUS_TXDEN, FT_CBUS_CLK30, FT_CBUS_CLK15, FT_CBUS_CLK7_5 + /// + public byte Cbus6 = FT_232H_CBUS_OPTIONS.FT_CBUS_TRISTATE; + + /// + /// Sets the function of the CBUS7 pin for FT232H devices. + /// Valid values are FT_CBUS_TRISTATE + /// + public byte Cbus7 = FT_232H_CBUS_OPTIONS.FT_CBUS_TRISTATE; + + /// + /// Sets the function of the CBUS8 pin for FT232H devices. + /// Valid values are FT_CBUS_TRISTATE, FT_CBUS_RXLED, FT_CBUS_TXLED, FT_CBUS_TXRXLED, + /// FT_CBUS_PWREN, FT_CBUS_SLEEP, FT_CBUS_DRIVE_0, FT_CBUS_DRIVE_1, FT_CBUS_IOMODE, + /// FT_CBUS_TXDEN, FT_CBUS_CLK30, FT_CBUS_CLK15, FT_CBUS_CLK7_5 + /// + public byte Cbus8 = FT_232H_CBUS_OPTIONS.FT_CBUS_TRISTATE; + + /// + /// Sets the function of the CBUS9 pin for FT232H devices. + /// Valid values are FT_CBUS_TRISTATE, FT_CBUS_RXLED, FT_CBUS_TXLED, FT_CBUS_TXRXLED, + /// FT_CBUS_PWREN, FT_CBUS_SLEEP, FT_CBUS_DRIVE_0, FT_CBUS_DRIVE_1, FT_CBUS_IOMODE, + /// FT_CBUS_TXDEN, FT_CBUS_CLK30, FT_CBUS_CLK15, FT_CBUS_CLK7_5 + /// + public byte Cbus9 = FT_232H_CBUS_OPTIONS.FT_CBUS_TRISTATE; + + /// + /// Determines if the device is in FIFO mode + /// + public bool IsFifo = false; + + /// + /// Determines if the device is in FIFO target mode + /// + public bool IsFifoTar = false; + + /// + /// Determines if the device is in fast serial mode + /// + public bool IsFastSer = false; + + /// + /// Determines if the device is in FT1248 mode + /// + public bool IsFT1248 = false; + + /// + /// Determines FT1248 mode clock polarity + /// + public bool FT1248Cpol = false; + + /// + /// Determines if data is ent MSB (0) or LSB (1) in FT1248 mode + /// + public bool FT1248Lsb = false; + + /// + /// Determines if FT1248 mode uses flow control + /// + public bool FT1248FlowControl = false; + + /// + /// Determines if the VCP driver is loaded + /// + public bool IsVCP = true; + + /// + /// For self-powered designs, keeps the FT232H in low power state until ACBUS7 is high + /// + public bool PowerSaveEnable = false; + +} diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/EEPROM_STRUCTURES/FT232R_EEPROM_STRUCTURE.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/EEPROM_STRUCTURES/FT232R_EEPROM_STRUCTURE.cs new file mode 100644 index 0000000000..11c9f017a5 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/EEPROM_STRUCTURES/FT232R_EEPROM_STRUCTURE.cs @@ -0,0 +1,119 @@ +namespace FTD2XX; + +/// +/// EEPROM structure specific to FT232R and FT245R devices. +/// Inherits from FT_EEPROM_DATA. +/// +internal class FT232R_EEPROM_STRUCTURE : FT_EEPROM_DATA +{ + /// + /// Disables the FT232R internal clock source. + /// If the device has external oscillator enabled it must have an external oscillator fitted to function + /// + public bool UseExtOsc = false; + + /// + /// Enables high current IOs + /// + public bool HighDriveIOs = false; + + /// + /// Sets the endpoint size. This should always be set to 64 + /// + public byte EndpointSize = 64; + + /// + /// Determines if IOs are pulled down when the device is in suspend + /// + public bool PullDownEnable = false; + + /// + /// Determines if the serial number is enabled + /// + public bool SerNumEnable = true; + + /// + /// Inverts the sense of the TXD line + /// + public bool InvertTXD = false; + + /// + /// Inverts the sense of the RXD line + /// + public bool InvertRXD = false; + + /// + /// Inverts the sense of the RTS line + /// + public bool InvertRTS = false; + + /// + /// Inverts the sense of the CTS line + /// + public bool InvertCTS = false; + + /// + /// Inverts the sense of the DTR line + /// + public bool InvertDTR = false; + + /// + /// Inverts the sense of the DSR line + /// + public bool InvertDSR = false; + + /// + /// Inverts the sense of the DCD line + /// + public bool InvertDCD = false; + + /// + /// Inverts the sense of the RI line + /// + public bool InvertRI = false; + + /// + /// Sets the function of the CBUS0 pin for FT232R devices. + /// Valid values are FT_CBUS_TXDEN, FT_CBUS_PWRON , FT_CBUS_RXLED, FT_CBUS_TXLED, + /// FT_CBUS_TXRXLED, FT_CBUS_SLEEP, FT_CBUS_CLK48, FT_CBUS_CLK24, FT_CBUS_CLK12, + /// FT_CBUS_CLK6, FT_CBUS_IOMODE, FT_CBUS_BITBANG_WR, FT_CBUS_BITBANG_RD + /// + public byte Cbus0 = FT_CBUS_OPTIONS.FT_CBUS_SLEEP; + + /// + /// Sets the function of the CBUS1 pin for FT232R devices. + /// Valid values are FT_CBUS_TXDEN, FT_CBUS_PWRON , FT_CBUS_RXLED, FT_CBUS_TXLED, + /// FT_CBUS_TXRXLED, FT_CBUS_SLEEP, FT_CBUS_CLK48, FT_CBUS_CLK24, FT_CBUS_CLK12, + /// FT_CBUS_CLK6, FT_CBUS_IOMODE, FT_CBUS_BITBANG_WR, FT_CBUS_BITBANG_RD + /// + public byte Cbus1 = FT_CBUS_OPTIONS.FT_CBUS_SLEEP; + + /// + /// Sets the function of the CBUS2 pin for FT232R devices. + /// Valid values are FT_CBUS_TXDEN, FT_CBUS_PWRON , FT_CBUS_RXLED, FT_CBUS_TXLED, + /// FT_CBUS_TXRXLED, FT_CBUS_SLEEP, FT_CBUS_CLK48, FT_CBUS_CLK24, FT_CBUS_CLK12, + /// FT_CBUS_CLK6, FT_CBUS_IOMODE, FT_CBUS_BITBANG_WR, FT_CBUS_BITBANG_RD + /// + public byte Cbus2 = FT_CBUS_OPTIONS.FT_CBUS_SLEEP; + + /// + /// Sets the function of the CBUS3 pin for FT232R devices. + /// Valid values are FT_CBUS_TXDEN, FT_CBUS_PWRON , FT_CBUS_RXLED, FT_CBUS_TXLED, + /// FT_CBUS_TXRXLED, FT_CBUS_SLEEP, FT_CBUS_CLK48, FT_CBUS_CLK24, FT_CBUS_CLK12, + /// FT_CBUS_CLK6, FT_CBUS_IOMODE, FT_CBUS_BITBANG_WR, FT_CBUS_BITBANG_RD + /// + public byte Cbus3 = FT_CBUS_OPTIONS.FT_CBUS_SLEEP; + + /// + /// Sets the function of the CBUS4 pin for FT232R devices. + /// Valid values are FT_CBUS_TXDEN, FT_CBUS_PWRON , FT_CBUS_RXLED, FT_CBUS_TXLED, + /// FT_CBUS_TXRXLED, FT_CBUS_SLEEP, FT_CBUS_CLK48, FT_CBUS_CLK24, FT_CBUS_CLK12, + /// FT_CBUS_CLK6 + /// + public byte Cbus4 = FT_CBUS_OPTIONS.FT_CBUS_SLEEP; + + /// + /// Determines if the VCP driver is loaded + /// + public bool RIsD2XX = false; +} \ No newline at end of file diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/EEPROM_STRUCTURES/FT4232H_EEPROM_STRUCTURE.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/EEPROM_STRUCTURES/FT4232H_EEPROM_STRUCTURE.cs new file mode 100644 index 0000000000..c69ce3883b --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/EEPROM_STRUCTURES/FT4232H_EEPROM_STRUCTURE.cs @@ -0,0 +1,118 @@ +namespace FTD2XX; + +/// +/// EEPROM structure specific to FT4232H devices. +/// Inherits from FT_EEPROM_DATA. +/// +internal class FT4232H_EEPROM_STRUCTURE : FT_EEPROM_DATA +{ + /// + /// Determines if IOs are pulled down when the device is in suspend + /// + public bool PullDownEnable = false; + + /// + /// Determines if the serial number is enabled + /// + public bool SerNumEnable = true; + + /// + /// Determines if A pins have a slow slew rate + /// + public bool ASlowSlew = false; + + /// + /// Determines if the A pins have a Schmitt input + /// + public bool ASchmittInput = false; + + /// + /// Determines the A pins drive current in mA. Valid values are FT_DRIVE_CURRENT_4MA, FT_DRIVE_CURRENT_8MA, FT_DRIVE_CURRENT_12MA or FT_DRIVE_CURRENT_16MA + /// + public byte ADriveCurrent = FT_DRIVE_CURRENT.FT_DRIVE_CURRENT_4MA; + + /// + /// Determines if B pins have a slow slew rate + /// + public bool BSlowSlew = false; + + /// + /// Determines if the B pins have a Schmitt input + /// + public bool BSchmittInput = false; + + /// + /// Determines the B pins drive current in mA. Valid values are FT_DRIVE_CURRENT_4MA, FT_DRIVE_CURRENT_8MA, FT_DRIVE_CURRENT_12MA or FT_DRIVE_CURRENT_16MA + /// + public byte BDriveCurrent = FT_DRIVE_CURRENT.FT_DRIVE_CURRENT_4MA; + + /// + /// Determines if C pins have a slow slew rate + /// + public bool CSlowSlew = false; + + /// + /// Determines if the C pins have a Schmitt input + /// + public bool CSchmittInput = false; + + /// + /// Determines the C pins drive current in mA. Valid values are FT_DRIVE_CURRENT_4MA, FT_DRIVE_CURRENT_8MA, FT_DRIVE_CURRENT_12MA or FT_DRIVE_CURRENT_16MA + /// + public byte CDriveCurrent = FT_DRIVE_CURRENT.FT_DRIVE_CURRENT_4MA; + + /// + /// Determines if D pins have a slow slew rate + /// + public bool DSlowSlew = false; + + /// + /// Determines if the D pins have a Schmitt input + /// + public bool DSchmittInput = false; + + /// + /// Determines the D pins drive current in mA. Valid values are FT_DRIVE_CURRENT_4MA, FT_DRIVE_CURRENT_8MA, FT_DRIVE_CURRENT_12MA or FT_DRIVE_CURRENT_16MA + /// + public byte DDriveCurrent = FT_DRIVE_CURRENT.FT_DRIVE_CURRENT_4MA; + + /// + /// RI of port A acts as RS485 transmit enable (TXDEN) + /// + public bool ARIIsTXDEN = false; + + /// + /// RI of port B acts as RS485 transmit enable (TXDEN) + /// + public bool BRIIsTXDEN = false; + + /// + /// RI of port C acts as RS485 transmit enable (TXDEN) + /// + public bool CRIIsTXDEN = false; + + /// + /// RI of port D acts as RS485 transmit enable (TXDEN) + /// + public bool DRIIsTXDEN = false; + + /// + /// Determines if channel A loads the VCP driver + /// + public bool AIsVCP = true; + + /// + /// Determines if channel B loads the VCP driver + /// + public bool BIsVCP = true; + + /// + /// Determines if channel C loads the VCP driver + /// + public bool CIsVCP = true; + + /// + /// Determines if channel D loads the VCP driver + /// + public bool DIsVCP = true; +} diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/EEPROM_STRUCTURES/FTX_EEPROM_STRUCTURE.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/EEPROM_STRUCTURES/FTX_EEPROM_STRUCTURE.cs new file mode 100644 index 0000000000..754f79737d --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/EEPROM_STRUCTURES/FTX_EEPROM_STRUCTURE.cs @@ -0,0 +1,221 @@ +namespace FTD2XX; + +/// +/// EEPROM structure specific to X-Series devices. +/// Inherits from FT_EEPROM_DATA. +/// +internal class FTX_EEPROM_STRUCTURE : FT_EEPROM_DATA +{ + /// + /// Determines if IOs are pulled down when the device is in suspend + /// + public bool PullDownEnable = false; + + /// + /// Determines if the serial number is enabled + /// + public bool SerNumEnable = true; + + /// + /// Determines if the USB version number is enabled + /// + public bool USBVersionEnable = true; + + /// + /// The USB version number: 0x0200 (USB 2.0) + /// + public ushort USBVersion = 0x0200; + + /// + /// Determines if AC pins have a slow slew rate + /// + public byte ACSlowSlew; + + /// + /// Determines if the AC pins have a Schmitt input + /// + public byte ACSchmittInput; + + /// + /// Determines the AC pins drive current in mA. Valid values are FT_DRIVE_CURRENT_4MA, FT_DRIVE_CURRENT_8MA, FT_DRIVE_CURRENT_12MA or FT_DRIVE_CURRENT_16MA + /// + public byte ACDriveCurrent; + + /// + /// Determines if AD pins have a slow slew rate + /// + public byte ADSlowSlew; + + /// + /// Determines if AD pins have a schmitt input + /// + public byte ADSchmittInput; + + /// + /// Determines the AD pins drive current in mA. Valid values are FT_DRIVE_CURRENT_4MA, FT_DRIVE_CURRENT_8MA, FT_DRIVE_CURRENT_12MA or FT_DRIVE_CURRENT_16MA + /// + public byte ADDriveCurrent; + + /// + /// Sets the function of the CBUS0 pin for FT232H devices. + /// Valid values are FT_CBUS_TRISTATE, FT_CBUS_RXLED, FT_CBUS_TXLED, FT_CBUS_TXRXLED, + /// FT_CBUS_PWREN, FT_CBUS_SLEEP, FT_CBUS_DRIVE_0, FT_CBUS_DRIVE_1, FT_CBUS_GPIO, FT_CBUS_TXDEN, FT_CBUS_CLK24, + /// FT_CBUS_CLK12, FT_CBUS_CLK6, FT_CBUS_BCD_CHARGER, FT_CBUS_BCD_CHARGER_N, FT_CBUS_VBUS_SENSE, FT_CBUS_BITBANG_WR, + /// FT_CBUS_BITBANG_RD, FT_CBUS_TIME_STAMP, FT_CBUS_KEEP_AWAKE + /// + public byte Cbus0; + + /// + /// Sets the function of the CBUS1 pin for FT232H devices. + /// Valid values are FT_CBUS_TRISTATE, FT_CBUS_RXLED, FT_CBUS_TXLED, FT_CBUS_TXRXLED, + /// FT_CBUS_PWREN, FT_CBUS_SLEEP, FT_CBUS_DRIVE_0, FT_CBUS_DRIVE_1, FT_CBUS_GPIO, FT_CBUS_TXDEN, FT_CBUS_CLK24, + /// FT_CBUS_CLK12, FT_CBUS_CLK6, FT_CBUS_BCD_CHARGER, FT_CBUS_BCD_CHARGER_N, FT_CBUS_VBUS_SENSE, FT_CBUS_BITBANG_WR, + /// FT_CBUS_BITBANG_RD, FT_CBUS_TIME_STAMP, FT_CBUS_KEEP_AWAKE + /// + public byte Cbus1; + + /// + /// Sets the function of the CBUS2 pin for FT232H devices. + /// Valid values are FT_CBUS_TRISTATE, FT_CBUS_RXLED, FT_CBUS_TXLED, FT_CBUS_TXRXLED, + /// FT_CBUS_PWREN, FT_CBUS_SLEEP, FT_CBUS_DRIVE_0, FT_CBUS_DRIVE_1, FT_CBUS_GPIO, FT_CBUS_TXDEN, FT_CBUS_CLK24, + /// FT_CBUS_CLK12, FT_CBUS_CLK6, FT_CBUS_BCD_CHARGER, FT_CBUS_BCD_CHARGER_N, FT_CBUS_VBUS_SENSE, FT_CBUS_BITBANG_WR, + /// FT_CBUS_BITBANG_RD, FT_CBUS_TIME_STAMP, FT_CBUS_KEEP_AWAKE + /// + public byte Cbus2; + + /// + /// Sets the function of the CBUS3 pin for FT232H devices. + /// Valid values are FT_CBUS_TRISTATE, FT_CBUS_RXLED, FT_CBUS_TXLED, FT_CBUS_TXRXLED, + /// FT_CBUS_PWREN, FT_CBUS_SLEEP, FT_CBUS_DRIVE_0, FT_CBUS_DRIVE_1, FT_CBUS_GPIO, FT_CBUS_TXDEN, FT_CBUS_CLK24, + /// FT_CBUS_CLK12, FT_CBUS_CLK6, FT_CBUS_BCD_CHARGER, FT_CBUS_BCD_CHARGER_N, FT_CBUS_VBUS_SENSE, FT_CBUS_BITBANG_WR, + /// FT_CBUS_BITBANG_RD, FT_CBUS_TIME_STAMP, FT_CBUS_KEEP_AWAKE + /// + public byte Cbus3; + + /// + /// Sets the function of the CBUS4 pin for FT232H devices. + /// Valid values are FT_CBUS_TRISTATE, FT_CBUS_RXLED, FT_CBUS_TXLED, FT_CBUS_TXRXLED, + /// FT_CBUS_PWREN, FT_CBUS_SLEEP, FT_CBUS_DRIVE_0, FT_CBUS_DRIVE_1, FT_CBUS_TXDEN, FT_CBUS_CLK24, + /// FT_CBUS_CLK12, FT_CBUS_CLK6, FT_CBUS_BCD_CHARGER, FT_CBUS_BCD_CHARGER_N, FT_CBUS_VBUS_SENSE, FT_CBUS_BITBANG_WR, + /// FT_CBUS_BITBANG_RD, FT_CBUS_TIME_STAMP, FT_CBUS_KEEP_AWAKE + /// + public byte Cbus4; + + /// + /// Sets the function of the CBUS5 pin for FT232H devices. + /// Valid values are FT_CBUS_TRISTATE, FT_CBUS_RXLED, FT_CBUS_TXLED, FT_CBUS_TXRXLED, + /// FT_CBUS_PWREN, FT_CBUS_SLEEP, FT_CBUS_DRIVE_0, FT_CBUS_DRIVE_1, FT_CBUS_TXDEN, FT_CBUS_CLK24, + /// FT_CBUS_CLK12, FT_CBUS_CLK6, FT_CBUS_BCD_CHARGER, FT_CBUS_BCD_CHARGER_N, FT_CBUS_VBUS_SENSE, FT_CBUS_BITBANG_WR, + /// FT_CBUS_BITBANG_RD, FT_CBUS_TIME_STAMP, FT_CBUS_KEEP_AWAKE + /// + public byte Cbus5; + + /// + /// Sets the function of the CBUS6 pin for FT232H devices. + /// Valid values are FT_CBUS_TRISTATE, FT_CBUS_RXLED, FT_CBUS_TXLED, FT_CBUS_TXRXLED, + /// FT_CBUS_PWREN, FT_CBUS_SLEEP, FT_CBUS_DRIVE_0, FT_CBUS_DRIVE_1, FT_CBUS_TXDEN, FT_CBUS_CLK24, + /// FT_CBUS_CLK12, FT_CBUS_CLK6, FT_CBUS_BCD_CHARGER, FT_CBUS_BCD_CHARGER_N, FT_CBUS_VBUS_SENSE, FT_CBUS_BITBANG_WR, + /// FT_CBUS_BITBANG_RD, FT_CBUS_TIME_STAMP, FT_CBUS_KEEP_AWAKE + /// + public byte Cbus6; + + /// + /// Inverts the sense of the TXD line + /// + public byte InvertTXD; + + /// + /// Inverts the sense of the RXD line + /// + public byte InvertRXD; + + /// + /// Inverts the sense of the RTS line + /// + public byte InvertRTS; + + /// + /// Inverts the sense of the CTS line + /// + public byte InvertCTS; + + /// + /// Inverts the sense of the DTR line + /// + public byte InvertDTR; + + /// + /// Inverts the sense of the DSR line + /// + public byte InvertDSR; + + /// + /// Inverts the sense of the DCD line + /// + public byte InvertDCD; + + /// + /// Inverts the sense of the RI line + /// + public byte InvertRI; + + /// + /// Determines whether the Battery Charge Detection option is enabled. + /// + public byte BCDEnable; + + /// + /// Asserts the power enable signal on CBUS when charging port detected. + /// + public byte BCDForceCbusPWREN; + + /// + /// Forces the device never to go into sleep mode. + /// + public byte BCDDisableSleep; + + /// + /// I2C slave device address. + /// + public short I2CSlaveAddress; + + /// + /// I2C device ID + /// + public int I2CDeviceId; + + /// + /// Disable I2C Schmitt trigger. + /// + public byte I2CDisableSchmitt; + + /// + /// FT1248 clock polarity - clock idle high (1) or clock idle low (0) + /// + public byte FT1248Cpol; + + /// + /// FT1248 data is LSB (1) or MSB (0) + /// + public byte FT1248Lsb; + + /// + /// FT1248 flow control enable. + /// + public byte FT1248FlowControl; + + /// + /// Enable RS485 Echo Suppression + /// + public byte RS485EchoSuppress; + + /// + /// Enable Power Save mode. + /// + public byte PowerSaveEnable; + + /// + /// Determines whether the VCP driver is loaded. + /// + public byte IsVCP; +} \ No newline at end of file diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FTDI.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FTDI.cs new file mode 100644 index 0000000000..f987bc3c9a --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FTDI.cs @@ -0,0 +1,4481 @@ +/* + * Original Filename: FTD2XX_NET.cs + * Original Copyright: 2009-2021 Future Technology Devices International Limited + * Original Version: 1.1.2 (https://github.com/swharden/FtdiSharp/blob/main/dev/FTD2XX_NET/FTD2XX_NET.cs) + * Original License: MIT + * + * Scott Harden modified the original code to spread it across several files, + * use more idiomatic C# and modern language features, and overall make it easier to learn from. + * https://github.com/swharden/FtdiSharp + * + * Wilderness Labs did some clean-up to make it match our standardized C# formatting + */ + +using Meadow.Foundation.ICs.IOExpanders; +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; + +namespace FTD2XX; + +internal class FTDI +{ + #region CONSTRUCTOR_DESTRUCTOR + // constructor + /// + /// Constructor for the FTDI class. + /// + public FTDI() + { + // If FTD2XX.DLL is NOT loaded already, load it + if (hFTD2XXDLL == IntPtr.Zero) + { + // Load our FTD2XX.DLL library + hFTD2XXDLL = LoadLibrary(@"FTD2XX.DLL"); + if (hFTD2XXDLL == IntPtr.Zero) + { + // Failed to load our FTD2XX.DLL library from System32 or the application directory + // Try the same directory that this FTD2XX_NET DLL is in + ErrorMessageAction("Attempting to load FTD2XX.DLL from:\n" + Path.GetDirectoryName(GetType().Assembly.Location)); + hFTD2XXDLL = LoadLibrary(@Path.GetDirectoryName(GetType().Assembly.Location) + "\\FTD2XX.DLL"); + } + } + + // If we have succesfully loaded the library, get the function pointers set up + if (hFTD2XXDLL != IntPtr.Zero) + { + FindFunctionPointers(); + } + else + { + // Failed to load our DLL - alert the user + ErrorMessageAction("Failed to load FTD2XX.DLL. Are the FTDI drivers installed?"); + } + } + + /// + /// Non default constructor allowing passing of string for dll handle. + /// + public FTDI(string dllFilePath) + { + // If nonstandard.DLL is NOT loaded already, load it + if (string.IsNullOrWhiteSpace(dllFilePath)) + { + return; + } + + if (hFTD2XXDLL == IntPtr.Zero) + { + // Load our nonstandard.DLL library + hFTD2XXDLL = LoadLibrary(dllFilePath); + if (hFTD2XXDLL == IntPtr.Zero) + { + // Failed to load our PathToDll library + // Give up :( + ErrorMessageAction("Attempting to load FTD2XX.DLL from:\n" + Path.GetDirectoryName(GetType().Assembly.Location)); + } + } + + // If we have succesfully loaded the library, get the function pointers set up + if (hFTD2XXDLL != IntPtr.Zero) + { + FindFunctionPointers(); + } + else + { + ErrorMessageAction("Failed to load FTD2XX.DLL. Are the FTDI drivers installed?"); + } + } + + private void FindFunctionPointers() + { + // Set up our function pointers for use through our exported methods + pFT_CreateDeviceInfoList = GetProcAddress(hFTD2XXDLL, "FT_CreateDeviceInfoList"); + pFT_GetDeviceInfoDetail = GetProcAddress(hFTD2XXDLL, "FT_GetDeviceInfoDetail"); + pFT_OpenEx = GetProcAddress(hFTD2XXDLL, "FT_OpenEx"); + pFT_Close = GetProcAddress(hFTD2XXDLL, "FT_Close"); + pFT_Read = GetProcAddress(hFTD2XXDLL, "FT_Read"); + pFT_Write = GetProcAddress(hFTD2XXDLL, "FT_Write"); + pFT_GetQueueStatus = GetProcAddress(hFTD2XXDLL, "FT_GetQueueStatus"); + pFT_GetModemStatus = GetProcAddress(hFTD2XXDLL, "FT_GetModemStatus"); + pFT_GetStatus = GetProcAddress(hFTD2XXDLL, "FT_GetStatus"); + pFT_SetBaudRate = GetProcAddress(hFTD2XXDLL, "FT_SetBaudRate"); + pFT_SetDataCharacteristics = GetProcAddress(hFTD2XXDLL, "FT_SetDataCharacteristics"); + pFT_SetFlowControl = GetProcAddress(hFTD2XXDLL, "FT_SetFlowControl"); + pFT_SetDtr = GetProcAddress(hFTD2XXDLL, "FT_SetDtr"); + pFT_ClrDtr = GetProcAddress(hFTD2XXDLL, "FT_ClrDtr"); + pFT_SetRts = GetProcAddress(hFTD2XXDLL, "FT_SetRts"); + pFT_ClrRts = GetProcAddress(hFTD2XXDLL, "FT_ClrRts"); + pFT_ResetDevice = GetProcAddress(hFTD2XXDLL, "FT_ResetDevice"); + pFT_ResetPort = GetProcAddress(hFTD2XXDLL, "FT_ResetPort"); + pFT_CyclePort = GetProcAddress(hFTD2XXDLL, "FT_CyclePort"); + pFT_Rescan = GetProcAddress(hFTD2XXDLL, "FT_Rescan"); + pFT_Reload = GetProcAddress(hFTD2XXDLL, "FT_Reload"); + pFT_Purge = GetProcAddress(hFTD2XXDLL, "FT_Purge"); + pFT_SetTimeouts = GetProcAddress(hFTD2XXDLL, "FT_SetTimeouts"); + pFT_SetBreakOn = GetProcAddress(hFTD2XXDLL, "FT_SetBreakOn"); + pFT_SetBreakOff = GetProcAddress(hFTD2XXDLL, "FT_SetBreakOff"); + pFT_GetDeviceInfo = GetProcAddress(hFTD2XXDLL, "FT_GetDeviceInfo"); + pFT_SetResetPipeRetryCount = GetProcAddress(hFTD2XXDLL, "FT_SetResetPipeRetryCount"); + pFT_StopInTask = GetProcAddress(hFTD2XXDLL, "FT_StopInTask"); + pFT_RestartInTask = GetProcAddress(hFTD2XXDLL, "FT_RestartInTask"); + pFT_GetDriverVersion = GetProcAddress(hFTD2XXDLL, "FT_GetDriverVersion"); + pFT_GetLibraryVersion = GetProcAddress(hFTD2XXDLL, "FT_GetLibraryVersion"); + pFT_SetDeadmanTimeout = GetProcAddress(hFTD2XXDLL, "FT_SetDeadmanTimeout"); + pFT_SetChars = GetProcAddress(hFTD2XXDLL, "FT_SetChars"); + pFT_SetEventNotification = GetProcAddress(hFTD2XXDLL, "FT_SetEventNotification"); + pFT_GetComPortNumber = GetProcAddress(hFTD2XXDLL, "FT_GetComPortNumber"); + pFT_SetLatencyTimer = GetProcAddress(hFTD2XXDLL, "FT_SetLatencyTimer"); + pFT_GetLatencyTimer = GetProcAddress(hFTD2XXDLL, "FT_GetLatencyTimer"); + pFT_SetBitMode = GetProcAddress(hFTD2XXDLL, "FT_SetBitMode"); + pFT_GetBitMode = GetProcAddress(hFTD2XXDLL, "FT_GetBitMode"); + pFT_SetUSBParameters = GetProcAddress(hFTD2XXDLL, "FT_SetUSBParameters"); + pFT_ReadEE = GetProcAddress(hFTD2XXDLL, "FT_ReadEE"); + pFT_WriteEE = GetProcAddress(hFTD2XXDLL, "FT_WriteEE"); + pFT_EraseEE = GetProcAddress(hFTD2XXDLL, "FT_EraseEE"); + pFT_EE_UASize = GetProcAddress(hFTD2XXDLL, "FT_EE_UASize"); + pFT_EE_UARead = GetProcAddress(hFTD2XXDLL, "FT_EE_UARead"); + pFT_EE_UAWrite = GetProcAddress(hFTD2XXDLL, "FT_EE_UAWrite"); + pFT_EE_Read = GetProcAddress(hFTD2XXDLL, "FT_EE_Read"); + pFT_EE_Program = GetProcAddress(hFTD2XXDLL, "FT_EE_Program"); + pFT_EEPROM_Read = GetProcAddress(hFTD2XXDLL, "FT_EEPROM_Read"); + pFT_EEPROM_Program = GetProcAddress(hFTD2XXDLL, "FT_EEPROM_Program"); + pFT_VendorCmdGet = GetProcAddress(hFTD2XXDLL, "FT_VendorCmdGet"); + pFT_VendorCmdSet = GetProcAddress(hFTD2XXDLL, "FT_VendorCmdSet"); + pFT_VendorCmdSetX = GetProcAddress(hFTD2XXDLL, "FT_VendorCmdSetX"); + } + + /// + /// Destructor for the FTDI class. + /// + ~FTDI() + { + // FreeLibrary here - we should only do this if we are completely finished + FreeLibrary(hFTD2XXDLL); + hFTD2XXDLL = IntPtr.Zero; + } + #endregion + + #region LOAD_LIBRARIES + /// + /// Built-in Windows API functions to allow us to dynamically load our own DLL. + /// Will allow us to use old versions of the DLL that do not have all of these functions available. + /// + [DllImport("kernel32.dll")] + private static extern IntPtr LoadLibrary(string dllToLoad); + [DllImport("kernel32.dll")] + private static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName); + [DllImport("kernel32.dll")] + private static extern bool FreeLibrary(IntPtr hModule); + #endregion + + #region DELEGATES + // Definitions for FTD2XX functions + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_CreateDeviceInfoList(ref int numdevs); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_GetDeviceInfoDetail(int index, ref int flags, ref FT_DEVICE chiptype, ref int id, ref int locid, byte[] serialnumber, byte[] description, ref IntPtr ftHandle); + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_OpenEx(string devstring, int dwFlags, ref IntPtr ftHandle); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_OpenExLoc(int devloc, int dwFlags, ref IntPtr ftHandle); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_Close(IntPtr ftHandle); + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_Read(IntPtr ftHandle, byte[] lpBuffer, int dwBytesToRead, ref int lpdwBytesReturned); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_Write(IntPtr ftHandle, byte[] lpBuffer, int dwBytesToWrite, ref int lpdwBytesWritten); + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_GetQueueStatus(IntPtr ftHandle, ref int lpdwAmountInRxQueue); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_GetModemStatus(IntPtr ftHandle, ref int lpdwModemStatus); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_GetStatus(IntPtr ftHandle, ref int lpdwAmountInRxQueue, ref int lpdwAmountInTxQueue, ref int lpdwEventStatus); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_SetBaudRate(IntPtr ftHandle, int dwBaudRate); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_SetDataCharacteristics(IntPtr ftHandle, byte uWordLength, byte uStopBits, byte uParity); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_SetFlowControl(IntPtr ftHandle, short usFlowControl, byte uXon, byte uXoff); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_SetDtr(IntPtr ftHandle); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_ClrDtr(IntPtr ftHandle); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_SetRts(IntPtr ftHandle); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_ClrRts(IntPtr ftHandle); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_ResetDevice(IntPtr ftHandle); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_ResetPort(IntPtr ftHandle); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_CyclePort(IntPtr ftHandle); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_Rescan(); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_Reload(short wVID, short wPID); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_Purge(IntPtr ftHandle, int dwMask); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_SetTimeouts(IntPtr ftHandle, int dwReadTimeout, int dwWriteTimeout); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_SetBreakOn(IntPtr ftHandle); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_SetBreakOff(IntPtr ftHandle); + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_GetDeviceInfo(IntPtr ftHandle, ref FT_DEVICE pftType, ref int lpdwID, byte[] pcSerialNumber, byte[] pcDescription, IntPtr pvDummy); + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_SetResetPipeRetryCount(IntPtr ftHandle, int dwCount); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_StopInTask(IntPtr ftHandle); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_RestartInTask(IntPtr ftHandle); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_GetDriverVersion(IntPtr ftHandle, ref int lpdwDriverVersion); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_GetLibraryVersion(ref int lpdwLibraryVersion); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_SetDeadmanTimeout(IntPtr ftHandle, int dwDeadmanTimeout); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_SetChars(IntPtr ftHandle, byte uEventCh, byte uEventChEn, byte uErrorCh, byte uErrorChEn); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_SetEventNotification(IntPtr ftHandle, int dwEventMask, SafeHandle hEvent); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_GetComPortNumber(IntPtr ftHandle, ref int dwComPortNumber); + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_SetLatencyTimer(IntPtr ftHandle, byte ucLatency); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_GetLatencyTimer(IntPtr ftHandle, ref byte ucLatency); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_SetBitMode(IntPtr ftHandle, byte ucMask, byte ucMode); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_GetBitMode(IntPtr ftHandle, ref byte ucMode); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_SetUSBParameters(IntPtr ftHandle, int dwInTransferSize, int dwOutTransferSize); + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_ReadEE(IntPtr ftHandle, int dwWordOffset, ref short lpwValue); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_WriteEE(IntPtr ftHandle, int dwWordOffset, short wValue); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_EraseEE(IntPtr ftHandle); + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_EE_UASize(IntPtr ftHandle, ref int dwSize); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_EE_UARead(IntPtr ftHandle, byte[] pucData, int dwDataLen, ref int lpdwDataRead); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_EE_UAWrite(IntPtr ftHandle, byte[] pucData, int dwDataLen); + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_EE_Read(IntPtr ftHandle, FT_PROGRAM_DATA pData); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_EE_Program(IntPtr ftHandle, FT_PROGRAM_DATA pData); + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_EEPROM_Read(IntPtr ftHandle, IntPtr eepromData, int eepromDataSize, byte[] manufacturer, byte[] manufacturerID, byte[] description, byte[] serialnumber); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_EEPROM_Program(IntPtr ftHandle, IntPtr eepromData, int eepromDataSize, byte[] manufacturer, byte[] manufacturerID, byte[] description, byte[] serialnumber); + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_VendorCmdGet(IntPtr ftHandle, short request, byte[] buf, short len); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_VendorCmdSet(IntPtr ftHandle, short request, byte[] buf, short len); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate FT_STATUS tFT_VendorCmdSetX(IntPtr ftHandle, short request, byte[] buf, short len); + + #endregion + + #region VARIABLES + // Create private variables for the device within the class + private IntPtr _ftHandle = IntPtr.Zero; + #endregion + + #region FUNCTION_IMPORTS_FTD2XX.DLL + // Handle to our DLL - used with GetProcAddress to load all of our functions + private IntPtr hFTD2XXDLL = IntPtr.Zero; + + // Declare pointers to each of the functions we are going to use in FT2DXX.DLL + // These are assigned in our constructor and freed in our destructor. + private IntPtr pFT_CreateDeviceInfoList = IntPtr.Zero; + private IntPtr pFT_GetDeviceInfoDetail = IntPtr.Zero; + private IntPtr pFT_Open = IntPtr.Zero; + private IntPtr pFT_OpenEx = IntPtr.Zero; + private IntPtr pFT_Close = IntPtr.Zero; + private IntPtr pFT_Read = IntPtr.Zero; + private IntPtr pFT_Write = IntPtr.Zero; + private IntPtr pFT_GetQueueStatus = IntPtr.Zero; + private IntPtr pFT_GetModemStatus = IntPtr.Zero; + private IntPtr pFT_GetStatus = IntPtr.Zero; + private IntPtr pFT_SetBaudRate = IntPtr.Zero; + private IntPtr pFT_SetDataCharacteristics = IntPtr.Zero; + private IntPtr pFT_SetFlowControl = IntPtr.Zero; + private IntPtr pFT_SetDtr = IntPtr.Zero; + private IntPtr pFT_ClrDtr = IntPtr.Zero; + private IntPtr pFT_SetRts = IntPtr.Zero; + private IntPtr pFT_ClrRts = IntPtr.Zero; + private IntPtr pFT_ResetDevice = IntPtr.Zero; + private IntPtr pFT_ResetPort = IntPtr.Zero; + private IntPtr pFT_CyclePort = IntPtr.Zero; + private IntPtr pFT_Rescan = IntPtr.Zero; + private IntPtr pFT_Reload = IntPtr.Zero; + private IntPtr pFT_Purge = IntPtr.Zero; + private IntPtr pFT_SetTimeouts = IntPtr.Zero; + private IntPtr pFT_SetBreakOn = IntPtr.Zero; + private IntPtr pFT_SetBreakOff = IntPtr.Zero; + private IntPtr pFT_GetDeviceInfo = IntPtr.Zero; + private IntPtr pFT_SetResetPipeRetryCount = IntPtr.Zero; + private IntPtr pFT_StopInTask = IntPtr.Zero; + private IntPtr pFT_RestartInTask = IntPtr.Zero; + private IntPtr pFT_GetDriverVersion = IntPtr.Zero; + private IntPtr pFT_GetLibraryVersion = IntPtr.Zero; + private IntPtr pFT_SetDeadmanTimeout = IntPtr.Zero; + private IntPtr pFT_SetChars = IntPtr.Zero; + private IntPtr pFT_SetEventNotification = IntPtr.Zero; + private IntPtr pFT_GetComPortNumber = IntPtr.Zero; + private IntPtr pFT_SetLatencyTimer = IntPtr.Zero; + private IntPtr pFT_GetLatencyTimer = IntPtr.Zero; + private IntPtr pFT_SetBitMode = IntPtr.Zero; + private IntPtr pFT_GetBitMode = IntPtr.Zero; + private IntPtr pFT_SetUSBParameters = IntPtr.Zero; + private IntPtr pFT_ReadEE = IntPtr.Zero; + private IntPtr pFT_WriteEE = IntPtr.Zero; + private IntPtr pFT_EraseEE = IntPtr.Zero; + private IntPtr pFT_EE_UASize = IntPtr.Zero; + private IntPtr pFT_EE_UARead = IntPtr.Zero; + private IntPtr pFT_EE_UAWrite = IntPtr.Zero; + private IntPtr pFT_EE_Read = IntPtr.Zero; + private IntPtr pFT_EE_Program = IntPtr.Zero; + private IntPtr pFT_EEPROM_Read = IntPtr.Zero; + private IntPtr pFT_EEPROM_Program = IntPtr.Zero; + private IntPtr pFT_VendorCmdGet = IntPtr.Zero; + private IntPtr pFT_VendorCmdSet = IntPtr.Zero; + private IntPtr pFT_VendorCmdSetX = IntPtr.Zero; + #endregion + + /// + /// Gets the number of FTDI devices available. + /// + /// FT_STATUS value from FT_CreateDeviceInfoList in FTD2XX.DLL + /// The number of FTDI devices available. + public FT_STATUS GetNumberOfDevices(ref int devcount) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + { + return ftStatus; + } + + // Check for our required function pointers being set up + if (pFT_CreateDeviceInfoList != IntPtr.Zero) + { + tFT_CreateDeviceInfoList FT_CreateDeviceInfoList = (tFT_CreateDeviceInfoList)Marshal.GetDelegateForFunctionPointer(pFT_CreateDeviceInfoList, typeof(tFT_CreateDeviceInfoList)); + + // Call FT_CreateDeviceInfoList + ftStatus = FT_CreateDeviceInfoList(ref devcount); + } + else + { + ErrorMessageAction("Failed to load function FT_CreateDeviceInfoList."); + } + return ftStatus; + + } + + /// + /// Gets information on all of the FTDI devices available. + /// + /// FT_STATUS value from FT_GetDeviceInfoDetail in FTD2XX.DLL + /// An array of type FT_DEVICE_INFO_NODE to contain the device information for all available devices. + /// Thrown when the supplied buffer is not large enough to contain the device info list. + public FT_STATUS GetDeviceList(FT_DEVICE_INFO_NODE[] devicelist) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + FT_ERROR ftErrorCondition = FT_ERROR.FT_NO_ERROR; + int nullIndex = 0; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if ((pFT_CreateDeviceInfoList != IntPtr.Zero) & (pFT_GetDeviceInfoDetail != IntPtr.Zero)) + { + int devcount = 0; + + tFT_CreateDeviceInfoList FT_CreateDeviceInfoList = (tFT_CreateDeviceInfoList)Marshal.GetDelegateForFunctionPointer(pFT_CreateDeviceInfoList, typeof(tFT_CreateDeviceInfoList)); + tFT_GetDeviceInfoDetail FT_GetDeviceInfoDetail = (tFT_GetDeviceInfoDetail)Marshal.GetDelegateForFunctionPointer(pFT_GetDeviceInfoDetail, typeof(tFT_GetDeviceInfoDetail)); + + // Call FT_CreateDeviceInfoList + ftStatus = FT_CreateDeviceInfoList(ref devcount); + + // Allocate the required storage for our list + + byte[] sernum = new byte[16]; + byte[] desc = new byte[64]; + + if (devcount > 0) + { + // Check the size of the buffer passed in is big enough + if (devicelist.Length < devcount) + { + // Buffer not big enough + ftErrorCondition = FT_ERROR.FT_BUFFER_SIZE; + // Throw exception + ThrowIfNotOK(ftStatus, ftErrorCondition); + } + + // Instantiate the array elements as FT_DEVICE_INFO_NODE + for (int i = 0; i < devcount; i++) + { + devicelist[i] = new FT_DEVICE_INFO_NODE(); + // Call FT_GetDeviceInfoDetail + ftStatus = FT_GetDeviceInfoDetail(i, ref devicelist[i].Flags, ref devicelist[i].Type, ref devicelist[i].ID, ref devicelist[i].LocId, sernum, desc, ref devicelist[i].ftHandle); + // Convert byte arrays to strings + devicelist[i].SerialNumber = Encoding.ASCII.GetString(sernum); + devicelist[i].Description = Encoding.ASCII.GetString(desc); + // Trim strings to first occurrence of a null terminator character + nullIndex = devicelist[i].SerialNumber.IndexOf('\0'); + if (nullIndex != -1) + devicelist[i].SerialNumber = devicelist[i].SerialNumber.Substring(0, nullIndex); + nullIndex = devicelist[i].Description.IndexOf('\0'); + if (nullIndex != -1) + devicelist[i].Description = devicelist[i].Description.Substring(0, nullIndex); + } + } + } + else + { + if (pFT_CreateDeviceInfoList == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_CreateDeviceInfoList."); + } + if (pFT_GetDeviceInfoDetail == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_GetDeviceInfoListDetail."); + } + } + return ftStatus; + } + + /// + /// Opens the FTDI device with the specified index. + /// + /// FT_STATUS value from FT_Open in FTD2XX.DLL + /// Index of the device to open. + /// Note that this cannot be guaranteed to open a specific device. + /// Initialises the device to 8 data bits, 1 stop bit, no parity, no flow control and 9600 Baud. + public FT_STATUS OpenByIndex(int index) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + { + return ftStatus; + } + + // Check for our required function pointers being set up + if ((pFT_Open != IntPtr.Zero) & (pFT_SetDataCharacteristics != IntPtr.Zero) & (pFT_SetFlowControl != IntPtr.Zero) & (pFT_SetBaudRate != IntPtr.Zero)) + { + tFT_SetDataCharacteristics FT_SetDataCharacteristics = (tFT_SetDataCharacteristics)Marshal.GetDelegateForFunctionPointer(pFT_SetDataCharacteristics, typeof(tFT_SetDataCharacteristics)); + tFT_SetFlowControl FT_SetFlowControl = (tFT_SetFlowControl)Marshal.GetDelegateForFunctionPointer(pFT_SetFlowControl, typeof(tFT_SetFlowControl)); + tFT_SetBaudRate FT_SetBaudRate = (tFT_SetBaudRate)Marshal.GetDelegateForFunctionPointer(pFT_SetBaudRate, typeof(tFT_SetBaudRate)); + + ftStatus = (FT_STATUS)Native.Ftd2xx.FT_Open(index, out _ftHandle); + + // Appears that the handle value can be non-NULL on a fail, so set it explicitly + if (ftStatus != FT_STATUS.FT_OK) + { + _ftHandle = IntPtr.Zero; + } + + if (_ftHandle != IntPtr.Zero) + { + // Initialise port data characteristics + byte WordLength = FT_DATA_BITS.FT_BITS_8; + byte StopBits = FT_STOP_BITS.FT_STOP_BITS_1; + byte Parity = FT_PARITY.FT_PARITY_NONE; + ftStatus = FT_SetDataCharacteristics(_ftHandle, WordLength, StopBits, Parity); + + // Initialise to no flow control + short FlowControl = FT_FLOW_CONTROL.FT_FLOW_NONE; + byte Xon = 0x11; + byte Xoff = 0x13; + ftStatus = FT_SetFlowControl(_ftHandle, FlowControl, Xon, Xoff); + + // Initialise Baud rate + int BaudRate = 9600; + ftStatus = FT_SetBaudRate(_ftHandle, BaudRate); + } + } + else + { + if (pFT_Open == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_Open."); + } + if (pFT_SetDataCharacteristics == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_SetDataCharacteristics."); + } + if (pFT_SetFlowControl == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_SetFlowControl."); + } + if (pFT_SetBaudRate == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_SetBaudRate."); + } + } + return ftStatus; + } + + /// + /// Opens the FTDI device with the specified serial number. + /// + /// FT_STATUS value from FT_OpenEx in FTD2XX.DLL + /// Serial number of the device to open. + /// Initialises the device to 8 data bits, 1 stop bit, no parity, no flow control and 9600 Baud. + public FT_STATUS OpenBySerialNumber(string serialnumber) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if ((pFT_OpenEx != IntPtr.Zero) & (pFT_SetDataCharacteristics != IntPtr.Zero) & (pFT_SetFlowControl != IntPtr.Zero) & (pFT_SetBaudRate != IntPtr.Zero)) + { + tFT_OpenEx FT_OpenEx = (tFT_OpenEx)Marshal.GetDelegateForFunctionPointer(pFT_OpenEx, typeof(tFT_OpenEx)); + tFT_SetDataCharacteristics FT_SetDataCharacteristics = (tFT_SetDataCharacteristics)Marshal.GetDelegateForFunctionPointer(pFT_SetDataCharacteristics, typeof(tFT_SetDataCharacteristics)); + tFT_SetFlowControl FT_SetFlowControl = (tFT_SetFlowControl)Marshal.GetDelegateForFunctionPointer(pFT_SetFlowControl, typeof(tFT_SetFlowControl)); + tFT_SetBaudRate FT_SetBaudRate = (tFT_SetBaudRate)Marshal.GetDelegateForFunctionPointer(pFT_SetBaudRate, typeof(tFT_SetBaudRate)); + + // Call FT_OpenEx + ftStatus = FT_OpenEx(serialnumber, FT_OPEN.BY_SERIAL_NUMBER, ref _ftHandle); + + // Appears that the handle value can be non-NULL on a fail, so set it explicitly + if (ftStatus != FT_STATUS.FT_OK) + _ftHandle = IntPtr.Zero; + + if (_ftHandle != IntPtr.Zero) + { + // Initialise port data characteristics + byte WordLength = FT_DATA_BITS.FT_BITS_8; + byte StopBits = FT_STOP_BITS.FT_STOP_BITS_1; + byte Parity = FT_PARITY.FT_PARITY_NONE; + ftStatus = FT_SetDataCharacteristics(_ftHandle, WordLength, StopBits, Parity); + + // Initialise to no flow control + short FlowControl = FT_FLOW_CONTROL.FT_FLOW_NONE; + byte Xon = 0x11; + byte Xoff = 0x13; + ftStatus = FT_SetFlowControl(_ftHandle, FlowControl, Xon, Xoff); + + // Initialise Baud rate + int BaudRate = 9600; + ftStatus = FT_SetBaudRate(_ftHandle, BaudRate); + } + } + else + { + if (pFT_OpenEx == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_OpenEx."); + } + if (pFT_SetDataCharacteristics == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_SetDataCharacteristics."); + } + if (pFT_SetFlowControl == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_SetFlowControl."); + } + if (pFT_SetBaudRate == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_SetBaudRate."); + } + } + return ftStatus; + } + + /// + /// Opens the FTDI device with the specified description. + /// + /// FT_STATUS value from FT_OpenEx in FTD2XX.DLL + /// Description of the device to open. + /// Initialises the device to 8 data bits, 1 stop bit, no parity, no flow control and 9600 Baud. + public FT_STATUS OpenByDescription(string description) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if ((pFT_OpenEx != IntPtr.Zero) & (pFT_SetDataCharacteristics != IntPtr.Zero) & (pFT_SetFlowControl != IntPtr.Zero) & (pFT_SetBaudRate != IntPtr.Zero)) + { + tFT_OpenEx FT_OpenEx = (tFT_OpenEx)Marshal.GetDelegateForFunctionPointer(pFT_OpenEx, typeof(tFT_OpenEx)); + tFT_SetDataCharacteristics FT_SetDataCharacteristics = (tFT_SetDataCharacteristics)Marshal.GetDelegateForFunctionPointer(pFT_SetDataCharacteristics, typeof(tFT_SetDataCharacteristics)); + tFT_SetFlowControl FT_SetFlowControl = (tFT_SetFlowControl)Marshal.GetDelegateForFunctionPointer(pFT_SetFlowControl, typeof(tFT_SetFlowControl)); + tFT_SetBaudRate FT_SetBaudRate = (tFT_SetBaudRate)Marshal.GetDelegateForFunctionPointer(pFT_SetBaudRate, typeof(tFT_SetBaudRate)); + + // Call FT_OpenEx + ftStatus = FT_OpenEx(description, FT_OPEN.BY_DESCRIPTION, ref _ftHandle); + + // Appears that the handle value can be non-NULL on a fail, so set it explicitly + if (ftStatus != FT_STATUS.FT_OK) + _ftHandle = IntPtr.Zero; + + if (_ftHandle != IntPtr.Zero) + { + // Initialise port data characteristics + byte WordLength = FT_DATA_BITS.FT_BITS_8; + byte StopBits = FT_STOP_BITS.FT_STOP_BITS_1; + byte Parity = FT_PARITY.FT_PARITY_NONE; + ftStatus = FT_SetDataCharacteristics(_ftHandle, WordLength, StopBits, Parity); + // Initialise to no flow control + short FlowControl = FT_FLOW_CONTROL.FT_FLOW_NONE; + byte Xon = 0x11; + byte Xoff = 0x13; + ftStatus = FT_SetFlowControl(_ftHandle, FlowControl, Xon, Xoff); + // Initialise Baud rate + int BaudRate = 9600; + ftStatus = FT_SetBaudRate(_ftHandle, BaudRate); + } + } + else + { + if (pFT_OpenEx == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_OpenEx."); + } + if (pFT_SetDataCharacteristics == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_SetDataCharacteristics."); + } + if (pFT_SetFlowControl == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_SetFlowControl."); + } + if (pFT_SetBaudRate == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_SetBaudRate."); + } + } + return ftStatus; + } + + /// + /// Opens the FTDI device at the specified physical location. + /// + /// FT_STATUS value from FT_OpenEx in FTD2XX.DLL + /// Location of the device to open. + /// Initialises the device to 8 data bits, 1 stop bit, no parity, no flow control and 9600 Baud. + public FT_STATUS OpenByLocation(int location) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if ((pFT_OpenEx != IntPtr.Zero) & (pFT_SetDataCharacteristics != IntPtr.Zero) & (pFT_SetFlowControl != IntPtr.Zero) & (pFT_SetBaudRate != IntPtr.Zero)) + { + tFT_OpenExLoc FT_OpenEx = (tFT_OpenExLoc)Marshal.GetDelegateForFunctionPointer(pFT_OpenEx, typeof(tFT_OpenExLoc)); + tFT_SetDataCharacteristics FT_SetDataCharacteristics = (tFT_SetDataCharacteristics)Marshal.GetDelegateForFunctionPointer(pFT_SetDataCharacteristics, typeof(tFT_SetDataCharacteristics)); + tFT_SetFlowControl FT_SetFlowControl = (tFT_SetFlowControl)Marshal.GetDelegateForFunctionPointer(pFT_SetFlowControl, typeof(tFT_SetFlowControl)); + tFT_SetBaudRate FT_SetBaudRate = (tFT_SetBaudRate)Marshal.GetDelegateForFunctionPointer(pFT_SetBaudRate, typeof(tFT_SetBaudRate)); + + // Call FT_OpenEx + //ftStatus = FT_OpenEx(location, FT_OPEN.BY_LOCATION, ref _ftHandle); + ftStatus = (FT_STATUS)Native.Ftd2xx.FT_OpenEx(location, Native.FT_OPEN_TYPE.FT_OPEN_BY_LOCATION, out _ftHandle); + + // Appears that the handle value can be non-NULL on a fail, so set it explicitly + if (ftStatus != FT_STATUS.FT_OK) + _ftHandle = IntPtr.Zero; + + if (_ftHandle != IntPtr.Zero) + { + // Initialise port data characteristics + byte WordLength = FT_DATA_BITS.FT_BITS_8; + byte StopBits = FT_STOP_BITS.FT_STOP_BITS_1; + byte Parity = FT_PARITY.FT_PARITY_NONE; + FT_SetDataCharacteristics(_ftHandle, WordLength, StopBits, Parity); + + // Initialise to no flow control + short FlowControl = FT_FLOW_CONTROL.FT_FLOW_NONE; + byte Xon = 0x11; + byte Xoff = 0x13; + FT_SetFlowControl(_ftHandle, FlowControl, Xon, Xoff); + + // Initialise Baud rate + int BaudRate = 9600; + FT_SetBaudRate(_ftHandle, BaudRate); + } + } + else + { + if (pFT_OpenEx == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_OpenEx."); + } + if (pFT_SetDataCharacteristics == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_SetDataCharacteristics."); + } + if (pFT_SetFlowControl == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_SetFlowControl."); + } + if (pFT_SetBaudRate == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_SetBaudRate."); + } + } + return ftStatus; + } + + /// + /// Closes the handle to an open FTDI device. + /// + /// FT_STATUS value from FT_Close in FTD2XX.DLL + public FT_STATUS Close() + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_Close != IntPtr.Zero) + { + tFT_Close FT_Close = (tFT_Close)Marshal.GetDelegateForFunctionPointer(pFT_Close, typeof(tFT_Close)); + + // Call FT_Close + ftStatus = FT_Close(_ftHandle); + + if (ftStatus == FT_STATUS.FT_OK) + { + _ftHandle = IntPtr.Zero; + } + } + else + { + if (pFT_Close == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_Close."); + } + } + + return ftStatus; + } + + /// + /// Read data from an open FTDI device. + /// + /// FT_STATUS value from FT_Read in FTD2XX.DLL + /// An array of bytes which will be populated with the data read from the device. + /// The number of bytes requested from the device. + /// The number of bytes actually read. + public FT_STATUS Read(byte[] dataBuffer, int numBytesToRead, ref int numBytesRead) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_Read != IntPtr.Zero) + { + + tFT_Read FT_Read = (tFT_Read)Marshal.GetDelegateForFunctionPointer(pFT_Read, typeof(tFT_Read)); + + // If the buffer is not big enough to receive the amount of data requested, adjust the number of bytes to read + if (dataBuffer.Length < numBytesToRead) + { + numBytesToRead = dataBuffer.Length; + } + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_Read + ftStatus = FT_Read(_ftHandle, dataBuffer, numBytesToRead, ref numBytesRead); + } + } + else + { + if (pFT_Read == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_Read."); + } + } + return ftStatus; + } + + /// + /// Read data from an open FTDI device. + /// + /// FT_STATUS value from FT_Read in FTD2XX.DLL + /// A string containing the data read + /// The number of bytes requested from the device. + /// The number of bytes actually read. + public FT_STATUS Read(out string dataBuffer, int numBytesToRead, ref int numBytesRead) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // As dataBuffer is an OUT parameter, needs to be assigned before returning + dataBuffer = string.Empty; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_Read != IntPtr.Zero) + { + tFT_Read FT_Read = (tFT_Read)Marshal.GetDelegateForFunctionPointer(pFT_Read, typeof(tFT_Read)); + + byte[] byteDataBuffer = new byte[numBytesToRead]; + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_Read + ftStatus = FT_Read(_ftHandle, byteDataBuffer, numBytesToRead, ref numBytesRead); + + // Convert ASCII byte array back to Unicode string for passing back + dataBuffer = Encoding.ASCII.GetString(byteDataBuffer); + // Trim buffer to actual bytes read + dataBuffer = dataBuffer.Substring(0, numBytesRead); + } + } + else + { + if (pFT_Read == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_Read."); + } + } + return ftStatus; + } + + public byte[] ReadBytes(int count, out FT_STATUS status) + { + byte[] readBuffer = new byte[count]; + int bytesRead = 0; + status = Read(readBuffer, count, ref bytesRead); + return readBuffer; + } + + /// + /// Write data to an open FTDI device. + /// + /// FT_STATUS value from FT_Write in FTD2XX.DLL + /// An array of bytes which contains the data to be written to the device. + /// The number of bytes to be written to the device. + /// The number of bytes actually written to the device. + public FT_STATUS Write(byte[] dataBuffer, int numBytesToWrite, ref int numBytesWritten) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_Write != IntPtr.Zero) + { + tFT_Write FT_Write = (tFT_Write)Marshal.GetDelegateForFunctionPointer(pFT_Write, typeof(tFT_Write)); + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_Write + ftStatus = FT_Write(_ftHandle, dataBuffer, numBytesToWrite, ref numBytesWritten); + } + } + else + { + if (pFT_Write == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_Write."); + } + } + return ftStatus; + } + + /// + /// Write data to an open FTDI device. + /// + /// FT_STATUS value from FT_Write in FTD2XX.DLL + /// A string which contains the data to be written to the device. + /// The number of bytes to be written to the device. + /// The number of bytes actually written to the device. + public FT_STATUS Write(string dataBuffer, int numBytesToWrite, ref int numBytesWritten) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_Write != IntPtr.Zero) + { + tFT_Write FT_Write = (tFT_Write)Marshal.GetDelegateForFunctionPointer(pFT_Write, typeof(tFT_Write)); + + // Convert Unicode string to ASCII byte array + byte[] byteDataBuffer = Encoding.ASCII.GetBytes(dataBuffer); + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_Write + ftStatus = FT_Write(_ftHandle, byteDataBuffer, numBytesToWrite, ref numBytesWritten); + } + } + else + { + if (pFT_Write == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_Write."); + } + } + return ftStatus; + } + + public FT_STATUS Write(byte[] bytes) + { + int bytesWritten = 0; + return Write(bytes, bytes.Length, ref bytesWritten); + } + + public FT_STATUS Write(byte b) + { + return Write(new byte[] { b }); + } + + /// + /// Reset an open FTDI device. + /// + /// FT_STATUS value from FT_ResetDevice in FTD2XX.DLL + public FT_STATUS ResetDevice() + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_ResetDevice != IntPtr.Zero) + { + tFT_ResetDevice FT_ResetDevice = (tFT_ResetDevice)Marshal.GetDelegateForFunctionPointer(pFT_ResetDevice, typeof(tFT_ResetDevice)); + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_ResetDevice + ftStatus = FT_ResetDevice(_ftHandle); + } + } + else + { + if (pFT_ResetDevice == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_ResetDevice."); + } + } + return ftStatus; + } + + /// + /// Purge data from the devices transmit and/or receive buffers. + /// + /// FT_STATUS value from FT_Purge in FTD2XX.DLL + /// Specifies which buffer(s) to be purged. Valid values are any combination of the following flags: FT_PURGE_RX, FT_PURGE_TX + public FT_STATUS Purge(int purgemask) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_Purge != IntPtr.Zero) + { + tFT_Purge FT_Purge = (tFT_Purge)Marshal.GetDelegateForFunctionPointer(pFT_Purge, typeof(tFT_Purge)); + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_Purge + ftStatus = FT_Purge(_ftHandle, purgemask); + } + } + else + { + if (pFT_Purge == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_Purge."); + } + } + return ftStatus; + } + + /// + /// Register for event notification. + /// + /// FT_STATUS value from FT_SetEventNotification in FTD2XX.DLL + /// After setting event notification, the event can be caught by executing the WaitOne() method of the EventWaitHandle. If multiple event types are being monitored, the event that fired can be determined from the GetEventType method. + /// The type of events to signal. Can be any combination of the following: FT_EVENT_RXCHAR, FT_EVENT_MODEM_STATUS, FT_EVENT_LINE_STATUS + /// Handle to the event that will receive the notification + public FT_STATUS SetEventNotification(int eventmask, EventWaitHandle eventhandle) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_SetEventNotification != IntPtr.Zero) + { + tFT_SetEventNotification FT_SetEventNotification = (tFT_SetEventNotification)Marshal.GetDelegateForFunctionPointer(pFT_SetEventNotification, typeof(tFT_SetEventNotification)); + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_SetSetEventNotification + ftStatus = FT_SetEventNotification(_ftHandle, eventmask, eventhandle.SafeWaitHandle); + } + } + else + { + if (pFT_SetEventNotification == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_SetEventNotification."); + } + } + return ftStatus; + } + + /// + /// Stops the driver issuing USB in requests. + /// + /// FT_STATUS value from FT_StopInTask in FTD2XX.DLL + public FT_STATUS StopInTask() + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_StopInTask != IntPtr.Zero) + { + tFT_StopInTask FT_StopInTask = (tFT_StopInTask)Marshal.GetDelegateForFunctionPointer(pFT_StopInTask, typeof(tFT_StopInTask)); + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_StopInTask + ftStatus = FT_StopInTask(_ftHandle); + } + } + else + { + if (pFT_StopInTask == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_StopInTask."); + } + } + return ftStatus; + } + + /// + /// Resumes the driver issuing USB in requests. + /// + /// FT_STATUS value from FT_RestartInTask in FTD2XX.DLL + public FT_STATUS RestartInTask() + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_RestartInTask != IntPtr.Zero) + { + tFT_RestartInTask FT_RestartInTask = (tFT_RestartInTask)Marshal.GetDelegateForFunctionPointer(pFT_RestartInTask, typeof(tFT_RestartInTask)); + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_RestartInTask + ftStatus = FT_RestartInTask(_ftHandle); + } + } + else + { + if (pFT_RestartInTask == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_RestartInTask."); + } + } + return ftStatus; + } + + /// + /// Resets the device port. + /// + /// FT_STATUS value from FT_ResetPort in FTD2XX.DLL + public FT_STATUS ResetPort() + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_ResetPort != IntPtr.Zero) + { + tFT_ResetPort FT_ResetPort = (tFT_ResetPort)Marshal.GetDelegateForFunctionPointer(pFT_ResetPort, typeof(tFT_ResetPort)); + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_ResetPort + ftStatus = FT_ResetPort(_ftHandle); + } + } + else + { + if (pFT_ResetPort == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_ResetPort."); + } + } + return ftStatus; + } + + /// + /// Causes the device to be re-enumerated on the USB bus. This is equivalent to unplugging and replugging the device. + /// Also calls FT_Close if FT_CyclePort is successful, so no need to call this separately in the application. + /// + /// FT_STATUS value from FT_CyclePort in FTD2XX.DLL + public FT_STATUS CyclePort() + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if ((pFT_CyclePort != IntPtr.Zero) & (pFT_Close != IntPtr.Zero)) + { + tFT_CyclePort FT_CyclePort = (tFT_CyclePort)Marshal.GetDelegateForFunctionPointer(pFT_CyclePort, typeof(tFT_CyclePort)); + tFT_Close FT_Close = (tFT_Close)Marshal.GetDelegateForFunctionPointer(pFT_Close, typeof(tFT_Close)); + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_CyclePort + ftStatus = FT_CyclePort(_ftHandle); + if (ftStatus == FT_STATUS.FT_OK) + { + // If successful, call FT_Close + ftStatus = FT_Close(_ftHandle); + if (ftStatus == FT_STATUS.FT_OK) + { + _ftHandle = IntPtr.Zero; + } + } + } + } + else + { + if (pFT_CyclePort == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_CyclePort."); + } + if (pFT_Close == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_Close."); + } + } + return ftStatus; + } + + /// + /// Causes the system to check for USB hardware changes. This is equivalent to clicking on the "Scan for hardware changes" button in the Device Manager. + /// + /// FT_STATUS value from FT_Rescan in FTD2XX.DLL + public FT_STATUS Rescan() + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_Rescan != IntPtr.Zero) + { + tFT_Rescan FT_Rescan = (tFT_Rescan)Marshal.GetDelegateForFunctionPointer(pFT_Rescan, typeof(tFT_Rescan)); + + // Call FT_Rescan + ftStatus = FT_Rescan(); + } + else + { + if (pFT_Rescan == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_Rescan."); + } + } + return ftStatus; + } + + /// + /// Forces a reload of the driver for devices with a specific VID and PID combination. + /// + /// FT_STATUS value from FT_Reload in FTD2XX.DLL + /// If the VID and PID parameters are 0, the drivers for USB root hubs will be reloaded, causing all USB devices connected to reload their drivers + /// Vendor ID of the devices to have the driver reloaded + /// Product ID of the devices to have the driver reloaded + public FT_STATUS Reload(short VendorID, short ProductID) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_Reload != IntPtr.Zero) + { + tFT_Reload FT_Reload = (tFT_Reload)Marshal.GetDelegateForFunctionPointer(pFT_Reload, typeof(tFT_Reload)); + + // Call FT_Reload + ftStatus = FT_Reload(VendorID, ProductID); + } + else + { + if (pFT_Reload == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_Reload."); + } + } + return ftStatus; + } + + /// + /// Puts the device in a mode other than the default UART or FIFO mode. + /// + /// FT_STATUS value from FT_SetBitMode in FTD2XX.DLL + /// Sets up which bits are inputs and which are outputs. A bit value of 0 sets the corresponding pin to an input, a bit value of 1 sets the corresponding pin to an output. + /// In the case of CBUS Bit Bang, the upper nibble of this value controls which pins are inputs and outputs, while the lower nibble controls which of the outputs are high and low. + /// For FT232H devices, valid values are FT_BIT_MODE_RESET, FT_BIT_MODE_ASYNC_BITBANG, FT_BIT_MODE_MPSSE, FT_BIT_MODE_SYNC_BITBANG, FT_BIT_MODE_CBUS_BITBANG, FT_BIT_MODE_MCU_HOST, FT_BIT_MODE_FAST_SERIAL, FT_BIT_MODE_SYNC_FIFO. + /// For FT2232H devices, valid values are FT_BIT_MODE_RESET, FT_BIT_MODE_ASYNC_BITBANG, FT_BIT_MODE_MPSSE, FT_BIT_MODE_SYNC_BITBANG, FT_BIT_MODE_MCU_HOST, FT_BIT_MODE_FAST_SERIAL, FT_BIT_MODE_SYNC_FIFO. + /// For FT4232H devices, valid values are FT_BIT_MODE_RESET, FT_BIT_MODE_ASYNC_BITBANG, FT_BIT_MODE_MPSSE, FT_BIT_MODE_SYNC_BITBANG. + /// For FT232R devices, valid values are FT_BIT_MODE_RESET, FT_BIT_MODE_ASYNC_BITBANG, FT_BIT_MODE_SYNC_BITBANG, FT_BIT_MODE_CBUS_BITBANG. + /// For FT245R devices, valid values are FT_BIT_MODE_RESET, FT_BIT_MODE_ASYNC_BITBANG, FT_BIT_MODE_SYNC_BITBANG. + /// For FT2232 devices, valid values are FT_BIT_MODE_RESET, FT_BIT_MODE_ASYNC_BITBANG, FT_BIT_MODE_MPSSE, FT_BIT_MODE_SYNC_BITBANG, FT_BIT_MODE_MCU_HOST, FT_BIT_MODE_FAST_SERIAL. + /// For FT232B and FT245B devices, valid values are FT_BIT_MODE_RESET, FT_BIT_MODE_ASYNC_BITBANG. + /// Thrown when the current device does not support the requested bit mode. + public FT_STATUS SetBitMode(byte Mask, byte BitMode) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + FT_ERROR ftErrorCondition = FT_ERROR.FT_NO_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_SetBitMode != IntPtr.Zero) + { + tFT_SetBitMode FT_SetBitMode = (tFT_SetBitMode)Marshal.GetDelegateForFunctionPointer(pFT_SetBitMode, typeof(tFT_SetBitMode)); + + if (_ftHandle != IntPtr.Zero) + { + + FT_DEVICE DeviceType = FT_DEVICE.FT_DEVICE_UNKNOWN; + // Set Bit Mode does not apply to FT8U232AM, FT8U245AM or FT8U100AX devices + GetDeviceType(ref DeviceType); + if (DeviceType == FT_DEVICE.FT_DEVICE_AM) + { + // Throw an exception + ftErrorCondition = FT_ERROR.FT_INVALID_BITMODE; + ThrowIfNotOK(ftStatus, ftErrorCondition); + } + else if (DeviceType == FT_DEVICE.FT_DEVICE_100AX) + { + // Throw an exception + ftErrorCondition = FT_ERROR.FT_INVALID_BITMODE; + ThrowIfNotOK(ftStatus, ftErrorCondition); + } + else if ((DeviceType == FT_DEVICE.FT_DEVICE_BM) && (BitMode != FT_BIT_MODES.FT_BIT_MODE_RESET)) + { + if ((BitMode & (FT_BIT_MODES.FT_BIT_MODE_ASYNC_BITBANG)) == 0) + { + // Throw an exception + ftErrorCondition = FT_ERROR.FT_INVALID_BITMODE; + ThrowIfNotOK(ftStatus, ftErrorCondition); + } + } + else if ((DeviceType == FT_DEVICE.FT_DEVICE_2232) && (BitMode != FT_BIT_MODES.FT_BIT_MODE_RESET)) + { + if ((BitMode & (FT_BIT_MODES.FT_BIT_MODE_ASYNC_BITBANG | FT_BIT_MODES.FT_BIT_MODE_MPSSE | FT_BIT_MODES.FT_BIT_MODE_SYNC_BITBANG | FT_BIT_MODES.FT_BIT_MODE_MCU_HOST | FT_BIT_MODES.FT_BIT_MODE_FAST_SERIAL)) == 0) + { + // Throw an exception + ftErrorCondition = FT_ERROR.FT_INVALID_BITMODE; + ThrowIfNotOK(ftStatus, ftErrorCondition); + } + if ((BitMode == FT_BIT_MODES.FT_BIT_MODE_MPSSE) & (InterfaceIdentifier != "A")) + { + // MPSSE mode is only available on channel A + // Throw an exception + ftErrorCondition = FT_ERROR.FT_INVALID_BITMODE; + ThrowIfNotOK(ftStatus, ftErrorCondition); + } + } + else if ((DeviceType == FT_DEVICE.FT_DEVICE_232R) && (BitMode != FT_BIT_MODES.FT_BIT_MODE_RESET)) + { + if ((BitMode & (FT_BIT_MODES.FT_BIT_MODE_ASYNC_BITBANG | FT_BIT_MODES.FT_BIT_MODE_SYNC_BITBANG | FT_BIT_MODES.FT_BIT_MODE_CBUS_BITBANG)) == 0) + { + // Throw an exception + ftErrorCondition = FT_ERROR.FT_INVALID_BITMODE; + ThrowIfNotOK(ftStatus, ftErrorCondition); + } + } + else if (((DeviceType == FT_DEVICE.FT_DEVICE_2232H) + || (DeviceType == FT_DEVICE.FT_DEVICE_2232HP) + || (DeviceType == FT_DEVICE.FT_DEVICE_2233HP) + || (DeviceType == FT_DEVICE.FT_DEVICE_2232HA)) + && (BitMode != FT_BIT_MODES.FT_BIT_MODE_RESET)) + { + if ((BitMode & (FT_BIT_MODES.FT_BIT_MODE_ASYNC_BITBANG | FT_BIT_MODES.FT_BIT_MODE_MPSSE | FT_BIT_MODES.FT_BIT_MODE_SYNC_BITBANG | FT_BIT_MODES.FT_BIT_MODE_MCU_HOST | FT_BIT_MODES.FT_BIT_MODE_FAST_SERIAL | FT_BIT_MODES.FT_BIT_MODE_SYNC_FIFO)) == 0) + { + // Throw an exception + ftErrorCondition = FT_ERROR.FT_INVALID_BITMODE; + ThrowIfNotOK(ftStatus, ftErrorCondition); + } + if (((BitMode == FT_BIT_MODES.FT_BIT_MODE_MCU_HOST) | (BitMode == FT_BIT_MODES.FT_BIT_MODE_SYNC_FIFO)) & (InterfaceIdentifier != "A")) + { + // MCU Host Emulation and Single channel synchronous 245 FIFO mode is only available on channel A + // Throw an exception + ftErrorCondition = FT_ERROR.FT_INVALID_BITMODE; + ThrowIfNotOK(ftStatus, ftErrorCondition); + } + } + else if (((DeviceType == FT_DEVICE.FT_DEVICE_4232H) + || (DeviceType == FT_DEVICE.FT_DEVICE_4232HP) + || (DeviceType == FT_DEVICE.FT_DEVICE_4233HP) + || (DeviceType == FT_DEVICE.FT_DEVICE_4232HA)) + && (BitMode != FT_BIT_MODES.FT_BIT_MODE_RESET)) + { + if ((BitMode & (FT_BIT_MODES.FT_BIT_MODE_ASYNC_BITBANG | FT_BIT_MODES.FT_BIT_MODE_MPSSE | FT_BIT_MODES.FT_BIT_MODE_SYNC_BITBANG)) == 0) + { + // Throw an exception + ftErrorCondition = FT_ERROR.FT_INVALID_BITMODE; + ThrowIfNotOK(ftStatus, ftErrorCondition); + } + if ((BitMode == FT_BIT_MODES.FT_BIT_MODE_MPSSE) & ((InterfaceIdentifier != "A") & (InterfaceIdentifier != "B"))) + { + // MPSSE mode is only available on channel A and B + // Throw an exception + ftErrorCondition = FT_ERROR.FT_INVALID_BITMODE; + ThrowIfNotOK(ftStatus, ftErrorCondition); + } + } + else if (((DeviceType == FT_DEVICE.FT_DEVICE_232H) + || (DeviceType == FT_DEVICE.FT_DEVICE_232HP) + || (DeviceType == FT_DEVICE.FT_DEVICE_233HP)) + && (BitMode != FT_BIT_MODES.FT_BIT_MODE_RESET)) + { + // FT232H supports all current bit modes! + if (BitMode > FT_BIT_MODES.FT_BIT_MODE_SYNC_FIFO) + { + // Throw an exception + ftErrorCondition = FT_ERROR.FT_INVALID_BITMODE; + ThrowIfNotOK(ftStatus, ftErrorCondition); + } + } + + // Requested bit mode is supported + // Note FT_BIT_MODES.FT_BIT_MODE_RESET falls through to here - no bits set so cannot check for AND + // Call FT_SetBitMode + ftStatus = FT_SetBitMode(_ftHandle, Mask, BitMode); + } + } + else + { + if (pFT_SetBitMode == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_SetBitMode."); + } + } + return ftStatus; + } + + /// + /// Gets the instantaneous state of the device IO pins. + /// + /// FT_STATUS value from FT_GetBitMode in FTD2XX.DLL + /// A bitmap value containing the instantaneous state of the device IO pins + public FT_STATUS GetPinStates(ref byte BitMode) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_GetBitMode != IntPtr.Zero) + { + tFT_GetBitMode FT_GetBitMode = (tFT_GetBitMode)Marshal.GetDelegateForFunctionPointer(pFT_GetBitMode, typeof(tFT_GetBitMode)); + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_GetBitMode + ftStatus = FT_GetBitMode(_ftHandle, ref BitMode); + } + } + else + { + if (pFT_GetBitMode == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_GetBitMode."); + } + } + return ftStatus; + } + + /// + /// Reads an individual word value from a specified location in the device's EEPROM. + /// + /// FT_STATUS value from FT_ReadEE in FTD2XX.DLL + /// The EEPROM location to read data from + /// The WORD value read from the EEPROM location specified in the Address paramter + public FT_STATUS ReadEEPROMLocation(int Address, ref short EEValue) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_ReadEE != IntPtr.Zero) + { + tFT_ReadEE FT_ReadEE = (tFT_ReadEE)Marshal.GetDelegateForFunctionPointer(pFT_ReadEE, typeof(tFT_ReadEE)); + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_ReadEE + ftStatus = FT_ReadEE(_ftHandle, Address, ref EEValue); + } + } + else + { + if (pFT_ReadEE == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_ReadEE."); + } + } + return ftStatus; + } + + /// + /// Writes an individual word value to a specified location in the device's EEPROM. + /// + /// FT_STATUS value from FT_WriteEE in FTD2XX.DLL + /// The EEPROM location to read data from + /// The WORD value to write to the EEPROM location specified by the Address parameter + public FT_STATUS WriteEEPROMLocation(int Address, short EEValue) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_WriteEE != IntPtr.Zero) + { + tFT_WriteEE FT_WriteEE = (tFT_WriteEE)Marshal.GetDelegateForFunctionPointer(pFT_WriteEE, typeof(tFT_WriteEE)); + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_WriteEE + ftStatus = FT_WriteEE(_ftHandle, Address, EEValue); + } + } + else + { + if (pFT_WriteEE == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_WriteEE."); + } + } + return ftStatus; + } + + /// + /// Erases the device EEPROM. + /// + /// FT_STATUS value from FT_EraseEE in FTD2XX.DLL + /// Thrown when attempting to erase the EEPROM of a device with an internal EEPROM such as an FT232R or FT245R. + public FT_STATUS EraseEEPROM() + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + FT_ERROR ftErrorCondition = FT_ERROR.FT_NO_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_EraseEE != IntPtr.Zero) + { + tFT_EraseEE FT_EraseEE = (tFT_EraseEE)Marshal.GetDelegateForFunctionPointer(pFT_EraseEE, typeof(tFT_EraseEE)); + + if (_ftHandle != IntPtr.Zero) + { + FT_DEVICE DeviceType = FT_DEVICE.FT_DEVICE_UNKNOWN; + // Check that it is not an FT232R or FT245R that we are trying to erase + GetDeviceType(ref DeviceType); + if (DeviceType == FT_DEVICE.FT_DEVICE_232R) + { + // If it is a device with an internal EEPROM, throw an exception + ftErrorCondition = FT_ERROR.FT_INCORRECT_DEVICE; + ThrowIfNotOK(ftStatus, ftErrorCondition); + } + + // Call FT_EraseEE + ftStatus = FT_EraseEE(_ftHandle); + } + } + else + { + if (pFT_EraseEE == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_EraseEE."); + } + } + return ftStatus; + } + + /// + /// Reads the EEPROM contents of an FT232B or FT245B device. + /// + /// FT_STATUS value from FT_EE_Read in FTD2XX DLL + /// An FT232B_EEPROM_STRUCTURE which contains only the relevant information for an FT232B and FT245B device. + /// Thrown when the current device does not match the type required by this method. + public FT_STATUS ReadFT232BEEPROM(FT232B_EEPROM_STRUCTURE ee232b) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + FT_ERROR ftErrorCondition = FT_ERROR.FT_NO_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_EE_Read != IntPtr.Zero) + { + tFT_EE_Read FT_EE_Read = (tFT_EE_Read)Marshal.GetDelegateForFunctionPointer(pFT_EE_Read, typeof(tFT_EE_Read)); + + if (_ftHandle != IntPtr.Zero) + { + FT_DEVICE DeviceType = FT_DEVICE.FT_DEVICE_UNKNOWN; + // Check that it is an FT232B or FT245B that we are trying to read + GetDeviceType(ref DeviceType); + if (DeviceType != FT_DEVICE.FT_DEVICE_BM) + { + // If it is not, throw an exception + ftErrorCondition = FT_ERROR.FT_INCORRECT_DEVICE; + ThrowIfNotOK(ftStatus, ftErrorCondition); + } + + FT_PROGRAM_DATA eedata = new() + { + // Set up structure headers + Signature1 = 0x00000000, + Signature2 = -1, + Version = 2, + + // Allocate space from unmanaged heap + Manufacturer = Marshal.AllocHGlobal(32), + ManufacturerID = Marshal.AllocHGlobal(16), + Description = Marshal.AllocHGlobal(64), + SerialNumber = Marshal.AllocHGlobal(16) + }; + + // Call FT_EE_Read + ftStatus = FT_EE_Read(_ftHandle, eedata); + + // Retrieve string values + ee232b.Manufacturer = Marshal.PtrToStringAnsi(eedata.Manufacturer)!; + ee232b.ManufacturerID = Marshal.PtrToStringAnsi(eedata.ManufacturerID)!; + ee232b.Description = Marshal.PtrToStringAnsi(eedata.Description)!; + ee232b.SerialNumber = Marshal.PtrToStringAnsi(eedata.SerialNumber)!; + + // Free unmanaged buffers + Marshal.FreeHGlobal(eedata.Manufacturer); + Marshal.FreeHGlobal(eedata.ManufacturerID); + Marshal.FreeHGlobal(eedata.Description); + Marshal.FreeHGlobal(eedata.SerialNumber); + + // Map non-string elements to structure to be returned + // Standard elements + ee232b.VendorID = eedata.VendorID; + ee232b.ProductID = eedata.ProductID; + ee232b.MaxPower = eedata.MaxPower; + ee232b.SelfPowered = Convert.ToBoolean(eedata.SelfPowered); + ee232b.RemoteWakeup = Convert.ToBoolean(eedata.RemoteWakeup); + // B specific fields + ee232b.PullDownEnable = Convert.ToBoolean(eedata.PullDownEnable); + ee232b.SerNumEnable = Convert.ToBoolean(eedata.SerNumEnable); + ee232b.USBVersionEnable = Convert.ToBoolean(eedata.USBVersionEnable); + ee232b.USBVersion = eedata.USBVersion; + } + } + else + { + if (pFT_EE_Read == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_EE_Read."); + } + } + return ftStatus; + } + + /// + /// Reads the EEPROM contents of an FT2232 device. + /// + /// FT_STATUS value from FT_EE_Read in FTD2XX DLL + /// An FT2232_EEPROM_STRUCTURE which contains only the relevant information for an FT2232 device. + /// Thrown when the current device does not match the type required by this method. + public FT_STATUS ReadFT2232EEPROM(FT2232_EEPROM_STRUCTURE ee2232) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + FT_ERROR ftErrorCondition = FT_ERROR.FT_NO_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_EE_Read != IntPtr.Zero) + { + tFT_EE_Read FT_EE_Read = (tFT_EE_Read)Marshal.GetDelegateForFunctionPointer(pFT_EE_Read, typeof(tFT_EE_Read)); + + if (_ftHandle != IntPtr.Zero) + { + FT_DEVICE DeviceType = FT_DEVICE.FT_DEVICE_UNKNOWN; + // Check that it is an FT2232 that we are trying to read + GetDeviceType(ref DeviceType); + if (DeviceType != FT_DEVICE.FT_DEVICE_2232) + { + // If it is not, throw an exception + ftErrorCondition = FT_ERROR.FT_INCORRECT_DEVICE; + ThrowIfNotOK(ftStatus, ftErrorCondition); + } + + FT_PROGRAM_DATA eedata = new() + { + // Set up structure headers + Signature1 = 0x00000000, + Signature2 = -1, + Version = 2, + + // Allocate space from unmanaged heap + Manufacturer = Marshal.AllocHGlobal(32), + ManufacturerID = Marshal.AllocHGlobal(16), + Description = Marshal.AllocHGlobal(64), + SerialNumber = Marshal.AllocHGlobal(16) + }; + + // Call FT_EE_Read + ftStatus = FT_EE_Read(_ftHandle, eedata); + + // Retrieve string values + ee2232.Manufacturer = Marshal.PtrToStringAnsi(eedata.Manufacturer)!; + ee2232.ManufacturerID = Marshal.PtrToStringAnsi(eedata.ManufacturerID)!; + ee2232.Description = Marshal.PtrToStringAnsi(eedata.Description)!; + ee2232.SerialNumber = Marshal.PtrToStringAnsi(eedata.SerialNumber)!; + + // Free unmanaged buffers + Marshal.FreeHGlobal(eedata.Manufacturer); + Marshal.FreeHGlobal(eedata.ManufacturerID); + Marshal.FreeHGlobal(eedata.Description); + Marshal.FreeHGlobal(eedata.SerialNumber); + + // Map non-string elements to structure to be returned + // Standard elements + ee2232.VendorID = eedata.VendorID; + ee2232.ProductID = eedata.ProductID; + ee2232.MaxPower = eedata.MaxPower; + ee2232.SelfPowered = Convert.ToBoolean(eedata.SelfPowered); + ee2232.RemoteWakeup = Convert.ToBoolean(eedata.RemoteWakeup); + // 2232 specific fields + ee2232.PullDownEnable = Convert.ToBoolean(eedata.PullDownEnable5); + ee2232.SerNumEnable = Convert.ToBoolean(eedata.SerNumEnable5); + ee2232.USBVersionEnable = Convert.ToBoolean(eedata.USBVersionEnable5); + ee2232.USBVersion = eedata.USBVersion5; + ee2232.AIsHighCurrent = Convert.ToBoolean(eedata.AIsHighCurrent); + ee2232.BIsHighCurrent = Convert.ToBoolean(eedata.BIsHighCurrent); + ee2232.IFAIsFifo = Convert.ToBoolean(eedata.IFAIsFifo); + ee2232.IFAIsFifoTar = Convert.ToBoolean(eedata.IFAIsFifoTar); + ee2232.IFAIsFastSer = Convert.ToBoolean(eedata.IFAIsFastSer); + ee2232.AIsVCP = Convert.ToBoolean(eedata.AIsVCP); + ee2232.IFBIsFifo = Convert.ToBoolean(eedata.IFBIsFifo); + ee2232.IFBIsFifoTar = Convert.ToBoolean(eedata.IFBIsFifoTar); + ee2232.IFBIsFastSer = Convert.ToBoolean(eedata.IFBIsFastSer); + ee2232.BIsVCP = Convert.ToBoolean(eedata.BIsVCP); + } + } + else + { + if (pFT_EE_Read == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_EE_Read."); + } + } + return ftStatus; + } + + /// + /// Reads the EEPROM contents of an FT232R or FT245R device. + /// Calls FT_EE_Read in FTD2XX DLL + /// + /// An FT232R_EEPROM_STRUCTURE which contains only the relevant information for an FT232R and FT245R device. + /// Thrown when the current device does not match the type required by this method. + public FT_STATUS ReadFT232REEPROM(FT232R_EEPROM_STRUCTURE ee232r) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + FT_ERROR ftErrorCondition = FT_ERROR.FT_NO_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_EE_Read != IntPtr.Zero) + { + tFT_EE_Read FT_EE_Read = (tFT_EE_Read)Marshal.GetDelegateForFunctionPointer(pFT_EE_Read, typeof(tFT_EE_Read)); + + if (_ftHandle != IntPtr.Zero) + { + FT_DEVICE DeviceType = FT_DEVICE.FT_DEVICE_UNKNOWN; + // Check that it is an FT232R or FT245R that we are trying to read + GetDeviceType(ref DeviceType); + if (DeviceType != FT_DEVICE.FT_DEVICE_232R) + { + // If it is not, throw an exception + ftErrorCondition = FT_ERROR.FT_INCORRECT_DEVICE; + ThrowIfNotOK(ftStatus, ftErrorCondition); + } + + FT_PROGRAM_DATA eedata = new() + { + // Set up structure headers + Signature1 = 0x00000000, + Signature2 = -1, + Version = 2, + + // Allocate space from unmanaged heap + Manufacturer = Marshal.AllocHGlobal(32), + ManufacturerID = Marshal.AllocHGlobal(16), + Description = Marshal.AllocHGlobal(64), + SerialNumber = Marshal.AllocHGlobal(16) + }; + + // Call FT_EE_Read + ftStatus = FT_EE_Read(_ftHandle, eedata); + + // Retrieve string values + ee232r.Manufacturer = Marshal.PtrToStringAnsi(eedata.Manufacturer)!; + ee232r.ManufacturerID = Marshal.PtrToStringAnsi(eedata.ManufacturerID)!; + ee232r.Description = Marshal.PtrToStringAnsi(eedata.Description)!; + ee232r.SerialNumber = Marshal.PtrToStringAnsi(eedata.SerialNumber)!; + + // Free unmanaged buffers + Marshal.FreeHGlobal(eedata.Manufacturer); + Marshal.FreeHGlobal(eedata.ManufacturerID); + Marshal.FreeHGlobal(eedata.Description); + Marshal.FreeHGlobal(eedata.SerialNumber); + + // Map non-string elements to structure to be returned + // Standard elements + ee232r.VendorID = eedata.VendorID; + ee232r.ProductID = eedata.ProductID; + ee232r.MaxPower = eedata.MaxPower; + ee232r.SelfPowered = Convert.ToBoolean(eedata.SelfPowered); + ee232r.RemoteWakeup = Convert.ToBoolean(eedata.RemoteWakeup); + // 232R specific fields + ee232r.UseExtOsc = Convert.ToBoolean(eedata.UseExtOsc); + ee232r.HighDriveIOs = Convert.ToBoolean(eedata.HighDriveIOs); + ee232r.EndpointSize = eedata.EndpointSize; + ee232r.PullDownEnable = Convert.ToBoolean(eedata.PullDownEnableR); + ee232r.SerNumEnable = Convert.ToBoolean(eedata.SerNumEnableR); + ee232r.InvertTXD = Convert.ToBoolean(eedata.InvertTXD); + ee232r.InvertRXD = Convert.ToBoolean(eedata.InvertRXD); + ee232r.InvertRTS = Convert.ToBoolean(eedata.InvertRTS); + ee232r.InvertCTS = Convert.ToBoolean(eedata.InvertCTS); + ee232r.InvertDTR = Convert.ToBoolean(eedata.InvertDTR); + ee232r.InvertDSR = Convert.ToBoolean(eedata.InvertDSR); + ee232r.InvertDCD = Convert.ToBoolean(eedata.InvertDCD); + ee232r.InvertRI = Convert.ToBoolean(eedata.InvertRI); + ee232r.Cbus0 = eedata.Cbus0; + ee232r.Cbus1 = eedata.Cbus1; + ee232r.Cbus2 = eedata.Cbus2; + ee232r.Cbus3 = eedata.Cbus3; + ee232r.Cbus4 = eedata.Cbus4; + ee232r.RIsD2XX = Convert.ToBoolean(eedata.RIsD2XX); + } + } + else + { + if (pFT_EE_Read == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_EE_Read."); + } + } + return ftStatus; + } + + /// + /// Reads the EEPROM contents of an FT2232H device. + /// + /// FT_STATUS value from FT_EE_Read in FTD2XX DLL + /// An FT2232H_EEPROM_STRUCTURE which contains only the relevant information for an FT2232H device. + /// Thrown when the current device does not match the type required by this method. + public FT_STATUS ReadFT2232HEEPROM(FT2232H_EEPROM_STRUCTURE ee2232h) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + FT_ERROR ftErrorCondition = FT_ERROR.FT_NO_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_EE_Read != IntPtr.Zero) + { + tFT_EE_Read FT_EE_Read = (tFT_EE_Read)Marshal.GetDelegateForFunctionPointer(pFT_EE_Read, typeof(tFT_EE_Read)); + + if (_ftHandle != IntPtr.Zero) + { + FT_DEVICE DeviceType = FT_DEVICE.FT_DEVICE_UNKNOWN; + // Check that it is an FT2232H that we are trying to read + GetDeviceType(ref DeviceType); + if (DeviceType != FT_DEVICE.FT_DEVICE_2232H) + { + // If it is not, throw an exception + ftErrorCondition = FT_ERROR.FT_INCORRECT_DEVICE; + ThrowIfNotOK(ftStatus, ftErrorCondition); + } + + FT_PROGRAM_DATA eedata = new() + { + // Set up structure headers + Signature1 = 0x00000000, + Signature2 = -1, + Version = 3, + + // Allocate space from unmanaged heap + Manufacturer = Marshal.AllocHGlobal(32), + ManufacturerID = Marshal.AllocHGlobal(16), + Description = Marshal.AllocHGlobal(64), + SerialNumber = Marshal.AllocHGlobal(16) + }; + + // Call FT_EE_Read + ftStatus = FT_EE_Read(_ftHandle, eedata); + + // Retrieve string values + ee2232h.Manufacturer = Marshal.PtrToStringAnsi(eedata.Manufacturer)!; + ee2232h.ManufacturerID = Marshal.PtrToStringAnsi(eedata.ManufacturerID)!; + ee2232h.Description = Marshal.PtrToStringAnsi(eedata.Description)!; + ee2232h.SerialNumber = Marshal.PtrToStringAnsi(eedata.SerialNumber)!; + + // Free unmanaged buffers + Marshal.FreeHGlobal(eedata.Manufacturer); + Marshal.FreeHGlobal(eedata.ManufacturerID); + Marshal.FreeHGlobal(eedata.Description); + Marshal.FreeHGlobal(eedata.SerialNumber); + + // Map non-string elements to structure to be returned + // Standard elements + ee2232h.VendorID = eedata.VendorID; + ee2232h.ProductID = eedata.ProductID; + ee2232h.MaxPower = eedata.MaxPower; + ee2232h.SelfPowered = Convert.ToBoolean(eedata.SelfPowered); + ee2232h.RemoteWakeup = Convert.ToBoolean(eedata.RemoteWakeup); + // 2232H specific fields + ee2232h.PullDownEnable = Convert.ToBoolean(eedata.PullDownEnable7); + ee2232h.SerNumEnable = Convert.ToBoolean(eedata.SerNumEnable7); + ee2232h.ALSlowSlew = Convert.ToBoolean(eedata.ALSlowSlew); + ee2232h.ALSchmittInput = Convert.ToBoolean(eedata.ALSchmittInput); + ee2232h.ALDriveCurrent = eedata.ALDriveCurrent; + ee2232h.AHSlowSlew = Convert.ToBoolean(eedata.AHSlowSlew); + ee2232h.AHSchmittInput = Convert.ToBoolean(eedata.AHSchmittInput); + ee2232h.AHDriveCurrent = eedata.AHDriveCurrent; + ee2232h.BLSlowSlew = Convert.ToBoolean(eedata.BLSlowSlew); + ee2232h.BLSchmittInput = Convert.ToBoolean(eedata.BLSchmittInput); + ee2232h.BLDriveCurrent = eedata.BLDriveCurrent; + ee2232h.BHSlowSlew = Convert.ToBoolean(eedata.BHSlowSlew); + ee2232h.BHSchmittInput = Convert.ToBoolean(eedata.BHSchmittInput); + ee2232h.BHDriveCurrent = eedata.BHDriveCurrent; + ee2232h.IFAIsFifo = Convert.ToBoolean(eedata.IFAIsFifo7); + ee2232h.IFAIsFifoTar = Convert.ToBoolean(eedata.IFAIsFifoTar7); + ee2232h.IFAIsFastSer = Convert.ToBoolean(eedata.IFAIsFastSer7); + ee2232h.AIsVCP = Convert.ToBoolean(eedata.AIsVCP7); + ee2232h.IFBIsFifo = Convert.ToBoolean(eedata.IFBIsFifo7); + ee2232h.IFBIsFifoTar = Convert.ToBoolean(eedata.IFBIsFifoTar7); + ee2232h.IFBIsFastSer = Convert.ToBoolean(eedata.IFBIsFastSer7); + ee2232h.BIsVCP = Convert.ToBoolean(eedata.BIsVCP7); + ee2232h.PowerSaveEnable = Convert.ToBoolean(eedata.PowerSaveEnable); + } + } + else + { + if (pFT_EE_Read == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_EE_Read."); + } + } + return ftStatus; + } + + /// + /// Reads the EEPROM contents of an FT4232H device. + /// + /// FT_STATUS value from FT_EE_Read in FTD2XX DLL + /// An FT4232H_EEPROM_STRUCTURE which contains only the relevant information for an FT4232H device. + /// Thrown when the current device does not match the type required by this method. + public FT_STATUS ReadFT4232HEEPROM(FT4232H_EEPROM_STRUCTURE ee4232h) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + FT_ERROR ftErrorCondition = FT_ERROR.FT_NO_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_EE_Read != IntPtr.Zero) + { + tFT_EE_Read FT_EE_Read = (tFT_EE_Read)Marshal.GetDelegateForFunctionPointer(pFT_EE_Read, typeof(tFT_EE_Read)); + + if (_ftHandle != IntPtr.Zero) + { + FT_DEVICE DeviceType = FT_DEVICE.FT_DEVICE_UNKNOWN; + // Check that it is an FT4232H that we are trying to read + GetDeviceType(ref DeviceType); + if (DeviceType != FT_DEVICE.FT_DEVICE_4232H) + { + // If it is not, throw an exception + ftErrorCondition = FT_ERROR.FT_INCORRECT_DEVICE; + ThrowIfNotOK(ftStatus, ftErrorCondition); + } + + FT_PROGRAM_DATA eedata = new() + { + // Set up structure headers + Signature1 = 0x00000000, + Signature2 = -1, + Version = 4, + + // Allocate space from unmanaged heap + Manufacturer = Marshal.AllocHGlobal(32), + ManufacturerID = Marshal.AllocHGlobal(16), + Description = Marshal.AllocHGlobal(64), + SerialNumber = Marshal.AllocHGlobal(16) + }; + + // Call FT_EE_Read + ftStatus = FT_EE_Read(_ftHandle, eedata); + + // Retrieve string values + ee4232h.Manufacturer = Marshal.PtrToStringAnsi(eedata.Manufacturer)!; + ee4232h.ManufacturerID = Marshal.PtrToStringAnsi(eedata.ManufacturerID)!; + ee4232h.Description = Marshal.PtrToStringAnsi(eedata.Description)!; + ee4232h.SerialNumber = Marshal.PtrToStringAnsi(eedata.SerialNumber)!; + + // Free unmanaged buffers + Marshal.FreeHGlobal(eedata.Manufacturer); + Marshal.FreeHGlobal(eedata.ManufacturerID); + Marshal.FreeHGlobal(eedata.Description); + Marshal.FreeHGlobal(eedata.SerialNumber); + + // Map non-string elements to structure to be returned + // Standard elements + ee4232h.VendorID = eedata.VendorID; + ee4232h.ProductID = eedata.ProductID; + ee4232h.MaxPower = eedata.MaxPower; + ee4232h.SelfPowered = Convert.ToBoolean(eedata.SelfPowered); + ee4232h.RemoteWakeup = Convert.ToBoolean(eedata.RemoteWakeup); + // 4232H specific fields + ee4232h.PullDownEnable = Convert.ToBoolean(eedata.PullDownEnable8); + ee4232h.SerNumEnable = Convert.ToBoolean(eedata.SerNumEnable8); + ee4232h.ASlowSlew = Convert.ToBoolean(eedata.ASlowSlew); + ee4232h.ASchmittInput = Convert.ToBoolean(eedata.ASchmittInput); + ee4232h.ADriveCurrent = eedata.ADriveCurrent; + ee4232h.BSlowSlew = Convert.ToBoolean(eedata.BSlowSlew); + ee4232h.BSchmittInput = Convert.ToBoolean(eedata.BSchmittInput); + ee4232h.BDriveCurrent = eedata.BDriveCurrent; + ee4232h.CSlowSlew = Convert.ToBoolean(eedata.CSlowSlew); + ee4232h.CSchmittInput = Convert.ToBoolean(eedata.CSchmittInput); + ee4232h.CDriveCurrent = eedata.CDriveCurrent; + ee4232h.DSlowSlew = Convert.ToBoolean(eedata.DSlowSlew); + ee4232h.DSchmittInput = Convert.ToBoolean(eedata.DSchmittInput); + ee4232h.DDriveCurrent = eedata.DDriveCurrent; + ee4232h.ARIIsTXDEN = Convert.ToBoolean(eedata.ARIIsTXDEN); + ee4232h.BRIIsTXDEN = Convert.ToBoolean(eedata.BRIIsTXDEN); + ee4232h.CRIIsTXDEN = Convert.ToBoolean(eedata.CRIIsTXDEN); + ee4232h.DRIIsTXDEN = Convert.ToBoolean(eedata.DRIIsTXDEN); + ee4232h.AIsVCP = Convert.ToBoolean(eedata.AIsVCP8); + ee4232h.BIsVCP = Convert.ToBoolean(eedata.BIsVCP8); + ee4232h.CIsVCP = Convert.ToBoolean(eedata.CIsVCP8); + ee4232h.DIsVCP = Convert.ToBoolean(eedata.DIsVCP8); + } + } + else + { + if (pFT_EE_Read == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_EE_Read."); + } + } + return ftStatus; + } + + /// + /// Reads the EEPROM contents of an FT232H device. + /// + /// FT_STATUS value from FT_EE_Read in FTD2XX DLL + /// An FT232H_EEPROM_STRUCTURE which contains only the relevant information for an FT232H device. + /// Thrown when the current device does not match the type required by this method. + public FT_STATUS ReadFT232HEEPROM(FT232H_EEPROM_STRUCTURE ee232h) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + FT_ERROR ftErrorCondition = FT_ERROR.FT_NO_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_EE_Read != IntPtr.Zero) + { + tFT_EE_Read FT_EE_Read = (tFT_EE_Read)Marshal.GetDelegateForFunctionPointer(pFT_EE_Read, typeof(tFT_EE_Read)); + + if (_ftHandle != IntPtr.Zero) + { + FT_DEVICE DeviceType = FT_DEVICE.FT_DEVICE_UNKNOWN; + // Check that it is an FT232H that we are trying to read + GetDeviceType(ref DeviceType); + if ((DeviceType != FT_DEVICE.FT_DEVICE_232H) + && (DeviceType != FT_DEVICE.FT_DEVICE_232HP) + && (DeviceType != FT_DEVICE.FT_DEVICE_233HP)) + { + // If it is not, throw an exception + ftErrorCondition = FT_ERROR.FT_INCORRECT_DEVICE; + ThrowIfNotOK(ftStatus, ftErrorCondition); + } + + FT_PROGRAM_DATA eedata = new() + { + // Set up structure headers + Signature1 = 0x00000000, + Signature2 = -1, + Version = 5, + + // Allocate space from unmanaged heap + Manufacturer = Marshal.AllocHGlobal(32), + ManufacturerID = Marshal.AllocHGlobal(16), + Description = Marshal.AllocHGlobal(64), + SerialNumber = Marshal.AllocHGlobal(16) + }; + + // Call FT_EE_Read + ftStatus = FT_EE_Read(_ftHandle, eedata); + + // Retrieve string values + ee232h.Manufacturer = Marshal.PtrToStringAnsi(eedata.Manufacturer)!; + ee232h.ManufacturerID = Marshal.PtrToStringAnsi(eedata.ManufacturerID)!; + ee232h.Description = Marshal.PtrToStringAnsi(eedata.Description)!; + ee232h.SerialNumber = Marshal.PtrToStringAnsi(eedata.SerialNumber)!; + + // Free unmanaged buffers + Marshal.FreeHGlobal(eedata.Manufacturer); + Marshal.FreeHGlobal(eedata.ManufacturerID); + Marshal.FreeHGlobal(eedata.Description); + Marshal.FreeHGlobal(eedata.SerialNumber); + + // Map non-string elements to structure to be returned + // Standard elements + ee232h.VendorID = eedata.VendorID; + ee232h.ProductID = eedata.ProductID; + ee232h.MaxPower = eedata.MaxPower; + ee232h.SelfPowered = Convert.ToBoolean(eedata.SelfPowered); + ee232h.RemoteWakeup = Convert.ToBoolean(eedata.RemoteWakeup); + // 232H specific fields + ee232h.PullDownEnable = Convert.ToBoolean(eedata.PullDownEnableH); + ee232h.SerNumEnable = Convert.ToBoolean(eedata.SerNumEnableH); + ee232h.ACSlowSlew = Convert.ToBoolean(eedata.ACSlowSlewH); + ee232h.ACSchmittInput = Convert.ToBoolean(eedata.ACSchmittInputH); + ee232h.ACDriveCurrent = eedata.ACDriveCurrentH; + ee232h.ADSlowSlew = Convert.ToBoolean(eedata.ADSlowSlewH); + ee232h.ADSchmittInput = Convert.ToBoolean(eedata.ADSchmittInputH); + ee232h.ADDriveCurrent = eedata.ADDriveCurrentH; + ee232h.Cbus0 = eedata.Cbus0H; + ee232h.Cbus1 = eedata.Cbus1H; + ee232h.Cbus2 = eedata.Cbus2H; + ee232h.Cbus3 = eedata.Cbus3H; + ee232h.Cbus4 = eedata.Cbus4H; + ee232h.Cbus5 = eedata.Cbus5H; + ee232h.Cbus6 = eedata.Cbus6H; + ee232h.Cbus7 = eedata.Cbus7H; + ee232h.Cbus8 = eedata.Cbus8H; + ee232h.Cbus9 = eedata.Cbus9H; + ee232h.IsFifo = Convert.ToBoolean(eedata.IsFifoH); + ee232h.IsFifoTar = Convert.ToBoolean(eedata.IsFifoTarH); + ee232h.IsFastSer = Convert.ToBoolean(eedata.IsFastSerH); + ee232h.IsFT1248 = Convert.ToBoolean(eedata.IsFT1248H); + ee232h.FT1248Cpol = Convert.ToBoolean(eedata.FT1248CpolH); + ee232h.FT1248Lsb = Convert.ToBoolean(eedata.FT1248LsbH); + ee232h.FT1248FlowControl = Convert.ToBoolean(eedata.FT1248FlowControlH); + ee232h.IsVCP = Convert.ToBoolean(eedata.IsVCPH); + ee232h.PowerSaveEnable = Convert.ToBoolean(eedata.PowerSaveEnableH); + } + } + else + { + if (pFT_EE_Read == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_EE_Read."); + } + } + return ftStatus; + } + + /// + /// Reads the EEPROM contents of an X-Series device. + /// + /// FT_STATUS value from FT_EEPROM_Read in FTD2XX DLL + /// An FT_XSERIES_EEPROM_STRUCTURE which contains only the relevant information for an X-Series device. + /// Thrown when the current device does not match the type required by this method. + public FT_STATUS ReadXSeriesEEPROM(FTX_EEPROM_STRUCTURE eeX) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + FT_ERROR ftErrorCondition = FT_ERROR.FT_NO_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_EEPROM_Read != IntPtr.Zero) + { + tFT_EEPROM_Read FT_EEPROM_Read = (tFT_EEPROM_Read)Marshal.GetDelegateForFunctionPointer(pFT_EEPROM_Read, typeof(tFT_EEPROM_Read)); + + if (_ftHandle != IntPtr.Zero) + { + FT_DEVICE DeviceType = FT_DEVICE.FT_DEVICE_UNKNOWN; + // Check that it is an FT232H that we are trying to read + GetDeviceType(ref DeviceType); + if (DeviceType != FT_DEVICE.FT_DEVICE_X_SERIES) + { + // If it is not, throw an exception + ftErrorCondition = FT_ERROR.FT_INCORRECT_DEVICE; + ThrowIfNotOK(ftStatus, ftErrorCondition); + } + + FT_XSERIES_DATA eeData = new(); + FT_EEPROM_HEADER eeHeader = new(); + + byte[] manufacturer = new byte[32]; + byte[] manufacturerID = new byte[16]; + byte[] description = new byte[64]; + byte[] serialNumber = new byte[16]; + + eeHeader.deviceType = (int)FT_DEVICE.FT_DEVICE_X_SERIES; + eeData.common = eeHeader; + + // Calculate the size of our data structure... + int size = Marshal.SizeOf(eeData); + + // Allocate space for our pointer... + IntPtr eeDataMarshal = Marshal.AllocHGlobal(size); + Marshal.StructureToPtr(eeData, eeDataMarshal, false); + + // Call FT_EEPROM_Read + ftStatus = FT_EEPROM_Read(_ftHandle, eeDataMarshal, size, manufacturer, manufacturerID, description, serialNumber); + + if (ftStatus == FT_STATUS.FT_OK) + { + // Get the data back from the pointer... + eeData = (FT_XSERIES_DATA)Marshal.PtrToStructure(eeDataMarshal, typeof(FT_XSERIES_DATA))!; + + // Retrieve string values + System.Text.UTF8Encoding enc = new(); + eeX.Manufacturer = enc.GetString(manufacturer); + eeX.ManufacturerID = enc.GetString(manufacturerID); + eeX.Description = enc.GetString(description); + eeX.SerialNumber = enc.GetString(serialNumber); + // Map non-string elements to structure to be returned + // Standard elements + eeX.VendorID = eeData.common.VendorId; + eeX.ProductID = eeData.common.ProductId; + eeX.MaxPower = eeData.common.MaxPower; + eeX.SelfPowered = Convert.ToBoolean(eeData.common.SelfPowered); + eeX.RemoteWakeup = Convert.ToBoolean(eeData.common.RemoteWakeup); + eeX.SerNumEnable = Convert.ToBoolean(eeData.common.SerNumEnable); + eeX.PullDownEnable = Convert.ToBoolean(eeData.common.PullDownEnable); + // X-Series specific fields + // CBUS + eeX.Cbus0 = eeData.Cbus0; + eeX.Cbus1 = eeData.Cbus1; + eeX.Cbus2 = eeData.Cbus2; + eeX.Cbus3 = eeData.Cbus3; + eeX.Cbus4 = eeData.Cbus4; + eeX.Cbus5 = eeData.Cbus5; + eeX.Cbus6 = eeData.Cbus6; + // Drive Options + eeX.ACDriveCurrent = eeData.ACDriveCurrent; + eeX.ACSchmittInput = eeData.ACSchmittInput; + eeX.ACSlowSlew = eeData.ACSlowSlew; + eeX.ADDriveCurrent = eeData.ADDriveCurrent; + eeX.ADSchmittInput = eeData.ADSchmittInput; + eeX.ADSlowSlew = eeData.ADSlowSlew; + // BCD + eeX.BCDDisableSleep = eeData.BCDDisableSleep; + eeX.BCDEnable = eeData.BCDEnable; + eeX.BCDForceCbusPWREN = eeData.BCDForceCbusPWREN; + // FT1248 + eeX.FT1248Cpol = eeData.FT1248Cpol; + eeX.FT1248FlowControl = eeData.FT1248FlowControl; + eeX.FT1248Lsb = eeData.FT1248Lsb; + // I2C + eeX.I2CDeviceId = eeData.I2CDeviceId; + eeX.I2CDisableSchmitt = eeData.I2CDisableSchmitt; + eeX.I2CSlaveAddress = eeData.I2CSlaveAddress; + // RS232 Signals + eeX.InvertCTS = eeData.InvertCTS; + eeX.InvertDCD = eeData.InvertDCD; + eeX.InvertDSR = eeData.InvertDSR; + eeX.InvertDTR = eeData.InvertDTR; + eeX.InvertRI = eeData.InvertRI; + eeX.InvertRTS = eeData.InvertRTS; + eeX.InvertRXD = eeData.InvertRXD; + eeX.InvertTXD = eeData.InvertTXD; + // Hardware Options + eeX.PowerSaveEnable = eeData.PowerSaveEnable; + eeX.RS485EchoSuppress = eeData.RS485EchoSuppress; + // Driver Option + eeX.IsVCP = eeData.DriverType; + } + } + } + else + { + if (pFT_EE_Read == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_EE_Read."); + } + } + return ftStatus; + } + + /// + /// Writes the specified values to the EEPROM of an FT232B or FT245B device. + /// + /// FT_STATUS value from FT_EE_Program in FTD2XX DLL + /// The EEPROM settings to be written to the device + /// If the strings are too long, they will be truncated to their maximum permitted lengths + /// Thrown when the current device does not match the type required by this method. + public FT_STATUS WriteFT232BEEPROM(FT232B_EEPROM_STRUCTURE ee232b) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + FT_ERROR ftErrorCondition = FT_ERROR.FT_NO_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_EE_Program != IntPtr.Zero) + { + tFT_EE_Program FT_EE_Program = (tFT_EE_Program)Marshal.GetDelegateForFunctionPointer(pFT_EE_Program, typeof(tFT_EE_Program)); + + if (_ftHandle != IntPtr.Zero) + { + FT_DEVICE DeviceType = FT_DEVICE.FT_DEVICE_UNKNOWN; + // Check that it is an FT232B or FT245B that we are trying to write + GetDeviceType(ref DeviceType); + if (DeviceType != FT_DEVICE.FT_DEVICE_BM) + { + // If it is not, throw an exception + ftErrorCondition = FT_ERROR.FT_INCORRECT_DEVICE; + ThrowIfNotOK(ftStatus, ftErrorCondition); + } + + // Check for VID and PID of 0x0000 + if ((ee232b.VendorID == 0x0000) | (ee232b.ProductID == 0x0000)) + { + // Do not allow users to program the device with VID or PID of 0x0000 + return FT_STATUS.FT_INVALID_PARAMETER; + } + + FT_PROGRAM_DATA eedata = new() + { + // Set up structure headers + Signature1 = 0x00000000, + Signature2 = -1, + Version = 2, + + // Allocate space from unmanaged heap + Manufacturer = Marshal.AllocHGlobal(32), + ManufacturerID = Marshal.AllocHGlobal(16), + Description = Marshal.AllocHGlobal(64), + SerialNumber = Marshal.AllocHGlobal(16) + }; + + // Check lengths of strings to make sure that they are within our limits + // If not, trim them to make them our maximum length + if (ee232b.Manufacturer.Length > 32) + ee232b.Manufacturer = ee232b.Manufacturer.Substring(0, 32); + if (ee232b.ManufacturerID.Length > 16) + ee232b.ManufacturerID = ee232b.ManufacturerID.Substring(0, 16); + if (ee232b.Description.Length > 64) + ee232b.Description = ee232b.Description.Substring(0, 64); + if (ee232b.SerialNumber.Length > 16) + ee232b.SerialNumber = ee232b.SerialNumber.Substring(0, 16); + + // Set string values + eedata.Manufacturer = Marshal.StringToHGlobalAnsi(ee232b.Manufacturer); + eedata.ManufacturerID = Marshal.StringToHGlobalAnsi(ee232b.ManufacturerID); + eedata.Description = Marshal.StringToHGlobalAnsi(ee232b.Description); + eedata.SerialNumber = Marshal.StringToHGlobalAnsi(ee232b.SerialNumber); + + // Map non-string elements to structure + // Standard elements + eedata.VendorID = ee232b.VendorID; + eedata.ProductID = ee232b.ProductID; + eedata.MaxPower = ee232b.MaxPower; + eedata.SelfPowered = (short)(ee232b.SelfPowered ? 1 : 0); + eedata.RemoteWakeup = (short)(ee232b.RemoteWakeup ? 1 : 0); + // B specific fields + eedata.Rev4 = Convert.ToByte(true); + eedata.PullDownEnable = Convert.ToByte(ee232b.PullDownEnable); + eedata.SerNumEnable = Convert.ToByte(ee232b.SerNumEnable); + eedata.USBVersionEnable = Convert.ToByte(ee232b.USBVersionEnable); + eedata.USBVersion = ee232b.USBVersion; + + // Call FT_EE_Program + ftStatus = FT_EE_Program(_ftHandle, eedata); + + // Free unmanaged buffers + Marshal.FreeHGlobal(eedata.Manufacturer); + Marshal.FreeHGlobal(eedata.ManufacturerID); + Marshal.FreeHGlobal(eedata.Description); + Marshal.FreeHGlobal(eedata.SerialNumber); + } + } + else + { + if (pFT_EE_Program == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_EE_Program."); + } + } + return ftStatus; + } + + /// + /// Writes the specified values to the EEPROM of an FT2232 device. + /// Calls FT_EE_Program in FTD2XX DLL + /// + /// FT_STATUS value from FT_EE_Program in FTD2XX DLL + /// The EEPROM settings to be written to the device + /// If the strings are too long, they will be truncated to their maximum permitted lengths + /// Thrown when the current device does not match the type required by this method. + public FT_STATUS WriteFT2232EEPROM(FT2232_EEPROM_STRUCTURE ee2232) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + FT_ERROR ftErrorCondition = FT_ERROR.FT_NO_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_EE_Program != IntPtr.Zero) + { + tFT_EE_Program FT_EE_Program = (tFT_EE_Program)Marshal.GetDelegateForFunctionPointer(pFT_EE_Program, typeof(tFT_EE_Program)); + + if (_ftHandle != IntPtr.Zero) + { + FT_DEVICE DeviceType = FT_DEVICE.FT_DEVICE_UNKNOWN; + // Check that it is an FT2232 that we are trying to write + GetDeviceType(ref DeviceType); + if (DeviceType != FT_DEVICE.FT_DEVICE_2232) + { + // If it is not, throw an exception + ftErrorCondition = FT_ERROR.FT_INCORRECT_DEVICE; + ThrowIfNotOK(ftStatus, ftErrorCondition); + } + + // Check for VID and PID of 0x0000 + if ((ee2232.VendorID == 0x0000) | (ee2232.ProductID == 0x0000)) + { + // Do not allow users to program the device with VID or PID of 0x0000 + return FT_STATUS.FT_INVALID_PARAMETER; + } + + FT_PROGRAM_DATA eedata = new() + { + // Set up structure headers + Signature1 = 0x00000000, + Signature2 = -1, + Version = 2, + + // Allocate space from unmanaged heap + Manufacturer = Marshal.AllocHGlobal(32), + ManufacturerID = Marshal.AllocHGlobal(16), + Description = Marshal.AllocHGlobal(64), + SerialNumber = Marshal.AllocHGlobal(16) + }; + + // Check lengths of strings to make sure that they are within our limits + // If not, trim them to make them our maximum length + if (ee2232.Manufacturer.Length > 32) + ee2232.Manufacturer = ee2232.Manufacturer.Substring(0, 32); + if (ee2232.ManufacturerID.Length > 16) + ee2232.ManufacturerID = ee2232.ManufacturerID.Substring(0, 16); + if (ee2232.Description.Length > 64) + ee2232.Description = ee2232.Description.Substring(0, 64); + if (ee2232.SerialNumber.Length > 16) + ee2232.SerialNumber = ee2232.SerialNumber.Substring(0, 16); + + // Set string values + eedata.Manufacturer = Marshal.StringToHGlobalAnsi(ee2232.Manufacturer); + eedata.ManufacturerID = Marshal.StringToHGlobalAnsi(ee2232.ManufacturerID); + eedata.Description = Marshal.StringToHGlobalAnsi(ee2232.Description); + eedata.SerialNumber = Marshal.StringToHGlobalAnsi(ee2232.SerialNumber); + + // Map non-string elements to structure + // Standard elements + eedata.VendorID = ee2232.VendorID; + eedata.ProductID = ee2232.ProductID; + eedata.MaxPower = ee2232.MaxPower; + eedata.SelfPowered = (short)(ee2232.SelfPowered ? 1 : 0); + eedata.RemoteWakeup = (short)(ee2232.RemoteWakeup ? 1 : 0); + // 2232 specific fields + eedata.Rev5 = Convert.ToByte(true); + eedata.PullDownEnable5 = Convert.ToByte(ee2232.PullDownEnable); + eedata.SerNumEnable5 = Convert.ToByte(ee2232.SerNumEnable); + eedata.USBVersionEnable5 = Convert.ToByte(ee2232.USBVersionEnable); + eedata.USBVersion5 = ee2232.USBVersion; + eedata.AIsHighCurrent = Convert.ToByte(ee2232.AIsHighCurrent); + eedata.BIsHighCurrent = Convert.ToByte(ee2232.BIsHighCurrent); + eedata.IFAIsFifo = Convert.ToByte(ee2232.IFAIsFifo); + eedata.IFAIsFifoTar = Convert.ToByte(ee2232.IFAIsFifoTar); + eedata.IFAIsFastSer = Convert.ToByte(ee2232.IFAIsFastSer); + eedata.AIsVCP = Convert.ToByte(ee2232.AIsVCP); + eedata.IFBIsFifo = Convert.ToByte(ee2232.IFBIsFifo); + eedata.IFBIsFifoTar = Convert.ToByte(ee2232.IFBIsFifoTar); + eedata.IFBIsFastSer = Convert.ToByte(ee2232.IFBIsFastSer); + eedata.BIsVCP = Convert.ToByte(ee2232.BIsVCP); + + // Call FT_EE_Program + ftStatus = FT_EE_Program(_ftHandle, eedata); + + // Free unmanaged buffers + Marshal.FreeHGlobal(eedata.Manufacturer); + Marshal.FreeHGlobal(eedata.ManufacturerID); + Marshal.FreeHGlobal(eedata.Description); + Marshal.FreeHGlobal(eedata.SerialNumber); + } + } + else + { + if (pFT_EE_Program == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_EE_Program."); + } + } + return ftStatus; + } + + /// + /// Writes the specified values to the EEPROM of an FT232R or FT245R device. + /// Calls FT_EE_Program in FTD2XX DLL + /// + /// FT_STATUS value from FT_EE_Program in FTD2XX DLL + /// The EEPROM settings to be written to the device + /// If the strings are too long, they will be truncated to their maximum permitted lengths + /// Thrown when the current device does not match the type required by this method. + public FT_STATUS WriteFT232REEPROM(FT232R_EEPROM_STRUCTURE ee232r) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + FT_ERROR ftErrorCondition = FT_ERROR.FT_NO_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_EE_Program != IntPtr.Zero) + { + tFT_EE_Program FT_EE_Program = (tFT_EE_Program)Marshal.GetDelegateForFunctionPointer(pFT_EE_Program, typeof(tFT_EE_Program)); + + if (_ftHandle != IntPtr.Zero) + { + FT_DEVICE DeviceType = FT_DEVICE.FT_DEVICE_UNKNOWN; + // Check that it is an FT232R or FT245R that we are trying to write + GetDeviceType(ref DeviceType); + if (DeviceType != FT_DEVICE.FT_DEVICE_232R) + { + // If it is not, throw an exception + ftErrorCondition = FT_ERROR.FT_INCORRECT_DEVICE; + ThrowIfNotOK(ftStatus, ftErrorCondition); + } + + // Check for VID and PID of 0x0000 + if ((ee232r.VendorID == 0x0000) | (ee232r.ProductID == 0x0000)) + { + // Do not allow users to program the device with VID or PID of 0x0000 + return FT_STATUS.FT_INVALID_PARAMETER; + } + + FT_PROGRAM_DATA eedata = new() + { + // Set up structure headers + Signature1 = 0x00000000, + Signature2 = -1, + Version = 2, + + // Allocate space from unmanaged heap + Manufacturer = Marshal.AllocHGlobal(32), + ManufacturerID = Marshal.AllocHGlobal(16), + Description = Marshal.AllocHGlobal(64), + SerialNumber = Marshal.AllocHGlobal(16) + }; + + // Check lengths of strings to make sure that they are within our limits + // If not, trim them to make them our maximum length + if (ee232r.Manufacturer.Length > 32) + ee232r.Manufacturer = ee232r.Manufacturer.Substring(0, 32); + if (ee232r.ManufacturerID.Length > 16) + ee232r.ManufacturerID = ee232r.ManufacturerID.Substring(0, 16); + if (ee232r.Description.Length > 64) + ee232r.Description = ee232r.Description.Substring(0, 64); + if (ee232r.SerialNumber.Length > 16) + ee232r.SerialNumber = ee232r.SerialNumber.Substring(0, 16); + + // Set string values + eedata.Manufacturer = Marshal.StringToHGlobalAnsi(ee232r.Manufacturer); + eedata.ManufacturerID = Marshal.StringToHGlobalAnsi(ee232r.ManufacturerID); + eedata.Description = Marshal.StringToHGlobalAnsi(ee232r.Description); + eedata.SerialNumber = Marshal.StringToHGlobalAnsi(ee232r.SerialNumber); + + // Map non-string elements to structure + // Standard elements + eedata.VendorID = ee232r.VendorID; + eedata.ProductID = ee232r.ProductID; + eedata.MaxPower = ee232r.MaxPower; + eedata.SelfPowered = (short)(ee232r.SelfPowered ? 1 : 0); + eedata.RemoteWakeup = (short)(ee232r.RemoteWakeup ? 1 : 0); + // 232R specific fields + eedata.PullDownEnableR = Convert.ToByte(ee232r.PullDownEnable); + eedata.SerNumEnableR = Convert.ToByte(ee232r.SerNumEnable); + eedata.UseExtOsc = Convert.ToByte(ee232r.UseExtOsc); + eedata.HighDriveIOs = Convert.ToByte(ee232r.HighDriveIOs); + // Override any endpoint size the user has selected and force 64 bytes + // Some users have been known to wreck devices by setting 0 here... + eedata.EndpointSize = 64; + eedata.PullDownEnableR = Convert.ToByte(ee232r.PullDownEnable); + eedata.SerNumEnableR = Convert.ToByte(ee232r.SerNumEnable); + eedata.InvertTXD = Convert.ToByte(ee232r.InvertTXD); + eedata.InvertRXD = Convert.ToByte(ee232r.InvertRXD); + eedata.InvertRTS = Convert.ToByte(ee232r.InvertRTS); + eedata.InvertCTS = Convert.ToByte(ee232r.InvertCTS); + eedata.InvertDTR = Convert.ToByte(ee232r.InvertDTR); + eedata.InvertDSR = Convert.ToByte(ee232r.InvertDSR); + eedata.InvertDCD = Convert.ToByte(ee232r.InvertDCD); + eedata.InvertRI = Convert.ToByte(ee232r.InvertRI); + eedata.Cbus0 = ee232r.Cbus0; + eedata.Cbus1 = ee232r.Cbus1; + eedata.Cbus2 = ee232r.Cbus2; + eedata.Cbus3 = ee232r.Cbus3; + eedata.Cbus4 = ee232r.Cbus4; + eedata.RIsD2XX = Convert.ToByte(ee232r.RIsD2XX); + + // Call FT_EE_Program + ftStatus = FT_EE_Program(_ftHandle, eedata); + + // Free unmanaged buffers + Marshal.FreeHGlobal(eedata.Manufacturer); + Marshal.FreeHGlobal(eedata.ManufacturerID); + Marshal.FreeHGlobal(eedata.Description); + Marshal.FreeHGlobal(eedata.SerialNumber); + } + } + else + { + if (pFT_EE_Program == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_EE_Program."); + } + } + return ftStatus; + } + + /// + /// Writes the specified values to the EEPROM of an FT2232H device. + /// Calls FT_EE_Program in FTD2XX DLL + /// + /// FT_STATUS value from FT_EE_Program in FTD2XX DLL + /// The EEPROM settings to be written to the device + /// If the strings are too long, they will be truncated to their maximum permitted lengths + /// Thrown when the current device does not match the type required by this method. + public FT_STATUS WriteFT2232HEEPROM(FT2232H_EEPROM_STRUCTURE ee2232h) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + FT_ERROR ftErrorCondition = FT_ERROR.FT_NO_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_EE_Program != IntPtr.Zero) + { + tFT_EE_Program FT_EE_Program = (tFT_EE_Program)Marshal.GetDelegateForFunctionPointer(pFT_EE_Program, typeof(tFT_EE_Program)); + + if (_ftHandle != IntPtr.Zero) + { + FT_DEVICE DeviceType = FT_DEVICE.FT_DEVICE_UNKNOWN; + // Check that it is an FT2232H that we are trying to write + GetDeviceType(ref DeviceType); + if (DeviceType != FT_DEVICE.FT_DEVICE_2232H) + { + // If it is not, throw an exception + ftErrorCondition = FT_ERROR.FT_INCORRECT_DEVICE; + ThrowIfNotOK(ftStatus, ftErrorCondition); + } + + // Check for VID and PID of 0x0000 + if ((ee2232h.VendorID == 0x0000) | (ee2232h.ProductID == 0x0000)) + { + // Do not allow users to program the device with VID or PID of 0x0000 + return FT_STATUS.FT_INVALID_PARAMETER; + } + + FT_PROGRAM_DATA eedata = new() + { + // Set up structure headers + Signature1 = 0x00000000, + Signature2 = -1, + Version = 3, + + // Allocate space from unmanaged heap + Manufacturer = Marshal.AllocHGlobal(32), + ManufacturerID = Marshal.AllocHGlobal(16), + Description = Marshal.AllocHGlobal(64), + SerialNumber = Marshal.AllocHGlobal(16) + }; + + // Check lengths of strings to make sure that they are within our limits + // If not, trim them to make them our maximum length + if (ee2232h.Manufacturer.Length > 32) + ee2232h.Manufacturer = ee2232h.Manufacturer.Substring(0, 32); + if (ee2232h.ManufacturerID.Length > 16) + ee2232h.ManufacturerID = ee2232h.ManufacturerID.Substring(0, 16); + if (ee2232h.Description.Length > 64) + ee2232h.Description = ee2232h.Description.Substring(0, 64); + if (ee2232h.SerialNumber.Length > 16) + ee2232h.SerialNumber = ee2232h.SerialNumber.Substring(0, 16); + + // Set string values + eedata.Manufacturer = Marshal.StringToHGlobalAnsi(ee2232h.Manufacturer); + eedata.ManufacturerID = Marshal.StringToHGlobalAnsi(ee2232h.ManufacturerID); + eedata.Description = Marshal.StringToHGlobalAnsi(ee2232h.Description); + eedata.SerialNumber = Marshal.StringToHGlobalAnsi(ee2232h.SerialNumber); + + // Map non-string elements to structure + // Standard elements + eedata.VendorID = ee2232h.VendorID; + eedata.ProductID = ee2232h.ProductID; + eedata.MaxPower = ee2232h.MaxPower; + eedata.SelfPowered = (short)(ee2232h.SelfPowered ? 1 : 0); + eedata.RemoteWakeup = (short)(ee2232h.RemoteWakeup ? 1 : 0); + // 2232H specific fields + eedata.PullDownEnable7 = Convert.ToByte(ee2232h.PullDownEnable); + eedata.SerNumEnable7 = Convert.ToByte(ee2232h.SerNumEnable); + eedata.ALSlowSlew = Convert.ToByte(ee2232h.ALSlowSlew); + eedata.ALSchmittInput = Convert.ToByte(ee2232h.ALSchmittInput); + eedata.ALDriveCurrent = ee2232h.ALDriveCurrent; + eedata.AHSlowSlew = Convert.ToByte(ee2232h.AHSlowSlew); + eedata.AHSchmittInput = Convert.ToByte(ee2232h.AHSchmittInput); + eedata.AHDriveCurrent = ee2232h.AHDriveCurrent; + eedata.BLSlowSlew = Convert.ToByte(ee2232h.BLSlowSlew); + eedata.BLSchmittInput = Convert.ToByte(ee2232h.BLSchmittInput); + eedata.BLDriveCurrent = ee2232h.BLDriveCurrent; + eedata.BHSlowSlew = Convert.ToByte(ee2232h.BHSlowSlew); + eedata.BHSchmittInput = Convert.ToByte(ee2232h.BHSchmittInput); + eedata.BHDriveCurrent = ee2232h.BHDriveCurrent; + eedata.IFAIsFifo7 = Convert.ToByte(ee2232h.IFAIsFifo); + eedata.IFAIsFifoTar7 = Convert.ToByte(ee2232h.IFAIsFifoTar); + eedata.IFAIsFastSer7 = Convert.ToByte(ee2232h.IFAIsFastSer); + eedata.AIsVCP7 = Convert.ToByte(ee2232h.AIsVCP); + eedata.IFBIsFifo7 = Convert.ToByte(ee2232h.IFBIsFifo); + eedata.IFBIsFifoTar7 = Convert.ToByte(ee2232h.IFBIsFifoTar); + eedata.IFBIsFastSer7 = Convert.ToByte(ee2232h.IFBIsFastSer); + eedata.BIsVCP7 = Convert.ToByte(ee2232h.BIsVCP); + eedata.PowerSaveEnable = Convert.ToByte(ee2232h.PowerSaveEnable); + + // Call FT_EE_Program + ftStatus = FT_EE_Program(_ftHandle, eedata); + + // Free unmanaged buffers + Marshal.FreeHGlobal(eedata.Manufacturer); + Marshal.FreeHGlobal(eedata.ManufacturerID); + Marshal.FreeHGlobal(eedata.Description); + Marshal.FreeHGlobal(eedata.SerialNumber); + } + } + else + { + if (pFT_EE_Program == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_EE_Program."); + } + } + return ftStatus; + } + + /// + /// Writes the specified values to the EEPROM of an FT4232H device. + /// Calls FT_EE_Program in FTD2XX DLL + /// + /// FT_STATUS value from FT_EE_Program in FTD2XX DLL + /// The EEPROM settings to be written to the device + /// If the strings are too long, they will be truncated to their maximum permitted lengths + /// Thrown when the current device does not match the type required by this method. + public FT_STATUS WriteFT4232HEEPROM(FT4232H_EEPROM_STRUCTURE ee4232h) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + FT_ERROR ftErrorCondition = FT_ERROR.FT_NO_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_EE_Program != IntPtr.Zero) + { + tFT_EE_Program FT_EE_Program = (tFT_EE_Program)Marshal.GetDelegateForFunctionPointer(pFT_EE_Program, typeof(tFT_EE_Program)); + + if (_ftHandle != IntPtr.Zero) + { + FT_DEVICE DeviceType = FT_DEVICE.FT_DEVICE_UNKNOWN; + // Check that it is an FT4232H that we are trying to write + GetDeviceType(ref DeviceType); + if (DeviceType != FT_DEVICE.FT_DEVICE_4232H) + { + // If it is not, throw an exception + ftErrorCondition = FT_ERROR.FT_INCORRECT_DEVICE; + ThrowIfNotOK(ftStatus, ftErrorCondition); + } + + // Check for VID and PID of 0x0000 + if ((ee4232h.VendorID == 0x0000) | (ee4232h.ProductID == 0x0000)) + { + // Do not allow users to program the device with VID or PID of 0x0000 + return FT_STATUS.FT_INVALID_PARAMETER; + } + + FT_PROGRAM_DATA eedata = new() + { + // Set up structure headers + Signature1 = 0x00000000, + Signature2 = -1, + Version = 4, + + // Allocate space from unmanaged heap + Manufacturer = Marshal.AllocHGlobal(32), + ManufacturerID = Marshal.AllocHGlobal(16), + Description = Marshal.AllocHGlobal(64), + SerialNumber = Marshal.AllocHGlobal(16) + }; + + // Check lengths of strings to make sure that they are within our limits + // If not, trim them to make them our maximum length + if (ee4232h.Manufacturer.Length > 32) + ee4232h.Manufacturer = ee4232h.Manufacturer.Substring(0, 32); + if (ee4232h.ManufacturerID.Length > 16) + ee4232h.ManufacturerID = ee4232h.ManufacturerID.Substring(0, 16); + if (ee4232h.Description.Length > 64) + ee4232h.Description = ee4232h.Description.Substring(0, 64); + if (ee4232h.SerialNumber.Length > 16) + ee4232h.SerialNumber = ee4232h.SerialNumber.Substring(0, 16); + + // Set string values + eedata.Manufacturer = Marshal.StringToHGlobalAnsi(ee4232h.Manufacturer); + eedata.ManufacturerID = Marshal.StringToHGlobalAnsi(ee4232h.ManufacturerID); + eedata.Description = Marshal.StringToHGlobalAnsi(ee4232h.Description); + eedata.SerialNumber = Marshal.StringToHGlobalAnsi(ee4232h.SerialNumber); + + // Map non-string elements to structure + // Standard elements + eedata.VendorID = ee4232h.VendorID; + eedata.ProductID = ee4232h.ProductID; + eedata.MaxPower = ee4232h.MaxPower; + eedata.SelfPowered = (short)(ee4232h.SelfPowered ? 1 : 0); + eedata.RemoteWakeup = (short)(ee4232h.RemoteWakeup ? 1 : 0); + // 4232H specific fields + eedata.PullDownEnable8 = Convert.ToByte(ee4232h.PullDownEnable); + eedata.SerNumEnable8 = Convert.ToByte(ee4232h.SerNumEnable); + eedata.ASlowSlew = Convert.ToByte(ee4232h.ASlowSlew); + eedata.ASchmittInput = Convert.ToByte(ee4232h.ASchmittInput); + eedata.ADriveCurrent = ee4232h.ADriveCurrent; + eedata.BSlowSlew = Convert.ToByte(ee4232h.BSlowSlew); + eedata.BSchmittInput = Convert.ToByte(ee4232h.BSchmittInput); + eedata.BDriveCurrent = ee4232h.BDriveCurrent; + eedata.CSlowSlew = Convert.ToByte(ee4232h.CSlowSlew); + eedata.CSchmittInput = Convert.ToByte(ee4232h.CSchmittInput); + eedata.CDriveCurrent = ee4232h.CDriveCurrent; + eedata.DSlowSlew = Convert.ToByte(ee4232h.DSlowSlew); + eedata.DSchmittInput = Convert.ToByte(ee4232h.DSchmittInput); + eedata.DDriveCurrent = ee4232h.DDriveCurrent; + eedata.ARIIsTXDEN = Convert.ToByte(ee4232h.ARIIsTXDEN); + eedata.BRIIsTXDEN = Convert.ToByte(ee4232h.BRIIsTXDEN); + eedata.CRIIsTXDEN = Convert.ToByte(ee4232h.CRIIsTXDEN); + eedata.DRIIsTXDEN = Convert.ToByte(ee4232h.DRIIsTXDEN); + eedata.AIsVCP8 = Convert.ToByte(ee4232h.AIsVCP); + eedata.BIsVCP8 = Convert.ToByte(ee4232h.BIsVCP); + eedata.CIsVCP8 = Convert.ToByte(ee4232h.CIsVCP); + eedata.DIsVCP8 = Convert.ToByte(ee4232h.DIsVCP); + + // Call FT_EE_Program + ftStatus = FT_EE_Program(_ftHandle, eedata); + + // Free unmanaged buffers + Marshal.FreeHGlobal(eedata.Manufacturer); + Marshal.FreeHGlobal(eedata.ManufacturerID); + Marshal.FreeHGlobal(eedata.Description); + Marshal.FreeHGlobal(eedata.SerialNumber); + } + } + else + { + if (pFT_EE_Program == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_EE_Program."); + } + } + return ftStatus; + } + + /// + /// Writes the specified values to the EEPROM of an FT232H device. + /// Calls FT_EE_Program in FTD2XX DLL + /// + /// FT_STATUS value from FT_EE_Program in FTD2XX DLL + /// The EEPROM settings to be written to the device + /// If the strings are too long, they will be truncated to their maximum permitted lengths + /// Thrown when the current device does not match the type required by this method. + public FT_STATUS WriteFT232HEEPROM(FT232H_EEPROM_STRUCTURE ee232h) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + FT_ERROR ftErrorCondition = FT_ERROR.FT_NO_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_EE_Program != IntPtr.Zero) + { + tFT_EE_Program FT_EE_Program = (tFT_EE_Program)Marshal.GetDelegateForFunctionPointer(pFT_EE_Program, typeof(tFT_EE_Program)); + + if (_ftHandle != IntPtr.Zero) + { + FT_DEVICE DeviceType = FT_DEVICE.FT_DEVICE_UNKNOWN; + // Check that it is an FT232H that we are trying to write + GetDeviceType(ref DeviceType); + if (DeviceType != FT_DEVICE.FT_DEVICE_232H) + { + // If it is not, throw an exception + ftErrorCondition = FT_ERROR.FT_INCORRECT_DEVICE; + ThrowIfNotOK(ftStatus, ftErrorCondition); + } + + // Check for VID and PID of 0x0000 + if ((ee232h.VendorID == 0x0000) | (ee232h.ProductID == 0x0000)) + { + // Do not allow users to program the device with VID or PID of 0x0000 + return FT_STATUS.FT_INVALID_PARAMETER; + } + + FT_PROGRAM_DATA eedata = new() + { + // Set up structure headers + Signature1 = 0x00000000, + Signature2 = -1, + Version = 5, + + // Allocate space from unmanaged heap + Manufacturer = Marshal.AllocHGlobal(32), + ManufacturerID = Marshal.AllocHGlobal(16), + Description = Marshal.AllocHGlobal(64), + SerialNumber = Marshal.AllocHGlobal(16) + }; + + // Check lengths of strings to make sure that they are within our limits + // If not, trim them to make them our maximum length + if (ee232h.Manufacturer.Length > 32) + ee232h.Manufacturer = ee232h.Manufacturer.Substring(0, 32); + if (ee232h.ManufacturerID.Length > 16) + ee232h.ManufacturerID = ee232h.ManufacturerID.Substring(0, 16); + if (ee232h.Description.Length > 64) + ee232h.Description = ee232h.Description.Substring(0, 64); + if (ee232h.SerialNumber.Length > 16) + ee232h.SerialNumber = ee232h.SerialNumber.Substring(0, 16); + + // Set string values + eedata.Manufacturer = Marshal.StringToHGlobalAnsi(ee232h.Manufacturer); + eedata.ManufacturerID = Marshal.StringToHGlobalAnsi(ee232h.ManufacturerID); + eedata.Description = Marshal.StringToHGlobalAnsi(ee232h.Description); + eedata.SerialNumber = Marshal.StringToHGlobalAnsi(ee232h.SerialNumber); + + // Map non-string elements to structure + // Standard elements + eedata.VendorID = ee232h.VendorID; + eedata.ProductID = ee232h.ProductID; + eedata.MaxPower = ee232h.MaxPower; + eedata.SelfPowered = (short)(ee232h.SelfPowered ? 1 : 0); + eedata.RemoteWakeup = (short)(ee232h.RemoteWakeup ? 1 : 0); + // 232H specific fields + eedata.PullDownEnableH = Convert.ToByte(ee232h.PullDownEnable); + eedata.SerNumEnableH = Convert.ToByte(ee232h.SerNumEnable); + eedata.ACSlowSlewH = Convert.ToByte(ee232h.ACSlowSlew); + eedata.ACSchmittInputH = Convert.ToByte(ee232h.ACSchmittInput); + eedata.ACDriveCurrentH = Convert.ToByte(ee232h.ACDriveCurrent); + eedata.ADSlowSlewH = Convert.ToByte(ee232h.ADSlowSlew); + eedata.ADSchmittInputH = Convert.ToByte(ee232h.ADSchmittInput); + eedata.ADDriveCurrentH = Convert.ToByte(ee232h.ADDriveCurrent); + eedata.Cbus0H = Convert.ToByte(ee232h.Cbus0); + eedata.Cbus1H = Convert.ToByte(ee232h.Cbus1); + eedata.Cbus2H = Convert.ToByte(ee232h.Cbus2); + eedata.Cbus3H = Convert.ToByte(ee232h.Cbus3); + eedata.Cbus4H = Convert.ToByte(ee232h.Cbus4); + eedata.Cbus5H = Convert.ToByte(ee232h.Cbus5); + eedata.Cbus6H = Convert.ToByte(ee232h.Cbus6); + eedata.Cbus7H = Convert.ToByte(ee232h.Cbus7); + eedata.Cbus8H = Convert.ToByte(ee232h.Cbus8); + eedata.Cbus9H = Convert.ToByte(ee232h.Cbus9); + eedata.IsFifoH = Convert.ToByte(ee232h.IsFifo); + eedata.IsFifoTarH = Convert.ToByte(ee232h.IsFifoTar); + eedata.IsFastSerH = Convert.ToByte(ee232h.IsFastSer); + eedata.IsFT1248H = Convert.ToByte(ee232h.IsFT1248); + eedata.FT1248CpolH = Convert.ToByte(ee232h.FT1248Cpol); + eedata.FT1248LsbH = Convert.ToByte(ee232h.FT1248Lsb); + eedata.FT1248FlowControlH = Convert.ToByte(ee232h.FT1248FlowControl); + eedata.IsVCPH = Convert.ToByte(ee232h.IsVCP); + eedata.PowerSaveEnableH = Convert.ToByte(ee232h.PowerSaveEnable); + + // Call FT_EE_Program + ftStatus = FT_EE_Program(_ftHandle, eedata); + + // Free unmanaged buffers + Marshal.FreeHGlobal(eedata.Manufacturer); + Marshal.FreeHGlobal(eedata.ManufacturerID); + Marshal.FreeHGlobal(eedata.Description); + Marshal.FreeHGlobal(eedata.SerialNumber); + } + } + else + { + if (pFT_EE_Program == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_EE_Program."); + } + } + return ftStatus; + } + + /// + /// Writes the specified values to the EEPROM of an X-Series device. + /// Calls FT_EEPROM_Program in FTD2XX DLL + /// + /// FT_STATUS value from FT_EEPROM_Program in FTD2XX DLL + /// The EEPROM settings to be written to the device + /// If the strings are too long, they will be truncated to their maximum permitted lengths + /// Thrown when the current device does not match the type required by this method. + public FT_STATUS WriteXSeriesEEPROM(FTX_EEPROM_STRUCTURE eeX) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + FT_ERROR ftErrorCondition = FT_ERROR.FT_NO_ERROR; + + byte[] manufacturer, manufacturerID, description, serialNumber; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_EEPROM_Program != IntPtr.Zero) + { + tFT_EEPROM_Program FT_EEPROM_Program = (tFT_EEPROM_Program)Marshal.GetDelegateForFunctionPointer(pFT_EEPROM_Program, typeof(tFT_EEPROM_Program)); + + if (_ftHandle != IntPtr.Zero) + { + FT_DEVICE DeviceType = FT_DEVICE.FT_DEVICE_UNKNOWN; + // Check that it is an FT232H that we are trying to write + GetDeviceType(ref DeviceType); + if (DeviceType != FT_DEVICE.FT_DEVICE_X_SERIES) + { + // If it is not, throw an exception + ftErrorCondition = FT_ERROR.FT_INCORRECT_DEVICE; + ThrowIfNotOK(ftStatus, ftErrorCondition); + } + + // Check for VID and PID of 0x0000 + if ((eeX.VendorID == 0x0000) | (eeX.ProductID == 0x0000)) + { + // Do not allow users to program the device with VID or PID of 0x0000 + return FT_STATUS.FT_INVALID_PARAMETER; + } + + FT_XSERIES_DATA eeData = new(); + + // String manipulation... + // Allocate space from unmanaged heap + manufacturer = new byte[32]; + manufacturerID = new byte[16]; + description = new byte[64]; + serialNumber = new byte[16]; + + // Check lengths of strings to make sure that they are within our limits + // If not, trim them to make them our maximum length + if (eeX.Manufacturer.Length > 32) + eeX.Manufacturer = eeX.Manufacturer.Substring(0, 32); + if (eeX.ManufacturerID.Length > 16) + eeX.ManufacturerID = eeX.ManufacturerID.Substring(0, 16); + if (eeX.Description.Length > 64) + eeX.Description = eeX.Description.Substring(0, 64); + if (eeX.SerialNumber.Length > 16) + eeX.SerialNumber = eeX.SerialNumber.Substring(0, 16); + + // Set string values + System.Text.UTF8Encoding encoding = new(); + manufacturer = encoding.GetBytes(eeX.Manufacturer); + manufacturerID = encoding.GetBytes(eeX.ManufacturerID); + description = encoding.GetBytes(eeX.Description); + serialNumber = encoding.GetBytes(eeX.SerialNumber); + + // Map non-string elements to structure to be returned + // Standard elements + eeData.common.deviceType = (int)FT_DEVICE.FT_DEVICE_X_SERIES; + eeData.common.VendorId = eeX.VendorID; + eeData.common.ProductId = eeX.ProductID; + eeData.common.MaxPower = eeX.MaxPower; + eeData.common.SelfPowered = Convert.ToByte(eeX.SelfPowered); + eeData.common.RemoteWakeup = Convert.ToByte(eeX.RemoteWakeup); + eeData.common.SerNumEnable = Convert.ToByte(eeX.SerNumEnable); + eeData.common.PullDownEnable = Convert.ToByte(eeX.PullDownEnable); + // X-Series specific fields + // CBUS + eeData.Cbus0 = eeX.Cbus0; + eeData.Cbus1 = eeX.Cbus1; + eeData.Cbus2 = eeX.Cbus2; + eeData.Cbus3 = eeX.Cbus3; + eeData.Cbus4 = eeX.Cbus4; + eeData.Cbus5 = eeX.Cbus5; + eeData.Cbus6 = eeX.Cbus6; + // Drive Options + eeData.ACDriveCurrent = eeX.ACDriveCurrent; + eeData.ACSchmittInput = eeX.ACSchmittInput; + eeData.ACSlowSlew = eeX.ACSlowSlew; + eeData.ADDriveCurrent = eeX.ADDriveCurrent; + eeData.ADSchmittInput = eeX.ADSchmittInput; + eeData.ADSlowSlew = eeX.ADSlowSlew; + // BCD + eeData.BCDDisableSleep = eeX.BCDDisableSleep; + eeData.BCDEnable = eeX.BCDEnable; + eeData.BCDForceCbusPWREN = eeX.BCDForceCbusPWREN; + // FT1248 + eeData.FT1248Cpol = eeX.FT1248Cpol; + eeData.FT1248FlowControl = eeX.FT1248FlowControl; + eeData.FT1248Lsb = eeX.FT1248Lsb; + // I2C + eeData.I2CDeviceId = eeX.I2CDeviceId; + eeData.I2CDisableSchmitt = eeX.I2CDisableSchmitt; + eeData.I2CSlaveAddress = eeX.I2CSlaveAddress; + // RS232 Signals + eeData.InvertCTS = eeX.InvertCTS; + eeData.InvertDCD = eeX.InvertDCD; + eeData.InvertDSR = eeX.InvertDSR; + eeData.InvertDTR = eeX.InvertDTR; + eeData.InvertRI = eeX.InvertRI; + eeData.InvertRTS = eeX.InvertRTS; + eeData.InvertRXD = eeX.InvertRXD; + eeData.InvertTXD = eeX.InvertTXD; + // Hardware Options + eeData.PowerSaveEnable = eeX.PowerSaveEnable; + eeData.RS485EchoSuppress = eeX.RS485EchoSuppress; + // Driver Option + eeData.DriverType = eeX.IsVCP; + + // Check the size of the structure... + int size = Marshal.SizeOf(eeData); + // Allocate space for our pointer... + IntPtr eeDataMarshal = Marshal.AllocHGlobal(size); + Marshal.StructureToPtr(eeData, eeDataMarshal, false); + + ftStatus = FT_EEPROM_Program(_ftHandle, eeDataMarshal, size, manufacturer, manufacturerID, description, serialNumber); + } + } + + return ftStatus; + } + + /// + /// Reads data from the user area of the device EEPROM. + /// + /// FT_STATUS from FT_UARead in FTD2XX.DLL + /// An array of bytes which will be populated with the data read from the device EEPROM user area. + /// The number of bytes actually read from the EEPROM user area. + public FT_STATUS EEReadUserArea(byte[] UserAreaDataBuffer, ref int numBytesRead) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if ((pFT_EE_UASize != IntPtr.Zero) & (pFT_EE_UARead != IntPtr.Zero)) + { + tFT_EE_UASize FT_EE_UASize = (tFT_EE_UASize)Marshal.GetDelegateForFunctionPointer(pFT_EE_UASize, typeof(tFT_EE_UASize)); + tFT_EE_UARead FT_EE_UARead = (tFT_EE_UARead)Marshal.GetDelegateForFunctionPointer(pFT_EE_UARead, typeof(tFT_EE_UARead)); + + if (_ftHandle != IntPtr.Zero) + { + int UASize = 0; + // Get size of user area to allocate an array of the correct size. + // The application must also get the UA size for its copy + ftStatus = FT_EE_UASize(_ftHandle, ref UASize); + + // Make sure we have enough storage for the whole user area + if (UserAreaDataBuffer.Length >= UASize) + { + // Call FT_EE_UARead + ftStatus = FT_EE_UARead(_ftHandle, UserAreaDataBuffer, UserAreaDataBuffer.Length, ref numBytesRead); + } + } + } + else + { + if (pFT_EE_UASize == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_EE_UASize."); + } + if (pFT_EE_UARead == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_EE_UARead."); + } + } + return ftStatus; + } + + /// + /// Writes data to the user area of the device EEPROM. + /// + /// FT_STATUS value from FT_UAWrite in FTD2XX.DLL + /// An array of bytes which will be written to the device EEPROM user area. + public FT_STATUS EEWriteUserArea(byte[] UserAreaDataBuffer) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if ((pFT_EE_UASize != IntPtr.Zero) & (pFT_EE_UAWrite != IntPtr.Zero)) + { + tFT_EE_UASize FT_EE_UASize = (tFT_EE_UASize)Marshal.GetDelegateForFunctionPointer(pFT_EE_UASize, typeof(tFT_EE_UASize)); + tFT_EE_UAWrite FT_EE_UAWrite = (tFT_EE_UAWrite)Marshal.GetDelegateForFunctionPointer(pFT_EE_UAWrite, typeof(tFT_EE_UAWrite)); + + if (_ftHandle != IntPtr.Zero) + { + int UASize = 0; + // Get size of user area to allocate an array of the correct size. + // The application must also get the UA size for its copy + ftStatus = FT_EE_UASize(_ftHandle, ref UASize); + + // Make sure we have enough storage for all the data in the EEPROM + if (UserAreaDataBuffer.Length <= UASize) + { + // Call FT_EE_UAWrite + ftStatus = FT_EE_UAWrite(_ftHandle, UserAreaDataBuffer, UserAreaDataBuffer.Length); + } + } + } + else + { + if (pFT_EE_UASize == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_EE_UASize."); + } + if (pFT_EE_UAWrite == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_EE_UAWrite."); + } + } + return ftStatus; + } + + /// + /// Gets the chip type of the current device. + /// + /// FT_STATUS value from FT_GetDeviceInfo in FTD2XX.DLL + /// The FTDI chip type of the current device. + public FT_STATUS GetDeviceType(ref FT_DEVICE DeviceType) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_GetDeviceInfo != IntPtr.Zero) + { + tFT_GetDeviceInfo FT_GetDeviceInfo = (tFT_GetDeviceInfo)Marshal.GetDelegateForFunctionPointer(pFT_GetDeviceInfo, typeof(tFT_GetDeviceInfo)); + + int DeviceID = 0; + byte[] sernum = new byte[16]; + byte[] desc = new byte[64]; + + DeviceType = FT_DEVICE.FT_DEVICE_UNKNOWN; + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_GetDeviceInfo + ftStatus = FT_GetDeviceInfo(_ftHandle, ref DeviceType, ref DeviceID, sernum, desc, IntPtr.Zero); + } + } + else + { + if (pFT_GetDeviceInfo == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_GetDeviceInfo."); + } + } + return ftStatus; + } + + /// + /// Gets the Vendor ID and Product ID of the current device. + /// + /// FT_STATUS value from FT_GetDeviceInfo in FTD2XX.DLL + /// The device ID (Vendor ID and Product ID) of the current device. + public FT_STATUS GetDeviceID(ref int DeviceID) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_GetDeviceInfo != IntPtr.Zero) + { + tFT_GetDeviceInfo FT_GetDeviceInfo = (tFT_GetDeviceInfo)Marshal.GetDelegateForFunctionPointer(pFT_GetDeviceInfo, typeof(tFT_GetDeviceInfo)); + + FT_DEVICE DeviceType = FT_DEVICE.FT_DEVICE_UNKNOWN; + byte[] sernum = new byte[16]; + byte[] desc = new byte[64]; + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_GetDeviceInfo + ftStatus = FT_GetDeviceInfo(_ftHandle, ref DeviceType, ref DeviceID, sernum, desc, IntPtr.Zero); + } + } + else + { + if (pFT_GetDeviceInfo == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_GetDeviceInfo."); + } + } + return ftStatus; + } + + /// + /// Gets the description of the current device. + /// + /// FT_STATUS value from FT_GetDeviceInfo in FTD2XX.DLL + /// The description of the current device. + public FT_STATUS GetDescription(out string Description) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + Description = String.Empty; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + + // Check for our required function pointers being set up + if (pFT_GetDeviceInfo != IntPtr.Zero) + { + tFT_GetDeviceInfo FT_GetDeviceInfo = (tFT_GetDeviceInfo)Marshal.GetDelegateForFunctionPointer(pFT_GetDeviceInfo, typeof(tFT_GetDeviceInfo)); + + int DeviceID = 0; + FT_DEVICE DeviceType = FT_DEVICE.FT_DEVICE_UNKNOWN; + byte[] sernum = new byte[16]; + byte[] desc = new byte[64]; + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_GetDeviceInfo + ftStatus = FT_GetDeviceInfo(_ftHandle, ref DeviceType, ref DeviceID, sernum, desc, IntPtr.Zero); + Description = Encoding.ASCII.GetString(desc); + Description = Description.Substring(0, Description.IndexOf('\0')); + } + } + else + { + if (pFT_GetDeviceInfo == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_GetDeviceInfo."); + } + } + return ftStatus; + } + + /// + /// Gets the serial number of the current device. + /// + /// FT_STATUS value from FT_GetDeviceInfo in FTD2XX.DLL + /// The serial number of the current device. + public FT_STATUS GetSerialNumber(out string SerialNumber) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + SerialNumber = String.Empty; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + + // Check for our required function pointers being set up + if (pFT_GetDeviceInfo != IntPtr.Zero) + { + tFT_GetDeviceInfo FT_GetDeviceInfo = (tFT_GetDeviceInfo)Marshal.GetDelegateForFunctionPointer(pFT_GetDeviceInfo, typeof(tFT_GetDeviceInfo)); + + int DeviceID = 0; + FT_DEVICE DeviceType = FT_DEVICE.FT_DEVICE_UNKNOWN; + byte[] sernum = new byte[16]; + byte[] desc = new byte[64]; + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_GetDeviceInfo + ftStatus = FT_GetDeviceInfo(_ftHandle, ref DeviceType, ref DeviceID, sernum, desc, IntPtr.Zero); + SerialNumber = Encoding.ASCII.GetString(sernum); + SerialNumber = SerialNumber.Substring(0, SerialNumber.IndexOf('\0')); + } + } + else + { + if (pFT_GetDeviceInfo == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_GetDeviceInfo."); + } + } + return ftStatus; + } + + /// + /// Gets the number of bytes available in the receive buffer. + /// + /// FT_STATUS value from FT_GetQueueStatus in FTD2XX.DLL + /// The number of bytes available to be read. + public FT_STATUS GetRxBytesAvailable(ref int RxQueue) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_GetQueueStatus != IntPtr.Zero) + { + tFT_GetQueueStatus FT_GetQueueStatus = (tFT_GetQueueStatus)Marshal.GetDelegateForFunctionPointer(pFT_GetQueueStatus, typeof(tFT_GetQueueStatus)); + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_GetQueueStatus + ftStatus = FT_GetQueueStatus(_ftHandle, ref RxQueue); + } + } + else + { + if (pFT_GetQueueStatus == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_GetQueueStatus."); + } + } + return ftStatus; + } + + /// + /// Gets the number of bytes waiting in the transmit buffer. + /// + /// FT_STATUS value from FT_GetStatus in FTD2XX.DLL + /// The number of bytes waiting to be sent. + public FT_STATUS GetTxBytesWaiting(ref int TxQueue) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_GetStatus != IntPtr.Zero) + { + tFT_GetStatus FT_GetStatus = (tFT_GetStatus)Marshal.GetDelegateForFunctionPointer(pFT_GetStatus, typeof(tFT_GetStatus)); + + int RxQueue = 0; + int EventStatus = 0; + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_GetStatus + ftStatus = FT_GetStatus(_ftHandle, ref RxQueue, ref TxQueue, ref EventStatus); + } + } + else + { + if (pFT_GetStatus == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_GetStatus."); + } + } + return ftStatus; + } + + /// + /// Gets the event type after an event has fired. Can be used to distinguish which event has been triggered when waiting on multiple event types. + /// + /// FT_STATUS value from FT_GetStatus in FTD2XX.DLL + /// The type of event that has occurred. + public FT_STATUS GetEventType(ref int EventType) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_GetStatus != IntPtr.Zero) + { + tFT_GetStatus FT_GetStatus = (tFT_GetStatus)Marshal.GetDelegateForFunctionPointer(pFT_GetStatus, typeof(tFT_GetStatus)); + + int RxQueue = 0; + int TxQueue = 0; + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_GetStatus + ftStatus = FT_GetStatus(_ftHandle, ref RxQueue, ref TxQueue, ref EventType); + } + } + else + { + if (pFT_GetStatus == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_GetStatus."); + } + } + return ftStatus; + } + + /// + /// Gets the current modem status. + /// + /// FT_STATUS value from FT_GetModemStatus in FTD2XX.DLL + /// A bit map representaion of the current modem status. + public FT_STATUS GetModemStatus(ref byte ModemStatus) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_GetModemStatus != IntPtr.Zero) + { + tFT_GetModemStatus FT_GetModemStatus = (tFT_GetModemStatus)Marshal.GetDelegateForFunctionPointer(pFT_GetModemStatus, typeof(tFT_GetModemStatus)); + + int ModemLineStatus = 0; + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_GetModemStatus + ftStatus = FT_GetModemStatus(_ftHandle, ref ModemLineStatus); + + } + ModemStatus = Convert.ToByte(ModemLineStatus & 0x000000FF); + } + else + { + if (pFT_GetModemStatus == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_GetModemStatus."); + } + } + return ftStatus; + } + + /// + /// Gets the current line status. + /// + /// FT_STATUS value from FT_GetModemStatus in FTD2XX.DLL + /// A bit map representaion of the current line status. + public FT_STATUS GetLineStatus(ref byte LineStatus) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_GetModemStatus != IntPtr.Zero) + { + tFT_GetModemStatus FT_GetModemStatus = (tFT_GetModemStatus)Marshal.GetDelegateForFunctionPointer(pFT_GetModemStatus, typeof(tFT_GetModemStatus)); + + int ModemLineStatus = 0; + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_GetModemStatus + ftStatus = FT_GetModemStatus(_ftHandle, ref ModemLineStatus); + } + LineStatus = Convert.ToByte((ModemLineStatus >> 8) & 0x000000FF); + } + else + { + if (pFT_GetModemStatus == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_GetModemStatus."); + } + } + return ftStatus; + } + + /// + /// Sets the current Baud rate. + /// + /// FT_STATUS value from FT_SetBaudRate in FTD2XX.DLL + /// The desired Baud rate for the device. + public FT_STATUS SetBaudRate(int BaudRate) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_SetBaudRate != IntPtr.Zero) + { + tFT_SetBaudRate FT_SetBaudRate = (tFT_SetBaudRate)Marshal.GetDelegateForFunctionPointer(pFT_SetBaudRate, typeof(tFT_SetBaudRate)); + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_SetBaudRate + ftStatus = FT_SetBaudRate(_ftHandle, BaudRate); + } + } + else + { + if (pFT_SetBaudRate == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_SetBaudRate."); + } + } + return ftStatus; + } + + /// + /// Sets the data bits, stop bits and parity for the device. + /// + /// FT_STATUS value from FT_SetDataCharacteristics in FTD2XX.DLL + /// The number of data bits for UART data. Valid values are FT_DATA_BITS.FT_DATA_7 or FT_DATA_BITS.FT_BITS_8 + /// The number of stop bits for UART data. Valid values are FT_STOP_BITS.FT_STOP_BITS_1 or FT_STOP_BITS.FT_STOP_BITS_2 + /// The parity of the UART data. Valid values are FT_PARITY.FT_PARITY_NONE, FT_PARITY.FT_PARITY_ODD, FT_PARITY.FT_PARITY_EVEN, FT_PARITY.FT_PARITY_MARK or FT_PARITY.FT_PARITY_SPACE + public FT_STATUS SetDataCharacteristics(byte DataBits, byte StopBits, byte Parity) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_SetDataCharacteristics != IntPtr.Zero) + { + tFT_SetDataCharacteristics FT_SetDataCharacteristics = (tFT_SetDataCharacteristics)Marshal.GetDelegateForFunctionPointer(pFT_SetDataCharacteristics, typeof(tFT_SetDataCharacteristics)); + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_SetDataCharacteristics + ftStatus = FT_SetDataCharacteristics(_ftHandle, DataBits, StopBits, Parity); + } + } + else + { + if (pFT_SetDataCharacteristics == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_SetDataCharacteristics."); + } + } + return ftStatus; + } + + /// + /// Sets the flow control type. + /// + /// FT_STATUS value from FT_SetFlowControl in FTD2XX.DLL + /// The type of flow control for the UART. Valid values are FT_FLOW_CONTROL.FT_FLOW_NONE, FT_FLOW_CONTROL.FT_FLOW_RTS_CTS, FT_FLOW_CONTROL.FT_FLOW_DTR_DSR or FT_FLOW_CONTROL.FT_FLOW_XON_XOFF + /// The Xon character for Xon/Xoff flow control. Ignored if not using Xon/XOff flow control. + /// The Xoff character for Xon/Xoff flow control. Ignored if not using Xon/XOff flow control. + public FT_STATUS SetFlowControl(short FlowControl, byte Xon, byte Xoff) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_SetFlowControl != IntPtr.Zero) + { + tFT_SetFlowControl FT_SetFlowControl = (tFT_SetFlowControl)Marshal.GetDelegateForFunctionPointer(pFT_SetFlowControl, typeof(tFT_SetFlowControl)); + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_SetFlowControl + ftStatus = FT_SetFlowControl(_ftHandle, FlowControl, Xon, Xoff); + } + } + else + { + if (pFT_SetFlowControl == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_SetFlowControl."); + } + } + return ftStatus; + } + + /// + /// Asserts or de-asserts the Request To Send (RTS) line. + /// + /// FT_STATUS value from FT_SetRts or FT_ClrRts in FTD2XX.DLL + /// If true, asserts RTS. If false, de-asserts RTS + public FT_STATUS SetRTS(bool Enable) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if ((pFT_SetRts != IntPtr.Zero) & (pFT_ClrRts != IntPtr.Zero)) + { + tFT_SetRts FT_SetRts = (tFT_SetRts)Marshal.GetDelegateForFunctionPointer(pFT_SetRts, typeof(tFT_SetRts)); + tFT_ClrRts FT_ClrRts = (tFT_ClrRts)Marshal.GetDelegateForFunctionPointer(pFT_ClrRts, typeof(tFT_ClrRts)); + + if (_ftHandle != IntPtr.Zero) + { + if (Enable) + { + // Call FT_SetRts + ftStatus = FT_SetRts(_ftHandle); + } + else + { + // Call FT_ClrRts + ftStatus = FT_ClrRts(_ftHandle); + } + } + } + else + { + if (pFT_SetRts == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_SetRts."); + } + if (pFT_ClrRts == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_ClrRts."); + } + } + return ftStatus; + } + + /// + /// Asserts or de-asserts the Data Terminal Ready (DTR) line. + /// + /// FT_STATUS value from FT_SetDtr or FT_ClrDtr in FTD2XX.DLL + /// If true, asserts DTR. If false, de-asserts DTR. + public FT_STATUS SetDTR(bool Enable) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if ((pFT_SetDtr != IntPtr.Zero) & (pFT_ClrDtr != IntPtr.Zero)) + { + tFT_SetDtr FT_SetDtr = (tFT_SetDtr)Marshal.GetDelegateForFunctionPointer(pFT_SetDtr, typeof(tFT_SetDtr)); + tFT_ClrDtr FT_ClrDtr = (tFT_ClrDtr)Marshal.GetDelegateForFunctionPointer(pFT_ClrDtr, typeof(tFT_ClrDtr)); + + if (_ftHandle != IntPtr.Zero) + { + if (Enable) + { + // Call FT_SetDtr + ftStatus = FT_SetDtr(_ftHandle); + } + else + { + // Call FT_ClrDtr + ftStatus = FT_ClrDtr(_ftHandle); + } + } + } + else + { + if (pFT_SetDtr == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_SetDtr."); + } + if (pFT_ClrDtr == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_ClrDtr."); + } + } + return ftStatus; + } + + /// + /// Sets the read and write timeout values. + /// + /// FT_STATUS value from FT_SetTimeouts in FTD2XX.DLL + /// Read timeout value in ms. A value of 0 indicates an infinite timeout. + /// Write timeout value in ms. A value of 0 indicates an infinite timeout. + public FT_STATUS SetTimeouts(int ReadTimeout, int WriteTimeout) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_SetTimeouts != IntPtr.Zero) + { + tFT_SetTimeouts FT_SetTimeouts = (tFT_SetTimeouts)Marshal.GetDelegateForFunctionPointer(pFT_SetTimeouts, typeof(tFT_SetTimeouts)); + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_SetTimeouts + ftStatus = FT_SetTimeouts(_ftHandle, ReadTimeout, WriteTimeout); + } + } + else + { + if (pFT_SetTimeouts == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_SetTimeouts."); + } + } + return ftStatus; + } + + /// + /// Sets or clears the break state. + /// + /// FT_STATUS value from FT_SetBreakOn or FT_SetBreakOff in FTD2XX.DLL + /// If true, sets break on. If false, sets break off. + public FT_STATUS SetBreak(bool Enable) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if ((pFT_SetBreakOn != IntPtr.Zero) & (pFT_SetBreakOff != IntPtr.Zero)) + { + tFT_SetBreakOn FT_SetBreakOn = (tFT_SetBreakOn)Marshal.GetDelegateForFunctionPointer(pFT_SetBreakOn, typeof(tFT_SetBreakOn)); + tFT_SetBreakOff FT_SetBreakOff = (tFT_SetBreakOff)Marshal.GetDelegateForFunctionPointer(pFT_SetBreakOff, typeof(tFT_SetBreakOff)); + + if (_ftHandle != IntPtr.Zero) + { + if (Enable) + { + // Call FT_SetBreakOn + ftStatus = FT_SetBreakOn(_ftHandle); + } + else + { + // Call FT_SetBreakOff + ftStatus = FT_SetBreakOff(_ftHandle); + } + } + } + else + { + if (pFT_SetBreakOn == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_SetBreakOn."); + } + if (pFT_SetBreakOff == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_SetBreakOff."); + } + } + return ftStatus; + } + + /// + /// Gets or sets the reset pipe retry count. Default value is 50. + /// + /// FT_STATUS vlaue from FT_SetResetPipeRetryCount in FTD2XX.DLL + /// The reset pipe retry count. + /// Electrically noisy environments may benefit from a larger value. + public FT_STATUS SetResetPipeRetryCount(int ResetPipeRetryCount) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_SetResetPipeRetryCount != IntPtr.Zero) + { + tFT_SetResetPipeRetryCount FT_SetResetPipeRetryCount = (tFT_SetResetPipeRetryCount)Marshal.GetDelegateForFunctionPointer(pFT_SetResetPipeRetryCount, typeof(tFT_SetResetPipeRetryCount)); + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_SetResetPipeRetryCount + ftStatus = FT_SetResetPipeRetryCount(_ftHandle, ResetPipeRetryCount); + } + } + else + { + if (pFT_SetResetPipeRetryCount == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_SetResetPipeRetryCount."); + } + } + return ftStatus; + } + + /// + /// Gets the current FTDIBUS.SYS driver version number. + /// + /// FT_STATUS value from FT_GetDriverVersion in FTD2XX.DLL + /// The current driver version number. + public FT_STATUS GetDriverVersion(ref int DriverVersion) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_GetDriverVersion != IntPtr.Zero) + { + tFT_GetDriverVersion FT_GetDriverVersion = (tFT_GetDriverVersion)Marshal.GetDelegateForFunctionPointer(pFT_GetDriverVersion, typeof(tFT_GetDriverVersion)); + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_GetDriverVersion + ftStatus = FT_GetDriverVersion(_ftHandle, ref DriverVersion); + } + } + else + { + if (pFT_GetDriverVersion == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_GetDriverVersion."); + } + } + return ftStatus; + } + + /// + /// Gets the current FTD2XX.DLL driver version number. + /// + /// FT_STATUS value from FT_GetLibraryVersion in FTD2XX.DLL + /// The current library version. + public FT_STATUS GetLibraryVersion(ref int LibraryVersion) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_GetLibraryVersion != IntPtr.Zero) + { + tFT_GetLibraryVersion FT_GetLibraryVersion = (tFT_GetLibraryVersion)Marshal.GetDelegateForFunctionPointer(pFT_GetLibraryVersion, typeof(tFT_GetLibraryVersion)); + + // Call FT_GetLibraryVersion + ftStatus = FT_GetLibraryVersion(ref LibraryVersion); + } + else + { + if (pFT_GetLibraryVersion == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_GetLibraryVersion."); + } + } + return ftStatus; + } + + /// + /// Sets the USB deadman timeout value. Default is 5000ms. + /// + /// FT_STATUS value from FT_SetDeadmanTimeout in FTD2XX.DLL + /// The deadman timeout value in ms. Default is 5000ms. + public FT_STATUS SetDeadmanTimeout(int DeadmanTimeout) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_SetDeadmanTimeout != IntPtr.Zero) + { + tFT_SetDeadmanTimeout FT_SetDeadmanTimeout = (tFT_SetDeadmanTimeout)Marshal.GetDelegateForFunctionPointer(pFT_SetDeadmanTimeout, typeof(tFT_SetDeadmanTimeout)); + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_SetDeadmanTimeout + ftStatus = FT_SetDeadmanTimeout(_ftHandle, DeadmanTimeout); + } + } + else + { + if (pFT_SetDeadmanTimeout == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_SetDeadmanTimeout."); + } + } + return ftStatus; + } + + /// + /// Sets the value of the latency timer. Default value is 16ms. + /// + /// FT_STATUS value from FT_SetLatencyTimer in FTD2XX.DLL + /// The latency timer value in ms. + /// Valid values are 2ms - 255ms for FT232BM, FT245BM and FT2232 devices. + /// Valid values are 0ms - 255ms for other devices. + public FT_STATUS SetLatency(byte Latency) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_SetLatencyTimer != IntPtr.Zero) + { + tFT_SetLatencyTimer FT_SetLatencyTimer = (tFT_SetLatencyTimer)Marshal.GetDelegateForFunctionPointer(pFT_SetLatencyTimer, typeof(tFT_SetLatencyTimer)); + + if (_ftHandle != IntPtr.Zero) + { + FT_DEVICE DeviceType = FT_DEVICE.FT_DEVICE_UNKNOWN; + // Set Bit Mode does not apply to FT8U232AM, FT8U245AM or FT8U100AX devices + GetDeviceType(ref DeviceType); + if ((DeviceType == FT_DEVICE.FT_DEVICE_BM) || (DeviceType == FT_DEVICE.FT_DEVICE_2232)) + { + // Do not allow latency of 1ms or 0ms for older devices + // since this can cause problems/lock up due to buffering mechanism + if (Latency < 2) + Latency = 2; + } + + // Call FT_SetLatencyTimer + ftStatus = FT_SetLatencyTimer(_ftHandle, Latency); + } + } + else + { + if (pFT_SetLatencyTimer == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_SetLatencyTimer."); + } + } + return ftStatus; + } + + /// + /// Gets the value of the latency timer. Default value is 16ms. + /// + /// FT_STATUS value from FT_GetLatencyTimer in FTD2XX.DLL + /// The latency timer value in ms. + public FT_STATUS GetLatency(ref byte Latency) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_GetLatencyTimer != IntPtr.Zero) + { + tFT_GetLatencyTimer FT_GetLatencyTimer = (tFT_GetLatencyTimer)Marshal.GetDelegateForFunctionPointer(pFT_GetLatencyTimer, typeof(tFT_GetLatencyTimer)); + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_GetLatencyTimer + ftStatus = FT_GetLatencyTimer(_ftHandle, ref Latency); + } + } + else + { + if (pFT_GetLatencyTimer == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_GetLatencyTimer."); + } + } + return ftStatus; + } + + /// + /// Sets the USB IN and OUT transfer sizes. + /// + /// FT_STATUS value from FT_SetUSBParameters in FTD2XX.DLL + /// The USB IN transfer size in bytes. + public FT_STATUS InTransferSize(int InTransferSize) + // Only support IN transfer sizes at the moment + //public int InTransferSize(int InTransferSize, int OutTransferSize) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_SetUSBParameters != IntPtr.Zero) + { + tFT_SetUSBParameters FT_SetUSBParameters = (tFT_SetUSBParameters)Marshal.GetDelegateForFunctionPointer(pFT_SetUSBParameters, typeof(tFT_SetUSBParameters)); + + int OutTransferSize = InTransferSize; + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_SetUSBParameters + ftStatus = FT_SetUSBParameters(_ftHandle, InTransferSize, OutTransferSize); + } + } + else + { + if (pFT_SetUSBParameters == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_SetUSBParameters."); + } + } + return ftStatus; + } + + /// + /// Sets an event character, an error character and enables or disables them. + /// + /// FT_STATUS value from FT_SetChars in FTD2XX.DLL + /// A character that will be tigger an IN to the host when this character is received. + /// Determines if the EventChar is enabled or disabled. + /// A character that will be inserted into the data stream to indicate that an error has occurred. + /// Determines if the ErrorChar is enabled or disabled. + public FT_STATUS SetCharacters(byte EventChar, bool EventCharEnable, byte ErrorChar, bool ErrorCharEnable) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_SetChars != IntPtr.Zero) + { + tFT_SetChars FT_SetChars = (tFT_SetChars)Marshal.GetDelegateForFunctionPointer(pFT_SetChars, typeof(tFT_SetChars)); + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_SetChars + ftStatus = FT_SetChars(_ftHandle, EventChar, Convert.ToByte(EventCharEnable), ErrorChar, Convert.ToByte(ErrorCharEnable)); + } + } + else + { + if (pFT_SetChars == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_SetChars."); + } + } + return ftStatus; + } + + /// + /// Gets the size of the EEPROM user area. + /// + /// FT_STATUS value from FT_EE_UASize in FTD2XX.DLL + /// The EEPROM user area size in bytes. + public FT_STATUS EEUserAreaSize(ref int UASize) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_EE_UASize != IntPtr.Zero) + { + tFT_EE_UASize FT_EE_UASize = (tFT_EE_UASize)Marshal.GetDelegateForFunctionPointer(pFT_EE_UASize, typeof(tFT_EE_UASize)); + + if (_ftHandle != IntPtr.Zero) + { + ftStatus = FT_EE_UASize(_ftHandle, ref UASize); + } + } + else + { + if (pFT_EE_UASize == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_EE_UASize."); + } + } + return ftStatus; + } + + /// + /// Gets the corresponding COM port number for the current device. If no COM port is exposed, an empty string is returned. + /// + /// FT_STATUS value from FT_GetComPortNumber in FTD2XX.DLL + /// The COM port name corresponding to the current device. If no COM port is installed, an empty string is passed back. + public FT_STATUS GetCOMPort(out string ComPortName) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // As ComPortName is an OUT paremeter, has to be assigned before returning + ComPortName = string.Empty; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_GetComPortNumber != IntPtr.Zero) + { + tFT_GetComPortNumber FT_GetComPortNumber = (tFT_GetComPortNumber)Marshal.GetDelegateForFunctionPointer(pFT_GetComPortNumber, typeof(tFT_GetComPortNumber)); + + int ComPortNumber = -1; + if (_ftHandle != IntPtr.Zero) + { + // Call FT_GetComPortNumber + ftStatus = FT_GetComPortNumber(_ftHandle, ref ComPortNumber); + } + + if (ComPortNumber == -1) + { + // If no COM port installed, return an empty string + ComPortName = string.Empty; + } + else + { + // If installed, return full COM string + // This can then be passed to an instance of the SerialPort class to assign the port number. + ComPortName = "COM" + ComPortNumber.ToString(); + } + } + else + { + if (pFT_GetComPortNumber == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_GetComPortNumber."); + } + } + return ftStatus; + } + + /// + /// Get data from the FT4222 using the vendor command interface. + /// + /// FT_STATUS value from FT_VendorCmdSet in FTD2XX.DLL + public FT_STATUS VendorCmdGet(short request, byte[] buf, short len) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_VendorCmdGet != IntPtr.Zero) + { + tFT_VendorCmdGet FT_VendorCmdGet = (tFT_VendorCmdGet)Marshal.GetDelegateForFunctionPointer(pFT_VendorCmdGet, typeof(tFT_VendorCmdGet)); + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_VendorCmdGet + ftStatus = FT_VendorCmdGet(_ftHandle, request, buf, len); + } + } + else + { + if (pFT_VendorCmdGet == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_VendorCmdGet."); + } + } + return ftStatus; + } + + /// + /// Set data from the FT4222 using the vendor command interface. + /// + /// FT_STATUS value from FT_VendorCmdSet in FTD2XX.DLL + public FT_STATUS VendorCmdSet(short request, byte[] buf, short len) + { + // Initialise ftStatus to something other than FT_OK + FT_STATUS ftStatus = FT_STATUS.FT_OTHER_ERROR; + + // If the DLL hasn't been loaded, just return here + if (hFTD2XXDLL == IntPtr.Zero) + return ftStatus; + + // Check for our required function pointers being set up + if (pFT_VendorCmdSet != IntPtr.Zero) + { + tFT_VendorCmdSet FT_VendorCmdSet = (tFT_VendorCmdSet)Marshal.GetDelegateForFunctionPointer(pFT_VendorCmdSet, typeof(tFT_VendorCmdSet)); + + if (_ftHandle != IntPtr.Zero) + { + // Call FT_VendorCmdSet + ftStatus = FT_VendorCmdSet(_ftHandle, request, buf, len); + } + } + else + { + if (pFT_VendorCmdSet == IntPtr.Zero) + { + ErrorMessageAction("Failed to load function FT_VendorCmdSet."); + } + } + return ftStatus; + } + + /// + /// Gets the open status of the device. + /// + public bool IsOpen + { + get + { + if (_ftHandle == IntPtr.Zero) + return false; + else + return true; + } + } + + /// + /// Gets the interface identifier. + /// + private string InterfaceIdentifier + { + get + { + string Identifier; + Identifier = String.Empty; + if (IsOpen) + { + FT_DEVICE deviceType = FT_DEVICE.FT_DEVICE_BM; + GetDeviceType(ref deviceType); + if (deviceType == FT_DEVICE.FT_DEVICE_2232H || + deviceType == FT_DEVICE.FT_DEVICE_4232H || + deviceType == FT_DEVICE.FT_DEVICE_2233HP || + deviceType == FT_DEVICE.FT_DEVICE_4233HP || + deviceType == FT_DEVICE.FT_DEVICE_2232HP || + deviceType == FT_DEVICE.FT_DEVICE_4232HP || + deviceType == FT_DEVICE.FT_DEVICE_2232HA || + deviceType == FT_DEVICE.FT_DEVICE_4232HA || + deviceType == FT_DEVICE.FT_DEVICE_2232) + { + string Description; + GetDescription(out Description); + Identifier = Description.Substring((Description.Length - 1)); + return Identifier; + } + } + return Identifier; + } + } + + /// + /// Method to check ftStatus and ftErrorCondition values for error conditions and throw exceptions accordingly. + /// + private void ThrowIfNotOK(FT_STATUS ftStatus, FT_ERROR ftErrorCondition) + { + ftStatus.ThrowIfNotOK(); + ftErrorCondition.ThrowIfNotOK(); + } + + /// + /// This function is invoked when this FTDI library produces a serious error. + /// Overwrite this to customize error reporting behavior. + /// + public Action ErrorMessageAction = ShowErrorMessageToConsole; + + private static void ShowErrorMessageToConsole(string message) + { + System.Diagnostics.Debug.WriteLine(message); + } + + public void FlushBuffer() + { + int BytesAvailable = 0; + GetRxBytesAvailable(ref BytesAvailable).ThrowIfNotOK(); + + if (BytesAvailable == 0) + return; + + byte[] buffer = new byte[BytesAvailable]; + int NumBytesRead = 0; + Read(buffer, BytesAvailable, ref NumBytesRead).ThrowIfNotOK(); + } +} diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_232H_CBUS_OPTIONS.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_232H_CBUS_OPTIONS.cs new file mode 100644 index 0000000000..4f4d03d804 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_232H_CBUS_OPTIONS.cs @@ -0,0 +1,72 @@ +namespace FTD2XX; + +/// +/// Available functions for the FT232H CBUS pins. Controlled by FT232H EEPROM settings +/// +public static class FT_232H_CBUS_OPTIONS +{ + /// + /// FT232H CBUS EEPROM options - Tristate + /// + public const byte FT_CBUS_TRISTATE = 0x00; + + /// + /// FT232H CBUS EEPROM options - Rx LED + /// + public const byte FT_CBUS_RXLED = 0x01; + + /// + /// FT232H CBUS EEPROM options - Tx LED + /// + public const byte FT_CBUS_TXLED = 0x02; + + /// + /// FT232H CBUS EEPROM options - Tx and Rx LED + /// + public const byte FT_CBUS_TXRXLED = 0x03; + + /// + /// FT232H CBUS EEPROM options - Power Enable# + /// + public const byte FT_CBUS_PWREN = 0x04; + + /// + /// FT232H CBUS EEPROM options - Sleep + /// + public const byte FT_CBUS_SLEEP = 0x05; + + /// + /// FT232H CBUS EEPROM options - Drive pin to logic 0 + /// + public const byte FT_CBUS_DRIVE_0 = 0x06; + + /// + /// FT232H CBUS EEPROM options - Drive pin to logic 1 + /// + public const byte FT_CBUS_DRIVE_1 = 0x07; + + /// + /// FT232H CBUS EEPROM options - IO Mode + /// + public const byte FT_CBUS_IOMODE = 0x08; + + /// + /// FT232H CBUS EEPROM options - Tx Data Enable + /// + public const byte FT_CBUS_TXDEN = 0x09; + + /// + /// FT232H CBUS EEPROM options - 30MHz clock + /// + public const byte FT_CBUS_CLK30 = 0x0A; + + /// + /// FT232H CBUS EEPROM options - 15MHz clock + /// + public const byte FT_CBUS_CLK15 = 0x0B; + + /// + /// FT232H CBUS EEPROM options - 7.5MHz clock + /// + public const byte FT_CBUS_CLK7_5 = 0x0C; +} \ No newline at end of file diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_BIT_MODES.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_BIT_MODES.cs new file mode 100644 index 0000000000..677ae44b32 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_BIT_MODES.cs @@ -0,0 +1,47 @@ +namespace FTD2XX; + +/// +/// Permitted bit mode values for FTDI devices. For use with SetBitMode +/// +public static class FT_BIT_MODES +{ + /// + /// Reset bit mode + /// + public const byte FT_BIT_MODE_RESET = 0x00; + + /// + /// Asynchronous bit-bang mode + /// + public const byte FT_BIT_MODE_ASYNC_BITBANG = 0x01; + + /// + /// MPSSE bit mode - only available on FT2232, FT2232H, FT4232H and FT232H + /// + public const byte FT_BIT_MODE_MPSSE = 0x02; + + /// + /// Synchronous bit-bang mode + /// + public const byte FT_BIT_MODE_SYNC_BITBANG = 0x04; + + /// + /// MCU host bus emulation mode - only available on FT2232, FT2232H, FT4232H and FT232H + /// + public const byte FT_BIT_MODE_MCU_HOST = 0x08; + + /// + /// Fast opto-isolated serial mode - only available on FT2232, FT2232H, FT4232H and FT232H + /// + public const byte FT_BIT_MODE_FAST_SERIAL = 0x10; + + /// + /// CBUS bit-bang mode - only available on FT232R and FT232H + /// + public const byte FT_BIT_MODE_CBUS_BITBANG = 0x20; + + /// + /// Single channel synchronous 245 FIFO mode - only available on FT2232H channel A and FT232H + /// + public const byte FT_BIT_MODE_SYNC_FIFO = 0x40; +} diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_CBUS_OPTIONS.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_CBUS_OPTIONS.cs new file mode 100644 index 0000000000..1df743eb3a --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_CBUS_OPTIONS.cs @@ -0,0 +1,72 @@ +namespace FTD2XX; + +/// +/// Available functions for the FT232R CBUS pins. Controlled by FT232R EEPROM settings +/// +public class FT_CBUS_OPTIONS +{ + /// + /// FT232R CBUS EEPROM options - Tx Data Enable + /// + public const byte FT_CBUS_TXDEN = 0x00; + + /// + /// FT232R CBUS EEPROM options - Power On + /// + public const byte FT_CBUS_PWRON = 0x01; + + /// + /// FT232R CBUS EEPROM options - Rx LED + /// + public const byte FT_CBUS_RXLED = 0x02; + + /// + /// FT232R CBUS EEPROM options - Tx LED + /// + public const byte FT_CBUS_TXLED = 0x03; + + /// + /// FT232R CBUS EEPROM options - Tx and Rx LED + /// + public const byte FT_CBUS_TXRXLED = 0x04; + + /// + /// FT232R CBUS EEPROM options - Sleep + /// + public const byte FT_CBUS_SLEEP = 0x05; + + /// + /// FT232R CBUS EEPROM options - 48MHz clock + /// + public const byte FT_CBUS_CLK48 = 0x06; + + /// + /// FT232R CBUS EEPROM options - 24MHz clock + /// + public const byte FT_CBUS_CLK24 = 0x07; + + /// + /// FT232R CBUS EEPROM options - 12MHz clock + /// + public const byte FT_CBUS_CLK12 = 0x08; + + /// + /// FT232R CBUS EEPROM options - 6MHz clock + /// + public const byte FT_CBUS_CLK6 = 0x09; + + /// + /// FT232R CBUS EEPROM options - IO mode + /// + public const byte FT_CBUS_IOMODE = 0x0A; + + /// + /// FT232R CBUS EEPROM options - Bit-bang write strobe + /// + public const byte FT_CBUS_BITBANG_WR = 0x0B; + + /// + /// FT232R CBUS EEPROM options - Bit-bang read strobe + /// + public const byte FT_CBUS_BITBANG_RD = 0x0C; +} \ No newline at end of file diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_DATA_BITS.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_DATA_BITS.cs new file mode 100644 index 0000000000..cbf61e7f03 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_DATA_BITS.cs @@ -0,0 +1,17 @@ +namespace FTD2XX; + +/// +/// Permitted data bits for FTDI devices +/// +public static class FT_DATA_BITS +{ + /// + /// 8 data bits + /// + public const byte FT_BITS_8 = 0x08; + + /// + /// 7 data bits + /// + public const byte FT_BITS_7 = 0x07; +} diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_DEFAULT_VALUES.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_DEFAULT_VALUES.cs new file mode 100644 index 0000000000..fb400a2095 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_DEFAULT_VALUES.cs @@ -0,0 +1,12 @@ +namespace FTD2XX; + +public static class FT_DEFAULT_VALUES +{ + public const int FT_DEFAULT_BAUD_RATE = 9600; + public const int FT_DEFAULT_DEADMAN_TIMEOUT = 5000; + public const int FT_COM_PORT_NOT_ASSIGNED = -1; + public const int FT_DEFAULT_IN_TRANSFER_SIZE = 0x1000; + public const int FT_DEFAULT_OUT_TRANSFER_SIZE = 0x1000; + public const byte FT_DEFAULT_LATENCY = 16; + public const int FT_DEFAULT_DEVICE_ID = 0x04036001; +} diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_DEVICE.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_DEVICE.cs new file mode 100644 index 0000000000..052a669347 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_DEVICE.cs @@ -0,0 +1,132 @@ +namespace FTD2XX; + +/// +/// List of FTDI device types +/// +public enum FT_DEVICE +{ + /// + /// FT232B or FT245B device + /// + FT_DEVICE_BM = 0, + + /// + /// FT8U232AM or FT8U245AM device + /// + FT_DEVICE_AM, + + /// + /// FT8U100AX device + /// + FT_DEVICE_100AX, + + /// + /// Unknown device + /// + FT_DEVICE_UNKNOWN, + + /// + /// FT2232 device + /// + FT_DEVICE_2232, + + /// + /// FT232R or FT245R device + /// + FT_DEVICE_232R, + + /// + /// FT2232H device + /// + FT_DEVICE_2232H, + + /// + /// FT4232H device + /// + FT_DEVICE_4232H, + + /// + /// FT232H device + /// + FT_DEVICE_232H, + + /// + /// FT X-Series device + /// + FT_DEVICE_X_SERIES, + + /// + /// FT4222 hi-speed device Mode 0 - 2 interfaces + /// + FT_DEVICE_4222H_0, + + /// + /// FT4222 hi-speed device Mode 1 or 2 - 4 interfaces + /// + FT_DEVICE_4222H_1_2, + + /// + /// FT4222 hi-speed device Mode 3 - 1 interface + /// + FT_DEVICE_4222H_3, + + /// + /// OTP programmer board for the FT4222. + /// + FT_DEVICE_4222_PROG, + + /// + /// OTP programmer board for the FT900. + /// + FT_DEVICE_FT900, + + /// + /// OTP programmer board for the FT930. + /// + FT_DEVICE_FT930, + + /// + /// Flash programmer board for the UMFTPD3A. + /// + FT_DEVICE_UMFTPD3A, + + /// + /// FT2233HP hi-speed device. + /// + FT_DEVICE_2233HP, + + /// + /// FT4233HP hi-speed device. + /// + FT_DEVICE_4233HP, + + /// + /// FT2233HP hi-speed device. + /// + FT_DEVICE_2232HP, + + /// + /// FT4233HP hi-speed device. + /// + FT_DEVICE_4232HP, + + /// + /// FT233HP hi-speed device. + /// + FT_DEVICE_233HP, + + /// + /// FT232HP hi-speed device. + /// + FT_DEVICE_232HP, + + /// + /// FT2233HA hi-speed device. + /// + FT_DEVICE_2232HA, + + /// + /// FT4233HA hi-speed device. + /// + FT_DEVICE_4232HA, +}; diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_DEVICE_INFO_NODE.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_DEVICE_INFO_NODE.cs new file mode 100644 index 0000000000..25a10f8c39 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_DEVICE_INFO_NODE.cs @@ -0,0 +1,49 @@ +using System; + +namespace FTD2XX; + +/// +/// Type that holds device information for GetDeviceInformation method. +/// Used with FT_GetDeviceInfo and FT_GetDeviceInfoDetail in FTD2XX.DLL +/// +public class FT_DEVICE_INFO_NODE +{ + /// + /// Indicates device state. + /// Can be any combination of the following: FT_FLAGS_OPENED, FT_FLAGS_HISPEED + /// Bit 0 (least significant bit) indicates if the port is open (1) or closed (0). + /// Bit 1 indicates if the device is enumerated as a high-speed USB device (2) or a full-speed USB device (0). + /// + public int Flags; + + /// + /// Indicates the device type. Can be one of the following: FT_DEVICE_232R, FT_DEVICE_2232C, FT_DEVICE_BM, FT_DEVICE_AM, FT_DEVICE_100AX or FT_DEVICE_UNKNOWN + /// + public FT_DEVICE Type; + + /// + /// The Vendor ID and Product ID of the device + /// + public int ID; + + /// + /// The physical location identifier of the device + /// + public int LocId; + + /// + /// The device serial number + /// + public string SerialNumber = string.Empty; + + /// + /// The device description + /// + public string Description = string.Empty; + + /// + /// The device handle. This value is not used externally and is provided for information only. + /// If the device is not open, this value is 0. + /// + public IntPtr ftHandle; +} \ No newline at end of file diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_DRIVE_CURRENT.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_DRIVE_CURRENT.cs new file mode 100644 index 0000000000..4dfe0bd2ba --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_DRIVE_CURRENT.cs @@ -0,0 +1,27 @@ +namespace FTD2XX; + +/// +/// Valid values for drive current options on FT2232H, FT4232H and FT232H devices. +/// +public static class FT_DRIVE_CURRENT +{ + /// + /// 4mA drive current + /// + public const byte FT_DRIVE_CURRENT_4MA = 4; + + /// + /// 8mA drive current + /// + public const byte FT_DRIVE_CURRENT_8MA = 8; + + /// + /// 12mA drive current + /// + public const byte FT_DRIVE_CURRENT_12MA = 12; + + /// + /// 16mA drive current + /// + public const byte FT_DRIVE_CURRENT_16MA = 16; +} diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_EEPROM_DATA.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_EEPROM_DATA.cs new file mode 100644 index 0000000000..c92872cd88 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_EEPROM_DATA.cs @@ -0,0 +1,53 @@ +namespace FTD2XX; + +/// +/// Common EEPROM elements for all devices. Inherited to specific device type EEPROMs. +/// +public abstract class FT_EEPROM_DATA +{ + /// + /// Vendor ID as supplied by the USB Implementers Forum + /// + public short VendorID = 0x0403; + + /// + /// Product ID + /// + public short ProductID = 0x6001; + + /// + /// Manufacturer name string + /// + public string Manufacturer = "FTDI"; + + /// + /// Manufacturer name abbreviation to be used as a prefix for automatically generated serial numbers + /// + public string ManufacturerID = "FT"; + + /// + /// Device description string + /// + public string Description = "USB-Serial Converter"; + + /// + /// Device serial number string + /// + public string SerialNumber = ""; + + /// + /// Maximum power the device needs + /// + public short MaxPower = 0x0090; + + //private bool PnP = true; + /// + /// Indicates if the device has its own power supply (self-powered) or gets power from the USB port (bus-powered) + /// + public bool SelfPowered = false; + + /// + /// Determines if the device can wake the host PC from suspend by toggling the RI line + /// + public bool RemoteWakeup = false; +} diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_EEPROM_HEADER.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_EEPROM_HEADER.cs new file mode 100644 index 0000000000..88b13629bd --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_EEPROM_HEADER.cs @@ -0,0 +1,19 @@ +using System.Runtime.InteropServices; + +namespace FTD2XX; + +[StructLayout(LayoutKind.Sequential, Pack = 4)] +internal struct FT_EEPROM_HEADER +{ + public int deviceType; // FTxxxx device type to be programmed + // Device descriptor options + public short VendorId; // 0x0403 + public short ProductId; // 0x6001 + public byte SerNumEnable; // non-zero if serial number to be used + // Config descriptor options + public short MaxPower; // 0 < MaxPower <= 500 + public byte SelfPowered; // 0 = bus powered, 1 = self powered + public byte RemoteWakeup; // 0 = not capable, 1 = capable + // Hardware options + public byte PullDownEnable; // non-zero if pull down in suspend enabled +} diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_ERROR.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_ERROR.cs new file mode 100644 index 0000000000..e497971103 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_ERROR.cs @@ -0,0 +1,37 @@ +namespace FTD2XX; + +/// +/// Error states not supported by FTD2XX DLL. +/// +public enum FT_ERROR +{ + FT_NO_ERROR = 0, + FT_INCORRECT_DEVICE, + FT_INVALID_BITMODE, + FT_BUFFER_SIZE +}; + +public static class FT_ERROR_EXTENSIONS +{ + public static bool IsOK(this FT_ERROR error) + { + return error == FT_ERROR.FT_NO_ERROR; + } + + public static void ThrowIfNotOK(this FT_ERROR error) + { + switch (error) + { + case FT_ERROR.FT_NO_ERROR: + return; + case FT_ERROR.FT_INCORRECT_DEVICE: + throw new FT_EXCEPTION("The current device type does not match the EEPROM structure."); + case FT_ERROR.FT_INVALID_BITMODE: + throw new FT_EXCEPTION("The requested bit mode is not valid for the current device."); + case FT_ERROR.FT_BUFFER_SIZE: + throw new FT_EXCEPTION("The supplied buffer is not big enough."); + default: + throw new FT_EXCEPTION($"Unknown Error: {error}"); + } + } +} \ No newline at end of file diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_EVENTS.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_EVENTS.cs new file mode 100644 index 0000000000..2d4bb5f278 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_EVENTS.cs @@ -0,0 +1,22 @@ +namespace FTD2XX; + +/// +/// FTDI device event types that can be monitored +/// +public static class FT_EVENTS +{ + /// + /// Event on receive character + /// + public const int FT_EVENT_RXCHAR = 0x00000001; + + /// + /// Event on modem status change + /// + public const int FT_EVENT_MODEM_STATUS = 0x00000002; + + /// + /// Event on line status change + /// + public const int FT_EVENT_LINE_STATUS = 0x00000004; +} diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_EXCEPTION.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_EXCEPTION.cs new file mode 100644 index 0000000000..d27071e1ce --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_EXCEPTION.cs @@ -0,0 +1,35 @@ +using System; + +namespace FTD2XX; + +/// +/// Exceptions thrown by errors within the FTDI class. +/// +[Serializable] +public class FT_EXCEPTION : Exception +{ + /// + /// + /// + public FT_EXCEPTION() { } + /// + /// + /// + /// + public FT_EXCEPTION(string message) : base(message) { } + /// + /// + /// + /// + /// + public FT_EXCEPTION(string message, Exception inner) : base(message, inner) { } + /// + /// + /// + /// + /// + protected FT_EXCEPTION( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) + : base(info, context) { } +} \ No newline at end of file diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_FLAGS.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_FLAGS.cs new file mode 100644 index 0000000000..f2fb8b0e3d --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_FLAGS.cs @@ -0,0 +1,17 @@ +namespace FTD2XX; + +/// +/// Flags that provide information on the FTDI device state +/// +public static class FT_FLAGS +{ + /// + /// Indicates that the device is open + /// + public const int FT_FLAGS_OPENED = 0x00000001; + + /// + /// Indicates that the device is enumerated as a hi-speed USB device + /// + public const int FT_FLAGS_HISPEED = 0x00000002; +} diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_FLOW_CONTROL.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_FLOW_CONTROL.cs new file mode 100644 index 0000000000..e2b982ad1f --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_FLOW_CONTROL.cs @@ -0,0 +1,27 @@ +namespace FTD2XX; + +/// +/// Permitted flow control values for FTDI devices +/// +public static class FT_FLOW_CONTROL +{ + /// + /// No flow control + /// + public const short FT_FLOW_NONE = 0x0000; + + /// + /// RTS/CTS flow control + /// + public const short FT_FLOW_RTS_CTS = 0x0100; + + /// + /// DTR/DSR flow control + /// + public const short FT_FLOW_DTR_DSR = 0x0200; + + /// + /// Xon/Xoff flow control + /// + public const short FT_FLOW_XON_XOFF = 0x0400; +} diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_LINE_STATUS.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_LINE_STATUS.cs new file mode 100644 index 0000000000..3b69ba3ec0 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_LINE_STATUS.cs @@ -0,0 +1,27 @@ +namespace FTD2XX; + +/// +/// Line status bit definitions +/// +public static class FT_LINE_STATUS +{ + /// + /// Overrun Error (OE) line status + /// + public const byte FT_OE = 0x02; + + /// + /// Parity Error (PE) line status + /// + public const byte FT_PE = 0x04; + + /// + /// Framing Error (FE) line status + /// + public const byte FT_FE = 0x08; + + /// + /// Break Interrupt (BI) line status + /// + public const byte FT_BI = 0x10; +} diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_MODEM_STATUS.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_MODEM_STATUS.cs new file mode 100644 index 0000000000..d23645e930 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_MODEM_STATUS.cs @@ -0,0 +1,27 @@ +namespace FTD2XX; + +/// +/// Modem status bit definitions +/// +public static class FT_MODEM_STATUS +{ + /// + /// Clear To Send (CTS) modem status + /// + public const byte FT_CTS = 0x10; + + /// + /// Data Set Ready (DSR) modem status + /// + public const byte FT_DSR = 0x20; + + /// + /// Ring Indicator (RI) modem status + /// + public const byte FT_RI = 0x40; + + /// + /// Data Carrier Detect (DCD) modem status + /// + public const byte FT_DCD = 0x80; +} \ No newline at end of file diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_OPEN.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_OPEN.cs new file mode 100644 index 0000000000..fc240caaeb --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_OPEN.cs @@ -0,0 +1,8 @@ +namespace FTD2XX; + +public static class FT_OPEN +{ + public const int BY_SERIAL_NUMBER = 0x00000001; + public const int BY_DESCRIPTION = 0x00000002; + public const int BY_LOCATION = 0x00000004; +} \ No newline at end of file diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_PARITY.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_PARITY.cs new file mode 100644 index 0000000000..07c5f80d5e --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_PARITY.cs @@ -0,0 +1,32 @@ +namespace FTD2XX; + +/// +/// Permitted parity values for FTDI devices +/// +public static class FT_PARITY +{ + /// + /// No parity + /// + public const byte FT_PARITY_NONE = 0x00; + + /// + /// Odd parity + /// + public const byte FT_PARITY_ODD = 0x01; + + /// + /// Even parity + /// + public const byte FT_PARITY_EVEN = 0x02; + + /// + /// Mark parity + /// + public const byte FT_PARITY_MARK = 0x03; + + /// + /// Space parity + /// + public const byte FT_PARITY_SPACE = 0x04; +} diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_PROGRAM_DATA.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_PROGRAM_DATA.cs new file mode 100644 index 0000000000..9ea1780d94 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_PROGRAM_DATA.cs @@ -0,0 +1,153 @@ +using System; +using System.Runtime.InteropServices; + +namespace FTD2XX; + +[StructLayout(LayoutKind.Sequential, Pack = 4)] +public class FT_PROGRAM_DATA +{ + public int Signature1; + public int Signature2; + public int Version; + public short VendorID; + public short ProductID; + + public IntPtr Manufacturer; + public IntPtr ManufacturerID; + public IntPtr Description; + public IntPtr SerialNumber; + + public short MaxPower; + public short PnP; + public short SelfPowered; + public short RemoteWakeup; + + // FT232B extensions + public byte Rev4; + public byte IsoIn; + public byte IsoOut; + public byte PullDownEnable; + public byte SerNumEnable; + public byte USBVersionEnable; + public short USBVersion; + + // FT2232D extensions + public byte Rev5; + public byte IsoInA; + public byte IsoInB; + public byte IsoOutA; + public byte IsoOutB; + public byte PullDownEnable5; + public byte SerNumEnable5; + public byte USBVersionEnable5; + public short USBVersion5; + public byte AIsHighCurrent; + public byte BIsHighCurrent; + public byte IFAIsFifo; + public byte IFAIsFifoTar; + public byte IFAIsFastSer; + public byte AIsVCP; + public byte IFBIsFifo; + public byte IFBIsFifoTar; + public byte IFBIsFastSer; + public byte BIsVCP; + + // FT232R extensions + public byte UseExtOsc; + public byte HighDriveIOs; + public byte EndpointSize; + public byte PullDownEnableR; + public byte SerNumEnableR; + public byte InvertTXD; // non-zero if invert TXD + public byte InvertRXD; // non-zero if invert RXD + public byte InvertRTS; // non-zero if invert RTS + public byte InvertCTS; // non-zero if invert CTS + public byte InvertDTR; // non-zero if invert DTR + public byte InvertDSR; // non-zero if invert DSR + public byte InvertDCD; // non-zero if invert DCD + public byte InvertRI; // non-zero if invert RI + public byte Cbus0; // Cbus Mux control - Ignored for FT245R + public byte Cbus1; // Cbus Mux control - Ignored for FT245R + public byte Cbus2; // Cbus Mux control - Ignored for FT245R + public byte Cbus3; // Cbus Mux control - Ignored for FT245R + public byte Cbus4; // Cbus Mux control - Ignored for FT245R + public byte RIsD2XX; // Default to loading VCP + + // FT2232H extensions + public byte PullDownEnable7; + public byte SerNumEnable7; + public byte ALSlowSlew; // non-zero if AL pins have slow slew + public byte ALSchmittInput; // non-zero if AL pins are Schmitt input + public byte ALDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + public byte AHSlowSlew; // non-zero if AH pins have slow slew + public byte AHSchmittInput; // non-zero if AH pins are Schmitt input + public byte AHDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + public byte BLSlowSlew; // non-zero if BL pins have slow slew + public byte BLSchmittInput; // non-zero if BL pins are Schmitt input + public byte BLDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + public byte BHSlowSlew; // non-zero if BH pins have slow slew + public byte BHSchmittInput; // non-zero if BH pins are Schmitt input + public byte BHDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + public byte IFAIsFifo7; // non-zero if interface is 245 FIFO + public byte IFAIsFifoTar7; // non-zero if interface is 245 FIFO CPU target + public byte IFAIsFastSer7; // non-zero if interface is Fast serial + public byte AIsVCP7; // non-zero if interface is to use VCP drivers + public byte IFBIsFifo7; // non-zero if interface is 245 FIFO + public byte IFBIsFifoTar7; // non-zero if interface is 245 FIFO CPU target + public byte IFBIsFastSer7; // non-zero if interface is Fast serial + public byte BIsVCP7; // non-zero if interface is to use VCP drivers + public byte PowerSaveEnable; // non-zero if using BCBUS7 to save power for self-powered designs + + // FT4232H extensions + public byte PullDownEnable8; + public byte SerNumEnable8; + public byte ASlowSlew; // non-zero if AL pins have slow slew + public byte ASchmittInput; // non-zero if AL pins are Schmitt input + public byte ADriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + public byte BSlowSlew; // non-zero if AH pins have slow slew + public byte BSchmittInput; // non-zero if AH pins are Schmitt input + public byte BDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + public byte CSlowSlew; // non-zero if BL pins have slow slew + public byte CSchmittInput; // non-zero if BL pins are Schmitt input + public byte CDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + public byte DSlowSlew; // non-zero if BH pins have slow slew + public byte DSchmittInput; // non-zero if BH pins are Schmitt input + public byte DDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + public byte ARIIsTXDEN; + public byte BRIIsTXDEN; + public byte CRIIsTXDEN; + public byte DRIIsTXDEN; + public byte AIsVCP8; // non-zero if interface is to use VCP drivers + public byte BIsVCP8; // non-zero if interface is to use VCP drivers + public byte CIsVCP8; // non-zero if interface is to use VCP drivers + public byte DIsVCP8; // non-zero if interface is to use VCP drivers + + // FT232H extensions + public byte PullDownEnableH; // non-zero if pull down enabled + public byte SerNumEnableH; // non-zero if serial number to be used + public byte ACSlowSlewH; // non-zero if AC pins have slow slew + public byte ACSchmittInputH; // non-zero if AC pins are Schmitt input + public byte ACDriveCurrentH; // valid values are 4mA, 8mA, 12mA, 16mA + public byte ADSlowSlewH; // non-zero if AD pins have slow slew + public byte ADSchmittInputH; // non-zero if AD pins are Schmitt input + public byte ADDriveCurrentH; // valid values are 4mA, 8mA, 12mA, 16mA + public byte Cbus0H; // Cbus Mux control + public byte Cbus1H; // Cbus Mux control + public byte Cbus2H; // Cbus Mux control + public byte Cbus3H; // Cbus Mux control + public byte Cbus4H; // Cbus Mux control + public byte Cbus5H; // Cbus Mux control + public byte Cbus6H; // Cbus Mux control + public byte Cbus7H; // Cbus Mux control + public byte Cbus8H; // Cbus Mux control + public byte Cbus9H; // Cbus Mux control + public byte IsFifoH; // non-zero if interface is 245 FIFO + public byte IsFifoTarH; // non-zero if interface is 245 FIFO CPU target + public byte IsFastSerH; // non-zero if interface is Fast serial + public byte IsFT1248H; // non-zero if interface is FT1248 + public byte FT1248CpolH; // FT1248 clock polarity + public byte FT1248LsbH; // FT1248 data is LSB (1) or MSB (0) + public byte FT1248FlowControlH; // FT1248 flow control enable + public byte IsVCPH; // non-zero if interface is to use VCP drivers + public byte PowerSaveEnableH; // non-zero if using ACBUS7 to save power for self-powered designs +} \ No newline at end of file diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_PURGE.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_PURGE.cs new file mode 100644 index 0000000000..d04bc2d9a4 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_PURGE.cs @@ -0,0 +1,17 @@ +namespace FTD2XX; + +/// +/// Purge buffer constant definitions +/// +public static class FT_PURGE +{ + /// + /// Purge Rx buffer + /// + public const byte FT_PURGE_RX = 0x01; + + /// + /// Purge Tx buffer + /// + public const byte FT_PURGE_TX = 0x02; +} \ No newline at end of file diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_STATUS.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_STATUS.cs new file mode 100644 index 0000000000..0979b41026 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_STATUS.cs @@ -0,0 +1,150 @@ +namespace FTD2XX; + +/// +/// Status values for FTDI devices. +/// +public enum FT_STATUS +{ + /// + /// Status OK + /// + FT_OK = 0, + + /// + /// The device handle is invalid + /// + FT_INVALID_HANDLE, + + /// + /// Device not found + /// + FT_DEVICE_NOT_FOUND, + + /// + /// Device is not open + /// + FT_DEVICE_NOT_OPENED, + + /// + /// IO error + /// + FT_IO_ERROR, + + /// + /// Insufficient resources + /// + FT_INSUFFICIENT_RESOURCES, + + /// + /// A parameter was invalid + /// + FT_INVALID_PARAMETER, + + /// + /// The requested baud rate is invalid + /// + FT_INVALID_BAUD_RATE, + + /// + /// Device not opened for erase + /// + FT_DEVICE_NOT_OPENED_FOR_ERASE, + + /// + /// Device not poened for write + /// + FT_DEVICE_NOT_OPENED_FOR_WRITE, + + /// + /// Failed to write to device + /// + FT_FAILED_TO_WRITE_DEVICE, + + /// + /// Failed to read the device EEPROM + /// + FT_EEPROM_READ_FAILED, + + /// + /// Failed to write the device EEPROM + /// + FT_EEPROM_WRITE_FAILED, + + /// + /// Failed to erase the device EEPROM + /// + FT_EEPROM_ERASE_FAILED, + + /// + /// An EEPROM is not fitted to the device + /// + FT_EEPROM_NOT_PRESENT, + + /// + /// Device EEPROM is blank + /// + FT_EEPROM_NOT_PROGRAMMED, + + /// + /// Invalid arguments + /// + FT_INVALID_ARGS, + + /// + /// An other error has occurred + /// + FT_OTHER_ERROR +}; + +public static class FT_STATUS_EXTENSIONS +{ + public static bool IsOK(this FT_STATUS status) + { + return status == FT_STATUS.FT_OK; + } + + public static void ThrowIfNotOK(this FT_STATUS status) + { + switch (status) + { + case FT_STATUS.FT_OK: + return; + case FT_STATUS.FT_DEVICE_NOT_FOUND: + throw new FT_EXCEPTION("FTDI device not found."); + case FT_STATUS.FT_DEVICE_NOT_OPENED: + throw new FT_EXCEPTION("FTDI device not opened."); + case FT_STATUS.FT_DEVICE_NOT_OPENED_FOR_ERASE: + throw new FT_EXCEPTION("FTDI device not opened for erase."); + case FT_STATUS.FT_DEVICE_NOT_OPENED_FOR_WRITE: + throw new FT_EXCEPTION("FTDI device not opened for write."); + case FT_STATUS.FT_EEPROM_ERASE_FAILED: + throw new FT_EXCEPTION("Failed to erase FTDI device EEPROM."); + case FT_STATUS.FT_EEPROM_NOT_PRESENT: + throw new FT_EXCEPTION("No EEPROM fitted to FTDI device."); + case FT_STATUS.FT_EEPROM_NOT_PROGRAMMED: + throw new FT_EXCEPTION("FTDI device EEPROM not programmed."); + case FT_STATUS.FT_EEPROM_READ_FAILED: + throw new FT_EXCEPTION("Failed to read FTDI device EEPROM."); + case FT_STATUS.FT_EEPROM_WRITE_FAILED: + throw new FT_EXCEPTION("Failed to write FTDI device EEPROM."); + case FT_STATUS.FT_FAILED_TO_WRITE_DEVICE: + throw new FT_EXCEPTION("Failed to write to FTDI device."); + case FT_STATUS.FT_INSUFFICIENT_RESOURCES: + throw new FT_EXCEPTION("Insufficient resources."); + case FT_STATUS.FT_INVALID_ARGS: + throw new FT_EXCEPTION("Invalid arguments for FTD2XX function call."); + case FT_STATUS.FT_INVALID_BAUD_RATE: + throw new FT_EXCEPTION("Invalid Baud rate for FTDI device."); + case FT_STATUS.FT_INVALID_HANDLE: + throw new FT_EXCEPTION("Invalid handle for FTDI device."); + case FT_STATUS.FT_INVALID_PARAMETER: + throw new FT_EXCEPTION("Invalid parameter for FTD2XX function call."); + case FT_STATUS.FT_IO_ERROR: + throw new FT_EXCEPTION("FTDI device IO error."); + case FT_STATUS.FT_OTHER_ERROR: + throw new FT_EXCEPTION("An unexpected error has occurred when trying to communicate with the FTDI device."); + default: + throw new FT_EXCEPTION($"Unknown Error: {status}"); + } + } +} \ No newline at end of file diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_STOP_BITS.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_STOP_BITS.cs new file mode 100644 index 0000000000..261f6e244b --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_STOP_BITS.cs @@ -0,0 +1,17 @@ +namespace FTD2XX; + +/// +/// Permitted stop bits for FTDI devices +/// +public static class FT_STOP_BITS +{ + /// + /// 1 stop bit + /// + public const byte FT_STOP_BITS_1 = 0x00; + + /// + /// 2 stop bits + /// + public const byte FT_STOP_BITS_2 = 0x02; +} diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_XSERIES_CBUS_OPTIONS.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_XSERIES_CBUS_OPTIONS.cs new file mode 100644 index 0000000000..c6afc320a6 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_XSERIES_CBUS_OPTIONS.cs @@ -0,0 +1,117 @@ +namespace FTD2XX; + +/// +/// Available functions for the X-Series CBUS pins. Controlled by X-Series EEPROM settings +/// +public static class FT_XSERIES_CBUS_OPTIONS +{ + /// + /// FT X-Series CBUS EEPROM options - Tristate + /// + public const byte FT_CBUS_TRISTATE = 0x00; + + /// + /// FT X-Series CBUS EEPROM options - RxLED# + /// + public const byte FT_CBUS_RXLED = 0x01; + + /// + /// FT X-Series CBUS EEPROM options - TxLED# + /// + public const byte FT_CBUS_TXLED = 0x02; + + /// + /// FT X-Series CBUS EEPROM options - TxRxLED# + /// + public const byte FT_CBUS_TXRXLED = 0x03; + + /// + /// FT X-Series CBUS EEPROM options - PwrEn# + /// + public const byte FT_CBUS_PWREN = 0x04; + + /// + /// FT X-Series CBUS EEPROM options - Sleep# + /// + public const byte FT_CBUS_SLEEP = 0x05; + + /// + /// FT X-Series CBUS EEPROM options - Drive_0 + /// + public const byte FT_CBUS_Drive_0 = 0x06; + + /// + /// FT X-Series CBUS EEPROM options - Drive_1 + /// + public const byte FT_CBUS_Drive_1 = 0x07; + + /// + /// FT X-Series CBUS EEPROM options - GPIO + /// + public const byte FT_CBUS_GPIO = 0x08; + + /// + /// FT X-Series CBUS EEPROM options - TxdEn + /// + public const byte FT_CBUS_TXDEN = 0x09; + + /// + /// FT X-Series CBUS EEPROM options - Clk24MHz + /// + public const byte FT_CBUS_CLK24MHz = 0x0A; + + /// + /// FT X-Series CBUS EEPROM options - Clk12MHz + /// + public const byte FT_CBUS_CLK12MHz = 0x0B; + + /// + /// FT X-Series CBUS EEPROM options - Clk6MHz + /// + public const byte FT_CBUS_CLK6MHz = 0x0C; + + /// + /// FT X-Series CBUS EEPROM options - BCD_Charger + /// + public const byte FT_CBUS_BCD_Charger = 0x0D; + + /// + /// FT X-Series CBUS EEPROM options - BCD_Charger# + /// + public const byte FT_CBUS_BCD_Charger_N = 0x0E; + + /// + /// FT X-Series CBUS EEPROM options - I2C_TXE# + /// + public const byte FT_CBUS_I2C_TXE = 0x0F; + + /// + /// FT X-Series CBUS EEPROM options - I2C_RXF# + /// + public const byte FT_CBUS_I2C_RXF = 0x10; + + /// + /// FT X-Series CBUS EEPROM options - VBUS_Sense + /// + public const byte FT_CBUS_VBUS_Sense = 0x11; + + /// + /// FT X-Series CBUS EEPROM options - BitBang_WR# + /// + public const byte FT_CBUS_BitBang_WR = 0x12; + + /// + /// FT X-Series CBUS EEPROM options - BitBang_RD# + /// + public const byte FT_CBUS_BitBang_RD = 0x13; + + /// + /// FT X-Series CBUS EEPROM options - Time_Stampe + /// + public const byte FT_CBUS_Time_Stamp = 0x14; + + /// + /// FT X-Series CBUS EEPROM options - Keep_Awake# + /// + public const byte FT_CBUS_Keep_Awake = 0x15; +} diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_XSERIES_DATA.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_XSERIES_DATA.cs new file mode 100644 index 0000000000..bf3bdf1948 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/FTD2XX/FT_XSERIES_DATA.cs @@ -0,0 +1,51 @@ +using System.Runtime.InteropServices; + +namespace FTD2XX; + +[StructLayout(LayoutKind.Sequential, Pack = 4)] +internal struct FT_XSERIES_DATA +{ + public FT_EEPROM_HEADER common; + + public byte ACSlowSlew; // non-zero if AC bus pins have slow slew + public byte ACSchmittInput; // non-zero if AC bus pins are Schmitt input + public byte ACDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + public byte ADSlowSlew; // non-zero if AD bus pins have slow slew + public byte ADSchmittInput; // non-zero if AD bus pins are Schmitt input + public byte ADDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + // CBUS options + public byte Cbus0; // Cbus Mux control + public byte Cbus1; // Cbus Mux control + public byte Cbus2; // Cbus Mux control + public byte Cbus3; // Cbus Mux control + public byte Cbus4; // Cbus Mux control + public byte Cbus5; // Cbus Mux control + public byte Cbus6; // Cbus Mux control + // UART signal options + public byte InvertTXD; // non-zero if invert TXD + public byte InvertRXD; // non-zero if invert RXD + public byte InvertRTS; // non-zero if invert RTS + public byte InvertCTS; // non-zero if invert CTS + public byte InvertDTR; // non-zero if invert DTR + public byte InvertDSR; // non-zero if invert DSR + public byte InvertDCD; // non-zero if invert DCD + public byte InvertRI; // non-zero if invert RI + // Battery Charge Detect options + public byte BCDEnable; // Enable Battery Charger Detection + public byte BCDForceCbusPWREN; // asserts the power enable signal on CBUS when charging port detected + public byte BCDDisableSleep; // forces the device never to go into sleep mode + // I2C options + public short I2CSlaveAddress; // I2C slave device address + public int I2CDeviceId; // I2C device ID + public byte I2CDisableSchmitt; // Disable I2C Schmitt trigger + // FT1248 options + public byte FT1248Cpol; // FT1248 clock polarity - clock idle high (1) or clock idle low (0) + public byte FT1248Lsb; // FT1248 data is LSB (1) or MSB (0) + public byte FT1248FlowControl; // FT1248 flow control enable + // Hardware options + public byte RS485EchoSuppress; // + public byte PowerSaveEnable; // + // Driver option + public byte DriverType; // +} + diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/Ft2232.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/Ft2232.cs index 8213b72e1a..afa878af8c 100644 --- a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/Ft2232.cs +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/Ft2232.cs @@ -16,9 +16,7 @@ internal Ft2232() public override II2cBus CreateI2cBus(int channel = 0, I2cBusSpeed busSpeed = I2cBusSpeed.Standard) { // TODO: depends on part - var bus = new Ft23xxI2cBus(this, busSpeed); - bus.Configure(); - return bus; + throw new NotSupportedException(); } /// diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/Ft232h.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/Ft232h.cs index bd38999f12..9cca0ba743 100644 --- a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/Ft232h.cs +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/Ft232h.cs @@ -16,8 +16,7 @@ public override II2cBus CreateI2cBus(int channel = 0, I2cBusSpeed busSpeed = I2c { // TODO: depends on part // TODO: make sure no SPI is in use - var bus = new Ft232hI2cBus(this, busSpeed); - bus.Configure(); + var bus = new Ft232hI2cBus(Device, channel, busSpeed); return bus; } @@ -25,8 +24,7 @@ public override II2cBus CreateI2cBus(int channel = 0, I2cBusSpeed busSpeed = I2c public override ISpiBus CreateSpiBus(int channel, SpiClockConfiguration configuration) { // TODO: make sure no SPI is in use - var bus = new Ft232hSpiBus(this, configuration); - bus.Configure(); + var bus = new Ft232hSpiBus(Device, channel, configuration); return bus; } } \ No newline at end of file diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/Ft4232.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/Ft4232.cs index d328e21bd8..46f50e4699 100644 --- a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/Ft4232.cs +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Drivers/Ft4232.cs @@ -15,10 +15,7 @@ internal Ft4232() /// public override II2cBus CreateI2cBus(int channel = 0, I2cBusSpeed busSpeed = I2cBusSpeed.Standard) { - // TODO: depends on part - var bus = new Ft23xxI2cBus(this, busSpeed); - bus.Configure(); - return bus; + throw new NotSupportedException(); } /// diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.DigitalInputPort.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.DigitalInputPort.cs index a4e025133e..e8fb075aaf 100644 --- a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.DigitalInputPort.cs +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.DigitalInputPort.cs @@ -33,8 +33,10 @@ public override bool State { get { - var states = _expander.GetGpioStates(_pin.IsLowByte); - return (states & (byte)_pin.Key) != 0; + return false; + + // var states = _expander.GetGpioStates(_pin.IsLowByte); + // return (states & (byte)_pin.Key) != 0; } } } diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.Ft232hI2cBus.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.Ft232hI2cBus.cs index 8e452a0c84..648ab83c25 100644 --- a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.Ft232hI2cBus.cs +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.Ft232hI2cBus.cs @@ -1,6 +1,9 @@ -using Meadow.Hardware; +using FTD2XX; +using Meadow.Hardware; using System; -using System.Threading; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; namespace Meadow.Foundation.ICs.IOExpanders; @@ -9,163 +12,263 @@ public abstract partial class FtdiExpander /// /// Represents an Ft232h expander I2C bus. /// - public class Ft232hI2cBus : I2CBus + public class Ft232hI2cBus : II2cBus { - internal Ft232hI2cBus(FtdiExpander expander, I2cBusSpeed busSpeed) - : base(expander, busSpeed) + private readonly FTDI _device; + + internal Ft232hI2cBus(FTDI device, int channel, I2cBusSpeed busSpeed) { + _device = device; + ConfigureMpsse(); + + // TODO: figure out how to set bus speed } - internal override void Configure() + public I2cBusSpeed BusSpeed { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + private void ConfigureMpsse() + { + _device.SetTimeouts(1000, 1000).ThrowIfNotOK(); + _device.SetLatency(16).ThrowIfNotOK(); + _device.SetFlowControl(FT_FLOW_CONTROL.FT_FLOW_RTS_CTS, 0x00, 0x00).ThrowIfNotOK(); + _device.SetBitMode(0x00, 0x00).ThrowIfNotOK(); // RESET + _device.SetBitMode(0x00, 0x02).ThrowIfNotOK(); // MPSSE + + _device.FlushBuffer(); + + /***** Synchronize the MPSSE interface by sending bad command 0xAA *****/ + _device.Write(new byte[] { 0xAA }).ThrowIfNotOK(); + byte[] rx1 = _device.ReadBytes(2, out FT_STATUS status1); + status1.ThrowIfNotOK(); + if ((rx1[0] != 0xFA) || (rx1[1] != 0xAA)) + throw new InvalidOperationException($"bad echo bytes: {rx1[0]} {rx1[1]}"); + + /***** Synchronize the MPSSE interface by sending bad command 0xAB *****/ + _device.Write(new byte[] { 0xAB }).ThrowIfNotOK(); + byte[] rx2 = _device.ReadBytes(2, out FT_STATUS status2); + status2.ThrowIfNotOK(); + if ((rx2[0] != 0xFA) || (rx2[1] != 0xAB)) + throw new InvalidOperationException($"bad echo bytes: {rx2[0]} {rx2[1]}"); + + const uint ClockDivisor = 199; //49 for 200 KHz, 199 for 100 KHz + const byte I2C_Data_SDAhi_SCLhi = 0x03; + const byte I2C_Dir_SDAout_SCLout = 0x03; + + int numBytesToSend = 0; + byte[] buffer = new byte[100]; + buffer[numBytesToSend++] = 0x8A; // Disable clock divide by 5 for 60Mhz master clock + buffer[numBytesToSend++] = 0x97; // Turn off adaptive clocking + buffer[numBytesToSend++] = 0x8C; // Enable 3 phase data clock, used by I2C to allow data on both clock edges + // The SK clock frequency can be worked out by below algorithm with divide by 5 set as off + // SK frequency = 60MHz /((1 + [(1 +0xValueH*256) OR 0xValueL])*2) + buffer[numBytesToSend++] = 0x86; //Command to set clock divisor + buffer[numBytesToSend++] = (byte)(ClockDivisor & 0x00FF); //Set 0xValueL of clock divisor + buffer[numBytesToSend++] = (byte)((ClockDivisor >> 8) & 0x00FF); //Set 0xValueH of clock divisor + buffer[numBytesToSend++] = 0x85; // loopback off + + buffer[numBytesToSend++] = 0x9E; //Enable the FT232H's drive-zero mode with the following enable mask... + buffer[numBytesToSend++] = 0x07; // ... Low byte (ADx) enables - bits 0, 1 and 2 and ... + buffer[numBytesToSend++] = 0x00; //...High byte (ACx) enables - all off + + buffer[numBytesToSend++] = 0x80; //Command to set directions of lower 8 pins and force value on bits set as output + buffer[numBytesToSend++] = I2C_Data_SDAhi_SCLhi; + buffer[numBytesToSend++] = I2C_Dir_SDAout_SCLout; + + byte[] msg = buffer.Take(numBytesToSend).ToArray(); + _device.Write(msg).ThrowIfNotOK(); + } + + private const byte I2C_Data_SDAlo_SCLlo = 0x00; + private const byte I2C_Data_SDAlo_SCLhi = 0x01; + private const byte I2C_Data_SDAhi_SCLlo = 0x02; + private const byte I2C_Data_SDAhi_SCLhi = 0x03; + private const byte I2C_ADbus = 0x80; + private const byte I2C_Dir_SDAout_SCLout = 0x03; + + private void Start() { - // Setup the clock and other elements - Span toSend = stackalloc byte[10]; - int idx = 0; - // Disable clock divide by 5 for 60Mhz master clock - toSend[idx++] = (byte)Native.FT_OPCODE.DisableClockDivideBy5; - // Turn off adaptive clocking - toSend[idx++] = (byte)Native.FT_OPCODE.TurnOffAdaptiveClocking; - // Enable 3 phase data clock, used by I2C to allow data on both clock edges - toSend[idx++] = (byte)Native.FT_OPCODE.Enable3PhaseDataClocking; - - // The SK clock frequency can be worked out by below algorithm with divide by 5 set as off - // TCK period = 60MHz / (( 1 + [ (0xValueH * 256) OR 0xValueL] ) * 2) - // Command to set clock divisor - toSend[idx++] = (byte)Native.FT_OPCODE.SetClockDivisor; - uint clockDivisor = (60000 / (((uint)BusSpeed / 1000) * 2)) - 1; - toSend[idx++] = (byte)(clockDivisor & 0x00FF); - toSend[idx++] = (byte)((clockDivisor >> 8) & 0x00FF); - - // loopback off - toSend[idx++] = (byte)Native.FT_OPCODE.DisconnectTDItoTDOforLoopback; - - // DEV NOTE (21 Fed 20204): - // the following is in FTDI's FT232H samples, but makes the clock signal an ugly sawtooth instead of squares - - // Enable the FT232H's drive-zero mode with the following enable mask - //toSend[idx++] = (byte)Native.FT_OPCODE.SetIOOnlyDriveOn0AndTristateOn1; - // Low byte (ADx) enables - bits 0, 1 and 2 - //toSend[idx++] = 0x07; - // High byte (ACx) enables - all off - //toSend[idx++] = 0x00; - - - // modify the GPIO state and direction without breaking other stuff - // SDA and SCL both output high(open drain) - toSend[idx++] = (byte)Native.FT_OPCODE.SetDataBitsLowByte; - _expander.GpioStateLow = (byte)(PinData.SDAhiSCLhi | (_expander.GpioStateLow & MaskGpio)); - _expander.GpioDirectionLow = (byte)(PinDirection.SDAoutSCLout | (_expander.GpioDirectionLow & MaskGpio)); - toSend[idx++] = _expander.GpioStateLow; - toSend[idx++] = _expander.GpioDirectionLow; - - _expander.Write(toSend); - - Thread.Sleep(20); - Idle(); - Thread.Sleep(30); + List bytes = new(); + + for (int i = 0; i < 6; i++) + bytes.AddRange(new byte[] { I2C_ADbus, I2C_Data_SDAhi_SCLhi, I2C_Dir_SDAout_SCLout, }); + + for (int i = 0; i < 6; i++) + bytes.AddRange(new byte[] { I2C_ADbus, I2C_Data_SDAlo_SCLhi, I2C_Dir_SDAout_SCLout, }); + + for (int i = 0; i < 6; i++) + bytes.AddRange(new byte[] { I2C_ADbus, I2C_Data_SDAlo_SCLlo, I2C_Dir_SDAout_SCLout, }); + + bytes.AddRange(new byte[] { I2C_ADbus, I2C_Data_SDAhi_SCLlo, I2C_Dir_SDAout_SCLout, }); + + _device.Write(bytes.ToArray()).ThrowIfNotOK(); } - internal override void Start() + private void Stop() { - // SDA high, SCL high - var direction = (byte)(PinDirection.SDAoutSCLout | (_expander.GpioDirectionLow & MaskGpio)); - Idle(); - // Wait(2); - - // SDA lo, SCL high - var state = (byte)(PinData.SDAloSCLhi | (_expander.GpioStateLow & MaskGpio)); - _expander.SetGpioDirectionAndState(true, direction, state); - // Wait(2); - - // SDA lo, SCL lo - state = (byte)(PinData.SDAloSCLlo | (_expander.GpioStateLow & MaskGpio)); - _expander.SetGpioDirectionAndState(true, direction, state); - // Wait(2); - - // Release SDA - // state = (byte)(PinData.SDAhiSCLlo | (_expander.GpioStateLow & MaskGpio)); - // _expander.SetGpioDirectionAndState(true, direction, state); - // Wait(6); + List bytes = new(); + + for (int i = 0; i < 6; i++) + bytes.AddRange(new byte[] { I2C_ADbus, I2C_Data_SDAlo_SCLlo, I2C_Dir_SDAout_SCLout, }); + + for (int i = 0; i < 6; i++) + bytes.AddRange(new byte[] { I2C_ADbus, I2C_Data_SDAlo_SCLhi, I2C_Dir_SDAout_SCLout, }); + + for (int i = 0; i < 6; i++) + bytes.AddRange(new byte[] { I2C_ADbus, I2C_Data_SDAhi_SCLhi, I2C_Dir_SDAout_SCLout, }); + + _device.Write(bytes.ToArray()).ThrowIfNotOK(); } - internal override void Stop() + private bool CommandWrite(byte address) { - // SDA low, SCL low - var state = (byte)(PinData.SDAloSCLlo | (_expander.GpioStateLow & MaskGpio)); - var direction = (byte)(PinDirection.SDAoutSCLout | (_expander.GpioDirectionLow & MaskGpio)); - - // SDA low, SCL high - state = (byte)(PinData.SDAloSCLhi | (_expander.GpioStateLow & MaskGpio)); - _expander.SetGpioDirectionAndState(true, direction, state); - Wait(6); - - // SDA high, SCL high - state = (byte)(PinData.SDAhiSCLhi | (_expander.GpioStateLow & MaskGpio)); - _expander.SetGpioDirectionAndState(true, direction, state); - Wait(6); + address <<= 1; + return SendDataByte(address); } - internal override void Idle() + private bool CommandRead(byte address) { - // SDA high, SCL high - // FT232H always output due to open drain capability - var state = (byte)(PinData.SDAhiSCLhi | (_expander.GpioStateLow & MaskGpio)); - var direction = (byte)(PinDirection.SDAoutSCLout | (_expander.GpioDirectionLow & MaskGpio)); - _expander.SetGpioDirectionAndState(true, direction, state); + address <<= 1; + address |= 0x01; + return SendDataByte(address); } - internal override TransferStatus SendDataByte(byte data) + private bool SendDataByte(byte byteToSend) { - Span txBuffer = stackalloc byte[10]; - Span rxBuffer = stackalloc byte[1]; - var idx = 0; - - // Just clock with one byte (0 = 1 byte) - txBuffer[idx++] = (byte)Native.FT_OPCODE.ClockDataBytesOutOnMinusVeClockMSBFirst; - txBuffer[idx++] = 0; - txBuffer[idx++] = 0; - txBuffer[idx++] = data; + const byte I2C_Data_SDAhi_SCLlo = 0x02; + const byte MSB_FALLING_EDGE_CLOCK_BYTE_OUT = 0x11; + const byte I2C_Dir_SDAout_SCLout = 0x03; + const byte MSB_RISING_EDGE_CLOCK_BIT_IN = 0x22; + + byte[] buffer = new byte[100]; + int bytesToSend = 0; + buffer[bytesToSend++] = MSB_FALLING_EDGE_CLOCK_BYTE_OUT; // clock data byte out + buffer[bytesToSend++] = 0x00; // + buffer[bytesToSend++] = 0x00; // Data length of 0x0000 means 1 byte data to clock in + buffer[bytesToSend++] = byteToSend; // Byte to send + // Put line back to idle (data released, clock pulled low) - _expander.GpioStateLow = (byte)(PinData.SDAloSCLlo | (_expander.GpioStateLow & MaskGpio)); - _expander.GpioDirectionLow = (byte)(PinDirection.SDAoutSCLout | (_expander.GpioDirectionLow & MaskGpio)); - txBuffer[idx++] = (byte)Native.FT_OPCODE.SetDataBitsLowByte; - txBuffer[idx++] = _expander.GpioStateLow; - txBuffer[idx++] = _expander.GpioDirectionLow; - // Clock in (0 = 1 bit) - txBuffer[idx++] = (byte)Native.FT_OPCODE.ClockDataBitsInOnPlusVeClockMSBFirst; - txBuffer[idx++] = 0; - txBuffer[idx++] = (byte)Native.FT_OPCODE.SendImmediate; - _expander.Write(txBuffer); - _expander.ReadInto(rxBuffer); - - return (rxBuffer[0] & 0x01) == 0 ? TransferStatus.Ack : TransferStatus.Nack; + buffer[bytesToSend++] = 0x80; // Command - set low byte + buffer[bytesToSend++] = I2C_Data_SDAhi_SCLlo; // Set the values + buffer[bytesToSend++] = I2C_Dir_SDAout_SCLout; // Set the directions + + // CLOCK IN ACK + buffer[bytesToSend++] = MSB_RISING_EDGE_CLOCK_BIT_IN; // clock data bits in + buffer[bytesToSend++] = 0x00; // Length of 0 means 1 bit + + // This command then tells the MPSSE to send any results gathered (in this case the ack bit) back immediately + buffer[bytesToSend++] = 0x87; + + // send commands to chip + byte[] msg = buffer.Take(bytesToSend).ToArray(); + _device.Write(msg).ThrowIfNotOK(); + + byte[] rx1 = _device.ReadBytes(1, out FT_STATUS status); + status.ThrowIfNotOK(); + + // if ack bit is 0 then sensor acked the transfer, otherwise it nak'd the transfer + bool ack = (rx1[0] & 0x01) == 0; + + return ack; + } + + private byte ReadDataByte(bool ACK = true) + { + const byte MSB_RISING_EDGE_CLOCK_BYTE_IN = 0x20; + const byte MSB_FALLING_EDGE_CLOCK_BIT_OUT = 0x13; + const byte I2C_Data_SDAhi_SCLlo = 0x02; + const byte I2C_Dir_SDAout_SCLout = 0x03; + int bytesToSend = 0; + + // Clock in one data byte + byte[] buffer = new byte[100]; + buffer[bytesToSend++] = MSB_RISING_EDGE_CLOCK_BYTE_IN; // Clock data byte in + buffer[bytesToSend++] = 0x00; + buffer[bytesToSend++] = 0x00; // Data length of 0x0000 means 1 byte data to clock in + + // clock out one bit as ack/nak bit + buffer[bytesToSend++] = MSB_FALLING_EDGE_CLOCK_BIT_OUT; // Clock data bit out + buffer[bytesToSend++] = 0x00; // Length of 0 means 1 bit + if (ACK == true) + buffer[bytesToSend++] = 0x00; // Data bit to send is a '0' + else + buffer[bytesToSend++] = 0xFF; // Data bit to send is a '1' + + // I2C lines back to idle state + buffer[bytesToSend++] = 0x80; // ' Command - set low byte + buffer[bytesToSend++] = I2C_Data_SDAhi_SCLlo; // ' Set the values + buffer[bytesToSend++] = I2C_Dir_SDAout_SCLout; // ' Set the directions + + // This command then tells the MPSSE to send any results gathered back immediately + buffer[bytesToSend++] = 0x87; // ' Send answer back immediate command + + // send commands to chip + byte[] msg = buffer.Take(bytesToSend).ToArray(); + _device.Write(msg).ThrowIfNotOK(); + + // get the byte which has been read from the driver's receive buffer + byte[] readBuffer = new byte[1]; + int bytesRead = 0; + _device.Read(readBuffer, 1, ref bytesRead).ThrowIfNotOK(); + + return readBuffer[0]; + } + + public void Dispose() + { + _device.Close(); } - internal override byte ReadDataByte(bool ackAfterRead) + public void Exchange(byte peripheralAddress, Span writeBuffer, Span readBuffer) { - int idx = 0; - Span toSend = stackalloc byte[10]; - Span toRead = stackalloc byte[1]; - - // The behavior is a bit different for FT232H and FT2232H/FT4232H - // Read one byte - toSend[idx++] = (byte)Native.FT_OPCODE.ClockDataBytesInOnPlusVeClockMSBFirst; - toSend[idx++] = 0; - toSend[idx++] = 0; - // Send out either ack either nak - toSend[idx++] = (byte)Native.FT_OPCODE.ClockDataBitsOutOnMinusVeClockMSBFirst; - toSend[idx++] = 0; - toSend[idx++] = (byte)(ackAfterRead ? 0x00 : 0xFF); - // I2C lines back to idle state - toSend[idx++] = (byte)Native.FT_OPCODE.SetDataBitsLowByte; - _expander.GpioStateLow = (byte)(PinData.SDAhiSCLlo | (_expander.GpioStateLow & MaskGpio)); - _expander.GpioDirectionLow = (byte)(PinDirection.SDAoutSCLout | (_expander.GpioDirectionLow & MaskGpio)); - toSend[idx++] = _expander.GpioStateLow; - toSend[idx++] = _expander.GpioDirectionLow; - toSend[idx++] = (byte)Native.FT_OPCODE.SendImmediate; - _expander.Write(toSend); - _expander.ReadInto(toRead); - return toRead[0]; + Start(); + CommandWrite(peripheralAddress); + for (int i = 0; i < writeBuffer.Length; i++) + { + SendDataByte(writeBuffer[i]); + } + + Start(); + + CommandRead(peripheralAddress); + for (int i = 0; i < readBuffer.Length; i++) + { + readBuffer[i] = ReadDataByte(ACK: true); + } + + Stop(); + } + + public void Read(byte peripheralAddress, Span readBuffer) + { + Start(); + + CommandRead(peripheralAddress); + + for (int i = 0; i < readBuffer.Length; i++) + { + readBuffer[i] = ReadDataByte(ACK: true); + } + + Stop(); + } + + public void Write(byte peripheralAddress, Span writeBuffer) + { + bool[] ack = new bool[writeBuffer.Length + 1]; + + Start(); + ack[0] = CommandWrite(peripheralAddress); + for (int i = 0; i < writeBuffer.Length; i++) + { + ack[i + 1] = SendDataByte(writeBuffer[i]); + } + Stop(); + + if (ack.Where(x => x == false).Any()) + { + Debug.WriteLine("WARNING: not all writes were ACK'd"); + Debug.WriteLine(string.Join(",", ack.Select(x => x.ToString()))); + } } } } \ No newline at end of file diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.Ft232hSpiBus.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.Ft232hSpiBus.cs index 9d66316631..7d47942841 100644 --- a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.Ft232hSpiBus.cs +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.Ft232hSpiBus.cs @@ -1,6 +1,8 @@ -using Meadow.Hardware; +using FTD2XX; +using Meadow.Hardware; using Meadow.Units; using System; +using System.Threading; namespace Meadow.Foundation.ICs.IOExpanders; @@ -9,63 +11,80 @@ public abstract partial class FtdiExpander /// /// Represents an SPI bus using the FT232H /// - public class Ft232hSpiBus : SpiBus + public class Ft232hSpiBus : ISpiBus { - private FtdiExpander _expander; + private readonly FTDI _device; private SpiClockConfiguration _configuration; /// - public override Frequency[] SupportedSpeeds => + public Frequency[] SupportedSpeeds => new Frequency[] { 1000000.Hertz() }; /// - public override SpiClockConfiguration Configuration => _configuration; + public SpiClockConfiguration Configuration => _configuration; - internal Ft232hSpiBus(FtdiExpander expander, SpiClockConfiguration configuration) + internal Ft232hSpiBus(FTDI device, int channel, SpiClockConfiguration configuration) { + _device = device; _configuration = configuration; - _expander = expander; + ConfigureMpsse(); } - internal override void Configure() + private void ConfigureMpsse() { - // Setup the clock and other elements - Span toSend = stackalloc byte[5]; - int idx = 0; - // Disable clock divide by 5 for 60Mhz master clock - toSend[idx++] = (byte)Native.FT_OPCODE.DisableClockDivideBy5; - // Turn off adaptive clocking - toSend[idx++] = (byte)Native.FT_OPCODE.TurnOffAdaptiveClocking; - // set SPI clock rate - toSend[idx++] = (byte)Native.FT_OPCODE.SetClockDivisor; - uint clockDivisor = (uint)(12000 / (_configuration.Speed.Kilohertz * 2)) - 1; - toSend[idx++] = (byte)(clockDivisor & 0x00FF); - toSend[idx++] = (byte)((clockDivisor >> 8) & 0x00FF); - - _expander.Write(toSend); - - // make the SCK and SDO lines outputs - _expander.SetGpioDirectionAndState(true, _expander.GpioDirectionLow |= 0x03, _expander.GpioStateLow); + _device.ResetDevice().ThrowIfNotOK(); + _device.SetBitMode(0, 0).ThrowIfNotOK(); // reset + _device.SetBitMode(0, 0x02).ThrowIfNotOK(); // MPSSE + _device.SetLatency(16).ThrowIfNotOK(); + _device.SetTimeouts(1000, 1000).ThrowIfNotOK(); // long + Thread.Sleep(50); + + // Configure the MPSSE for SPI communication (app note FT_000109 section 6) + byte[] bytes1 = new byte[] + { + 0x8A, // disable clock divide by 5 for 60Mhz master clock + 0x97, // turn off adaptive clocking + 0x8d // disable 3 phase data clock + }; + _device.Write(bytes1).ThrowIfNotOK(); + + // The SK clock frequency can be worked out by below algorithm with divide by 5 set as off + // SCL Frequency (MHz) = 60 / ((1 + DIVISOR) * 2) + var clockDivisor = 29; // for 1 MHz + + // increase clock divisor to slow down signaling + var slowDownFactor = 1; + clockDivisor *= slowDownFactor; + + // set the SCK and MOSI as outputs, with a value of low + byte[] bytes2 = new byte[] + { + 0x80, // Set directions of lower 8 pins + 0b00000000, // all low + 0x00000011, // MOSI and SCK output, others input + 0x86, // use clock divisor + (byte)(clockDivisor & 0xFF), // clock divisor low byte + (byte)(clockDivisor >> 8), // clock divisor high byte + }; + _device.Write(bytes2).ThrowIfNotOK(); + Thread.Sleep(50); + + // disable loopback + _device.Write(new byte[] { 0x85 }).ThrowIfNotOK(); + Thread.Sleep(50); + + //_expander.SetGpioDirectionAndState(true, _expander.GpioDirectionLow |= 0x03, _expander.GpioStateLow); } /// - public override void Exchange(IDigitalOutputPort? chipSelect, Span writeBuffer, Span readBuffer, ChipSelectMode csMode = ChipSelectMode.ActiveLow) + public void Exchange(IDigitalOutputPort? chipSelect, Span writeBuffer, Span readBuffer, ChipSelectMode csMode = ChipSelectMode.ActiveLow) { - byte clock; - switch (_configuration.SpiMode) + if (writeBuffer.Length > 65535) { - default: - case SpiClockConfiguration.Mode.Mode3: - case SpiClockConfiguration.Mode.Mode0: - clock = (byte)Native.FT_OPCODE.ClockDataBytesOutOnMinusVeClockMSBFirst; - break; - case SpiClockConfiguration.Mode.Mode2: - case SpiClockConfiguration.Mode.Mode1: - clock = (byte)Native.FT_OPCODE.ClockDataBytesOutOnPlusVeClockMSBFirst; - break; + throw new ArgumentException("Buffer too large, maximum size if 65535"); } if (chipSelect != null) @@ -73,14 +92,24 @@ public override void Exchange(IDigitalOutputPort? chipSelect, Span writeBu chipSelect.State = csMode == ChipSelectMode.ActiveLow ? false : true; } - int idx = 0; - Span toSend = stackalloc byte[3 + writeBuffer.Length]; - toSend[idx++] = clock; - toSend[idx++] = (byte)((writeBuffer.Length - 1) & 0xff); // LSB of length to write - toSend[idx++] = (byte)((writeBuffer.Length - 1) >> 8); ; // MSB of length to write - writeBuffer.CopyTo(toSend[3..]); - _expander.Write(toSend); - _expander.ReadInto(readBuffer); + var shiftOut = new byte[3 + writeBuffer.Length]; + shiftOut[0] = _configuration.SpiMode switch + { + SpiClockConfiguration.Mode.Mode0 => 0x31, + SpiClockConfiguration.Mode.Mode3 => 0x31, + _ => 0x34 + }; + shiftOut[1] = (byte)writeBuffer.Length; + shiftOut[2] = (byte)(writeBuffer.Length >> 8); + writeBuffer.CopyTo(shiftOut[3..]); + + _device.FlushBuffer(); + _device.Write(shiftOut).ThrowIfNotOK(); + + byte[] rx = new byte[readBuffer.Length]; + int bytesRead = 0; + _device.Read(rx, writeBuffer.Length, ref bytesRead).ThrowIfNotOK(); + rx.CopyTo(readBuffer); if (chipSelect != null) { @@ -89,35 +118,29 @@ public override void Exchange(IDigitalOutputPort? chipSelect, Span writeBu } /// - public override void Read(IDigitalOutputPort? chipSelect, Span readBuffer, ChipSelectMode csMode = ChipSelectMode.ActiveLow) + public void Read(IDigitalOutputPort? chipSelect, Span readBuffer, ChipSelectMode csMode = ChipSelectMode.ActiveLow) { - byte clock; - switch (_configuration.SpiMode) - { - default: - case SpiClockConfiguration.Mode.Mode3: - case SpiClockConfiguration.Mode.Mode0: - clock = (byte)Native.FT_OPCODE.ClockDataBytesInOnPlusVeClockMSBFirst; - break; - case SpiClockConfiguration.Mode.Mode2: - case SpiClockConfiguration.Mode.Mode1: - clock = (byte)Native.FT_OPCODE.ClockDataBytesInOnMinusVeClockMSBFirst; - break; - } - if (chipSelect != null) { chipSelect.State = csMode == ChipSelectMode.ActiveLow ? false : true; } - Span toSend = stackalloc byte[4]; - var idx = 0; - toSend[idx++] = clock; - toSend[idx++] = (byte)((readBuffer.Length - 1) & 0xff); // LSB of length to read - toSend[idx++] = (byte)((readBuffer.Length - 1) >> 8); ; // MSB of length to read - toSend[idx++] = (byte)Native.FT_OPCODE.SendImmediate; // read now - _expander.Write(toSend); - var readCount = _expander.ReadInto(readBuffer); + byte[] shiftOut = new byte[3]; + shiftOut[0] = _configuration.SpiMode switch + { + SpiClockConfiguration.Mode.Mode0 => 0x20, + SpiClockConfiguration.Mode.Mode3 => 0x20, + _ => 0x24 + }; + shiftOut[1] = (byte)readBuffer.Length; + shiftOut[2] = (byte)(readBuffer.Length >> 8); + + _device.Write(shiftOut).ThrowIfNotOK(); + + int bytesRead = 0; + var read = new byte[readBuffer.Length]; + _device.Read(read, readBuffer.Length, ref bytesRead).ThrowIfNotOK(); + read.CopyTo(readBuffer); if (chipSelect != null) { @@ -126,7 +149,7 @@ public override void Read(IDigitalOutputPort? chipSelect, Span readBuffer, } /// - public override void Write(IDigitalOutputPort? chipSelect, Span writeBuffer, ChipSelectMode csMode = ChipSelectMode.ActiveLow) + public void Write(IDigitalOutputPort? chipSelect, Span writeBuffer, ChipSelectMode csMode = ChipSelectMode.ActiveLow) { if (writeBuffer.Length > 65535) { @@ -158,7 +181,7 @@ public override void Write(IDigitalOutputPort? chipSelect, Span writeBuffe toSend[idx++] = (byte)((writeBuffer.Length - 1) & 0xff); // LSB of length to write toSend[idx++] = (byte)((writeBuffer.Length - 1) >> 8); ; // MSB of length to write writeBuffer.CopyTo(toSend[3..]); - _expander.Write(toSend); + // _expander.Write(toSend); if (chipSelect != null) { diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.Ft23xxI2cBus.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.Ft23xxI2cBus.cs deleted file mode 100644 index fea9caa4d4..0000000000 --- a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.Ft23xxI2cBus.cs +++ /dev/null @@ -1,185 +0,0 @@ -using Meadow.Hardware; -using System; - -namespace Meadow.Foundation.ICs.IOExpanders; - -public abstract partial class FtdiExpander -{ - /// - /// Represents an FTDI expander I2C bus. - /// - public class Ft23xxI2cBus : I2CBus, II2cBus - { - internal Ft23xxI2cBus(FtdiExpander expander, I2cBusSpeed busSpeed) - : base(expander, busSpeed) - { - } - - internal override void Configure() - { - // Setup the clock and other elements - Span toSend = stackalloc byte[10]; - int idx = 0; - // Disable clock divide by 5 for 60Mhz master clock - toSend[idx++] = (byte)Native.FT_OPCODE.DisableClockDivideBy5; - // Turn off adaptive clocking - toSend[idx++] = (byte)Native.FT_OPCODE.TurnOffAdaptiveClocking; - // Enable 3 phase data clock, used by I2C to allow data on both clock edges - toSend[idx++] = (byte)Native.FT_OPCODE.Enable3PhaseDataClocking; - // The SK clock frequency can be worked out by below algorithm with divide by 5 set as off - // TCK period = 60MHz / (( 1 + [ (0xValueH * 256) OR 0xValueL] ) * 2) - // Command to set clock divisor - toSend[idx++] = (byte)Native.FT_OPCODE.SetClockDivisor; - uint clockDivisor = (60000 / (((uint)BusSpeed / 1000) * 2)) - 1; - toSend[idx++] = (byte)(clockDivisor & 0x00FF); - toSend[idx++] = (byte)((clockDivisor >> 8) & 0x00FF); - // loopback off - toSend[idx++] = (byte)Native.FT_OPCODE.DisconnectTDItoTDOforLoopback; - // Enable the FT232H's drive-zero mode with the following enable mask - // toSend[idx++] = (byte)Native.FT_OPCODE.SetIOOnlyDriveOn0AndTristateOn1; - // Low byte (ADx) enables - bits 0, 1 and 2 - // toSend[idx++] = 0x07; - // High byte (ACx) enables - all off - // toSend[idx++] = 0x00; - // Command to set directions of lower 8 pins and force value on bits set as output - toSend[idx++] = (byte)Native.FT_OPCODE.SetDataBitsLowByte; - - // modify the GPIO state and direction without breaking other stuff - // SDA and SCL set low but as input to mimic open drain - _expander.GpioStateLow = (byte)(PinData.SDAloSCLlo | (_expander.GpioStateLow & MaskGpio)); - _expander.GpioDirectionLow = (byte)(PinDirection.SDAinSCLin | (_expander.GpioDirectionLow & MaskGpio)); - - toSend[idx++] = _expander.GpioStateLow; - toSend[idx++] = _expander.GpioDirectionLow; - _expander.Write(toSend); - } - - internal override void Start() - { - // Both SDA and SCL high (setting to input simulates open drain high) - var state = (byte)(PinData.SDAloSCLlo | (_expander.GpioStateLow & MaskGpio)); - Idle(); - Wait(6); - - // SDA low, SCL high (setting to input simulates open drain high) - var direction = (byte)(0x00 | PinDirection.SDAoutSCLin | (_expander.GpioDirectionLow & 0xF8)); - _expander.SetGpioDirectionAndState(true, direction, state); - Wait(6); - - // SDA low, SCL low - direction = (byte)(0x00 | PinDirection.SDAoutSCLout | (_expander.GpioDirectionLow & 0xF8)); - _expander.SetGpioDirectionAndState(true, direction, state); - Wait(6); - - // Release SDA (setting to input simulates open drain high) - direction = (byte)(0x00 | PinDirection.SDAinSCLout | (_expander.GpioDirectionLow & 0xF8)); - _expander.SetGpioDirectionAndState(true, direction, state); - Wait(6); - } - - internal override void Stop() - { - // SDA low, SCL low - var state = (byte)(PinData.SDAloSCLlo | (_expander.GpioStateLow & MaskGpio)); - var direction = (byte)(PinDirection.SDAoutSCLout | (_expander.GpioDirectionLow & MaskGpio)); - _expander.SetGpioDirectionAndState(true, direction, state); - Wait(6); - - - // SDA low, SCL high (note: setting to input simulates open drain high) - direction = (byte)(PinDirection.SDAoutSCLin | (_expander.GpioDirectionLow & MaskGpio)); - _expander.SetGpioDirectionAndState(true, direction, state); - Wait(6); - - // SDA high, SCL high (note: setting to input simulates open drain high) - direction = (byte)(PinDirection.SDAinSCLin | (_expander.GpioDirectionLow & MaskGpio)); - _expander.SetGpioDirectionAndState(true, direction, state); - Wait(6); - } - - internal override void Idle() - { - // SDA high, SCL high - var state = (byte)(PinData.SDAloSCLlo | (_expander.GpioStateLow & MaskGpio)); - // FT2232H/FT4232H use input to mimic open drain - var direction = (byte)(PinDirection.SDAinSCLin | (_expander.GpioDirectionLow & MaskGpio)); - _expander.SetGpioDirectionAndState(true, direction, state); - } - - internal override TransferStatus SendDataByte(byte data) - { - Span txBuffer = stackalloc byte[13]; - Span rxBuffer = stackalloc byte[1]; - var idx = 0; - - _expander.GpioStateLow = (byte)(0x00 | PinData.SDAloSCLlo | (_expander.GpioStateLow & 0xF8)); - _expander.GpioDirectionLow = (byte)(0x00 | PinDirection.SDAoutSCLout | (_expander.GpioDirectionLow & 0xF8));// back to output - txBuffer[idx++] = (byte)Native.FT_OPCODE.SetDataBitsLowByte; // Command - set low byte - txBuffer[idx++] = _expander.GpioStateLow; // Set the values - txBuffer[idx++] = _expander.GpioDirectionLow; // Set the directions - // clock out one byte - txBuffer[idx++] = (byte)Native.FT_OPCODE.ClockDataBytesOutOnMinusVeClockMSBFirst; // clock data byte out - txBuffer[idx++] = 0x00; // - txBuffer[idx++] = 0x00; // Data length of 0x0000 means 1 byte data to clock in - txBuffer[idx++] = data; // Byte to send - - // Put line back to idle (data released, clock pulled low) so that sensor can drive data line - _expander.GpioStateLow = (byte)(0x00 | PinData.SDAloSCLlo | (_expander.GpioStateLow & 0xF8)); - _expander.GpioDirectionLow = (byte)(0x00 | PinDirection.SDAinSCLout | (_expander.GpioDirectionLow & 0xF8)); // make data input - txBuffer[idx++] = 0x80; // Command - set low byte - txBuffer[idx++] = _expander.GpioStateLow; // Set the values - txBuffer[idx++] = _expander.GpioDirectionLow; // Set the directions - - // CLOCK IN ACK (0 == 1 bit) - txBuffer[idx++] = (byte)Native.FT_OPCODE.ClockDataBitsInOnPlusVeClockMSBFirst; // clock data byte in - txBuffer[idx++] = 0x00; // Length of 0 means 1 bit - - // This command then tells the MPSSE to send any results gathered (in this case the ack bit) back immediately - txBuffer[idx++] = (byte)Native.FT_OPCODE.SendImmediate; // ' Send answer back immediate command - _expander.Write(txBuffer); - _expander.ReadInto(rxBuffer); - - return (rxBuffer[0] & 0x01) == 0 ? TransferStatus.Ack : TransferStatus.Nack; - } - - internal override byte ReadDataByte(bool ackAfterRead) - { - int idx = 0; - Span toSend = stackalloc byte[16]; - Span toRead = stackalloc byte[1]; - - // Make sure no open gain - _expander.GpioStateLow = (byte)(PinData.SDAloSCLlo | (_expander.GpioStateLow & MaskGpio)); - _expander.GpioDirectionLow = (byte)(PinDirection.SDAinSCLout | (_expander.GpioDirectionLow & MaskGpio)); - toSend[idx++] = (byte)Native.FT_OPCODE.SetDataBitsLowByte; - toSend[idx++] = _expander.GpioStateLow; - toSend[idx++] = _expander.GpioDirectionLow; - // Read one byte - toSend[idx++] = (byte)Native.FT_OPCODE.ClockDataBytesInOnPlusVeClockMSBFirst; - toSend[idx++] = 0; - toSend[idx++] = 0; - // Change direction - _expander.GpioStateLow = (byte)(PinData.SDAloSCLlo | (_expander.GpioStateLow & MaskGpio)); - _expander.GpioDirectionLow = (byte)(PinDirection.SDAoutSCLout | (_expander.GpioDirectionLow & MaskGpio)); - toSend[idx++] = (byte)Native.FT_OPCODE.SetDataBitsLowByte; - toSend[idx++] = _expander.GpioStateLow; - toSend[idx++] = _expander.GpioDirectionLow; - // Send out either ack either nak - toSend[idx++] = (byte)Native.FT_OPCODE.ClockDataBitsOutOnMinusVeClockMSBFirst; - toSend[idx++] = 0; - toSend[idx++] = (byte)(ackAfterRead ? 0x00 : 0xFF); - // I2C lines back to idle state - toSend[idx++] = (byte)Native.FT_OPCODE.SetDataBitsLowByte; - _expander.GpioStateLow = (byte)(PinData.SDAhiSCLlo | (_expander.GpioStateLow & MaskGpio)); - _expander.GpioDirectionLow = (byte)(PinDirection.SDAinSCLout | (_expander.GpioDirectionLow & MaskGpio)); - toSend[idx++] = _expander.GpioStateLow; - toSend[idx++] = _expander.GpioDirectionLow; - - // And ask it right away - toSend[idx++] = (byte)Native.FT_OPCODE.SendImmediate; - _expander.Write(toSend); - _expander.ReadInto(toRead); - return toRead[0]; - } - } -} \ No newline at end of file diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.I2CBus.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.I2CBus.cs deleted file mode 100644 index 7fd19c4b1c..0000000000 --- a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.I2CBus.cs +++ /dev/null @@ -1,252 +0,0 @@ -using Meadow.Hardware; -using System; -using System.IO; -using System.Threading; - -namespace Meadow.Foundation.ICs.IOExpanders; - -/// -/// Represents an FTDI I2C bus expander. -/// -public abstract partial class FtdiExpander -{ - /// - /// Represents an I2C bus for the FTDI expander. - /// - public abstract class I2CBus : II2cBus - { - /// - /// The FTDI expander instance associated with this I2C bus. - /// - protected internal readonly FtdiExpander _expander; - - /// - /// Gets or sets the speed of the I2C bus. - /// - public I2cBusSpeed BusSpeed { get; set; } - - private SpinWait _spinWait = new(); - - /// - /// Configures the I2C bus. - /// - internal abstract void Configure(); - - /// - /// Starts the I2C communication. - /// - internal abstract void Start(); - - /// - /// Stops the I2C communication. - /// - internal abstract void Stop(); - - /// - /// Idles the I2C bus. - /// - internal abstract void Idle(); - - /// - /// Sends a data byte over the I2C bus. - /// - /// The data byte to send. - /// The transfer status after sending the data byte. - internal abstract TransferStatus SendDataByte(byte data); - - /// - /// Reads a data byte from the I2C bus. - /// - /// Whether to acknowledge after reading the byte. - /// The read data byte. - internal abstract byte ReadDataByte(bool ackAfterRead); - - /// - /// Mask for GPIO operations. - /// - protected internal const byte MaskGpio = 0xF8; - - /// - /// Initializes a new instance of the class. - /// - /// The FTDI expander instance. - /// The speed of the I2C bus. - internal I2CBus(FtdiExpander expander, I2cBusSpeed busSpeed) - { - _expander = expander; - BusSpeed = busSpeed; - } - - /// - /// Represents the status of an I2C transfer. - /// - internal enum TransferStatus - { - Ack = 0, - Nack - } - - /// - /// Contains constants for pin directions. - /// - protected static class PinDirection - { - /// - /// SDA in and SCL in - /// - public const byte SDAinSCLin = 0x00; - /// - /// SDA in and SCL out - /// - public const byte SDAinSCLout = 0x01; - /// - /// SDA out and SCL in - /// - public const byte SDAoutSCLin = 0x02; - /// - /// SDA out and SCL out - /// - public const byte SDAoutSCLout = 0x03; - } - - /// - /// Contains constants for pin data states. - /// - protected static class PinData - { - /// - /// SDA low and SCL high - /// - public const byte SDAloSCLhi = 0x01; - - /// - /// SDA high and SCL high - /// - public const byte SDAhiSCLhi = 0x03; - /// - /// SDA low and SCL low - /// - public const byte SDAloSCLlo = 0x00; - /// - /// SDA high and SCL low - /// - public const byte SDAhiSCLlo = 0x02; - } - - /// - /// Waits for a specified number of spin counts. - /// - /// The number of spin counts to wait. - protected void Wait(int spinCount) - { - for (var i = 0; i < spinCount; i++) - { - _spinWait.SpinOnce(); - } - } - - /// - /// Sends the address byte over the I2C bus. - /// - /// The address byte to send. - /// Indicates if the operation is a read operation. - /// The transfer status after sending the address byte. - private TransferStatus SendAddressByte(byte address, bool isRead) - { - // Set address for read or write - address <<= 1; - if (isRead == true) - { - address |= 0x01; - } - - return SendDataByte(address); - } - - /// - /// Writes data to a peripheral device. - /// - /// The address of the peripheral device. - /// The data buffer to write. - public void Write(byte peripheralAddress, Span writeBuffer) - { - Write(peripheralAddress, writeBuffer, true); - } - - /// - /// Writes data to a peripheral device with an option to send a stop condition. - /// - /// The address of the peripheral device. - /// The data buffer to write. - /// Whether to send a stop condition after writing. - public void Write(byte peripheralAddress, Span writeBuffer, bool terminatingStop) - { - Start(); - if (SendAddressByte(peripheralAddress, false) == TransferStatus.Nack) - { - Stop(); - throw new IOException($"Error writing device while setting up address"); - } - - for (int i = 0; i < writeBuffer.Length; i++) - { - if (SendDataByte(writeBuffer[i]) == TransferStatus.Nack) - { - Stop(); - throw new IOException($"Error writing device on byte {i}"); - } - } - - if (terminatingStop) - { - Stop(); - } - } - - /// - /// Releases all resources used by the . - /// - public void Dispose() - { - } - - /// - /// Exchanges data with a peripheral device. - /// - /// The address of the peripheral device. - /// The data buffer to write. - /// The data buffer to read. - public void Exchange(byte peripheralAddress, Span writeBuffer, Span readBuffer) - { - Write(peripheralAddress, writeBuffer, false); - Read(peripheralAddress, readBuffer); - } - - /// - /// Reads data from a peripheral device. - /// - /// The address of the peripheral device. - /// The data buffer to read. - public void Read(byte peripheralAddress, Span readBuffer) - { - Start(); - if (SendAddressByte(peripheralAddress, true) == TransferStatus.Nack) - { - Stop(); - throw new IOException($"Error reading device while setting up address"); - } - - for (int i = 0; i < readBuffer.Length - 1; i++) - { - readBuffer[i] = ReadDataByte(true); - } - - if (readBuffer.Length > 0) - { - readBuffer[readBuffer.Length - 1] = ReadDataByte(false); - } - - Stop(); - } - } -} \ No newline at end of file diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.SpiBus.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.SpiBus.cs deleted file mode 100644 index ac1c9a029c..0000000000 --- a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.SpiBus.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Meadow.Hardware; -using Meadow.Units; -using System; - -namespace Meadow.Foundation.ICs.IOExpanders; - -public abstract partial class FtdiExpander -{ - /// - /// Represnets the SPI bus for the FTDI expander - /// - public abstract class SpiBus : ISpiBus - { - /// - public abstract Frequency[] SupportedSpeeds { get; } - /// - public abstract SpiClockConfiguration Configuration { get; } - - internal abstract void Configure(); - - /// - public abstract void Exchange(IDigitalOutputPort? chipSelect, Span writeBuffer, Span readBuffer, ChipSelectMode csMode = ChipSelectMode.ActiveLow); - /// - public abstract void Read(IDigitalOutputPort? chipSelect, Span readBuffer, ChipSelectMode csMode = ChipSelectMode.ActiveLow); - /// - public abstract void Write(IDigitalOutputPort? chipSelect, Span writeBuffer, ChipSelectMode csMode = ChipSelectMode.ActiveLow); - } -} \ No newline at end of file diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.cs index 270ec65209..a21654e57d 100644 --- a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.cs +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.cs @@ -1,11 +1,8 @@ -using Meadow.Hardware; +using FTD2XX; +using Meadow.Hardware; using Meadow.Units; using System; -using System.IO; using System.Linq; -using System.Runtime.InteropServices; -using System.Threading; -using static Meadow.Foundation.ICs.IOExpanders.Native.Ftd2xx; namespace Meadow.Foundation.ICs.IOExpanders; @@ -20,13 +17,10 @@ public abstract partial class FtdiExpander : internal byte GpioDirectionHigh { get; set; } internal byte GpioStateHigh { get; set; } - internal uint Index { get; private set; } - internal uint Flags { get; private set; } - internal uint ID { get; private set; } - internal uint LocID { get; private set; } + internal FTDI Device { get; private set; } + internal int Index { get; private set; } internal string? SerialNumber { get; private set; } internal string? Description { get; private set; } - internal IntPtr Handle { get; private set; } /// public abstract II2cBus CreateI2cBus(int channel = 0, I2cBusSpeed busSpeed = I2cBusSpeed.Standard); @@ -39,66 +33,32 @@ public abstract partial class FtdiExpander : public PinDefinitions Pins { get; } internal static FtdiExpander Create( - uint index, - uint flags, - FtDeviceType deviceType, - uint id, - uint locid, + FTDI device, + int index, + FT_DEVICE deviceType, string serialNumber, - string description, - IntPtr handle) + string description) { FtdiExpander expander = deviceType switch { - FtDeviceType.Ft232H => new Ft232h + FT_DEVICE.FT_DEVICE_232H => new Ft232h { + Device = device, Index = index, - Flags = flags, - ID = id, - LocID = locid, SerialNumber = serialNumber, Description = description, - Handle = handle }, - FtDeviceType.Ft2232 => new Ft2232 - { - Index = index, - Flags = flags, - ID = id, - LocID = locid, - SerialNumber = serialNumber, - Description = description, - Handle = handle - }, - FtDeviceType.Ft2232H => new Ft232h - { - Index = index, - Flags = flags, - ID = id, - LocID = locid, - SerialNumber = serialNumber, - Description = description, - Handle = handle - }, - FtDeviceType.Ft4232H => throw new NotImplementedException(), _ => throw new NotSupportedException(), }; - expander.Open(); - expander.InitializeGpio(); - - return expander; - } - - private void Open() - { - if (Handle == IntPtr.Zero) + if (!device.IsOpen) { - Native.CheckStatus( - FT_OpenEx(LocID, Native.FT_OPEN_TYPE.FT_OPEN_BY_LOCATION, out IntPtr handle) - ); - Handle = handle; + device + .OpenByIndex(index) + .ThrowIfNotOK(); } + + return expander; } internal FtdiExpander() @@ -106,58 +66,14 @@ internal FtdiExpander() Pins = new PinDefinitions(this); } - private void InitializeGpio() - { - Native.FT_STATUS status; - status = Native.Ftd2xx.FT_SetUSBParameters(Handle, 65536, 65536); // Set USB request transfer sizes - status |= Native.Ftd2xx.FT_SetChars(Handle, 0, 0, 0, 0); // Disable event and error characters - status |= Native.Ftd2xx.FT_SetTimeouts(Handle, 5000, 5000); // Set the read and write timeouts to 5 seconds - status |= Native.Ftd2xx.FT_SetLatencyTimer(Handle, 16); // Keep the latency timer at default of 16ms - - status |= Native.Ftd2xx.FT_SetFlowControl(Handle, Native.FT_FLOWCONTROL.FT_FLOW_RTS_CTS, 0, 0); - - status |= Native.Ftd2xx.FT_SetBitMode(Handle, 0x00, Native.FT_BITMODE.FT_BITMODE_RESET); // Reset the mode to whatever is set in EEPROM - status |= Native.Ftd2xx.FT_SetBitMode(Handle, 0x00, Native.FT_BITMODE.FT_BITMODE_MPSSE); // Enable MPSSE mode - - Native.CheckStatus(status); - - Thread.Sleep(50); // the FTDI C example does this, so we keep it - - ClearInputBuffer(); - InitializeMpsse(); - } - - private void ClearInputBuffer() - { - var available = GetAvailableBytes(); - - if (available > 0) - { - var rxBuffer = new byte[available]; - uint bytesRead = 0; - Native.CheckStatus( - FT_Read(Handle, in rxBuffer[0], available, ref bytesRead)); - } - } - - private uint GetAvailableBytes() - { - uint availableBytes = 0; - - Native.CheckStatus( - FT_GetQueueStatus(Handle, ref availableBytes)); - - return availableBytes; - } - internal byte GetGpioStates(bool lowByte) { Span outBuffer = stackalloc byte[2]; Span inBuffer = stackalloc byte[1]; outBuffer[0] = (byte)(lowByte ? Native.FT_OPCODE.ReadDataBitsLowByte : Native.FT_OPCODE.ReadDataBitsHighByte); outBuffer[1] = (byte)Native.FT_OPCODE.SendImmediate; - Write(outBuffer); - ReadInto(inBuffer); + Device.Write(outBuffer.ToArray()); + inBuffer = Device.ReadBytes(inBuffer.Length, out FT_STATUS status); return inBuffer[0]; } @@ -169,7 +85,7 @@ internal void SetGpioDirectionAndState(bool lowByte, byte direction, byte state) outBuffer[2] = direction; //direction 1 == output, 0 == input // Console.WriteLine($"{(BitConverter.ToString(outBuffer.ToArray()))}"); - Write(outBuffer); + Device.Write(outBuffer.ToArray()); if (lowByte) { @@ -183,57 +99,6 @@ internal void SetGpioDirectionAndState(bool lowByte, byte direction, byte state) } } - private void InitializeMpsse() - { - // Synchronise the MPSSE by sending bad command AA to it - Span writeBuffer = stackalloc byte[1]; - writeBuffer[0] = 0xAA; - Write(writeBuffer); - Span readBuffer = stackalloc byte[2]; - ReadInto(readBuffer); - if (!((readBuffer[0] == 0xFA) && (readBuffer[1] == 0xAA))) - { - throw new IOException($"Failed to setup device in MPSSE mode using magic 0xAA sync"); - } - - // Synchronise the MPSSE by sending bad command AB to it - writeBuffer[0] = 0xAB; - Write(writeBuffer); - ReadInto(readBuffer); - if (!((readBuffer[0] == 0xFA) && (readBuffer[1] == 0xAB))) - { - throw new IOException($"Failed to setup device in MPSSE mode using magic 0xAB sync"); - } - } - - internal int ReadInto(Span buffer) - { - var totalRead = 0; - uint read = 0; - - while (totalRead < buffer.Length) - { - var available = GetAvailableBytes(); - if (available > 0) - { - Native.CheckStatus( - FT_Read(Handle, in buffer[totalRead], available, ref read)); - - totalRead += (int)read; - } - } - - return totalRead; - } - - internal void Write(ReadOnlySpan data) - { - uint written = 0; - - Native.CheckStatus( - FT_Write(Handle, in MemoryMarshal.GetReference(data), (ushort)data.Length, ref written)); - } - /// public IDigitalOutputPort CreateDigitalOutputPort(IPin pin, bool initialState = false, OutputType initialOutputType = OutputType.PushPull) { @@ -335,6 +200,8 @@ public ISpiBus CreateSpiBus(int channel = 0) /// public IDigitalInputPort CreateDigitalInputPort(IPin pin, ResistorMode resistorMode) { + throw new NotSupportedException(); + /* switch (resistorMode) { case ResistorMode.InternalPullUp: @@ -367,5 +234,6 @@ public IDigitalInputPort CreateDigitalInputPort(IPin pin, ResistorMode resistorM } return new DigitalInputPort(this, pin, (pin.SupportedChannels.First() as IDigitalChannelInfo)!, resistorMode); + */ } } diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpanderCollection.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpanderCollection.cs index b69fe0fa54..27888b477b 100644 --- a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpanderCollection.cs +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpanderCollection.cs @@ -1,9 +1,7 @@ -using System; +using FTD2XX; +using System; using System.Collections; using System.Collections.Generic; -using System.Runtime.InteropServices; -using System.Text; -using static Meadow.Foundation.ICs.IOExpanders.Native.Ftd2xx; namespace Meadow.Foundation.ICs.IOExpanders; @@ -36,42 +34,47 @@ private FtdiExpanderCollection() /// public void Refresh() { - Native.CheckStatus(Native.Ftd2xx.FT_CreateDeviceInfoList(out uint count)); + // the FTDI class is poorly designed. It holdsan internal handle, but also can be used to query globals + // until I rewrite it, we'll use this hack/trash + var api = new FTDI(); + + var deviceCount = 0; + api.GetNumberOfDevices(ref deviceCount).ThrowIfNotOK(); + var deviceInfos = new FT_DEVICE_INFO_NODE[deviceCount]; + api.GetDeviceList(deviceInfos).ThrowIfNotOK(); _expanders.Clear(); ReadOnlySpan serialNumberBuffer = stackalloc byte[16]; ReadOnlySpan descriptionBuffer = stackalloc byte[64]; - for (uint index = 0; index < count; index++) + for (int index = 0; index < deviceCount; index++) { - Native.CheckStatus(FT_GetDeviceInfoDetail( - index, - out uint flags, - out FtDeviceType deviceType, - out uint id, - out uint locid, - in MemoryMarshal.GetReference(serialNumberBuffer), - in MemoryMarshal.GetReference(descriptionBuffer), - out IntPtr handle)); - - switch (deviceType) + var device = new FTDI(); // create a new instance that will hold our handle + device.OpenByIndex(index); + + FT_DEVICE type = FT_DEVICE.FT_DEVICE_UNKNOWN; + + device.GetDeviceType(ref type); + + switch (type) { - case FtDeviceType.Ft232H: - case FtDeviceType.Ft2232: - case FtDeviceType.Ft2232H: - case FtDeviceType.Ft4232H: + case FT_DEVICE.FT_DEVICE_232H: + case FT_DEVICE.FT_DEVICE_2232H: + case FT_DEVICE.FT_DEVICE_4232H: + case FT_DEVICE.FT_DEVICE_2232: // valid, add to list break; default: continue; } - // no idea why the buffer isn't all zeros after the null terminator - thanks FTDI! - var serialNumber = Encoding.ASCII.GetString(serialNumberBuffer.ToArray(), 0, serialNumberBuffer.IndexOf((byte)0)); - var description = Encoding.ASCII.GetString(descriptionBuffer.ToArray(), 0, descriptionBuffer.IndexOf((byte)0)); + device.GetSerialNumber(out string serialNumber); + device.GetDescription(out string description); + + device.Close(); - _expanders.Add(FtdiExpander.Create(index, flags, deviceType, id, locid, serialNumber, description, handle)); + _expanders.Add(FtdiExpander.Create(device, index, type, serialNumber, description)); } } diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Native.Ftd2xx.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Native.Ftd2xx.cs index 39d8391e8c..e9fb81f506 100644 --- a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Native.Ftd2xx.cs +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/Native.Ftd2xx.cs @@ -34,7 +34,10 @@ public enum FtDeviceType public static extern FT_STATUS FT_GetDeviceInfoDetail(uint index, out uint flags, out FtDeviceType chiptype, out uint id, out uint locid, in byte serialnumber, in byte description, out IntPtr ftHandle); [DllImport(FTDI_LIB, CallingConvention = CallingConvention.Cdecl, SetLastError = true)] - public static extern FT_STATUS FT_OpenEx(uint pvArg1, FT_OPEN_TYPE dwFlags, out IntPtr ftHandle); + public static extern FT_STATUS FT_Open(int index, out IntPtr ftHandle); + + [DllImport(FTDI_LIB, CallingConvention = CallingConvention.Cdecl, SetLastError = true)] + public static extern FT_STATUS FT_OpenEx(int pvArg1, FT_OPEN_TYPE dwFlags, out IntPtr ftHandle); [DllImport(FTDI_LIB, CallingConvention = CallingConvention.Cdecl, SetLastError = true)] public static extern FT_STATUS FT_Close(IntPtr ftHandle); diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Ahtx0/Driver/Ahtx0.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Ahtx0/Driver/Ahtx0.cs index 54bf726cd5..f4a81f35dc 100644 --- a/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Ahtx0/Driver/Ahtx0.cs +++ b/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Ahtx0/Driver/Ahtx0.cs @@ -97,6 +97,7 @@ private async Task InitializeIfRequired() private bool IsBusy() { BusComms.Read(ReadBuffer.Span[0..1]); + return (ReadBuffer.Span[0] & 0x80) == 0x80; } diff --git a/Source/Meadow.Foundation.sln b/Source/Meadow.Foundation.sln index 1dbf572dfe..9d863e8a13 100644 --- a/Source/Meadow.Foundation.sln +++ b/Source/Meadow.Foundation.sln @@ -1495,6 +1495,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsciiConsole_Sample", "Mead EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BarChart_Sample", "Meadow.Foundation.Libraries_and_Frameworks\Graphics.MicroLayout\Samples\BarChart_Sample\BarChart_Sample.csproj", "{DEE00EAF-617D-4768-A2CB-A04729ADF426}" EndProject +Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "Bme280_VB_Sample", "Meadow.Foundation.Peripherals\Sensors.Atmospheric.Bmx280\Samples\Bme280_VB_Sample\Bme280_VB_Sample.vbproj", "{933A1748-3481-497E-94BC-8F93D5A6E9BA}" +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Silk", "Silk", "{0E913C73-609E-40D7-949C-553615CD13B8}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Displays.Silk", "Meadow.Foundation.Peripherals\Displays.Silk\Driver\Displays.Silk.csproj", "{37F84366-1DC7-4DDF-8C33-6A45219F4882}" @@ -1561,6 +1563,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Meadow.Desktop", "..\..\Mea EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Meadow.Mac", "..\..\Meadow.Core\Source\implementations\mac\Meadow.Mac\Meadow.Mac.csproj", "{FD7E56EE-6BBE-44BB-BB8B-8DB0647CDD0D}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ICs.IOExpanders.PCanBasic", "Meadow.Foundation.Peripherals\ICs.IOExpanders.PCanBasic\Driver\ICs.IOExpanders.PCanBasic.csproj", "{C7C2B091-E66B-4A83-84E4-9E6024981D41}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ICs.CAN.Mcp2515", "Meadow.Foundation.Peripherals\ICs.CAN.Mcp2515\Driver\ICs.CAN.Mcp2515.csproj", "{18785D65-35BB-4DCD-89EF-0D1DFA3F1463}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CAN", "CAN", "{5C9C0932-CA09-4599-8546-8373F79B37B7}" @@ -1591,10 +1595,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sensors.Color.Tcs3472x", "M EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tcs3472x_Sample", "Meadow.Foundation.Peripherals\Sensors.Color.Tcs3472x\Samples\Tcs3472x_Sample\Tcs3472x_Sample.csproj", "{08BECE38-EBCB-4A38-9F9B-0914F3C7592E}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PCanBasic", "PCanBasic", "{48CA0124-A227-4F35-BEFB-FF07F1CE6D20}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PCan", "PCan", "{48CA0124-A227-4F35-BEFB-FF07F1CE6D20}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{3D40446F-F902-4C89-93B9-2BE094BDE136}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PCanBasic_Sample", "Meadow.Foundation.Peripherals\ICs.IOExpanders.PCanBasic\Samples\PCanBasic_Sample\PCanBasic_Sample.csproj", "{506044BB-BEC1-42D1-AF84-CD28D4E2911A}" +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{97463BD7-A424-4720-B737-CB1D9A9C6AEF}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RTCs.Pcf8523", "Meadow.Foundation.Peripherals\RTCs.Pcf8523\Driver\RTCs.Pcf8523.csproj", "{947BDDE4-3F2D-4521-AC9E-CF6DF9D6935D}" @@ -1623,23 +1629,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ICs.IOExpanders.Ads1263", " EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ads1263_Sample", "Meadow.Foundation.Peripherals\ICs.IOExpanders.Ads1263\Samples\Ads1263_Sample\Ads1263_Sample.csproj", "{3A402704-9390-4492-93D4-B377BE8F034C}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "StepperOnline", "StepperOnline", "{CC1FB401-1B19-4254-9208-339661134D9B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Motors.StepperOnline", "Meadow.Foundation.Peripherals\Motors.StepperOnline\Driver\Motors.StepperOnline.csproj", "{D8D26232-ECA0-4042-88F4-7ECF1BC3E62F}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Keller.XLine", "Keller.XLine", "{2240AB38-3CC6-4800-8556-D3BB5C44B720}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sensors.Environmental.Keller.XLine", "Meadow.Foundation.Peripherals\Sensors.Environmental.Keller.XLine\Driver\Sensors.Environmental.Keller.XLine.csproj", "{729B86E1-49EE-4668-A599-8D7C28842F9E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Epd2in15g_Sample", "Meadow.Foundation.Peripherals\Displays.ePaperWaveShare\Samples\Epd2in15g_Sample\Epd2in15g_Sample.csproj", "{EA8D8CA1-BB32-49D6-88CF-9EB50ABDC44B}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Flow", "Flow", "{C5AA856B-4199-43B1-AECE-8871E91A0EF1}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Ad7768", "Ad7768", "{E586D03E-2A07-4401-94EE-7511794A57C1}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sensors.Flow.HallEffect", "Meadow.Foundation.Peripherals\Sensors.Flow.HallEffect\Driver\Sensors.Flow.HallEffect.csproj", "{EE40720A-33B0-4151-80AE-F73F9C1A45D8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ICs.ADC.Ad7768", "Meadow.Foundation.Peripherals\ICs.ADC.Ad7768\Driver\ICs.ADC.Ad7768.csproj", "{2AC67CED-7436-46C3-8228-D388D377733F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICs.CAN.PCanBasic", "Meadow.Foundation.Peripherals\ICs.CAN.PCanBasic\Driver\ICs.CAN.PCanBasic.csproj", "{477CEDDB-1C1E-401D-B878-8C310E3F652E}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{7BAA185F-A469-488A-A9CF-FE496F6AF2E6}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PCanBasic_Sample", "Meadow.Foundation.Peripherals\ICs.CAN.PCanBasic\Samples\PCanBasic_Sample\PCanBasic_Sample.csproj", "{C18E250D-37BA-407B-90A5-8846DDBE77AA}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ad7768_Sample", "Meadow.Foundation.Peripherals\ICs.ADC.Ad7768\Samples\Ad7768_Sample\Ad7768_Sample.csproj", "{D1B61010-72D2-4395-9666-62A7AD642C01}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -3763,6 +3759,10 @@ Global {DEE00EAF-617D-4768-A2CB-A04729ADF426}.Debug|Any CPU.Build.0 = Debug|Any CPU {DEE00EAF-617D-4768-A2CB-A04729ADF426}.Release|Any CPU.ActiveCfg = Release|Any CPU {DEE00EAF-617D-4768-A2CB-A04729ADF426}.Release|Any CPU.Build.0 = Release|Any CPU + {933A1748-3481-497E-94BC-8F93D5A6E9BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {933A1748-3481-497E-94BC-8F93D5A6E9BA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {933A1748-3481-497E-94BC-8F93D5A6E9BA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {933A1748-3481-497E-94BC-8F93D5A6E9BA}.Release|Any CPU.Build.0 = Release|Any CPU {37F84366-1DC7-4DDF-8C33-6A45219F4882}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {37F84366-1DC7-4DDF-8C33-6A45219F4882}.Debug|Any CPU.Build.0 = Debug|Any CPU {37F84366-1DC7-4DDF-8C33-6A45219F4882}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -3859,6 +3859,10 @@ Global {FD7E56EE-6BBE-44BB-BB8B-8DB0647CDD0D}.Debug|Any CPU.Build.0 = Debug|Any CPU {FD7E56EE-6BBE-44BB-BB8B-8DB0647CDD0D}.Release|Any CPU.ActiveCfg = Release|Any CPU {FD7E56EE-6BBE-44BB-BB8B-8DB0647CDD0D}.Release|Any CPU.Build.0 = Release|Any CPU + {C7C2B091-E66B-4A83-84E4-9E6024981D41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C7C2B091-E66B-4A83-84E4-9E6024981D41}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C7C2B091-E66B-4A83-84E4-9E6024981D41}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C7C2B091-E66B-4A83-84E4-9E6024981D41}.Release|Any CPU.Build.0 = Release|Any CPU {18785D65-35BB-4DCD-89EF-0D1DFA3F1463}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {18785D65-35BB-4DCD-89EF-0D1DFA3F1463}.Debug|Any CPU.Build.0 = Debug|Any CPU {18785D65-35BB-4DCD-89EF-0D1DFA3F1463}.Debug|Any CPU.Deploy.0 = Debug|Any CPU @@ -3901,6 +3905,10 @@ Global {08BECE38-EBCB-4A38-9F9B-0914F3C7592E}.Release|Any CPU.ActiveCfg = Release|Any CPU {08BECE38-EBCB-4A38-9F9B-0914F3C7592E}.Release|Any CPU.Build.0 = Release|Any CPU {08BECE38-EBCB-4A38-9F9B-0914F3C7592E}.Release|Any CPU.Deploy.0 = Release|Any CPU + {506044BB-BEC1-42D1-AF84-CD28D4E2911A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {506044BB-BEC1-42D1-AF84-CD28D4E2911A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {506044BB-BEC1-42D1-AF84-CD28D4E2911A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {506044BB-BEC1-42D1-AF84-CD28D4E2911A}.Release|Any CPU.Build.0 = Release|Any CPU {947BDDE4-3F2D-4521-AC9E-CF6DF9D6935D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {947BDDE4-3F2D-4521-AC9E-CF6DF9D6935D}.Debug|Any CPU.Build.0 = Debug|Any CPU {947BDDE4-3F2D-4521-AC9E-CF6DF9D6935D}.Debug|Any CPU.Deploy.0 = Debug|Any CPU @@ -3937,36 +3945,18 @@ Global {3A402704-9390-4492-93D4-B377BE8F034C}.Release|Any CPU.ActiveCfg = Release|Any CPU {3A402704-9390-4492-93D4-B377BE8F034C}.Release|Any CPU.Build.0 = Release|Any CPU {3A402704-9390-4492-93D4-B377BE8F034C}.Release|Any CPU.Deploy.0 = Release|Any CPU - {D8D26232-ECA0-4042-88F4-7ECF1BC3E62F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D8D26232-ECA0-4042-88F4-7ECF1BC3E62F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D8D26232-ECA0-4042-88F4-7ECF1BC3E62F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D8D26232-ECA0-4042-88F4-7ECF1BC3E62F}.Release|Any CPU.Build.0 = Release|Any CPU - {729B86E1-49EE-4668-A599-8D7C28842F9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {729B86E1-49EE-4668-A599-8D7C28842F9E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {729B86E1-49EE-4668-A599-8D7C28842F9E}.Debug|Any CPU.Deploy.0 = Debug|Any CPU - {729B86E1-49EE-4668-A599-8D7C28842F9E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {729B86E1-49EE-4668-A599-8D7C28842F9E}.Release|Any CPU.Build.0 = Release|Any CPU - {729B86E1-49EE-4668-A599-8D7C28842F9E}.Release|Any CPU.Deploy.0 = Release|Any CPU - {EA8D8CA1-BB32-49D6-88CF-9EB50ABDC44B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EA8D8CA1-BB32-49D6-88CF-9EB50ABDC44B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EA8D8CA1-BB32-49D6-88CF-9EB50ABDC44B}.Debug|Any CPU.Deploy.0 = Debug|Any CPU - {EA8D8CA1-BB32-49D6-88CF-9EB50ABDC44B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EA8D8CA1-BB32-49D6-88CF-9EB50ABDC44B}.Release|Any CPU.Build.0 = Release|Any CPU - {EA8D8CA1-BB32-49D6-88CF-9EB50ABDC44B}.Release|Any CPU.Deploy.0 = Release|Any CPU - {EE40720A-33B0-4151-80AE-F73F9C1A45D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EE40720A-33B0-4151-80AE-F73F9C1A45D8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EE40720A-33B0-4151-80AE-F73F9C1A45D8}.Debug|Any CPU.Deploy.0 = Debug|Any CPU - {EE40720A-33B0-4151-80AE-F73F9C1A45D8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EE40720A-33B0-4151-80AE-F73F9C1A45D8}.Release|Any CPU.Build.0 = Release|Any CPU - {EE40720A-33B0-4151-80AE-F73F9C1A45D8}.Release|Any CPU.Deploy.0 = Release|Any CPU - {477CEDDB-1C1E-401D-B878-8C310E3F652E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {477CEDDB-1C1E-401D-B878-8C310E3F652E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {477CEDDB-1C1E-401D-B878-8C310E3F652E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {477CEDDB-1C1E-401D-B878-8C310E3F652E}.Release|Any CPU.Build.0 = Release|Any CPU - {C18E250D-37BA-407B-90A5-8846DDBE77AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C18E250D-37BA-407B-90A5-8846DDBE77AA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C18E250D-37BA-407B-90A5-8846DDBE77AA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C18E250D-37BA-407B-90A5-8846DDBE77AA}.Release|Any CPU.Build.0 = Release|Any CPU + {2AC67CED-7436-46C3-8228-D388D377733F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2AC67CED-7436-46C3-8228-D388D377733F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2AC67CED-7436-46C3-8228-D388D377733F}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {2AC67CED-7436-46C3-8228-D388D377733F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2AC67CED-7436-46C3-8228-D388D377733F}.Release|Any CPU.Build.0 = Release|Any CPU + {2AC67CED-7436-46C3-8228-D388D377733F}.Release|Any CPU.Deploy.0 = Release|Any CPU + {D1B61010-72D2-4395-9666-62A7AD642C01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D1B61010-72D2-4395-9666-62A7AD642C01}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D1B61010-72D2-4395-9666-62A7AD642C01}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {D1B61010-72D2-4395-9666-62A7AD642C01}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D1B61010-72D2-4395-9666-62A7AD642C01}.Release|Any CPU.Build.0 = Release|Any CPU + {D1B61010-72D2-4395-9666-62A7AD642C01}.Release|Any CPU.Deploy.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -4713,6 +4703,7 @@ Global {1A156008-49C6-4ADD-BED9-1CF98D8FB076} = {21C511DD-43DD-486E-86D7-18D8F6810ACD} {85383653-A9EC-4023-BBA1-419A5CC30A78} = {40687DAC-F3EF-4F70-850A-0429B9586648} {DEE00EAF-617D-4768-A2CB-A04729ADF426} = {E762EEFF-E646-4517-BAE6-4E23A34854DC} + {933A1748-3481-497E-94BC-8F93D5A6E9BA} = {21C511DD-43DD-486E-86D7-18D8F6810ACD} {0E913C73-609E-40D7-949C-553615CD13B8} = {2B794146-DFEE-475A-B919-7D3ED48587B8} {37F84366-1DC7-4DDF-8C33-6A45219F4882} = {0E913C73-609E-40D7-949C-553615CD13B8} {3D090B0B-F863-4B8A-942C-89ED6C71BFF2} = {0E913C73-609E-40D7-949C-553615CD13B8} @@ -4744,6 +4735,7 @@ Global {2BB9FA79-851A-48EE-A2E1-91AE3F2B61EF} = {E0384B86-37FC-403C-B1F7-AA5D1B869EB1} {84CEDB6D-C9B1-4317-8A4E-84785ACCA6D1} = {2BB9FA79-851A-48EE-A2E1-91AE3F2B61EF} {F531D6BC-D3F2-4AFF-A84B-59351E2FA462} = {2BB9FA79-851A-48EE-A2E1-91AE3F2B61EF} + {C7C2B091-E66B-4A83-84E4-9E6024981D41} = {48CA0124-A227-4F35-BEFB-FF07F1CE6D20} {18785D65-35BB-4DCD-89EF-0D1DFA3F1463} = {066DBCFD-A21D-4FD2-87A5-B88363158149} {5C9C0932-CA09-4599-8546-8373F79B37B7} = {A1917BD0-881F-4775-88D9-38D42D448CF5} {066DBCFD-A21D-4FD2-87A5-B88363158149} = {5C9C0932-CA09-4599-8546-8373F79B37B7} @@ -4761,6 +4753,7 @@ Global {08BECE38-EBCB-4A38-9F9B-0914F3C7592E} = {C883EE04-FAC0-4734-9983-5BBF8E817ECF} {48CA0124-A227-4F35-BEFB-FF07F1CE6D20} = {5C9C0932-CA09-4599-8546-8373F79B37B7} {3D40446F-F902-4C89-93B9-2BE094BDE136} = {48CA0124-A227-4F35-BEFB-FF07F1CE6D20} + {506044BB-BEC1-42D1-AF84-CD28D4E2911A} = {3D40446F-F902-4C89-93B9-2BE094BDE136} {97463BD7-A424-4720-B737-CB1D9A9C6AEF} = {066DBCFD-A21D-4FD2-87A5-B88363158149} {947BDDE4-3F2D-4521-AC9E-CF6DF9D6935D} = {DA1B8F44-071F-492F-A1CA-66D656B9142E} {DA1B8F44-071F-492F-A1CA-66D656B9142E} = {15C7A398-35B0-4035-AE4B-FE84026D0D9E} @@ -4775,15 +4768,10 @@ Global {BEAD51B2-CF51-4836-ACBA-0911841E00F6} = {6D5016B9-7BF5-4E9D-BBA4-A621BAE0E638} {B414A340-EA69-4CD3-AB8B-D0B3835527B2} = {6D5016B9-7BF5-4E9D-BBA4-A621BAE0E638} {3A402704-9390-4492-93D4-B377BE8F034C} = {BEAD51B2-CF51-4836-ACBA-0911841E00F6} - {CC1FB401-1B19-4254-9208-339661134D9B} = {2486B48D-D4A2-4505-BF50-F33B2E15DA97} - {D8D26232-ECA0-4042-88F4-7ECF1BC3E62F} = {CC1FB401-1B19-4254-9208-339661134D9B} - {2240AB38-3CC6-4800-8556-D3BB5C44B720} = {78E463DA-0FA1-4AAE-A281-D3297C9388C9} - {729B86E1-49EE-4668-A599-8D7C28842F9E} = {2240AB38-3CC6-4800-8556-D3BB5C44B720} - {EA8D8CA1-BB32-49D6-88CF-9EB50ABDC44B} = {7311794D-7D2F-47E8-A5B0-C216CBD64A13} - {C5AA856B-4199-43B1-AECE-8871E91A0EF1} = {9F4EEBFB-F2B6-4B28-ABAD-D219F4AB15F3} - {EE40720A-33B0-4151-80AE-F73F9C1A45D8} = {C5AA856B-4199-43B1-AECE-8871E91A0EF1} - {477CEDDB-1C1E-401D-B878-8C310E3F652E} = {48CA0124-A227-4F35-BEFB-FF07F1CE6D20} - {C18E250D-37BA-407B-90A5-8846DDBE77AA} = {3D40446F-F902-4C89-93B9-2BE094BDE136} + {E586D03E-2A07-4401-94EE-7511794A57C1} = {E97B3C9A-7F99-4482-989D-56146C87055A} + {2AC67CED-7436-46C3-8228-D388D377733F} = {E586D03E-2A07-4401-94EE-7511794A57C1} + {7BAA185F-A469-488A-A9CF-FE496F6AF2E6} = {E586D03E-2A07-4401-94EE-7511794A57C1} + {D1B61010-72D2-4395-9666-62A7AD642C01} = {7BAA185F-A469-488A-A9CF-FE496F6AF2E6} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {AF7CA16F-8C38-4546-87A2-5DAAF58A1520}