1
0
mirror of https://github.com/preble/libpinproc synced 2026-02-22 18:15:25 +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
The MIT License
#### The MIT License
Copyright (c) 2009 Gerry Stellenberg, Adam Preble
Permission is hereby granted, free of charge, to any person

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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)
{

View File

@@ -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);
};

View File

@@ -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];

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;
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_

View File

@@ -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)