1
0
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:
Adam Preble
2009-05-20 20:17:00 -04:00
parent 62d3176463
commit c46d928ee3
8 changed files with 139 additions and 73 deletions

View File

@@ -4,7 +4,8 @@ Library for Gerry Stellenberg's [P-ROC](http://pinballcontrollers.com/) (Pinball
### License ### License
The MIT License #### The MIT License
Copyright (c) 2009 Gerry Stellenberg, Adam Preble Copyright (c) 2009 Gerry Stellenberg, Adam Preble
Permission is hereby granted, free of charge, to any person Permission is hereby granted, free of charge, to any person

View File

@@ -101,23 +101,14 @@ void ConfigureSwitches(PRHandle proc)
{ {
int i; 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++) for (i = 0; i <= kPRSwitchPhysicalLast; i++)
{ {
PRSwitchRule sw; PRSwitchRule sw;
sw.switchNum = i;
sw.notifyHost = true; sw.notifyHost = true;
sw.changeOutput = false;
sw.linkActive = false;
sw.linkAddress = 0;
sw.eventType = kPREventTypeSwitchClosedDebounced; sw.eventType = kPREventTypeSwitchClosedDebounced;
sw.driver = defaultDriver; PRSwitchesUpdateRule(proc, i, &sw, NULL, 0);
PRSwitchesUpdateRules(proc, &sw, 1);
sw.eventType = kPREventTypeSwitchOpenDebounced; sw.eventType = kPREventTypeSwitchOpenDebounced;
PRSwitchesUpdateRules(proc, &sw, 1); PRSwitchesUpdateRule(proc, i, &sw, NULL, 0);
} }
} }

View File

@@ -185,17 +185,12 @@ PR_EXPORT PRResult PRDriverPatter(PRHandle handle, uint16_t driverNum, uint16_t
/** @} */ /** @} */
typedef struct PRSwitchRule { 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. */ PREventType eventType; /**< The event type that this rule generates. Determines closed/open, debounced/non-debounced. */
bool_t notifyHost; 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; } PRSwitchRule;
/** Updates the rules for the given switch and PREventType combinations. */ /** Updates the rules for the given switch. */
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);

View File

@@ -83,10 +83,13 @@ void PRDevice::Reset()
} }
for (i = 0; i < maxSwitchRules; i++) for (i = 0; i < maxSwitchRules; i++)
{ {
PRSwitchRule *switchRule = &switchRules[i]; PRSwitchRuleInternal *switchRule = &switchRules[i];
memset(switchRule, 0x00, sizeof(PRSwitchRule)); 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; switchRule->driver.polarity = defaultPolarity;
if (switchRule->switchNum >= kPRSwitchVirtualFirst && switchRule->switchNum <= kPRSwitchVirtualLast)
freeSwitchRules.push(addr);
} }
unrequestedDataQueue.empty(); 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; return &switchRules[addr>>P_ROC_SWITCH_RULE_ADDR_SWITCH_NUM_SHIFT];
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;
} }
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) int32_t PRDevice::DMDUpdateGlobalConfig(PRDMDGlobalConfig *dmdGlobalConfig)
{ {

View File

@@ -37,7 +37,7 @@ using namespace std;
#define maxDriverGroups (26) #define maxDriverGroups (26)
#define maxDrivers (256) #define maxDrivers (256)
#define maxSwitchRules (256) #define maxSwitchRules (256<<2) // 8 bits of switchNum indicies plus bits for debounced and state.
#ifdef NDEBUG #ifdef NDEBUG
# define DEBUG(block) # define DEBUG(block)
@@ -69,7 +69,7 @@ public:
PRResult DriverSchedule(uint16_t driverNum, uint32_t schedule, uint8_t cycleSeconds, bool now); 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 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 DMDUpdateGlobalConfig(PRDMDGlobalConfig *dmdGlobalConfig);
PRResult DMDDraw(uint8_t * dots, uint16_t columns, uint8_t rows, uint8_t numSubFrames); PRResult DMDDraw(uint8_t * dots, uint16_t columns, uint8_t rows, uint8_t numSubFrames);
@@ -138,6 +138,8 @@ protected:
PRDriverGlobalConfig driverGlobalConfig; PRDriverGlobalConfig driverGlobalConfig;
PRDriverGroupConfig driverGroups[maxDriverGroups]; PRDriverGroupConfig driverGroups[maxDriverGroups];
PRDriverState drivers[maxDrivers]; PRDriverState drivers[maxDrivers];
PRSwitchRule switchRules[maxSwitchRules];
PRSwitchRuleInternal switchRules[maxSwitchRules];
queue<uint32_t> freeSwitchRules; /**< Addresses of available switch rules. */
PRSwitchRuleInternal *GetSwitchRuleByAddress(uint32_t addr);
}; };

View File

@@ -125,19 +125,35 @@ int32_t CreateDriverUpdateBurst ( uint32_t * burst, PRDriverState *driver) {
return kPRSuccess; return kPRSuccess;
} }
int32_t CreateSwitchesUpdateRulesBurst ( uint32_t * burst, PRSwitchRule *rule_record) { int32_t CreateSwitchRuleAddr(uint8_t switchNum, PREventType eventType)
uint32_t addr; {
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]; uint32_t driver_command[3];
CreateDriverUpdateBurst ( driver_command, &(rule_record->driver)); 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[0] = CreateBurstCommand (P_ROC_BUS_STATE_CHANGE_PROC_SELECT, addr, 3 );
burst[1] = driver_command[1]; burst[1] = driver_command[1];
burst[2] = driver_command[2]; burst[2] = driver_command[2];

View File

@@ -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; 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); 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 CreateDriverUpdateGlobalConfigBurst ( uint32_t * burst, PRDriverGlobalConfig *driver_globals);
int32_t CreateDriverUpdateGroupConfigBurst ( uint32_t * burst, PRDriverGroupConfig *driver_group); int32_t CreateDriverUpdateGroupConfigBurst ( uint32_t * burst, PRDriverGroupConfig *driver_group);
int32_t CreateDriverUpdateBurst ( uint32_t * burst, PRDriverState *driver); 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); 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_ #endif // _PROC_HARDWARE_H_

View File

@@ -126,9 +126,9 @@ PR_EXPORT PRResult PRDriverPatter(PRHandle handle, uint16_t driverNum, uint16_t
// Switches // 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) PR_EXPORT int32_t PRDMDUpdateGlobalConfig(PRHandle handle, PRDMDGlobalConfig *dmdGlobalConfig)