From 0f4976c5e54dc04fc31f683eb8dceb044d6c4875 Mon Sep 17 00:00:00 2001 From: gstellenberg Date: Mon, 25 May 2009 22:27:50 -0500 Subject: [PATCH 01/22] Implemented PRSwitchUpdateConfig --- examples/pinproctest/pinproctest.cpp | 20 +++++++++++++++----- include/pinproc.h | 28 ++++++++++++++++++++-------- src/PRDevice.cpp | 26 +++++++++++++++++++++----- src/PRDevice.h | 4 +++- src/PRHardware.cpp | 24 +++++++++++++++++++++++- src/PRHardware.h | 24 ++++++++++++++++-------- src/pinproc.cpp | 9 +++++++-- 7 files changed, 105 insertions(+), 30 deletions(-) diff --git a/examples/pinproctest/pinproctest.cpp b/examples/pinproctest/pinproctest.cpp index 5249554..e70fbc9 100644 --- a/examples/pinproctest/pinproctest.cpp +++ b/examples/pinproctest/pinproctest.cpp @@ -135,13 +135,23 @@ void ConfigureSwitches(PRHandle proc) { int i; + // Configure switch controller registers (if the defaults aren't acceptable) + PRSwitchConfig switchConfig; + switchConfig.clear = false; + switchConfig.directMatrixScanLoopTime = 2; // milliseconds + switchConfig.pulsesBeforeCheckingRX = 10; + switchConfig.inactivePulsesAfterBurst = 12; + switchConfig.pulsesPerBurst = 6; + switchConfig.pulseHalfPeriodTime = 13; // milliseconds + PRSwitchUpdateConfig(proc, &switchConfig); + // Configures rules to notify the host for every debounced switch event. for (i = 0; i <= kPRSwitchPhysicalLast; i++) { PRSwitchRule sw; sw.notifyHost = true; - PRSwitchesUpdateRule(proc, i, kPREventTypeSwitchClosedDebounced, &sw, NULL, 0); - PRSwitchesUpdateRule(proc, i, kPREventTypeSwitchOpenDebounced, &sw, NULL, 0); + PRSwitchUpdateRule(proc, i, kPREventTypeSwitchClosedDebounced, &sw, NULL, 0); + PRSwitchUpdateRule(proc, i, kPREventTypeSwitchOpenDebounced, &sw, NULL, 0); } } @@ -157,7 +167,7 @@ void ConfigureWPCFlipperSwitchRule (PRHandle proc, int swNum, int mainCoilNum, i PRDriverGetState(proc, holdCoilNum, &drivers[1]); PRDriverStatePulse(&drivers[1],0); // Turn on indefintely (set pulse for 0ms) sw.notifyHost = false; - PRSwitchesUpdateRule(proc,swNum, kPREventTypeSwitchClosedNondebounced, &sw, drivers, numDriverRules); + PRSwitchUpdateRule(proc,swNum, kPREventTypeSwitchClosedNondebounced, &sw, drivers, numDriverRules); // Flipper off rules PRDriverGetState(proc, mainCoilNum, &drivers[0]); @@ -165,7 +175,7 @@ void ConfigureWPCFlipperSwitchRule (PRHandle proc, int swNum, int mainCoilNum, i PRDriverGetState(proc, holdCoilNum, &drivers[1]); PRDriverStateDisable(&drivers[1]); // Disable hold coil sw.notifyHost = false; - PRSwitchesUpdateRule(proc,swNum, kPREventTypeSwitchOpenNondebounced, &sw, drivers, numDriverRules); + PRSwitchUpdateRule(proc,swNum, kPREventTypeSwitchOpenNondebounced, &sw, drivers, numDriverRules); } void ConfigureBumperRule (PRHandle proc, int swNum, int coilNum, int pulseTime) @@ -178,7 +188,7 @@ void ConfigureBumperRule (PRHandle proc, int swNum, int coilNum, int pulseTime) PRDriverGetState(proc, coilNum, &drivers[0]); PRDriverStatePulse(&drivers[0],pulseTime); // Pulse coil for 34ms. sw.notifyHost = false; - PRSwitchesUpdateRule(proc,swNum, kPREventTypeSwitchClosedNondebounced, &sw, drivers, numDriverRules); + PRSwitchUpdateRule(proc,swNum, kPREventTypeSwitchClosedNondebounced, &sw, drivers, numDriverRules); } void ConfigureSwitchRules(PRHandle proc) diff --git a/include/pinproc.h b/include/pinproc.h index c0aacac..71a56a2 100644 --- a/include/pinproc.h +++ b/include/pinproc.h @@ -178,25 +178,25 @@ PR_EXPORT PRResult PRDriverWatchdogTickle(PRHandle handle); /** * Changes the given #PRDriverState to reflect a disabled state. - * @note The driver state structure must be applied using PRDriverUpdateState() or linked to a switch rule using PRSwitchesUpdateRule() to have any effect. + * @note The driver state structure must be applied using PRDriverUpdateState() or linked to a switch rule using PRSwitchUpdateRule() to have any effect. */ PR_EXPORT void PRDriverStateDisable(PRDriverState *driverState); /** * Changes the given #PRDriverState to reflect a pulse state. * @param milliseconds Number of milliseconds to pulse the driver for. - * @note The driver state structure must be applied using PRDriverUpdateState() or linked to a switch rule using PRSwitchesUpdateRule() to have any effect. + * @note The driver state structure must be applied using PRDriverUpdateState() or linked to a switch rule using PRSwitchUpdateRule() to have any effect. */ PR_EXPORT void PRDriverStatePulse(PRDriverState *driverState, int milliseconds); /** * Changes the given #PRDriverState to reflect a scheduled state. * Assigns a repeating schedule to the given driver. - * @note The driver state structure must be applied using PRDriverUpdateState() or linked to a switch rule using PRSwitchesUpdateRule() to have any effect. + * @note The driver state structure must be applied using PRDriverUpdateState() or linked to a switch rule using PRSwitchUpdateRule() to have any effect. */ PR_EXPORT void PRDriverStateSchedule(PRDriverState *driverState, uint32_t schedule, uint8_t cycleSeconds, bool_t now); /** * @brief Changes the given #PRDriverState to reflect a pitter-patter schedule state. * Assigns a pitter-patter schedule (repeating on/off) to the given driver. - * @note The driver state structure must be applied using PRDriverUpdateState() or linked to a switch rule using PRSwitchesUpdateRule() to have any effect. + * @note The driver state structure must be applied using PRDriverUpdateState() or linked to a switch rule using PRSwitchUpdateRule() to have any effect. * * Use originalOnTime to pulse the driver for a number of milliseconds before the pitter-patter schedule begins. */ @@ -236,10 +236,22 @@ PR_EXPORT int PRGetEvents(PRHandle handle, PREvent *eventsOut, int maxEvents); #define kPRSwitchVirtualFirst (224) /**< Switch number of the first virtual switch. */ #define kPRSwitchVirtualLast (255) /**< Switch number of the last virtual switch. */ +typedef struct PRSwitchConfig { + bool_t clear; // Drive the clear output + uint8_t directMatrixScanLoopTime; // milliseconds + uint8_t pulsesBeforeCheckingRX; + uint8_t inactivePulsesAfterBurst; + uint8_t pulsesPerBurst; + uint8_t pulseHalfPeriodTime; // milliseconds +} PRSwitchConfig; + typedef struct PRSwitchRule { bool_t notifyHost; /**< If true this switch change event will provided to the user via PRGetEvents(). */ } PRSwitchRule; +/** Update the switch controller configurion registers */ +PR_EXPORT PRResult PRSwitchUpdateConfig(PRHandle handle, PRSwitchConfig *switchConfig); + /** * @brief Configures the handling of switch rules within P-ROC. * @@ -264,7 +276,7 @@ typedef struct PRSwitchRule { * @code * PRSwitchRule rule; * rule.notifyHost = true; - * PRSwitchesUpdateRule(handle, switchNum, kPREventTypeSwitchOpenDebounced, &rule, NULL, 0); + * PRSwitchUpdateRule(handle, switchNum, kPREventTypeSwitchOpenDebounced, &rule, NULL, 0); * @endcode * * Configuring a pop bumper switch to pulse the coil and a flash lamp for 50ms each: @@ -277,11 +289,11 @@ typedef struct PRSwitchRule { * PRDriverGetState(handle, drvFlashLamp1, &drivers[1]); * PRDriverStatePulse(&drivers[0], 50); * PRDriverStatePulse(&drivers[1], 50); - * PRSwitchesUpdateRule(handle, swPopBumper1, kPREventTypeSwitchClosedNondebounced, + * PRSwitchUpdateRule(handle, swPopBumper1, kPREventTypeSwitchClosedNondebounced, * &rule, drivers, 2); * // Now configure a switch rule to process scoring in software: * rule.notifyHost = true; - * PRSwitchesUpdateRule(handle, swPopBumper1, kPREventTypeSwitchClosedDebounced, + * PRSwitchUpdateRule(handle, swPopBumper1, kPREventTypeSwitchClosedDebounced, * &rule, NULL, 0); * @endcode * @@ -292,7 +304,7 @@ typedef struct PRSwitchRule { * @param linkedDrivers An array of #PRDriverState structures describing the driver state changes to be made when this switch rule is triggered. May be NULL if numDrivers is 0. * @param numDrivers Number of elements in the linkedDrivers array. May be zero or more. */ -PR_EXPORT PRResult PRSwitchesUpdateRule(PRHandle handle, uint8_t switchNum, PREventType eventType, PRSwitchRule *rule, PRDriverState *linkedDrivers, int numDrivers); +PR_EXPORT PRResult PRSwitchUpdateRule(PRHandle handle, uint8_t switchNum, PREventType eventType, PRSwitchRule *rule, PRDriverState *linkedDrivers, int numDrivers); /** @} */ // End of Switches & Events diff --git a/src/PRDevice.cpp b/src/PRDevice.cpp index 4ca579f..e09f343 100644 --- a/src/PRDevice.cpp +++ b/src/PRDevice.cpp @@ -211,7 +211,23 @@ PRSwitchRuleInternal *PRDevice::GetSwitchRuleByIndex(uint16_t index) return &switchRules[index]; } -PRResult PRDevice::SwitchesUpdateRule(uint8_t switchNum, PREventType eventType, PRSwitchRule *rule, PRDriverState *linkedDrivers, int numDrivers) +PRResult PRDevice::SwitchUpdateConfig(PRSwitchConfig *switchConfig) +{ + uint32_t rc; + const int burstWords = 2; + uint32_t burst[burstWords]; + + this->switchConfig = *switchConfig; + CreateSwitchUpdateConfigBurst(burst, switchConfig); + + DEBUG(PRLog("Configuring Switch Logic")); + DEBUG(PRLog("Words: %x %x\n",burst[0],burst[1])); + + rc = WriteData(burst, burstWords); + return rc; +} + +PRResult PRDevice::SwitchUpdateRule(uint8_t switchNum, PREventType eventType, PRSwitchRule *rule, PRDriverState *linkedDrivers, int numDrivers) { // Updates a single rule with the associated linked driver state changes. const int burstSize = 4; @@ -265,7 +281,7 @@ PRResult PRDevice::SwitchesUpdateRule(uint8_t switchNum, PREventType eventType, newRule->linkIndex = freeSwitchRuleIndexes.front(); freeSwitchRuleIndexes.pop(); - CreateSwitchesUpdateRulesBurst(burst, newRule); + CreateSwitchUpdateRulesBurst(burst, newRule); // Prepare for the next rule: newRule = GetSwitchRuleByIndex(newRule->linkIndex); @@ -273,7 +289,7 @@ PRResult PRDevice::SwitchesUpdateRule(uint8_t switchNum, PREventType eventType, else { newRule->linkActive = false; - CreateSwitchesUpdateRulesBurst(burst, newRule); + CreateSwitchUpdateRulesBurst(burst, newRule); } DEBUG(PRLog("Rule Words: %x %x %x %x\n", burst[0],burst[1],burst[2],burst[3])); @@ -285,7 +301,7 @@ PRResult PRDevice::SwitchesUpdateRule(uint8_t switchNum, PREventType eventType, newRule = GetSwitchRuleByIndex(firstRuleIndex); newRule->changeOutput = false; newRule->linkActive = false; - CreateSwitchesUpdateRulesBurst(burst, newRule); + CreateSwitchUpdateRulesBurst(burst, newRule); if (WriteData(burst, burstSize) == kPRSuccess) DEBUG(PRLog("Disabled successfully.\n")); else @@ -299,7 +315,7 @@ PRResult PRDevice::SwitchesUpdateRule(uint8_t switchNum, PREventType eventType, } else { - CreateSwitchesUpdateRulesBurst(burst, newRule); + CreateSwitchUpdateRulesBurst(burst, newRule); DEBUG(PRLog("Rule Words: %x %x %x %x\n", burst[0],burst[1],burst[2],burst[3])); // Write the rule: diff --git a/src/PRDevice.h b/src/PRDevice.h index b4117b2..5eb05c5 100644 --- a/src/PRDevice.h +++ b/src/PRDevice.h @@ -64,7 +64,8 @@ public: PRResult DriverGetState(uint8_t driverNum, PRDriverState *driverState); PRResult DriverUpdateState(PRDriverState *driverState); - PRResult SwitchesUpdateRule(uint8_t switchNum, PREventType eventType, PRSwitchRule *rule, PRDriverState *linkedDrivers, int numDrivers); + PRResult SwitchUpdateConfig(PRSwitchConfig *switchConfig); + PRResult SwitchUpdateRule(uint8_t switchNum, PREventType eventType, PRSwitchRule *rule, PRDriverState *linkedDrivers, int numDrivers); PRResult DriverWatchdogTickle(); @@ -137,6 +138,7 @@ protected: PRDriverState drivers[maxDrivers]; PRDMDConfig dmdConfig; + PRSwitchConfig switchConfig; PRSwitchRuleInternal switchRules[maxSwitchRules]; queue freeSwitchRuleIndexes; /**< Indexes of available switch rules. */ PRSwitchRuleInternal *GetSwitchRuleByIndex(uint16_t index); diff --git a/src/PRHardware.cpp b/src/PRHardware.cpp index ca46741..2bcf7d6 100644 --- a/src/PRHardware.cpp +++ b/src/PRHardware.cpp @@ -139,6 +139,28 @@ int32_t CreateWatchdogConfigBurst ( uint32_t * burst, bool_t watchdogExpired, return kPRSuccess; } +int32_t CreateSwitchUpdateConfigBurst ( uint32_t * burst, PRSwitchConfig *switchConfig) +{ + uint32_t addr; + uint32_t i; + + addr = 0; + burst[0] = CreateBurstCommand (P_ROC_BUS_SWITCH_CTRL_SELECT, addr, 1 ); + burst[1] = (switchConfig->clear << P_ROC_SWITCH_CONFIG_CLEAR_SHIFT) | + (switchConfig->directMatrixScanLoopTime << + P_ROC_SWITCH_CONFIG_MS_PER_DM_SCAN_LOOP_SHIFT) | + (switchConfig->pulsesBeforeCheckingRX << + P_ROC_SWITCH_CONFIG_PULSES_BEFORE_CHECKING_RX_SHIFT) | + (switchConfig->inactivePulsesAfterBurst << + P_ROC_SWITCH_CONFIG_INACTIVE_PULSES_AFTER_BURST_SHIFT) | + (switchConfig->pulsesPerBurst << + P_ROC_SWITCH_CONFIG_PULSES_PER_BURST_SHIFT) | + (switchConfig->pulseHalfPeriodTime << + P_ROC_SWITCH_CONFIG_MS_PER_PULSE_HALF_PERIOD_SHIFT); + + return kPRSuccess; +} + int16_t CreateSwitchRuleIndex(uint8_t switchNum, PREventType eventType) { uint32_t debounce = (eventType == kPREventTypeSwitchOpenDebounced) || (eventType == kPREventTypeSwitchClosedDebounced) ? 1 : 0; @@ -169,7 +191,7 @@ void ParseSwitchRuleIndex(uint16_t index, uint8_t *switchNum, PREventType *event *eventType = debounce ? kPREventTypeSwitchClosedDebounced : kPREventTypeSwitchClosedNondebounced; } -int32_t CreateSwitchesUpdateRulesBurst ( uint32_t * burst, PRSwitchRuleInternal *rule_record) { +int32_t CreateSwitchUpdateRulesBurst ( uint32_t * burst, PRSwitchRuleInternal *rule_record) { uint32_t addr = CreateSwitchRuleAddr(rule_record->switchNum, rule_record->eventType); uint32_t driver_command[3]; diff --git a/src/PRHardware.h b/src/PRHardware.h index 657b847..5f7709c 100644 --- a/src/PRHardware.h +++ b/src/PRHardware.h @@ -121,14 +121,21 @@ const uint32_t P_ROC_DRIVER_CONFIG_PATTER_ENABLE_SHIFT = 30; const uint32_t P_ROC_DRIVER_CONFIG_TABLE_DRIVER_NUM_SHIFT = 1; -const uint32_t P_ROC_SWITCH_RULE_NUM_DEBOUNCE_SHIFT = 9; -const uint32_t P_ROC_SWITCH_RULE_NUM_STATE_SHIFT = 8; -const uint32_t P_ROC_SWITCH_RULE_NUM_SWITCH_NUM_SHIFT = 0; -const uint32_t P_ROC_SWITCH_RULE_NUM_TO_ADDR_SHIFT = 2; +const uint32_t P_ROC_SWITCH_CONFIG_CLEAR_SHIFT = 31; +const uint32_t P_ROC_SWITCH_CONFIG_MS_PER_DM_SCAN_LOOP_SHIFT = 24; +const uint32_t P_ROC_SWITCH_CONFIG_PULSES_BEFORE_CHECKING_RX_SHIFT = 18; +const uint32_t P_ROC_SWITCH_CONFIG_INACTIVE_PULSES_AFTER_BURST_SHIFT = 12; +const uint32_t P_ROC_SWITCH_CONFIG_PULSES_PER_BURST_SHIFT = 6; +const uint32_t P_ROC_SWITCH_CONFIG_MS_PER_PULSE_HALF_PERIOD_SHIFT = 0; -const uint32_t P_ROC_SWITCH_RULE_NOTIFY_HOST_SHIFT = 23; -const uint32_t P_ROC_SWITCH_RULE_LINK_ACTIVE_SHIFT = 10; -const uint32_t P_ROC_SWITCH_RULE_LINK_ADDRESS_SHIFT = 11; +const uint32_t P_ROC_SWITCH_RULE_NUM_DEBOUNCE_SHIFT = 9; +const uint32_t P_ROC_SWITCH_RULE_NUM_STATE_SHIFT = 8; +const uint32_t P_ROC_SWITCH_RULE_NUM_SWITCH_NUM_SHIFT = 0; +const uint32_t P_ROC_SWITCH_RULE_NUM_TO_ADDR_SHIFT = 2; + +const uint32_t P_ROC_SWITCH_RULE_NOTIFY_HOST_SHIFT = 23; +const uint32_t P_ROC_SWITCH_RULE_LINK_ACTIVE_SHIFT = 10; +const uint32_t P_ROC_SWITCH_RULE_LINK_ADDRESS_SHIFT = 11; const uint32_t P_ROC_SWITCH_RULE_CHANGE_OUTPUT_SHIFT = 9; const uint32_t P_ROC_SWITCH_RULE_DRIVER_NUM_SHIFT = 0; @@ -160,7 +167,8 @@ uint32_t CreateBurstCommand ( uint32_t select, uint32_t addr, uint32_t num_words int32_t CreateDriverUpdateGlobalConfigBurst ( uint32_t * burst, PRDriverGlobalConfig *driver_globals); int32_t CreateDriverUpdateGroupConfigBurst ( uint32_t * burst, PRDriverGroupConfig *driver_group); int32_t CreateDriverUpdateBurst ( uint32_t * burst, PRDriverState *driver); -int32_t CreateSwitchesUpdateRulesBurst ( uint32_t * burst, PRSwitchRuleInternal *rule_record); +int32_t CreateSwitchUpdateConfigBurst ( uint32_t * burst, PRSwitchConfig *switchConfig); +int32_t CreateSwitchUpdateRulesBurst ( uint32_t * burst, PRSwitchRuleInternal *rule_record); int32_t CreateWatchdogConfigBurst ( uint32_t * burst, bool_t watchdogExpired, bool_t watchdogEnable, uint16_t watchdogResetTime); int32_t CreateDMDUpdateConfigBurst ( uint32_t * burst, PRDMDConfig *dmd_config); diff --git a/src/pinproc.cpp b/src/pinproc.cpp index 9dddd1e..91fc8f5 100644 --- a/src/pinproc.cpp +++ b/src/pinproc.cpp @@ -181,9 +181,14 @@ PR_EXPORT void PRDriverStatePatter(PRDriverState *driver, uint16_t millisecondsO // Switches -PR_EXPORT PRResult PRSwitchesUpdateRule(PRHandle handle, uint8_t switchNum, PREventType eventType, PRSwitchRule *rule, PRDriverState *linkedDrivers, int numDrivers) +PR_EXPORT PRResult PRSwitchUpdateConfig(PRHandle handle, PRSwitchConfig *switchConfig) { - return handleAsDevice->SwitchesUpdateRule(switchNum, eventType, rule, linkedDrivers, numDrivers); + return handleAsDevice->SwitchUpdateConfig(switchConfig); +} + +PR_EXPORT PRResult PRSwitchUpdateRule(PRHandle handle, uint8_t switchNum, PREventType eventType, PRSwitchRule *rule, PRDriverState *linkedDrivers, int numDrivers) +{ + return handleAsDevice->SwitchUpdateRule(switchNum, eventType, rule, linkedDrivers, numDrivers); } PR_EXPORT int32_t PRDMDUpdateConfig(PRHandle handle, PRDMDConfig *dmdConfig) From 511d5d49c4cdb843cea1846e830dbb3b2fe9c8ae Mon Sep 17 00:00:00 2001 From: Adam Preble Date: Tue, 26 May 2009 20:18:36 -0400 Subject: [PATCH 02/22] Moved libftdi-specific code to PRHardware.cpp and added abstract PRHardware*() functions. Added PRCommon.h. --- libpinproc.xcodeproj/project.pbxproj | 4 + src/PRCommon.h | 36 ++++++++ src/PRDevice.cpp | 125 ++++++--------------------- src/PRDevice.h | 12 +-- src/PRHardware.cpp | 111 ++++++++++++++++++++++++ src/PRHardware.h | 6 ++ 6 files changed, 184 insertions(+), 110 deletions(-) create mode 100644 src/PRCommon.h 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 4ca579f..e3827b5 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(); } @@ -375,112 +375,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; } @@ -561,7 +488,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) { @@ -623,7 +550,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: @@ -117,9 +110,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 ca46741..30ed6e0 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 ) { @@ -212,3 +214,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 657b847..355c529 100644 --- a/src/PRHardware.h +++ b/src/PRHardware.h @@ -169,4 +169,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_ From 8fd8939ee8304d4422d4b7473bd64474481bc0da Mon Sep 17 00:00:00 2001 From: gstellenberg Date: Tue, 26 May 2009 21:05:55 -0500 Subject: [PATCH 03/22] Added private Shutdown() method to PRDevice to disable all drivers and switch rules before Close(). --- src/PRDevice.cpp | 26 ++++++++++++++++++++++++++ src/PRDevice.h | 1 + 2 files changed, 27 insertions(+) diff --git a/src/PRDevice.cpp b/src/PRDevice.cpp index e433cc6..fb5fe48 100644 --- a/src/PRDevice.cpp +++ b/src/PRDevice.cpp @@ -37,6 +37,7 @@ PRDevice::PRDevice(PRMachineType machineType) : machineType(machineType) PRDevice::~PRDevice() { + Shutdown(); Close(); } @@ -99,6 +100,31 @@ void PRDevice::Reset() // TODO: Assign defaults based on machineType. Some may have already been done above. } +void PRDevice::Shutdown() +{ + int i; + PRDriverState driverState; + PRSwitchRule switchRule; + + // Deactivate all drivers + for (i = 0; i < maxDrivers; i++) + { + // Get each driver's current state just in case polarity was changed from the default. + DriverGetState(i, &driverState); + driverState.state = false; + DriverUpdateState(&driverState); + } + + // Deactivate all switch rules + switchRule.notifyHost = false; + for (i = kPRSwitchPhysicalFirst; i < kPRSwitchPhysicalLast; i++) + { + SwitchUpdateRule(i, kPREventTypeSwitchOpenDebounced, &switchRule, NULL, 0); + SwitchUpdateRule(i, kPREventTypeSwitchClosedDebounced, &switchRule, NULL, 0); + SwitchUpdateRule(i, kPREventTypeSwitchOpenNondebounced, &switchRule, NULL, 0); + SwitchUpdateRule(i, kPREventTypeSwitchClosedNondebounced, &switchRule, NULL, 0); + } +} int PRDevice::GetEvents(PREvent *events, int maxEvents) { diff --git a/src/PRDevice.h b/src/PRDevice.h index 1b6b3d6..3292be1 100644 --- a/src/PRDevice.h +++ b/src/PRDevice.h @@ -121,6 +121,7 @@ protected: // Local Device State + void Shutdown(); void Reset(); PRMachineType machineType; PRDriverGlobalConfig driverGlobalConfig; From 059c0965315ef758372270eef98a027d1a0c99c5 Mon Sep 17 00:00:00 2001 From: Adam Preble Date: Tue, 26 May 2009 23:36:09 -0400 Subject: [PATCH 04/22] Updated pinproctest to load switches and coils from command-line specified YAML file. Removed Makefiles. Added instructions to install yaml-cpp in /usr/local so CMake can find it (relative paths == bad). --- CMakeLists.txt | 8 +- Makefile | 23 ----- README.markdown | 10 +- examples/pinproctest/Example.yaml | 7 -- examples/pinproctest/JD.yaml | 29 ++++++ examples/pinproctest/Makefile | 30 ------ examples/pinproctest/pinproctest.cpp | 134 +++++++++++++++++++-------- libpinproc.xcodeproj/project.pbxproj | 22 +++-- src/PRHardware.cpp | 1 - 9 files changed, 147 insertions(+), 117 deletions(-) delete mode 100644 Makefile delete mode 100644 examples/pinproctest/Example.yaml create mode 100644 examples/pinproctest/JD.yaml delete mode 100644 examples/pinproctest/Makefile diff --git a/CMakeLists.txt b/CMakeLists.txt index 69639dd..e619546 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,18 +1,18 @@ cmake_minimum_required(VERSION 2.6) -#set( CMAKE_OSX_ARCHITECTURES ppc;i386 ) #Comment out if not universal binary +#set( CMAKE_OSX_ARCHITECTURES ppc;i386 ) # Uncomment for universal binary #set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ../bin) #set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ../bin) #set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ../bin) -include_directories(/usr/local/include ./include) +include_directories(/usr/local/include $ENV{EXTRA_INC}) -link_directories(/usr/local/lib) +link_directories(/usr/local/lib $ENV{EXTRA_LINK}) set(FILES src/pinproc.cpp src/PRDevice.cpp src/PRHardware.cpp) add_library(pinproc ${FILES}) add_executable(pinproctest examples/pinproctest/pinproctest.cpp) -target_link_libraries(pinproctest pinproc usb ftdi) +target_link_libraries(pinproctest pinproc usb ftdi yaml-cpp) diff --git a/Makefile b/Makefile deleted file mode 100644 index a1f8b48..0000000 --- a/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -# -# File: Makefile (for library) -# -CC=g++ -LIB=libpinproc.a -LIBDEST=./bin/ - -LIBSRC=src/pinproc.cpp src/PRDevice.cpp src/PRHardware.cpp - -LIBOBJ=$(LIBSRC:.cpp=.o) - -CXXFLAGS= - -$(LIB): $(LIBOBJ) - @echo lib Makefile - archiving $(LIB) - $(AR) r $(LIBDEST)$(LIB) $(LIBOBJ) - -.cpp.o: - @echo lib Makefile - compiling $< - $(CC) $(CXXFLAGS) -c $< -o $@ - -clean: - rm -f $(LIBOBJ) $(LIBDEST)$(LIB) diff --git a/README.markdown b/README.markdown index e92e344..a9bb1b0 100644 --- a/README.markdown +++ b/README.markdown @@ -11,14 +11,16 @@ libpinproc requires: - [libusb-0.1.12](http://libusb.wiki.sourceforge.net/): Install with the default /usr/local prefix. - [libftdi-0.16](http://www.intra2net.com/en/developer/libftdi/): Install with the default /usr/local prefix. -Once required but not right now: +The pinproctest example requires [yaml-cpp](http://code.google.com/p/yaml-cpp/). Follow the build instructions, creating the build subdirectory. After building, from the build directory, run the following commands to manually install it: -- [yaml-cpp](http://code.google.com/p/yaml-cpp/): Should be checked out in the directory two levels below libpinproc in the full source tree (at the same level as ./P-ROC) in a directory named yaml-cpp. Follow the build instructions, creating the build subdirectory. The Makefiles and other project files expect to find libyaml-cpp.a in the yaml-cpp/build/bin directory. - -We are presently experimenting with different build mechanisms. As such there are three ways to build libpinproc at this time: CMake, GNU Make, and the Xcode project (for Mac). As the preferred method is presently CMake, here's how. Before you get started, you will need CMake if you don't already have it. + sudo cp bin/libyaml-cpp.a /usr/local/lib/ + sudo mkdir /usr/local/include/yaml-cpp + sudo cp ../include/*.h /usr/local/include/yaml-cpp/ #### Building with CMake +Download and install [CMake](http://www.cmake.org/cmake/resources/software.html). Then: + cd libpinproc mkdir build; cd build cmake .. diff --git a/examples/pinproctest/Example.yaml b/examples/pinproctest/Example.yaml deleted file mode 100644 index f99a700..0000000 --- a/examples/pinproctest/Example.yaml +++ /dev/null @@ -1,7 +0,0 @@ -PRGameName: My Great Pin -PRDrivers: - 1: driver one - 2: driver two -PRSwitches: - 1: switch one - 2: switch two diff --git a/examples/pinproctest/JD.yaml b/examples/pinproctest/JD.yaml new file mode 100644 index 0000000..4c978bf --- /dev/null +++ b/examples/pinproctest/JD.yaml @@ -0,0 +1,29 @@ +# P-ROC Game Description file for Judge Dredd +PRGame: + machineType: wpc +PRFlippers: + - flipperLwR + - flipperLwL + - flipperUpR + - flipperUpL +PRBumpers: + - slingL + - slingR +PRSwitches: + flipperLwR: 1 + flipperLwL: 3 + flipperUpR: 5 + flipperUpL: 7 + slingL: 96 + slingR: 97 +PRCoils: + flipperLwRMain: 32 + flipperLwRHold: 33 + flipperLwLMain: 34 + flipperLwLHold: 35 + flipperUpRMain: 36 + flipperUpRHold: 37 + flipperUpLMain: 38 + flipperUpLHold: 39 + slingL: 70 + slingR: 71 \ No newline at end of file diff --git a/examples/pinproctest/Makefile b/examples/pinproctest/Makefile deleted file mode 100644 index 8b5ddf4..0000000 --- a/examples/pinproctest/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# -# File: Makefile for application -# -PINPROC_PATH=../.. - -CC=g++ -LDFLAGS=-L$(PINPROC_PATH)/bin -L/usr/local/lib -LIBS=-lpinproc -lusb -lftdi - -SRC=pinproctest.cpp - -CXXFLAGS=-I$(PINPROC_PATH)/include - -OBJS=$(SRC:.cpp=.o) - -EXE=pinproctest - -all: $(EXE) - -# FIXME: This makes the exe require libpinproc but not in a very graceful way. -$(EXE): $(OBJS) $(PINPROC_PATH)/bin/libpinproc.a - @echo application Makefile - linking $< - $(CC) $^ $(LDFLAGS) $(LIBS) -o $@ - -.cpp.o: - @echo application Makefile - compiling $< - $(CC) $(CXXFLAGS) -c $< -o $@ - -clean: - rm -f $(OBJS) $(EXE) diff --git a/examples/pinproctest/pinproctest.cpp b/examples/pinproctest/pinproctest.cpp index e70fbc9..4582a73 100644 --- a/examples/pinproctest/pinproctest.cpp +++ b/examples/pinproctest/pinproctest.cpp @@ -32,29 +32,14 @@ #include #include #include -#include "pinproc.h" // Include libpinproc's header. +#include "../../include/pinproc.h" // Include libpinproc's header. +#include +#include - -#define kFlipperLwRightSw (1) -#define kFlipperLwLeftSw (3) -#define kFlipperUpRightSw (5) -#define kFlipperUpLeftSw (7) - -#define kFlipperLwRightMain (32) -#define kFlipperLwLeftMain (34) -#define kFlipperUpRightMain (36) -#define kFlipperUpLeftMain (38) - -#define kFlipperLwRightHold (33) -#define kFlipperLwLeftHold (35) -#define kFlipperUpRightHold (37) -#define kFlipperUpLeftHold (39) - -#define kSlingLeftSw (96) -#define kSlingRightSw (97) - -#define kSlingLeftCoil (70) -#define kSlingRightCoil (71) +#define kFlippersSection "PRFlippers" +#define kBumpersSection "PRBumpers" +#define kCoilsSection "PRCoils" +#define kSwitchesSection "PRSwitches" #define kFlipperPulseTime (34) // 34 ms #define kBumperPulseTime (25) // 25 ms @@ -69,7 +54,42 @@ void TestLogger(const char *text) fprintf(stderr, "TEST: %s", text); } -void ConfigureDrivers(PRHandle proc) +PRResult LoadConfiguration(YAML::Node& yamlDoc, const char *yamlFilePath) +{ + try + { + std::ifstream fin(yamlFilePath); + if (fin.is_open() == false) + { + fprintf(stderr, "YAML file not found: %s\n", yamlFilePath); + return kPRFailure; + } + YAML::Parser parser(fin); + + while(parser) + { + parser.GetNextDocument(yamlDoc); + } + } + catch (YAML::ParserException& ex) + { + fprintf(stderr, "YAML parse error at line=%d col=%d: %s\n", ex.line, ex.column, ex.msg.c_str()); + return kPRFailure; + } + catch (YAML::RepresentationException& ex) + { + fprintf(stderr, "YAML representation error at line=%d col=%d: %s\n", ex.line, ex.column, ex.msg.c_str()); + return kPRFailure; + } + catch (...) + { + fprintf(stderr, "Unexpected exception while parsing YAML config.\n"); + return kPRFailure; + } + return kPRSuccess; +} + +void ConfigureDrivers(PRHandle proc, YAML::Node& yamlDoc) { int i; @@ -131,7 +151,7 @@ void ConfigureDrivers(PRHandle proc) } } -void ConfigureSwitches(PRHandle proc) +void ConfigureSwitches(PRHandle proc, YAML::Node& yamlDoc) { int i; @@ -191,17 +211,32 @@ void ConfigureBumperRule (PRHandle proc, int swNum, int coilNum, int pulseTime) PRSwitchUpdateRule(proc,swNum, kPREventTypeSwitchClosedNondebounced, &sw, drivers, numDriverRules); } -void ConfigureSwitchRules(PRHandle proc) +void ConfigureSwitchRules(PRHandle proc, YAML::Node& yamlDoc) { // WPC Flippers - ConfigureWPCFlipperSwitchRule (proc, kFlipperLwRightSw, kFlipperLwRightMain, kFlipperLwRightHold, kFlipperPulseTime); // Lower Right WPC Flipper - ConfigureWPCFlipperSwitchRule (proc, kFlipperLwLeftSw, kFlipperLwLeftMain, kFlipperLwLeftHold, kFlipperPulseTime); // Lower Left WPC Flipper - ConfigureWPCFlipperSwitchRule (proc, kFlipperUpRightSw, kFlipperUpRightMain, kFlipperUpRightHold, kFlipperPulseTime); // Upper Right WPC Flipper - ConfigureWPCFlipperSwitchRule (proc, kFlipperUpLeftSw, kFlipperUpLeftMain, kFlipperUpLeftHold, kFlipperPulseTime); // Upper Left WPC Flipper + const YAML::Node& flippers = yamlDoc[kFlippersSection]; + for (YAML::Iterator flippersIt = flippers.begin(); flippersIt != flippers.end(); ++flippersIt) + { + int swNum, coilMain, coilHold; + std::string flipperName; + *flippersIt >> flipperName; + yamlDoc[kSwitchesSection][flipperName] >> swNum; + yamlDoc[kCoilsSection][flipperName + "Main"] >> coilMain; + yamlDoc[kCoilsSection][flipperName + "Hold"] >> coilHold; + ConfigureWPCFlipperSwitchRule (proc, swNum, coilMain, coilHold, kFlipperPulseTime); + } - // WPC Slingshots - ConfigureBumperRule (proc, kSlingRightSw, kSlingRightCoil, kBumperPulseTime); // WPC Right Slingshot - ConfigureBumperRule (proc, kSlingLeftSw, kSlingLeftCoil, kBumperPulseTime); // WPC Left Slingshot + const YAML::Node& bumpers = yamlDoc[kBumpersSection]; + for (YAML::Iterator bumpersIt = bumpers.begin(); bumpersIt != bumpers.end(); ++bumpersIt) + { + int swNum, coilNum; + // WPC Slingshots + std::string bumperName; + *bumpersIt >> bumperName; + yamlDoc[kSwitchesSection][bumperName] >> swNum; + yamlDoc[kCoilsSection][bumperName] >> coilNum; + ConfigureBumperRule (proc, swNum, coilNum, kBumperPulseTime); + } } void ConfigureDMD(PRHandle proc) @@ -325,26 +360,49 @@ void sigint(int) printf("Exiting...\n"); } -int main(const char **argv, int argc) +int main(int argc, const char **argv) { // Set a signal handler so that we can exit gracefully on Ctrl-C: signal(SIGINT, sigint); + if (argc < 2) + { + fprintf(stderr, "Usage: %s \n", argv[0]); + return 1; + } + const char *yamlFilename = argv[1]; + // Assign a custom logging callback to demonstrate capturing log information from P-ROC: PRLogSetCallback(TestLogger); + + YAML::Node yamlDoc; + LoadConfiguration(yamlDoc, yamlFilename); + PRMachineType machineType = kPRMachineInvalid; + std::string machineTypeString; + yamlDoc["PRGame"]["machineType"] >> machineTypeString; + if (machineTypeString == "wpc") + machineType = kPRMachineWPC; + else if(machineTypeString == "stern") + machineType = kPRMachineStern; + else + { + fprintf(stderr, "Unknown machine type: %s\n", machineTypeString.c_str()); + return 1; + } + // Finally instantiate the P-ROC device: - PRHandle proc = PRCreate(kPRMachineWPC); + PRHandle proc = PRCreate(machineType); if (proc == kPRHandleInvalid) return 1; - + ConfigureDMD(proc); - ConfigureSwitches(proc); // Notify host for all debounced switch events. - ConfigureSwitchRules(proc); // Flippers, slingshots + ConfigureSwitches(proc, yamlDoc); // Notify host for all debounced switch events. + ConfigureSwitchRules(proc, yamlDoc); // Flippers, slingshots // Make Drivers the last thing to configure so watchdog doesn't expire // before the RunLoop begins. - ConfigureDrivers(proc); + ConfigureDrivers(proc, yamlDoc); printf("Running. Hit Ctrl-C to exit.\n"); diff --git a/libpinproc.xcodeproj/project.pbxproj b/libpinproc.xcodeproj/project.pbxproj index 4febfb7..e23674d 100644 --- a/libpinproc.xcodeproj/project.pbxproj +++ b/libpinproc.xcodeproj/project.pbxproj @@ -225,10 +225,7 @@ GCC_ENABLE_FIX_AND_CONTINUE = YES; GCC_MODEL_TUNING = G5; GCC_OPTIMIZATION_LEVEL = 0; - HEADER_SEARCH_PATHS = ( - /usr/local/include, - "../../yaml-cpp/include", - ); + HEADER_SEARCH_PATHS = /usr/local/include; INSTALL_PATH = /usr/local/lib; PRODUCT_NAME = pinproc; }; @@ -240,10 +237,7 @@ ALWAYS_SEARCH_USER_PATHS = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_MODEL_TUNING = G5; - HEADER_SEARCH_PATHS = ( - /usr/local/include, - "../../yaml-cpp/include", - ); + HEADER_SEARCH_PATHS = /usr/local/include; INSTALL_PATH = /usr/local/lib; PRODUCT_NAME = pinproc; }; @@ -284,8 +278,12 @@ GCC_ENABLE_FIX_AND_CONTINUE = YES; GCC_MODEL_TUNING = G5; GCC_OPTIMIZATION_LEVEL = 0; + HEADER_SEARCH_PATHS = /usr/local/include; INSTALL_PATH = /usr/local/bin; - OTHER_LDFLAGS = "-lftdi"; + OTHER_LDFLAGS = ( + "-lyaml-cpp", + "-lftdi", + ); PREBINDING = NO; PRODUCT_NAME = pinproctest; }; @@ -299,8 +297,12 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_MODEL_TUNING = G5; + HEADER_SEARCH_PATHS = /usr/local/include; INSTALL_PATH = /usr/local/bin; - OTHER_LDFLAGS = "-lftdi"; + OTHER_LDFLAGS = ( + "-lyaml-cpp", + "-lftdi", + ); PREBINDING = NO; PRODUCT_NAME = pinproctest; ZERO_LINK = NO; diff --git a/src/PRHardware.cpp b/src/PRHardware.cpp index 9d255bc..fd32748 100644 --- a/src/PRHardware.cpp +++ b/src/PRHardware.cpp @@ -31,7 +31,6 @@ #include "PRHardware.h" #include "PRCommon.h" -#include "pinproc.h" uint32_t CreateRegRequestWord( uint32_t select, uint32_t addr, uint32_t num_words ) { From 06442264a1ddee9d8fafcedf778435a654dea9c4 Mon Sep 17 00:00:00 2001 From: gstellenberg Date: Wed, 27 May 2009 19:10:44 -0500 Subject: [PATCH 05/22] Made PRDevice::Reset public for use in pinproctest and added a parameter to allow the disabled driver and switch rule structures to be written to the P-ROC. --- examples/pinproctest/pinproctest.cpp | 4 ++ include/pinproc.h | 5 +++ src/PRDevice.cpp | 56 ++++++++++++---------------- src/PRDevice.h | 3 +- src/pinproc.cpp | 6 +++ 5 files changed, 39 insertions(+), 35 deletions(-) diff --git a/examples/pinproctest/pinproctest.cpp b/examples/pinproctest/pinproctest.cpp index 4582a73..8e2f198 100644 --- a/examples/pinproctest/pinproctest.cpp +++ b/examples/pinproctest/pinproctest.cpp @@ -415,6 +415,10 @@ int main(int argc, const char **argv) RunLoop(proc); + // Clean up P-ROC. + printf("Disabling P-ROC drivers and switch rules...\n"); + PRReset(proc,true); // Reset the device structs and write them into the device. + // Destroy the P-ROC device handle: PRDelete(proc); proc = kPRHandleInvalid; diff --git a/include/pinproc.h b/include/pinproc.h index 71a56a2..fc791ab 100644 --- a/include/pinproc.h +++ b/include/pinproc.h @@ -90,6 +90,7 @@ typedef enum PRMachineType { PR_EXPORT PRHandle PRCreate(PRMachineType machineType); /**< Create a new P-ROC device handle. Only one handle per device may be created. This handle must be destroyed with PRDelete() when it is no longer needed. Returns #kPRHandleInvalid if an error occurred. */ PR_EXPORT void PRDelete(PRHandle handle); /**< Destroys an existing P-ROC device handle. */ +PR_EXPORT void PRReset(PRHandle handle, bool updateDevice); /**< Resets internally maintained driver and switch rule structures and optionally writes those to the P-ROC to turn off drivers and switch rules. */ /** @} */ // End of Device Creation & Deletion @@ -98,6 +99,9 @@ PR_EXPORT void PRDelete(PRHandle handle); /**< Destroys an existin * @{ */ +#define kPRDriverGroupsMax (26) /**< Number of available driver groups. */ +#define kPRDriverCount (256) /**< Total number of drivers */ + typedef struct PRDriverGlobalConfig { bool_t enableOutputs; // Formerly enable_direct_outputs bool_t globalPolarity; @@ -235,6 +239,7 @@ PR_EXPORT int PRGetEvents(PRHandle handle, PREvent *eventsOut, int maxEvents); #define kPRSwitchPhysicalLast (223) /**< Switch number of the last physical switch. */ #define kPRSwitchVirtualFirst (224) /**< Switch number of the first virtual switch. */ #define kPRSwitchVirtualLast (255) /**< Switch number of the last virtual switch. */ +#define kPRSwitchRulesCount ((kPRSwitchVirtualLast + 1) << 2) /**< Total number of available switch rules. */ typedef struct PRSwitchConfig { bool_t clear; // Drive the clear output diff --git a/src/PRDevice.cpp b/src/PRDevice.cpp index fb5fe48..ae69440 100644 --- a/src/PRDevice.cpp +++ b/src/PRDevice.cpp @@ -32,12 +32,12 @@ PRDevice::PRDevice(PRMachineType machineType) : machineType(machineType) { - Reset(); + // Reset internally maintainted driver and switch structures, but do not update the device. + Reset(false); } PRDevice::~PRDevice() { - Shutdown(); Close(); } @@ -58,34 +58,50 @@ PRDevice* PRDevice::Create(PRMachineType machineType) return NULL; } - dev->Reset(); + // Reset internally maintainted driver and switch structures, but do not update the device. + dev->Reset(false); return dev; } -void PRDevice::Reset() +void PRDevice::Reset(bool updateDevice) { bool defaultPolarity = machineType != kPRMachineWPC; int i; memset(&driverGlobalConfig, 0x00, sizeof(PRDriverGlobalConfig)); - for (i = 0; i < maxDrivers; i++) + for (i = 0; i < kPRDriverCount; i++) { PRDriverState *driver = &drivers[i]; memset(driver, 0x00, sizeof(PRDriverState)); driver->driverNum = i; driver->polarity = defaultPolarity; + if (updateDevice) DriverUpdateState(driver); } - for (i = 0; i < maxDriverGroups; i++) + for (i = 0; i < kPRDriverGroupsMax; i++) { PRDriverGroupConfig *group = &driverGroups[i]; memset(group, 0x00, sizeof(PRDriverGroupConfig)); group->groupNum = i; group->polarity = defaultPolarity; } - for (i = 0; i < maxSwitchRules; i++) + + // Create empty switch rule for clearing the rules in the device. + PRSwitchRule emptySwitchRule; + memset(&emptySwitchRule, 0x00, sizeof(PRSwitchRule)); + + for (i = 0; i < kPRSwitchRulesCount; i++) { PRSwitchRuleInternal *switchRule = &switchRules[i]; memset(switchRule, 0x00, sizeof(PRSwitchRule)); + + // Send blank rule for each event type to Device if necessary + if (updateDevice && i <= kPRSwitchPhysicalLast) { + SwitchUpdateRule(i, kPREventTypeSwitchOpenDebounced, &emptySwitchRule, NULL, 0); + SwitchUpdateRule(i, kPREventTypeSwitchClosedDebounced, &emptySwitchRule, NULL, 0); + SwitchUpdateRule(i, kPREventTypeSwitchOpenNondebounced, &emptySwitchRule, NULL, 0); + SwitchUpdateRule(i, kPREventTypeSwitchClosedNondebounced, &emptySwitchRule, NULL, 0); + } + uint16_t ruleIndex = i; ParseSwitchRuleIndex(ruleIndex, &switchRule->switchNum, &switchRule->eventType); switchRule->driver.polarity = defaultPolarity; @@ -100,32 +116,6 @@ void PRDevice::Reset() // TODO: Assign defaults based on machineType. Some may have already been done above. } -void PRDevice::Shutdown() -{ - int i; - PRDriverState driverState; - PRSwitchRule switchRule; - - // Deactivate all drivers - for (i = 0; i < maxDrivers; i++) - { - // Get each driver's current state just in case polarity was changed from the default. - DriverGetState(i, &driverState); - driverState.state = false; - DriverUpdateState(&driverState); - } - - // Deactivate all switch rules - switchRule.notifyHost = false; - for (i = kPRSwitchPhysicalFirst; i < kPRSwitchPhysicalLast; i++) - { - SwitchUpdateRule(i, kPREventTypeSwitchOpenDebounced, &switchRule, NULL, 0); - SwitchUpdateRule(i, kPREventTypeSwitchClosedDebounced, &switchRule, NULL, 0); - SwitchUpdateRule(i, kPREventTypeSwitchOpenNondebounced, &switchRule, NULL, 0); - SwitchUpdateRule(i, kPREventTypeSwitchClosedNondebounced, &switchRule, NULL, 0); - } -} - int PRDevice::GetEvents(PREvent *events, int maxEvents) { SortReturningData(); diff --git a/src/PRDevice.h b/src/PRDevice.h index 3292be1..cd4e20a 100644 --- a/src/PRDevice.h +++ b/src/PRDevice.h @@ -44,6 +44,7 @@ class PRDevice public: static PRDevice *Create(PRMachineType machineType); ~PRDevice(); + void Reset(bool updateDevice); protected: PRDevice(PRMachineType machineType); @@ -121,8 +122,6 @@ protected: // Local Device State - void Shutdown(); - void Reset(); PRMachineType machineType; PRDriverGlobalConfig driverGlobalConfig; PRDriverGroupConfig driverGroups[maxDriverGroups]; diff --git a/src/pinproc.cpp b/src/pinproc.cpp index 91fc8f5..9d57655 100644 --- a/src/pinproc.cpp +++ b/src/pinproc.cpp @@ -72,6 +72,12 @@ PR_EXPORT void PRDelete(PRHandle handle) delete (PRDevice*)handle; } +/** Resets internally maintained driver and switch rule structures and optionally writes those to the P-ROC device. */ +PR_EXPORT void PRReset(PRHandle handle, bool updateDevice) +{ + return handleAsDevice->Reset(updateDevice); +} + // Events /** Get all of the available events that have been received. */ From 1c70e5235fe008bb1591062b3bc9b50d7dbfd8bf Mon Sep 17 00:00:00 2001 From: Adam Preble Date: Wed, 27 May 2009 21:11:36 -0400 Subject: [PATCH 06/22] Updated yaml-cpp instructions to reflect new build location. --- README.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.markdown b/README.markdown index a9bb1b0..965fd17 100644 --- a/README.markdown +++ b/README.markdown @@ -11,11 +11,11 @@ libpinproc requires: - [libusb-0.1.12](http://libusb.wiki.sourceforge.net/): Install with the default /usr/local prefix. - [libftdi-0.16](http://www.intra2net.com/en/developer/libftdi/): Install with the default /usr/local prefix. -The pinproctest example requires [yaml-cpp](http://code.google.com/p/yaml-cpp/). Follow the build instructions, creating the build subdirectory. After building, from the build directory, run the following commands to manually install it: +The pinproctest example requires [yaml-cpp](http://code.google.com/p/yaml-cpp/). Follow the build instructions, creating the build subdirectory. After building, from the main source directory, run the following commands to manually install it: - sudo cp bin/libyaml-cpp.a /usr/local/lib/ + sudo cp lib/libyaml-cpp.a /usr/local/lib/ sudo mkdir /usr/local/include/yaml-cpp - sudo cp ../include/*.h /usr/local/include/yaml-cpp/ + sudo cp include/*.h /usr/local/include/yaml-cpp/ #### Building with CMake From b3b1298d23261e2051ac8e055f5c3c66ee29be84 Mon Sep 17 00:00:00 2001 From: Adam Preble Date: Wed, 27 May 2009 21:29:18 -0400 Subject: [PATCH 07/22] Reworked PRReset() and added kPRResetFlag* #defs. --- examples/pinproctest/pinproctest.cpp | 2 +- include/pinproc.h | 10 +++++++++- src/PRDevice.cpp | 14 ++++++-------- src/PRDevice.h | 2 +- src/pinproc.cpp | 4 ++-- 5 files changed, 19 insertions(+), 13 deletions(-) diff --git a/examples/pinproctest/pinproctest.cpp b/examples/pinproctest/pinproctest.cpp index 8e2f198..923f1a9 100644 --- a/examples/pinproctest/pinproctest.cpp +++ b/examples/pinproctest/pinproctest.cpp @@ -417,7 +417,7 @@ int main(int argc, const char **argv) // Clean up P-ROC. printf("Disabling P-ROC drivers and switch rules...\n"); - PRReset(proc,true); // Reset the device structs and write them into the device. + PRReset(proc, kPRResetFlagUpdateDevice); // Reset the device structs and write them into the device. // Destroy the P-ROC device handle: PRDelete(proc); diff --git a/include/pinproc.h b/include/pinproc.h index fc791ab..4cf3eeb 100644 --- a/include/pinproc.h +++ b/include/pinproc.h @@ -90,7 +90,15 @@ typedef enum PRMachineType { PR_EXPORT PRHandle PRCreate(PRMachineType machineType); /**< Create a new P-ROC device handle. Only one handle per device may be created. This handle must be destroyed with PRDelete() when it is no longer needed. Returns #kPRHandleInvalid if an error occurred. */ PR_EXPORT void PRDelete(PRHandle handle); /**< Destroys an existing P-ROC device handle. */ -PR_EXPORT void PRReset(PRHandle handle, bool updateDevice); /**< Resets internally maintained driver and switch rule structures and optionally writes those to the P-ROC to turn off drivers and switch rules. */ + +#define kPRResetFlagDefault (0) /**< Only resets state in memory and does not write changes to the device. */ +#define kPRResetFlagUpdateDevice (1) /**< Instructs PRReset() to update the device once it has reset the configuration to its defaults. */ + +/** + * @brief Resets internally maintained driver and switch rule structures. + * @param resetFlags Specify #kPRResetFlagDefault to only reset the configuration in host memory. #kPRResetFlagUpdateDevice will write the default configuration to the device, effectively disabling all drivers and switch rules. + */ +PR_EXPORT PRResult PRReset(PRHandle handle, uint32_t resetFlags); /** @} */ // End of Device Creation & Deletion diff --git a/src/PRDevice.cpp b/src/PRDevice.cpp index ae69440..1b21f65 100644 --- a/src/PRDevice.cpp +++ b/src/PRDevice.cpp @@ -33,7 +33,7 @@ PRDevice::PRDevice(PRMachineType machineType) : machineType(machineType) { // Reset internally maintainted driver and switch structures, but do not update the device. - Reset(false); + Reset(kPRResetFlagDefault); } PRDevice::~PRDevice() @@ -58,13 +58,10 @@ PRDevice* PRDevice::Create(PRMachineType machineType) return NULL; } - // Reset internally maintainted driver and switch structures, but do not update the device. - dev->Reset(false); - return dev; } -void PRDevice::Reset(bool updateDevice) +PRResult PRDevice::Reset(uint32_t resetFlags) { bool defaultPolarity = machineType != kPRMachineWPC; int i; @@ -75,7 +72,7 @@ void PRDevice::Reset(bool updateDevice) memset(driver, 0x00, sizeof(PRDriverState)); driver->driverNum = i; driver->polarity = defaultPolarity; - if (updateDevice) DriverUpdateState(driver); + if (resetFlags & kPRResetFlagUpdateDevice) DriverUpdateState(driver); } for (i = 0; i < kPRDriverGroupsMax; i++) { @@ -95,7 +92,7 @@ void PRDevice::Reset(bool updateDevice) memset(switchRule, 0x00, sizeof(PRSwitchRule)); // Send blank rule for each event type to Device if necessary - if (updateDevice && i <= kPRSwitchPhysicalLast) { + if ((resetFlags & kPRResetFlagUpdateDevice) && i <= kPRSwitchPhysicalLast) { SwitchUpdateRule(i, kPREventTypeSwitchOpenDebounced, &emptySwitchRule, NULL, 0); SwitchUpdateRule(i, kPREventTypeSwitchClosedDebounced, &emptySwitchRule, NULL, 0); SwitchUpdateRule(i, kPREventTypeSwitchOpenNondebounced, &emptySwitchRule, NULL, 0); @@ -105,7 +102,7 @@ void PRDevice::Reset(bool updateDevice) uint16_t ruleIndex = i; ParseSwitchRuleIndex(ruleIndex, &switchRule->switchNum, &switchRule->eventType); switchRule->driver.polarity = defaultPolarity; - if (switchRule->switchNum >= kPRSwitchVirtualFirst && switchRule->switchNum <= kPRSwitchVirtualLast) + if (switchRule->switchNum >= kPRSwitchVirtualFirst) // Disabled for compiler warning (always true due to data type): && switchRule->switchNum <= kPRSwitchVirtualLast) freeSwitchRuleIndexes.push(ruleIndex); } @@ -114,6 +111,7 @@ void PRDevice::Reset(bool updateDevice) num_collected_bytes = 0; // TODO: Assign defaults based on machineType. Some may have already been done above. + return kPRSuccess; } int PRDevice::GetEvents(PREvent *events, int maxEvents) diff --git a/src/PRDevice.h b/src/PRDevice.h index cd4e20a..128598c 100644 --- a/src/PRDevice.h +++ b/src/PRDevice.h @@ -44,7 +44,7 @@ class PRDevice public: static PRDevice *Create(PRMachineType machineType); ~PRDevice(); - void Reset(bool updateDevice); + PRResult Reset(uint32_t resetFlags); protected: PRDevice(PRMachineType machineType); diff --git a/src/pinproc.cpp b/src/pinproc.cpp index 9d57655..2617236 100644 --- a/src/pinproc.cpp +++ b/src/pinproc.cpp @@ -73,9 +73,9 @@ PR_EXPORT void PRDelete(PRHandle handle) } /** Resets internally maintained driver and switch rule structures and optionally writes those to the P-ROC device. */ -PR_EXPORT void PRReset(PRHandle handle, bool updateDevice) +PR_EXPORT PRResult PRReset(PRHandle handle, uint32_t resetFlags) { - return handleAsDevice->Reset(updateDevice); + return handleAsDevice->Reset(resetFlags); } // Events From 1b9865da788b92c6aeda35383047097766ec2ce6 Mon Sep 17 00:00:00 2001 From: gstellenberg Date: Thu, 28 May 2009 18:50:53 -0500 Subject: [PATCH 08/22] Added switch statement to change setup of driver globals and groups between WPC and Stern. Also changed the order of the WPC drivers to better match the order in game manuals --- examples/pinproctest/pinproctest.cpp | 63 ++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 18 deletions(-) diff --git a/examples/pinproctest/pinproctest.cpp b/examples/pinproctest/pinproctest.cpp index 923f1a9..15e7a4f 100644 --- a/examples/pinproctest/pinproctest.cpp +++ b/examples/pinproctest/pinproctest.cpp @@ -89,24 +89,50 @@ PRResult LoadConfiguration(YAML::Node& yamlDoc, const char *yamlFilePath) return kPRSuccess; } -void ConfigureDrivers(PRHandle proc, YAML::Node& yamlDoc) +void ConfigureDrivers(PRHandle proc, PRMachineType machineType, YAML::Node& yamlDoc) { int i; + int mappedDriverGroupEnableIndex[kPRDriverGroupsMax]; + int mappedWPCDriverGroupEnableIndex[] = {0, 0, 0, 0, 0, 4, 3, 2, 1, 5, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0}; + int rowEnableIndex1; + int rowEnableIndex0; + bool tickleSternWatchdog; + bool globalPolarity; + bool activeLowMatrixRows; + int driverLoopTime; + int watchdogResetTime; + int slowGroupTime; + + switch (machineType) + { + case kPRMachineWPC: { + memcpy(mappedDriverGroupEnableIndex,mappedWPCDriverGroupEnableIndex, sizeof(mappedDriverGroupEnableIndex)); + rowEnableIndex1 = 6; // Unused in WPC + rowEnableIndex0 = 6; + tickleSternWatchdog = false; + globalPolarity = false; + activeLowMatrixRows = true; + driverLoopTime = 4; // milliseconds + watchdogResetTime = 1000; // milliseconds + slowGroupTime = driverLoopTime * 100; // microseconds + break; + } + } PRDriverGlobalConfig globals; globals.enableOutputs = false; - globals.globalPolarity = false; + globals.globalPolarity = globalPolarity; globals.useClear = false; globals.strobeStartSelect = false; - globals.startStrobeTime = 4; // milliseconds per output loop - globals.matrixRowEnableIndex1 = 12; - globals.matrixRowEnableIndex0 = 6; - globals.activeLowMatrixRows = true; - globals.tickleSternWatchdog = false; + globals.startStrobeTime = driverLoopTime; // milliseconds per output loop + globals.matrixRowEnableIndex1 = rowEnableIndex1; + globals.matrixRowEnableIndex0 = rowEnableIndex0; + globals.activeLowMatrixRows = activeLowMatrixRows; + globals.tickleSternWatchdog = tickleSternWatchdog; globals.encodeEnables = false; globals.watchdogExpired = false; globals.watchdogEnable = true; - globals.watchdogResetTime = 1000; // milliseconds + globals.watchdogResetTime = watchdogResetTime; // We want to start up safely, so we'll update the global driver config twice. // When we toggle enableOutputs like this P-ROC will reset the polarity: @@ -120,13 +146,14 @@ void ConfigureDrivers(PRHandle proc, YAML::Node& yamlDoc) // Configure the groups. Each group corresponds to 8 consecutive drivers, starting // with driver #32. The following 6 groups are configured for coils/flashlamps. + PRDriverGroupConfig group; - for (i = 0; i < 6; i++) + for (i = 4; i < 10; i++) { - PRDriverGetGroupConfig(proc, i + 4, &group); + PRDriverGetGroupConfig(proc, i, &group); group.slowTime = 0; - group.enableIndex = i; - group.rowActivateIndex = i; + group.enableIndex = mappedDriverGroupEnableIndex[i]; + group.rowActivateIndex = 0; group.rowEnableSelect = 0; group.matrixed = false; group.polarity = false; @@ -137,11 +164,11 @@ void ConfigureDrivers(PRHandle proc, YAML::Node& yamlDoc) } // The following 8 groups are configured for the feature lamp matrix. - for (i = 6; i < 14; i++) { - PRDriverGetGroupConfig(proc, i + 4, &group); - group.slowTime = 400; - group.enableIndex = 7; - group.rowActivateIndex = i - 6; + for (i = 10; i < 18; i++) { + PRDriverGetGroupConfig(proc, i, &group); + group.slowTime = slowGroupTime; + group.enableIndex = mappedDriverGroupEnableIndex[i]; + group.rowActivateIndex = i - 10; group.rowEnableSelect = 0; group.matrixed = 1; group.polarity = 0; @@ -402,7 +429,7 @@ int main(int argc, const char **argv) // Make Drivers the last thing to configure so watchdog doesn't expire // before the RunLoop begins. - ConfigureDrivers(proc, yamlDoc); + ConfigureDrivers(proc, machineType, yamlDoc); printf("Running. Hit Ctrl-C to exit.\n"); From e2ee7897937d999e9e664d40f3b2cd61a3f89142 Mon Sep 17 00:00:00 2001 From: Adam Preble Date: Thu, 28 May 2009 23:40:06 -0400 Subject: [PATCH 09/22] Added time information to switch printf()s. Made vars in DMD update routine more descriptive. ConfigureSwitches() no longer sets everything to notifyHost=true. --- examples/pinproctest/pinproctest.cpp | 46 +++++++++++++++------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/examples/pinproctest/pinproctest.cpp b/examples/pinproctest/pinproctest.cpp index 923f1a9..af548bf 100644 --- a/examples/pinproctest/pinproctest.cpp +++ b/examples/pinproctest/pinproctest.cpp @@ -35,6 +35,7 @@ #include "../../include/pinproc.h" // Include libpinproc's header. #include #include +#include #define kFlippersSection "PRFlippers" #define kBumpersSection "PRBumpers" @@ -153,8 +154,6 @@ void ConfigureDrivers(PRHandle proc, YAML::Node& yamlDoc) void ConfigureSwitches(PRHandle proc, YAML::Node& yamlDoc) { - int i; - // Configure switch controller registers (if the defaults aren't acceptable) PRSwitchConfig switchConfig; switchConfig.clear = false; @@ -164,15 +163,6 @@ void ConfigureSwitches(PRHandle proc, YAML::Node& yamlDoc) switchConfig.pulsesPerBurst = 6; switchConfig.pulseHalfPeriodTime = 13; // milliseconds PRSwitchUpdateConfig(proc, &switchConfig); - - // Configures rules to notify the host for every debounced switch event. - for (i = 0; i <= kPRSwitchPhysicalLast; i++) - { - PRSwitchRule sw; - sw.notifyHost = true; - PRSwitchUpdateRule(proc, i, kPREventTypeSwitchClosedDebounced, &sw, NULL, 0); - PRSwitchUpdateRule(proc, i, kPREventTypeSwitchOpenDebounced, &sw, NULL, 0); - } } void ConfigureWPCFlipperSwitchRule (PRHandle proc, int swNum, int mainCoilNum, int holdCoilNum, int pulseTime) @@ -187,7 +177,9 @@ void ConfigureWPCFlipperSwitchRule (PRHandle proc, int swNum, int mainCoilNum, i PRDriverGetState(proc, holdCoilNum, &drivers[1]); PRDriverStatePulse(&drivers[1],0); // Turn on indefintely (set pulse for 0ms) sw.notifyHost = false; - PRSwitchUpdateRule(proc,swNum, kPREventTypeSwitchClosedNondebounced, &sw, drivers, numDriverRules); + PRSwitchUpdateRule(proc, swNum, kPREventTypeSwitchClosedNondebounced, &sw, drivers, numDriverRules); + sw.notifyHost = true; + PRSwitchUpdateRule(proc, swNum, kPREventTypeSwitchClosedDebounced, &sw, drivers, numDriverRules); // Flipper off rules PRDriverGetState(proc, mainCoilNum, &drivers[0]); @@ -195,7 +187,9 @@ void ConfigureWPCFlipperSwitchRule (PRHandle proc, int swNum, int mainCoilNum, i PRDriverGetState(proc, holdCoilNum, &drivers[1]); PRDriverStateDisable(&drivers[1]); // Disable hold coil sw.notifyHost = false; - PRSwitchUpdateRule(proc,swNum, kPREventTypeSwitchOpenNondebounced, &sw, drivers, numDriverRules); + PRSwitchUpdateRule(proc, swNum, kPREventTypeSwitchOpenNondebounced, &sw, drivers, numDriverRules); + sw.notifyHost = true; + PRSwitchUpdateRule(proc, swNum, kPREventTypeSwitchOpenDebounced, &sw, drivers, numDriverRules); } void ConfigureBumperRule (PRHandle proc, int swNum, int coilNum, int pulseTime) @@ -208,7 +202,9 @@ void ConfigureBumperRule (PRHandle proc, int swNum, int coilNum, int pulseTime) PRDriverGetState(proc, coilNum, &drivers[0]); PRDriverStatePulse(&drivers[0],pulseTime); // Pulse coil for 34ms. sw.notifyHost = false; - PRSwitchUpdateRule(proc,swNum, kPREventTypeSwitchClosedNondebounced, &sw, drivers, numDriverRules); + PRSwitchUpdateRule(proc, swNum, kPREventTypeSwitchClosedNondebounced, &sw, drivers, numDriverRules); + sw.notifyHost = true; + PRSwitchUpdateRule(proc, swNum, kPREventTypeSwitchClosedDebounced, &sw, drivers, numDriverRules); } void ConfigureSwitchRules(PRHandle proc, YAML::Node& yamlDoc) @@ -271,7 +267,7 @@ void ConfigureDMD(PRHandle proc) // starting with dim dots at the top. void UpdateDots( unsigned char * dots, unsigned int dotOffset ) { - int i,j,k,color,mappedColor,loopCtr,byte_shifter; + int row,col,subFrame,color,mappedColor,loopCtr,byte_shifter; const int rate_reduction_divisor = 1; loopCtr = dotOffset/rate_reduction_divisor; @@ -288,33 +284,34 @@ void UpdateDots( unsigned char * dots, unsigned int dotOffset ) memset(dots,0,((kDMDColumns*kDMDRows)/8)*kDMDSubFrames); // Loop through all of the rows - for (i = kDMDRows - 1; i >= 0; i--) + for (row = kDMDRows - 1; row >= 0; row--) { // Map the color index to the DMD's physical color map int mappedColors[] = {0, 2, 8, 10, 1, 3, 9, 11, 4, 6, 12, 14, 5, 7, 13, 15}; mappedColor = mappedColors[color]; // Loop through each of 16 bytes in a row - for (j = 0; j < kDMDColumns / 8; j++) + for (col = 0; col < kDMDColumns / 8; col++) { // Loop through each subframe - for (k = 0; k < kDMDSubFrames; k++) + for (subFrame = 0; subFrame < kDMDSubFrames; subFrame++) { // Turn on the byte in each sub-frame that's enabled // active for the color code. - if ((mappedColor >> k) & 1 == 1) - dots[k*(kDMDColumns*kDMDRows/8)+((i%kDMDRows)*(kDMDColumns / 8))+j] = byte_shifter; + if ((mappedColor >> subFrame) & 1 == 1) + dots[subFrame*(kDMDColumns*kDMDRows/8)+((row%kDMDRows)*(kDMDColumns / 8))+col] = byte_shifter; } } // Determine where to change the color in order to progress from row 0 = color 0 // to the last row being the last color. - if (i % (int)((kDMDRows/pow(2,kDMDSubFrames))) == 0) color--; + if (row % (int)((kDMDRows/pow(2,kDMDSubFrames))) == 0) color--; if (byte_shifter == 1) byte_shifter = 0x80; else byte_shifter = byte_shifter >> 1; } } } +time_t startTime; bool runLoopRun = true; void RunLoop(PRHandle proc) @@ -347,7 +344,9 @@ void RunLoop(PRHandle proc) case kPREventTypeSwitchOpenNondebounced: stateText = "open(ndb)"; break; case kPREventTypeSwitchClosedNondebounced: stateText = "closed(ndb)"; break; } - printf("switch % 3d: %s\n", event->value, stateText); + struct timeval tv; + gettimeofday(&tv, NULL); + printf("%d.%03d switch % 3d: %s\n", tv.tv_sec-startTime, tv.tv_usec/1000, event->value, stateText); } usleep(10*1000); // Sleep for 10ms so we aren't pegging the CPU. } @@ -364,6 +363,7 @@ int main(int argc, const char **argv) { // Set a signal handler so that we can exit gracefully on Ctrl-C: signal(SIGINT, sigint); + startTime = time(NULL); if (argc < 2) { @@ -396,6 +396,8 @@ int main(int argc, const char **argv) if (proc == kPRHandleInvalid) return 1; + PRReset(proc, kPRResetFlagUpdateDevice); // Reset the device structs and write them into the device. + ConfigureDMD(proc); ConfigureSwitches(proc, yamlDoc); // Notify host for all debounced switch events. ConfigureSwitchRules(proc, yamlDoc); // Flippers, slingshots From 9b1765e94c3c0500d050ca98038037c9df7f77b8 Mon Sep 17 00:00:00 2001 From: Adam Preble Date: Thu, 28 May 2009 23:43:23 -0400 Subject: [PATCH 10/22] Reworked PRReset() logic with respect to switch rules. --- include/pinproc.h | 3 ++- src/PRDevice.cpp | 30 ++++++++++++++++++------------ 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/include/pinproc.h b/include/pinproc.h index 4cf3eeb..24b7540 100644 --- a/include/pinproc.h +++ b/include/pinproc.h @@ -247,7 +247,8 @@ PR_EXPORT int PRGetEvents(PRHandle handle, PREvent *eventsOut, int maxEvents); #define kPRSwitchPhysicalLast (223) /**< Switch number of the last physical switch. */ #define kPRSwitchVirtualFirst (224) /**< Switch number of the first virtual switch. */ #define kPRSwitchVirtualLast (255) /**< Switch number of the last virtual switch. */ -#define kPRSwitchRulesCount ((kPRSwitchVirtualLast + 1) << 2) /**< Total number of available switch rules. */ +#define kPRSwitchCount (256) +#define kPRSwitchRulesCount (kPRSwitchCount << 2) /**< Total number of available switch rules. */ typedef struct PRSwitchConfig { bool_t clear; // Drive the clear output diff --git a/src/PRDevice.cpp b/src/PRDevice.cpp index 1b21f65..272f77f 100644 --- a/src/PRDevice.cpp +++ b/src/PRDevice.cpp @@ -82,29 +82,35 @@ PRResult PRDevice::Reset(uint32_t resetFlags) group->polarity = defaultPolarity; } - // Create empty switch rule for clearing the rules in the device. - PRSwitchRule emptySwitchRule; - memset(&emptySwitchRule, 0x00, sizeof(PRSwitchRule)); - + freeSwitchRuleIndexes.empty(); + for (i = 0; i < kPRSwitchRulesCount; i++) { PRSwitchRuleInternal *switchRule = &switchRules[i]; memset(switchRule, 0x00, sizeof(PRSwitchRule)); - // Send blank rule for each event type to Device if necessary - if ((resetFlags & kPRResetFlagUpdateDevice) && i <= kPRSwitchPhysicalLast) { - SwitchUpdateRule(i, kPREventTypeSwitchOpenDebounced, &emptySwitchRule, NULL, 0); - SwitchUpdateRule(i, kPREventTypeSwitchClosedDebounced, &emptySwitchRule, NULL, 0); - SwitchUpdateRule(i, kPREventTypeSwitchOpenNondebounced, &emptySwitchRule, NULL, 0); - SwitchUpdateRule(i, kPREventTypeSwitchClosedNondebounced, &emptySwitchRule, NULL, 0); - } - uint16_t ruleIndex = i; ParseSwitchRuleIndex(ruleIndex, &switchRule->switchNum, &switchRule->eventType); switchRule->driver.polarity = defaultPolarity; if (switchRule->switchNum >= kPRSwitchVirtualFirst) // Disabled for compiler warning (always true due to data type): && switchRule->switchNum <= kPRSwitchVirtualLast) freeSwitchRuleIndexes.push(ruleIndex); } + + // Create empty switch rule for clearing the rules in the device. + PRSwitchRule emptySwitchRule; + memset(&emptySwitchRule, 0x00, sizeof(PRSwitchRule)); + + for (i = 0; i < kPRSwitchCount; i++) + { + // Send blank rule for each event type to Device if necessary + if ((resetFlags & kPRResetFlagUpdateDevice) && i <= kPRSwitchPhysicalLast) + { + SwitchUpdateRule(i, kPREventTypeSwitchOpenDebounced, &emptySwitchRule, NULL, 0); + SwitchUpdateRule(i, kPREventTypeSwitchClosedDebounced, &emptySwitchRule, NULL, 0); + SwitchUpdateRule(i, kPREventTypeSwitchOpenNondebounced, &emptySwitchRule, NULL, 0); + SwitchUpdateRule(i, kPREventTypeSwitchClosedNondebounced, &emptySwitchRule, NULL, 0); + } + } unrequestedDataQueue.empty(); requestedDataQueue.empty(); From 8d65a9a35223e89dce92372cb690603899927767 Mon Sep 17 00:00:00 2001 From: Gerry Stellenberg Date: Thu, 28 May 2009 22:54:06 -0500 Subject: [PATCH 11/22] Changed WPC coil mappings --- examples/pinproctest/pinproctest.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/examples/pinproctest/pinproctest.cpp b/examples/pinproctest/pinproctest.cpp index 15e7a4f..12eb92c 100644 --- a/examples/pinproctest/pinproctest.cpp +++ b/examples/pinproctest/pinproctest.cpp @@ -93,7 +93,13 @@ void ConfigureDrivers(PRHandle proc, PRMachineType machineType, YAML::Node& yaml { int i; int mappedDriverGroupEnableIndex[kPRDriverGroupsMax]; - int mappedWPCDriverGroupEnableIndex[] = {0, 0, 0, 0, 0, 4, 3, 2, 1, 5, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0}; + + // This mapping determines which enable line is driven for each group of 8 outputs, + // starting with output 0-7. The first 4 groups are not used in WPC. + // The next 6 correspond to coil/flasher circuits. The next 8 correspond to the + // lamp matrix. The last 8 are unused. + int mappedWPCDriverGroupEnableIndex[] = {0, 0, 0, 0, 0, 2, 4, 3, 1, 5, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0}; + int rowEnableIndex1; int rowEnableIndex0; bool tickleSternWatchdog; @@ -117,6 +123,8 @@ void ConfigureDrivers(PRHandle proc, PRMachineType machineType, YAML::Node& yaml slowGroupTime = driverLoopTime * 100; // microseconds break; } + + // TODO: Add kPRMachineStern } PRDriverGlobalConfig globals; @@ -436,7 +444,7 @@ int main(int argc, const char **argv) // Pulse a coil for testing purposes. //PRDriverPulse(proc, 53, 100); // Schedule a feature lamp for testing purposes. - //PRDriverSchedule(proc, 80, 0xFF00FF00, 0, 0); + PRDriverSchedule(proc, 80, 0xFF00FF00, 0, 0); // Pitter-patter a feature lamp for testing purposes. //PRDriverPatter(proc, 84, 127, 127, 0); From 1cf8101b19b0e3b746ca4659ee663b7870a19ac1 Mon Sep 17 00:00:00 2001 From: gstellenberg Date: Thu, 28 May 2009 23:05:58 -0500 Subject: [PATCH 12/22] Changed WPC coil mappings again. Previous change lost in a merge --- examples/pinproctest/pinproctest.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/examples/pinproctest/pinproctest.cpp b/examples/pinproctest/pinproctest.cpp index 815a04e..1e368df 100644 --- a/examples/pinproctest/pinproctest.cpp +++ b/examples/pinproctest/pinproctest.cpp @@ -94,13 +94,7 @@ void ConfigureDrivers(PRHandle proc, PRMachineType machineType, YAML::Node& yaml { int i; int mappedDriverGroupEnableIndex[kPRDriverGroupsMax]; - - // This mapping determines which enable line is driven for each group of 8 outputs, - // starting with output 0-7. The first 4 groups are not used in WPC. - // The next 6 correspond to coil/flasher circuits. The next 8 correspond to the - // lamp matrix. The last 8 are unused. int mappedWPCDriverGroupEnableIndex[] = {0, 0, 0, 0, 0, 2, 4, 3, 1, 5, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0}; - int rowEnableIndex1; int rowEnableIndex0; bool tickleSternWatchdog; @@ -124,8 +118,6 @@ void ConfigureDrivers(PRHandle proc, PRMachineType machineType, YAML::Node& yaml slowGroupTime = driverLoopTime * 100; // microseconds break; } - - // TODO: Add kPRMachineStern } PRDriverGlobalConfig globals; @@ -446,7 +438,7 @@ int main(int argc, const char **argv) // Pulse a coil for testing purposes. //PRDriverPulse(proc, 53, 100); // Schedule a feature lamp for testing purposes. - PRDriverSchedule(proc, 80, 0xFF00FF00, 0, 0); + //PRDriverSchedule(proc, 80, 0xFF00FF00, 0, 0); // Pitter-patter a feature lamp for testing purposes. //PRDriverPatter(proc, 84, 127, 127, 0); From dc8ec90ab5bc9efea48c7bf49dfab498a35369fd Mon Sep 17 00:00:00 2001 From: gstellenberg Date: Thu, 28 May 2009 23:16:06 -0500 Subject: [PATCH 13/22] Changed slingshot coil numbers to reflect updated WPC mappings --- examples/pinproctest/JD.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/pinproctest/JD.yaml b/examples/pinproctest/JD.yaml index 4c978bf..ef1c186 100644 --- a/examples/pinproctest/JD.yaml +++ b/examples/pinproctest/JD.yaml @@ -25,5 +25,5 @@ PRCoils: flipperUpRHold: 37 flipperUpLMain: 38 flipperUpLHold: 39 - slingL: 70 - slingR: 71 \ No newline at end of file + slingL: 54 + slingR: 55 From 375f2f4005c7ad3d36975b7476c44e3857145d4a Mon Sep 17 00:00:00 2001 From: gstellenberg Date: Fri, 29 May 2009 12:05:25 -0500 Subject: [PATCH 14/22] Implement ganged writes to improve USB utilization --- src/PRDevice.cpp | 51 ++++++++++++++++++++++++++++++++++++++---------- src/PRDevice.h | 11 +++++++++++ 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/src/PRDevice.cpp b/src/PRDevice.cpp index 272f77f..9e6f541 100644 --- a/src/PRDevice.cpp +++ b/src/PRDevice.cpp @@ -115,6 +115,7 @@ PRResult PRDevice::Reset(uint32_t resetFlags) unrequestedDataQueue.empty(); requestedDataQueue.empty(); num_collected_bytes = 0; + numPreparedWriteWords = 0; // TODO: Assign defaults based on machineType. Some may have already been done above. return kPRSuccess; @@ -159,7 +160,7 @@ PRResult PRDevice::DriverUpdateGlobalConfig(PRDriverGlobalConfig *driverGlobalCo DEBUG(PRLog("Driver Global words: %x %x\n", burst[0], burst[1])); DEBUG(PRLog("Watchdog words: %x %x\n", burst[2], burst[3])); - return WriteData(burst, burstWords); + return PrepareWriteData(burst, burstWords); } PRResult PRDevice::DriverGetGroupConfig(uint8_t groupNum, PRDriverGroupConfig *driverGroupConfig) @@ -179,7 +180,7 @@ PRResult PRDevice::DriverUpdateGroupConfig(PRDriverGroupConfig *driverGroupConfi rc = CreateDriverUpdateGroupConfigBurst(burst, driverGroupConfig); DEBUG(PRLog("Words: %x %x\n", burst[0], burst[1])); - return WriteData(burst, burstWords); + return PrepareWriteData(burst, burstWords); } PRResult PRDevice::DriverGetState(uint8_t driverNum, PRDriverState *driverState) @@ -207,7 +208,7 @@ PRResult PRDevice::DriverUpdateState(PRDriverState *driverState) rc = CreateDriverUpdateBurst(burst, &drivers[driverState->driverNum]); DEBUG(PRLog("Words: %x %x %x\n", burst[0], burst[1], burst[2])); - return WriteData(burst, burstWords); + return PrepareWriteData(burst, burstWords); } @@ -221,7 +222,7 @@ PRResult PRDevice::DriverWatchdogTickle() driverGlobalConfig.watchdogEnable, driverGlobalConfig.watchdogResetTime); - return WriteData(burst, burstWords); + return PrepareWriteData(burst, burstWords); } @@ -243,7 +244,7 @@ PRResult PRDevice::SwitchUpdateConfig(PRSwitchConfig *switchConfig) DEBUG(PRLog("Configuring Switch Logic")); DEBUG(PRLog("Words: %x %x\n",burst[0],burst[1])); - rc = WriteData(burst, burstWords); + rc = PrepareWriteData(burst, burstWords); return rc; } @@ -314,7 +315,7 @@ PRResult PRDevice::SwitchUpdateRule(uint8_t switchNum, PREventType eventType, PR DEBUG(PRLog("Rule Words: %x %x %x %x\n", burst[0],burst[1],burst[2],burst[3])); // Write the rule: - res = WriteData(burst, burstSize); + res = PrepareWriteData(burst, burstSize); if (res != kPRSuccess) { DEBUG(PRLog("Error while writing switch update, attempting to revert switch rule to a safe state...")); @@ -322,7 +323,7 @@ PRResult PRDevice::SwitchUpdateRule(uint8_t switchNum, PREventType eventType, PR newRule->changeOutput = false; newRule->linkActive = false; CreateSwitchUpdateRulesBurst(burst, newRule); - if (WriteData(burst, burstSize) == kPRSuccess) + if (PrepareWriteData(burst, burstSize) == kPRSuccess) DEBUG(PRLog("Disabled successfully.\n")); else DEBUG(PRLog("Failed to disable.\n")); @@ -339,7 +340,7 @@ PRResult PRDevice::SwitchUpdateRule(uint8_t switchNum, PREventType eventType, PR DEBUG(PRLog("Rule Words: %x %x %x %x\n", burst[0],burst[1],burst[2],burst[3])); // Write the rule: - res = WriteData(burst, burstSize); + res = PrepareWriteData(burst, burstSize); } return res; @@ -358,7 +359,7 @@ int32_t PRDevice::DMDUpdateConfig(PRDMDConfig *dmdConfig) DEBUG(PRLog("Words: %x %x %x %x %x %x %x\n",burst[0],burst[1],burst[2],burst[3], burst[4],burst[5],burst[6])); - rc = WriteData(burst, burstWords); + rc = PrepareWriteData(burst, burstWords); return rc; } @@ -379,7 +380,7 @@ PRResult PRDevice::DMDDraw(uint8_t * dots) dmd_command_buffer[k+1] = p_dmd_frame_buffer_words[k]; } - return WriteData(dmd_command_buffer, words_per_frame+1); + return PrepareWriteData(dmd_command_buffer, words_per_frame+1); // The following code prints out the init lines for the 4 Xilinx BlockRAMs // in the FPGA. It's used to make an image for the P-ROC to display on power-up. @@ -497,6 +498,36 @@ PRResult PRDevice::RequestData(uint32_t module_select, uint32_t start_addr, int3 return WriteData(&requestWord, 1); } +PRResult PRDevice::PrepareWriteData(uint32_t * words, int32_t numWords) +{ + if (numWords > maxWriteWords) + { + DEBUG(PRLog("%d words Exceeds write capabilities. Restrict write requests to %d words.", numWords, maxWriteWords)); + return kPRFailure; + } + + // If there are already some words prepared to be written and the addition of the new + // words will be too many, flush the currently prepared words to the P-ROC now. + if (numPreparedWriteWords + numWords > maxWriteWords) + { + if (FlushWriteData() == kPRFailure); + return kPRFailure; + } + + memcpy(preparedWriteWords + numPreparedWriteWords, words, numWords * 4); + numPreparedWriteWords += numWords; + + return kPRSuccess; +} + +PRResult PRDevice::FlushWriteData() +{ + PRResult res; + res = WriteData(preparedWriteWords, numPreparedWriteWords); + numPreparedWriteWords = 0; // Reset word counter + return res; +} + PRResult PRDevice::WriteData(uint32_t * words, int32_t numWords) { int32_t j,k; diff --git a/src/PRDevice.h b/src/PRDevice.h index 128598c..4099c23 100644 --- a/src/PRDevice.h +++ b/src/PRDevice.h @@ -38,6 +38,7 @@ using namespace std; #define maxDriverGroups (26) #define maxDrivers (256) #define maxSwitchRules (256<<2) // 8 bits of switchNum indicies plus bits for debounced and state. +#define maxWriteWords (1536) // Hardware supports 2048 word bursts, but restrict to 1536 for margin. class PRDevice { @@ -76,6 +77,13 @@ protected: PRResult VerifyChipID(); // Raw write and read methods + // + + /** Schedules data to be written to the P-ROC. */ + PRResult PrepareWriteData(uint32_t * buffer, int32_t numWords); + + /** Initiates a burst write of all data scheduled to be written to the P-ROC. */ + PRResult FlushWriteData(); /** Writes data to P-ROC. * Returns #kPFailure if the number of words read does not match the number requested. @@ -112,6 +120,9 @@ 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(). */ + uint32_t preparedWriteWords[maxWriteWords]; + int32_t numPreparedWriteWords; + uint8_t collected_bytes_fifo[FTDI_BUFFER_SIZE]; int32_t collected_bytes_rd_addr; int32_t collected_bytes_wr_addr; From 183046ce8c3afc4e1c7cfc8c24b91ba331aabbbb Mon Sep 17 00:00:00 2001 From: gstellenberg Date: Fri, 29 May 2009 12:13:53 -0500 Subject: [PATCH 15/22] Added PRFlushWriteData --- src/pinproc.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/pinproc.cpp b/src/pinproc.cpp index 2617236..8ed6d80 100644 --- a/src/pinproc.cpp +++ b/src/pinproc.cpp @@ -78,6 +78,14 @@ PR_EXPORT PRResult PRReset(PRHandle handle, uint32_t resetFlags) return handleAsDevice->Reset(resetFlags); } +// I/O + +/** Flush all pending write data out to the P-ROC */ +PR_EXPORT PRResult PRFlushWriteData(PRHandle handle) +{ + return handleAsDevice->FlushWriteData(); +} + // Events /** Get all of the available events that have been received. */ @@ -86,7 +94,6 @@ PR_EXPORT int PRGetEvents(PRHandle handle, PREvent *eventsOut, int maxEvents) return handleAsDevice->GetEvents(eventsOut, maxEvents); } - // Drivers PR_EXPORT PRResult PRDriverUpdateGlobalConfig(PRHandle handle, PRDriverGlobalConfig *driverGlobalConfig) { From c080334515bd7262e033059564694d52347af8df Mon Sep 17 00:00:00 2001 From: gstellenberg Date: Fri, 29 May 2009 12:13:58 -0500 Subject: [PATCH 16/22] Added PRFlushWriteData --- include/pinproc.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/pinproc.h b/include/pinproc.h index 24b7540..c99f215 100644 --- a/include/pinproc.h +++ b/include/pinproc.h @@ -102,6 +102,11 @@ PR_EXPORT PRResult PRReset(PRHandle handle, uint32_t resetFlags); /** @} */ // End of Device Creation & Deletion +// I/O + +/** Flush all pending write data out to the P-ROC */ +PR_EXPORT PRResult PRFlushWriteData(PRHandle handle); + // Drivers /** @defgroup drivers Driver Manipulation * @{ From a8f8e1782413dccb3cf0714d0a9a27a83668311f Mon Sep 17 00:00:00 2001 From: gstellenberg Date: Fri, 29 May 2009 12:14:24 -0500 Subject: [PATCH 17/22] Added call to PRFlushWriteData at the end of each run loop. --- examples/pinproctest/pinproctest.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/pinproctest/pinproctest.cpp b/examples/pinproctest/pinproctest.cpp index 1e368df..f06904f 100644 --- a/examples/pinproctest/pinproctest.cpp +++ b/examples/pinproctest/pinproctest.cpp @@ -375,6 +375,7 @@ void RunLoop(PRHandle proc) gettimeofday(&tv, NULL); printf("%d.%03d switch % 3d: %s\n", tv.tv_sec-startTime, tv.tv_usec/1000, event->value, stateText); } + PRFlushWriteData(proc); usleep(10*1000); // Sleep for 10ms so we aren't pegging the CPU. } } From 528d3b4842c7d7c6e9c4e2f64c34fa825ff9e45f Mon Sep 17 00:00:00 2001 From: gstellenberg Date: Fri, 29 May 2009 12:14:51 -0500 Subject: [PATCH 18/22] Made FlushWriteData public. --- src/PRDevice.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/PRDevice.h b/src/PRDevice.h index 4099c23..d6cfb0a 100644 --- a/src/PRDevice.h +++ b/src/PRDevice.h @@ -53,6 +53,8 @@ public: // public libpinproc API: int GetEvents(PREvent *events, int maxEvents); + PRResult FlushWriteData(); + PRResult DriverUpdateGlobalConfig(PRDriverGlobalConfig *driverGlobalConfig); PRResult DriverGetGroupConfig(uint8_t groupNum, PRDriverGroupConfig *driverGroupConfig); PRResult DriverUpdateGroupConfig(PRDriverGroupConfig *driverGroupConfig); @@ -82,9 +84,6 @@ protected: /** Schedules data to be written to the P-ROC. */ PRResult PrepareWriteData(uint32_t * buffer, int32_t numWords); - /** Initiates a burst write of all data scheduled to be written to the P-ROC. */ - PRResult FlushWriteData(); - /** Writes data to P-ROC. * Returns #kPFailure if the number of words read does not match the number requested. */ From 579d3532ea07cd3413de42b3dc624395ce64de72 Mon Sep 17 00:00:00 2001 From: Adam Preble Date: Fri, 29 May 2009 19:09:38 -0400 Subject: [PATCH 19/22] Fixed calls to PRSwitchUpdateRule() that weren't supposed to have drivers linked. --- examples/pinproctest/pinproctest.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/pinproctest/pinproctest.cpp b/examples/pinproctest/pinproctest.cpp index f06904f..ac6e7d0 100644 --- a/examples/pinproctest/pinproctest.cpp +++ b/examples/pinproctest/pinproctest.cpp @@ -206,7 +206,7 @@ void ConfigureWPCFlipperSwitchRule (PRHandle proc, int swNum, int mainCoilNum, i sw.notifyHost = false; PRSwitchUpdateRule(proc, swNum, kPREventTypeSwitchClosedNondebounced, &sw, drivers, numDriverRules); sw.notifyHost = true; - PRSwitchUpdateRule(proc, swNum, kPREventTypeSwitchClosedDebounced, &sw, drivers, numDriverRules); + PRSwitchUpdateRule(proc, swNum, kPREventTypeSwitchClosedDebounced, &sw, NULL, 0); // Flipper off rules PRDriverGetState(proc, mainCoilNum, &drivers[0]); @@ -216,7 +216,7 @@ void ConfigureWPCFlipperSwitchRule (PRHandle proc, int swNum, int mainCoilNum, i sw.notifyHost = false; PRSwitchUpdateRule(proc, swNum, kPREventTypeSwitchOpenNondebounced, &sw, drivers, numDriverRules); sw.notifyHost = true; - PRSwitchUpdateRule(proc, swNum, kPREventTypeSwitchOpenDebounced, &sw, drivers, numDriverRules); + PRSwitchUpdateRule(proc, swNum, kPREventTypeSwitchOpenDebounced, &sw, NULL, 0); } void ConfigureBumperRule (PRHandle proc, int swNum, int coilNum, int pulseTime) @@ -231,7 +231,7 @@ void ConfigureBumperRule (PRHandle proc, int swNum, int coilNum, int pulseTime) sw.notifyHost = false; PRSwitchUpdateRule(proc, swNum, kPREventTypeSwitchClosedNondebounced, &sw, drivers, numDriverRules); sw.notifyHost = true; - PRSwitchUpdateRule(proc, swNum, kPREventTypeSwitchClosedDebounced, &sw, drivers, numDriverRules); + PRSwitchUpdateRule(proc, swNum, kPREventTypeSwitchClosedDebounced, &sw, NULL, 0); } void ConfigureSwitchRules(PRHandle proc, YAML::Node& yamlDoc) From f3a71b7a6f4e140eeaac7310499365c154f62db9 Mon Sep 17 00:00:00 2001 From: Adam Preble Date: Fri, 29 May 2009 19:54:11 -0400 Subject: [PATCH 20/22] pinproctest: Expanded YAML format to allow for fields inside of each PRSwitches/PRLamps/PRCoils entry. Added use of 'number' field. Added TZ.yaml. --- examples/pinproctest/JD.yaml | 48 ++++++++++++++++++---------- examples/pinproctest/TZ.yaml | 48 ++++++++++++++++++++++++++++ examples/pinproctest/pinproctest.cpp | 11 ++++--- 3 files changed, 86 insertions(+), 21 deletions(-) create mode 100644 examples/pinproctest/TZ.yaml diff --git a/examples/pinproctest/JD.yaml b/examples/pinproctest/JD.yaml index ef1c186..39ca4e5 100644 --- a/examples/pinproctest/JD.yaml +++ b/examples/pinproctest/JD.yaml @@ -10,20 +10,36 @@ PRBumpers: - slingL - slingR PRSwitches: - flipperLwR: 1 - flipperLwL: 3 - flipperUpR: 5 - flipperUpL: 7 - slingL: 96 - slingR: 97 + flipperLwR: + number: 1 + flipperLwL: + number: 3 + flipperUpR: + number: 5 + flipperUpL: + number: 7 + slingL: + number: 96 + slingR: + number: 97 PRCoils: - flipperLwRMain: 32 - flipperLwRHold: 33 - flipperLwLMain: 34 - flipperLwLHold: 35 - flipperUpRMain: 36 - flipperUpRHold: 37 - flipperUpLMain: 38 - flipperUpLHold: 39 - slingL: 54 - slingR: 55 + flipperLwRMain: + number: 32 + flipperLwRHold: + number: 33 + flipperLwLMain: + number: 34 + flipperLwLHold: + number: 35 + flipperUpRMain: + number: 36 + flipperUpRHold: + number: 37 + flipperUpLMain: + number: 38 + flipperUpLHold: + number: 39 + slingL: + number: 54 + slingR: + number: 55 \ No newline at end of file diff --git a/examples/pinproctest/TZ.yaml b/examples/pinproctest/TZ.yaml new file mode 100644 index 0000000..455ea82 --- /dev/null +++ b/examples/pinproctest/TZ.yaml @@ -0,0 +1,48 @@ +# P-ROC Game Description file for Twilight Zone +PRGame: + machineType: wpc +PRFlippers: + - flipperLwR + - flipperLwL + - flipperUpR + - flipperUpL +PRBumpers: + - slingL + - slingR +PRSwitches: + flipperLwR: + number: 1 + flipperLwL: + number: 3 + flipperUpR: + number: 5 + flipperUpL: + number: 7 + slingL: + number: 96 + slingR: + number: 97 +PRCoils: + flipperLwRMain: + number: 32 + flipperLwRHold: + number: 33 + flipperLwLMain: + number: 34 + flipperLwLHold: + number: 35 + flipperUpRMain: + number: 36 + flipperUpRHold: + number: 37 + flipperUpLMain: + number: 38 + flipperUpLHold: + number: 39 + slingL: + number: 54 + slingR: + number: 55 +PRLamps: + doorTheCamera: + number: 80 \ No newline at end of file diff --git a/examples/pinproctest/pinproctest.cpp b/examples/pinproctest/pinproctest.cpp index ac6e7d0..d3ee3dd 100644 --- a/examples/pinproctest/pinproctest.cpp +++ b/examples/pinproctest/pinproctest.cpp @@ -41,6 +41,7 @@ #define kBumpersSection "PRBumpers" #define kCoilsSection "PRCoils" #define kSwitchesSection "PRSwitches" +#define kNumberField "number" #define kFlipperPulseTime (34) // 34 ms #define kBumperPulseTime (25) // 25 ms @@ -243,9 +244,9 @@ void ConfigureSwitchRules(PRHandle proc, YAML::Node& yamlDoc) int swNum, coilMain, coilHold; std::string flipperName; *flippersIt >> flipperName; - yamlDoc[kSwitchesSection][flipperName] >> swNum; - yamlDoc[kCoilsSection][flipperName + "Main"] >> coilMain; - yamlDoc[kCoilsSection][flipperName + "Hold"] >> coilHold; + yamlDoc[kSwitchesSection][flipperName][kNumberField] >> swNum; + yamlDoc[kCoilsSection][flipperName + "Main"][kNumberField] >> coilMain; + yamlDoc[kCoilsSection][flipperName + "Hold"][kNumberField] >> coilHold; ConfigureWPCFlipperSwitchRule (proc, swNum, coilMain, coilHold, kFlipperPulseTime); } @@ -256,8 +257,8 @@ void ConfigureSwitchRules(PRHandle proc, YAML::Node& yamlDoc) // WPC Slingshots std::string bumperName; *bumpersIt >> bumperName; - yamlDoc[kSwitchesSection][bumperName] >> swNum; - yamlDoc[kCoilsSection][bumperName] >> coilNum; + yamlDoc[kSwitchesSection][bumperName][kNumberField] >> swNum; + yamlDoc[kCoilsSection][bumperName][kNumberField] >> coilNum; ConfigureBumperRule (proc, swNum, coilNum, kBumperPulseTime); } } From afc63b44600cc05bade7effa713e34eac3b51426 Mon Sep 17 00:00:00 2001 From: Adam Preble Date: Fri, 29 May 2009 21:41:47 -0400 Subject: [PATCH 21/22] Added setting of FTDI latency timer to improve PRHardwareRead() times that were slowing down reading switch events. --- src/PRHardware.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/PRHardware.cpp b/src/PRHardware.cpp index fd32748..886441d 100644 --- a/src/PRHardware.cpp +++ b/src/PRHardware.cpp @@ -316,6 +316,9 @@ PRResult PRHardwareOpen() uint32_t chipid; ftdi_read_chipid(&ftdic,&chipid); DEBUG(PRLog("FTDI chip_id = 0x%x\n", chipid)); + // Set some defaults: + ftdi_read_data_set_chunksize(&ftdic, 4096); + ftdi_set_latency_timer(&ftdic, 2); // This helps make reads much faster. 16 appeared to be the default. ftdiInitialized = true; return kPRSuccess; } From 8e65a15a6863125b509035117a1fa871b190637a Mon Sep 17 00:00:00 2001 From: Adam Preble Date: Fri, 29 May 2009 22:24:39 -0400 Subject: [PATCH 22/22] pinproctest now checks return value of LoadConfiguration(). --- examples/pinproctest/pinproctest.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/pinproctest/pinproctest.cpp b/examples/pinproctest/pinproctest.cpp index d3ee3dd..d45d768 100644 --- a/examples/pinproctest/pinproctest.cpp +++ b/examples/pinproctest/pinproctest.cpp @@ -405,7 +405,11 @@ int main(int argc, const char **argv) PRLogSetCallback(TestLogger); YAML::Node yamlDoc; - LoadConfiguration(yamlDoc, yamlFilename); + if (LoadConfiguration(yamlDoc, yamlFilename) != kPRSuccess) + { + fprintf(stderr, "Failed to load configuration file %s\n", yamlFilename); + return 1; + } PRMachineType machineType = kPRMachineInvalid; std::string machineTypeString;