diff --git a/libpinproc.xcodeproj/project.pbxproj b/libpinproc.xcodeproj/project.pbxproj index aea7949..4febfb7 100644 --- a/libpinproc.xcodeproj/project.pbxproj +++ b/libpinproc.xcodeproj/project.pbxproj @@ -15,6 +15,7 @@ 668249E30FC0A3960051560E /* pinproctest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 668249E20FC0A3960051560E /* pinproctest.cpp */; }; 668249EA0FC0A4280051560E /* libpinproc.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D2AAC046055464E500DB518D /* libpinproc.a */; }; 668249ED0FC0A4CD0051560E /* PRHardware.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 668249EC0FC0A4CD0051560E /* PRHardware.cpp */; }; + 66824E7B0FCCBAFF0051560E /* PRCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = 66824E7A0FCCBAFF0051560E /* PRCommon.h */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -36,6 +37,7 @@ 668249D90FC0A30A0051560E /* pinproctest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = pinproctest; sourceTree = BUILT_PRODUCTS_DIR; }; 668249E20FC0A3960051560E /* pinproctest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = pinproctest.cpp; path = examples/pinproctest/pinproctest.cpp; sourceTree = ""; }; 668249EC0FC0A4CD0051560E /* PRHardware.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PRHardware.cpp; path = src/PRHardware.cpp; sourceTree = ""; }; + 66824E7A0FCCBAFF0051560E /* PRCommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PRCommon.h; path = src/PRCommon.h; sourceTree = ""; }; D2AAC046055464E500DB518D /* libpinproc.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libpinproc.a; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -95,6 +97,7 @@ 668249410FC07D900051560E /* PRDevice.cpp */, 6682494A0FC0870B0051560E /* PRHardware.h */, 668249EC0FC0A4CD0051560E /* PRHardware.cpp */, + 66824E7A0FCCBAFF0051560E /* PRCommon.h */, ); name = libpinproc; sourceTree = ""; @@ -124,6 +127,7 @@ 6682492C0FC079050051560E /* pinproc.h in Headers */, 668249420FC07D900051560E /* PRDevice.h in Headers */, 6682494B0FC0870B0051560E /* PRHardware.h in Headers */, + 66824E7B0FCCBAFF0051560E /* PRCommon.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/src/PRCommon.h b/src/PRCommon.h new file mode 100644 index 0000000..6beb403 --- /dev/null +++ b/src/PRCommon.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2009 Gerry Stellenberg, Adam Preble + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef _PRCOMMON_H_ +#define _PRCOMMON_H_ + +#ifdef NDEBUG +# define DEBUG(block) +#else +# define DEBUG(block) block +#endif + +extern void PRLog(const char *format, ...); + +#endif // _PRCOMMON_H_ diff --git a/src/PRDevice.cpp b/src/PRDevice.cpp index e09f343..e433cc6 100644 --- a/src/PRDevice.cpp +++ b/src/PRDevice.cpp @@ -30,7 +30,7 @@ #include "PRDevice.h" -PRDevice::PRDevice(PRMachineType machineType) : machineType(machineType), ftdiInitialized(false) +PRDevice::PRDevice(PRMachineType machineType) : machineType(machineType) { Reset(); } @@ -391,112 +391,39 @@ PRResult PRDevice::DMDDraw(uint8_t * dots) PRResult PRDevice::Open() { - int32_t i=0; - PRResult rc; - struct ftdi_device_list *devlist, *curdev; - char manufacturer[128], description[128]; - uint32_t temp_word; - - ftdiInitialized = false; - - // Open the FTDI device - if (ftdi_init(&ftdic) != 0) + PRResult res = PRHardwareOpen(); + if (res == kPRSuccess) { - DEBUG(PRLog("Failed to initialize FTDI.\n")); - return kPRFailure; - } - - // Find all FTDI devices - // This is very basic and really only expects to see 1 device. It needs to be - // smarter. At the very least, it should check some register on the P-ROC versus - // an input parameter to ensure the software is set up for the same architecture as - // the P-ROC (Stern vs WPC). Otherwise, it's possible to drive the coils the wrong - // polarity and blow fuses or fry transistors and all other sorts of badness. - - // We first enumerate all of the devices: - int numDevices = ftdi_usb_find_all(&ftdic, &devlist, FTDI_VENDOR_ID, FTDI_FT245RL_PRODUCT_ID); - if (numDevices < 0) { - DEBUG(PRLog("ftdi_usb_find_all failed: %d: %s\n", numDevices, ftdi_get_error_string(&ftdic))); - ftdi_deinit(&ftdic); - return kPRFailure; - } - else { - DEBUG(PRLog("Number of FTDI devices found: %d\n", numDevices)); - - for (curdev = devlist; curdev != NULL; i++) { - DEBUG(PRLog("Checking device %d\n", i)); - if ((rc = (int32_t)ftdi_usb_get_strings(&ftdic, curdev->dev, manufacturer, 128, description, 128, NULL, 0)) < 0) { - DEBUG(PRLog(" ftdi_usb_get_strings failed: %d: %s\n", rc, ftdi_get_error_string(&ftdic))); - } - else { - DEBUG(PRLog(" Device #%d:\n", i)); - DEBUG(PRLog(" Manufacturer: %s\n", manufacturer)); - DEBUG(PRLog(" Description: %s\n", description)); - } - curdev = curdev->next; + // Try to verify the P-ROC IS in the FPGA before initializing the FPGA's FTDI interface + // just in case it was already initialized from a previous application execution. + DEBUG(PRLog("Verifying P-ROC ID: \n")); + if (VerifyChipID() == kPRFailure) { + // Since the FPGA didn't appear to be responding properly, send the FPGA's FTDI + // initialization sequence. This is a set of bytes the FPGA is waiting to receive + // before it allows access deeper into the chip. This keeps garbage from getting + // in and wreaking havoc before software is up and running. + DEBUG(PRLog("Initializing P-ROC...\n")); + res = FlushReadBuffer(); + uint32_t temp_word = P_ROC_INIT_PATTERN_A; + res = WriteData(&temp_word, 1); + temp_word = P_ROC_INIT_PATTERN_B; + res = WriteData(&temp_word, 1); + res = VerifyChipID(); } - - } - - // Don't need the device list anymore - ftdi_list_free (&devlist); - // Did previous logic leave ftdic clean? Probably - // Need to de-init and re-init before opening usb? Doubtful. - //ftdi_deinit(&ftdic); - //ftdi_init(&ftdic); - - - if ((rc = (int32_t)ftdi_usb_open(&ftdic, FTDI_VENDOR_ID, FTDI_FT245RL_PRODUCT_ID)) < 0) - { - DEBUG(PRLog("ERROR: Unable to open ftdi device: %d: %s\n", rc, ftdi_get_error_string(&ftdic))); - return kPRFailure; - } - else - { - rc = kPRSuccess; - if (ftdic.type == TYPE_R) { - uint32_t chipid; - ftdi_read_chipid(&ftdic,&chipid); - DEBUG(PRLog("FTDI chip_id = 0x%x\n", chipid)); - - // Try to verify the P-ROC IS in the FPGA before initializing the FPGA's FTDI interface - // just in case it was already initialized from a previous application execution. - DEBUG(PRLog("Verifying P-ROC ID: \n")); - if (VerifyChipID() == kPRFailure) { - // Since the FPGA didn't appear to be responding properly, send the FPGA's FTDI - // initialization sequence. This is a set of bytes the FPGA is waiting to receive - // before it allows access deeper into the chip. This keeps garbage from getting - // in and wreaking havoc before software is up and running. - DEBUG(PRLog("Initializing P-ROC...\n")); - rc = FlushReadBuffer(); - temp_word = P_ROC_INIT_PATTERN_A; - rc = WriteData(&temp_word, 1); - temp_word = P_ROC_INIT_PATTERN_B; - rc = WriteData(&temp_word, 1); - rc = VerifyChipID(); - } - else - { - DEBUG(PRLog("Failed to verify chip ID.")); - rc = kPRFailure; - } + else + { + DEBUG(PRLog("Failed to verify chip ID.")); + res = kPRFailure; } } - if (rc == kPRSuccess) - ftdiInitialized = true; - - return rc; + return res; } PRResult PRDevice::Close() { // TODO: Add protection against closing a not-open ftdic. - if (ftdiInitialized) - { - ftdi_usb_close(&ftdic); - ftdi_deinit(&ftdic); - } + PRHardwareClose(); return kPRSuccess; } @@ -577,7 +504,7 @@ PRResult PRDevice::WriteData(uint32_t * words, int32_t numWords) } int bytesToWrite = numWords * 4; - int bytesWritten = (int32_t)ftdi_write_data(&ftdic, wr_buffer, bytesToWrite); + int bytesWritten = PRHardwareWrite(wr_buffer, bytesToWrite); if (bytesWritten != bytesToWrite) { @@ -639,7 +566,7 @@ PRResult PRDevice::FlushReadBuffer() int32_t PRDevice::CollectReadData() { int32_t rc,i; - rc = ftdi_read_data(&ftdic, collect_buffer, FTDI_BUFFER_SIZE-num_collected_bytes); + rc = PRHardwareRead(collect_buffer, FTDI_BUFFER_SIZE-num_collected_bytes); for (i=0; i -#include using namespace std; @@ -39,13 +39,6 @@ using namespace std; #define maxDrivers (256) #define maxSwitchRules (256<<2) // 8 bits of switchNum indicies plus bits for debounced and state. -#ifdef NDEBUG -# define DEBUG(block) -#else -# define DEBUG(block) block -#endif -extern void PRLog(const char *format, ...); - class PRDevice { public: @@ -118,9 +111,6 @@ protected: queue unrequestedDataQueue; /**< Queue of words received from the device that were not requested via RequestData(). Usually switch events. */ queue requestedDataQueue; /**< Queue of words received from the device as the result of a call to RequestData(). */ - bool ftdiInitialized; - ftdi_context ftdic; - uint8_t collected_bytes_fifo[FTDI_BUFFER_SIZE]; int32_t collected_bytes_rd_addr; int32_t collected_bytes_wr_addr; diff --git a/src/PRHardware.cpp b/src/PRHardware.cpp index 2bcf7d6..9d255bc 100644 --- a/src/PRHardware.cpp +++ b/src/PRHardware.cpp @@ -30,6 +30,8 @@ #include "PRHardware.h" +#include "PRCommon.h" +#include "pinproc.h" uint32_t CreateRegRequestWord( uint32_t select, uint32_t addr, uint32_t num_words ) { @@ -234,3 +236,112 @@ int32_t CreateDMDUpdateConfigBurst ( uint32_t * burst, PRDMDConfig *dmd_config) return kPRSuccess; } + +/** + * This is where all FTDI driver-specific code should go. + * As we add support for other drivers (such as D2xx on Windows), we will add more implementations of the PRHardware*() functions here. + */ + +#if !defined(USE_LIBFTDI) +#define USE_LIBFTDI 1 +#endif + +#if USE_LIBFTDI + +#include + +static bool ftdiInitialized; +static ftdi_context ftdic; + + +PRResult PRHardwareOpen() +{ + int32_t i=0; + PRResult rc; + struct ftdi_device_list *devlist, *curdev; + char manufacturer[128], description[128]; + + ftdiInitialized = false; + + // Open the FTDI device + if (ftdi_init(&ftdic) != 0) + { + DEBUG(PRLog("Failed to initialize FTDI.\n")); + return kPRFailure; + } + + // Find all FTDI devices + // This is very basic and really only expects to see 1 device. It needs to be + // smarter. At the very least, it should check some register on the P-ROC versus + // an input parameter to ensure the software is set up for the same architecture as + // the P-ROC (Stern vs WPC). Otherwise, it's possible to drive the coils the wrong + // polarity and blow fuses or fry transistors and all other sorts of badness. + + // We first enumerate all of the devices: + int numDevices = ftdi_usb_find_all(&ftdic, &devlist, FTDI_VENDOR_ID, FTDI_FT245RL_PRODUCT_ID); + if (numDevices < 0) { + DEBUG(PRLog("ftdi_usb_find_all failed: %d: %s\n", numDevices, ftdi_get_error_string(&ftdic))); + ftdi_deinit(&ftdic); + return kPRFailure; + } + else { + DEBUG(PRLog("Number of FTDI devices found: %d\n", numDevices)); + + for (curdev = devlist; curdev != NULL; i++) { + DEBUG(PRLog("Checking device %d\n", i)); + if ((rc = (int32_t)ftdi_usb_get_strings(&ftdic, curdev->dev, manufacturer, 128, description, 128, NULL, 0)) < 0) { + DEBUG(PRLog(" ftdi_usb_get_strings failed: %d: %s\n", rc, ftdi_get_error_string(&ftdic))); + } + else { + DEBUG(PRLog(" Device #%d:\n", i)); + DEBUG(PRLog(" Manufacturer: %s\n", manufacturer)); + DEBUG(PRLog(" Description: %s\n", description)); + } + curdev = curdev->next; + } + + } + + // Don't need the device list anymore + ftdi_list_free (&devlist); + + if ((rc = (int32_t)ftdi_usb_open(&ftdic, FTDI_VENDOR_ID, FTDI_FT245RL_PRODUCT_ID)) < 0) + { + DEBUG(PRLog("ERROR: Unable to open ftdi device: %d: %s\n", rc, ftdi_get_error_string(&ftdic))); + return kPRFailure; + } + else + { + rc = kPRSuccess; + if (ftdic.type == TYPE_R) { + uint32_t chipid; + ftdi_read_chipid(&ftdic,&chipid); + DEBUG(PRLog("FTDI chip_id = 0x%x\n", chipid)); + ftdiInitialized = true; + return kPRSuccess; + } + else + { + DEBUG(PRLog("FTDI type != TYPE_R: 0x%x\n", ftdic.type)); + return kPRFailure; + } + } +} +void PRHardwareClose() +{ + if (ftdiInitialized) + { + ftdi_usb_close(&ftdic); + ftdi_deinit(&ftdic); + } +} +int PRHardwareRead(uint8_t *buffer, int maxBytes) +{ + return ftdi_read_data(&ftdic, buffer, maxBytes); +} +int PRHardwareWrite(uint8_t *buffer, int bytes) +{ + return ftdi_write_data(&ftdic, buffer, bytes); +} + +#endif // USE_LIBFTDI diff --git a/src/PRHardware.h b/src/PRHardware.h index 5f7709c..2072eb3 100644 --- a/src/PRHardware.h +++ b/src/PRHardware.h @@ -177,4 +177,10 @@ void ParseSwitchRuleIndex(uint16_t index, uint8_t *switchNum, PREventType *event int16_t CreateSwitchRuleIndex(uint8_t switchNum, PREventType eventType); int32_t CreateSwitchRuleAddr(uint8_t switchNum, PREventType eventType); + +PRResult PRHardwareOpen(); +void PRHardwareClose(); +int PRHardwareRead(uint8_t *buffer, int maxBytes); +int PRHardwareWrite(uint8_t *buffer, int bytes); + #endif // _PROC_HARDWARE_H_