export ft_ee_read, ft_ee_program
export FtProgramData
export FT_232R_CBUS_TXDEN, FT_232R_CBUS_PWRON, FT_232R_CBUS_RXLED, 
       FT_232R_CBUS_TXLED, FT_232R_CBUS_TXRXLED, FT_232R_CBUS_SLEEP,
       FT_232R_CBUS_CLK48, FT_232R_CBUS_CLK24, FT_232R_CBUS_CLK12,
       FT_232R_CBUS_CLK6, FT_232R_CBUS_IOMODE, FT_232R_CBUS_BITBANG_WR,
       FT_232R_CBUS_BITBANG_RD
export FT_232H_CBUS_TRISTATE, FT_232H_CBUS_RXLED, FT_232H_CBUS_TXLED,
       FT_232H_CBUS_TXRXLED, FT_232H_CBUS_PWREN, FT_232H_CBUS_SLEEP,
       FT_232H_CBUS_DRIVE_0, FT_232H_CBUS_DRIVE_1, FT_232H_CBUS_IOMODE,
       FT_232H_CBUS_TXDEN, FT_232H_CBUS_CLK30, FT_232H_CBUS_CLK15,
       FT_232H_CBUS_CLK7_5
export FT_X_SERIES_CBUS_TRISTATE, FT_X_SERIES_CBUS_RXLED, FT_X_SERIES_CBUS_TXLED,
       FT_X_SERIES_CBUS_TXRXLED, FT_X_SERIES_CBUS_PWREN, FT_X_SERIES_CBUS_SLEEP,
       FT_X_SERIES_CBUS_DRIVE_0, FT_X_SERIES_CBUS_DRIVE_1, FT_X_SERIES_CBUS_IOMODE,
       FT_X_SERIES_CBUS_TXDEN, FT_X_SERIES_CBUS_CLK24, FT_X_SERIES_CBUS_CLK12,
       FT_X_SERIES_CBUS_CLK6, FT_X_SERIES_CBUS_BCD_CHARGER, FT_X_SERIES_CBUS_BCD_CHARGER_N,
       FT_X_SERIES_CBUS_I2C_TXE, FT_X_SERIES_CBUS_I2C_RXF, FT_X_SERIES_CBUS_VBUS_SENSE,
       FT_X_SERIES_CBUS_BITBANG_WR, FT_X_SERIES_CBUS_BITBANG_RD, FT_X_SERIES_CBUS_TIMESTAMP,
       FT_X_SERIES_CBUS_KEEP_AWAKE
export FT_DRIVER_TYPE_D2XX, FT_DRIVER_TYPE_VCP

#FT232R CBUS EEPROM OPTIONS - Ignored for FT245R (see ft_ee_program and ft_ee_read) 
const FT_232R_CBUS_TXDEN = 0x00 
const FT_232R_CBUS_PWRON = 0x01 
const FT_232R_CBUS_RXLED = 0x02 
const FT_232R_CBUS_TXLED = 0x03 
const FT_232R_CBUS_TXRXLED = 0x04 
const FT_232R_CBUS_SLEEP = 0x05 
const FT_232R_CBUS_CLK48 = 0x06 
const FT_232R_CBUS_CLK24 = 0x07 
const FT_232R_CBUS_CLK12 = 0x08 
const FT_232R_CBUS_CLK6 = 0x09 
const FT_232R_CBUS_IOMODE = 0x0A 
const FT_232R_CBUS_BITBANG_WR = 0x0B 
const FT_232R_CBUS_BITBANG_RD = 0x0C

#FT232H CBUS EEPROM OPTIONS (see ft_ee_program and ft_ee_read) 
const FT_232H_CBUS_TRISTATE = 0x00 
const FT_232H_CBUS_RXLED = 0x01 
const FT_232H_CBUS_TXLED = 0x02 
const FT_232H_CBUS_TXRXLED = 0x03 
const FT_232H_CBUS_PWREN = 0x04 
const FT_232H_CBUS_SLEEP = 0x05 
const FT_232H_CBUS_DRIVE_0 = 0x06 
const FT_232H_CBUS_DRIVE_1 = 0x07 
const FT_232H_CBUS_IOMODE = 0x08 
const FT_232H_CBUS_TXDEN = 0x09 
const FT_232H_CBUS_CLK30 = 0x0A 
const FT_232H_CBUS_CLK15 = 0x0B 
const FT_232H_CBUS_CLK7_5 = 0x0C

#FT X Series CBUS Options EEPROM values (see ft_eeprom_read and ft_eeprom_program)
const FT_X_SERIES_CBUS_TRISTATE = 0x00
const FT_X_SERIES_CBUS_RXLED = 0x01
const FT_X_SERIES_CBUS_TXLED = 0x02
const FT_X_SERIES_CBUS_TXRXLED = 0x03
const FT_X_SERIES_CBUS_PWREN = 0x04
const FT_X_SERIES_CBUS_SLEEP = 0x05
const FT_X_SERIES_CBUS_DRIVE_0 = 0x06
const FT_X_SERIES_CBUS_DRIVE_1 = 0x07
const FT_X_SERIES_CBUS_IOMODE = 0x08
const FT_X_SERIES_CBUS_TXDEN = 0x09
const FT_X_SERIES_CBUS_CLK24 = 0x0A
const FT_X_SERIES_CBUS_CLK12 = 0x0B
const FT_X_SERIES_CBUS_CLK6 = 0x0C
const FT_X_SERIES_CBUS_BCD_CHARGER = 0x0D
const FT_X_SERIES_CBUS_BCD_CHARGER_N = 0x0E
const FT_X_SERIES_CBUS_I2C_TXE = 0x0F
const FT_X_SERIES_CBUS_I2C_RXF = 0x10
const FT_X_SERIES_CBUS_VBUS_SENSE = 0x11
const FT_X_SERIES_CBUS_BITBANG_WR = 0x12
const FT_X_SERIES_CBUS_BITBANG_RD = 0x13
const FT_X_SERIES_CBUS_TIMESTAMP = 0x14
const FT_X_SERIES_CBUS_KEEP_AWAKE = 0x15

