/* * * Copyright © 2004, University of Washington, * Department of Computer Science and Engineering. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither name of the University of Washington, Department of Computer * Science and Engineering nor the names of its contributors may be used to * endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * */ #include "FTDI466API.h" // constructor FTDI466API::FTDI466API() { m_hFtdiDLL = NULL; m_hFtdiDevice = NULL; m_pFnListDevices = NULL; m_pFnOpenEx = NULL; m_pFnClose = NULL; m_pFnRead = NULL; m_pFnWrite = NULL; m_pFnResetDevice = NULL; m_pFnPurge = NULL; m_pFnSetTimeouts = NULL; m_pFnGetQueueStatus = NULL; m_pFnGetStatus = NULL; m_pFnSetLatencyTimer = NULL; m_pFnGetBitMode = NULL; m_pFnSetBitMode = NULL; } // Loads the DLL, creates function pointers, and setups the FTDI chip for MPSSE // Returns: success bool FTDI466API::open() { FT_STATUS ftStatus; DWORD numDevs; char buffer[256]; cout << "Opening Connection to USB Device" << endl; // link to DLL if(m_hFtdiDLL == NULL) { if(!loadDLL()) // load the DLL if fails return false return false; } // get list of devices ftStatus = ListDevices(&numDevs, NULL, FT_LIST_NUMBER_ONLY); if(!FT_SUCCESS(ftStatus)) { printError(ftStatus); cerr << "DRIVER PROBLEM: Could not obtain list of devices" << endl; return false; } // print out a description of the FTDI devices that are connected for(UINT i = 0; i < numDevs; i++) { ftStatus = ListDevices((PVOID)i, buffer, FT_LIST_BY_INDEX|FT_OPEN_BY_DESCRIPTION); if(FT_SUCCESS(ftStatus)) { cout << "Number: " << i << " Description: " << buffer << endl; } else { printError(ftStatus); cerr << "DRIVER PROBLEM: Could not obtain description of device" << endl; } } // connect to FDTI device that is A. // TODO: Assuming that the first index is A and is passing by description because there // could be multiple devices attached. Need to make this code a bit more robust; UINT deviceIndex = 0; ftStatus = ListDevices((PVOID)deviceIndex, buffer, FT_LIST_BY_INDEX|FT_OPEN_BY_DESCRIPTION); if(!FT_SUCCESS(ftStatus)) { printError(ftStatus); cerr << "DRIVER PROBLEM: Unable to obtain pointer to the A channel" << endl; return false; } // open a handle to the device ftStatus = OpenEx(buffer, FT_OPEN_BY_DESCRIPTION); if(!FT_SUCCESS(ftStatus)) { printError(ftStatus); cerr << "FAILED TO OBTAIN HANDLE TO CHANNEL A! " << endl; return false; } // reset the device ftStatus = ResetDevice(); if(!FT_SUCCESS(ftStatus)) { printError(ftStatus); cerr << "FAILED TO RESET DEVICE!" << endl; return 0; } // set the receive buffer flush ftStatus = SetLatencyTimer(5); if(!FT_SUCCESS(ftStatus)) { printError(ftStatus); cerr << "DRIVER PROBLEM: Unable to update Latency Timer" << endl; return false; } // reset the IO bit mode ftStatus = SetBitMode(0x00, 0x00); if(!FT_SUCCESS(ftStatus)) { printError(ftStatus); cerr << "DRIVER PROBLEM: Unable to reset IO bit mode" << endl; return false; } // set for MPSSE ftStatus = SetBitMode(0x00, 0x02); if(!FT_SUCCESS(ftStatus)) { printError(ftStatus); cerr << "DRIVER PROBLEM: Unable to set IO bit mode to MPSSE" << endl; return false; } // sync the MPSSE return syncMPSSE(); } // helper function used to make sure the MPSSE gets synced with the driver bool FTDI466API::syncMPSSE() { int count = 0; FT_STATUS ftStatus; UCHAR rxBuffer[256]; UCHAR txBuffer[256]; DWORD bytesReceived; DWORD numBytesToRead; DWORD bytesSent; // ORIGINAL PROGRAM REPEATS sending a bad character except it is 0xab instead of 0xaa while(count++ < 2) { // purge the receive and transmit buffers device ftStatus = Purge(FT_PURGE_RX | FT_PURGE_TX); if(!FT_SUCCESS(ftStatus)) { printError(ftStatus); cerr << "DRIVER PROBLEM: Unable to purge device when trying to sync MPSSE" << endl; return false; } // send a bad command to ensure system is synced txBuffer[0] = 0xAA; // bad command ftStatus = Write( txBuffer, 1, &bytesSent); if(!FT_SUCCESS(ftStatus) && bytesSent != 1) { printError(ftStatus); cerr << "DRIVER PROBLEM: Unable to write sync byte" << endl; return false; } Sleep(10); // get number of bytes to read back numBytesToRead = getReceiveQueueSize(); ftStatus = Read(rxBuffer, numBytesToRead, &bytesReceived); if(!FT_SUCCESS(ftStatus)) { printError(ftStatus); cerr << "DRIVER PROBLEM: Unable to read receive buffer when trying to sync MPSSE" << endl; return false; } else { if(rxBuffer[0] != 0xFA && rxBuffer[1] != 0xAA) cout << "FAILED MPSSE SYNC TEST" << endl; } } return true; } // Closes the DLL, clears function pointers // Returns: success bool FTDI466API::close() { FT_STATUS ftStatus = Close(); if(!FT_SUCCESS(ftStatus)) { printError(ftStatus); cerr << "DRIVER PROBLEM: Unable to close connection to USB device" << endl; return false; } return true; } // Purges receive and transmit buffers in the device // Flags to pass in bufferMask: Any combination of FT_PURGE_RX and FT_PURGE_TX // Example: purgeBuffers(FT_PURGE_RX | FT_PURGE_TX); // Returns: success bool FTDI466API::purgeBuffers(DWORD bufferMask) { FT_STATUS ftStatus = Purge(bufferMask); if(!FT_SUCCESS(ftStatus)) { printError(ftStatus); cerr << "DRIVER PROBLEM: Unable to purge device" << endl; return false; } return true; } // Gets the number of characters in the receive queue and the number of characters in the transmit queue // Parameters: // sizeRxQueue: pointer to a variable of type DWORD that will receive the number of characters in receive queue // sizeTxQueue: pointer to a variable of type DWORD that will receive the number of characters in transmit queue // Returns success bool FTDI466API::getQueueSizes(LPDWORD sizeRxQueue, LPDWORD sizeTxQueue) { // NOTE: get status actually returns the current state of event status // but since we are not using events it is not needed for this assignment // thus it is not exposed DWORD eventStatus; FT_STATUS ftStatus = GetStatus(sizeRxQueue, sizeTxQueue, &eventStatus); if(!FT_SUCCESS(ftStatus)) { printError(ftStatus); cerr << "DRIVER PROBLEM: Unable to execute GetStatus to get queue sizes" << endl; return false; } return true; } // Returns the number of characters in the receive queue of the device DWORD FTDI466API::getReceiveQueueSize() { FT_STATUS ftStatus; DWORD num; ftStatus = GetQueueStatus(&num); if(!FT_SUCCESS(ftStatus)) { printError(ftStatus); cerr << "DRIVER PROBLEM: The attempt to get the status of the receive queue failed " << endl; return 0; } return num; } // Read data from the device // Parameters: // buffer: pointer to a buffer that receives the data // numBytes: number of bytes to be read from the device // Returns: number of bytes read from the device DWORD FTDI466API::read(LPVOID buffer, DWORD numBytes) { FT_STATUS ftStatus; DWORD numBytesRead; ftStatus = Read(buffer, numBytes, &numBytesRead); if(!FT_SUCCESS(ftStatus)) { printError(ftStatus); cerr << "DRIVER PROBLEM: The attempt to read bytes from the receive queue failed " << endl; return 0; } return numBytesRead; } // Write data to the device // Parameters: // buffer: pointer to a buffer that contains the data to be written to the device // numBytes: number of bytes to write to the device // Returns: number of bytes written to the device DWORD FTDI466API::write(LPVOID buffer, DWORD numBytes) { FT_STATUS ftStatus; DWORD numBytesWritten; ftStatus = Write(buffer, numBytes, &numBytesWritten); if(!FT_SUCCESS(ftStatus)) { printError(ftStatus); cerr << "DRIVER PROBLEM: The attempt to read bytes from the receive queue failed " << endl; return 0; } return numBytesWritten; } // helper function that unloads the DLL and sets function pointers to NULL bool FTDI466API::unloadDLL() { if(FreeLibrary(m_hFtdiDLL)) { m_pFnListDevices = NULL; m_pFnOpenEx = NULL; m_pFnClose = NULL; m_pFnRead = NULL; m_pFnWrite = NULL; m_pFnResetDevice = NULL; m_pFnPurge = NULL; m_pFnSetTimeouts = NULL; m_pFnGetQueueStatus = NULL; m_pFnGetStatus = NULL; m_pFnSetLatencyTimer = NULL; m_pFnGetBitMode = NULL; m_pFnSetBitMode = NULL; m_hFtdiDLL = NULL; m_hFtdiDevice = NULL; cout << "FINISHED UNLOADING DLL" << endl; return true; } return false; } // helper function to load the DLL and create function pointers bool FTDI466API::loadDLL() { // load the DLL m_hFtdiDLL = LoadLibrary("Ftd2xx.dll"); if(m_hFtdiDLL == NULL) { cerr << "DRIVER PROBLEM: Unable to load FTD2XX.dll" << endl; return false; } /*** get the function pointers ***/ m_pFnListDevices = (FnPtr_FT_ListDevices)GetProcAddress(m_hFtdiDLL, "FT_ListDevices"); if(m_pFnListDevices == NULL) { cerr << "DRIVER PROBLEM: Unable to find FT_ListDevices" << endl; return false; } m_pFnOpenEx = (FnPtr_FT_OpenEx)GetProcAddress(m_hFtdiDLL, "FT_OpenEx"); if (m_pFnOpenEx == NULL) { cerr << "DRIVER PROBLEM: Unable to find FT_OpenEx" << endl; return false; } m_pFnClose = (FnPtr_FT_Close)GetProcAddress(m_hFtdiDLL, "FT_Close"); if (m_pFnClose == NULL) { cerr << "DRIVER PROBLEM: Unable to find FT_Close" << endl; return false; } m_pFnRead = (FnPtr_FT_Read)GetProcAddress(m_hFtdiDLL, "FT_Read"); if (m_pFnRead == NULL) { cerr << "DRIVER PROBLEM: Unable to find FT_Read" << endl; return false; } m_pFnWrite = (FnPtr_FT_Write)GetProcAddress(m_hFtdiDLL, "FT_Write"); if (m_pFnWrite == NULL) { cerr << "DRIVER PROBLEM: Unable to find FT_Write" << endl; return false; } m_pFnResetDevice = (FnPtr_FT_ResetDevice)GetProcAddress(m_hFtdiDLL, "FT_ResetDevice"); if (m_pFnResetDevice == NULL) { cerr << "DRIVER PROBLEM: Unable to find FT_ResetDevice" << endl; return false; } m_pFnPurge = (FnPtr_FT_Purge)GetProcAddress(m_hFtdiDLL, "FT_Purge"); if (m_pFnPurge == NULL) { cerr << "DRIVER PROBLEM: Unable to find FT_Purge" << endl; return false; } m_pFnSetTimeouts = (FnPtr_FT_SetTimeouts)GetProcAddress(m_hFtdiDLL, "FT_SetTimeouts"); if (m_pFnSetTimeouts == NULL) { cerr << "DRIVER PROBLEM: Unable to find FT_SetTimeouts" << endl; return false; } m_pFnGetQueueStatus = (FnPtr_FT_GetQueueStatus)GetProcAddress(m_hFtdiDLL, "FT_GetQueueStatus"); if (m_pFnGetQueueStatus == NULL) { cerr << "DRIVER PROBLEM: Unable to find FT_GetQueueStatus" << endl; return false; } m_pFnGetStatus = (FnPtr_FT_GetStatus)GetProcAddress(m_hFtdiDLL, "FT_GetStatus"); if (m_pFnGetStatus == NULL) { cerr << "DRIVER PROBLEM: Unable to find FT_GetStatus" << endl; return false; } m_pFnSetLatencyTimer = (FnPtr_FT_SetLatencyTimer)GetProcAddress(m_hFtdiDLL, "FT_SetLatencyTimer"); if (m_pFnSetLatencyTimer == NULL) { cerr << "DRIVER PROBLEM: Unable to find FT_SetLatencyTimer" << endl; return false; } m_pFnGetBitMode = (FnPtr_FT_GetBitMode)GetProcAddress(m_hFtdiDLL, "FT_GetBitMode"); if (m_pFnGetBitMode == NULL) { cerr << "DRIVER PROBLEM: Unable to find FT_GetBitMode" << endl; return false; } m_pFnSetBitMode = (FnPtr_FT_SetBitMode)GetProcAddress(m_hFtdiDLL, "FT_SetBitMode"); if (m_pFnSetBitMode == NULL) { cerr << "DRIVER PROBLEM: Unable to find FT_SetBitMode" << endl; return false; } cout << "FINISHED LOADING DLL" << endl; return true; } FT_STATUS FTDI466API::ListDevices(PVOID pArg1, PVOID pArg2, DWORD dwFlags) { if (m_pFnListDevices != NULL){ return (*m_pFnListDevices)(pArg1, pArg2, dwFlags); } else { cout << "DRIVER PROBLEM: Handle to FT_ListDevices is invalid!" << endl; return FT_INVALID_HANDLE; } } FT_STATUS FTDI466API::OpenEx(PVOID pArg1, DWORD dwFlags) { if (m_pFnOpenEx != NULL){ return (*m_pFnOpenEx)(pArg1, dwFlags, &m_hFtdiDevice); } else { cout << "DRIVER PROBLEM: Handle to FT_OpenEx is invalid!" << endl; return FT_INVALID_HANDLE; } } FT_STATUS FTDI466API::Close() { if (m_pFnClose != NULL){ return (*m_pFnClose)(m_hFtdiDevice); } else { cout << "DRIVER PROBLEM: Handle to FT_Close is invalid!" << endl; return FT_INVALID_HANDLE; } } FT_STATUS FTDI466API::Read(LPVOID lpvBuffer, DWORD dwBuffSize, LPDWORD lpdwBytesRead) { if (m_pFnRead != NULL){ return (*m_pFnRead)(m_hFtdiDevice, lpvBuffer, dwBuffSize, lpdwBytesRead); } else { cout << "DRIVER PROBLEM: Handle to FT_Read is not invalid!" << endl; return FT_INVALID_HANDLE; } } FT_STATUS FTDI466API::Write(LPVOID lpvBuffer, DWORD dwBuffSize, LPDWORD lpdwBytes) { if (m_pFnWrite != NULL){ return (*m_pFnWrite)(m_hFtdiDevice, lpvBuffer, dwBuffSize, lpdwBytes); }else{ cout << "DRIVER PROBLEM: Handle to FT_Write is invalid!" << endl; return FT_INVALID_HANDLE; } } FT_STATUS FTDI466API::ResetDevice() { if (m_pFnResetDevice != NULL){ return (*m_pFnResetDevice)(m_hFtdiDevice); }else{ cout << "DRIVER PROBLEM: Handle to FT_ResetDevice is invalid!" << endl; return FT_INVALID_HANDLE; } } FT_STATUS FTDI466API::Purge(DWORD dwMask) { if (m_pFnPurge != NULL){ return (*m_pFnPurge)(m_hFtdiDevice, dwMask); } else { cout << "DRIVER PROBLEM: Handle to FT_Purge is invalid!" << endl; return FT_INVALID_HANDLE; } } FT_STATUS FTDI466API::SetTimeouts(DWORD dwReadTimeout, DWORD dwWriteTimeout) { if (m_pFnSetTimeouts != NULL){ return (*m_pFnSetTimeouts)(m_hFtdiDevice, dwReadTimeout, dwWriteTimeout); }else { cout << "DRIVER PROBLEM: Handle to FT_SetTimeouts is invalid!" << endl; return FT_INVALID_HANDLE; } } FT_STATUS FTDI466API::GetQueueStatus(LPDWORD lpdwAmountInRxQueue) { if (m_pFnGetQueueStatus != NULL){ return (*m_pFnGetQueueStatus)(m_hFtdiDevice, lpdwAmountInRxQueue); } else { cout << "DRIVER PROBLEM: Handle to FT_GetQueueStatus is invalid!" << endl; return FT_INVALID_HANDLE; } } FT_STATUS FTDI466API::GetStatus(LPDWORD lpdwAmountInRxQueue, LPDWORD lpdwAmountInTxQueue, LPDWORD lpdwEventStatus) { if (m_pFnGetStatus != NULL){ return (*m_pFnGetStatus)(m_hFtdiDevice, lpdwAmountInRxQueue, lpdwAmountInTxQueue, lpdwEventStatus); } else { cout << "DRIVER PROBLEM: Handle to FT_GetStatus is invalid!" << endl; return FT_INVALID_HANDLE; } } FT_STATUS FTDI466API::SetLatencyTimer(UCHAR ucTimer) { if (m_pFnSetLatencyTimer != NULL) { return (*m_pFnSetLatencyTimer)(m_hFtdiDevice, ucTimer); } else { cout << "DRIVER PROBLEM: Handle to FT_SetLatencyTimer is invalid!" << endl; return FT_INVALID_HANDLE; } } FT_STATUS FTDI466API::GetBitMode(PUCHAR pucMode) { if (m_pFnGetBitMode != NULL) { return (*m_pFnGetBitMode)(m_hFtdiDevice, pucMode); } else { cout << "DRIVER PROBLEM: Handle to FT_GetBitMode is invalid!" << endl; return FT_INVALID_HANDLE; } } FT_STATUS FTDI466API::SetBitMode(UCHAR ucMask, UCHAR ucMode) { if (m_pFnSetBitMode != NULL) { return (*m_pFnSetBitMode)(m_hFtdiDevice, ucMask, ucMode); } else { cout << "DRIVER PROBLEM: Handle to FT_SetBitMode is invalid!" << endl; return FT_INVALID_HANDLE; } } void FTDI466API::printError(DWORD error) { switch(error) { case FT_INVALID_HANDLE: cerr << "ERROR: FT_INVALID_HANDLE" << endl; break; case FT_DEVICE_NOT_FOUND: cerr << "ERROR: FT_DEVICE_NOT_FOUND" << endl; break; case FT_DEVICE_NOT_OPENED: cerr << "ERROR: FT_DEVICE_NOT_OPENED" << endl; break; case FT_IO_ERROR: cerr << "ERROR: FT_IO_ERROR" << endl; break; case FT_INSUFFICIENT_RESOURCES: cerr << "ERROR: FT_INSUFFICIENT_RESOURCES" << endl; break; case FT_INVALID_PARAMETER: cerr << "ERROR: FT_INVALID_PARAMETER" << endl; break; case FT_INVALID_BAUD_RATE: cerr << "ERROR: FT_INVALID_BAUD_RATE" << endl; break; case FT_DEVICE_NOT_OPENED_FOR_ERASE: cerr << "ERROR: FT_DEVICE_NOT_OPENED_FOR_ERASE" << endl; break; case FT_DEVICE_NOT_OPENED_FOR_WRITE: cerr << "ERROR: FT_DEVICE_NOT_OPENED_FOR_WRITE" << endl; break; case FT_FAILED_TO_WRITE_DEVICE: cerr << "ERROR: FT_FAILED_TO_WRITE_DEVICE" << endl; break; case FT_EEPROM_READ_FAILED: cerr << "ERROR: FT_EEPROM_READ_FAILED" << endl; break; case FT_EEPROM_WRITE_FAILED: cerr << "ERROR: FT_EEPROM_WRITE_FAILED" << endl; break; case FT_EEPROM_ERASE_FAILED: cerr << "ERROR: FT_EEPROM_ERASE_FAILED" << endl; break; case FT_EEPROM_NOT_PRESENT: cerr << "ERROR: FT_EEPROM_NOT_PRESENT" << endl; break; case FT_EEPROM_NOT_PROGRAMMED: cerr << "ERROR: FT_EEPROM_NOT_PROGRAMMED" << endl; break; case FT_INVALID_ARGS: cerr << "ERROR: FT_INVALID_ARGS" << endl; break; case FT_OTHER_ERROR: cerr << "ERROR: FT_OTHER_ERROR" << endl; break; } }