unit CoreExports; interface uses Windows; type TDACEntry = packed record Channel: Word; Value: Word; end; PDACEntry = ^TDACEntry; procedure LoadDriverLinks; //Global. function GetDevices: LongWord; cdecl; function QueryDeviceInfo(DeviceIndex: LongWord; pPID: PLongWord; pNameSize: PLongWord; pName: PAnsiChar; pDIOBytes, pCounters: PLongWord): LongWord; cdecl; function ClearDevices: LongWord; cdecl; function AIOUSB_CloseDevice(DeviceIndex: LongWord): LongWord; cdecl; function GetDeviceUniqueStr(DeviceIndex: LongWord; pIIDSize: PLongWord; pIID: PAnsiChar): LongWord; cdecl; function GetDeviceSerialNumber(DeviceIndex: LongWord; var pSerialNumber: Int64): LongWord; cdecl; function GetDeviceByEEPROMByte(Data: Byte): LongWord; cdecl; function GetDeviceByEEPROMData(StartAddress, DataSize: LongWord; pData: PByte): LongWord; cdecl; function ResolveDeviceIndex(DeviceIndex: LongWord): LongWord; cdecl; function GetDeviceBySerialNumber(const pSerialNumber: Int64): LongWord; cdecl; function CustomEEPROMRead(DeviceIndex: LongWord; StartAddress: LongWord; var DataSize: LongWord; Data: Pointer): LongWord; cdecl; function CustomEEPROMWrite(DeviceIndex: LongWord; StartAddress: LongWord; DataSize: LongWord; Data: Pointer): LongWord; cdecl; function AIOUSB_FlashRead(DeviceIndex: LongWord; StartAddress: LongWord; var DataSize: LongWord; Data: Pointer): LongWord; cdecl; function AIOUSB_FlashWrite(DeviceIndex: LongWord; StartAddress: LongWord; DataSize: LongWord; Data: Pointer): LongWord; cdecl; function AIOUSB_FlashEraseSector(DeviceIndex: LongWord; Sector: Integer): LongWord; cdecl; function GenericVendorRead(DeviceIndex: LongWord; Request: Byte; Value, Index: Word; var DataSize: LongWord; pData: Pointer): LongWord; cdecl; function GenericVendorWrite(DeviceIndex: LongWord; Request: Byte; Value, Index: Word; DataSize: LongWord; pData: Pointer): LongWord; cdecl; function AWU_GenericBulkIn(DeviceIndex: LongWord; PipeID: LongWord; pData: Pointer; DataSize: LongWord; var BytesRead: LongWord): LongWord; cdecl; function AWU_GenericBulkOut(DeviceIndex: LongWord; PipeID: LongWord; pData: Pointer; DataSize: LongWord; var BytesWritten: LongWord): LongWord; cdecl; function AIOUSB_ClearFIFO(DeviceIndex: LongWord; TimeMethod: LongWord): LongWord; cdecl; function AIOUSB_GetStreamStatus(DeviceIndex: LongWord; var Status: LongWord): LongWord; cdecl; function AIOUSB_SetStreamingBlockSize(DeviceIndex, BlockSize: LongWord): LongWord; cdecl; function AIOUSB_ResetChip(DeviceIndex: LongWord): LongWord; cdecl; //Load-time defaults. function AIOUSB_SaveStateAsDefaults(DeviceIndex: LongWord): LongWord; cdecl; function AIOUSB_RestoreFactoryDefaults(DeviceIndex: LongWord): LongWord; cdecl; function AIOUSB_SetDefaultsTable(DeviceIndex: LongWord; pDefTable: Pointer; pDefTableBytes: PLongWord): LongWord; cdecl; function AIOUSB_GetDefaultsTable(DeviceIndex: LongWord; pDefTable: Pointer; pDefTableBytes: PLongWord): LongWord; cdecl; //Global tick. function AIOUSB_SetGlobalTickRate(DeviceIndex: LongWord; pHz: PDouble): LongWord; cdecl; //DIO. function DIO_Configure(DeviceIndex: LongWord; Tristate: ByteBool; pOutMask: Pointer; pData: Pointer): LongWord; cdecl; function DIO_ConfigureEx(DeviceIndex: LongWord; pOutMask: Pointer; pData: Pointer; pTristateMask: Pointer): LongWord; cdecl; function DIO_ConfigurationQuery(DeviceIndex: LongWord; pOutMask: Pointer; pTristateMask: Pointer): LongWord; cdecl; function DIO_Write1(DeviceIndex, BitIndex: LongWord; Data: ByteBool): LongWord; cdecl; function DIO_Write8(DeviceIndex, ByteIndex: LongWord; Data: Byte): LongWord; cdecl; function DIO_WriteAll(DeviceIndex: LongWord; pData: Pointer): LongWord; cdecl; function DIO_Read1(DeviceIndex, BitIndex: LongWord; Buffer: PByte): LongWord; cdecl; function DIO_Read8(DeviceIndex, ByteIndex: LongWord; Buffer: PByte): LongWord; cdecl; function DIO_ReadAll(DeviceIndex: LongWord; pData: Pointer): LongWord; cdecl; function DIO_StreamOpen(DeviceIndex: LongWord; bIsRead: LongBool): LongWord; cdecl; function DIO_StreamClose(DeviceIndex: LongWord): LongWord; cdecl; function DIO_StreamFrame(DeviceIndex, FramePoints: LongWord; pFrameData: PWord; var BytesTransferred: LongWord): LongWord; cdecl; function DIO_StreamSetClocks(DeviceIndex: LongWord; var ReadClockHz, WriteClockHz: Double): LongWord; cdecl; function DIO_SPI_Write(DeviceIndex: LongWord; Address, Reg, Value: Byte): LongWord; cdecl; function DIO_SPI_Read(DeviceIndex: LongWord; Address, Reg: Byte; pValue: PByte): LongWord; cdecl; //DIO automapping. function DIO_Automap_ClearTable(DeviceIndex: LongWord): LongWord; cdecl; //function DIO_Automap_GetTable(DeviceIndex: LongWord; pMapTable: Pointer; pMapTableBytes: PLongWord): LongWord; cdecl; function DIO_Automap_SetTable(DeviceIndex: LongWord; pMapTable: Pointer; pMapTableBytes: PLongWord): LongWord; cdecl; function DIO_Automap_AddEntry(DeviceIndex: LongWord; pMapEntry: PWord): LongWord; cdecl; function DIO_Automap_SetTickDivisor(DeviceIndex: LongWord; pDivisor: PByte): LongWord; cdecl; //DIO PWM. //function DIO_PWM_GetAll(DeviceIndex: LongWord; pDutyCycles: Pointer; pDutyCyclesBytes: PLongWord): LongWord; cdecl; function DIO_PWM_SetAll(DeviceIndex: LongWord; pDivisor: PByte; pPWMTable: Pointer; pPWMTableBytes: PLongWord): LongWord; cdecl; //function DIO_PWM_Clear(DeviceIndex: LongWord): LongWord; cdecl; //function DIO_PWM_Add(DeviceIndex: LongWord; BitIndex: LongWord; DutyCycle: LongWord): LongWord; cdecl; //function PWM_SetGlobalTicksPerPWMPeriod(DeviceIndex: LongWord; ): LongWord; cdecl; //DIO latching. function DIO_Latch_SetDivisor(DeviceIndex: LongWord; pDivisor: PByte): LongWord; cdecl; function DIO_Latch_Reset(DeviceIndex: LongWord): LongWord; cdecl; function DIO_Latch_Read(DeviceIndex: LongWord; pLowLatches, pHighLatches, pNoLatches: PByte; pLatchesBytes: PLongWord): LongWord; cdecl; //DIO debounce. function DIO_Deb_SetConfig(DeviceIndex: LongWord; pDebTable: Pointer; pDebTableBytes: PLongWord): LongWord; cdecl; function DIO_Deb_ReadAll(DeviceIndex: LongWord; pDebData: PByte): LongWord; cdecl; //Counters. function CTR_8254Mode(DeviceIndex, BlockIndex, CounterIndex, Mode: LongWord): LongWord; cdecl; function CTR_8254Load(DeviceIndex, BlockIndex, CounterIndex: LongWord; LoadValue: Word): LongWord; cdecl; function CTR_8254ModeLoad(DeviceIndex, BlockIndex, CounterIndex, Mode: LongWord; LoadValue: Word): LongWord; cdecl; function CTR_8254ReadModeLoad(DeviceIndex, BlockIndex, CounterIndex, Mode: LongWord; LoadValue: Word; pReadValue: PWord): LongWord; cdecl; function CTR_8254Read(DeviceIndex, BlockIndex, CounterIndex: LongWord; pReadValue: PWord): LongWord; cdecl; function CTR_8254ReadStatus(DeviceIndex, BlockIndex, CounterIndex: LongWord; pReadValue: PWord; pStatus: PByte): LongWord; cdecl; function CTR_8254ReadAll(DeviceIndex: LongWord; pData: PWord): LongWord; cdecl; function CTR_StartOutputFreq(DeviceIndex, BlockIndex: LongWord; pHz: PDouble): LongWord; cdecl; function CTR_8254ReadLatched(DeviceIndex: LongWord; pData: PWord): LongWord; cdecl; function CTR_8254SelectGate(DeviceIndex, GateIndex: LongWord): LongWord; cdecl; function CTR_SetWaitGates(DeviceIndex: LongWord; A, B: Byte): LongWord; cdecl; function CTR_EndWaitGates(DeviceIndex: LongWord): LongWord; cdecl; function CTR_WaitForGate(DeviceIndex: LongWord; GateIndex: Byte; var Content: Word): LongWord; cdecl; function CTR_StartMeasuringPulseWidth(DeviceIndex: LongWord): LongWord; cdecl; function CTR_StopMeasuringPulseWidth(DeviceIndex: LongWord): LongWord; cdecl; function CTR_GetPulseWidthMeasurement(DeviceIndex, BlockIndex, CounterIndex: LongWord; pReadValue: PWord): LongWord; cdecl; //A/D. function ADC_GetConfig(DeviceIndex: LongWord; pConfigBuf: Pointer; var ConfigBufSize: LongWord): LongWord; cdecl; function ADC_SetConfig(DeviceIndex: LongWord; pConfigBuf: Pointer; var ConfigBufSize: LongWord): LongWord; cdecl; function ADC_RangeAll(DeviceIndex: LongWord; pGainCodes: PByte; bDifferential: LongBool): LongWord; cdecl; function ADC_Range1(DeviceIndex, ADChannel: LongWord; GainCode: Byte; bDifferential: LongBool): LongWord; cdecl; function ADC_ADMode(DeviceIndex: LongWord; TriggerMode, CalMode: Byte): LongWord; cdecl; function ADC_SetScanLimits(DeviceIndex, StartChannel, EndChannel: LongWord): LongWord; cdecl; function ADC_SetOversample(DeviceIndex: LongWord; Oversample: Byte): LongWord; cdecl; function ADC_QueryCal(DeviceIndex: LongWord): LongWord; cdecl; function ADC_SetCal(DeviceIndex: LongWord; CalFileName: PAnsiChar): LongWord; cdecl; function ADC_Initialize(DeviceIndex: LongWord; pConfigBuf: Pointer; var ConfigBufSize: LongWord; CalFileName: PAnsiChar): LongWord; cdecl; function ADC_Start(DeviceIndex: LongWord): LongWord; cdecl; function ADC_Stop(DeviceIndex: LongWord): LongWord; cdecl; function ADC_BulkAcquire(DeviceIndex: LongWord; BufSize: LongWord; pBuf: Pointer): LongWord; cdecl; function ADC_BulkPoll(DeviceIndex: LongWord; var BytesLeft: LongWord): LongWord; cdecl; function ADC_BulkAbort(DeviceIndex: LongWord): LongWord; cdecl; function ADC_BulkMode(DeviceIndex, BulkMode: LongWord): LongWord; cdecl; function ADC_BulkContinuousCallbackStart(DeviceIndex: LongWord; BufSize: LongWord; BaseBufCount: LongWord; Context: LongWord; pCallback: Pointer): LongWord; cdecl; function ADC_BulkContinuousEnd(DeviceIndex: LongWord; pIOStatus: PLongWord): LongWord; cdecl; function ADC_BulkContinuousDebug(DeviceIndex: LongWord; var Blanks, Accessings, GotDatas: LongWord): LongWord; cdecl; function ADC_GetImmediate(DeviceIndex, Channel: LongWord; pBuf: PWord): LongWord; cdecl; function ADC_GetScan(DeviceIndex: LongWord; pBuf: PWord): LongWord; cdecl; function ADC_GetScanV(DeviceIndex: LongWord; pBuf: PDouble): LongWord; cdecl; function ADC_GetTrigScan(DeviceIndex: LongWord; pBuf: PWord; TimeoutMS: LongInt): LongWord; cdecl; function ADC_GetTrigScanV(DeviceIndex: LongWord; pBuf: PDouble; TimeoutMS: LongInt): LongWord; cdecl; function ADC_GetChannelV(DeviceIndex, ChannelIndex: LongWord; pBuf: PDouble): LongWord; cdecl; function ADC_GetCalRefV(DeviceIndex, CalRefIndex: LongWord; var pRef: Double): LongWord; cdecl; //D/A. function DACDirect(DeviceIndex: LongWord; Channel: Word; Value: Word): LongWord; cdecl; function DACMultiDirect(DeviceIndex: LongWord; pDACData: PDACEntry; DACDataCount: LongWord): LongWord; cdecl; function DACSetBoardRange(DeviceIndex: LongWord; RangeCode: LongWord): LongWord; cdecl; function DACSetChannelCal(DeviceIndex: LongWord; Channel: LongWord; CalFileName: PAnsiChar): LongWord; cdecl; function DACOutputOpen(DeviceIndex: LongWord; var ClockHz: Double): LongWord; cdecl; function DACOutputAbort(DeviceIndex: LongWord): LongWord; cdecl; function DACOutputClose(DeviceIndex: LongWord; bWait: LongBool): LongWord; cdecl; function DACOutputCloseNoEnd(DeviceIndex: LongWord; bWait: LongBool): LongWord; cdecl; function DACOutputSetCount(DeviceIndex, NewCount: LongWord): LongWord; cdecl; function DACOutputFrame(DeviceIndex, FramePoints: LongWord; FrameData: PWord): LongWord; cdecl; function DACOutputFrameRaw(DeviceIndex, FramePoints: LongWord; FrameData: PWord): LongWord; cdecl; function DACOutputStatus(DeviceIndex: LongWord): LongWord; cdecl; function DACOutputStart(DeviceIndex: LongWord): LongWord; cdecl; function DACOutputSetInterlock(DeviceIndex: LongWord; bInterlock: LongBool): LongWord; cdecl; function DACOutputProcess(DeviceIndex: LongWord; var ClockHz: Double; Samples: LongWord; pSampleData: PWord): LongWord; cdecl; //Watchdog. //function WDG_SetTimeout(DeviceIndex: LongWord; pTimeoutSeconds: PDouble): LongWord; cdecl; //function WDG_GetTimeout(DeviceIndex: LongWord; pTimeoutSeconds: PDouble): LongWord; cdecl; function WDG_SetConfig(DeviceIndex: LongWord; pTimeoutSeconds: PDouble; pWDGTable: Pointer; pWDGTableBytes: PLongWord): LongWord; cdecl; function WDG_GetStatus(DeviceIndex: LongWord; pStatus: Pointer; pStatusBytes: PLongWord): LongWord; cdecl; function WDG_Pet(DeviceIndex: LongWord; PetFlag: LongWord): LongWord; cdecl; function AIOUSB_OfflineWrite1(DeviceIndex: LongWord; SampleIndex: LongWord; Buf: Word): LongWord; cdecl; function AIOUSB_OfflineRead1(DeviceIndex: LongWord; SampleIndex: LongWord; pBuf: PWord): LongWord; cdecl; //Custom. function ADC_InitFastITScanV(DeviceIndex: LongWord): LongWord; cdecl; function ADC_ResetFastITScanV(DeviceIndex: LongWord): LongWord; cdecl; function ADC_SetFastITScanVChannels(DeviceIndex, NewChannels: LongWord): LongWord; cdecl; function ADC_GetFastITScanV(DeviceIndex: LongWord; pBuf: PDouble): LongWord; cdecl; function ADC_GetITScanV(DeviceIndex: LongWord; pBuf: PDouble): LongWord; cdecl; function DIO_CSA_DoSync(DeviceIndex: LongWord; var BaseRateHz, DurAms, DurBms, DurCms: Double): LongWord; cdecl; function DIO_CSA_DebounceSet(DeviceIndex, DebounceCounts: LongWord): LongWord; cdecl; function DIO_CSA_DebounceReadAll(DeviceIndex: LongWord; pData: Pointer): LongWord; cdecl; function DAC_CSA_SetRangeLimits(DeviceIndex: LongWord; pData: Pointer): LongWord; cdecl; function DAC_CSA_ClearRangeLimits(DeviceIndex: LongWord): LongWord; cdecl; function DIO_CSA_ReadAllString(DeviceIndex: LongWord; pData: Pointer; pDataBytes: PLongWord): LongWord; cdecl; //Debug / engineering. function GetPipes(DeviceIndex: LongWord; var PipeCount: LongWord; pPipeData: PLongWord): LongWord; cdecl; function GetDeviceHandle(DeviceIndex: LongWord; Data: PLongWord): LongWord; cdecl; function AIOUSB_UploadFirmware(DeviceIndex: LongWord; FirmBuf: PAnsiChar; BufLen: LongWord): LongWord; cdecl; function DEB_BulkIn(DeviceIndex: LongWord): LongWord; cdecl; function DEB_BulkOut(DeviceIndex, TargetPipe: LongWord; pBuf: Pointer; BufLen: LongWord): LongWord; cdecl; function DEB_SetInterface(DeviceIndex: LongWord; TargetInterface: Word): LongWord; cdecl; implementation uses Math, SysUtils, Classes, SetupDi, WinUSB; const NAN = 0/0; ERROR_DEVICE_REMOVED = 1617; ERROR_DEVICE_NOT_CONNECTED = 1167; //Observed on an actual motherboard, probably typoed from ERROR_DEVICE_REMOVED. FILE_DEVICE_UNKNOWN = $0022; METHOD_BUFFERED = 0; METHOD_NEITHER = 3; FILE_ANY_ACCESS = 0; { IOCTL_BASE = LongWord(FILE_DEVICE_UNKNOWN shl 16); IOCTL_AIOUSB_READ = ($831 shl 2) or IOCTL_BASE; IOCTL_AIOUSB_WRITE = ($830 shl 2) or IOCTL_BASE; IOCTL_HARDWARE_ID = ($832 shl 2) or IOCTL_BASE; IOCTL_AIOUSB_BENCH = ($833 shl 2) or IOCTL_BASE; IOCTL_INSTANCE_ID = ($834 shl 2) or IOCTL_BASE; IOCTL_AIOUSB_UPLOAD = ($840 shl 2) or IOCTL_BASE; IOCTL_SetIFace = $00222040; IOCTL_GetPipes = $00222000; IOCTL_BulkIn = $0022204E; IOCTL_BulkOut = $00222051; //Has two input buffers, instead of an input buffer and an output buffer } IOCTL_ADAPT_INDEX = $0000; IOCTL_CY_BASE = LongWord(FILE_DEVICE_UNKNOWN shl 16) or (FILE_ANY_ACCESS shl 14); IOCTL_ADAPT_SEND_EP0_CONTROL_TRANSFER = IOCTL_CY_BASE or ((IOCTL_ADAPT_INDEX+8) shl 2) or METHOD_BUFFERED; IOCTL_ADAPT_SELECT_INTERFACE = IOCTL_CY_BASE or ((IOCTL_ADAPT_INDEX+3) shl 2) or METHOD_BUFFERED; IOCTL_ADAPT_SEND_NON_EP0_DIRECT = IOCTL_CY_BASE or ((IOCTL_ADAPT_INDEX+18) shl 2) or METHOD_NEITHER; AIOWinUSBClassGUID: TGUID = (D1: $88D87F5A; D2: $EA16; D3: $93FC; D4: ($21, $65, $39, $C9, $1C, $36, $C9, $6E) ); AIOCyUSBClassGUID: TGUID = (D1: $D52D27E3; D2: $CF76; D3: $25EB; D4: ($72, $EA, $59, $6F, $22, $34, $C0, $E1) ); CyBaseTimeout = 42; //It's an integer, and all the .PDF says is it's the value you'd expect divided by 1000. WTF. type { TVendorRequestData = packed record Request: Byte; case Byte of 2: ( ValueIndex: LongWord; ); 1: ( Value, Index: Word; ); 0: ( ValueL, ValueH, IndexL, IndexH: Byte; ) end; PVendorRequestData = ^TVendorRequestData; } TCySetupPacket = packed record bRequestType: Byte; bRequest: Byte; Value, Index, Len: Word; ulTimeOut: LongWord; end; TCySingleTransfer = packed record SetupPacket: TCySetupPacket; reserved: Byte; ucEndpointAddress: Byte; NtStatus, UsbdStatus, IsoPacketOffset, IsoPacketLength, BufferOffset, BufferLength: LongWord; end; PCySingleTransfer = ^TCySingleTransfer; TStringArray = array of AnsiString; TWordArray = array of Word; const AUR_DIO_WRITE = $10; AUR_DIO_READ = $11; AUR_DIO_CONFIG = $12; AUR_DIO_CONFIG_QUERY = $13; AUR_DIO_LATCH_READ = $14; AUR_DIO_DEB_READ = $15; AUR_DIO_ADVANCED = $18; AUR_CTR_READ = $20; AUR_CTR_MODE = $21; AUR_CTR_LOAD = $22; AUR_CTR_MODELOAD = $23; AUR_CTR_SELGATE = $24; AUR_CTR_READALL = $25; AUR_CTR_READLATCHED = $26; AUR_CTR_COS_BULK_GATE2 = $27; AUR_CTR_COS_BULK_ABORT = $29; { AUR_CTR_PUR_FIRST = $28; //Not used with device, for index offsetting AUR_CTR_PUR_OFRQ = $28; //Set up to output frequency AUR_CTR_PUR_MFRQ = $2C; //Set up to measure frequency AUR_CTR_PUR_EVCT = $2D; //Set up to count events AUR_CTR_PUR_MPUL = $2E; //Set up to measure pulse width } AUR_WDG_STATUS = $2E; AUR_DIO_WDG16_DEPREC = $2F; AUR_GEN_CLEAR_FIFO_NEXT = $34; AUR_GEN_CLEAR_FIFO = $35; AUR_GEN_CLEAR_FIFO_WAIT = $36; AUR_GEN_ABORT_AND_CLEAR = $38; AUR_SET_GPIF_MODE = $39; AUR_GEN_REGISTER = $3C; AUR_WDG = $44; AUR_OFFLINE_READWRITE = $50; // $90; //First index assigned to self-tests. AUR_SELF_TEST_1 = $91; // $9F; //Last index assigned to self-tests. AUR_DAC_CONTROL = $B0; AUR_DAC_DATAPTR = $B1; AUR_DAC_DIVISOR = $B2; AUR_DAC_IMMEDIATE = $B3; AUR_GEN_STREAM_STATUS = $B4; AUR_FLASH_READWRITE = $B5; AUR_DAC_RANGE = $B7; AUR_PROBE_CALFEATURE = $BA; // $BB; // $BC; AUR_DIO_SETCLOCKS = $BD; AUR_ADC_SET_CONFIG = $BE; AUR_ADC_IMMEDIATE = $BF; AUR_DIO_SPI_WRITE = $C0; AUR_DIO_SPI_READ = $C1; AUR_SET_CUSTOM_CLOCKS = $C4; AUR_ADC_GET_CONFIG = $D2; AUR_DEBUG_DEBUG = $D4; AUR_DEBUG_FLASH_1TO1 = $F0; AUR_DEBUG_FLASH_ERASE = $FC; //Cypress FX2 vendor requests. CUR_RAM_READ = $A3; //Flags for streaming callback(s). CallbackFlag_BeginBC = $1; CallbackFlag_EndStream = $2; CallbackFlag_Inserted = $4; type TDACWorker = class(TThread) public Index: Integer; protected procedure Execute; override; end; TDACData = AnsiString; TADCWorker = class(TThread) public DI: LongWord; TargetPipe: LongWord; BytesLeft: LongInt; pTar: PWord; bAbort: Boolean; protected ADBuf: array of Byte; procedure Execute; override; end; PContCallback = procedure (pBuf: PWord; BufSize, Flags, Context: LongWord); cdecl; TADCContAcqWorker = class; TADCContBufWorker = class; TContBuf = record ADBuf: array of Byte; BufState: (bsBlank, bsAccessing, bsGotData); Index: Integer; UsedSize, Flags: LongWord; end; PContBuf = ^TContBuf; TADCContAcqWorker = class(TThread) public DI: LongWord; TargetPipe: LongWord; //BytesPerBC, IOStatus: LongWord; MyBufThread: TADCContBufWorker; protected procedure Execute; override; end; TADCContBufWorker = class(TThread) public BytesPerBuf: LongWord; hBufMutex, hBlankBufSem, hDataBufSem, hKillSem: THandle; MyAcqThread: TADCContAcqWorker; BufBuf: array of PContBuf; NextIndexIn, NextIndexOut: Integer; Callback: PContCallback; CallbackContext: LongWord; procedure GetDebugStats(var Blanks, Accessings, GotDatas: LongWord); protected procedure Execute; override; function GetBlankBuf(Flags: LongWord): PContBuf; procedure PutDataBuf(pNewBuf: PContBuf); function GetDataBufOrKilled: PContBuf; procedure PutBlankBuf(pNewBuf: PContBuf); function ExtraBuf: PContBuf; end; TCtrMonitorThread = class(TThread) public DI: LongWord; hListMutex: THandle; MeasuredPulseWidth: array of Word; protected procedure Execute; override; end; TDeviceData = record bOpen, bDeviceWasHere: Boolean; Handle, hWinUSBFile: THandle; bCyUSB: Boolean; //`@ Should be a load-type enum, to protect if WinUSB not loaded. DevPath: AnsiString; DIOBytes, DIOConfigBits: LongWord; LastDIOData: array of Byte; Counters: LongWord; Tristates: LongWord; bGateSelectable: Boolean; RootClock: Double; //LastPurpose: Byte; LastEventCount: Word; PID: LongWord; CtrDivisor: Word; bGetName: Boolean; ConfigBytes: LongWord; ImmDACs, ImmADCs: LongWord; bDACBoardRange, bDACChannelCal, bDACStream: Boolean; DACsUsed: Integer; bDACOpen, bDACClosing, bDACAborting, bDACStarted: Boolean; DACData: array of TDACData; hDACDataMutex, hDACDataSem: THandle; PendingDACData: TDACData; WorkerThread: TDACWorker; CtrMonitorThread: TCtrMonitorThread; bADCBulk: Boolean; ADCChannels, ADCMUXChannels: LongWord; ADCWorker: TADCWorker; ADCContAcqWorker: TADCContAcqWorker; ADCContBufWorker: TADCContBufWorker; RangeShift: Byte; FastITConfig, FastITBakConfig: array of Byte; bDIOStream, bDIOOpen, bDIORead: Boolean; StreamingBlockSize: LongWord; bDIODebounce, bDIOSPI: Boolean; bSetCustomClocks: Boolean; WDGBytes: LongWord; bClearFIFO: Boolean; FlashSectors: Integer; bFirmware20: Boolean; end; PDeviceData = ^TDeviceData; const diNone = $FFFFFFFF; diFirst = $FFFFFFFE; diOnly = $FFFFFFFD; var Dev: array[0..31] of TDeviceData; { procedure Swap(var A, D: Byte); overload; asm mov CL, [EAX] xchg CL, [EDX] mov [EAX], CL end; procedure Swap(var A, D: Word); overload; asm mov CX, [EAX] xchg CX, [EDX] mov [EAX], CX end; procedure Swap(var A, D: LongWord); overload; asm mov ECX, [EAX] xchg ECX, [EDX] mov [EAX], ECX end; } function MotorolaWord(W: Word): Word; //asm // xchg AL, AH begin Result := (W shr 8) or (W shl 8); end; function IsNAN(V: Double): Boolean; var NANBits: Int64; VBits: Int64 absolute V; begin PDouble(@NANBits)^ := NAN; Result := VBits = NANBits; end; function Validate(var DeviceIndex: LongWord): LongWord; var I: Integer; bGotOne, bOnly: Boolean; begin if (DeviceIndex = diOnly) or (DeviceIndex = diFirst) then begin bOnly := DeviceIndex = diOnly; bGotOne := False; for I := 0 to High(Dev) do begin if Dev[I].Handle <> 0 then begin if bGotOne then begin Result := ERROR_DUP_NAME; Exit; end; DeviceIndex := I; if not bOnly then begin Result := ERROR_SUCCESS; Exit; end; bGotOne := True; end; end; if DeviceIndex < LongWord(Length(Dev)) then Result := ERROR_SUCCESS else Result := ERROR_FILE_NOT_FOUND ; end else if DeviceIndex >= LongWord(Length(Dev)) then begin Result := ERROR_INVALID_INDEX; end else Result := ERROR_SUCCESS; ; end; function AIOUSB_CloseDevice(DeviceIndex: LongWord): LongWord; cdecl; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if Handle = 0 then begin if bDeviceWasHere then begin bDeviceWasHere := False; Result := ERROR_SUCCESS; end else Result := ERROR_INVALID_HANDLE ; Exit; end; try bDeviceWasHere := False; if bCyUSB then begin CloseHandle(Handle); end else begin WinUSB_Free(Handle); CloseHandle(hWinUSBFile); end; Result := ERROR_SUCCESS; except Result := GetLastError; if Result = ERROR_SUCCESS then Result := ERROR_GEN_FAILURE; end; Handle := 0; hWinUSBFile := 0; end; end; { function OpenDevice(DeviceIndex: LongWord): THandle; begin Result := CreateFile(PAnsiChar('\\.\AIOUSB-' + IntToStr(DeviceIndex)), GENERIC_WRITE or GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0); if Result = INVALID_HANDLE_VALUE then Result := 0; end; } function GetDevicePaths(const ClassGUID: TGUID): TStringArray; var DevInterfaceData: SP_DEVICE_INTERFACE_DATA; MemberIndex: Integer; hDevInfo: THandle; L: LongWord; pDetailData: PSP_DEVICE_INTERFACE_DETAIL_DATA; Buf: AnsiString; I, RL: Integer; begin RL := 0; SetLength(Result, RL); hDevInfo := SetupDiGetClassDevs(@ClassGUID, nil, 0, DIGCF_PRESENT or DIGCF_DEVICEINTERFACE); if hDevInfo = 0 then Exit; DevInterfaceData.cbSize := sizeof(DevInterfaceData); MemberIndex := 0; while SetupDiEnumDeviceInterfaces(hDevInfo, nil, ClassGUID, MemberIndex, DevInterfaceData) do begin L := 0; SetupDiGetDeviceInterfaceDetail(hDevInfo, @DevInterfaceData, nil, 0, @L, nil); GetMem(pDetailData, L); if SizeOf(Pointer) = 8 then pDetailData.cbSize := 8 //The fixed portion is 4. Dunno where 8 comes from. else pDetailData.cbSize := 5 //The fixed portion is 4. Dunno where 5 comes from. ; if not SetupDiGetDeviceInterfaceDetail(hDevInfo, @DevInterfaceData, pDetailData, L, nil, nil) then begin FreeMem(pDetailData); Inc(MemberIndex); Continue; end; SetString(Buf, PAnsiChar(@pDetailData.DevicePath[0]), L - 4); FreeMem(pDetailData); I := Pos(AnsiChar(#0), Buf); if I <> 0 then SetLength(Buf, I - 1); SetLength(Result, RL + 1); Result[RL] := Buf; Inc(RL); Buf := ''; Inc(MemberIndex); end; SetupDiDestroyDeviceInfoList(hDevInfo); end; { function CheckVID(InterfaceHandle: THandle): Boolean; var DeviceInfo: USB_DEV_DSC; dwBytesReturned: LongWord; begin Result := False; if InterfaceHandle = 0 then Exit; dwBytesReturned := 0; if not WinUSB_GetDescriptor(InterfaceHandle, USB_DEVICE_DESCRIPTOR_TYPE, 0, $0409, @DeviceInfo, sizeof(DeviceInfo), dwBytesReturned) then Exit; Result := DeviceInfo.idVendor = $1605; end; } procedure LoadDriverLinks; var DevicePath: TStringArray; ThisPath: AnsiString; PI, DI: Integer; hFile, hWinUSB: THandle; //SetupData: TUSBSetupPacket; //ThisSN: Int64; //BytesRead: LongWord; bFull: Boolean; begin //CyUSB links. DevicePath := GetDevicePaths(AIOCyUSBClassGUID); for PI := 0 to High(DevicePath) do begin ThisPath := DevicePath[PI]; for DI := 0 to High(Dev) do if Dev[DI].Handle <> 0 then if Dev[DI].DevPath = ThisPath then begin ThisPath := ''; Break; end ; if Length(ThisPath) = 0 then Continue; hFile := CreateFileA(PAnsiChar(ThisPath), GENERIC_WRITE or GENERIC_READ, FILE_SHARE_WRITE or FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); ThisPath := ''; if hFile = INVALID_HANDLE_VALUE then hFile := 0; if hFile = 0 then Continue; bFull := True; for DI := 0 to High(Dev) do with Dev[DI] do if (Handle = 0) and not bDeviceWasHere then begin Handle := hFile; hWinUSBFile := 0; bCyUSB := True; DevPath := DevicePath[PI]; bOpen := False; bDACOpen := False; bDACClosing := False; bFull := False; Break; end ; if bFull then begin CloseHandle(hFile); Break; end; end; SetLength(DevicePath, 0); //WinUSB links. if bWinUSBLoaded then begin DevicePath := GetDevicePaths(AIOWinUSBClassGUID); for PI := 0 to High(DevicePath) do begin hFile := CreateFileA(PAnsiChar(DevicePath[PI]), GENERIC_WRITE or GENERIC_READ, 0, nil, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); DevicePath[PI] := ''; if hFile = INVALID_HANDLE_VALUE then hFile := 0; if hFile = 0 then Continue; if not WinUSB_Initialize(hFile, hWinUSB) then begin CloseHandle(hFile); Continue; end; { if not CheckVID(hWinUSB) then begin WinUSB_Free(hWinUSB); CloseHandle(hFile); Continue; end; SetupData.RequestType := $C0; SetupData.Request := $A2; SetupData.Value := $1DF8; SetupData.Index := 0; SetupData.DataLength := SizeOf(ThisSN); if (not WinUSB_ControlTransfer(hWinUSB, SetupData, @ThisSN, SizeOf(ThisSN), BytesRead, nil)) or (BytesRead <> SizeOf(ThisSN)) then begin WinUSB_Free(hWinUSB); CloseHandle(hFile); Continue; end; } bFull := True; DI := 0; while DI < Length(Dev) do with Dev[DI] do if (Handle = 0) and not bDeviceWasHere then begin Handle := hWinUSB; hWinUSBFile := hFile; bCyUSB := False; bOpen := False; bDACOpen := False; bDACClosing := False; bFull := False; Break; end else Inc(DI) ; if bFull then begin WinUSB_Free(hWinUSB); CloseHandle(hFile); Break; end; end; SetLength(DevicePath, 0); end; end; function GetMappedFailure(DeviceIndex: LongWord): LongWord; begin Result := GetLastError; case Result of ERROR_INVALID_HANDLE, ERROR_DEVICE_REMOVED, ERROR_DEVICE_NOT_CONNECTED, ERROR_FILE_NOT_FOUND: begin AIOUSB_CloseDevice(DeviceIndex); Dev[DeviceIndex].bDeviceWasHere := True; Dev[DeviceIndex].bOpen := False; Dev[DeviceIndex].bDACOpen := False; Dev[DeviceIndex].bDACClosing := False; Result := ERROR_DEVICE_REMOVED; end; ERROR_SUCCESS: Result := ERROR_GEN_FAILURE; end; end; function _Cy_GenericRead(DeviceIndex: LongWord; RequestType, Request: Byte; Value, Index: Word; var DataSize: LongWord; pData: Pointer): LongWord; register; forward; function EnsureOpen(const DeviceIndex: LongWord): LongWord; var Device: PDeviceData; DeviceInfo: USB_DEV_DSC; dwBytesReturned: LongWord; begin Device := @Dev[DeviceIndex]; if Device.Handle = 0 then begin if Device.bDeviceWasHere then Result := ERROR_DEVICE_REMOVED else Result := ERROR_FILE_NOT_FOUND ; Exit; end; if Device.bOpen then begin Result := ERROR_SUCCESS; Exit; end; Device.PID := $FFFFFFFF; if Device.bCyUSB then begin dwBytesReturned := SizeOf(DeviceInfo); Result := _Cy_GenericRead(DeviceIndex, $00, $06, $0100, $0000, dwBytesReturned, @DeviceInfo); if dwBytesReturned < SizeOf(DeviceInfo) then Result := ERROR_READ_FAULT; if Result <> ERROR_SUCCESS then Exit; Device.PID := DeviceInfo.idProduct; end else begin dwBytesReturned := 0; if WinUSB_GetDescriptor(Device.Handle, USB_DEVICE_DESCRIPTOR_TYPE, 0, $0409, @DeviceInfo, SizeOf(DeviceInfo), dwBytesReturned) then Device.PID := DeviceInfo.idProduct else begin Result := GetMappedFailure(DeviceIndex); Exit; end; end; Device.DIOBytes := 0; Device.DIOConfigBits := 0; Device.Counters := 0; Device.RootClock := 0; Device.Tristates := 0; Device.bGetName := False; Device.ConfigBytes := 0; Device.bGateSelectable := False; Device.bDACBoardRange := False; Device.bDACChannelCal := False; Device.ImmDACs := 0; Device.ImmADCs := 0; Device.ADCChannels := 0; Device.ADCMUXChannels := 0; Device.ADCWorker := nil; Device.bDACStream := False; Device.bADCBulk := False; Device.RangeShift := 0; Device.bDIOStream := False; Device.StreamingBlockSize := 31*1024; Device.bDIODebounce := False; Device.bDIOSPI := False; Device.bClearFIFO := False; Device.FlashSectors := 0; Device.WDGBytes := 0; Device.bSetCustomClocks := False; case Device.PID of $8001: begin //USB-DIO-32 Device.DIOBytes := 4; Device.Counters := 3; Device.RootClock := 3000000; Device.bGetName := True; Device.bSetCustomClocks := True; Device.bDIODebounce := True; end; $8004: begin //USB-DIO-32I Device.DIOBytes := 4; Device.DIOConfigBits := 32; Device.bGetName := True; Device.bSetCustomClocks := True; end; $8002: begin //USB-DIO-48 Device.DIOBytes := 6; Device.bGetName := True; end; $8003: begin //USB-DIO-96 Device.DIOBytes := 12; Device.bGetName := True; end; $8008, $8009, $800A: begin //USB-DIO16A family, old revs Device.DIOBytes := 1; Device.bGetName := True; Device.bDIOStream := True; Device.bDIOSPI := True; Device.bClearFIFO := True; end; $800C, $800D, $800E, $800F: begin //USB-DIO16A family, current revs Device.DIOBytes := 4; Device.Tristates := 2; Device.bGetName := True; Device.bDIOStream := True; Device.bDIOSPI := True; Device.bClearFIFO := True; end; $8010, $8011, $8012, $8014, $8015, $8016, //USB-IIRO-16 family $8018, $801A, $801C, $801E, //USB-IDIO-16 family $8019, $801D, $801F: begin //USB-II-16-OEM family Device.DIOBytes := 4; Device.bGetName := True; Device.WDGBytes := 2; end; $4001, $4002: begin //USB-DA12-8A Device.bGetName := False; Device.bDACStream := True; Device.ImmDACs := 8; Device.DACsUsed := 5; Device.bGetName := True; end; $4003: begin //USB-DA12-8E (no streaming) Device.bGetName := False; Device.ImmDACs := 8; Device.bGetName := True; end; $8020: begin //USB-CTR-15 Device.Counters := 5; Device.bGateSelectable := True; Device.RootClock := 10000000; Device.bGetName := True; end; $8030, $8031: begin //USB-IIRO4-2SM, USB-IIRO4-COM Device.DIOBytes := 2; Device.bGetName := True; end; $8032: begin //USBP-DIO16RO8 Device.DIOBytes := 3; Device.bGetName := True; end; $8033: begin //PICO-DIO16RO8 Device.DIOBytes := 3; Device.bGetName := True; end; $8036: begin //USBP-II8IDO4 Device.DIOBytes := 2; Device.bGetName := True; Device.ImmADCs := 2; end; $8037: begin //PICO-II8IDO4 Device.DIOBytes := 2; Device.bGetName := True; Device.ImmADCs := 2; end; $8040..$8044, $8140..$8144: begin //USB-AI(O)16-16 family Device.DIOBytes := 2; Device.Counters := 1; Device.RootClock := 10000000; Device.bGetName := True; Device.bADCBulk := True; Device.ADCChannels := 16; Device.ADCMUXChannels := 16; Device.ConfigBytes := 20; Device.RangeShift := 0; Device.bClearFIFO := True; if (Device.PID and $0100) <> 0 then begin Device.bDACBoardRange := True; Device.ImmDACs := 2; end; end; $8045..$8049, $8145..$8149: begin //USB-AI(O)16-64 family Device.DIOBytes := 2; Device.Counters := 1; Device.RootClock := 10000000; Device.bGetName := True; Device.bADCBulk := True; Device.ADCChannels := 16; Device.ADCMUXChannels := 64; Device.ConfigBytes := 21; Device.RangeShift := 2; Device.bClearFIFO := True; if (Device.PID and $0100) <> 0 then begin Device.bDACBoardRange := True; Device.ImmDACs := 2; end; end; $804A..$805F, $814A..$815F: begin //USB-AI(O)16-32+ family Device.DIOBytes := 2; Device.Counters := 1; Device.RootClock := 10000000; Device.bGetName := True; Device.bADCBulk := True; Device.ADCChannels := 16; Device.ADCMUXChannels := 32 * ((((Device.PID - $804A) and not $0100) div 5) + 1); Device.ConfigBytes := 21; Device.RangeShift := 3; Device.bClearFIFO := True; if (Device.PID and $0100) <> 0 then begin Device.bDACBoardRange := True; Device.ImmDACs := 2; end; end; $8060, $8070..$807F: begin //USB-AO16-16A family Device.DIOBytes := 2; Device.bGetName := True; Device.FlashSectors := 32; Device.bDACBoardRange := True; Device.bDACChannelCal := True; //Device.bClearFIFO := True; //Add a new-style DAC streaming case Device.PID and $6 of $0: Device.ImmDACs := 16; $2: Device.ImmDACs := 12; $4: Device.ImmDACs := 8; $6: Device.ImmDACs := 4; end; if (Device.PID and 1) = 0 then Device.ImmADCs := 2; end; else begin //Device.bADCStream := True; Result := ERROR_SUCCESS; //Device.bDIOStream := True; Result := ERROR_SUCCESS; //Device.bDIOSPI := True; Result := ERROR_SUCCESS; end; end; if Device.DIOConfigBits = 0 then Device.DIOConfigBits := Device.DIOBytes; SetLength(Device.LastDIOData, Device.DIOBytes); Device.bOpen := True; Result := ERROR_SUCCESS; end; function CheckFirmware20(DeviceIndex: LongWord): LongWord; var L: LongWord; MemFlags: array[0..2] of Byte; begin if Dev[DeviceIndex].bFirmware20 then begin Result := ERROR_SUCCESS; Exit; end; //Read out the first chunk of "memory" flags. L := Length(MemFlags); Result := GenericVendorRead(DeviceIndex, CUR_RAM_READ, $8000, 1, L, @MemFlags[0]); if Result <> ERROR_SUCCESS then Exit; Result := ERROR_NOT_SUPPORTED; if LongInt(L) < Length(MemFlags) then Exit; if MemFlags[0] = $FF then Exit; if MemFlags[0] < 3 then Exit; if (MemFlags[2] and $02) = 0 then Exit; Result := ERROR_SUCCESS; Dev[DeviceIndex].bFirmware20 := True; end; function _GenericVendorRead(DeviceIndex: LongWord; Request: Byte; Value, Index: Word; var DataSize: LongWord; pData: Pointer): LongWord; cdecl; var SetupData: TWinUSBSetupPacket; Buf: AnsiString; pCT: PCySingleTransfer; BytesReturned: LongWord; begin try SetString(Buf, PAnsiChar(pData), DataSize); except Result := ERROR_NOACCESS; Exit; end; if Dev[DeviceIndex].bCyUSB then begin //CyUSB. Buf := StringOfChar(AnsiChar(#0), SizeOf(TCySingleTransfer)) + Buf; pCT := PCySingleTransfer(PAnsiChar(Buf)); pCT.SetupPacket.bRequestType := $C0; pCT.SetupPacket.bRequest := Request; pCT.SetupPacket.Value := Value; pCT.SetupPacket.Index := Index; pCT.SetupPacket.Len := DataSize; pCT.SetupPacket.ulTimeOut := CyBaseTimeout; pCT.ucEndpointAddress := 0; //EP0. pCT.IsoPacketLength := 0; pCT.BufferOffset := SizeOf(TCySingleTransfer); pCT.BufferLength := pCT.SetupPacket.Len; BytesReturned := 0; if DeviceIoControl(Dev[DeviceIndex].Handle, IOCTL_ADAPT_SEND_EP0_CONTROL_TRANSFER, PAnsiChar(Buf), Length(Buf), PAnsiChar(Buf), Length(Buf), BytesReturned, nil) then begin Result := ERROR_SUCCESS; BytesReturned := Min(BytesReturned, Length(Buf)); if BytesReturned <= SizeOf(TCySingleTransfer) then DataSize := 0 else DataSize := BytesReturned - SizeOf(TCySingleTransfer) ; try Move(Buf[1 + SizeOf(TCySingleTransfer)], pData^, DataSize); except Result := ERROR_NOACCESS; end; end else begin Result := GetLastError; if Result = ERROR_SUCCESS then Result := ERROR_GEN_FAILURE; Buf := ''; end; end else begin //WinUSB. SetupData.RequestType := $C0; SetupData.Request := Request; SetupData.Value := Value; SetupData.Index := Index; SetupData.DataLength := DataSize; if WinUSB_ControlTransfer(Dev[DeviceIndex].Handle, SetupData, PByte(PAnsiChar(Buf)), DataSize, BytesReturned, nil) then begin Result := ERROR_SUCCESS; DataSize := Min(BytesReturned, Length(Buf)); try Move(Buf[1], pData^, DataSize); except Result := ERROR_NOACCESS; end; end else Result := GetMappedFailure(DeviceIndex) ; end; end; function _GenericVendorWrite(DeviceIndex: LongWord; Request: Byte; Value, Index: Word; DataSize: LongWord; pData: Pointer): LongWord; cdecl; var SetupData: TWinUSBSetupPacket; Buf: AnsiString; pCT: PCySingleTransfer; BytesReturned: LongWord; begin try SetString(Buf, PAnsiChar(pData), DataSize); except Result := ERROR_NOACCESS; Exit; end; if Dev[DeviceIndex].bCyUSB then begin //CyUSB. Buf := StringOfChar(AnsiChar(#0), SizeOf(TCySingleTransfer)) + Buf; pCT := PCySingleTransfer(PAnsiChar(Buf)); pCT.SetupPacket.bRequestType := $40; pCT.SetupPacket.bRequest := Request; pCT.SetupPacket.Value := Value; pCT.SetupPacket.Index := Index; pCT.SetupPacket.Len := DataSize; pCT.SetupPacket.ulTimeOut := CyBaseTimeout; pCT.ucEndpointAddress := 0; //EP0. pCT.IsoPacketLength := 0; pCT.BufferOffset := SizeOf(TCySingleTransfer); pCT.BufferLength := pCT.SetupPacket.Len; BytesReturned := 0; if DeviceIoControl(Dev[DeviceIndex].Handle, IOCTL_ADAPT_SEND_EP0_CONTROL_TRANSFER, PAnsiChar(Buf), Length(Buf), PAnsiChar(Buf), Length(Buf), BytesReturned, nil) then Result := ERROR_SUCCESS else Result := GetMappedFailure(DeviceIndex) ; end else begin //WinUSB. SetupData.RequestType := $40; SetupData.Request := Request; SetupData.Value := Value; SetupData.Index := Index; SetupData.DataLength := DataSize; if WinUSB_ControlTransfer(Dev[DeviceIndex].Handle, SetupData, PByte(PAnsiChar(Buf)), DataSize, DataSize, nil) then Result := ERROR_SUCCESS else Result := GetMappedFailure(DeviceIndex) ; end; end; function GenericVendorRead(DeviceIndex: LongWord; Request: Byte; Value, Index: Word; var DataSize: LongWord; pData: Pointer): LongWord; cdecl; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := _GenericVendorRead(DeviceIndex, Request, Value, Index, DataSize, pData); end; function GenericVendorWrite(DeviceIndex: LongWord; Request: Byte; Value, Index: Word; DataSize: LongWord; pData: Pointer): LongWord; cdecl; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := _GenericVendorWrite(DeviceIndex, Request, Value, Index, DataSize, pData); end; function _Cy_GenericRead(DeviceIndex: LongWord; RequestType, Request: Byte; Value, Index: Word; var DataSize: LongWord; pData: Pointer): LongWord; register; var Buf: AnsiString; pCT: PCySingleTransfer; BytesReturned: LongWord; begin try SetString(Buf, PAnsiChar(pData), DataSize); except Result := ERROR_NOACCESS; Exit; end; Buf := StringOfChar(AnsiChar(#0), SizeOf(TCySingleTransfer)) + Buf; pCT := PCySingleTransfer(PAnsiChar(Buf)); pCT.SetupPacket.bRequestType := RequestType or $80; pCT.SetupPacket.bRequest := Request; pCT.SetupPacket.Value := Value; pCT.SetupPacket.Index := Index; pCT.SetupPacket.Len := DataSize; pCT.SetupPacket.ulTimeOut := CyBaseTimeout; pCT.ucEndpointAddress := 0; //EP0. pCT.IsoPacketLength := 0; pCT.BufferOffset := SizeOf(TCySingleTransfer); pCT.BufferLength := pCT.SetupPacket.Len; BytesReturned := 0; if DeviceIoControl(Dev[DeviceIndex].Handle, IOCTL_ADAPT_SEND_EP0_CONTROL_TRANSFER, PAnsiChar(Buf), Length(Buf), PAnsiChar(Buf), Length(Buf), BytesReturned, nil) then begin Result := ERROR_SUCCESS; BytesReturned := Min(BytesReturned, Length(Buf)); if BytesReturned <= SizeOf(TCySingleTransfer) then DataSize := 0 else DataSize := BytesReturned - SizeOf(TCySingleTransfer) ; try Move(Buf[1 + SizeOf(TCySingleTransfer)], pData^, DataSize); except Result := ERROR_NOACCESS; end; end else begin Result := GetLastError; if Result = ERROR_SUCCESS then Result := ERROR_GEN_FAILURE; Buf := ''; end; end; function AWU_GenericBulkIn(DeviceIndex: LongWord; PipeID: LongWord; pData: Pointer; DataSize: LongWord; var BytesRead: LongWord): LongWord; cdecl; var CT: TCySingleTransfer; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; if Dev[DeviceIndex].bCyUSB then begin FillChar(CT, SizeOf(CT), 0); CT.ucEndpointAddress := PipeID; if DeviceIoControl(Dev[DeviceIndex].Handle, IOCTL_ADAPT_SEND_NON_EP0_DIRECT, @CT, SizeOf(CT), pData, DataSize, BytesRead, nil) then begin if BytesRead > DataSize then BytesRead := DataSize; end else Result := GetMappedFailure(DeviceIndex) ; end else begin SetLastError(ERROR_GEN_FAILURE); if WinUsb_ReadPipe(Dev[DeviceIndex].Handle, PipeID, pData, DataSize, BytesRead, nil) then Result := ERROR_SUCCESS else Result := GetMappedFailure(DeviceIndex) ; end; end; function AWU_GenericBulkOut(DeviceIndex: LongWord; PipeID: LongWord; pData: Pointer; DataSize: LongWord; var BytesWritten: LongWord): LongWord; cdecl; var CT: TCySingleTransfer; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; if Dev[DeviceIndex].bCyUSB then begin FillChar(CT, SizeOf(CT), 0); CT.ucEndpointAddress := PipeID; if DeviceIoControl(Dev[DeviceIndex].Handle, IOCTL_ADAPT_SEND_NON_EP0_DIRECT, @CT, SizeOf(CT), pData, DataSize, BytesWritten, nil) then begin if BytesWritten > DataSize then BytesWritten := DataSize; end else Result := GetMappedFailure(DeviceIndex) ; end else begin SetLastError(ERROR_GEN_FAILURE); if WinUsb_WritePipe(Dev[DeviceIndex].Handle, PipeID, pData, DataSize, BytesWritten, nil) then begin Result := ERROR_SUCCESS; end else Result := GetMappedFailure(DeviceIndex) ; end; end; function _GenericBulkIn(DeviceIndex: LongWord; PipeID: LongWord; pData: Pointer; DataSize: LongWord; var BytesRead: LongWord): LongWord; var CT: TCySingleTransfer; begin if Dev[DeviceIndex].bCyUSB then begin FillChar(CT, SizeOf(CT), 0); CT.ucEndpointAddress := PipeID; if DeviceIoControl(Dev[DeviceIndex].Handle, IOCTL_ADAPT_SEND_NON_EP0_DIRECT, @CT, SizeOf(CT), pData, DataSize, BytesRead, nil) then begin Result := ERROR_SUCCESS; if BytesRead > DataSize then BytesRead := DataSize; end else Result := GetMappedFailure(DeviceIndex) ; end else begin SetLastError(ERROR_GEN_FAILURE); if WinUsb_ReadPipe(Dev[DeviceIndex].Handle, PipeID, pData, DataSize, BytesRead, nil) then Result := ERROR_SUCCESS else Result := GetMappedFailure(DeviceIndex) ; end; end; { function DoSetIFace(hDev: THandle; IFace: Word): LongWord; begin Result := ERROR_SUCCESS; Result := ERROR_SUCCESS; end; } function QueryDeviceInfo(DeviceIndex: LongWord; pPID: PLongWord; pNameSize: PLongWord; pName: PAnsiChar; pDIOBytes, pCounters: PLongWord): LongWord; cdecl; var Content: AnsiString; wContent: WideString; L, L2: LongWord; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; if Dev[DeviceIndex].Handle = 0 then LoadDriverLinks; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; if pPID <> nil then pPID ^ := Dev[DeviceIndex].PID ; if pDIOBytes <> nil then pDIOBytes^ := Dev[DeviceIndex].DIOBytes; if pCounters <> nil then pCounters^ := Dev[DeviceIndex].Counters; if pNameSize <> nil then begin if not Dev[DeviceIndex].bGetName then begin //Old ASM firmwares do not support get-string pNameSize^ := 0; end else begin SetString(wContent, nil, pNameSize^ + 1); L := Length(wContent) * SizeOf(wContent[1]); Result := GenericVendorRead(DeviceIndex, $06, $0302, 0, L, PWChar(wContent)); //Cypress get-string if Result <> ERROR_SUCCESS then Exit; L2 := Byte(wContent[1]) div 2; if L2 <> 0 then begin Dec(L2); if pName <> nil then begin L := Min(pNameSize^, L2); wContent := Copy(wContent, 2, L); Content := AnsiString(wContent); Move(Content[1], pName^, L); end; end; Result := ERROR_SUCCESS; pNameSize^ := L2; end; end; except Result := ERROR_INTERNAL_ERROR; end; end; function GetDevices: LongWord; cdecl; var I: Integer; begin LoadDriverLinks; Result := 0; for I := 0 to High(Dev) do if EnsureOpen(I) = ERROR_SUCCESS then Result := Result or (1 shl I) ; end; function ResolveDeviceIndex(DeviceIndex: LongWord): LongWord; cdecl; begin Result := Validate(DeviceIndex); SetLastError(Result); if Result = ERROR_SUCCESS then begin Result := DeviceIndex; end else begin Result := diNone; end; end; function ClearDevices: LongWord; cdecl; var I: Integer; wContent: WideString; L: LongWord; ErrorCode: LongWord; begin for I := High(Dev) downto 0 do begin if Dev[I].Handle <> 0 then begin if not Dev[I].bGetName then begin //Old ASM firmwares do not support get-string end else begin ErrorCode := EnsureOpen(I); if ErrorCode = ERROR_SUCCESS then begin SetString(wContent, nil, 257); L := Length(wContent) * SizeOf(wContent[1]); ErrorCode := GenericVendorRead(I, $06, $0302, 0, L, PWChar(wContent)); if ErrorCode <> ERROR_SUCCESS then GetMappedFailure(I) ; end; end; end else begin Dev[I].bDeviceWasHere := False; end; end; Result := ERROR_SUCCESS; end; function GetDeviceBySerialNumber(const pSerialNumber: Int64): LongWord; cdecl; var I: Integer; ThisSerialNumber: Int64; Status: LongWord; begin for I := 0 to High(Dev) do begin Status := GetDeviceSerialNumber(I, ThisSerialNumber); if Status <> ERROR_SUCCESS then Continue; if ThisSerialNumber <> pSerialNumber then Continue; Result := I; Exit; end; Result := diNone; end; function GetDeviceByEEPROMByte(Data: Byte): LongWord; cdecl; var ThisData: Byte; Status, ThisDataSize, MyLastError: LongWord; I: Integer; begin Result := diNone; MyLastError := ERROR_FILE_NOT_FOUND; for I := 0 to High(Dev) do begin ThisDataSize := 1; Status := CustomEEPROMRead(I, 0, ThisDataSize, @ThisData); if Status <> ERROR_SUCCESS then Continue; if ThisDataSize <> 1 then Continue; if ThisData <> Data then Continue; if Result = diNone then begin Result := I; MyLastError := ERROR_SUCCESS; end else begin MyLastError := ERROR_DUP_NAME; end; end; SetLastError(MyLastError); end; function GetDeviceByEEPROMData(StartAddress, DataSize: LongWord; pData: PByte): LongWord; cdecl; var ipData: PByte; ThisData: array of Byte; Status, ThisDataSize, MyLastError: LongWord; I, J: Integer; bMatch: Boolean; begin Result := diNone; MyLastError := ERROR_FILE_NOT_FOUND; if DataSize > $100 then begin SetLastError(ERROR_BAD_LENGTH); Exit; end; if DataSize = 0 then begin Result := ResolveDeviceIndex(diFirst); Exit; end; SetLength(ThisData, DataSize); for I := 0 to High(Dev) do begin ThisDataSize := DataSize; Status := CustomEEPROMRead(I, StartAddress, ThisDataSize, @ThisData[0]); if Status <> ERROR_SUCCESS then Continue; if ThisDataSize <> DataSize then Continue; bMatch := True; ipData := pData; for J := 0 to DataSize - 1 do begin if ThisData[J] <> ipData^ then begin bMatch := False; Break; end; Inc(ipData); end; if not bMatch then Continue; if Result = diNone then begin Result := I; MyLastError := ERROR_SUCCESS; end else begin MyLastError := ERROR_DUP_NAME; end; end; SetLastError(MyLastError); end; function CustomEEPROMRead(DeviceIndex: LongWord; StartAddress: LongWord; var DataSize: LongWord; Data: Pointer): LongWord; cdecl; begin if StartAddress > $FF then begin Result := ERROR_SEEK; Exit; end; if DataSize > (LongWord($100) - StartAddress) then begin Result := ERROR_BAD_LENGTH; Exit; end; Result := GenericVendorRead(DeviceIndex, $A2, $1E00 + StartAddress, 0, DataSize, Data); end; function CustomEEPROMWrite(DeviceIndex: LongWord; StartAddress: LongWord; DataSize: LongWord; Data: Pointer): LongWord; cdecl; const BlockSize = 32; begin if StartAddress > $FF then begin Result := ERROR_SEEK; Exit; end; if DataSize > (LongWord($100) - StartAddress) then begin Result := ERROR_BAD_LENGTH; Exit; end; while DataSize > BlockSize do begin Result := GenericVendorWrite(DeviceIndex, $A2, $1E00 + StartAddress, 0, BlockSize, Data); if Result <> ERROR_SUCCESS then Exit; Inc(StartAddress, BlockSize); Dec(DataSize, BlockSize); Inc(PByte(Data), BlockSize); end; Result := GenericVendorWrite(DeviceIndex, $A2, $1E00 + StartAddress, 0, DataSize, Data); end; function AIOUSB_FlashRead(DeviceIndex: LongWord; StartAddress: LongWord; var DataSize: LongWord; Data: Pointer): LongWord; cdecl; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if FlashSectors = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if StartAddress > $FFFFF then begin Result := ERROR_SEEK; Exit; end; if DataSize > (LongWord($100000) - StartAddress) then begin Result := ERROR_BAD_LENGTH; Exit; end; if (DataSize and 1) <> 0 then begin DataSize := DataSize and $FFFFFFFE; end; Result := GenericVendorRead(DeviceIndex, AUR_FLASH_READWRITE, StartAddress shr 1, 0, DataSize, Data); end; end; function AIOUSB_FlashWrite(DeviceIndex: LongWord; StartAddress: LongWord; DataSize: LongWord; Data: Pointer): LongWord; cdecl; const BlockSize = 4096; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if FlashSectors = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if StartAddress >= $200000 then begin Result := ERROR_SEEK; Exit; end; if DataSize > (LongWord($200000) - StartAddress) then begin Result := ERROR_BAD_LENGTH; Exit; end; if (DataSize and 1) <> 0 then begin DataSize := DataSize and $FFFFFFFE; end; while DataSize > BlockSize do begin Result := GenericVendorWrite(DeviceIndex, AUR_FLASH_READWRITE, StartAddress shr 1, StartAddress shr 17, BlockSize, Data); if Result <> ERROR_SUCCESS then Exit; Inc(StartAddress, BlockSize); Dec(DataSize, BlockSize); Inc(PByte(Data), BlockSize); end; Result := GenericVendorWrite(DeviceIndex, AUR_FLASH_READWRITE, StartAddress shr 1, StartAddress shr 17, DataSize, Data); end; end; function AIOUSB_FlashEraseSector(DeviceIndex: LongWord; Sector: Integer): LongWord; cdecl; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if FlashSectors = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if Sector >= FlashSectors then begin Result := ERROR_SEEK; Exit; end; Result := GenericVendorWrite(DeviceIndex, AUR_DEBUG_FLASH_ERASE, 0, Sector, 0, nil); end; end; (* function DoIOBench(DeviceIndex, Data: LongWord): LongWord; var Content: AnsiString; pVRD: PVendorRequestData absolute Content; //L: LongWord; //Suc: Boolean; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := ERROR_NOT_SUPPORTED; { with Dev[DeviceIndex] do begin SetString(Content, nil, SizeOf(TVendorRequestData)); pVRD.Request := AUR_DAC_DATAPTR; pVRD.ValueIndex := Data; L := 0; Suc := DeviceIoControl(Handle, IOCTL_AIOUSB_WRITE, pVRD, Length(Content), nil, 0, L, nil); if Suc then Result := ERROR_SUCCESS else Result := GetMappedFailure(DeviceIndex) ; end; } end; *) function GetPipes(DeviceIndex: LongWord; var PipeCount: LongWord; pPipeData: PLongWord): LongWord; cdecl; var bSuc: Boolean; InterfaceDescriptor: USB_INTERFACE_DESCRIPTOR; I, L: Integer; PipeInfo: WINUSB_PIPE_INFORMATION; pIPipeData: PLongWord; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; if Dev[DeviceIndex].bCyUSB then begin //`@ CyUSB. Result := ERROR_NOT_SUPPORTED; Result := ERROR_NOT_SUPPORTED; Exit; end else begin //WinUSB. SetLastError(ERROR_GEN_FAILURE); bSuc := WinUsb_QueryInterfaceSettings(Dev[DeviceIndex].Handle, 0, @InterfaceDescriptor); if not bSuc then begin Result := GetMappedFailure(DeviceIndex); PipeCount := 0; Exit; end; if PipeCount < InterfaceDescriptor.bNumEndpoints then L := PipeCount else L := InterfaceDescriptor.bNumEndpoints ; PipeCount := InterfaceDescriptor.bNumEndpoints; pIPipeData := pPipeData; for I := 0 to L - 1 do begin pIPipeData^ := $FFFFFFFF; Inc(pIPipeData); end; pIPipeData := pPipeData; for I := 0 to L - 1 do begin bSuc := WinUsb_QueryPipe(Dev[DeviceIndex].Handle, 0, I, @PipeInfo); if not bSuc then begin Result := GetMappedFailure(DeviceIndex); Exit; end; pIPipeData^ := PipeInfo.PipeId or (PipeInfo.PipeType shl 8); Inc(pIPipeData); end; end; Result := ERROR_SUCCESS; end; function GetDeviceHandle(DeviceIndex: LongWord; Data: PLongWord): LongWord; cdecl; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Data^ := Dev[DeviceIndex].Handle; end; function GetDeviceSerialNumber(DeviceIndex: LongWord; var pSerialNumber: Int64): LongWord; cdecl; var L: LongWord; Content: Int64; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; L := SizeOf(Content); Result := GenericVendorRead(DeviceIndex, $A2, $1DF8, 0, L, @Content); if (Result = ERROR_SUCCESS) and (L = SizeOf(Content)) then begin if Content = 0 then Content := -1; pSerialNumber := Content; if Content = -1 then Result := ERROR_NOT_SUPPORTED; end else begin Result := GetMappedFailure(DeviceIndex); end; end; function GetDeviceUniqueStr(DeviceIndex: LongWord; pIIDSize: PLongWord; pIID: PAnsiChar): LongWord; cdecl; var Content: Int64; begin Result := GetDeviceSerialNumber(DeviceIndex, Content); if Result <> ERROR_SUCCESS then Exit; Move(Content, pIID^, Min(SizeOf(Content), pIIDSize^)); end; function DACDirect(DeviceIndex: LongWord; Channel: Word; Value: Word): LongWord; cdecl; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if ImmDACs = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if bDACStream and (bDACOpen or bDACClosing) then begin Result := ERROR_TOO_MANY_OPEN_FILES; Exit; end; if Channel >= ImmDACs then begin Result := ERROR_INVALID_ADDRESS; Exit; end; Result := GenericVendorWrite(DeviceIndex, AUR_DAC_IMMEDIATE, Value, Channel, 0, nil); end; end; function DACMultiDirect(DeviceIndex: LongWord; pDACData: PDACEntry; DACDataCount: LongWord): LongWord; cdecl; var Content: AnsiString; pDE: PDACEntry; pDB, pMB: PByte; I, J: Integer; L: LongWord; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if ImmDACs = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if bDACStream and (bDACOpen or bDACClosing) then begin Result := ERROR_TOO_MANY_OPEN_FILES; Exit; end; if DACDataCount = 0 then Exit; //If length is zero, it's a nop pDE := pDACData; L := 0; for I := 0 to DACDataCount - 1 do begin if pDE.Channel > L then L := pDE.Channel; Inc(pDE); end; //L is now highest channel if L >= ImmDACs then begin Result := ERROR_INVALID_ADDRESS; Exit; end; L := (L div 8) + 1; //Number of blocks of 8 DACs Content := StringOfChar(AnsiChar(#0), L * 17); pDB := PByte(PAnsiChar(Content)); pDE := pDACData; for I := 0 to DACDataCount - 1 do begin J := pDE.Channel; pMB := pDB; Inc(pMB, J * 2 + (J div 8) + 1); PWord(pMB)^ := pDE.Value; pMB := pDB; Inc(pMB, (J div 8) * 17); pMB^ := pMB^ or (1 shl (J and 7)); Inc(pDE); end; Result := GenericVendorWrite(DeviceIndex, AUR_DAC_IMMEDIATE, 0, 0, Length(Content), PAnsiChar(Content)); end; end; function DACSetBoardRange(DeviceIndex: LongWord; RangeCode: LongWord): LongWord; cdecl; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; if not Dev[DeviceIndex].bDACBoardRange then begin //`@ If the board has channel range, then channel range in a loop. Result := ERROR_BAD_TOKEN_TYPE; Exit; end; Result := GenericVendorWrite(DeviceIndex, AUR_DAC_RANGE, RangeCode, 0, 0, nil); end; function InStrC(C: AnsiChar; S: AnsiString; StartIndex: Integer = 1): LongWord; var I: Integer; begin for I := StartIndex to Length(S) do if S[I] = C then begin Result := I; Exit; end ; Result := 0; end; function StringReplaceC(const S: AnsiString; const OldChar, NewChar: AnsiChar): AnsiString; var I: Integer; begin Result := S; for I := 1 to Length(Result) do if Result[I] = OldChar then Result[I] := NewChar ; end; function DACSetChannelCal(DeviceIndex: LongWord; Channel: LongWord; CalFileName: PAnsiChar): LongWord; cdecl; var CalTable: array of Word; Suc: Boolean; L, L2: LongWord; hFil: THandle; InterBuf: AnsiString; I, J, K: Integer; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if (FlashSectors = 0) or not bDACChannelCal then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if Channel >= ImmDACs then begin Result := ERROR_INVALID_ADDRESS; Exit; end; if (CalFileName = ':1TO1:') or (CalFileName = ':NONE:') then begin Result := AIOUSB_FlashEraseSector(DeviceIndex, Channel * 2); if Result <> ERROR_SUCCESS then Exit; Result := AIOUSB_FlashEraseSector(DeviceIndex, Channel * 2 + 1); if Result <> ERROR_SUCCESS then Exit; Result := GenericVendorWrite(DeviceIndex, AUR_DEBUG_FLASH_1TO1, 0, Channel, 0, nil); end else begin hFil := CreateFileA(CalFileName, GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0); if (hFil = 0) or (hFil = INVALID_HANDLE_VALUE) then begin Result := GetLastError; if Result = ERROR_SUCCESS then Result := ERROR_GEN_FAILURE; Exit; end; L := GetFileSize(hFil, nil); Result := GetLastError; if Result <> ERROR_SUCCESS then begin CloseHandle(hFil); Exit; end; L := Min(L, $08000000); //Cap for RAM reasons. Even a 0x-based file should be $80000 bytes. try SetString(InterBuf, nil, L + 1); InterBuf[L + 1] := #13; //Terminate for the read-out logic. except CloseHandle(hFil); Result := ERROR_OUTOFMEMORY; Exit; end; Suc := ReadFile(hFil, InterBuf[1], L, L2, nil); Result := GetLastError; if (Result = ERROR_SUCCESS) and not Suc then Result := ERROR_GEN_FAILURE; if (Result = ERROR_SUCCESS) and (L2 < L) then begin Result := GetLastError; if Result = ERROR_SUCCESS then Result := ERROR_GEN_FAILURE; end; CloseHandle(hFil); if Result <> ERROR_SUCCESS then Exit; SetLength(CalTable, $10000); try InterBuf := StringReplaceC(InterBuf, #10, #13); J := 1; for I := 0 to High(CalTable) do begin repeat K := InStrC(#13, InterBuf, J); if K = 0 then begin Result := ERROR_HANDLE_EOF; SetLength(CalTable, 0); Exit; end else if K = J then begin Inc(J); end else begin CalTable[I] := StrToInt(Trim(UnicodeString(Copy(InterBuf, J, K - J)))); J := K + 1; Break; end; until False; end; except SetLength(CalTable, 0); Result := ERROR_INVALID_DATA; Exit; end; Result := AIOUSB_FlashEraseSector(DeviceIndex, Channel * 2); if Result <> ERROR_SUCCESS then Exit; Result := AIOUSB_FlashEraseSector(DeviceIndex, Channel * 2 + 1); if Result <> ERROR_SUCCESS then Exit; Result := AIOUSB_FlashWrite(DeviceIndex, Channel * $20000, Length(CalTable) * SizeOf(CalTable[0]), @CalTable[0]); SetLength(CalTable, 0); end; end; end; function DACOutputOpen(DeviceIndex: LongWord; var ClockHz: Double): LongWord; cdecl; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bDACStream then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if bDACOpen or bDACClosing then begin Result := ERROR_TOO_MANY_OPEN_FILES; Exit; end; //DoSetIFace(Handle, $100); Result := GenericVendorWrite(DeviceIndex, AUR_DAC_CONTROL, $80, 0, 0, nil); //Reset if Result <> ERROR_SUCCESS then Exit; Result := GenericVendorWrite(DeviceIndex, AUR_DAC_DATAPTR, $00, 0, 0, nil); //DataPtr << 0 if Result <> ERROR_SUCCESS then Exit; CtrDivisor := Round(12000000 / ClockHz); ClockHz := 12000000 / CtrDivisor; Result := GenericVendorWrite(DeviceIndex, AUR_DAC_DIVISOR, 0, CtrDivisor, 0, nil); //Set divisor if Result <> ERROR_SUCCESS then Exit; hDACDataMutex := CreateMutex(nil, False, nil); hDACDataSem := CreateSemaphore(nil, 0, $FFFF, nil); WorkerThread := TDACWorker.Create(True); WorkerThread.FreeOnTerminate := False; WorkerThread.Index := DeviceIndex; WorkerThread.Start; bDACOpen := True; end; end; function DACOutputAbort(DeviceIndex: LongWord): LongWord; cdecl; begin Result := ERROR_NOT_SUPPORTED; //`@ end; function DACOutputClose(DeviceIndex: LongWord; bWait: LongBool): LongWord; cdecl; var L, L2, Releases: Integer; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bDACStream then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if not bDACOpen then begin Result := ERROR_FILE_NOT_FOUND; Exit; end; bDACOpen := False; //Flush pending data to worker buffer, adding EOM($8000), and release semaphore one extra time. WaitForSingleObject(hDACDataMutex, INFINITE); L := Length(DACData); if L = 0 then begin SetLength(DACData, 1); L2 := Length(PendingDACData); if L2 <> 0 then begin //No buffered buffers but we have pending data, so we'll buffer and use that. PendingDACData[L2] := AnsiChar(Byte(PendingDACData[L2]) or $80); DACData[0] := PendingDACData; Releases := 2; end else begin //No buffered buffers and no pending data, so buffer a little buffer so we can add EOM. DACData[0] := #$00#$E0; //`@ Releases := 2; end; end else begin L2 := Length(PendingDACData); if L2 <> 0 then begin //Some buffered buffers, but we have pending data, so we'll buffer and use the pending data. SetLength(DACDAta, L + 1); PendingDACData[L2] := AnsiChar(Byte(PendingDACData[L2]) or $80); DACData[L] := PendingDACData; Releases := 2; end else begin //Some buffered buffers and no pending data, so we'll use the last buffer. Dec(L); L2 := Length(DACData[L]); DACData[L][L2] := AnsiChar(Byte(DACData[L][L2]) or $80); Releases := 1; end; end; ReleaseMutex(hDACDataMutex); PendingDACData := ''; bDACClosing := True; ReleaseSemaphore(hDACDataSem, Releases, nil); { while WaitForSingleObject(hDACDataSem, 0) <> WAIT_TIMEOUT do ReleaseSemaphore(hDACDataSem, 1, nil) ; } { if bWait then begin //Once worker thread has drained its buffer, it checks bDACOpen, and if false it closes and reports back to us. //`@ end; } WorkerThread.Terminate; WorkerThread.Free; end; end; function DACOutputCloseNoEnd(DeviceIndex: LongWord; bWait: LongBool): LongWord; cdecl; var L, L2, Releases: Integer; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bDACStream then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if not bDACOpen then begin Result := ERROR_FILE_NOT_FOUND; Exit; end; bDACOpen := False; //Flush pending data to worker buffer, and release semaphore one extra time. WaitForSingleObject(hDACDataMutex, INFINITE); L2 := Length(PendingDACData); if L2 <> 0 then begin L := Length(DACData); SetLength(DACDAta, L + 1); DACData[L] := PendingDACData; Releases := 2; end else begin //No pending data, so just release the semaphore to signal end. Releases := 1; end; ReleaseMutex(hDACDataMutex); PendingDACData := ''; bDACClosing := True; ReleaseSemaphore(hDACDataSem, Releases, nil); { if bWait then begin //Once worker thread has drained its buffer, it checks bDACOpen, and if false it closes and reports back to us. //`@ end; } WorkerThread.Terminate; WorkerThread.Free; end; end; function DACOutputSetCount(DeviceIndex, NewCount: LongWord): LongWord; cdecl; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bDACStream then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if not bDACOpen then begin Result := ERROR_FILE_NOT_FOUND; Exit; end; if NewCount = 0 then begin Result := ERROR_INVALID_PARAMETER; Exit; end; if NewCount > 8 then begin Result := ERROR_OUTOFMEMORY; Exit; end; DACsUsed := NewCount; end; except Result := ERROR_INTERNAL_ERROR; end; end; function DACOutputFrame(DeviceIndex, FramePoints: LongWord; FrameData: PWord): LongWord; cdecl; const FrameBufferSize = 8192; //Bytes per buffer, bloody ass band-aid. var I, L, Ch: Integer; FrameSamples, FrameBytes, FrameBuffers: Integer; NewDACData: TDACData; pSample: PWord; pBuffer: PAnsiChar; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bDACStream then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if not bDACOpen then begin Result := ERROR_FILE_NOT_FOUND; Exit; end; if FramePoints <= 0 then begin Result := ERROR_INVALID_PARAMETER; Exit; end; if FramePoints > 6400 then begin Result := ERROR_OUTOFMEMORY; Exit; end; WaitForSingleObject(hDACDataMutex, INFINITE); L := Length(DACData); ReleaseMutex(hDACDataMutex); if L > 32 then begin Result := ERROR_NOT_READY; Exit; end; try FrameSamples := Integer(FramePoints) * DACsUsed; SetString(NewDACData, PAnsiChar(FrameData), FrameSamples * SizeOf(Word)); except Result := ERROR_NOACCESS; Exit; end; pSample := PWord(PAnsiChar(NewDACData)); Ch := 0; for I := 0 to FrameSamples - 1 do begin pSample^ := pSample^ and $0FFF; Inc(Ch); if Ch = DACsUsed then begin pSample^ := pSample^ or $2000; Ch := 0; end; Inc(pSample); end; Dec(pSample); pSample^ := pSample^ or $4000; NewDACData := PendingDACData + NewDACData; FrameBytes := Length(NewDACData); FrameBuffers := FrameBytes div FrameBufferSize; pBuffer := PAnsiChar(NewDACData); WaitForSingleObject(hDACDataMutex, INFINITE); L := Length(DACData); SetLength(DACData, L + FrameBuffers); for I := 0 to FrameBuffers - 1 do begin SetString(DACData[L + I], pBuffer, FrameBufferSize); Inc(pBuffer, FrameBufferSize); end; ReleaseMutex(hDACDataMutex); ReleaseSemaphore(hDACDataSem, FrameBuffers, nil); FrameBytes := FrameBytes mod FrameBufferSize; if FrameBytes <> 0 then SetString(PendingDACData, pBuffer, FrameBytes) else PendingDACData := '' ; NewDACData := ''; end; except Result := ERROR_INTERNAL_ERROR; end; end; function DACOutputFrameRaw(DeviceIndex, FramePoints: LongWord; FrameData: PWord): LongWord; cdecl; const FrameBufferSize = 8192; //Bytes per buffer, bloody ass band-aid. var I, L: Integer; FrameSamples, FrameBytes, FrameBuffers: Integer; NewDACData: TDACData; pBuffer: PAnsiChar; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bDACStream then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if not bDACOpen then begin Result := ERROR_FILE_NOT_FOUND; Exit; end; if FramePoints <= 0 then begin Result := ERROR_INVALID_PARAMETER; Exit; end; if FramePoints > 6400 then begin Result := ERROR_OUTOFMEMORY; Exit; end; WaitForSingleObject(hDACDataMutex, INFINITE); L := Length(DACData); ReleaseMutex(hDACDataMutex); if L > 32 then begin Result := ERROR_NOT_READY; Exit; end; try FrameSamples := Integer(FramePoints) * DACsUsed; SetString(NewDACData, PAnsiChar(FrameData), FrameSamples * SizeOf(Word)); except Result := ERROR_NOACCESS; Exit; end; NewDACData := PendingDACData + NewDACData; FrameBytes := Length(NewDACData); FrameBuffers := FrameBytes div FrameBufferSize; pBuffer := PAnsiChar(NewDACData); WaitForSingleObject(hDACDataMutex, INFINITE); L := Length(DACData); SetLength(DACData, L + FrameBuffers); for I := 0 to FrameBuffers - 1 do begin SetString(DACData[L + I], pBuffer, FrameBufferSize); Inc(pBuffer, FrameBufferSize); end; ReleaseMutex(hDACDataMutex); ReleaseSemaphore(hDACDataSem, FrameBuffers, nil); FrameBytes := FrameBytes mod FrameBufferSize; if FrameBytes <> 0 then SetString(PendingDACData, pBuffer, FrameBytes) else PendingDACData := '' ; NewDACData := ''; end; except Result := ERROR_INTERNAL_ERROR; end; end; function DACOutputStatus(DeviceIndex: LongWord): LongWord; cdecl; begin Result := ERROR_NOT_SUPPORTED; //`@ end; function DACOutputStart(DeviceIndex: LongWord): LongWord; cdecl; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bDACStream then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if not bDACOpen then begin Result := ERROR_FILE_NOT_FOUND; Exit; end; if bDACStarted then begin Result := ERROR_ALREADY_EXISTS; Exit; end; Result := GenericVendorWrite(DeviceIndex, AUR_DAC_CONTROL, $01, 0, 0, nil); if Result = ERROR_SUCCESS then bDACStarted := True; end; except Result := ERROR_INTERNAL_ERROR; end; end; function DACOutputSetInterlock(DeviceIndex: LongWord; bInterlock: LongBool): LongWord; cdecl; var Value: Byte; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bDACStream then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if not bDACOpen then begin Result := ERROR_FILE_NOT_FOUND; Exit; end; if bInterlock then Value := $20 else Value := $00; Result := GenericVendorWrite(DeviceIndex, AUR_DAC_CONTROL, Value, 0, 0, nil); end; except Result := ERROR_INTERNAL_ERROR; end; end; function DACOutputProcess(DeviceIndex: LongWord; var ClockHz: Double; Samples: LongWord; pSampleData: PWord): LongWord; cdecl; const BlockSamples = 31*512; var TargetPipe: LongWord; L: LongWord; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bDACStream then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if bDACOpen or bDACClosing then begin Result := ERROR_TOO_MANY_OPEN_FILES; Exit; end; if Samples >= 128*1024 then begin Result := ERROR_OUTOFMEMORY; Exit; end; //Result := DoSetIFace(Handle, $100); //if Result <> ERROR_SUCCESS then begin Result := GetMappedFailure(DeviceIndex); Exit; end; Result := GenericVendorWrite(DeviceIndex, AUR_DAC_CONTROL, $80, 0, 0, nil); //Reset if Result <> ERROR_SUCCESS then Exit; Result := GenericVendorWrite(DeviceIndex, AUR_DAC_DATAPTR, $00, 0, 0, nil); //DataPtr << 0 if Result <> ERROR_SUCCESS then Exit; CtrDivisor := Round(12000000 / ClockHz); ClockHz := 12000000 / CtrDivisor; Result := GenericVendorWrite(DeviceIndex, AUR_DAC_DIVISOR, 0, CtrDivisor, 0, nil); //Set divisor if Result <> ERROR_SUCCESS then Exit; //Transfer data TargetPipe := $02; while Samples > BlockSamples do begin L := 0; Result := AWU_GenericBulkOut(DeviceIndex, TargetPipe, pSampleData, BlockSamples * 2, L); if Result <> ERROR_SUCCESS then Exit; Inc(pSampleData, BlockSamples); Dec(Samples, BlockSamples); end; L := 0; Result := AWU_GenericBulkOut(DeviceIndex, TargetPipe, pSampleData, Samples * 2, L); if Result <> ERROR_SUCCESS then Exit; Result := GenericVendorWrite(DeviceIndex, AUR_DAC_CONTROL, $01, 0, 0, nil); //Start //if Result <> ERROR_SUCCESS then Exit; end; end; function DEB_SetInterface(DeviceIndex: LongWord; TargetInterface: Word): LongWord; cdecl; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; //Result := DoSetIFace(Dev[DeviceIndex].Handle, TargetInterface); Result := ERROR_NOT_SUPPORTED; except Result := ERROR_INTERNAL_ERROR; end; end; function DEB_BulkIn(DeviceIndex: LongWord): LongWord; cdecl; begin Result := ERROR_NOT_SUPPORTED; end; function DEB_BulkOut(DeviceIndex, TargetPipe: LongWord; pBuf: Pointer; BufLen: LongWord): LongWord; cdecl; var L: LongWord; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; L := 0; Result := AWU_GenericBulkOut(DeviceIndex, TargetPipe, pBuf, BufLen, L); except Result := ERROR_INTERNAL_ERROR; end; end; { TDACWorker } procedure TDACWorker.Execute; var {I,} L, Intro: Integer; DACData: TDACData; TargetPipe, nBytes: LongWord; bExit: Boolean; //DataPtr: LongWord; //BufferSends: LongInt; //hDevice: THandle; begin Intro := (128 + 32)*1024; //After one and a quarter 128KB SRAMs, issue the start, if the user hasn't issued it first. //BufferSends := 0; TargetPipe := $02; //DataPtr := 0; //hDevice := Dev[Index].Handle; bExit := False; repeat try WaitForSingleObject(Dev[Index].hDACDataSem, INFINITE); if Dev[Index].bDACAborting then Break; WaitForSingleObject(Dev[Index].hDACDataMutex, INFINITE); L := Length(Dev[Index].DACData); if L = 0 then begin if Dev[Index].bDACClosing then bExit := True; end else begin DACData := Dev[Index].DACData[0]; Dec(L); if L <> 0 then begin Dev[Index].DACData[0] := Dev[Index].DACData[L]; //For garbage collection Move(Dev[Index].DACData[1], Dev[Index].DACData[0], L * 4); end; SetLength(Dev[Index].DACData, L); end; ReleaseMutex(Dev[Index].hDACDataMutex); if bExit then Break; L := Length(DACData); { for I := 1 to L do if ((I and 1) = 0) and ((Byte(DACData[I]) and $80) <> 0) then Beep ; } AWU_GenericBulkOut(Index, TargetPipe, PAnsiChar(DACData), L, nBytes); DACData := ''; //Inc(BufferSends); //Inc(DataPtr, L); if Intro <> 0 then begin Dec(Intro, L); if Intro <= 0 then begin Intro := 0; { VRD.Request := AUR_DAC_CONTROL; //Reset VRD.Value := $80; VRD.Index := 0; nBytes := 0; DeviceIoControl(hDevice, IOCTL_AIOUSB_WRITE, @VRD, SizeOf(VRD), nil, 0, nBytes, nil); VRD.Request := AUR_DAC_DIVISOR; //Set divisor VRD.Value := 0; VRD.Index := Dev[Index].CtrDivisor; nBytes := 0; DeviceIoControl(hDevice, IOCTL_AIOUSB_WRITE, @VRD, SizeOf(VRD), nil, 0, nBytes, nil); } DACOutputStart(Index); end; end; { VRD.Request := AUR_DAC_DATAPTR; //Set DataPtr to proper value - debug VRD.Value := (DataPtr shr 6) and $0700; VRD.Index := DataPtr and $3FFF; nBytes := 0; DeviceIoControl(hDevice, IOCTL_AIOUSB_WRITE, @VRD, SizeOf(VRD), nil, 0, nBytes, nil); } except Break; end; until Terminated; WaitForSingleObject(Dev[Index].hDACDataMutex, INFINITE); SetLength(Dev[Index].DACData, 0); ReleaseMutex(Dev[Index].hDACDataMutex); //if BufferSends <> 0 then BufferSends := 0; //CloseHandle(hDevice); CloseHandle(Dev[Index].hDACDataMutex); CloseHandle(Dev[Index].hDACDataSem); Dev[Index].bDACClosing := False; Dev[Index].bDACAborting := False; Dev[Index].bDACStarted := False; end; function DACOutputInvade(DeviceIndex, InvasionType: LongWord; InvasionData: PLongWord): LongWord; cdecl; begin Result := ERROR_NOT_SUPPORTED; end; function ADC_GetConfig(DeviceIndex: LongWord; pConfigBuf: Pointer; var ConfigBufSize: LongWord): LongWord; cdecl; var Content: AnsiString; L: LongWord; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if ConfigBytes = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if ConfigBufSize < ConfigBytes then begin Result := ERROR_INSUFFICIENT_BUFFER; ConfigBufSize := ConfigBytes; Exit; end; if pConfigBuf = nil then begin Result := ERROR_INVALID_PARAMETER; Exit; end; SetString(Content, PAnsiChar(pConfigBuf), ConfigBytes); //Probe buffer L := ConfigBytes; Result := GenericVendorRead(DeviceIndex, AUR_ADC_GET_CONFIG, 0, 0, L, pConfigBuf); if Result = ERROR_SUCCESS then ConfigBufSize := ConfigBytes; end; end; function ADC_SetConfig(DeviceIndex: LongWord; pConfigBuf: Pointer; var ConfigBufSize: LongWord): LongWord; cdecl; var Content: AnsiString; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if ConfigBytes = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if ConfigBufSize < ConfigBytes then begin Result := ERROR_INSUFFICIENT_BUFFER; ConfigBufSize := ConfigBytes; Exit; end; if pConfigBuf = nil then begin Result := ERROR_INVALID_PARAMETER; Exit; end; SetString(Content, PAnsiChar(pConfigBuf), ConfigBytes); //Probe buffer Result := GenericVendorWrite(DeviceIndex, AUR_ADC_SET_CONFIG, 0, 0, ConfigBytes, pConfigBuf); if Result = ERROR_SUCCESS then ConfigBufSize := ConfigBytes; end; end; function ADC_RangeAll(DeviceIndex: LongWord; pGainCodes: PByte; bDifferential: LongBool): LongWord; cdecl; var ConfigStr: AnsiString; L: LongWord; I: Integer; pRC: PByte; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if (ADCChannels = 0) or (not bADCBulk) then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if pGainCodes = nil then begin Result := ERROR_INVALID_PARAMETER; Exit; end; pRC := pGainCodes; for I := 1 to ADCChannels do begin if (pRC^ and $F8) <> 0 then begin Result := ERROR_INVALID_DATA; Exit; end; Inc(pRC); end; L := ConfigBytes; SetString(ConfigStr, nil, L); Result := GenericVendorRead(DeviceIndex, AUR_ADC_GET_CONFIG, 0, 0, L, PAnsiChar(ConfigStr)); if Result <> ERROR_SUCCESS then Exit; pRC := pGainCodes; for I := 1 to ADCChannels do begin ConfigStr[I] := AnsiChar(pRC^ or (Ord(bDifferential) shl 3)); Inc(pRC); end; Result := GenericVendorWrite(DeviceIndex, AUR_ADC_SET_CONFIG, 0, 0, Length(ConfigStr), PAnsiChar(ConfigStr)); end; end; function ADC_Range1(DeviceIndex, ADChannel: LongWord; GainCode: Byte; bDifferential: LongBool): LongWord; cdecl; var ConfigStr: AnsiString; L: LongWord; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bADCBulk then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if ADChannel >= ADCChannels then begin Result := ERROR_INVALID_ADDRESS; Exit; end; if (GainCode and $F8) <> 0 then begin Result := ERROR_INVALID_PARAMETER; Exit; end; L := ConfigBytes; SetString(ConfigStr, nil, L); Result := GenericVendorRead(DeviceIndex, AUR_ADC_GET_CONFIG, 0, 0, L, PAnsiChar(ConfigStr)); if Result <> ERROR_SUCCESS then Exit; ConfigStr[1 + (ADChannel mod ADCChannels)] := AnsiChar(GainCode or (Ord(bDifferential) shl 3)); Result := GenericVendorWrite(DeviceIndex, AUR_ADC_SET_CONFIG, 0, 0, Length(ConfigStr), PAnsiChar(ConfigStr)); end; end; function ADC_ADMode(DeviceIndex: LongWord; TriggerMode, CalMode: Byte): LongWord; cdecl; var ConfigStr: AnsiString; L: LongWord; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bADCBulk then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if not CalMode in [$00, $01, $03, $05, $07] then begin Result := ERROR_INVALID_PARAMETER; Exit; end; L := ConfigBytes; SetString(ConfigStr, nil, L); Result := GenericVendorRead(DeviceIndex, AUR_ADC_GET_CONFIG, 0, 0, L, PAnsiChar(ConfigStr)); if Result <> ERROR_SUCCESS then Exit; ConfigStr[1 + $10] := AnsiChar(CalMode); ConfigStr[1 + $11] := AnsiChar(TriggerMode); Result := GenericVendorWrite(DeviceIndex, AUR_ADC_SET_CONFIG, 0, 0, Length(ConfigStr), PAnsiChar(ConfigStr)); end; end; function ADC_SetScanLimits(DeviceIndex, StartChannel, EndChannel: LongWord): LongWord; cdecl; var ConfigStr: AnsiString; L: LongWord; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bADCBulk then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if (StartChannel > EndChannel) or (EndChannel > ADCMUXChannels) then begin Result := ERROR_INVALID_PARAMETER; Exit; end; L := ConfigBytes; SetString(ConfigStr, nil, L); Result := GenericVendorRead(DeviceIndex, AUR_ADC_GET_CONFIG, 0, 0, L, PAnsiChar(ConfigStr)); if Result <> ERROR_SUCCESS then Exit; if ConfigBytes < $15 then ConfigStr[1 + $12] := AnsiChar(StartChannel or (EndChannel shl 4)) else begin ConfigStr[1 + $12] := AnsiChar((StartChannel and $0F) or (EndChannel shl 4)); ConfigStr[1 + $14] := AnsiChar((StartChannel shr 4) or (EndChannel and $F0)); end; Result := GenericVendorWrite(DeviceIndex, AUR_ADC_SET_CONFIG, 0, 0, Length(ConfigStr), PAnsiChar(ConfigStr)); end; end; function ADC_SetOversample(DeviceIndex: LongWord; Oversample: Byte): LongWord; cdecl; var ConfigStr: AnsiString; L: LongWord; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bADCBulk then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; L := ConfigBytes; SetString(ConfigStr, nil, L); Result := GenericVendorRead(DeviceIndex, AUR_ADC_GET_CONFIG, 0, 0, L, PAnsiChar(ConfigStr)); if Result <> ERROR_SUCCESS then Exit; ConfigStr[1 + $13] := AnsiChar(Oversample); Result := GenericVendorWrite(DeviceIndex, AUR_ADC_SET_CONFIG, 0, 0, Length(ConfigStr), PAnsiChar(ConfigStr)); end; end; function ADC_QueryCal(DeviceIndex: LongWord): LongWord; cdecl; var L: LongWord; DataByte: Byte; Status: LongWord; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bADCBulk then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; DataByte := $FF; L := SizeOf(DataByte); Status := GenericVendorRead(DeviceIndex, AUR_PROBE_CALFEATURE, 0, 0, L, @DataByte); if Status <> ERROR_SUCCESS then begin Result := Status; Exit; end; if (L <> SizeOf(DataByte)) or (DataByte <> $BB) then begin Result := ERROR_NOT_SUPPORTED; Exit; end; Result := ERROR_SUCCESS; end; end; function ADC_SetCal(DeviceIndex: LongWord; CalFileName: PAnsiChar): LongWord; cdecl; const ChunkSize = $400; var CalTable: array of Word; oConfig, nConfig: array of Byte; Suc: Boolean; procedure DoLoadCalTable; var bFirstChunkDouble: Boolean; TargetPipe: LongWord; SRAMIndex: Integer; L, L2: LongWord; begin bFirstChunkDouble := True; TargetPipe := $02; SRAMIndex := 0; repeat L2 := (Length(CalTable) - SRAMIndex); if L2 > ChunkSize then L2 := ChunkSize; L := 0; Suc := AWU_GenericBulkOut(DeviceIndex, TargetPipe, @CalTable[SRAMIndex], SizeOf(CalTable[0]) * L2, L) = ERROR_SUCCESS; if not Suc then Break; GenericVendorWrite(DeviceIndex, $BB, SRAMIndex, L2, 0, nil); L := L div 2; //Entries L := L and $FF00; //Entries in complete packets Inc(SRAMIndex, L); if bFirstChunkDouble then begin bFirstChunkDouble := False; SRAMIndex := 0; end; until (SRAMIndex = $10000); end; function ConfigureAndAcquire: Double; var L: LongWord; I, Tot: Integer; Sample: Word; begin L := Length(nConfig); ADC_SetConfig(DeviceIndex, @nConfig[0], L); Tot := 0; for I := 1 to 256 do begin ADC_GetImmediate(DeviceIndex, 0, @Sample); Inc(Tot, Sample); end; Result := Tot * (1 / 256); end; function ConfigureAndBulkAcquire: Double; var L, BytesLeft, TargetPipe, BCData: LongWord; I, Tot: Integer; ADData: array of Word; pADBuf: PByte; begin L := Length(nConfig); ADC_SetConfig(DeviceIndex, @nConfig[0], L); SetLength(ADData, 256); //Inline bulk the data. TargetPipe := $86; BytesLeft := SizeOf(ADData[0]) * Length(ADData); pADBuf := @ADData[0]; //GenericVendorWrite(DeviceIndex, AUR_SET_GPIF_MODE, 0, $0, 0, nil); BCData := $00000005; GenericVendorWrite(DeviceIndex, $BC, 0, Length(ADData), SizeOf(BCData), @BCData); ADC_GetImmediate(DeviceIndex, 0, @ADData[0]); repeat L := 0; Result := AWU_GenericBulkIn(DeviceIndex, TargetPipe, pADBuf, BytesLeft, L); if Result <> ERROR_SUCCESS then Break; Dec(BytesLeft, L); Inc(pADBuf, L); until BytesLeft <= 0; //Average it up. Tot := 0; for I := 0 to High(ADData) do Inc(Tot, ADData[I]); Result := Tot / Length(ADData); end; function GetHiRef: Word; var Status, DataSize: LongWord; begin DataSize := 2; Status := GenericVendorRead(DeviceIndex, $A2, $1DF2, 0, DataSize, @Result); if Status <> ERROR_SUCCESS then Result := 0 else if DataSize <> 2 then Result := 0 else if Result = $FFFF then Result := 0 ; end; const LoRefRef = 0 * 6553.6; HiRefRef = 9.9339 * 6553.6; var I, J, K: Integer; L: LongWord; hFil: THandle; F, LoRef, HiRef, dRef, LoRead, HiRead, dRead: Double; DataByte: Byte; Status: LongWord; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bADCBulk then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; DataByte := $FF; L := SizeOf(DataByte); Status := GenericVendorRead(DeviceIndex, AUR_PROBE_CALFEATURE, 0, 0, L, @DataByte); if Status <> ERROR_SUCCESS then begin Result := Status; Exit; end; if (L <> SizeOf(DataByte)) or (DataByte <> $BB) then begin Result := ERROR_NOT_SUPPORTED; Exit; end; L := ConfigBytes; SetLength(oConfig, L); SetLength(nConfig, L); FillChar(oConfig[0], L, $00); FillChar(nConfig[0], L, $00); ADC_GetConfig(DeviceIndex, @oConfig[0], L); try if CalFileName = ':AUTO:' then begin LoRef := LoRefRef; HiRef := GetHiRef; if HiRef = 0 then HiRef := HiRefRef; dRef := HiRef - LoRef; nConfig[$10] := $05; //Select bip low ref, to select bip cal bank(on banked boards). nConfig[$00] := $01; //Select ±10V range for channel 0. for K := 0 to 1 do begin ADC_SetConfig(DeviceIndex, @nConfig[0], L); //Load 1-to-1 to cal against. SetLength(CalTable, $10000); for I := 0 to High(CalTable) do CalTable[I] := I; DoLoadCalTable; nConfig[$11] := $04; //scan software-start nConfig[$12] := $00; //select 1 channel nConfig[$13] := $FF; //+255 oversample per channel, for 256 samples per scan nConfig[$10] := nConfig[$10] or $02; //cal high ref HiRead := ConfigureAndBulkAcquire; //$FE3F; if HiRead < $F000 then begin Result := ERROR_INVALID_DATA; Exit; end; Sleep(10); //Cargo cult. nConfig[$10] := nConfig[$10] and not $02; //cal low ref LoRead := ConfigureAndBulkAcquire; //$0042; if K = 0 then begin if (LoRead < $7F00) or (LoRead > $80FF) then begin Result := ERROR_INVALID_DATA; Exit; end; end else begin if LoRead > $00FF then begin Result := ERROR_INVALID_DATA; Exit; end; end; Sleep(10); //Cargo cult. dRead := HiRead - LoRead; SetLength(CalTable, $10000); for I := 0 to High(CalTable) do begin F := (I - LoRead) / dRead; F := LoRef + F * dRef; if K = 0 then F := 0.5 * (F + $10000); J := Round(F); if J <= 0 then J := 0 else if J >= $FFFF then J := $FFFF ; CalTable[I] := J; end; DoLoadCalTable; nConfig[$10] := $01; //Select unip low ref, to select unip cal bank(on banked boards). nConfig[$00] := $00; //Select 0-10V range for channel 0. end; end else if (CalFileName = ':NORM:') then begin LoRef := LoRefRef; HiRef := GetHiRef; if HiRef = 0 then HiRef := HiRefRef; dRef := HiRef - LoRef; LoRead := $0042; HiRead := $FE3F; dRead := HiRead - LoRead; SetLength(CalTable, $10000); for I := 0 to High(CalTable) do begin F := (I - LoRead) / dRead; F := LoRef + F * dRef; J := Round(F); if J <= 0 then J := 0 else if J >= $FFFF then J := $FFFF ; CalTable[I] := J; end; nConfig[$10] := $05; //Select bip low ref, to select bip cal bank(on banked boards). for K := 0 to 1 do begin ADC_SetConfig(DeviceIndex, @nConfig[0], L); DoLoadCalTable; nConfig[$10] := $01; //Select unip low ref, to select unip cal bank(on banked boards). end; end else if (CalFileName = ':1TO1:') or (CalFileName = ':NONE:') then begin SetLength(CalTable, $10000); for I := 0 to High(CalTable) do CalTable[I] := I; nConfig[$10] := $05; //Select bip low ref, to select bip cal bank(on banked boards). for K := 0 to 1 do begin ADC_SetConfig(DeviceIndex, @nConfig[0], L); DoLoadCalTable; nConfig[$10] := $01; //Select unip low ref, to select unip cal bank(on banked boards). end; end else if Copy(CalFileName, 1, 1) = ':' then begin Result := ERROR_MOD_NOT_FOUND; Exit; end else begin //Not one of the macros, so treat it as a filename. hFil := CreateFileA(CalFileName, GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0); if (hFil = 0) or (hFil = INVALID_HANDLE_VALUE) then begin Result := GetLastError; if Result = ERROR_SUCCESS then Result := ERROR_GEN_FAILURE; Exit; end; SetLength(CalTable, $10000); L := 0; Suc := ReadFile(hFil, CalTable[0], SizeOf(CalTable[0]) * Length(CalTable), L, nil); Result := GetLastError; if (Result = ERROR_SUCCESS) and not Suc then Result := ERROR_GEN_FAILURE; if (Result = ERROR_SUCCESS) and (Integer(L) < SizeOf(CalTable[0]) * Length(CalTable)) then Result := ERROR_HANDLE_EOF; CloseHandle(hFil); if Result <> ERROR_SUCCESS then Exit; DoLoadCalTable; end; finally L := ConfigBytes; ADC_SetConfig(DeviceIndex, @oConfig[0], L); SetLength(oConfig, 0); SetLength(nConfig, 0); SetLength(CalTable, 0); end; if Suc then Result := ERROR_SUCCESS else Result := GetMappedFailure(DeviceIndex) ; end; end; function ADC_Initialize(DeviceIndex: LongWord; pConfigBuf: Pointer; var ConfigBufSize: LongWord; CalFileName: PAnsiChar): LongWord; cdecl; begin Result := ERROR_SUCCESS; if (pConfigBuf <> nil) and (ConfigBufSize <> 0) then begin Result := ADC_SetConfig(DeviceIndex, pConfigBuf, ConfigBufSize); if Result <> ERROR_SUCCESS then Exit; end; if CalFileName <> nil then begin Result := ADC_SetCal(DeviceIndex, CalFileName); //if Result <> ERROR_SUCCESS then Exit; end; end; function ADC_Start(DeviceIndex: LongWord): LongWord; cdecl; var //L: LongWord; Suc: Boolean; //TargetPipe: LongWord; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bADCBulk then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; { if bADCOpen then begin Result := ERROR_TOO_MANY_OPEN_FILES; Exit; end; } { TargetPipe := $100; L := 0; Suc := DeviceIoControl(Handle, IOCTL_SetIFace, @TargetPipe, 2, nil, 0, L, nil); } Suc := True; { SetString(Content, nil, SizeOf(TVendorRequestData)); pVRD.Request := AUR_ADC_GO; pVRD.Value := 0; pVRD.Index := 0; L := 0; Suc := DeviceIoControl(Handle, IOCTL_AIOUSB_WRITE, pVRD, Length(Content), nil, 0, L, nil); } if Suc then begin //bADCOpen := True; Result := ERROR_SUCCESS; end else Result := GetMappedFailure(DeviceIndex) ; end; end; function ADC_Stop(DeviceIndex: LongWord): LongWord; cdecl; var //L: LongWord; Suc: Boolean; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bADCBulk then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; Suc := True; { SetString(Content, nil, SizeOf(TVendorRequestData)); pVRD.Request := AUR_ADC_STOP; pVRD.Value := 0; pVRD.Index := 0; L := 0; Suc := DeviceIoControl(Handle, IOCTL_AIOUSB_WRITE, pVRD, Length(Content), nil, 0, L, nil); } if Suc then Result := ERROR_SUCCESS else Result := GetMappedFailure(DeviceIndex) ; end; end; { TADCWorker } procedure TADCWorker.Execute; var L, Status: LongWord; begin SetThreadPriority(Handle, THREAD_PRIORITY_TIME_CRITICAL); SetLength(ADBuf, Min(BytesLeft, Dev[DI].StreamingBlockSize)); repeat if bAbort then begin ReturnValue := ERROR_OPERATION_ABORTED; BytesLeft := 0; Exit; end; L := 0; Status := AWU_GenericBulkIn(DI, TargetPipe, @ADBuf[0], Length(ADBuf), L); if Status <> ERROR_SUCCESS then begin ReturnValue := Status; BytesLeft := 0; Exit; end; Move(ADBuf[0], pTar^, L); Inc(pTar, L div 2); Dec(BytesLeft, L); if BytesLeft < Length(ADBuf) then SetLength(ADBuf, BytesLeft); until BytesLeft = 0; ReturnValue := ERROR_SUCCESS; end; function ADC_BulkAcquire(DeviceIndex: LongWord; BufSize: LongWord; pBuf: Pointer): LongWord; cdecl; var oADCWorker: TADCWorker; oADCContAcqWorker: TADCContAcqWorker; oADCContBufWorker: TADCContBufWorker; BCData: LongWord; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bADCBulk then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; { if not bADCOpen then begin Result := ERROR_FILE_NOT_FOUND; Exit; end; } oADCWorker := ADCWorker; oADCContAcqWorker := ADCContAcqWorker; oADCContBufWorker := ADCContBufWorker; if ((oADCWorker <> nil) and (oADCWorker.BytesLeft <> 0)) or (oADCContAcqWorker <> nil) or (oADCContBufWorker <> nil) then begin Result := ERROR_TOO_MANY_OPEN_FILES; Exit; end; //GenericVendorWrite(DeviceIndex, AUR_SET_GPIF_MODE, 0, $0, 0, nil); BCData := $00000005; GenericVendorWrite(DeviceIndex, $BC, BufSize shr 17, BufSize shr 1, SizeOf(BCData), @BCData); ADCWorker := TADCWorker.Create(True); with ADCWorker do begin FreeOnTerminate := False; DI := DeviceIndex; TargetPipe := $86; BytesLeft := BufSize; pTar := pBuf; bAbort := False; Start; end; if oADCWorker <> nil then oADCWorker.Free; end; end; function ADC_BulkPoll(DeviceIndex: LongWord; var BytesLeft: LongWord): LongWord; cdecl; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bADCBulk then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if ADCWorker = nil then begin Result := ERROR_FILE_NOT_FOUND; Exit; end; if (WaitForSingleObject(ADCWorker.Handle, 0) = WAIT_OBJECT_0) and (ADCWorker.ReturnValue <> ERROR_SUCCESS) then begin Result := ADCWorker.ReturnValue; Exit; end; BytesLeft := ADCWorker.BytesLeft; end; end; function ADC_BulkAbort(DeviceIndex: LongWord): LongWord; cdecl; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bADCBulk then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if ADCWorker = nil then begin Result := ERROR_FILE_NOT_FOUND; Exit; end; if WaitForSingleObject(ADCWorker.Handle, 0) = WAIT_OBJECT_0 then Result := ADCWorker.ReturnValue else begin ADCWorker.bAbort := True; Result := ERROR_SUCCESS; end; end; end; function ADC_BulkMode(DeviceIndex, BulkMode: LongWord): LongWord; cdecl; var oADCWorker: TADCWorker; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bADCBulk then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; oADCWorker := ADCWorker; if (oADCWorker <> nil) and (oADCWorker.BytesLeft <> 0) then begin Result := ERROR_TOO_MANY_OPEN_FILES; Exit; end; BulkMode := BulkMode and $1; Result := GenericVendorWrite(DeviceIndex, AUR_SET_GPIF_MODE, 0, BulkMode, 0, nil); end; end; { TADCContAcqWorker } procedure TADCContAcqWorker.Execute; { function D4StartStop(D4Data: Byte): LongWord; begin Result := _GenericVendorWrite(DI, AUR_DEBUG_DEBUG, 0, $1F, SizeOf(D4Data), @D4Data); end; } function DoBCControl(TCSize: LongWord; ControlData: LongWord): LongWord; begin Result := _GenericVendorWrite(DI, $BC, TCSize shr 16, TCSize, SizeOf(ControlData), @ControlData); end; procedure DoErrOut(Status: LongWord); begin IOStatus := Status; ReturnValue := Status; ReleaseSemaphore(MyBufThread.hKillSem, 1, nil); ReleaseSemaphore(MyBufThread.hDataBufSem, 1, nil); end; var BytesLeft, DataSize, Status: LongWord; ThisBuf: PContBuf; begin SetThreadPriority(Handle, THREAD_PRIORITY_TIME_CRITICAL); IOStatus := ERROR_SUCCESS; //GenericVendorWrite(DI, AUR_SET_GPIF_MODE, 0, $1, 0, nil); DoBCControl(0, $01000007); { _GenericVendorWrite(DI, $BC, 0, 0, 0, nil); //_GenericVendorWrite(DI, $BC, $00AA, $AC00, 0, nil); D4StartStop($0); } while not Terminated do begin ThisBuf := MyBufThread.GetBlankBuf(0); ThisBuf.UsedSize := 0; Status := _GenericBulkIn(DI, TargetPipe, @ThisBuf.ADBuf[0], Length(ThisBuf.ADBuf), ThisBuf.UsedSize); if Status <> ERROR_SUCCESS then begin DoErrOut(Status); DoBCControl(0, $00020002); //D4StartStop($2); Exit; end; if ThisBuf.UsedSize <> 0 then MyBufThread.PutDataBuf(ThisBuf) else MyBufThread.PutBlankBuf(ThisBuf) ; end; DoBCControl(0, $00020002); //D4StartStop($2); repeat BytesLeft := 0; DataSize := SizeOf(BytesLeft); Status := _GenericVendorRead(DI, $BC, 0, 0, DataSize, @BytesLeft); if Status <> ERROR_SUCCESS then begin DoErrOut(Status); Exit; end; BytesLeft := BytesLeft and $0000FFFF; if BytesLeft = 0 then Break; ThisBuf := MyBufThread.GetBlankBuf(0); ThisBuf.UsedSize := 0; DataSize := Length(ThisBuf.ADBuf); if DataSize < BytesLeft then BytesLeft := DataSize; Status := _GenericBulkIn(DI, TargetPipe, @ThisBuf.ADBuf[0], BytesLeft, ThisBuf.UsedSize); if Status <> ERROR_SUCCESS then begin DoErrOut(Status); Exit; end; if ThisBuf.UsedSize <> 0 then MyBufThread.PutDataBuf(ThisBuf) else MyBufThread.PutBlankBuf(ThisBuf) ; until True;//`@ False; ReturnValue := ERROR_SUCCESS; end; { TADCContBufWorker } procedure TADCContBufWorker.Execute; var ThisBuf: PContBuf; begin repeat if Terminated then begin ReturnValue := ERROR_OPERATION_ABORTED; Exit; end; ThisBuf := GetDataBufOrKilled; if ThisBuf = nil then begin try Callback(nil, 0, CallbackFlag_EndStream, CallbackContext); except end; ReturnValue := ERROR_OPERATION_ABORTED; Exit; end; if (ThisBuf.UsedSize <> 0) or (ThisBuf.Flags <> 0) then try Callback(@ThisBuf.ADBuf[0], ThisBuf.UsedSize, ThisBuf.Flags, CallbackContext); except end; PutBlankBuf(ThisBuf); until False; ReturnValue := ERROR_SUCCESS; end; function TADCContBufWorker.ExtraBuf: PContBuf; var I: Integer; begin WaitForSingleObject(hBufMutex, INFINITE); I := Length(BufBuf); SetLength(BufBuf, I + 1); New(BufBuf[I]); Result := BufBuf[I]; SetLength(Result.ADBuf, BytesPerBuf); Result.BufState := bsAccessing; ReleaseMutex(hBufMutex); end; function TADCContBufWorker.GetBlankBuf(Flags: LongWord): PContBuf; var I: Integer; begin if WaitForSingleObject(hBlankBufSem, 0) = WAIT_TIMEOUT then begin Result := ExtraBuf; Result.Flags := CallbackFlag_Inserted or Flags; Exit; end; Result := nil; WaitForSingleObject(hBufMutex, INFINITE); for I := 0 to High(BufBuf) do if BufBuf[I].BufState = bsBlank then begin Result := BufBuf[I]; Result.Flags := Flags; Break; end ; ReleaseMutex(hBufMutex); if Result = nil then begin Result := ExtraBuf; //We have a semaphore to prevent this, so not likely to matter. Result.Flags := CallbackFlag_Inserted or Flags; end; end; function TADCContBufWorker.GetDataBufOrKilled: PContBuf; var I: Integer; begin repeat WaitForSingleObject(hDataBufSem, INFINITE); Result := nil; WaitForSingleObject(hBufMutex, INFINITE); for I := 0 to High(BufBuf) do if (BufBuf[I].BufState = bsGotData) and (BufBuf[I].Index = NextIndexOut) then begin Result := BufBuf[I]; Result.BufState := bsAccessing; Inc(NextIndexOut); Break; end ; ReleaseMutex(hBufMutex); if Result = nil then begin if WaitForSingleObject(hKillSem, 0) <> WAIT_TIMEOUT then Exit; end; until Result <> nil; //We have a semaphore to prevent this, so just go around again if it happens. end; procedure TADCContBufWorker.GetDebugStats(var Blanks, Accessings, GotDatas: LongWord); var I: Integer; iBlanks, iAccessings, iGotDatas: LongWord; begin iBlanks := 0; iAccessings := 0; iGotDatas := 0; WaitForSingleObject(hBufMutex, INFINITE); for I := 0 to High(BufBuf) do case BufBuf[I].BufState of bsBlank: Inc(iBlanks); bsAccessing: Inc(iAccessings); bsGotData: Inc(iGotDatas); end ; ReleaseMutex(hBufMutex); Blanks := iBlanks; Accessings := iAccessings; GotDatas := iGotDatas; end; procedure TADCContBufWorker.PutBlankBuf(pNewBuf: PContBuf); begin WaitForSingleObject(hBufMutex, INFINITE); pNewBuf.BufState := bsBlank; ReleaseMutex(hBufMutex); ReleaseSemaphore(hBlankBufSem, 1, nil); end; procedure TADCContBufWorker.PutDataBuf(pNewBuf: PContBuf); begin WaitForSingleObject(hBufMutex, INFINITE); pNewBuf.BufState := bsGotData; pNewBuf.Index := NextIndexIn; Inc(NextIndexIn); ReleaseMutex(hBufMutex); ReleaseSemaphore(hDataBufSem, 1, nil); end; { Done } function ADC_BulkContinuousCallbackStart(DeviceIndex: LongWord; BufSize: LongWord; BaseBufCount: LongWord; Context: LongWord; pCallback: Pointer): LongWord; cdecl; var oADCWorker: TADCWorker; oADCContAcqWorker: TADCContAcqWorker; oADCContBufWorker: TADCContBufWorker; I: Integer; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bADCBulk then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if (BufSize and $1FF) <> 0 then begin Result := ERROR_INVALID_USER_BUFFER; Exit; end; oADCWorker := ADCWorker; oADCContAcqWorker := ADCContAcqWorker; oADCContBufWorker := ADCContBufWorker; if ((oADCWorker <> nil) and (oADCWorker.BytesLeft <> 0)) or (oADCContAcqWorker <> nil) or (oADCContBufWorker <> nil) then begin Result := ERROR_TOO_MANY_OPEN_FILES; Exit; end; ADCContAcqWorker := TADCContAcqWorker.Create(True); ADCContBufWorker := TADCContBufWorker.Create(True); with ADCContBufWorker do begin FreeOnTerminate := False; MyAcqThread := ADCContAcqWorker; BytesPerBuf := BufSize; Callback := pCallback; CallbackContext := Context; hBufMutex := CreateMutex(nil, False, nil); hKillSem := CreateSemaphore(nil, 0, $FFFFFF, nil); hBlankBufSem := CreateSemaphore(nil, BaseBufCount, $FFFFFF, nil); hDataBufSem := CreateSemaphore(nil, 0, $FFFFFF, nil); SetLength(ADCContBufWorker.BufBuf, BaseBufCount); for I := 0 to BaseBufCount-1 do begin New(ADCContBufWorker.BufBuf[I]); SetLength(ADCContBufWorker.BufBuf[I].ADBuf, BufSize); ADCContBufWorker.BufBuf[I].BufState := bsBlank; end; Start; end; with ADCContAcqWorker do begin FreeOnTerminate := False; MyBufThread := ADCContBufWorker; DI := DeviceIndex; TargetPipe := $86; //BytesPerBC := BufSize * BaseBufCount; Start; end; if oADCWorker <> nil then oADCWorker.Free; end; except Result := ERROR_INTERNAL_ERROR; end; end; function ADC_BulkContinuousEnd(DeviceIndex: LongWord; pIOStatus: PLongWord): LongWord; cdecl; var oADCContAcqWorker: TADCContAcqWorker; oADCContBufWorker: TADCContBufWorker; I: Integer; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bADCBulk then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; oADCContAcqWorker := ADCContAcqWorker; oADCContBufWorker := ADCContBufWorker; ADCContAcqWorker := nil; ADCContBufWorker := nil; if (oADCContAcqWorker = nil) or (oADCContBufWorker = nil) then begin Result := ERROR_HANDLE_EOF; Exit; end; if pIOStatus <> nil then pIOStatus^ := oADCContAcqWorker.IOStatus; oADCContAcqWorker.Terminate; ReleaseSemaphore(oADCContBufWorker.hKillSem, 1, nil); ReleaseSemaphore(oADCContBufWorker.hDataBufSem, 1, nil); oADCContAcqWorker.WaitFor; oADCContBufWorker.WaitFor; CloseHandle(oADCContBufWorker.hBufMutex); CloseHandle(oADCContBufWorker.hKillSem); CloseHandle(oADCContBufWorker.hBlankBufSem); CloseHandle(oADCContBufWorker.hDataBufSem); for I := 0 to High(oADCContBufWorker.BufBuf) do begin Dispose(oADCContBufWorker.BufBuf[I]); end; SetLength(oADCContBufWorker.BufBuf, 0); oADCContAcqWorker.Free; oADCContBufWorker.Free; end; except Result := ERROR_INTERNAL_ERROR; end; end; function ADC_BulkContinuousDebug(DeviceIndex: LongWord; var Blanks, Accessings, GotDatas: LongWord): LongWord; cdecl; var oADCContAcqWorker: TADCContAcqWorker; oADCContBufWorker: TADCContBufWorker; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bADCBulk then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; oADCContAcqWorker := ADCContAcqWorker; oADCContBufWorker := ADCContBufWorker; if (oADCContAcqWorker = nil) or (oADCContBufWorker = nil) then begin Result := ERROR_HANDLE_EOF; Exit; end; oADCContBufWorker.GetDebugStats(Blanks, Accessings, GotDatas); end; except Result := ERROR_INTERNAL_ERROR; end; end; function ADC_GetImmediate(DeviceIndex, Channel: LongWord; pBuf: PWord): LongWord; cdecl; var L: LongWord; oADCWorker: TADCWorker; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bADCBulk then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; { if not bADCOpen then begin Result := ERROR_FILE_NOT_FOUND; Exit; end; } oADCWorker := ADCWorker; if (oADCWorker <> nil) and (oADCWorker.BytesLeft <> 0) then begin Result := ERROR_TOO_MANY_OPEN_FILES; Exit; end; try pBuf^ := $0000; //Probe buffer except Result := ERROR_NOACCESS; Exit; end; L := 0; Result := GenericVendorWrite(DeviceIndex, AUR_ADC_IMMEDIATE, 0, Channel, L, nil); end; end; type TTimeoutTriggerThread = class(TThread) public DI: Integer; TimeoutMS: LongInt; bTimeout: Boolean; protected procedure Execute; override; end; procedure TTimeoutTriggerThread.Execute; var StartTime, ThisTime, DeltaTime, TimeoutTime: Int64; L: LongWord; begin bTimeout := False; QueryPerformanceFrequency(TimeoutTime); TimeoutTime := (TimeoutTime * TimeoutMS) div 1000; QueryPerformanceCounter(StartTime); repeat Sleep(1); if Terminated then Break; QueryPerformanceCounter(ThisTime); DeltaTime := ThisTime - StartTime; if DeltaTime > TimeoutTime then begin L := 0; GenericVendorWrite(DI, AUR_ADC_IMMEDIATE, 0, 0, L, nil); bTimeout := True; Break; end; until False; end; function ADC_GetScan_Inner(var DeviceIndex: LongWord; var Config: array of Byte; var ADBuf: TWordArray; var StartChannel, EndChannel: Byte; TimeoutMS: LongInt): LongWord; var pADBuf: PByte; L, BytesLeft, TargetPipe, BCData: LongWord; Channels: Byte; I: Integer; TimeoutTriggerThread: TTimeoutTriggerThread; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; if Dev[DeviceIndex].bADCBulk then begin L := SizeOf(Config); ADC_GetConfig(DeviceIndex, @Config[0], L); if TimeoutMS <> 0 then Config[$11] := $04 or Config[$11] //Turn scan on. else Config[$11] := $04 or Config[$11] and not $03 //Turn scan on, turn timer and external trigger off. ; StartChannel := Config[$12] and $F; EndChannel := Config[$12] shr 4; if L >= 21 then begin StartChannel := StartChannel or ((Config[20] and $F) shl 4); EndChannel := EndChannel or (Config[20] and $F0); end; Channels := EndChannel - StartChannel + 1; Config[$13] := Max(1, Config[$13]); //Oversample at least +1. if Channels * (1 + Config[$13]) > 1024 then Config[$13] := (1024 div Channels) - 1; //Don't take more than the board can buffer, since we aren't threading. SetLength(ADBuf, Channels * (1 + Config[$13])); ADC_SetConfig(DeviceIndex, @Config[0], L); TargetPipe := $86; BytesLeft := SizeOf(ADBuf[0]) * Length(ADBuf); pADBuf := @ADBuf[0]; //GenericVendorWrite(DeviceIndex, AUR_SET_GPIF_MODE, 0, $0, 0, nil); BCData := $00000005; GenericVendorWrite(DeviceIndex, $BC, 0, Length(ADBuf), SizeOf(BCData), @BCData); if TimeoutMS <> 0 then begin //Spawn timeout-trigger thread. TimeoutTriggerThread := TTimeoutTriggerThread.Create(True); TimeoutTriggerThread.FreeOnTerminate := False; TimeoutTriggerThread.DI := DeviceIndex; TimeoutTriggerThread.TimeoutMS := TimeoutMS; TimeoutTriggerThread.Start; end else begin ADC_GetImmediate(DeviceIndex, 0, @ADBuf[0]); TimeoutTriggerThread := nil; end; repeat L := 0; Result := AWU_GenericBulkIn(DeviceIndex, TargetPipe, pADBuf, BytesLeft, L); if Result <> ERROR_SUCCESS then Break; Dec(BytesLeft, L); Inc(pADBuf, L); until BytesLeft <= 0; if TimeoutTriggerThread <> nil then begin //Tell timeout-trigger thread to not bother if it hasn't tripped yet. TimeoutTriggerThread.Terminate; //Report timeout if it did. if (Result = ERROR_SUCCESS) and TimeoutTriggerThread.bTimeout then Result := ERROR_TIMEOUT; //And clean up the thread. TimeoutTriggerThread.Free; end; end else if Dev[DeviceIndex].ImmADCs <> 0 then begin SetLength(ADBuf, Dev[DeviceIndex].ImmADCs); L := Dev[DeviceIndex].ImmADCs * 2; Result := GenericVendorRead(DeviceIndex, AUR_ADC_IMMEDIATE, 0, 0, L, @ADBuf[0]); StartChannel := 0; EndChannel := Dev[DeviceIndex].ImmADCs - 1; for I := 0 to 15 do Config[I] := $02; //0-5V Config[$13] := 0; end else begin Result := ERROR_BAD_TOKEN_TYPE; end; end; function ADC_GetScan(DeviceIndex: LongWord; pBuf: PWord): LongWord; cdecl; var Config: array[0..21] of Byte; ADBuf: TWordArray; I, Ch, J, Tot: Integer; StartChannel, EndChannel: Byte; begin Result := ADC_GetScan_Inner(DeviceIndex, Config, ADBuf, StartChannel, EndChannel, 0); if Result <> ERROR_SUCCESS then Exit; if Config[$13] <> 0 then begin I := 0; Inc(pBuf, StartChannel); for Ch := StartChannel to EndChannel do begin Tot := 0; for J := 1 to Config[$13] do Tot := Tot + ADBuf[I * (1 + Config[$13]) + J] ; pBuf^ := Round(Tot / Config[$13]); Inc(pBuf); Inc(I); end; end else begin I := 0; Inc(pBuf, StartChannel); for Ch := StartChannel to EndChannel do begin pBuf^ := ADBuf[I]; Inc(pBuf); Inc(I); end; end; end; function ADC_GetScanV(DeviceIndex: LongWord; pBuf: PDouble): LongWord; cdecl; var Config: array[0..21] of Byte; ADBuf: TWordArray; I, Ch, J, Tot: Integer; V: Double; StartChannel, EndChannel, RangeCode, RangeShift: Byte; begin Result := ADC_GetScan_Inner(DeviceIndex, Config, ADBuf, StartChannel, EndChannel, 0); if Result <> ERROR_SUCCESS then Exit; RangeShift := Dev[DeviceIndex].RangeShift; if Config[$13] <> 0 then begin I := 0; Inc(pBuf, StartChannel); for Ch := StartChannel to EndChannel do begin RangeCode := Config[Ch shr RangeShift]; Tot := 0; for J := 1 to Config[$13] do Tot := Tot + ADBuf[I * (1 + Config[$13]) + J] ; V := Tot / Config[$13] * (1 / 65536); if (RangeCode and 1) <> 0 then V := V * 2 - 1; if (RangeCode and 2) = 0 then V := V * 2; if (RangeCode and 4) = 0 then V := V * 5; pBuf^ := V; Inc(pBuf); Inc(I); end; end else begin I := 0; Inc(pBuf, StartChannel); for Ch := StartChannel to EndChannel do begin V := ADBuf[I] * (5 / 65536); pBuf^ := V; Inc(pBuf); Inc(I); end; end; end; function ADC_GetTrigScan(DeviceIndex: LongWord; pBuf: PWord; TimeoutMS: LongInt): LongWord; cdecl; var Config: array[0..21] of Byte; ADBuf: TWordArray; I, Ch, J, Tot: Integer; StartChannel, EndChannel: Byte; begin if TimeoutMS <= 0 then TimeoutMS := 1; Result := ADC_GetScan_Inner(DeviceIndex, Config, ADBuf, StartChannel, EndChannel, TimeoutMS); if Result <> ERROR_SUCCESS then Exit; if Config[$13] <> 0 then begin I := 0; Inc(pBuf, StartChannel); for Ch := StartChannel to EndChannel do begin Tot := 0; for J := 1 to Config[$13] do Tot := Tot + ADBuf[I * (1 + Config[$13]) + J] ; pBuf^ := Round(Tot / Config[$13]); Inc(pBuf); Inc(I); end; end else begin I := 0; Inc(pBuf, StartChannel); for Ch := StartChannel to EndChannel do begin pBuf^ := ADBuf[I]; Inc(pBuf); Inc(I); end; end; end; function ADC_GetTrigScanV(DeviceIndex: LongWord; pBuf: PDouble; TimeoutMS: LongInt): LongWord; cdecl; var Config: array[0..21] of Byte; ADBuf: TWordArray; I, Ch, J, Tot: Integer; V: Double; StartChannel, EndChannel, RangeCode, RangeShift: Byte; begin if TimeoutMS <= 0 then TimeoutMS := 1; Result := ADC_GetScan_Inner(DeviceIndex, Config, ADBuf, StartChannel, EndChannel, TimeoutMS); if (Result <> ERROR_SUCCESS) and (Result <> ERROR_TIMEOUT) then Exit; RangeShift := Dev[DeviceIndex].RangeShift; if Config[$13] <> 0 then begin I := 0; Inc(pBuf, StartChannel); for Ch := StartChannel to EndChannel do begin RangeCode := Config[Ch shr RangeShift]; Tot := 0; for J := 1 to Config[$13] do Tot := Tot + ADBuf[I * (1 + Config[$13]) + J] ; V := Tot / Config[$13] * (1 / 65536); if (RangeCode and 1) <> 0 then V := V * 2 - 1; if (RangeCode and 2) = 0 then V := V * 2; if (RangeCode and 4) = 0 then V := V * 5; pBuf^ := V; Inc(pBuf); Inc(I); end; end else begin I := 0; Inc(pBuf, StartChannel); for Ch := StartChannel to EndChannel do begin V := ADBuf[I] * (5 / 65536); pBuf^ := V; Inc(pBuf); Inc(I); end; end; end; function ADC_GetChannelV(DeviceIndex, ChannelIndex: LongWord; pBuf: PDouble): LongWord; cdecl; var ScanData: array of Double; I: Integer; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bADCBulk then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if ChannelIndex >= ADCMUXChannels then begin Result := ERROR_INVALID_INDEX; Exit; end; SetLength(ScanData, ADCMUXChannels); for I := 0 to ADCMUXChannels - 1 do ScanData[I] := NAN; Result := ADC_GetScanV(DeviceIndex, @ScanData[0]); if Result <> ERROR_SUCCESS then Exit; pBuf^ := ScanData[ChannelIndex]; end; end; function ADC_GetCalRefV(DeviceIndex, CalRefIndex: LongWord; var pRef: Double): LongWord; cdecl; var oConfig, nConfig: array of Byte; L: LongWord; bBip: Boolean; ADData: array of Double; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bADCBulk then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if ConfigBytes < 20 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; L := ConfigBytes; SetLength(oConfig, L); SetLength(nConfig, L); FillChar(oConfig[0], L, $00); FillChar(nConfig[0], L, $00); Result := ADC_GetConfig(DeviceIndex, @oConfig[0], L); if Result <> ERROR_SUCCESS then Exit; try bBip := (oConfig[$00] and 1) <> 0; //Select bip or unip ref based on how they've set channel 0. nConfig[$00] := oConfig[$00]; //Use their selected range. case CalRefIndex of 0: if bBip then //Lo ref. nConfig[$10] := $05 else nConfig[$10] := $01 ; 1: if bBip then //Hi ref. nConfig[$10] := $07 else nConfig[$10] := $03 ; else begin Result := ERROR_INVALID_INDEX; Exit; end; end; nConfig[$13] := $FF; //Max oversample, make sure we get a good read. nConfig[$12] := $00; //Scan one channel. if ConfigBytes > $14 then nConfig[$14] := $00; //Scan one channel. ADC_SetConfig(DeviceIndex, @nConfig[0], L); SetLength(ADData, ADCMUXChannels); Result := ADC_GetScanV(DeviceIndex, @ADData[0]); if Result <> ERROR_SUCCESS then Exit; finally L := ConfigBytes; ADC_SetConfig(DeviceIndex, @oConfig[0], L); SetLength(oConfig, 0); SetLength(nConfig, 0); end; pRef := ADData[0]; //Result := ERROR_SUCCESS; end; except Result := ERROR_INTERNAL_ERROR; end; end; function ADC_InitFastITScanV(DeviceIndex: LongWord): LongWord; cdecl; var I: Integer; L: LongWord; Dat: Byte; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bADCBulk then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if ConfigBytes < 20 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; SetLength(FastITConfig, ConfigBytes); SetLength(FastITBakConfig, ConfigBytes); L := ConfigBytes; Result := ADC_GetConfig(DeviceIndex, @FastITBakConfig[0], L); if Result <> ERROR_SUCCESS then Exit; for I := 0 to 15 do FastITConfig[I] := FastITBakConfig[I]; //Use their range codes. //FastITConfig[$11] := $04 or (FastITBakConfig[$11] and $10); //Software-start scan, use their CTR0 EXT bit. FastITConfig[$11] := $05 or (FastITBakConfig[$11] and $10); //Timer scan, use their CTR0 EXT bit. FastITConfig[$13] := Max(3, FastITBakConfig[$13]); //Oversample at least +3. Dat := Min(64, ADCMUXChannels) - 1; FastITConfig[$12] := Dat shl 4; FastITConfig[$14] := Dat and $F0; Result := ADC_SetConfig(DeviceIndex, @FastITConfig[0], L); if Result <> ERROR_SUCCESS then begin ADC_SetConfig(DeviceIndex, @FastITBakConfig[0], L); Exit; end; Dat := $01; Result := GenericVendorWrite(DeviceIndex, $D4, $1E, 0, SizeOf(Dat), @Dat); if Result <> ERROR_SUCCESS then ADC_SetConfig(DeviceIndex, @FastITBakConfig[0], L); end; except Result := ERROR_INTERNAL_ERROR; end; end; function ADC_ResetFastITScanV(DeviceIndex: LongWord): LongWord; cdecl; var L: LongWord; Dat: Byte; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bADCBulk then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if ConfigBytes < 20 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; L := Length(FastITBakConfig); Result := ADC_SetConfig(DeviceIndex, @FastITBakConfig[0], L); if Result <> ERROR_SUCCESS then Exit; Dat := $00; Result := GenericVendorWrite(DeviceIndex, $D4, $1E, 0, SizeOf(Dat), @Dat); end; except Result := ERROR_INTERNAL_ERROR; end; end; function ADC_SetFastITScanVChannels(DeviceIndex, NewChannels: LongWord): LongWord; cdecl; var L: LongWord; Dat: Byte; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bADCBulk then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if ConfigBytes < 20 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if Length(FastITConfig) < 20 then begin Result := ERROR_NOT_READY; Exit; end; L := Length(FastITConfig); Dat := Min(NewChannels, ADCMUXChannels) - 1; FastITConfig[$12] := Dat shl 4; FastITConfig[$14] := Dat and $F0; Result := ADC_SetConfig(DeviceIndex, @FastITConfig[0], L); end; except Result := ERROR_INTERNAL_ERROR; end; end; function ADC_GetFastITScanV(DeviceIndex: LongWord; pBuf: PDouble): LongWord; cdecl; var ADBuf: TWordArray; I, Ch, J, Tot, Wt: Integer; V: Double; StartChannel, EndChannel, Channels, RangeCode: Byte; //Dummy: Word; BytesLeft: LongWord; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bADCBulk then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if ConfigBytes < 20 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; //Determine channels. StartChannel := FastITConfig[$12] and $F; EndChannel := FastITConfig[$12] shr 4; if ConfigBytes >= 21 then begin StartChannel := StartChannel or ((FastITConfig[20] and $F) shl 4); EndChannel := EndChannel or (FastITConfig[20] and $F0); end; Channels := EndChannel - StartChannel + 1; //Set array to receive scan(=channels * (1+oversample)). SetLength(ADBuf, Channels * (1 + FastITConfig[$13])); //Begin get-data. Result := ADC_BulkAcquire(DeviceIndex, Length(ADBuf) * SizeOf(ADBuf[0]), @ADBuf[0]); if Result <> ERROR_SUCCESS then Exit; CTR_8254Mode(DeviceIndex, 0, 2, 0); CTR_8254Mode(DeviceIndex, 0, 2, 1); //ADC_GetImmediate(DeviceIndex, 0, @Dummy); //Complete get-data. if WaitForSingleObject(ADCWorker.Handle, 1000) <> WAIT_OBJECT_0 then begin Result := ERROR_TIMEOUT; Exit; end; Result := ADC_BulkPoll(DeviceIndex, BytesLeft); if Result <> ERROR_SUCCESS then Exit; if BytesLeft <> 0 then begin Result := ERROR_HANDLE_EOF; Exit; end; //Condition data; cull 75%(round down) of samples per channel from first block of channels, cull first from others, and average. I := 0; Inc(pBuf, StartChannel); for Ch := StartChannel to EndChannel do begin RangeCode := FastITConfig[Ch shr RangeShift]; Tot := 0; Wt := 0; if (Ch shr RangeShift) = 0 then J := 4 else J := 1; //Discard first 4 samples from first 8 channels, and first 1 sample from other channels. J := Min(J, FastITConfig[$13]); //Except always keep at least one sample. for J := J to FastITConfig[$13] do begin Tot := Tot + ADBuf[I * (1 + FastITConfig[$13]) + J]; Inc(Wt); end; V := Tot / Wt * (1 / 65536); if (RangeCode and 1) <> 0 then V := V * 2 - 1; if (RangeCode and 2) = 0 then V := V * 2; if (RangeCode and 4) = 0 then V := V * 5; pBuf^ := V; Inc(pBuf); Inc(I); end; end; except Result := ERROR_INTERNAL_ERROR; end; end; function ADC_GetITScanV(DeviceIndex: LongWord; pBuf: PDouble): LongWord; cdecl; begin try Result := ADC_InitFastITScanV(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := ADC_GetFastITScanV(DeviceIndex, pBuf); if Result <> ERROR_SUCCESS then begin ADC_ResetFastITScanV(DeviceIndex); Exit; end; Result := ADC_ResetFastITScanV(DeviceIndex); except Result := ERROR_INTERNAL_ERROR; end; end; function AIOUSB_OfflineWrite1(DeviceIndex: LongWord; SampleIndex: LongWord; Buf: Word): LongWord; cdecl; var Data: AnsiString; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; SetString(Data, PAnsiChar(@Buf), 2); Result := GenericVendorWrite(DeviceIndex, AUR_OFFLINE_READWRITE, SampleIndex, SampleIndex shr 16, Length(Data), PAnsiChar(Data)); end; function AIOUSB_OfflineRead1(DeviceIndex: LongWord; SampleIndex: LongWord; pBuf: PWord): LongWord; cdecl; var Buf: Word; L: LongWord; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin L := SizeOf(Buf); Result := GenericVendorRead(DeviceIndex, AUR_OFFLINE_READWRITE, SampleIndex, SampleIndex shr 16, L, @Buf); if Result = ERROR_SUCCESS then begin pBuf^ := Buf; end; end; end; function DIO_Configure(DeviceIndex: LongWord; Tristate: ByteBool; pOutMask: Pointer; pData: Pointer): LongWord; cdecl; var Content: AnsiString; Data, OutMask, COSMask: AnsiString; L: LongWord; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if DIOBytes = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if (pOutMask = nil) or (pData = nil) then begin Result := ERROR_INVALID_PARAMETER; Exit; end; SetString(Data, PAnsiChar(pData), DIOBytes); Move(Data[1], LastDIOData[0], DIOBytes); L := (DIOConfigBits + 7) div 8; SetString(OutMask, PAnsiChar(pOutMask), L); COSMask := StringOfChar(AnsiChar(#$00), L); Content := Data + OutMask + COSMask; Result := GenericVendorWrite(DeviceIndex, AUR_DIO_CONFIG, Ord(Tristate), 0, Length(Content), PAnsiChar(Content)); end; end; function DIO_ConfigureEx(DeviceIndex: LongWord; pOutMask: Pointer; pData: Pointer; pTristateMask: Pointer): LongWord; cdecl; var Content: AnsiString; Data, OutMask, TriMask: AnsiString; L: LongWord; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if (DIOBytes = 0) or (Tristates = 0) then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if (pOutMask = nil) or (pData = nil) or (pTristateMask = nil) then begin Result := ERROR_INVALID_PARAMETER; Exit; end; SetString(Data, PAnsiChar(pData), DIOBytes); Move(Data[1], LastDIOData[0], DIOBytes); L := (DIOConfigBits + 7) div 8; SetString(OutMask, PAnsiChar(pOutMask), L); L := (Tristates + 7) div 8; SetString(TriMask, PAnsiChar(pTristateMask), L); Content := Data + OutMask + TriMask; Result := GenericVendorWrite(DeviceIndex, AUR_DIO_CONFIG, 0, DIOBytes, Length(Content), PAnsiChar(Content)); end; end; function DIO_ConfigurationQuery(DeviceIndex: LongWord; pOutMask: Pointer; pTristateMask: Pointer): LongWord; cdecl; var Content: AnsiString; OutMask, TriMask: AnsiString; L, OutL, TriL: LongWord; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if (Tristates = 0) then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if (pOutMask = nil) or (pTristateMask = nil) then begin Result := ERROR_INVALID_PARAMETER; Exit; end; OutL := (DIOConfigBits + 7) div 8; TriL := (Tristates + 7) div 8; L := OutL + TriL; SetString(Content, nil, L); Result := GenericVendorRead(DeviceIndex, AUR_DIO_CONFIG_QUERY, 0, DIOBytes, L, PAnsiChar(Content)); //OutMask + TriMask := Content; OutMask := Copy(Content, 1, OutL); TriMask := Copy(Content, 1 + OutL, TriL); Move(OutMask[1], pOutMask^, OutL); Move(TriMask[1], pTristateMask^, TriL); end; end; function DIO_Write1(DeviceIndex, BitIndex: LongWord; Data: ByteBool): LongWord; cdecl; var ByteIndex: LongWord; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if DIOBytes = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; ByteIndex := BitIndex div 8; BitIndex := BitIndex and 7; if ByteIndex >= DIOBytes then begin Result := ERROR_INVALID_ADDRESS; Exit; end; if Data then LastDIOData[ByteIndex] := LastDIOData[ByteIndex] or (1 shl BitIndex) else LastDIOData[ByteIndex] := LastDIOData[ByteIndex] and not (1 shl BitIndex) ; Result := GenericVendorWrite(DeviceIndex, AUR_DIO_WRITE, 0, 0, DIOBytes, @LastDIOData[0]); end; except Result := ERROR_INTERNAL_ERROR; end; end; function DIO_Write8(DeviceIndex, ByteIndex: LongWord; Data: Byte): LongWord; cdecl; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if DIOBytes = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if ByteIndex >= DIOBytes then begin Result := ERROR_INVALID_ADDRESS; Exit; end; LastDIOData[ByteIndex] := Data; Result := GenericVendorWrite(DeviceIndex, AUR_DIO_WRITE, 0, 0, DIOBytes, @LastDIOData[0]); end; except Result := ERROR_INTERNAL_ERROR; end; end; function DIO_WriteAll(DeviceIndex: LongWord; pData: Pointer): LongWord; cdecl; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if DIOBytes = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; Move(pData^, LastDIOData[0], DIOBytes); Result := GenericVendorWrite(DeviceIndex, AUR_DIO_WRITE, 0, 0, DIOBytes, @LastDIOData[0]); end; except Result := ERROR_INTERNAL_ERROR; end; end; function DIO_Read1(DeviceIndex, BitIndex: LongWord; Buffer: PByte): LongWord; cdecl; var Content: AnsiString; L: LongWord; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if DIOBytes = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if BitIndex >= DIOBytes * 8 then begin Result := ERROR_INVALID_ADDRESS; Exit; end; L := DIOBytes; SetString(Content, nil, L); Result := GenericVendorRead(DeviceIndex, AUR_DIO_READ, 0, 0, L, PAnsiChar(Content)); if Result = ERROR_SUCCESS then begin if (Byte(Content[(BitIndex div 8) + 1]) and (1 shl (BitIndex mod 8))) <> 0 then Buffer^ := 1 else Buffer^ := 0 ; end; end; except Result := ERROR_INTERNAL_ERROR; end; end; function DIO_Read8(DeviceIndex, ByteIndex: LongWord; Buffer: PByte): LongWord; cdecl; var Content: AnsiString; L: LongWord; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if DIOBytes = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if ByteIndex >= DIOBytes then begin Result := ERROR_INVALID_ADDRESS; Exit; end; L := DIOBytes; SetString(Content, nil, L); Result := GenericVendorRead(DeviceIndex, AUR_DIO_READ, 0, 0, L, PAnsiChar(Content)); if Result = ERROR_SUCCESS then begin PAnsiChar(Buffer)^ := Content[ByteIndex + 1]; end; end; except Result := ERROR_INTERNAL_ERROR; end; end; function DIO_ReadAll(DeviceIndex: LongWord; pData: Pointer): LongWord; cdecl; var L: LongWord; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if DIOBytes = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; L := DIOBytes; Result := GenericVendorRead(DeviceIndex, AUR_DIO_READ, 0, 0, L, pData); end; except Result := ERROR_INTERNAL_ERROR; end; end; function DIO_SetWatchdog16(DeviceIndex: LongWord; Delay, Data: Word): LongWord; cdecl; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if DIOBytes = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; case PID of $8010, $8011, $8012, $8014, $8015, $8016: ; //USB-IIRO-16 family else begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; end; Result := GenericVendorWrite(DeviceIndex, AUR_DIO_WDG16_DEPREC, Delay, Data, 0, nil); end; end; function SetWatchdog(DeviceIndex: LongWord; var Delay: Double; pData: Pointer): LongWord; cdecl; var DV: Word; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if WDGBytes = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; DV := Max(1, Round(Delay)); Delay := DV; Result := GenericVendorWrite(DeviceIndex, AUR_WDG, 0, 0, WDGBytes, pData); end; end; function DIO_StreamOpen(DeviceIndex: LongWord; bIsRead: LongBool): LongWord; cdecl; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bDIOStream then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if bDIOOpen then begin Result := ERROR_TOO_MANY_OPEN_FILES; Exit; end; bDIOOpen := True; //Result := DoSetIFace(Handle, $100); //if Result <> ERROR_SUCCESS then Exit; if bIsRead then begin bDIORead := True; Result := GenericVendorWrite(DeviceIndex, $BC, 0, 0, 0, nil); end else begin bDIORead := False; Result := GenericVendorWrite(DeviceIndex, $BB, 0, 0, 0, nil); end; end; end; function WordAsStr(W: Word): AnsiString; begin SetString(Result, PAnsiChar(@W), 2); end; function OctDacFromFreq(var ClockHz: Double): Word; var Octave, Offset: Integer; begin if ClockHz = 0 then begin Result := 0; Exit; end; if ClockHz > 40000000 then ClockHz := 40000000; //if ClockHz > 66000000 then ClockHz := 66000000; Octave := Floor(3.322 * Log10(ClockHz / 1039)); if Octave < 0 then begin //Don't bother with upper limit, we already covered it and then some above. Octave := 0; Offset := 0; Result := $0000; end else begin Offset := Round(2048 - (LDExp(2078, 10 + Octave)/ClockHz)); //Don't bother with limits, we covered that when calculating the octave. Result := (Octave shl 12) or (Offset shl 2); Result := MotorolaWord(Result); end; ClockHz := (2078 shl Octave) / (2 - Offset / 1024); end; function DIO_StreamSetClocks(DeviceIndex: LongWord; var ReadClockHz, WriteClockHz: Double): LongWord; cdecl; var Content: AnsiString; pDB: PByte; pDW: PWord absolute pDB; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bDIOStream then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; { if not bDIOOpen then begin Result := ERROR_FILE_NOT_FOUND; Exit; end; } SetString(Content, nil, 5); pDB := PByte(PAnsiChar(Content)); pDB^ := $00; if WriteClockHz = 0 then Inc(pDB^, 1); if ReadClockHz = 0 then Inc(pDB^, 2); Inc(pDB); pDW^ := OctDacFromFreq(WriteClockHz); Inc(pDW); pDW^ := OctDacFromFreq(ReadClockHz); { SetString(Content, nil, SizeOf(TVendorRequestData)); pVRD.Request := AUR_DIO_SETCLOCKS; pVRD.Value := 0; pVRD.Index := 0; Content := Content + #$02 + WordAsStr(OctDacFromFreq(WriteClockHz)) + WordAsStr(OctDacFromFreq(WriteClockHz)); } Result := GenericVendorWrite(DeviceIndex, AUR_DIO_SETCLOCKS, 0, 0, Length(Content), PAnsiChar(Content)); end; end; function DIO_StreamClose(DeviceIndex: LongWord): LongWord; cdecl; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bDIOStream then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if not bDIOOpen then begin Result := ERROR_FILE_NOT_FOUND; Exit; end; bDIOOpen := False; Result := ERROR_SUCCESS; end; end; function DIO_StreamFrame(DeviceIndex, FramePoints: LongWord; pFrameData: PWord; var BytesTransferred: LongWord): LongWord; cdecl; var TargetPipe: Word; L: LongWord; begin try BytesTransferred := 0; Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bDIOStream then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if not bDIOOpen then begin Result := ERROR_FILE_NOT_FOUND; Exit; end; if FramePoints <= 0 then begin Result := ERROR_INVALID_PARAMETER; Exit; end; Result := ERROR_SUCCESS; if bDIORead then begin TargetPipe := $86; while FramePoints > StreamingBlockSize do begin L := 0; Result := _GenericBulkIn(DeviceIndex, TargetPipe, pFrameData, StreamingBlockSize * 2, L); if L < StreamingBlockSize * 2 then Result := ERROR_HANDLE_EOF; BytesTransferred := BytesTransferred + L; if Result <> ERROR_SUCCESS then Break; Inc(pFrameData, StreamingBlockSize); Dec(FramePoints, StreamingBlockSize); end; if (Result = ERROR_SUCCESS) and (FramePoints <> 0) then begin L := 0; Result := _GenericBulkIn(DeviceIndex, TargetPipe, pFrameData, FramePoints * 2, L); if Result = ERROR_SUCCESS then BytesTransferred := BytesTransferred + L; end; end else begin TargetPipe := $02; while FramePoints > StreamingBlockSize do begin L := 0; Result := AWU_GenericBulkOut(DeviceIndex, TargetPipe, pFrameData, StreamingBlockSize * 2, L); if L < StreamingBlockSize * 2 then Result := ERROR_HANDLE_EOF; BytesTransferred := BytesTransferred + L; if Result <> ERROR_SUCCESS then Break; Inc(pFrameData, StreamingBlockSize); Dec(FramePoints, StreamingBlockSize); end; if (Result = ERROR_SUCCESS) and (FramePoints <> 0) then begin L := 0; Result := AWU_GenericBulkOut(DeviceIndex, TargetPipe, pFrameData, FramePoints * 2, L); if Result = ERROR_SUCCESS then BytesTransferred := BytesTransferred + L; end; end; end; except Result := ERROR_INTERNAL_ERROR; end; end; { function DIO_StreamFrameAsync(DeviceIndex, FramePoints: LongWord; pFrameData: PWord): LongWord; cdecl; var TargetPipe: Word; MyIOCTL: LongWord; //MyRequest: Byte; L: LongWord; Suc: Boolean; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bDIOStream then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if not bDIOOpen then begin Result := ERROR_FILE_NOT_FOUND; Exit; end; if FramePoints <= 0 then begin Result := ERROR_INVALID_PARAMETER; Exit; end; if bDIORead then begin TargetPipe := 2; MyIOCTL := IOCTL_BulkIn; //MyRequest := $BC; end else begin TargetPipe := 0; MyIOCTL := IOCTL_BulkOut; //MyRequest := $BB; end; Suc := DeviceIoControl(Handle, MyIOCTL, @TargetPipe, 2, pFrameData, FramePoints * 2, L, nil); if Suc then Result := ERROR_SUCCESS else Result := GetMappedFailure(DeviceIndex) ; end; end; function DIO_StreamFrameSync(DeviceIndex: LongWord; var FramePoints: LongWord; pFrameData: PWord): LongWord; cdecl; var TargetPipe: Word; MyIOCTL: LongWord; //MyRequest: Byte; L: LongWord; Suc: Boolean; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bDIOStream then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if not bDIOOpen then begin Result := ERROR_FILE_NOT_FOUND; Exit; end; if FramePoints <= 0 then begin Result := ERROR_INVALID_PARAMETER; Exit; end; if bDIORead then begin TargetPipe := 2; MyIOCTL := IOCTL_BulkIn; //MyRequest := $BC; end else begin TargetPipe := 0; MyIOCTL := IOCTL_BulkOut; //MyRequest := $BB; end; Suc := DeviceIoControl(Handle, MyIOCTL, @TargetPipe, 2, pFrameData, FramePoints * 2, L, nil); if Suc then begin FramePoints := L div 2; Result := ERROR_SUCCESS; end else Result := GetMappedFailure(DeviceIndex) ; end; end; } const FDD_Input = $00000001; FDD_Output = $00000010; FDD_ = $00000011; FDM_HandshakeAuto = $00000100; FDM_HandshakeSlave = $00001000; FDM_HandshakeForcedMaster = $00010000; FDM_ = $00011100; function DIO_16A_SetFunctionDirection(DeviceIndex, DIOStreaming, SPIBus, DIOA, DIOB, DIOCH: LongWord): LongWord; cdecl; begin //`@ Result := ERROR_NOT_SUPPORTED; end; function MapCounterBlock(DeviceIndex: LongWord; var CounterIndex, BlockIndex: LongWord): LongWord; begin Result := ERROR_SUCCESS; if BlockIndex = 0 then begin //Contiguous counter addressing BlockIndex := CounterIndex div 3; CounterIndex := CounterIndex mod 3; if BlockIndex >= Dev[DeviceIndex].Counters then Result := ERROR_INVALID_ADDRESS ; end else begin if (BlockIndex >= Dev[DeviceIndex].Counters) or (CounterIndex >= 3) then Result := ERROR_INVALID_ADDRESS ; end; end; function CTR_8254Mode(DeviceIndex, BlockIndex, CounterIndex, Mode: LongWord): LongWord; cdecl; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if Counters = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; Result := MapCounterBlock(DeviceIndex, CounterIndex, BlockIndex); if Result <> ERROR_SUCCESS then Exit; if Mode >= 6 then begin Result := ERROR_INVALID_ADDRESS; Exit; end; Mode := (CounterIndex shl 6) or (Mode shl 1) or $30; Result := GenericVendorWrite(DeviceIndex, AUR_CTR_MODE, BlockIndex or (Mode shl 8), 0, 0, nil); end; end; function CTR_8254Load(DeviceIndex, BlockIndex, CounterIndex: LongWord; LoadValue: Word): LongWord; cdecl; var Mode: Byte; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if Counters = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; Result := MapCounterBlock(DeviceIndex, CounterIndex, BlockIndex); if Result <> ERROR_SUCCESS then Exit; Mode := (CounterIndex shl 6) //or (Mode shl 1) or $30 ; Result := GenericVendorWrite(DeviceIndex, AUR_CTR_LOAD, BlockIndex or (Mode shl 8), LoadValue, 0, nil); end; end; function CTR_8254ModeLoad(DeviceIndex, BlockIndex, CounterIndex, Mode: LongWord; LoadValue: Word): LongWord; cdecl; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if Counters = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; Result := MapCounterBlock(DeviceIndex, CounterIndex, BlockIndex); if Result <> ERROR_SUCCESS then Exit; if Mode >= 6 then begin Result := ERROR_INVALID_ADDRESS; Exit; end; Mode := (CounterIndex shl 6) or (Mode shl 1) or $30; Result := GenericVendorWrite(DeviceIndex, AUR_CTR_MODELOAD, BlockIndex or (Mode shl 8), LoadValue, 0, nil); end; except Result := ERROR_INTERNAL_ERROR; end; end; function CTR_8254ReadModeLoad(DeviceIndex, BlockIndex, CounterIndex, Mode: LongWord; LoadValue: Word; pReadValue: PWord): LongWord; cdecl; var L: LongWord; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if Counters = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; Result := MapCounterBlock(DeviceIndex, CounterIndex, BlockIndex); if Result <> ERROR_SUCCESS then Exit; if Mode >= 6 then begin Result := ERROR_INVALID_ADDRESS; Exit; end; Mode := (CounterIndex shl 6) or (Mode shl 1) or $30; L := 2; Result := GenericVendorRead(DeviceIndex, AUR_CTR_MODELOAD, BlockIndex or (Mode shl 8), LoadValue, L, pReadValue); end; end; function CTR_8254Read(DeviceIndex, BlockIndex, CounterIndex: LongWord; pReadValue: PWord): LongWord; cdecl; var L: LongWord; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if Counters = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; Result := MapCounterBlock(DeviceIndex, CounterIndex, BlockIndex); if Result <> ERROR_SUCCESS then Exit; L := 2; Result := GenericVendorRead(DeviceIndex, AUR_CTR_READ, BlockIndex or (CounterIndex shl 8), 0, L, pReadValue); end; end; function CTR_8254ReadStatus(DeviceIndex, BlockIndex, CounterIndex: LongWord; pReadValue: PWord; pStatus: PByte): LongWord; cdecl; var Content: AnsiString; L: LongWord; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if Counters = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; Result := MapCounterBlock(DeviceIndex, CounterIndex, BlockIndex); if Result <> ERROR_SUCCESS then Exit; L := 3; SetString(Content, nil, L); Result := GenericVendorRead(DeviceIndex, AUR_CTR_READ, BlockIndex or (CounterIndex shl 8), 0, L, PAnsiChar(Content)); pReadValue^ := PWord(@Content[1])^; pStatus^ := PByte(@Content[3])^; end; end; { function CTR_8254ModeLoadAll(DeviceIndex: LongWord; pModes: PByte; pLoadValues: PWord): LongWord; cdecl; var Buf: AnsiString; I: Integer; Mode: Byte; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if Counters < 15 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; SetLength(Buf, 3*15); for I := 0 to 14 do begin Mode := pModes^; if Mode >= 6 then begin Result := ERROR_INVALID_ADDRESS; Exit; end; Mode := (CounterIndex shl 6) or (Mode shl 1) or $30; Buf[3 * I + 1] := AnsiChar(Mode); PWord(@Buf[3 * I + 2])^ := pLoadValues^; Inc(pModes); Inc(pLoadValues); end; Result := GenericVendorWrite(DeviceIndex, AUR_CTR_MODELOAD, 0, LoadValue, 0, nil); end; except Result := ERROR_INTERNAL_ERROR; end; end; } function CTR_8254ReadAll(DeviceIndex: LongWord; pData: PWord): LongWord; cdecl; var L: LongWord; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if Counters = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; L := Counters * 3 * 2; Result := GenericVendorRead(DeviceIndex, AUR_CTR_READALL, 0, 0, L, pData); end; end; function CTR_8254ReadLatched(DeviceIndex: LongWord; pData: PWord): LongWord; cdecl; var L: LongWord; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if Counters = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; L := Counters * 3 * 2 + 1; Result := GenericVendorRead(DeviceIndex, AUR_CTR_READLATCHED, 0, 0, L, pData); end; end; function CTR_8254SelectGate(DeviceIndex, GateIndex: LongWord): LongWord; cdecl; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if Counters = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if not bGateSelectable then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if GateIndex >= Counters * 3 then begin Result := ERROR_INVALID_ADDRESS; Exit; end; Result := GenericVendorWrite(DeviceIndex, AUR_CTR_SELGATE, GateIndex, 0, 0, nil); end; end; function CTR_StartOutputFreq(DeviceIndex, BlockIndex: LongWord; pHz: PDouble): LongWord; cdecl; var L, DivisorA, DivisorB: LongWord; DivisorAB: Extended; Err, MinErr, Hz: Double; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if Counters = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if BlockIndex >= Counters then begin Result := ERROR_INVALID_ADDRESS; Exit; end; if pHz = nil then begin Result := ERROR_INVALID_PARAMETER; Exit; end; Hz := pHz^; if Hz <= 0 then begin CTR_8254Mode(DeviceIndex, BlockIndex, 1, 2); Result := CTR_8254Mode(DeviceIndex, BlockIndex, 2, 3); end else begin if Hz * 4 >= RootClock then begin DivisorA := 2; DivisorB := 2; end else begin DivisorAB := RootClock / Hz; L := Round(SqRt(DivisorAB)); DivisorA := Round(DivisorAB / L); DivisorB := L; MinErr := Abs(Hz - (RootClock / (DivisorA * L))); for L := L downto 2 do begin DivisorA := Round(DivisorAB / L); if DivisorA > $FFFF then Break; //Limited to 16 bits, so this and all further L are invalid. Err := Abs(Hz - (RootClock / (DivisorA * L))); if Err = 0 then begin DivisorB := L; Break; end; if Err < MinErr then begin DivisorB := L; MinErr := Err; end; end; DivisorA := Round(DivisorAB / DivisorB); end; //LastPurpose := AUR_CTR_PUR_OFRQ; pHz^ := RootClock / (DivisorA * DivisorB); CTR_8254ModeLoad(DeviceIndex, BlockIndex, 1, 2, DivisorA); Result := CTR_8254ModeLoad(DeviceIndex, BlockIndex, 2, 3, DivisorB); end; end; end; function CTR_SetWaitGates(DeviceIndex: LongWord; A, B: Byte): LongWord; cdecl; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if Counters = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if not bGateSelectable then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if A >= Counters * 3 then begin Result := ERROR_INVALID_ADDRESS; Exit; end; if B >= Counters * 3 then begin Result := ERROR_INVALID_ADDRESS; Exit; end; //DoSetIFace(Handle, $100); Result := GenericVendorWrite(DeviceIndex, AUR_CTR_COS_BULK_GATE2, 0, A or (B shl 8), 0, nil); end; end; function CTR_EndWaitGates(DeviceIndex: LongWord): LongWord; cdecl; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if Counters = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if not bGateSelectable then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; Result := GenericVendorWrite(DeviceIndex, AUR_CTR_COS_BULK_ABORT, 0, 0, 0, nil); end; end; function CTR_WaitForGate(DeviceIndex: LongWord; GateIndex: Byte; var Content: Word): LongWord; cdecl; var TargetPipe: LongWord; L: LongWord; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if Counters = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if not bGateSelectable then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; case GateIndex of 0: TargetPipe := $82; 1: TargetPipe := $86; else begin Result := ERROR_INVALID_ADDRESS; Exit; end; end; L := 0; Result := AWU_GenericBulkIn(DeviceIndex, TargetPipe, @Content, SizeOf(Content), L); end; end; procedure TCtrMonitorThread.Execute; var ReadingsA, ReadingsB: array of Word; I, L: Integer; bA: Boolean; begin L := Length(MeasuredPulseWidth); SetLength(ReadingsA, L); SetLength(ReadingsB, L); CTR_8254ReadAll(DI, @ReadingsB[0]); bA := True; repeat if bA then CTR_8254ReadAll(DI, @ReadingsA[0]) else CTR_8254ReadAll(DI, @ReadingsB[0]) ; bA := not bA; WaitForSingleObject(hListMutex, INFINITE); for I := 0 to L - 1 do if ReadingsA[I] = ReadingsB[I] then MeasuredPulseWidth[I] := ReadingsA[I] ; ReleaseMutex(hListMutex); until Terminated; CloseHandle(hListMutex); end; function CTR_StartMeasuringPulseWidth(DeviceIndex: LongWord): LongWord; cdecl; var I: Integer; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if Counters = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if CtrMonitorThread <> nil then CTR_StopMeasuringPulseWidth(DeviceIndex); CtrMonitorThread := nil; try CtrMonitorThread := TCtrMonitorThread.Create(True); with CtrMonitorThread do begin DI := DeviceIndex; hListMutex := CreateMutex(nil, False, nil); SetLength(MeasuredPulseWidth, Counters * 3); for I := 0 to High(MeasuredPulseWidth) do MeasuredPulseWidth[I] := 0; Start; end; Result := ERROR_SUCCESS; except Result := ERROR_INTERNAL_ERROR; FreeAndNil(CtrMonitorThread); end; end; end; function CTR_StopMeasuringPulseWidth(DeviceIndex: LongWord): LongWord; cdecl; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if Counters = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if CtrMonitorThread = nil then begin Result := ERROR_FILE_NOT_FOUND; Exit; end; FreeAndNil(CtrMonitorThread); Result := ERROR_SUCCESS; end; end; function CTR_GetPulseWidthMeasurement(DeviceIndex, BlockIndex, CounterIndex: LongWord; pReadValue: PWord): LongWord; cdecl; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if Counters = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; Result := MapCounterBlock(DeviceIndex, CounterIndex, BlockIndex); if Result <> ERROR_SUCCESS then Exit; if CtrMonitorThread = nil then begin Result := ERROR_FILE_NOT_FOUND; Exit; end; try pReadValue^ := 0; try WaitForSingleObject(CtrMonitorThread.hListMutex, INFINITE); pReadValue^ := CtrMonitorThread.MeasuredPulseWidth[BlockIndex * 3 + CounterIndex]; CtrMonitorThread.MeasuredPulseWidth[BlockIndex * 3 + CounterIndex] := 0; ReleaseMutex(CtrMonitorThread.hListMutex); if pReadValue^ = 0 then Result := ERROR_NO_DATA_DETECTED else Result := ERROR_SUCCESS ; except Result := ERROR_INTERNAL_ERROR; end; except Result := ERROR_NOACCESS; end; end; end; function DIO_SPI_Write(DeviceIndex: LongWord; Address, Reg, Value: Byte): LongWord; cdecl; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bDIOSPI then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; Result := GenericVendorWrite(DeviceIndex, AUR_DIO_SPI_WRITE, Value, Reg or (Address shl 8), 0, nil); end; end; function DIO_SPI_Read(DeviceIndex: LongWord; Address, Reg: Byte; pValue: PByte): LongWord; cdecl; var ReadValue: Byte; L: LongWord; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bDIOSPI then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; L := SizeOf(ReadValue); Result := GenericVendorRead(DeviceIndex, AUR_DIO_SPI_READ, 0, Reg or (Address shl 8), L, @ReadValue); if Result = ERROR_SUCCESS then pValue^ := ReadValue; end; end; function AIOUSB_ClearFIFO(DeviceIndex: LongWord; TimeMethod: LongWord): LongWord; cdecl; var Req: Byte; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bClearFIFO then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; case TimeMethod of 0: Req := AUR_GEN_CLEAR_FIFO; 1: Req := AUR_GEN_CLEAR_FIFO_NEXT; 5: Req := AUR_GEN_ABORT_AND_CLEAR; 86: Req := AUR_GEN_CLEAR_FIFO_WAIT; else begin Result := ERROR_INVALID_PARAMETER; Exit; end; end; Result := GenericVendorWrite(DeviceIndex, Req, 0, 0, 0, nil); end; end; function AIOUSB_GetStreamStatus(DeviceIndex: LongWord; var Status: LongWord): LongWord; cdecl; var L: LongWord; ReadValue: LongWord; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bClearFIFO then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; L := SizeOf(ReadValue); Result := GenericVendorRead(DeviceIndex, AUR_GEN_STREAM_STATUS, 0, 0, L, @ReadValue); if Result = ERROR_SUCCESS then Status := ReadValue; end; end; function AIOUSB_SetStreamingBlockSize(DeviceIndex, BlockSize: LongWord): LongWord; cdecl; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not (bDIOStream or bADCBulk) then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if (BlockSize = 0) or (BlockSize > 31*1024*1024) then begin Result := ERROR_INVALID_PARAMETER; Exit; end; if bADCBulk then begin if (BlockSize and $1FF) <> 0 then BlockSize := (BlockSize and $FFFFFE00) + $200 else BlockSize := (BlockSize and $FFFFFE00) ; end; if bDIOStream then begin if (BlockSize and $FF) <> 0 then BlockSize := (BlockSize and $FFFFFF00) + $100 else BlockSize := (BlockSize and $FFFFFF00) ; end; StreamingBlockSize := BlockSize; Result := ERROR_SUCCESS; end; end; function AIOUSB_ResetChip(DeviceIndex: LongWord): LongWord; cdecl; var CPUCSByte: Byte; begin try //Put CPU into reset CPUCSByte := $01; Result := GenericVendorWrite(DeviceIndex, $A0, $E600, 0, 1, @CPUCSByte); if Result <> ERROR_SUCCESS then Exit; //take CPU out of reset CPUCSByte := $00; Result := GenericVendorWrite(DeviceIndex, $A0, $E600, 0, 1, @CPUCSByte); except Result := ERROR_INTERNAL_ERROR; end; end; function IsHex(S: AnsiString): Boolean; var I: Integer; begin Result := False; for I := 1 to Length(S) do if not (S[I] in ['0'..'9', 'A'..'F']) then Exit ; Result := True; end; function HexToNybble(Hex: AnsiChar): Byte; begin case Hex of '0'..'9': Result := Byte(Hex) - Byte('0'); 'A'..'F': Result := Byte(Hex) - Byte('A') + 10; 'a'..'f': Result := Byte(Hex) - Byte('a') + 10; else raise Exception.CreateFmt('Invalid hex character "%s"', [ Hex ]); end; end; function HexToStr(Hex: AnsiString): AnsiString; var I: Integer; begin SetString(Result, nil, (Length(Hex) + 1) div 2); for I := Length(Result) downto 1 do Result[I] := AnsiChar(HexToNybble(Hex[I * 2]) + HexToNybble(Hex[I * 2 - 1]) shl 4) ; end; function AIOUSB_UploadFirmware(DeviceIndex: LongWord; FirmBuf: PAnsiChar; BufLen: LongWord): LongWord; cdecl; { var Buf, Addr: AnsiString; Content: TStringList; I, J: Integer; //L: Integer; //pBuf: PAnsiChar; //cbRet: LongWord; CPUCSByte: Byte; Addr16: Word; } begin Result := ERROR_NOT_SUPPORTED; (* try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if bDACOpen or bDIOOpen then begin Result := ERROR_FILE_EXISTS; Exit; end; Content := TStringList.Create; try SetString(Buf, FirmBuf, BufLen); Content.Text := UpperCase(Buf); Content.Delete(Content.Count - 1); //Validate hex file (one validation step is also performed later) Result := ERROR_INVALID_DATA; for I := 0 to Content.Count - 1 do begin Buf := Content[I]; if Length(Buf) = 0 then Exit; if Buf[1] <> ':' then Exit; Buf := Copy(Buf, 2, MAXINT); if not IsHex(Buf) then Exit; end; J := Content.Count - 1; for I := 0 to J do begin Buf := Content[I]; Addr := Copy(Buf, 4, 4); Buf := Copy(Buf, 10, Length(Buf) - 11); if (Length(Buf) and 1) <> 0 then Exit; //If source file has extra nybble, reject as invalid try Buf := HexToStr(Addr + Buf); except Exit; end; Content[I] := Buf; end; //Data is valid, let's be optimistic about the tranfer process Result := ERROR_SUCCESS; //Put CPU into reset CPUCSByte := $01; Result := GenericVendorWrite(DeviceIndex, $A0, $E600, 0, 1, @CPUCSByte); if Result <> ERROR_SUCCESS then Exit; for I := 0 to J do begin Buf := Content[I]; Addr16 := MotorolaWord(PWord(PAnsiChar(Buf))^); Buf := Copy(Buf, 3, MAXINT); GenericVendorWrite(DeviceIndex, $A0, Addr16, 0, Length(Buf), PAnsiChar(Buf)); end; //take CPU out of reset CPUCSByte := $00; GenericVendorWrite(DeviceIndex, $A0, $E600, 0, 1, @CPUCSByte); //It has probably just disappeared, so close the connections AIOUSB_CloseDevice(DeviceIndex); bOpen := False; bDACOpen := False; bDACClosing := False; { L := 0; for I := 0 to J do L := L + Length(Content[I]) ; SetString(Buf, nil, L + 1); pBuf := PAnsiChar(Buf); for I := 0 to J do begin Addr := Content[I]; L := Length(Addr); Move(Addr[1], pBuf^, L); Inc(pBuf, L); end; pBuf^ := #0; //Null-terminate buffer, for LoadFirmware in .SYS } finally Content.Free; end; { if not DeviceIoControl(Handle, IOCTL_AIOUSB_UPLOAD, PAnsiChar(Buf), Length(Buf), nil, 0, cbRet, nil) then Result := ERROR_SUCCESS else begin ThisHandle := nil; Result := GetMappedFailure(DeviceIndex); end; } end; except Result := ERROR_INTERNAL_ERROR; end; *) end; function DIO_CSA_DoSync(DeviceIndex: LongWord; var BaseRateHz, DurAms, DurBms, DurCms: Double): LongWord; cdecl; const RootSyncClock = 3000; var Divisor, DurATicks, DurBTicks, DurCTicks: Integer; Value, Index: Word; begin Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if not bSetCustomClocks then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; if BaseRateHz < (RootSyncClock/255.5) then Divisor := 0 else if BaseRateHz >= RootSyncClock then Divisor := 1 else Divisor := Min($FF, Round(RootSyncClock / BaseRateHz)) ; if Divisor = 0 then begin BaseRateHz := 0; DurATicks := 0; DurAms := 0; DurBTicks := 0; DurBms := 0; DurCTicks := 0; DurCms := 0; end else begin BaseRateHz := RootSyncClock / Divisor; DurATicks := Min($FF, Round(3 * DurAms)); DurAms := 1/3 * DurATicks; DurBTicks := Min($FF, Round(3 * DurBms)); DurBms := 1/3 * DurBTicks; DurCTicks := Min($FF, Round(3 * DurCms)); DurCms := 1/3 * DurCTicks; end; Value := Divisor or (DurATicks shl 8); Index := DurBTicks or (DurCTicks shl 8); Result := GenericVendorWrite(DeviceIndex, AUR_SET_CUSTOM_CLOCKS, Value, Index, 0, nil); end; end; function DIO_CSA_DebounceSet(DeviceIndex, DebounceCounts: LongWord): LongWord; cdecl; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if (DIOBytes = 0) or not bDIODebounce then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; Result := GenericVendorWrite(DeviceIndex, AUR_DIO_ADVANCED, DebounceCounts, $100, 0, nil); end; except Result := ERROR_INTERNAL_ERROR; end; end; function DIO_CSA_DebounceReadAll(DeviceIndex: LongWord; pData: Pointer): LongWord; cdecl; var L: LongWord; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; with Dev[DeviceIndex] do begin if (DIOBytes = 0) or not bDIODebounce then begin Result := ERROR_BAD_TOKEN_TYPE; Exit; end; L := DIOBytes * 2; Result := GenericVendorRead(DeviceIndex, AUR_DIO_ADVANCED, 0, $101, L, pData); end; except Result := ERROR_INTERNAL_ERROR; end; end; function DAC_CSA_SetRangeLimits(DeviceIndex: LongWord; pData: Pointer): LongWord; cdecl; var InterBuf: AnsiString; begin try SetString(InterBuf, PAnsiChar(pData), 32); except Result := ERROR_NOACCESS; Exit; end; InterBuf := #1 + InterBuf; Result := GenericVendorWrite(DeviceIndex, $A2, $1D00, 0, Length(InterBuf), PAnsiChar(InterBuf)); InterBuf := ''; end; function DAC_CSA_ClearRangeLimits(DeviceIndex: LongWord): LongWord; cdecl; var InterBuf: AnsiString; begin InterBuf := #0; Result := GenericVendorWrite(DeviceIndex, $A2, $1D00, 0, Length(InterBuf), PAnsiChar(InterBuf)); InterBuf := ''; end; function DIO_CSA_ReadAllString(DeviceIndex: LongWord; pData: Pointer; pDataBytes: PLongWord): LongWord; cdecl; var L, LPer, BytesRead: LongWord; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then begin pDataBytes^ := 0; Exit; end; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then begin pDataBytes^ := 0; Exit; end; with Dev[DeviceIndex] do begin if DIOBytes = 0 then begin Result := ERROR_BAD_TOKEN_TYPE; pDataBytes^ := 0; Exit; end; LPer := DIOBytes; BytesRead := 0; L := pDataBytes^; Result := ERROR_SUCCESS; while L < LPer do begin Result := GenericVendorRead(DeviceIndex, AUR_DIO_READ, 0, 0, LPer, pData); if (Result <> ERROR_SUCCESS) or (LPer < DIOBytes) then Break; Inc(BytesRead, LPer); Dec(L, LPer); Inc(PByte(pData), LPer); end; pDataBytes^ := BytesRead; end; except Result := ERROR_INTERNAL_ERROR; pDataBytes^ := 0; end; end; //Load-time defaults. function AIOUSB_SaveStateAsDefaults(DeviceIndex: LongWord): LongWord; cdecl; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := CheckFirmware20(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := GenericVendorWrite(DeviceIndex, AUR_GEN_REGISTER, $ACCE, $0010, 0, nil); except Result := ERROR_INTERNAL_ERROR; end; end; function AIOUSB_RestoreFactoryDefaults(DeviceIndex: LongWord): LongWord; cdecl; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := CheckFirmware20(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := GenericVendorWrite(DeviceIndex, AUR_GEN_REGISTER, $ACCE, $0011, 0, nil); except Result := ERROR_INTERNAL_ERROR; end; end; function AIOUSB_SetDefaultsTable(DeviceIndex: LongWord; pDefTable: Pointer; pDefTableBytes: PLongWord): LongWord; cdecl; var DefBuf: array of Byte; L: LongWord; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := CheckFirmware20(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; L := pDefTableBytes^; if L > 1024 then begin Result := ERROR_BAD_LENGTH; Exit; end; SetLength(DefBuf, L); try Move(pDefTable^, DefBuf[0], L); except Result := ERROR_NOACCESS; Exit; end; Result := GenericVendorWrite(DeviceIndex, AUR_GEN_REGISTER, $ACCE, $0022, L, @DefBuf[0]); except Result := ERROR_INTERNAL_ERROR; end; end; function AIOUSB_GetDefaultsTable(DeviceIndex: LongWord; pDefTable: Pointer; pDefTableBytes: PLongWord): LongWord; cdecl; var DefBuf: array of Byte; L: LongWord; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := CheckFirmware20(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; L := pDefTableBytes^; if L > 1024 then begin Result := ERROR_BAD_LENGTH; Exit; end; SetLength(DefBuf, L); try Move(pDefTable^, DefBuf[0], L); except Result := ERROR_NOACCESS; Exit; end; Result := GenericVendorRead(DeviceIndex, AUR_GEN_REGISTER, $0000, $0020, L, @DefBuf[0]); if L > LongWord(Length(DefBuf)) then L := Length(DefBuf); Move(DefBuf[0], pDefTable^, L); pDefTableBytes^ := L; except Result := ERROR_INTERNAL_ERROR; end; end; //Global tick. function AIOUSB_SetGlobalTickRate(DeviceIndex: LongWord; pHz: PDouble): LongWord; cdecl; var Hz, fDivisor: Double; Divisor: Word; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := CheckFirmware20(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Hz := pHz^; if Hz = 0 then Divisor := $FFFF //Will load 0 into the counter. else begin fDivisor := 12000000 / Hz; //12MHz is the CPU clock. if fDivisor <= 0 then Divisor := 0 else if fDivisor >= $FFFF then Divisor := $FFFF else Divisor := Round(fDivisor) ; end; Result := GenericVendorWrite(DeviceIndex, AUR_GEN_REGISTER, $FFFF - Divisor, $8001, 0, nil); except Result := ERROR_INTERNAL_ERROR; end; end; //Watchdog. function WDG_SetConfig(DeviceIndex: LongWord; pTimeoutSeconds: PDouble; pWDGTable: Pointer; pWDGTableBytes: PLongWord): LongWord; cdecl; var WDGBuf: array of Byte; fTimeout: Double; Timeout: Word; L: LongWord; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := CheckFirmware20(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; fTimeout := pTimeoutSeconds^; if fTimeout <= 0 then Timeout := 0 else if fTimeout >= $FFFF then Timeout := $FFFF else Timeout := Round(fTimeout) ; L := pWDGTableBytes^; if L > 1024 then begin Result := ERROR_BAD_LENGTH; Exit; end; SetLength(WDGBuf, 2 + L); PWord(@WDGBuf[0])^ := Timeout; try Move(pWDGTable^, WDGBuf[2], L); except Result := ERROR_NOACCESS; Exit; end; Result := GenericVendorWrite(DeviceIndex, AUR_GEN_REGISTER, $0000, $0041, 2 + L, @WDGBuf[0]); except Result := ERROR_INTERNAL_ERROR; end; end; function WDG_GetStatus(DeviceIndex: LongWord; pStatus: Pointer; pStatusBytes: PLongWord): LongWord; cdecl; var WDGBuf: array of Byte; L: LongWord; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := CheckFirmware20(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; L := pStatusBytes^; if L > 1024 then begin Result := ERROR_BAD_LENGTH; Exit; end; SetLength(WDGBuf, L); try Move(pStatus^, WDGBuf[0], L); except Result := ERROR_NOACCESS; Exit; end; Result := GenericVendorRead(DeviceIndex, AUR_WDG_STATUS, $0000, $0041, L, @WDGBuf[0]); if L > LongWord(Length(WDGBuf)) then L := Length(WDGBuf); Move(WDGBuf[0], pStatus^, L); pStatusBytes^ := L; except Result := ERROR_INTERNAL_ERROR; end; end; function WDG_Pet(DeviceIndex: LongWord; PetFlag: LongWord): LongWord; cdecl; var TimeoutLeft: Word; L: LongWord; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := CheckFirmware20(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; case PetFlag of 0: begin //Read a little status and throw it away, because we can't read zero bytes. L := SizeOf(TimeoutLeft); Result := GenericVendorRead(DeviceIndex, AUR_WDG_STATUS, $0000, $0041, L, @TimeoutLeft); end; else begin Result := ERROR_INVALID_FLAG_NUMBER; end; end; except Result := ERROR_INTERNAL_ERROR; end; end; //DIO automapping. function DIO_Automap_ClearTable(DeviceIndex: LongWord): LongWord; cdecl; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := CheckFirmware20(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := GenericVendorWrite(DeviceIndex, AUR_GEN_REGISTER, $0000, $0082, 0, nil); except Result := ERROR_INTERNAL_ERROR; end; end; function DIO_Automap_SetTable(DeviceIndex: LongWord; pMapTable: Pointer; pMapTableBytes: PLongWord): LongWord; cdecl; const MapCount = 32; var AutomapBuf: array of Byte; L: LongWord; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := CheckFirmware20(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; L := pMapTableBytes^; if L > 2*MapCount then begin Result := ERROR_BAD_LENGTH; Exit; end; if (L and 1) <> 0 then begin L := L and not 1; pMapTableBytes^ := L; end; SetLength(AutomapBuf, 2*MapCount + 1); FillChar(AutomapBuf[0], 2*MapCount, 0); try Move(pMapTable^, AutomapBuf[0], L); except Result := ERROR_NOACCESS; Exit; end; AutomapBuf[2*MapCount] := L div 2; Result := GenericVendorWrite(DeviceIndex, AUR_GEN_REGISTER, $0000, $0081, L, @AutomapBuf[0]); except Result := ERROR_INTERNAL_ERROR; end; end; function DIO_Automap_AddEntry(DeviceIndex: LongWord; pMapEntry: PWord): LongWord; cdecl; var MapEntry: Word; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := CheckFirmware20(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; try MapEntry := pMapEntry^; except Result := ERROR_NOACCESS; Exit; end; Result := GenericVendorWrite(DeviceIndex, AUR_GEN_REGISTER, $0000, $0084, SizeOf(MapEntry), @MapEntry); except Result := ERROR_INTERNAL_ERROR; end; end; function DIO_Automap_SetTickDivisor(DeviceIndex: LongWord; pDivisor: PByte): LongWord; cdecl; var Divisor: Byte; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := CheckFirmware20(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; try Divisor := pDivisor^; except Result := ERROR_NOACCESS; Exit; end; Result := GenericVendorWrite(DeviceIndex, AUR_GEN_REGISTER, $0000, $0083, SizeOf(Divisor), @Divisor); except Result := ERROR_INTERNAL_ERROR; end; end; //DIO PWM. function DIO_PWM_SetAll(DeviceIndex: LongWord; pDivisor: PByte; pPWMTable: Pointer; pPWMTableBytes: PLongWord): LongWord; cdecl; const PWMCount = 8; var PWMBuf: array of Byte; L: LongWord; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := CheckFirmware20(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; L := pPWMTableBytes^; if L > 2*PWMCount then begin Result := ERROR_BAD_LENGTH; Exit; end; if (L and 1) <> 0 then begin L := L and not 1; pPWMTableBytes^ := L; end; SetLength(PWMBuf, 2*PWMCount + 2); FillChar(PWMBuf[1], 2*PWMCount, 0); try Move(pPWMTable^, PWMBuf[1], L); except Result := ERROR_NOACCESS; Exit; end; PWMBuf[2*PWMCount + 1] := L div 2; try PWMBuf[0] := pDivisor^; except Result := ERROR_NOACCESS; Exit; end; Result := GenericVendorWrite(DeviceIndex, AUR_GEN_REGISTER, $0000, $0071, L, @PWMBuf[0]); except Result := ERROR_INTERNAL_ERROR; end; end; //DIO latching. function DIO_Latch_SetDivisor(DeviceIndex: LongWord; pDivisor: PByte): LongWord; cdecl; var Divisor: Byte; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := CheckFirmware20(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; try Divisor := pDivisor^; except Result := ERROR_NOACCESS; Exit; end; Result := GenericVendorWrite(DeviceIndex, AUR_GEN_REGISTER, $0000, $0063, SizeOf(Divisor), @Divisor); except Result := ERROR_INTERNAL_ERROR; end; end; function DIO_Latch_Reset(DeviceIndex: LongWord): LongWord; cdecl; var L: LongWord; LatchBuf: array of Byte; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := CheckFirmware20(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; SetLength(LatchBuf, Dev[DeviceIndex].DIOBytes * 3); L := Length(LatchBuf); Result := GenericVendorRead(DeviceIndex, AUR_DIO_LATCH_READ, $0000, $0000, L, @LatchBuf[0]); if Result <> ERROR_SUCCESS then Exit; except Result := ERROR_INTERNAL_ERROR; end; end; function DIO_Latch_Read(DeviceIndex: LongWord; pLowLatches, pHighLatches, pNoLatches: PByte; pLatchesBytes: PLongWord): LongWord; cdecl; var L, oL: LongWord; LatchBuf: array of Byte; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := CheckFirmware20(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; oL := Min(pLatchesBytes^, Dev[DeviceIndex].DIOBytes); SetLength(LatchBuf, Dev[DeviceIndex].DIOBytes * 3); try Move(pLowLatches^, LatchBuf[0], oL); Move(pHighLatches^, LatchBuf[0], oL); Move(pNoLatches^, LatchBuf[0], oL); except Result := ERROR_NOACCESS; Exit; end; L := Length(LatchBuf); Result := GenericVendorRead(DeviceIndex, AUR_DIO_LATCH_READ, $0000, $0000, L, @LatchBuf[0]); if Result <> ERROR_SUCCESS then Exit; if Integer(L) < Length(LatchBuf) then begin Result := ERROR_INVALID_DATA; Exit; end; L := Dev[DeviceIndex].DIOBytes; try Move(LatchBuf[ L], pLowLatches^, oL); Move(LatchBuf[2*L], pHighLatches^, oL); Move(LatchBuf[0 ], pNoLatches^, oL); except Result := ERROR_NOACCESS; Exit; end; pLatchesBytes^ := L; except Result := ERROR_INTERNAL_ERROR; end; end; //DIO debounce. function DIO_Deb_SetConfig(DeviceIndex: LongWord; pDebTable: Pointer; pDebTableBytes: PLongWord): LongWord; cdecl; var DebBuf: array of Byte; L: LongWord; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := CheckFirmware20(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; L := pDebTableBytes^; if L > 1024 then begin Result := ERROR_BAD_LENGTH; Exit; end; SetLength(DebBuf, L); try Move(pDebTable^, DebBuf[0], L); except Result := ERROR_NOACCESS; Exit; end; Result := GenericVendorWrite(DeviceIndex, AUR_GEN_REGISTER, $0000, $0051, L, @DebBuf[0]); except Result := ERROR_INTERNAL_ERROR; end; end; function DIO_Deb_ReadAll(DeviceIndex: LongWord; pDebData: PByte): LongWord; cdecl; var DebBuf: array of Byte; L: LongWord; begin try Result := Validate(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := EnsureOpen(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; Result := CheckFirmware20(DeviceIndex); if Result <> ERROR_SUCCESS then Exit; L := Dev[DeviceIndex].DIOBytes; SetLength(DebBuf, L); try Move(pDebData^, DebBuf[0], L); except Result := ERROR_NOACCESS; Exit; end; Result := GenericVendorRead(DeviceIndex, AUR_DIO_DEB_READ, $0000, $0000, L, @DebBuf[0]); if Result <> ERROR_SUCCESS then Exit; try Move(DebBuf[0], pDebData^, L); except Result := ERROR_NOACCESS; Exit; end; except Result := ERROR_INTERNAL_ERROR; end; end; end.