# Driver types
const FT_DRIVER_TYPE_D2XX = 0
const FT_DRIVER_TYPE_VCP = 1

# FT_PROGRAM_DATA_STRUCTURE 
type FtProgramData_C
  Signature1 :: Cuint # Header - must be 0x0000000
  Signature2 :: Cuint # Header - must be 0xffffffff
  Version :: Cuint # Header - FT_PROGRAM_DATA version 
                   # 0 = original (FT232B) 
                   # 1 = FT2232 extensions 
                   # 2 = FT232R extensions
                   # 3 = FT2232H extensions
                   # 4 = FT4232H extensions
                   # 5 = FT232H extensions
  VendorId :: Cushort # 0x0403 
  ProductId :: Cushort # 0x6001 
  Manufacturer :: Ptr{UInt8}    # "FTDI"
  ManufacturerId :: Ptr{UInt8} # "FT" 
  Description :: Ptr{UInt8}    # "USB HS Serial Converter" 
  SerialNumber :: Ptr{UInt8}   # "FT000001" if fixed, or NULL 
  MaxPower :: Cushort # 0 < MaxPower <= 500
  PnP :: Cushort # 0 = disabled, 1 = enabled 
  SelfPowered :: Cushort # 0 = bus powered, 1 = self powered 
  RemoteWakeup :: Cushort  # 0 = not capable, 1 = capable
  #
  # Rev4 (FT232B) extensions 
  #
  Rev4 :: Cuchar # non-zero if Rev4 chip, zero otherwise 
  IsoIn :: Cuchar # non-zero if in endpoint is isochronous 
  IsoOut :: Cuchar # non-zero if out endpoint is isochronous
  PullDownEnable :: Cuchar # non-zero if pull down enabled 
  SerNumEnable :: Cuchar # non-zero if serial number to be used 
  USBVersionEnable :: Cuchar # non-zero if chip uses USBVersion 
  USBVersion :: Cushort # BCD (0x0200 => USB2) 
  #
  # Rev 5 (FT2232) extensions
  #
  Rev5 :: Cuchar # non-zero if Rev5 chip, zero otherwise 
  IsoInA :: Cuchar # non-zero if in endpoint is isochronous
  IsoInB :: Cuchar # non-zero if in endpoint is isochronous
  IsoOutA :: Cuchar # non-zero if out endpoint is isochronous
  IsoOutB :: Cuchar # non-zero if out endpoint is isochronous 
  PullDownEnable5 :: Cuchar # non-zero if pull down enabled 
  SerNumEnable5 :: Cuchar # non-zero if serial number to be used
  USBVersionEnable5 :: Cuchar # non-zero if chip uses USBVersion 
  USBVersion5 :: Cshort # BCD (0x0200 => USB2) 
  AIsHighCurrent :: Cuchar # non-zero if interface is high current 
  BIsHighCurrent :: Cuchar # non-zero if interface is high current 
  IFAIsFifo :: Cuchar # non-zero if interface is 245 FIFO 
  IFAIsFifoTar :: Cuchar # non-zero if interface is 245 FIFO CPU target
  IFAIsFastSer :: Cuchar # non-zero if interface is Fast serial 
  AIsVCP :: Cuchar # non-zero if interface is to use VCP drivers 
  IFBIsFifo :: Cuchar # non-zero if interface is 245 FIFO
  IFBIsFifoTar :: Cuchar # non-zero if interface is 245 FIFO CPU target 
  IFBIsFastSer :: Cuchar # non-zero if interface is Fast serial
  BIsVCP  :: Cuchar # non-zero if interface is to use VCP drivers 
  #
  # Rev 6 (FT232R) extensions
  #
  UseExtOsc :: Cuchar # Use External Oscillator 
  HighDriveIOs :: Cuchar # High Drive I/Os 
  EndpointSize :: Cuchar # Endpoint size 
  PullDownEnableR :: Cuchar # non-zero if pull down enabled 
  SerNumEnableR :: Cuchar # non-zero if serial number to be used 
  InvertTXD :: Cuchar # non-zero if invert TXD 
  InvertRXD :: Cuchar # non-zero if invert RXD 
  InvertRTS :: Cuchar # non-zero if invert RTS 
  InvertCTS :: Cuchar # non-zero if invert CTS 
  InvertDTR :: Cuchar # non-zero if invert DTR 
  InvertDSR :: Cuchar # non-zero if invert DSR
  InvertDCD :: Cuchar # non-zero if invert DCD 
  InvertRI  :: Cuchar # non-zero if invert RI 
  Cbus0 :: Cuchar # Cbus Mux control 
  Cbus1 :: Cuchar # Cbus Mux control 
  Cbus2 :: Cuchar # Cbus Mux control 
  Cbus3 :: Cuchar # Cbus Mux control 
  Cbus4 :: Cuchar # Cbus Mux control
  RIsD2XX :: Cuchar # non-zero if using D2XX driver 
  #
  # Rev 7 (FT2232H) Extensions 
  #
  PullDownEnable7 :: Cuchar # non-zero if pull down enabled 
  SerNumEnable7 :: Cuchar # non-zero if serial number to be used 
  ALSlowSlew :: Cuchar # non-zero if AL pins have slow slew 
  ALSchmittInput :: Cuchar # non-zero if AL pins are Schmitt input 
  ALDriveCurrent :: Cuchar # valid values are 4mA, 8mA, 12mA, 16mA 
  AHSlowSlew :: Cuchar # non-zero if AH pins have slow slew 
  AHSchmittInput :: Cuchar # non-zero if AH pins are Schmitt input 
  AHDriveCurrent :: Cuchar # valid values are 4mA, 8mA, 12mA, 16mA 
  BLSlowSlew :: Cuchar # non-zero if BL pins have slow slew 
  BLSchmittInput :: Cuchar # non-zero if BL pins are Schmitt input 
  BLDriveCurrent :: Cuchar # valid values are 4mA, 8mA, 12mA, 16mA 
  BHSlowSlew :: Cuchar # non-zero if BH pins have slow slew 
  BHSchmittInput :: Cuchar # non-zero if BH pins are Schmitt input 
  BHDriveCurrent :: Cuchar # valid values are 4mA, 8mA, 12mA, 16mA 
  IFAIsFifo7 :: Cuchar # non-zero if interface is 245 FIFO 
  IFAIsFifoTar7 :: Cuchar # non-zero if interface is 245 FIFO CPU target 
  IFAIsFastSer7 :: Cuchar # non-zero if interface is Fast serial 
  AIsVCP7 :: Cuchar # non-zero if interface is to use VCP drivers 
  IFBIsFifo7 :: Cuchar # non-zero if interface is 245 FIFO 
  IFBIsFifoTar7 :: Cuchar # non-zero if interface is 245 FIFO CPU target 
  IFBIsFastSer7 :: Cuchar # non-zero if interface is Fast serial 
  BIsVCP7 :: Cuchar # non-zero if interface is to use VCP drivers 
  PowerSaveEnable :: Cuchar # non-zero if using BCBUS7 to save power for self-powered designs 
  #
  # Rev 8 (FT4232H) Extensions 
  #
  PullDownEnable8 :: Cuchar # non-zero if pull down enabled 
  SerNumEnable8 :: Cuchar # non-zero if serial number to be used 
  ASlowSlew :: Cuchar # non-zero if AL pins have slow slew 
  ASchmittInput :: Cuchar # non-zero if AL pins are Schmitt input 
  ADriveCurrent :: Cuchar # valid values are 4mA, 8mA, 12mA, 16mA 
  BSlowSlew :: Cuchar # non-zero if AH pins have slow slew 
  BSchmittInput :: Cuchar # non-zero if AH pins are Schmitt input 
  BDriveCurrent :: Cuchar # valid values are 4mA, 8mA, 12mA, 16mA
  CSlowSlew :: Cuchar # non-zero if BL pins have slow slew 
  CSchmittInput :: Cuchar # non-zero if BL pins are Schmitt input 
  CDriveCurrent :: Cuchar # valid values are 4mA, 8mA, 12mA, 16mA 
  DSlowSlew :: Cuchar # non-zero if BH pins have slow slew 
  DSchmittInput :: Cuchar # non-zero if BH pins are Schmitt input 
  DDriveCurrent :: Cuchar # valid values are 4mA, 8mA, 12mA, 16mA 
  ARIIsTXDEN :: Cuchar # non-zero if port A uses RI as RS485 TXDEN 
  BRIIsTXDEN :: Cuchar # non-zero if port B uses RI as RS485 TXDEN 
  CRIIsTXDEN :: Cuchar # non-zero if port C uses RI as RS485 TXDEN 
  DRIIsTXDEN :: Cuchar # non-zero if port D uses RI as RS485 TXDEN 
  AIsVCP8 :: Cuchar # non-zero if interface is to use VCP drivers 
  BIsVCP8 :: Cuchar # non-zero if interface is to use VCP drivers 
  CIsVCP8 :: Cuchar # non-zero if interface is to use VCP drivers 
  DIsVCP8 :: Cuchar # non-zero if interface is to use VCP drivers 
  #
  # Rev 9 (FT232H) Extensions 
  #
  PullDownEnableH :: Cuchar # non-zero if pull down enabled 
  SerNumEnableH :: Cuchar # non-zero if serial number to be used 
  ACSlowSlewH :: Cuchar # non-zero if AC pins have slow slew 
  ACSchmittInputH :: Cuchar # non-zero if AC pins are Schmitt input 
  ACDriveCurrentH :: Cuchar # valid values are 4mA, 8mA, 12mA, 16mA 
  ADSlowSlewH :: Cuchar # non-zero if AD pins have slow slew 
  ADSchmittInputH :: Cuchar # non-zero if AD pins are Schmitt input 
  ADDriveCurrentH :: Cuchar # valid values are 4mA, 8mA, 12mA, 16mA 
  Cbus0H :: Cuchar # Cbus Mux control 
  Cbus1H :: Cuchar # Cbus Mux control 
  Cbus2H :: Cuchar # Cbus Mux control 
  Cbus3H :: Cuchar # Cbus Mux control 
  Cbus4H :: Cuchar # Cbus Mux control 
  Cbus5H :: Cuchar # Cbus Mux control 
  Cbus6H :: Cuchar # Cbus Mux control 
  Cbus7H :: Cuchar # Cbus Mux control 
  Cbus8H :: Cuchar # Cbus Mux control 
  Cbus9H :: Cuchar # Cbus Mux control 
  IsFifoH :: Cuchar # non-zero if interface is 245 FIFO 
  IsFifoTarH :: Cuchar # non-zero if interface is 245 FIFO CPU target 
  IsFastSerH :: Cuchar # non-zero if interface is Fast serial 
  IsFT1248H :: Cuchar # non-zero if interface is FT1248 
  FT1248CpolH :: Cuchar # FT1248 clock polarity - clock idle high (1) or clock idle low (0) 
  FT1248LsbH :: Cuchar # FT1248 data is LSB (1) or MSB (0) 
  FT1248FlowControlH :: Cuchar # FT1248 flow control enable 
  IsVCPH :: Cuchar # non-zero if interface is to use VCP drivers 
  PowerSaveEnableH :: Cuchar # non-zero if using ACBUS7 to save power for self-powered designs
  
  function FtProgramData_C(Version::Integer,
                           Manufacturer::ASCIIString,
                           ManufacturerId::ASCIIString,
                           Description::ASCIIString,
                           SerialNumber::ASCIIString)
    @assert (length(Manufacturer) + length(ManufacturerId)) < 41
    @assert length(Description)<=64
    @assert length(SerialNumber)<=16
    mfg = zeros(UInt8,41)
    mfgid = zeros(UInt8,41)
    d = zeros(UInt8,65)
    sn = zeros(UInt8,17)
    for (p,c) in enumerate(Manufacturer)
      mfg[p] = Int(c)
    end
    for (p,c) in enumerate(ManufacturerId)
      mfgid[p] = Int(c)
    end
    for (p,c) in enumerate(Description)
      d[p] = Int(c)
    end
    for (p,c) in enumerate(SerialNumber)
      sn[p] = Int(c)
    end
    mfgptr = pointer(mfg)
    mfgidptr = pointer(mfgid)
    dptr = pointer(d)
    snptr = pointer(sn)
    new(0x00000000, 0xffffffff, Version, 0, 0, mfgptr, mfgidptr, dptr, snptr)
  end
  FtProgramData_C(Version) = FtProgramData_C(Version,"","","","")  
