mirror of
https://github.com/preble/libpinproc
synced 2026-02-24 18:25:23 +01:00
Added new PRSwitchesUpdateSwitch() call, removed old PRSwitchesUpdateSwitches(). Added maintaining switch rules in memory. Fixed license formatting in README.markdown.
This commit is contained in:
@@ -4,7 +4,8 @@ Library for Gerry Stellenberg's [P-ROC](http://pinballcontrollers.com/) (Pinball
|
||||
|
||||
### License
|
||||
|
||||
The MIT License
|
||||
#### The MIT License
|
||||
|
||||
Copyright (c) 2009 Gerry Stellenberg, Adam Preble
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
|
||||
@@ -101,23 +101,14 @@ void ConfigureSwitches(PRHandle proc)
|
||||
{
|
||||
int i;
|
||||
|
||||
// Create a basic driver for all of the switches to default to:
|
||||
PRDriverState defaultDriver;
|
||||
memset(&defaultDriver, 0x0, sizeof(defaultDriver)); // Set all fields to 0.
|
||||
|
||||
for (i = 0; i <= kPRSwitchPhysicalLast; i++)
|
||||
{
|
||||
PRSwitchRule sw;
|
||||
sw.switchNum = i;
|
||||
sw.notifyHost = true;
|
||||
sw.changeOutput = false;
|
||||
sw.linkActive = false;
|
||||
sw.linkAddress = 0;
|
||||
sw.eventType = kPREventTypeSwitchClosedDebounced;
|
||||
sw.driver = defaultDriver;
|
||||
PRSwitchesUpdateRules(proc, &sw, 1);
|
||||
PRSwitchesUpdateRule(proc, i, &sw, NULL, 0);
|
||||
sw.eventType = kPREventTypeSwitchOpenDebounced;
|
||||
PRSwitchesUpdateRules(proc, &sw, 1);
|
||||
PRSwitchesUpdateRule(proc, i, &sw, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -185,17 +185,12 @@ PR_EXPORT PRResult PRDriverPatter(PRHandle handle, uint16_t driverNum, uint16_t
|
||||
/** @} */
|
||||
|
||||
typedef struct PRSwitchRule {
|
||||
uint16_t switchNum; /**< Number of the physical switch, or for linked driver changes the virtual switch number (224 and up). */
|
||||
PREventType eventType; /**< The event type that this rule generates. Determines closed/open, debounced/non-debounced. */
|
||||
bool_t notifyHost;
|
||||
bool_t changeOutput; /**< True if this switch rule should affect a driver output change. */
|
||||
bool_t linkActive; /**< True if this switch rule has additional linked driver updates. */
|
||||
uint32_t linkAddress; /**< Switch number of the linked driver update. */
|
||||
PRDriverState driver; /**< Driver state change to affect once this rule is triggered. */
|
||||
} PRSwitchRule;
|
||||
|
||||
/** Updates the rules for the given switch and PREventType combinations. */
|
||||
PR_EXPORT PRResult PRSwitchesUpdateRules(PRHandle handle, PRSwitchRule *rules, int numRules);
|
||||
/** Updates the rules for the given switch. */
|
||||
PR_EXPORT PRResult PRSwitchesUpdateRule(PRHandle handle, uint8_t switchNum, PRSwitchRule *rule, PRDriverState *linkedDrivers, int numDrivers);
|
||||
|
||||
|
||||
|
||||
|
||||
125
src/PRDevice.cpp
125
src/PRDevice.cpp
@@ -83,10 +83,13 @@ void PRDevice::Reset()
|
||||
}
|
||||
for (i = 0; i < maxSwitchRules; i++)
|
||||
{
|
||||
PRSwitchRule *switchRule = &switchRules[i];
|
||||
PRSwitchRuleInternal *switchRule = &switchRules[i];
|
||||
memset(switchRule, 0x00, sizeof(PRSwitchRule));
|
||||
switchRule->switchNum = i;
|
||||
uint32_t addr = (i << P_ROC_SWITCH_RULE_ADDR_SWITCH_NUM_SHIFT);
|
||||
ParseSwitchAddress(addr, &switchRule->switchNum, &switchRule->eventType);
|
||||
switchRule->driver.polarity = defaultPolarity;
|
||||
if (switchRule->switchNum >= kPRSwitchVirtualFirst && switchRule->switchNum <= kPRSwitchVirtualLast)
|
||||
freeSwitchRules.push(addr);
|
||||
}
|
||||
|
||||
unrequestedDataQueue.empty();
|
||||
@@ -245,45 +248,91 @@ PRResult PRDevice::DriverPatter(uint16_t driverNum, uint16_t millisecondsOn, uin
|
||||
}
|
||||
|
||||
|
||||
PRResult PRDevice::SwitchesUpdateRules(PRSwitchRule *rules, int numRules)
|
||||
PRSwitchRuleInternal *PRDevice::GetSwitchRuleByAddress(uint32_t addr)
|
||||
{
|
||||
int32_t i,rc;
|
||||
DEBUG(PRLog("SwitchesUpdateRules: numRules: %d\n", numRules));
|
||||
|
||||
// Iterate through the array of rules, install each in the P-ROC
|
||||
for (i=0; i < numRules; i++) {
|
||||
uint16_t switchNum = rules[i].switchNum;
|
||||
switchRules[switchNum] = rules[i];
|
||||
PRSwitchRule *rule = &switchRules[switchNum];
|
||||
PRSwitchRule *nextRule = NULL;
|
||||
|
||||
// See if this is the last item. If not, need to add a link to the current item
|
||||
if (i != numRules - 1) {
|
||||
nextRule = &rules[i+1];
|
||||
|
||||
// Link address is the switch number assigned to the next rule as that's where
|
||||
// the next rule will be installed
|
||||
rule->linkAddress = nextRule->switchNum;
|
||||
rule->linkActive = true;
|
||||
}
|
||||
else {
|
||||
rule->linkActive = false;
|
||||
rule->linkAddress = 0;
|
||||
}
|
||||
|
||||
DEBUG(PRLog("Installing switch rule: switchNum: %d, eventType: %d\n link: %d, link address: %d\n",
|
||||
rule->switchNum, rule->eventType, rule->linkActive, rule->linkAddress));
|
||||
|
||||
uint32_t rule_burst[4];
|
||||
rc = CreateSwitchesUpdateRulesBurst (rule_burst, rule);
|
||||
|
||||
DEBUG(PRLog("words: %d:%d:%d:%d\n", rule_burst[0], rule_burst[1], rule_burst[2], rule_burst[3]));
|
||||
|
||||
rc = WriteData(rule_burst, 4);
|
||||
}
|
||||
return rc;
|
||||
return &switchRules[addr>>P_ROC_SWITCH_RULE_ADDR_SWITCH_NUM_SHIFT];
|
||||
}
|
||||
|
||||
PRResult PRDevice::SwitchesUpdateRule(uint8_t switchNum, PRSwitchRule *rule, PRDriverState *linkedDrivers, int numDrivers)
|
||||
{
|
||||
// Updates a single rule with the associated linked driver state changes.
|
||||
const int burstSize = 4;
|
||||
uint32_t burst[burstSize];
|
||||
|
||||
if (switchNum > kPRSwitchPhysicalLast) // Always true due to data type.
|
||||
{
|
||||
DEBUG(PRLog("Switch rule out of range 0-%d\n", kPRSwitchPhysicalLast));
|
||||
return kPRFailure;
|
||||
}
|
||||
if (freeSwitchRules.size() < numDrivers-1) // -1 because the first switch rule holds the first driver.
|
||||
{
|
||||
DEBUG(PRLog("Not enough free switch rules: %d available, need %d\n", freeSwitchRules.size(), numDrivers));
|
||||
return kPRFailure;
|
||||
}
|
||||
|
||||
PRResult res = kPRSuccess;
|
||||
uint32_t newRuleAddr = CreateSwitchRuleAddr(switchNum, rule->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);
|
||||
while (oldRule->linkActive)
|
||||
{
|
||||
oldRule = GetSwitchRuleByAddress(oldRule->linkAddress);
|
||||
freeSwitchRules.push(oldRule->linkAddress);
|
||||
}
|
||||
|
||||
// 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.
|
||||
newRule->notifyHost = rule->notifyHost;
|
||||
newRule->changeOutput = false;
|
||||
newRule->linkActive = false;
|
||||
|
||||
while (numDrivers > 0)
|
||||
{
|
||||
newRule->changeOutput = true;
|
||||
newRule->driver = linkedDrivers[0];
|
||||
|
||||
if (numDrivers > 1)
|
||||
{
|
||||
newRule->linkActive = true;
|
||||
newRule->linkAddress = freeSwitchRules.front();
|
||||
freeSwitchRules.pop();
|
||||
|
||||
CreateSwitchesUpdateRulesBurst(burst, newRule);
|
||||
|
||||
// Prepare for the next rule:
|
||||
newRule = GetSwitchRuleByAddress(newRule->linkAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
newRule->linkActive = false;
|
||||
CreateSwitchesUpdateRulesBurst(burst, newRule);
|
||||
}
|
||||
|
||||
// Write the actual rule:
|
||||
res = WriteData(burst, burstSize);
|
||||
if (res != kPRSuccess)
|
||||
{
|
||||
DEBUG(PRLog("Error while writing switch update, attempting to revert switch rule to a safe state..."));
|
||||
newRule = GetSwitchRuleByAddress(firstRuleAddr);
|
||||
newRule->changeOutput = false;
|
||||
newRule->linkActive = false;
|
||||
CreateSwitchesUpdateRulesBurst(burst, newRule);
|
||||
if (WriteData(burst, burstSize) == kPRSuccess)
|
||||
DEBUG(PRLog("Disabled successfully.\n"));
|
||||
else
|
||||
DEBUG(PRLog("Failed to disable.\n"));
|
||||
return res;
|
||||
}
|
||||
|
||||
linkedDrivers++;
|
||||
numDrivers--;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t PRDevice::DMDUpdateGlobalConfig(PRDMDGlobalConfig *dmdGlobalConfig)
|
||||
{
|
||||
|
||||
@@ -37,7 +37,7 @@ using namespace std;
|
||||
|
||||
#define maxDriverGroups (26)
|
||||
#define maxDrivers (256)
|
||||
#define maxSwitchRules (256)
|
||||
#define maxSwitchRules (256<<2) // 8 bits of switchNum indicies plus bits for debounced and state.
|
||||
|
||||
#ifdef NDEBUG
|
||||
# define DEBUG(block)
|
||||
@@ -69,7 +69,7 @@ public:
|
||||
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 SwitchesUpdateRules(PRSwitchRule *rules, int numRules);
|
||||
PRResult SwitchesUpdateRule(uint8_t switchNum, PRSwitchRule *rule, PRDriverState *linkedDrivers, int numDrivers);
|
||||
|
||||
PRResult DMDUpdateGlobalConfig(PRDMDGlobalConfig *dmdGlobalConfig);
|
||||
PRResult DMDDraw(uint8_t * dots, uint16_t columns, uint8_t rows, uint8_t numSubFrames);
|
||||
@@ -138,6 +138,8 @@ protected:
|
||||
PRDriverGlobalConfig driverGlobalConfig;
|
||||
PRDriverGroupConfig driverGroups[maxDriverGroups];
|
||||
PRDriverState drivers[maxDrivers];
|
||||
PRSwitchRule switchRules[maxSwitchRules];
|
||||
|
||||
PRSwitchRuleInternal switchRules[maxSwitchRules];
|
||||
queue<uint32_t> freeSwitchRules; /**< Addresses of available switch rules. */
|
||||
PRSwitchRuleInternal *GetSwitchRuleByAddress(uint32_t addr);
|
||||
};
|
||||
|
||||
@@ -125,19 +125,35 @@ int32_t CreateDriverUpdateBurst ( uint32_t * burst, PRDriverState *driver) {
|
||||
return kPRSuccess;
|
||||
}
|
||||
|
||||
int32_t CreateSwitchesUpdateRulesBurst ( uint32_t * burst, PRSwitchRule *rule_record) {
|
||||
uint32_t addr;
|
||||
int32_t CreateSwitchRuleAddr(uint8_t switchNum, PREventType eventType)
|
||||
{
|
||||
uint32_t debounce = (eventType == kPREventTypeSwitchOpenDebounced) || (eventType == kPREventTypeSwitchClosedDebounced) ? 1 : 0;
|
||||
uint32_t state = (eventType == kPREventTypeSwitchOpenDebounced) || (eventType == kPREventTypeSwitchOpenNondebounced) ? 1 : 0;
|
||||
|
||||
uint32_t addr = ((debounce << P_ROC_SWITCH_RULE_ADDR_DEBOUNCE_SHIFT) |
|
||||
(state << P_ROC_SWITCH_RULE_ADDR_STATE_SHIFT) |
|
||||
(switchNum << P_ROC_SWITCH_RULE_ADDR_SWITCH_NUM_SHIFT) );
|
||||
return addr;
|
||||
}
|
||||
|
||||
void ParseSwitchAddress(uint32_t addr, uint8_t *switchNum, PREventType *eventType)
|
||||
{
|
||||
*switchNum = (addr >> P_ROC_SWITCH_RULE_ADDR_SWITCH_NUM_SHIFT) & 0xff;
|
||||
|
||||
bool open = ((addr >> P_ROC_SWITCH_RULE_ADDR_STATE_SHIFT) & 0x1) == 0x1;
|
||||
bool debounce = ((addr >> P_ROC_SWITCH_RULE_ADDR_DEBOUNCE_SHIFT) & 0x1) == 0x1;
|
||||
if (open)
|
||||
*eventType = debounce ? kPREventTypeSwitchOpenDebounced : kPREventTypeSwitchOpenNondebounced;
|
||||
else
|
||||
*eventType = debounce ? kPREventTypeSwitchClosedDebounced : kPREventTypeSwitchClosedNondebounced;
|
||||
}
|
||||
|
||||
int32_t CreateSwitchesUpdateRulesBurst ( uint32_t * burst, PRSwitchRuleInternal *rule_record) {
|
||||
uint32_t addr = CreateSwitchRuleAddr(rule_record->switchNum, rule_record->eventType);
|
||||
uint32_t driver_command[3];
|
||||
|
||||
CreateDriverUpdateBurst ( driver_command, &(rule_record->driver));
|
||||
|
||||
uint32_t debounce = (rule_record->eventType == kPREventTypeSwitchOpenDebounced) || (rule_record->eventType == kPREventTypeSwitchClosedDebounced) ? 1 : 0;
|
||||
uint32_t state = (rule_record->eventType == kPREventTypeSwitchOpenDebounced) || (rule_record->eventType == kPREventTypeSwitchOpenNondebounced) ? 1 : 0;
|
||||
|
||||
addr = ( (debounce << P_ROC_SWITCH_RULE_ADDR_DEBOUNCE_SHIFT) |
|
||||
(state << P_ROC_SWITCH_RULE_ADDR_STATE_SHIFT) |
|
||||
(rule_record->switchNum << P_ROC_SWITCH_RULE_ADDR_SWITCH_NUM_SHIFT) );
|
||||
|
||||
burst[0] = CreateBurstCommand (P_ROC_BUS_STATE_CHANGE_PROC_SELECT, addr, 3 );
|
||||
burst[1] = driver_command[1];
|
||||
burst[2] = driver_command[2];
|
||||
|
||||
@@ -140,6 +140,15 @@ const uint32_t P_ROC_DMD_RCLK_LOW_CYCLES_SHIFT = 24;
|
||||
|
||||
const uint32_t P_ROC_DMD_DOT_TABLE_BASE_ADDR = 0x1000;
|
||||
|
||||
typedef struct PRSwitchRuleInternal {
|
||||
uint8_t switchNum; /**< Number of the physical switch, or for linked driver changes the virtual switch number (224 and up). */
|
||||
PREventType eventType; /**< The event type that this rule generates. Determines closed/open, debounced/non-debounced. */
|
||||
bool_t notifyHost;
|
||||
bool_t changeOutput; /**< True if this switch rule should affect a driver output change. */
|
||||
bool_t linkActive; /**< True if this switch rule has additional linked driver updates. */
|
||||
uint32_t linkAddress; /**< Switch number of the linked driver update. */
|
||||
PRDriverState driver; /**< Driver state change to affect once this rule is triggered. */
|
||||
} PRSwitchRuleInternal;
|
||||
|
||||
|
||||
uint32_t CreateRegRequestWord( uint32_t select, uint32_t addr, uint32_t num_words);
|
||||
@@ -147,7 +156,10 @@ 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, PRSwitchRule *rule_record);
|
||||
int32_t CreateSwitchesUpdateRulesBurst ( uint32_t * burst, PRSwitchRuleInternal *rule_record);
|
||||
int32_t CreateDMDUpdateGlobalConfigBurst ( uint32_t * burst, PRDMDConfig *dmd_config);
|
||||
|
||||
void ParseSwitchAddress(uint32_t addr, uint8_t *switchNum, PREventType *eventType);
|
||||
int32_t CreateSwitchRuleAddr(uint8_t switchNum, PREventType eventType);
|
||||
|
||||
#endif // _PROC_HARDWARE_H_
|
||||
|
||||
@@ -126,9 +126,9 @@ PR_EXPORT PRResult PRDriverPatter(PRHandle handle, uint16_t driverNum, uint16_t
|
||||
|
||||
// Switches
|
||||
|
||||
PR_EXPORT PRResult PRSwitchesUpdateRules(PRHandle handle, PRSwitchRule *rules, int numRules)
|
||||
PR_EXPORT PRResult PRSwitchesUpdateRule(PRHandle handle, uint8_t switchNum, PRSwitchRule *rule, PRDriverState *linkedDrivers, int numDrivers)
|
||||
{
|
||||
return handleAsDevice->SwitchesUpdateRules(rules, numRules);
|
||||
return handleAsDevice->SwitchesUpdateRule(switchNum, rule, linkedDrivers, numDrivers);
|
||||
}
|
||||
|
||||
PR_EXPORT int32_t PRDMDUpdateGlobalConfig(PRHandle handle, PRDMDGlobalConfig *dmdGlobalConfig)
|
||||
|
||||
Reference in New Issue
Block a user