diff --git a/examples/pinproctest/pinproctest.cpp b/examples/pinproctest/pinproctest.cpp index 5d4efa6..68edb68 100644 --- a/examples/pinproctest/pinproctest.cpp +++ b/examples/pinproctest/pinproctest.cpp @@ -105,10 +105,8 @@ void ConfigureSwitches(PRHandle proc) { PRSwitchRule sw; sw.notifyHost = true; - sw.eventType = kPREventTypeSwitchClosedDebounced; - PRSwitchesUpdateRule(proc, i, &sw, NULL, 0); - sw.eventType = kPREventTypeSwitchOpenDebounced; - PRSwitchesUpdateRule(proc, i, &sw, NULL, 0); + PRSwitchesUpdateRule(proc, i, kPREventTypeSwitchClosedDebounced, &sw, NULL, 0); + PRSwitchesUpdateRule(proc, i, kPREventTypeSwitchOpenDebounced, &sw, NULL, 0); } } diff --git a/include/pinproc.h b/include/pinproc.h index e83034e..9b2c1d8 100644 --- a/include/pinproc.h +++ b/include/pinproc.h @@ -172,6 +172,16 @@ PR_EXPORT PRResult PRDriverSchedule(PRHandle handle, uint16_t driverNum, uint32_ PR_EXPORT PRResult PRDriverPatter(PRHandle handle, uint16_t driverNum, uint16_t millisecondsOn, uint16_t millisecondsOff, uint16_t originalOnTime); +/** Disables (turns off) the given driver. */ +PR_EXPORT void PRDriverStateDisable(PRDriverState *driverState); +/** Pulses the given driver for a number of milliseconds. */ +PR_EXPORT void PRDriverStatePulse(PRDriverState *driverState, int milliseconds); +/** Assigns a repeating schedule to the given driver. */ +PR_EXPORT void PRDriverStateSchedule(PRDriverState *driverState, uint32_t schedule, uint8_t cycleSeconds, bool_t now); +/** Assigns a pitter-patter schedule (repeating on/off) to the given driver. */ +PR_EXPORT void PRDriverStatePatter(PRDriverState *driverState, uint16_t millisecondsOn, uint16_t millisecondsOff, uint16_t originalOnTime); + + // Switches @@ -185,12 +195,59 @@ PR_EXPORT PRResult PRDriverPatter(PRHandle handle, uint16_t driverNum, uint16_t /** @} */ typedef struct PRSwitchRule { - PREventType eventType; /**< The event type that this rule generates. Determines closed/open, debounced/non-debounced. */ - bool_t notifyHost; + bool_t notifyHost; /**< If true this switch change event will provided to the user via PRGetEvents(). */ } PRSwitchRule; -/** Updates the rules for the given switch. */ -PR_EXPORT PRResult PRSwitchesUpdateRule(PRHandle handle, uint8_t switchNum, PRSwitchRule *rule, PRDriverState *linkedDrivers, int numDrivers); +/** + * @brief Configures the handling of switch rules within P-ROC. + * + * P-ROC's switch event system allows the user to receive and act upon events specific to the individual switch's application. + * For example, P-ROC can provide debounced switch events to software by means of the PRGetEvents() call (to create + * a lane change behavior). The same switch can also be configured with a non-debounced rule to fire a flipper coil. + * Multiple driver changes can be tied to a single switch state transition to create more complicated effects: a slingshot + * switch that fires the slingshot coil, a flash lamp, and a score event. + * + * P-ROC holds four different switch rules for each switch: closed to open and open to closed, each with a debounced and non-debounced versions: + * - #kPREventTypeSwitchOpenDebounced + * - #kPREventTypeSwitchClosedDebounced + * - #kPREventTypeSwitchOpenNondebounced + * - #kPREventTypeSwitchClosedNondebounced + * + * @section Examples + * + * Configuring a basic switch rule with no driver state changes that will appear in PRGetEvents(): + * @code + * PRSwitchRule rule; + * rule.notifyHost = true; + * PRSwitchesUpdateRule(handle, switchNum, kPREventTypeSwitchOpenDebounced, &rule, NULL, 0); + * @endcode + * + * Configuring a pop bumper switch to pulse the coil and a flash lamp: + * @code + * // Configure a switch rule to fire the coil and flash lamp: + * PRSwitchRule rule; + * rule.notifyHost = false; + * PRDriverState drivers[2]; + * PRDriverGetState(handle, drvCoilPopBumper1, &drivers[0]); + * PRDriverGetState(handle, drvFlashLamp1, &drivers[1]); + * PRDriverStatePulse(&drivers[0], 50); + * PRDriverStatePulse(&drivers[1], 50); + * PRSwitchesUpdateRule(handle, drvSwPopBumper1, kPREventTypeSwitchClosedNondebounced, + * &rule, drivers, 2); + * // Now configure a switch rule to process scoring in software: + * rule.notifyHost = false; + * PRSwitchesUpdateRule(handle, drvSwPopBumper1, kPREventTypeSwitchClosedDebounced, + * &rule, NULL, 0); + * @endcode + * + * @param handle The P-ROC device handle. + * @param switchNum The index of the switch this configuration affects. + * @param eventType The switch rule for the specified switchNum to be configured. + * @param rule A pointer to the #PRSwitchRule structure describing how this state change should be handled. May not be NULL. + * @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); diff --git a/src/PRDevice.cpp b/src/PRDevice.cpp index 2549e1f..35b8a46 100644 --- a/src/PRDevice.cpp +++ b/src/PRDevice.cpp @@ -188,64 +188,6 @@ PRResult PRDevice::DriverUpdateState(PRDriverState *driverState) } -PRResult PRDevice::DriverDisable(uint16_t driverNum) -{ - PRDriverState driver; - DriverGetState(driverNum, &driver); - driver.state = 0; - driver.timeslots = 0; - driver.waitForFirstTimeSlot = false; - driver.outputDriveTime = 0; - driver.patterOnTime = 0; - driver.patterOffTime = 0; - driver.patterEnable = false; - return DriverUpdateState(&driver); -} - - -PRResult PRDevice::DriverPulse(uint16_t driverNum, int milliseconds) -{ - PRDriverState driver; - DriverGetState(driverNum, &driver); - driver.state = 1; - driver.timeslots = 0; - driver.waitForFirstTimeSlot = false; - driver.outputDriveTime = milliseconds; - driver.patterOnTime = 0; - driver.patterOffTime = 0; - driver.patterEnable = false; - return DriverUpdateState(&driver); -} - - -PRResult PRDevice::DriverSchedule(uint16_t driverNum, uint32_t schedule, uint8_t cycleSeconds, bool now) -{ - PRDriverState driver; - DriverGetState(driverNum, &driver); - driver.state = 1; - driver.timeslots = schedule; - driver.waitForFirstTimeSlot = !now; - driver.outputDriveTime = cycleSeconds; - driver.patterOnTime = 0; - driver.patterOffTime = 0; - driver.patterEnable = false; - return DriverUpdateState(&driver); -} - - -PRResult PRDevice::DriverPatter(uint16_t driverNum, uint16_t millisecondsOn, uint16_t millisecondsOff, uint16_t originalOnTime) -{ - PRDriverState driver; - DriverGetState(driverNum, &driver); - driver.state = originalOnTime != 0; - driver.timeslots = 0; - driver.waitForFirstTimeSlot = false; - driver.outputDriveTime = originalOnTime; - driver.patterOnTime = millisecondsOn; - driver.patterOffTime = millisecondsOff; - driver.patterEnable = true; - return DriverUpdateState(&driver); -} PRSwitchRuleInternal *PRDevice::GetSwitchRuleByAddress(uint32_t addr) @@ -253,7 +195,7 @@ PRSwitchRuleInternal *PRDevice::GetSwitchRuleByAddress(uint32_t addr) return &switchRules[addr>>P_ROC_SWITCH_RULE_ADDR_SWITCH_NUM_SHIFT]; } -PRResult PRDevice::SwitchesUpdateRule(uint8_t switchNum, PRSwitchRule *rule, PRDriverState *linkedDrivers, int numDrivers) +PRResult PRDevice::SwitchesUpdateRule(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; @@ -271,7 +213,7 @@ PRResult PRDevice::SwitchesUpdateRule(uint8_t switchNum, PRSwitchRule *rule, PRD } PRResult res = kPRSuccess; - uint32_t newRuleAddr = CreateSwitchRuleAddr(switchNum, rule->eventType); + uint32_t newRuleAddr = CreateSwitchRuleAddr(switchNum, eventType); // First we need to check the linked rule to see if the indicated switchNum has any rules that need to be freed: PRSwitchRuleInternal *oldRule = GetSwitchRuleByAddress(newRuleAddr); @@ -284,7 +226,8 @@ PRResult PRDevice::SwitchesUpdateRule(uint8_t switchNum, PRSwitchRule *rule, PRD // Now let's setup the first actual rule: uint32_t firstRuleAddr = newRuleAddr; PRSwitchRuleInternal *newRule = GetSwitchRuleByAddress(newRuleAddr); - newRule->eventType = rule->eventType; // This shouldn't be necessary. + if (newRule->eventType != eventType) + DEBUG(PRLog("Unexpected state: switch rule at 0x%x has event type 0x%x (expected 0x%x).\n", newRuleAddr, newRule->eventType, eventType)); newRule->notifyHost = rule->notifyHost; newRule->changeOutput = false; newRule->linkActive = false; diff --git a/src/PRDevice.h b/src/PRDevice.h index 051614d..11498e8 100644 --- a/src/PRDevice.h +++ b/src/PRDevice.h @@ -64,12 +64,7 @@ public: PRResult DriverGetState(uint8_t driverNum, PRDriverState *driverState); PRResult DriverUpdateState(PRDriverState *driverState); - PRResult DriverDisable(uint16_t driverNum); - PRResult DriverPulse(uint16_t driverNum, int milliseconds); - PRResult DriverSchedule(uint16_t driverNum, uint32_t schedule, uint8_t cycleSeconds, bool now); - PRResult DriverPatter(uint16_t driverNum, uint16_t millisecondsOn, uint16_t millisecondsOff, uint16_t originalOnTime); - - PRResult SwitchesUpdateRule(uint8_t switchNum, PRSwitchRule *rule, PRDriverState *linkedDrivers, int numDrivers); + PRResult SwitchesUpdateRule(uint8_t switchNum, PREventType eventType, PRSwitchRule *rule, PRDriverState *linkedDrivers, int numDrivers); PRResult DMDUpdateGlobalConfig(PRDMDGlobalConfig *dmdGlobalConfig); PRResult DMDDraw(uint8_t * dots, uint16_t columns, uint8_t rows, uint8_t numSubFrames); diff --git a/src/pinproc.cpp b/src/pinproc.cpp index f7843f1..8b1aa7d 100644 --- a/src/pinproc.cpp +++ b/src/pinproc.cpp @@ -107,28 +107,81 @@ PR_EXPORT PRResult PRDriverUpdateState(PRHandle handle, PRDriverState *driverSta // Driver Helper functions: PR_EXPORT PRResult PRDriverDisable(PRHandle handle, uint16_t driverNum) { - return handleAsDevice->DriverDisable(driverNum); + PRDriverState driver; + handleAsDevice->DriverGetState(driverNum, &driver); + PRDriverStateDisable(&driver); + return handleAsDevice->DriverUpdateState(&driver); } PR_EXPORT PRResult PRDriverPulse(PRHandle handle, uint16_t driverNum, int milliseconds) { - return handleAsDevice->DriverPulse(driverNum, milliseconds); + PRDriverState driver; + handleAsDevice->DriverGetState(driverNum, &driver); + PRDriverStatePulse(&driver, milliseconds); + return handleAsDevice->DriverUpdateState(&driver); } PR_EXPORT PRResult PRDriverSchedule(PRHandle handle, uint16_t driverNum, uint32_t schedule, uint8_t cycleSeconds, bool_t now) { - return handleAsDevice->DriverSchedule(driverNum, schedule, cycleSeconds, now); + PRDriverState driver; + handleAsDevice->DriverGetState(driverNum, &driver); + PRDriverStateSchedule(&driver, schedule, cycleSeconds, now); + return handleAsDevice->DriverUpdateState(&driver); } PR_EXPORT PRResult PRDriverPatter(PRHandle handle, uint16_t driverNum, uint16_t millisecondsOn, uint16_t millisecondsOff, uint16_t originalOnTime) { - return handleAsDevice->DriverPatter(driverNum, millisecondsOn, millisecondsOff, originalOnTime); + PRDriverState driver; + handleAsDevice->DriverGetState(driverNum, &driver); + PRDriverStatePatter(&driver, millisecondsOn, millisecondsOff, originalOnTime); + return handleAsDevice->DriverUpdateState(&driver); } +PR_EXPORT void PRDriverStateDisable(PRDriverState *driver) +{ + driver->state = 0; + driver->timeslots = 0; + driver->waitForFirstTimeSlot = false; + driver->outputDriveTime = 0; + driver->patterOnTime = 0; + driver->patterOffTime = 0; + driver->patterEnable = false; +} +PR_EXPORT void PRDriverStatePulse(PRDriverState *driver, int milliseconds) +{ + driver->state = 1; + driver->timeslots = 0; + driver->waitForFirstTimeSlot = false; + driver->outputDriveTime = milliseconds; + driver->patterOnTime = 0; + driver->patterOffTime = 0; + driver->patterEnable = false; +} +PR_EXPORT void PRDriverStateSchedule(PRDriverState *driver, uint32_t schedule, uint8_t cycleSeconds, bool_t now) +{ + driver->state = 1; + driver->timeslots = schedule; + driver->waitForFirstTimeSlot = !now; + driver->outputDriveTime = cycleSeconds; + driver->patterOnTime = 0; + driver->patterOffTime = 0; + driver->patterEnable = false; +} +PR_EXPORT void PRDriverStatePatter(PRDriverState *driver, uint16_t millisecondsOn, uint16_t millisecondsOff, uint16_t originalOnTime) +{ + driver->state = originalOnTime != 0; + driver->timeslots = 0; + driver->waitForFirstTimeSlot = false; + driver->outputDriveTime = originalOnTime; + driver->patterOnTime = millisecondsOn; + driver->patterOffTime = millisecondsOff; + driver->patterEnable = true; +} + // Switches -PR_EXPORT PRResult PRSwitchesUpdateRule(PRHandle handle, uint8_t switchNum, PRSwitchRule *rule, PRDriverState *linkedDrivers, int numDrivers) +PR_EXPORT PRResult PRSwitchesUpdateRule(PRHandle handle, uint8_t switchNum, PREventType eventType, PRSwitchRule *rule, PRDriverState *linkedDrivers, int numDrivers) { - return handleAsDevice->SwitchesUpdateRule(switchNum, rule, linkedDrivers, numDrivers); + return handleAsDevice->SwitchesUpdateRule(switchNum, eventType, rule, linkedDrivers, numDrivers); } PR_EXPORT int32_t PRDMDUpdateGlobalConfig(PRHandle handle, PRDMDGlobalConfig *dmdGlobalConfig)