end

type FtProgramData
  Signature1 :: UInt32 # Header - must be 0x0000000
  Signature2 :: UInt32 # Header - must be 0xffffffff
  Version :: UInt32 # Header - FT_PROGRAM_DATA version 
                   # 0 = original (FT232B) 
                   # 1 = FT2232 extensions 
                   # 2 = FT232R extensions
                   # 3 = FT2232H extensions
                   # 4 = FT4232H extensions
                   # 5 = FT232H extensions
  VendorId :: UInt16 # 0x0403 
  ProductId :: UInt16 # 0x6001 
  Manufacturer :: ASCIIString     # "FTDI"
  ManufacturerId :: ASCIIString  # "FT" 
  Description :: ASCIIString     # "USB HS Serial Converter" 
  SerialNumber :: ASCIIString    # "FT000001" if fixed, or NULL 
  MaxPower :: UInt16 # 0 < MaxPower <= 500
  PnP :: UInt16 # 0 = disabled, 1 = enabled 
  SelfPowered :: UInt16 # 0 = bus powered, 1 = self powered 
  RemoteWakeup :: UInt16  # 0 = not capable, 1 = capable
  #
  # Rev4 (FT232B) extensions 
  #
  Rev4 :: UInt8 # non-zero if Rev4 chip, zero otherwise 
  IsoIn :: UInt8 # non-zero if in endpoint is isochronous 
  IsoOut :: UInt8 # non-zero if out endpoint is isochronous
  PullDownEnable :: UInt8 # non-zero if pull down enabled 
  SerNumEnable :: UInt8 # non-zero if serial number to be used 
  USBVersionEnable :: UInt8 # non-zero if chip uses USBVersion 
  USBVersion :: UInt16 # BCD (0x0200 => USB2) 
  #
  # Rev 5 (FT2232) extensions
  #
  Rev5 :: UInt8 # non-zero if Rev5 chip, zero otherwise 
  IsoInA :: UInt8 # non-zero if in endpoint is isochronous
  IsoInB :: UInt8 # non-zero if in endpoint is isochronous
  IsoOutA :: UInt8 # non-zero if out endpoint is isochronous
  IsoOutB :: UInt8 # non-zero if out endpoint is isochronous 
  PullDownEnable5 :: UInt8 # non-zero if pull down enabled 
  SerNumEnable5 :: UInt8 # non-zero if serial number to be used
  USBVersionEnable5 :: UInt8 # non-zero if chip uses USBVersion 
  USBVersion5 :: UInt16 # BCD (0x0200 => USB2) 
  AIsHighCurrent :: UInt8 # non-zero if interface is high current 
  BIsHighCurrent :: UInt8 # non-zero if interface is high current 
  IFAIsFifo :: UInt8 # non-zero if interface is 245 FIFO 
  IFAIsFifoTar :: UInt8 # non-zero if interface is 245 FIFO CPU target
  IFAIsFastSer :: UInt8 # non-zero if interface is Fast serial 
  AIsVCP :: UInt8 # non-zero if interface is to use VCP drivers 
  IFBIsFifo :: UInt8 # non-zero if interface is 245 FIFO
  IFBIsFifoTar :: UInt8 # non-zero if interface is 245 FIFO CPU target 
  IFBIsFastSer :: UInt8 # non-zero if interface is Fast serial
  BIsVCP  :: UInt8 # non-zero if interface is to use VCP drivers 
  #
  # Rev 6 (FT232R) extensions
  #
  UseExtOsc :: UInt8 # Use External Oscillator 
  HighDriveIOs :: UInt8 # High Drive I/Os 
  EndpointSize :: UInt8 # Endpoint size 
  PullDownEnableR :: UInt8 # non-zero if pull down enabled 
  SerNumEnableR :: UInt8 # non-zero if serial number to be used 
  InvertTXD :: UInt8 # non-zero if invert TXD 
  InvertRXD :: UInt8 # non-zero if invert RXD 
  InvertRTS :: UInt8 # non-zero if invert RTS 
  InvertCTS :: UInt8 # non-zero if invert CTS 
  InvertDTR :: UInt8 # non-zero if invert DTR 
  InvertDSR :: UInt8 # non-zero if invert DSR
  InvertDCD :: UInt8 # non-zero if invert DCD 
  InvertRI  :: UInt8 # non-zero if invert RI 
  Cbus0 :: UInt8 # Cbus Mux control 
  Cbus1 :: UInt8 # Cbus Mux control 
  Cbus2 :: UInt8 # Cbus Mux control 
  Cbus3 :: UInt8 # Cbus Mux control 
  Cbus4 :: UInt8 # Cbus Mux control
  RIsD2XX :: UInt8 # non-zero if using D2XX driver 
  #
  # Rev 7 (FT2232H) Extensions 
  #
  PullDownEnable7 :: UInt8 # non-zero if pull down enabled 
  SerNumEnable7 :: UInt8 # non-zero if serial number to be used 
  ALSlowSlew :: UInt8 # non-zero if AL pins have slow slew 
  ALSchmittInput :: UInt8 # non-zero if AL pins are Schmitt input 
  ALDriveCurrent :: UInt8 # valid values are 4mA, 8mA, 12mA, 16mA 
  AHSlowSlew :: UInt8 # non-zero if AH pins have slow slew 
  AHSchmittInput :: UInt8 # non-zero if AH pins are Schmitt input 
  AHDriveCurrent :: UInt8 # valid values are 4mA, 8mA, 12mA, 16mA 
  BLSlowSlew :: UInt8 # non-zero if BL pins have slow slew 
  BLSchmittInput :: UInt8 # non-zero if BL pins are Schmitt input 
  BLDriveCurrent :: UInt8 # valid values are 4mA, 8mA, 12mA, 16mA 
  BHSlowSlew :: UInt8 # non-zero if BH pins have slow slew 
  BHSchmittInput :: UInt8 # non-zero if BH pins are Schmitt input 
  BHDriveCurrent :: UInt8 # valid values are 4mA, 8mA, 12mA, 16mA 
  IFAIsFifo7 :: UInt8 # non-zero if interface is 245 FIFO 
  IFAIsFifoTar7 :: UInt8 # non-zero if interface is 245 FIFO CPU target 
  IFAIsFastSer7 :: UInt8 # non-zero if interface is Fast serial 
  AIsVCP7 :: UInt8 # non-zero if interface is to use VCP drivers 
  IFBIsFifo7 :: UInt8 # non-zero if interface is 245 FIFO 
  IFBIsFifoTar7 :: UInt8 # non-zero if interface is 245 FIFO CPU target 
  IFBIsFastSer7 :: UInt8 # non-zero if interface is Fast serial 
  BIsVCP7 :: UInt8 # non-zero if interface is to use VCP drivers 
  PowerSaveEnable :: UInt8 # non-zero if using BCBUS7 to save power for self-powered designs 
  #
  # Rev 8 (FT4232H) Extensions 
  #
  PullDownEnable8 :: UInt8 # non-zero if pull down enabled 
  SerNumEnable8 :: UInt8 # non-zero if serial number to be used 
  ASlowSlew :: UInt8 # non-zero if AL pins have slow slew 
  ASchmittInput :: UInt8 # non-zero if AL pins are Schmitt input 
  ADriveCurrent :: UInt8 # valid values are 4mA, 8mA, 12mA, 16mA 
  BSlowSlew :: UInt8 # non-zero if AH pins have slow slew 
  BSchmittInput :: UInt8 # non-zero if AH pins are Schmitt input 
  BDriveCurrent :: UInt8 # valid values are 4mA, 8mA, 12mA, 16mA
  CSlowSlew :: UInt8 # non-zero if BL pins have slow slew 
  CSchmittInput :: UInt8 # non-zero if BL pins are Schmitt input 
  CDriveCurrent :: UInt8 # valid values are 4mA, 8mA, 12mA, 16mA 
  DSlowSlew :: UInt8 # non-zero if BH pins have slow slew 
  DSchmittInput :: UInt8 # non-zero if BH pins are Schmitt input 
  DDriveCurrent :: UInt8 # valid values are 4mA, 8mA, 12mA, 16mA 
  ARIIsTXDEN :: UInt8 # non-zero if port A uses RI as RS485 TXDEN 
  BRIIsTXDEN :: UInt8 # non-zero if port B uses RI as RS485 TXDEN 
  CRIIsTXDEN :: UInt8 # non-zero if port C uses RI as RS485 TXDEN 
  DRIIsTXDEN :: UInt8 # non-zero if port D uses RI as RS485 TXDEN 
  AIsVCP8 :: UInt8 # non-zero if interface is to use VCP drivers 
  BIsVCP8 :: UInt8 # non-zero if interface is to use VCP drivers 
  CIsVCP8 :: UInt8 # non-zero if interface is to use VCP drivers 
  DIsVCP8 :: UInt8 # non-zero if interface is to use VCP drivers 
  #
  # Rev 9 (FT232H) Extensions 
  #
  PullDownEnableH :: UInt8 # non-zero if pull down enabled 
  SerNumEnableH :: UInt8 # non-zero if serial number to be used 
  ACSlowSlewH :: UInt8 # non-zero if AC pins have slow slew 
  ACSchmittInputH :: UInt8 # non-zero if AC pins are Schmitt input 
  ACDriveCurrentH :: UInt8 # valid values are 4mA, 8mA, 12mA, 16mA 
  ADSlowSlewH :: UInt8 # non-zero if AD pins have slow slew 
  ADSchmittInputH :: UInt8 # non-zero if AD pins are Schmitt input 
  ADDriveCurrentH :: UInt8 # valid values are 4mA, 8mA, 12mA, 16mA 
  Cbus0H :: UInt8 # Cbus Mux control 
  Cbus1H :: UInt8 # Cbus Mux control 
  Cbus2H :: UInt8 # Cbus Mux control 
  Cbus3H :: UInt8 # Cbus Mux control 
  Cbus4H :: UInt8 # Cbus Mux control 
  Cbus5H :: UInt8 # Cbus Mux control 
  Cbus6H :: UInt8 # Cbus Mux control 
  Cbus7H :: UInt8 # Cbus Mux control 
  Cbus8H :: UInt8 # Cbus Mux control 
  Cbus9H :: UInt8 # Cbus Mux control 
  IsFifoH :: UInt8 # non-zero if interface is 245 FIFO 
  IsFifoTarH :: UInt8 # non-zero if interface is 245 FIFO CPU target 
  IsFastSerH :: UInt8 # non-zero if interface is Fast serial 
  IsFT1248H :: UInt8 # non-zero if interface is FT1248 
  FT1248CpolH :: UInt8 # FT1248 clock polarity - clock idle high (1) or clock idle low (0) 
  FT1248LsbH :: UInt8 # FT1248 data is LSB (1) or MSB (0) 
  FT1248FlowControlH :: UInt8 # FT1248 flow control enable 
  IsVCPH :: UInt8 # non-zero if interface is to use VCP drivers 
  PowerSaveEnableH :: UInt8 # non-zero if using ACBUS7 to save power for self-powered designs
  function FtProgramData(pd :: FtProgramData_C)
    newpd = new(pd.Signature1,pd.Signature2,pd.Version,pd.VendorId,pd.ProductId)
    newpd.Manufacturer = bytestring(pd.Manufacturer)
    newpd.ManufacturerId = bytestring(pd.ManufacturerId)
    newpd.Description = bytestring(pd.Description)
    newpd.SerialNumber = bytestring(pd.SerialNumber)
    for i in 10:130
      newpd.(i) = pd.(i)
    end
    return newpd
  end
end

function FtProgramData_C(pd::FtProgramData)
  newpd = FtProgramData_C(pd.Version,pd.Manufacturer,pd.ManufacturerId,pd.Description,pd.SerialNumber)
  newpd.VendorId = pd.VendorId
  newpd.ProductId = pd.ProductId
  for i in 10:130
    newpd.(i) = pd.(i)
  end
  return newpd
end

function Base.show(io::IO, pd::FtProgramData)
  f()=@printf(io,"Signature1 = 0x%08x \n",pd.Signature1);f() 
  f()=@printf(io,"Signature2 = 0x%08x \n",pd.Signature2);f() 
  f()=@printf(io,"Version = 0x%08x \n",pd.Version);f()  
  f()=@printf(io,"VendorId = 0x%04x \n",pd.VendorId);f() 
  f()=@printf(io,"ProductId = 0x%04x \n",pd.ProductId);f() 
  println(io,"Manufacturer = $(pd.Manufacturer)") 
  println(io,"ManufacturerId = $(pd.ManufacturerId)") 
  println(io,"Description = $(pd.Description)") 
  println(io,"SerialNumber = $(pd.SerialNumber)") 
  f()=@printf(io,"MaxPower = 0x%04x \n",pd.MaxPower) ;f()
  f()=@printf(io,"PnP = 0x%04x \n",pd.PnP) ;f()
  f()=@printf(io,"SelfPowered = 0x%04x \n",pd.SelfPowered) ;f()
  f()=@printf(io,"RemoteWakeup = 0x%04x \n",pd.RemoteWakeup);f()
  if pd.Version >= 0
    println(io)
    println(io,"Rev4 (FT232B) extensions")
    f()=@printf(io,"Rev4 = 0x%02x \n",pd.Rev4);f()
    f()=@printf(io,"IsoIn = 0x%02x \n",pd.IsoIn);f()
    f()=@printf(io,"PullDownEnable = 0x%02x \n",pd.PullDownEnable);f()
    f()=@printf(io,"SerNumEnable = 0x%02x \n",pd.SerNumEnable);f()
    f()=@printf(io,"USBVersionEnable = 0x%02x \n",pd.USBVersionEnable);f()
    f()=@printf(io,"USBVersion = 0x%04x \n",pd.USBVersion);f()
  end
  if pd.Version >= 1
    println(io)
    println(io,"Rev 5 (FT2232) extensions")
    f()=@printf(io,"Rev5 = 0x%02x \n",pd.Rev5);f()
    f()=@printf(io,"IsoInA = 0x%02x \n",pd.IsoInA);f()
    f()=@printf(io,"IsoInB = 0x%02x \n",pd.IsoInB);f()
    f()=@printf(io,"IsoOutA = 0x%02x \n",pd.IsoOutA);f()
    f()=@printf(io,"PullDownEnable5 = 0x%02x \n",pd.PullDownEnable5);f()
    f()=@printf(io,"SerNumEnable5 = 0x%02x \n",pd.SerNumEnable5);f()
    f()=@printf(io,"USBVersionEnable5 = 0x%02x \n",pd.USBVersionEnable5);f()
    f()=@printf(io,"USBVersion5 = 0x%04x \n",pd.USBVersion5);f()
    f()=@printf(io,"AIsHighCurrent = 0x%02x \n",pd.AIsHighCurrent);f()
    f()=@printf(io,"BIsHighCurrent = 0x%02x \n",pd.BIsHighCurrent);f()
    f()=@printf(io,"IFAIsFifo = 0x%02x \n",pd.IFAIsFifo);f()
    f()=@printf(io,"IFAIsFifoTar = 0x%02x \n",pd.IFAIsFifoTar);f()
    f()=@printf(io,"IFAIsFastSer = 0x%02x \n",pd.IFAIsFastSer);f()
    f()=@printf(io,"AIsVCP = 0x%02x \n",pd.AIsVCP);f()
    f()=@printf(io,"IFBIsFifo = 0x%02x \n",pd.IFBIsFifo);f()
    f()=@printf(io,"IFBIsFifoTar = 0x%02x \n",pd.IFBIsFifoTar);f()
    f()=@printf(io,"IFBIsFastSer = 0x%02x \n",pd.IFBIsFastSer);f()
    f()=@printf(io,"BIsVCP = 0x%02x \n",pd.BIsVCP);f()
  end
  if pd.Version >=2
    println(io)
    println(io,"Rev 6 (FT232R) extensions")
    f()=@printf(io,"UseExtOsc = 0x%02x \n",pd.UseExtOsc);f()
    f()=@printf(io,"HighDriveIOs = 0x%02x \n",pd.HighDriveIOs);f()
    f()=@printf(io,"EndpointSize = 0x%02x \n",pd.EndpointSize);f()
    f()=@printf(io,"PullDownEnableR = 0x%02x \n",pd.PullDownEnableR);f()
    f()=@printf(io,"SerNumEnableR = 0x%02x \n",pd.SerNumEnableR);f()
    f()=@printf(io,"InvertTXD = 0x%02x \n",pd.InvertTXD);f()
    f()=@printf(io,"InvertRXD = 0x%02x \n",pd.InvertRXD);f()
    f()=@printf(io,"InvertRTS = 0x%02x \n",pd.InvertRTS);f()
    f()=@printf(io,"InvertCTS = 0x%02x \n",pd.InvertCTS);f()
    f()=@printf(io,"InvertDTR = 0x%02x \n",pd.InvertDTR);f()
    f()=@printf(io,"InvertDSR = 0x%02x \n",pd.InvertDSR);f()
    f()=@printf(io,"InvertDCD = 0x%02x \n",pd.InvertDCD);f()
    f()=@printf(io,"InvertRI = 0x%02x \n",pd.InvertRI);f()
    f()=@printf(io,"Cbus0 = 0x%02x \n",pd.Cbus0);f()
    f()=@printf(io,"Cbus1 = 0x%02x \n",pd.Cbus1);f()
    f()=@printf(io,"Cbus2 = 0x%02x \n",pd.Cbus2);f()
    f()=@printf(io,"Cbus3 = 0x%02x \n",pd.Cbus3);f()
    f()=@printf(io,"Cbus4 = 0x%02x \n",pd.Cbus4);f()
    f()=@printf(io,"RIsD2XX = 0x%02x \n",pd.RIsD2XX);f()
  end
  if pd.Version >=3
    println(io)
    println(io,"Rev 7 (FT2232H) Extensions")
    f()=@printf(io,"PullDownEnable7 = 0x%02x \n",pd.PullDownEnable7);f()
    f()=@printf(io,"SerNumEnable7 = 0x%02x \n",pd.SerNumEnable7);f()
    f()=@printf(io,"ALSlowSlew = 0x%02x \n",pd.ALSlowSlew);f()
    f()=@printf(io,"ALSchmittInput = 0x%02x \n",pd.ALSchmittInput);f()
    f()=@printf(io,"ALDriveCurrent = 0x%02x \n",pd.ALDriveCurrent);f()
    f()=@printf(io,"AHSlowSlew = 0x%02x \n",pd.AHSlowSlew);f()
    f()=@printf(io,"AHSchmittInput = 0x%02x \n",pd.AHSchmittInput);f()
    f()=@printf(io,"AHDriveCurrent = 0x%02x \n",pd.AHDriveCurrent);f()
    f()=@printf(io,"BLSlowSlew = 0x%02x \n",pd.BLSlowSlew);f()
    f()=@printf(io,"BLSchmittInput = 0x%02x \n",pd.BLSchmittInput);f()
    f()=@printf(io,"BLDriveCurrent = 0x%02x \n",pd.BLDriveCurrent);f()
    f()=@printf(io,"BHSlowSlew = 0x%02x \n",pd.BHSlowSlew);f()
    f()=@printf(io,"BHSchmittInput = 0x%02x \n",pd.BHSchmittInput);f()
    f()=@printf(io,"BHDriveCurrent = 0x%02x \n",pd.BHDriveCurrent);f()
    f()=@printf(io,"IFAIsFifo7 = 0x%02x \n",pd.IFAIsFifo7);f()
    f()=@printf(io,"IFAIsFifoTar7 = 0x%02x \n",pd.IFAIsFifoTar7);f()
    f()=@printf(io,"IFAIsFastSer7 = 0x%02x \n",pd.IFAIsFastSer7);f()
    f()=@printf(io,"AIsVCP7 = 0x%02x \n",pd.AIsVCP7);f()
    f()=@printf(io,"IFBIsFifo7 = 0x%02x \n",pd.IFBIsFifo7);f()
    f()=@printf(io,"IFBIsFifoTar7 = 0x%02x \n",pd.IFBIsFifoTar7);f()
    f()=@printf(io,"IFBIsFastSer7 = 0x%02x \n",pd.IFBIsFastSer7);f()
    f()=@printf(io,"BIsVCP7 = 0x%02x \n",pd.BIsVCP7);f()
    f()=@printf(io,"PowerSaveEnable = 0x%02x \n",pd.PowerSaveEnable);f()
  end
  if pd.Version >=4
    println(io)
    println(io,"Rev 8 (FT4232H) Extensions ")
    f()=@printf(io,"PullDownEnable8 = 0x%02x \n",pd.PullDownEnable8);f()
    f()=@printf(io,"SerNumEnable8 = 0x%02x \n",pd.SerNumEnable8);f()
    f()=@printf(io,"ASlowSlew = 0x%02x \n",pd.ASlowSlew);f()
    f()=@printf(io,"ASchmittInput = 0x%02x \n",pd.ASchmittInput);f()
    f()=@printf(io,"ADriveCurrent = 0x%02x \n",pd.ADriveCurrent);f()
    f()=@printf(io,"BSlowSlew = 0x%02x \n",pd.BSlowSlew);f()
    f()=@printf(io,"BSchmittInput = 0x%02x \n",pd.BSchmittInput);f()
    f()=@printf(io,"BDriveCurrent = 0x%02x \n",pd.BDriveCurrent);f()
    f()=@printf(io,"CSlowSlew = 0x%02x \n",pd.CSlowSlew);f()
    f()=@printf(io,"CSchmittInput = 0x%02x \n",pd.CSchmittInput);f()
    f()=@printf(io,"CDriveCurrent = 0x%02x \n",pd.CDriveCurrent);f()
    f()=@printf(io,"DSlowSlew = 0x%02x \n",pd.DSlowSlew);f()
    f()=@printf(io,"DSchmittInput = 0x%02x \n",pd.DSchmittInput);f()
    f()=@printf(io,"DDriveCurrent = 0x%02x \n",pd.DDriveCurrent);f()
    f()=@printf(io,"ARIIsTXDEN = 0x%02x \n",pd.ARIIsTXDEN);f()
    f()=@printf(io,"BRIIsTXDEN = 0x%02x \n",pd.BRIIsTXDEN);f()
    f()=@printf(io,"CRIIsTXDEN = 0x%02x \n",pd.CRIIsTXDEN);f()
    f()=@printf(io,"DRIIsTXDEN = 0x%02x \n",pd.DRIIsTXDEN);f()
    f()=@printf(io,"AIsVCP8 = 0x%02x \n",pd.AIsVCP8);f()
    f()=@printf(io,"BIsVCP8 = 0x%02x \n",pd.BIsVCP8);f()
    f()=@printf(io,"CIsVCP8 = 0x%02x \n",pd.CIsVCP8);f()
    f()=@printf(io,"DIsVCP8 = 0x%02x \n",pd.DIsVCP8);f()
  end
  if pd.Version >=5
    println(io)
    println(io,"Rev 9 (FT232H) Extensions")
    f()=@printf(io,"PullDownEnableH = 0x%02x \n",pd.PullDownEnableH);f()
    f()=@printf(io,"SerNumEnableH = 0x%02x \n",pd.SerNumEnableH);f()
    f()=@printf(io,"ACSlowSlewH = 0x%02x \n",pd.ACSlowSlewH);f()
    f()=@printf(io,"ACSchmittInputH = 0x%02x \n",pd.ACSchmittInputH);f()
    f()=@printf(io,"ACDriveCurrentH = 0x%02x \n",pd.ACDriveCurrentH);f()
    f()=@printf(io,"ADSlowSlewH = 0x%02x \n",pd.ADSlowSlewH);f()
    f()=@printf(io,"ADSchmittInputH = 0x%02x \n",pd.ADSchmittInputH);f()
    f()=@printf(io,"ADDriveCurrentH = 0x%02x \n",pd.ADDriveCurrentH);f()
    f()=@printf(io,"Cbus0H = 0x%02x \n",pd.Cbus0H);f()
    f()=@printf(io,"Cbus1H = 0x%02x \n",pd.Cbus1H);f()
    f()=@printf(io,"Cbus2H = 0x%02x \n",pd.Cbus2H);f()
    f()=@printf(io,"Cbus3H = 0x%02x \n",pd.Cbus3H);f()
    f()=@printf(io,"Cbus4H = 0x%02x \n",pd.Cbus4H);f()
    f()=@printf(io,"Cbus5H = 0x%02x \n",pd.Cbus5H);f()
    f()=@printf(io,"Cbus6H = 0x%02x \n",pd.Cbus6H);f()
    f()=@printf(io,"Cbus7H = 0x%02x \n",pd.Cbus7H);f()
    f()=@printf(io,"Cbus8H = 0x%02x \n",pd.Cbus8H);f()
    f()=@printf(io,"Cbus9H = 0x%02x \n",pd.Cbus9H);f()
    f()=@printf(io,"IsFifoH = 0x%02x \n",pd.IsFifoH);f()
    f()=@printf(io,"IsFifoTarH = 0x%02x \n",pd.IsFifoTarH);f()
    f()=@printf(io,"IsFastSerH = 0x%02x \n",pd.IsFastSerH);f()
    f()=@printf(io,"IsFT1248H = 0x%02x \n",pd.IsFT1248H);f()
    f()=@printf(io,"FT1248CpolH = 0x%02x \n",pd.FT1248CpolH);f()
    f()=@printf(io,"FT1248LsbH = 0x%02x \n",pd.FT1248LsbH);f()
    f()=@printf(io,"FT1248FlowControlH = 0x%02x \n",pd.FT1248FlowControlH);f()
    f()=@printf(io,"IsVCPH = 0x%02x \n",pd.IsVCPH);f()
    f()=@printf(io,"PowerSaveEnableH = 0x%02x \n",pd.PowerSaveEnableH);f()
  end
end

function ft_ee_read(ft_handle::Culong, version::Integer = 5)
  @assert version>-1
  ftpds = Ref{FtProgramData_C}(FtProgramData_C(version))
  ft_status = ccall((:FT_EE_Read, d2xx),
                     Cuint,
                     (Culong, Ref{FtProgramData_C}),
                     ft_handle, ftpds)
  checkstatus(ft_status)
  return FtProgramData(ftpds[])
end

function ft_ee_program(ft_handle::Culong, pd::FtProgramData)
  ftpds = Ref{FtProgramData_C}(FtProgramData_C(pd))
  ft_status = ccall((:FT_EE_Program, d2xx),
                     Cuint,
                     (Culong, Ref{FtProgramData_C}),
                     ft_handle, ftpds)
  checkstatus(ft_status)
  return nothing
end