mirror of
https://github.com/preble/libpinproc
synced 2026-02-24 18:25:23 +01:00
Merge branch 'master' into python
This commit is contained in:
@@ -13,6 +13,6 @@ 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)
|
||||
add_executable(pinproctest examples/pinproctest/pinproctest.cpp examples/pinproctest/drivers.cpp examples/pinproctest/dmd.cpp examples/pinproctest/switches.cpp)
|
||||
target_link_libraries(pinproctest pinproc usb ftdi yaml-cpp)
|
||||
|
||||
|
||||
102
examples/pinproctest/dmd.cpp
Normal file
102
examples/pinproctest/dmd.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
#include "pinproctest.h"
|
||||
|
||||
|
||||
void ConfigureDMD(PRHandle proc)
|
||||
{
|
||||
int i;
|
||||
|
||||
// Create the structure that holds the DMD settings
|
||||
PRDMDConfig dmdConfig;
|
||||
memset(&dmdConfig, 0x0, sizeof(dmdConfig));
|
||||
|
||||
dmdConfig.numRows = kDMDRows;
|
||||
dmdConfig.numColumns = kDMDColumns;
|
||||
dmdConfig.numSubFrames = kDMDSubFrames;
|
||||
|
||||
for (i = 0; i < kDMDSubFrames; i++)
|
||||
{
|
||||
dmdConfig.rclkLowCycles[i] = 15;
|
||||
dmdConfig.latchHighCycles[i] = 15;
|
||||
dmdConfig.dotclkHalfPeriod[i] = 1;
|
||||
}
|
||||
|
||||
dmdConfig.deHighCycles[0] = 250;
|
||||
dmdConfig.deHighCycles[1] = 400;
|
||||
dmdConfig.deHighCycles[2] = 180;
|
||||
dmdConfig.deHighCycles[3] = 800;
|
||||
|
||||
PRDMDUpdateConfig(proc, &dmdConfig);
|
||||
}
|
||||
|
||||
// Display a simple pattern to verify DMD functionality.
|
||||
// 16 diagonal lines will rotate to the right. Every two rows will get brighter,
|
||||
// starting with dim dots at the top.
|
||||
void UpdateDots( unsigned char * dots, unsigned int dotOffset )
|
||||
{
|
||||
int row,col,subFrame,color,mappedColor,loopCtr,byte_shifter;
|
||||
const int rate_reduction_divisor = 1;
|
||||
|
||||
loopCtr = dotOffset/rate_reduction_divisor;
|
||||
color = pow(2,kDMDSubFrames) - 1;
|
||||
byte_shifter = 0x80;
|
||||
|
||||
// Slow it down just a tad
|
||||
if (dotOffset%rate_reduction_divisor == 0)
|
||||
{
|
||||
// Set up byte_shifter to rotate pattern to the right.
|
||||
byte_shifter = pow(2,(loopCtr%8));
|
||||
|
||||
// Clear the DMD dots every time the rotation occurs
|
||||
memset(dots,0,((kDMDColumns*kDMDRows)/8)*kDMDSubFrames);
|
||||
|
||||
// Loop through all of the rows
|
||||
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 (col = 0; col < kDMDColumns / 8; col++)
|
||||
{
|
||||
// Loop through each subframe
|
||||
for (subFrame = 0; subFrame < kDMDSubFrames; subFrame++)
|
||||
{
|
||||
// Turn on the byte in each sub-frame that's enabled
|
||||
// active for the color code.
|
||||
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 (row % (int)((kDMDRows/pow(2,kDMDSubFrames))) == 0) color--;
|
||||
if (byte_shifter == 1) byte_shifter = 0x80;
|
||||
else byte_shifter = byte_shifter >> 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
159
examples/pinproctest/drivers.cpp
Normal file
159
examples/pinproctest/drivers.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
#include "pinproctest.h"
|
||||
|
||||
|
||||
|
||||
void ConfigureDrivers(PRHandle proc, PRMachineType machineType, YAML::Node& yamlDoc)
|
||||
{
|
||||
int i;
|
||||
|
||||
const int WPCDriverLoopTime = 4; // milliseconds
|
||||
const int SternDriverLoopTime = 2; // milliseconds
|
||||
|
||||
const 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};
|
||||
const int mappedSternDriverGroupEnableIndex[] = {0, 0, 0, 0, 1, 0, 2, 3, 0, 0, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9};
|
||||
const int mappedWPCDriverGroupSlowTime[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 400, 400, 400, 400, 400, 400, 400, 400, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
const int mappedSternDriverGroupSlowTime[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 200, 0, 200, 0, 200, 0, 200, 0, 200, 0, 200, 0, 200};
|
||||
const int mappedWPCDriverGroupActivateIndex[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
const int mappedSternDriverGroupActivateIndex[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7};
|
||||
|
||||
const int watchdogResetTime = 1000; // milliseconds
|
||||
|
||||
int mappedDriverGroupEnableIndex[kPRDriverGroupsMax];
|
||||
int mappedDriverGroupSlowTime[kPRDriverGroupsMax];
|
||||
int mappedDriverGroupActivateIndex[kPRDriverGroupsMax];
|
||||
int rowEnableIndex1;
|
||||
int rowEnableIndex0;
|
||||
bool tickleSternWatchdog;
|
||||
bool globalPolarity;
|
||||
bool activeLowMatrixRows;
|
||||
int driverLoopTime;
|
||||
int slowGroupTime;
|
||||
int numMatrixGroups;
|
||||
bool encodeEnables;
|
||||
int rowEnableSelect;
|
||||
|
||||
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
|
||||
memcpy(mappedDriverGroupSlowTime,mappedWPCDriverGroupSlowTime,
|
||||
sizeof(mappedDriverGroupSlowTime));
|
||||
memcpy(mappedDriverGroupActivateIndex,mappedWPCDriverGroupActivateIndex,
|
||||
sizeof(mappedDriverGroupActivateIndex));
|
||||
numMatrixGroups = 8;
|
||||
encodeEnables = false;
|
||||
rowEnableSelect = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case kPRMachineStern:
|
||||
{
|
||||
memcpy(mappedDriverGroupEnableIndex,mappedSternDriverGroupEnableIndex,
|
||||
sizeof(mappedDriverGroupEnableIndex));
|
||||
rowEnableIndex1 = 6; // Unused in Stern
|
||||
rowEnableIndex0 = 10;
|
||||
tickleSternWatchdog = true;
|
||||
globalPolarity = true;
|
||||
activeLowMatrixRows = false;
|
||||
driverLoopTime = 2; // milliseconds
|
||||
memcpy(mappedDriverGroupSlowTime,mappedSternDriverGroupSlowTime,
|
||||
sizeof(mappedDriverGroupSlowTime));
|
||||
memcpy(mappedDriverGroupActivateIndex,mappedSternDriverGroupActivateIndex,
|
||||
sizeof(mappedDriverGroupActivateIndex));
|
||||
numMatrixGroups = 16;
|
||||
encodeEnables = true;
|
||||
rowEnableSelect = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PRDriverGlobalConfig globals;
|
||||
globals.enableOutputs = false;
|
||||
globals.globalPolarity = globalPolarity;
|
||||
globals.useClear = false;
|
||||
globals.strobeStartSelect = false;
|
||||
globals.startStrobeTime = driverLoopTime; // milliseconds per output loop
|
||||
globals.matrixRowEnableIndex1 = rowEnableIndex1;
|
||||
globals.matrixRowEnableIndex0 = rowEnableIndex0;
|
||||
globals.activeLowMatrixRows = activeLowMatrixRows;
|
||||
globals.tickleSternWatchdog = tickleSternWatchdog;
|
||||
globals.encodeEnables = encodeEnables;
|
||||
globals.watchdogExpired = false;
|
||||
globals.watchdogEnable = true;
|
||||
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:
|
||||
|
||||
// Enable now without the outputs enabled:
|
||||
PRDriverUpdateGlobalConfig(proc, &globals);
|
||||
|
||||
// Now enable the outputs: (TODO: Why?)
|
||||
globals.enableOutputs = true;
|
||||
PRDriverUpdateGlobalConfig(proc, &globals);
|
||||
|
||||
// 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 = 4; i < 10; i++)
|
||||
{
|
||||
PRDriverGetGroupConfig(proc, i, &group);
|
||||
group.slowTime = 0;
|
||||
group.enableIndex = mappedDriverGroupEnableIndex[i];
|
||||
group.rowActivateIndex = 0;
|
||||
group.rowEnableSelect = 0;
|
||||
group.matrixed = false;
|
||||
group.polarity = globalPolarity;
|
||||
group.active = 1;
|
||||
group.disableStrobeAfter = false;
|
||||
|
||||
PRDriverUpdateGroupConfig(proc, &group);
|
||||
}
|
||||
|
||||
// The following 8 groups are configured for the feature lamp matrix.
|
||||
for (i = 10; i < 10 + numMatrixGroups; i++) {
|
||||
PRDriverGetGroupConfig(proc, i, &group);
|
||||
group.slowTime = mappedDriverGroupSlowTime[i];
|
||||
group.enableIndex = mappedDriverGroupEnableIndex[i];
|
||||
group.rowActivateIndex = mappedDriverGroupActivateIndex[i];
|
||||
group.rowEnableSelect = rowEnableSelect;
|
||||
group.matrixed = 1;
|
||||
group.polarity = globalPolarity;
|
||||
group.active = 1;
|
||||
group.disableStrobeAfter = mappedDriverGroupSlowTime[i] != 0;
|
||||
PRDriverUpdateGroupConfig(proc, &group);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright (c) 2009 Gerry Stellenberg, Adam Preble
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
@@ -27,31 +26,11 @@
|
||||
* pinproctest.cpp
|
||||
* libpinproc
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <cmath>
|
||||
#include "../../include/pinproc.h" // Include libpinproc's header.
|
||||
#include <fstream>
|
||||
#include <yaml-cpp/yaml.h>
|
||||
#include <sys/time.h>
|
||||
#include "pinproctest.h"
|
||||
|
||||
#define kFlippersSection "PRFlippers"
|
||||
#define kBumpersSection "PRBumpers"
|
||||
#define kCoilsSection "PRCoils"
|
||||
#define kSwitchesSection "PRSwitches"
|
||||
#define kNumberField "number"
|
||||
|
||||
#define kFlipperPulseTime (34) // 34 ms
|
||||
#define kBumperPulseTime (25) // 25 ms
|
||||
|
||||
#define kDMDColumns (128)
|
||||
#define kDMDRows (32)
|
||||
#define kDMDSubFrames (4) // For color depth of 16
|
||||
|
||||
/** Demonstration of the custom logging callback. */
|
||||
void TestLogger(const char *text)
|
||||
void TestLogger(PRLogLevel level, const char *text)
|
||||
{
|
||||
fprintf(stderr, "TEST: %s", text);
|
||||
}
|
||||
@@ -91,253 +70,6 @@ PRResult LoadConfiguration(YAML::Node& yamlDoc, const char *yamlFilePath)
|
||||
return kPRSuccess;
|
||||
}
|
||||
|
||||
void ConfigureDrivers(PRHandle proc, PRMachineType machineType, YAML::Node& yamlDoc)
|
||||
{
|
||||
int i;
|
||||
int mappedDriverGroupEnableIndex[kPRDriverGroupsMax];
|
||||
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;
|
||||
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 = globalPolarity;
|
||||
globals.useClear = false;
|
||||
globals.strobeStartSelect = 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 = 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:
|
||||
|
||||
// Enable now without the outputs enabled:
|
||||
PRDriverUpdateGlobalConfig(proc, &globals);
|
||||
|
||||
// Now enable the outputs: (TODO: Why?)
|
||||
globals.enableOutputs = true;
|
||||
PRDriverUpdateGlobalConfig(proc, &globals);
|
||||
|
||||
// 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 = 4; i < 10; i++)
|
||||
{
|
||||
PRDriverGetGroupConfig(proc, i, &group);
|
||||
group.slowTime = 0;
|
||||
group.enableIndex = mappedDriverGroupEnableIndex[i];
|
||||
group.rowActivateIndex = 0;
|
||||
group.rowEnableSelect = 0;
|
||||
group.matrixed = false;
|
||||
group.polarity = false;
|
||||
group.active = 1;
|
||||
group.disableStrobeAfter = false;
|
||||
|
||||
PRDriverUpdateGroupConfig(proc, &group);
|
||||
}
|
||||
|
||||
// The following 8 groups are configured for the feature lamp matrix.
|
||||
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;
|
||||
group.active = 1;
|
||||
group.disableStrobeAfter = 1;
|
||||
PRDriverUpdateGroupConfig(proc, &group);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigureSwitches(PRHandle proc, YAML::Node& yamlDoc)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
|
||||
void ConfigureWPCFlipperSwitchRule (PRHandle proc, int swNum, int mainCoilNum, int holdCoilNum, int pulseTime)
|
||||
{
|
||||
const int numDriverRules = 2;
|
||||
PRDriverState drivers[numDriverRules];
|
||||
PRSwitchRule sw;
|
||||
|
||||
// Flipper on rules
|
||||
PRDriverGetState(proc, mainCoilNum, &drivers[0]);
|
||||
PRDriverStatePulse(&drivers[0],pulseTime); // Pulse coil for 34ms.
|
||||
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);
|
||||
sw.notifyHost = true;
|
||||
PRSwitchUpdateRule(proc, swNum, kPREventTypeSwitchClosedDebounced, &sw, NULL, 0);
|
||||
|
||||
// Flipper off rules
|
||||
PRDriverGetState(proc, mainCoilNum, &drivers[0]);
|
||||
PRDriverStateDisable(&drivers[0]); // Disable main coil
|
||||
PRDriverGetState(proc, holdCoilNum, &drivers[1]);
|
||||
PRDriverStateDisable(&drivers[1]); // Disable hold coil
|
||||
sw.notifyHost = false;
|
||||
PRSwitchUpdateRule(proc, swNum, kPREventTypeSwitchOpenNondebounced, &sw, drivers, numDriverRules);
|
||||
sw.notifyHost = true;
|
||||
PRSwitchUpdateRule(proc, swNum, kPREventTypeSwitchOpenDebounced, &sw, NULL, 0);
|
||||
}
|
||||
|
||||
void ConfigureBumperRule (PRHandle proc, int swNum, int coilNum, int pulseTime)
|
||||
{
|
||||
const int numDriverRules = 1;
|
||||
PRDriverState drivers[numDriverRules];
|
||||
PRSwitchRule sw;
|
||||
|
||||
// Lower Right Flipper On
|
||||
PRDriverGetState(proc, coilNum, &drivers[0]);
|
||||
PRDriverStatePulse(&drivers[0],pulseTime); // Pulse coil for 34ms.
|
||||
sw.notifyHost = false;
|
||||
PRSwitchUpdateRule(proc, swNum, kPREventTypeSwitchClosedNondebounced, &sw, drivers, numDriverRules);
|
||||
sw.notifyHost = true;
|
||||
PRSwitchUpdateRule(proc, swNum, kPREventTypeSwitchClosedDebounced, &sw, NULL, 0);
|
||||
}
|
||||
|
||||
void ConfigureSwitchRules(PRHandle proc, YAML::Node& yamlDoc)
|
||||
{
|
||||
// WPC Flippers
|
||||
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][kNumberField] >> swNum;
|
||||
yamlDoc[kCoilsSection][flipperName + "Main"][kNumberField] >> coilMain;
|
||||
yamlDoc[kCoilsSection][flipperName + "Hold"][kNumberField] >> coilHold;
|
||||
ConfigureWPCFlipperSwitchRule (proc, swNum, coilMain, coilHold, kFlipperPulseTime);
|
||||
}
|
||||
|
||||
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][kNumberField] >> swNum;
|
||||
yamlDoc[kCoilsSection][bumperName][kNumberField] >> coilNum;
|
||||
ConfigureBumperRule (proc, swNum, coilNum, kBumperPulseTime);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigureDMD(PRHandle proc)
|
||||
{
|
||||
int i;
|
||||
|
||||
// Create the structure that holds the DMD settings
|
||||
PRDMDConfig dmdConfig;
|
||||
memset(&dmdConfig, 0x0, sizeof(dmdConfig));
|
||||
|
||||
dmdConfig.numRows = kDMDRows;
|
||||
dmdConfig.numColumns = kDMDColumns;
|
||||
dmdConfig.numSubFrames = kDMDSubFrames;
|
||||
|
||||
for (i = 0; i < kDMDSubFrames; i++)
|
||||
{
|
||||
dmdConfig.rclkLowCycles[i] = 15;
|
||||
dmdConfig.latchHighCycles[i] = 15;
|
||||
dmdConfig.dotclkHalfPeriod[i] = 1;
|
||||
}
|
||||
|
||||
dmdConfig.deHighCycles[0] = 250;
|
||||
dmdConfig.deHighCycles[1] = 400;
|
||||
dmdConfig.deHighCycles[2] = 180;
|
||||
dmdConfig.deHighCycles[3] = 800;
|
||||
|
||||
PRDMDUpdateConfig(proc, &dmdConfig);
|
||||
}
|
||||
|
||||
// Display a simple pattern to verify DMD functionality.
|
||||
// 16 diagonal lines will rotate to the right. Every two rows will get brighter,
|
||||
// starting with dim dots at the top.
|
||||
void UpdateDots( unsigned char * dots, unsigned int dotOffset )
|
||||
{
|
||||
int row,col,subFrame,color,mappedColor,loopCtr,byte_shifter;
|
||||
const int rate_reduction_divisor = 1;
|
||||
|
||||
loopCtr = dotOffset/rate_reduction_divisor;
|
||||
color = pow(2,kDMDSubFrames) - 1;
|
||||
byte_shifter = 0x80;
|
||||
|
||||
// Slow it down just a tad
|
||||
if (dotOffset%rate_reduction_divisor == 0)
|
||||
{
|
||||
// Set up byte_shifter to rotate pattern to the right.
|
||||
byte_shifter = pow(2,(loopCtr%8));
|
||||
|
||||
// Clear the DMD dots every time the rotation occurs
|
||||
memset(dots,0,((kDMDColumns*kDMDRows)/8)*kDMDSubFrames);
|
||||
|
||||
// Loop through all of the rows
|
||||
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 (col = 0; col < kDMDColumns / 8; col++)
|
||||
{
|
||||
// Loop through each subframe
|
||||
for (subFrame = 0; subFrame < kDMDSubFrames; subFrame++)
|
||||
{
|
||||
// Turn on the byte in each sub-frame that's enabled
|
||||
// active for the color code.
|
||||
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 (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;
|
||||
@@ -427,7 +159,10 @@ int main(int argc, const char **argv)
|
||||
// Finally instantiate the P-ROC device:
|
||||
PRHandle proc = PRCreate(machineType);
|
||||
if (proc == kPRHandleInvalid)
|
||||
{
|
||||
fprintf(stderr, "Error during PRCreate: %s\n", PRGetLastErrorText());
|
||||
return 1;
|
||||
}
|
||||
|
||||
PRReset(proc, kPRResetFlagUpdateDevice); // Reset the device structs and write them into the device.
|
||||
|
||||
@@ -444,7 +179,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);
|
||||
|
||||
|
||||
59
examples/pinproctest/pinproctest.h
Normal file
59
examples/pinproctest/pinproctest.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* 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.
|
||||
*/
|
||||
/*
|
||||
* pinproctest.cpp
|
||||
* libpinproc
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <cmath>
|
||||
#include "../../include/pinproc.h" // Include libpinproc's header.
|
||||
#include <fstream>
|
||||
#include <yaml-cpp/yaml.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#define kFlippersSection "PRFlippers"
|
||||
#define kBumpersSection "PRBumpers"
|
||||
#define kCoilsSection "PRCoils"
|
||||
#define kSwitchesSection "PRSwitches"
|
||||
#define kNumberField "number"
|
||||
|
||||
#define kFlipperPulseTime (34) // 34 ms
|
||||
#define kBumperPulseTime (25) // 25 ms
|
||||
|
||||
#define kDMDColumns (128)
|
||||
#define kDMDRows (32)
|
||||
#define kDMDSubFrames (4) // For color depth of 16
|
||||
|
||||
void ConfigureDrivers(PRHandle proc, PRMachineType machineType, YAML::Node& yamlDoc);
|
||||
|
||||
void ConfigureSwitches(PRHandle proc, YAML::Node& yamlDoc);
|
||||
void ConfigureSwitchRules(PRHandle proc, YAML::Node& yamlDoc);
|
||||
|
||||
void ConfigureDMD(PRHandle proc);
|
||||
void UpdateDots(unsigned char * dots, unsigned int dotOffset);
|
||||
109
examples/pinproctest/switches.cpp
Normal file
109
examples/pinproctest/switches.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
#include "pinproctest.h"
|
||||
|
||||
|
||||
void ConfigureSwitches(PRHandle proc, YAML::Node& yamlDoc)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
|
||||
void ConfigureWPCFlipperSwitchRule (PRHandle proc, int swNum, int mainCoilNum, int holdCoilNum, int pulseTime)
|
||||
{
|
||||
const int numDriverRules = 2;
|
||||
PRDriverState drivers[numDriverRules];
|
||||
PRSwitchRule sw;
|
||||
|
||||
// Flipper on rules
|
||||
PRDriverGetState(proc, mainCoilNum, &drivers[0]);
|
||||
PRDriverStatePulse(&drivers[0],pulseTime); // Pulse coil for 34ms.
|
||||
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);
|
||||
sw.notifyHost = true;
|
||||
PRSwitchUpdateRule(proc, swNum, kPREventTypeSwitchClosedDebounced, &sw, NULL, 0);
|
||||
|
||||
// Flipper off rules
|
||||
PRDriverGetState(proc, mainCoilNum, &drivers[0]);
|
||||
PRDriverStateDisable(&drivers[0]); // Disable main coil
|
||||
PRDriverGetState(proc, holdCoilNum, &drivers[1]);
|
||||
PRDriverStateDisable(&drivers[1]); // Disable hold coil
|
||||
sw.notifyHost = false;
|
||||
PRSwitchUpdateRule(proc, swNum, kPREventTypeSwitchOpenNondebounced, &sw, drivers, numDriverRules);
|
||||
sw.notifyHost = true;
|
||||
PRSwitchUpdateRule(proc, swNum, kPREventTypeSwitchOpenDebounced, &sw, NULL, 0);
|
||||
}
|
||||
|
||||
void ConfigureBumperRule (PRHandle proc, int swNum, int coilNum, int pulseTime)
|
||||
{
|
||||
const int numDriverRules = 1;
|
||||
PRDriverState drivers[numDriverRules];
|
||||
PRSwitchRule sw;
|
||||
|
||||
// Lower Right Flipper On
|
||||
PRDriverGetState(proc, coilNum, &drivers[0]);
|
||||
PRDriverStatePulse(&drivers[0],pulseTime); // Pulse coil for 34ms.
|
||||
sw.notifyHost = false;
|
||||
PRSwitchUpdateRule(proc, swNum, kPREventTypeSwitchClosedNondebounced, &sw, drivers, numDriverRules);
|
||||
sw.notifyHost = true;
|
||||
PRSwitchUpdateRule(proc, swNum, kPREventTypeSwitchClosedDebounced, &sw, NULL, 0);
|
||||
}
|
||||
|
||||
void ConfigureSwitchRules(PRHandle proc, YAML::Node& yamlDoc)
|
||||
{
|
||||
// WPC Flippers
|
||||
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][kNumberField] >> swNum;
|
||||
yamlDoc[kCoilsSection][flipperName + "Main"][kNumberField] >> coilMain;
|
||||
yamlDoc[kCoilsSection][flipperName + "Hold"][kNumberField] >> coilHold;
|
||||
ConfigureWPCFlipperSwitchRule (proc, swNum, coilMain, coilHold, kFlipperPulseTime);
|
||||
}
|
||||
|
||||
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][kNumberField] >> swNum;
|
||||
yamlDoc[kCoilsSection][bumperName][kNumberField] >> coilNum;
|
||||
ConfigureBumperRule (proc, swNum, coilNum, kBumperPulseTime);
|
||||
}
|
||||
}
|
||||
@@ -71,9 +71,20 @@ typedef int32_t PRResult; /**< See: #kPRSuccess and #kPRFailure. */
|
||||
typedef void * PRHandle; /**< Opaque type used to reference an individual P-ROC device. Created with PRCreate() and destroyed with PRDelete(). This value is used as the first parameter to all P-ROC API function calls. */
|
||||
#define kPRHandleInvalid (0) /**< Value returned by PRCreate() on failure. Indicates an invalid #PRHandle. */
|
||||
|
||||
typedef void (*PRLogCallback)(const char *text); /**< Function pointer type for a custom logging callback. See: PRLogSetCallback(). */
|
||||
typedef enum PRLogLevel {
|
||||
kPRLogVerbose,
|
||||
kPRLogInfo,
|
||||
kPRLogWarning,
|
||||
kPRLogError
|
||||
} PRLogLevel;
|
||||
|
||||
typedef void (*PRLogCallback)(PRLogLevel level, const char *text); /**< Function pointer type for a custom logging callback. See: PRLogSetCallback(). */
|
||||
PR_EXPORT void PRLogSetCallback(PRLogCallback callback); /**< Replaces the default logging handler with the given callback function. */
|
||||
|
||||
PR_EXPORT void PRLogSetLevel(PRLogLevel level);
|
||||
|
||||
PR_EXPORT const char *PRGetLastErrorText();
|
||||
|
||||
/**
|
||||
* @defgroup device Device Creation & Deletion
|
||||
* @{
|
||||
@@ -145,7 +156,7 @@ typedef struct PRDriverGroupConfig {
|
||||
|
||||
typedef struct PRDriverState {
|
||||
uint16_t driverNum;
|
||||
uint32_t outputDriveTime;
|
||||
uint8_t outputDriveTime;
|
||||
bool_t polarity;
|
||||
bool_t state;
|
||||
bool_t waitForFirstTimeSlot;
|
||||
@@ -179,7 +190,7 @@ PR_EXPORT PRResult PRDriverDisable(PRHandle handle, uint16_t driverNum);
|
||||
* Pulses the given driver for a number of milliseconds.
|
||||
* This function is provided for convenience. See PRDriverStatePulse() for a full description.
|
||||
*/
|
||||
PR_EXPORT PRResult PRDriverPulse(PRHandle handle, uint16_t driverNum, int milliseconds);
|
||||
PR_EXPORT PRResult PRDriverPulse(PRHandle handle, uint16_t driverNum, uint8_t milliseconds);
|
||||
/**
|
||||
* Assigns a repeating schedule to the given driver.
|
||||
* This function is provided for convenience. See PRDriverStateSchedule() for a full description.
|
||||
@@ -203,7 +214,7 @@ PR_EXPORT void PRDriverStateDisable(PRDriverState *driverState);
|
||||
* @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 PRSwitchUpdateRule() to have any effect.
|
||||
*/
|
||||
PR_EXPORT void PRDriverStatePulse(PRDriverState *driverState, int milliseconds);
|
||||
PR_EXPORT void PRDriverStatePulse(PRDriverState *driverState, uint8_t milliseconds);
|
||||
/**
|
||||
* Changes the given #PRDriverState to reflect a scheduled state.
|
||||
* Assigns a repeating schedule to the given driver.
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
66640E5E0FD1CFB6003135D8 /* dmd.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66640E5B0FD1CFB6003135D8 /* dmd.cpp */; };
|
||||
66640E5F0FD1CFB6003135D8 /* drivers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66640E5C0FD1CFB6003135D8 /* drivers.cpp */; };
|
||||
66640E600FD1CFB6003135D8 /* switches.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66640E5D0FD1CFB6003135D8 /* switches.cpp */; };
|
||||
6682492C0FC079050051560E /* pinproc.h in Headers */ = {isa = PBXBuildFile; fileRef = 6682492B0FC079050051560E /* pinproc.h */; };
|
||||
6682493A0FC07B2A0051560E /* pinproc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 668249390FC07B2A0051560E /* pinproc.cpp */; };
|
||||
668249420FC07D900051560E /* PRDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 668249400FC07D900051560E /* PRDevice.h */; };
|
||||
@@ -29,6 +32,10 @@
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
66640E5B0FD1CFB6003135D8 /* dmd.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dmd.cpp; path = examples/pinproctest/dmd.cpp; sourceTree = "<group>"; };
|
||||
66640E5C0FD1CFB6003135D8 /* drivers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = drivers.cpp; path = examples/pinproctest/drivers.cpp; sourceTree = "<group>"; };
|
||||
66640E5D0FD1CFB6003135D8 /* switches.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = switches.cpp; path = examples/pinproctest/switches.cpp; sourceTree = "<group>"; };
|
||||
66640E610FD1D010003135D8 /* pinproctest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pinproctest.h; path = examples/pinproctest/pinproctest.h; sourceTree = "<group>"; };
|
||||
6682492B0FC079050051560E /* pinproc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pinproc.h; path = include/pinproc.h; sourceTree = "<group>"; };
|
||||
668249390FC07B2A0051560E /* pinproc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = pinproc.cpp; path = src/pinproc.cpp; sourceTree = "<group>"; };
|
||||
668249400FC07D900051560E /* PRDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PRDevice.h; path = src/PRDevice.h; sourceTree = "<group>"; };
|
||||
@@ -105,7 +112,11 @@
|
||||
668249D30FC0A2C10051560E /* pinproctest */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
66640E610FD1D010003135D8 /* pinproctest.h */,
|
||||
668249E20FC0A3960051560E /* pinproctest.cpp */,
|
||||
66640E5B0FD1CFB6003135D8 /* dmd.cpp */,
|
||||
66640E5C0FD1CFB6003135D8 /* drivers.cpp */,
|
||||
66640E5D0FD1CFB6003135D8 /* switches.cpp */,
|
||||
);
|
||||
name = pinproctest;
|
||||
sourceTree = "<group>";
|
||||
@@ -192,6 +203,9 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
668249E30FC0A3960051560E /* pinproctest.cpp in Sources */,
|
||||
66640E5E0FD1CFB6003135D8 /* dmd.cpp in Sources */,
|
||||
66640E5F0FD1CFB6003135D8 /* drivers.cpp in Sources */,
|
||||
66640E600FD1CFB6003135D8 /* switches.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
# define DEBUG(block) block
|
||||
#endif
|
||||
|
||||
extern void PRLog(const char *format, ...);
|
||||
void PRLog(PRLogLevel level, const char *format, ...);
|
||||
void PRSetLastErrorText(const char *format, ...);
|
||||
|
||||
#endif // _PRCOMMON_H_
|
||||
|
||||
@@ -47,13 +47,13 @@ PRDevice* PRDevice::Create(PRMachineType machineType)
|
||||
|
||||
if (dev == NULL)
|
||||
{
|
||||
DEBUG(PRLog("Error allocating memory for P-ROC device\n"));
|
||||
DEBUG(PRLog(kPRLogError, "Error allocating memory for P-ROC device\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!dev->Open())
|
||||
{
|
||||
DEBUG(PRLog("Error opening P-ROC device.\n"));
|
||||
DEBUG(PRLog(kPRLogError, "Error opening P-ROC device.\n"));
|
||||
delete dev;
|
||||
return NULL;
|
||||
}
|
||||
@@ -150,7 +150,7 @@ PRResult PRDevice::DriverUpdateGlobalConfig(PRDriverGlobalConfig *driverGlobalCo
|
||||
uint32_t burst[burstWords];
|
||||
int32_t rc;
|
||||
|
||||
DEBUG(PRLog("Installing driver globals\n"));
|
||||
DEBUG(PRLog(kPRLogInfo, "Installing driver globals\n"));
|
||||
|
||||
this->driverGlobalConfig = *driverGlobalConfig;
|
||||
rc = CreateDriverUpdateGlobalConfigBurst(burst, driverGlobalConfig);
|
||||
@@ -158,8 +158,8 @@ PRResult PRDevice::DriverUpdateGlobalConfig(PRDriverGlobalConfig *driverGlobalCo
|
||||
driverGlobalConfig->watchdogEnable,
|
||||
driverGlobalConfig->watchdogResetTime);
|
||||
|
||||
DEBUG(PRLog("Driver Global words: %x %x\n", burst[0], burst[1]));
|
||||
DEBUG(PRLog("Watchdog words: %x %x\n", burst[2], burst[3]));
|
||||
DEBUG(PRLog(kPRLogVerbose, "Driver Global words: %x %x\n", burst[0], burst[1]));
|
||||
DEBUG(PRLog(kPRLogVerbose, "Watchdog words: %x %x\n", burst[2], burst[3]));
|
||||
return PrepareWriteData(burst, burstWords);
|
||||
}
|
||||
|
||||
@@ -176,10 +176,10 @@ PRResult PRDevice::DriverUpdateGroupConfig(PRDriverGroupConfig *driverGroupConfi
|
||||
int32_t rc;
|
||||
|
||||
driverGroups[driverGroupConfig->groupNum] = *driverGroupConfig;
|
||||
DEBUG(PRLog("Installing driver group\n"));
|
||||
DEBUG(PRLog(kPRLogInfo, "Installing driver group\n"));
|
||||
rc = CreateDriverUpdateGroupConfigBurst(burst, driverGroupConfig);
|
||||
|
||||
DEBUG(PRLog("Words: %x %x\n", burst[0], burst[1]));
|
||||
DEBUG(PRLog(kPRLogVerbose, "Words: %x %x\n", burst[0], burst[1]));
|
||||
return PrepareWriteData(burst, burstWords);
|
||||
}
|
||||
|
||||
@@ -195,18 +195,18 @@ PRResult PRDevice::DriverUpdateState(PRDriverState *driverState)
|
||||
uint32_t burst[burstWords];
|
||||
int32_t rc;
|
||||
|
||||
DEBUG(PRLog("Updating driver #%d\n", driverState->driverNum));
|
||||
DEBUG(PRLog(kPRLogInfo, "Updating driver #%d\n", driverState->driverNum));
|
||||
|
||||
if (driverState->polarity != drivers[driverState->driverNum].polarity && machineType != kPRMachineCustom)
|
||||
{
|
||||
DEBUG(PRLog("Refusing to update driver #%d; polarity differs on non-custom machine.\n", driverState->driverNum));
|
||||
PRSetLastErrorText("Refusing to update driver #%d; polarity differs on non-custom machine.", driverState->driverNum);
|
||||
return kPRFailure;
|
||||
}
|
||||
|
||||
drivers[driverState->driverNum] = *driverState;
|
||||
|
||||
rc = CreateDriverUpdateBurst(burst, &drivers[driverState->driverNum]);
|
||||
DEBUG(PRLog("Words: %x %x %x\n", burst[0], burst[1], burst[2]));
|
||||
DEBUG(PRLog(kPRLogVerbose, "Words: %x %x %x\n", burst[0], burst[1], burst[2]));
|
||||
|
||||
return PrepareWriteData(burst, burstWords);
|
||||
}
|
||||
@@ -241,8 +241,8 @@ PRResult PRDevice::SwitchUpdateConfig(PRSwitchConfig *switchConfig)
|
||||
this->switchConfig = *switchConfig;
|
||||
CreateSwitchUpdateConfigBurst(burst, switchConfig);
|
||||
|
||||
DEBUG(PRLog("Configuring Switch Logic"));
|
||||
DEBUG(PRLog("Words: %x %x\n",burst[0],burst[1]));
|
||||
DEBUG(PRLog(kPRLogInfo, "Configuring Switch Logic"));
|
||||
DEBUG(PRLog(kPRLogVerbose, "Words: %x %x\n",burst[0],burst[1]));
|
||||
|
||||
rc = PrepareWriteData(burst, burstWords);
|
||||
return rc;
|
||||
@@ -256,7 +256,7 @@ PRResult PRDevice::SwitchUpdateRule(uint8_t switchNum, PREventType eventType, PR
|
||||
|
||||
if (switchNum > kPRSwitchPhysicalLast) // Always true due to data type.
|
||||
{
|
||||
DEBUG(PRLog("Switch rule out of range 0-%d\n", kPRSwitchPhysicalLast));
|
||||
PRSetLastErrorText("Switch rule out of range 0-%d", kPRSwitchPhysicalLast);
|
||||
return kPRFailure;
|
||||
}
|
||||
|
||||
@@ -264,7 +264,7 @@ PRResult PRDevice::SwitchUpdateRule(uint8_t switchNum, PREventType eventType, PR
|
||||
// the links.
|
||||
if (numDrivers > 0 && freeSwitchRuleIndexes.size() < numDrivers-1) // -1 because the first switch rule holds the first driver.
|
||||
{
|
||||
DEBUG(PRLog("Not enough free switch rule indexes: %d available, need %d\n", freeSwitchRuleIndexes.size(), numDrivers));
|
||||
PRSetLastErrorText("Not enough free switch rule indexes: %d available, need %d", freeSwitchRuleIndexes.size(), numDrivers);
|
||||
return kPRFailure;
|
||||
}
|
||||
|
||||
@@ -283,7 +283,7 @@ PRResult PRDevice::SwitchUpdateRule(uint8_t switchNum, PREventType eventType, PR
|
||||
uint16_t firstRuleIndex = newRuleIndex;
|
||||
PRSwitchRuleInternal *newRule = GetSwitchRuleByIndex(newRuleIndex);
|
||||
if (newRule->eventType != eventType)
|
||||
DEBUG(PRLog("Unexpected state: switch rule at 0x%x has event type 0x%x (expected 0x%x).\n", newRuleIndex, newRule->eventType, eventType));
|
||||
DEBUG(PRLog(kPRLogWarning, "Unexpected state: switch rule at 0x%x has event type 0x%x (expected 0x%x).\n", newRuleIndex, newRule->eventType, eventType));
|
||||
newRule->notifyHost = rule->notifyHost;
|
||||
newRule->changeOutput = false;
|
||||
newRule->linkActive = false;
|
||||
@@ -313,20 +313,20 @@ PRResult PRDevice::SwitchUpdateRule(uint8_t switchNum, PREventType eventType, PR
|
||||
CreateSwitchUpdateRulesBurst(burst, newRule);
|
||||
}
|
||||
|
||||
DEBUG(PRLog("Rule Words: %x %x %x %x\n", burst[0],burst[1],burst[2],burst[3]));
|
||||
DEBUG(PRLog(kPRLogVerbose, "Rule Words: %x %x %x %x\n", burst[0],burst[1],burst[2],burst[3]));
|
||||
// Write the rule:
|
||||
res = PrepareWriteData(burst, burstSize);
|
||||
if (res != kPRSuccess)
|
||||
{
|
||||
DEBUG(PRLog("Error while writing switch update, attempting to revert switch rule to a safe state..."));
|
||||
DEBUG(PRLog(kPRLogError, "Error while writing switch update, attempting to revert switch rule to a safe state..."));
|
||||
newRule = GetSwitchRuleByIndex(firstRuleIndex);
|
||||
newRule->changeOutput = false;
|
||||
newRule->linkActive = false;
|
||||
CreateSwitchUpdateRulesBurst(burst, newRule);
|
||||
if (PrepareWriteData(burst, burstSize) == kPRSuccess)
|
||||
DEBUG(PRLog("Disabled successfully.\n"));
|
||||
DEBUG(PRLog(kPRLogError, "Disabled successfully.\n"));
|
||||
else
|
||||
DEBUG(PRLog("Failed to disable.\n"));
|
||||
DEBUG(PRLog(kPRLogError, "Failed to disable.\n"));
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -337,7 +337,7 @@ PRResult PRDevice::SwitchUpdateRule(uint8_t switchNum, PREventType eventType, PR
|
||||
else
|
||||
{
|
||||
CreateSwitchUpdateRulesBurst(burst, newRule);
|
||||
DEBUG(PRLog("Rule Words: %x %x %x %x\n", burst[0],burst[1],burst[2],burst[3]));
|
||||
DEBUG(PRLog(kPRLogVerbose, "Rule Words: %x %x %x %x\n", burst[0],burst[1],burst[2],burst[3]));
|
||||
|
||||
// Write the rule:
|
||||
res = PrepareWriteData(burst, burstSize);
|
||||
@@ -355,8 +355,8 @@ int32_t PRDevice::DMDUpdateConfig(PRDMDConfig *dmdConfig)
|
||||
this->dmdConfig = *dmdConfig;
|
||||
CreateDMDUpdateConfigBurst(burst, dmdConfig);
|
||||
|
||||
DEBUG(PRLog("Configuring DMD"));
|
||||
DEBUG(PRLog("Words: %x %x %x %x %x %x %x\n",burst[0],burst[1],burst[2],burst[3],
|
||||
DEBUG(PRLog(kPRLogInfo, "Configuring DMD"));
|
||||
DEBUG(PRLog(kPRLogVerbose, "Words: %x %x %x %x %x %x %x\n",burst[0],burst[1],burst[2],burst[3],
|
||||
burst[4],burst[5],burst[6]));
|
||||
|
||||
rc = PrepareWriteData(burst, burstWords);
|
||||
@@ -417,24 +417,21 @@ PRResult PRDevice::Open()
|
||||
{
|
||||
// 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"));
|
||||
DEBUG(PRLog(kPRLogInfo, "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"));
|
||||
DEBUG(PRLog(kPRLogInfo, "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();
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG(PRLog("Failed to verify chip ID."));
|
||||
res = kPRFailure;
|
||||
if (res == kPRFailure)
|
||||
DEBUG(PRLog(kPRLogWarning, "Unable to read Chip ID - P-ROC could not be initialized.\n"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -474,19 +471,20 @@ PRResult PRDevice::VerifyChipID()
|
||||
|
||||
if (wordsRead == 5) {
|
||||
//std::cout << rc << " words read. \n"
|
||||
DEBUG(PRLog("FPGA Chip ID: 0x%x\n", buffer[1]));
|
||||
DEBUG(PRLog("FPGA Chip Version/Rev: %d.%d\n", buffer[2] >> 16, buffer[2] & 0xffff));
|
||||
DEBUG(PRLog("Watchdog Settings: 0x%x\n", buffer[3]));
|
||||
DEBUG(PRLog("Switches: 0x%x\n", buffer[4]));
|
||||
DEBUG(PRLog(kPRLogInfo, "FPGA Chip ID: 0x%x\n", buffer[1]));
|
||||
DEBUG(PRLog(kPRLogInfo, "FPGA Chip Version/Rev: %d.%d\n", buffer[2] >> 16, buffer[2] & 0xffff));
|
||||
DEBUG(PRLog(kPRLogInfo, "Watchdog Settings: 0x%x\n", buffer[3]));
|
||||
DEBUG(PRLog(kPRLogInfo, "Switches: 0x%x\n", buffer[4]));
|
||||
rc = kPRSuccess;
|
||||
}
|
||||
else {
|
||||
DEBUG(PRLog("Error reading Chip IP and Version. Incorrect number of bytes received from read_data().\n"));
|
||||
DEBUG(PRLog(kPRLogError, "Error reading Chip IP and Version. Incorrect number of bytes received from read_data().\n"));
|
||||
rc = kPRFailure;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DEBUG(PRLog("Unable to read Chip ID - P-ROC not yet initialized.\n"));
|
||||
else
|
||||
{
|
||||
// Return failure without logging; calling function must log.
|
||||
rc = kPRFailure;
|
||||
}
|
||||
return (rc);
|
||||
@@ -502,7 +500,7 @@ 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));
|
||||
PRSetLastErrorText("%d words Exceeds write capabilities. Restrict write requests to %d words.", numWords, maxWriteWords);
|
||||
return kPRFailure;
|
||||
}
|
||||
|
||||
@@ -559,7 +557,7 @@ PRResult PRDevice::WriteData(uint32_t * words, int32_t numWords)
|
||||
|
||||
if (bytesWritten != bytesToWrite)
|
||||
{
|
||||
DEBUG(PRLog("Error in WriteData: wrote %d of %d bytes\n", bytesWritten, bytesToWrite));
|
||||
PRSetLastErrorText("Error in WriteData: wrote %d of %d bytes", bytesWritten, bytesToWrite);
|
||||
return kPRFailure;
|
||||
}
|
||||
else
|
||||
@@ -596,7 +594,7 @@ int32_t PRDevice::ReadData(uint32_t *buffer, int32_t num_words)
|
||||
else {
|
||||
rc = 0;
|
||||
}
|
||||
DEBUG(PRLog("Read num bytes: %d\n", rc));
|
||||
DEBUG(PRLog(kPRLogVerbose, "Read num bytes: %d\n", rc));
|
||||
return (rc);
|
||||
}
|
||||
|
||||
@@ -628,7 +626,7 @@ int32_t PRDevice::CollectReadData()
|
||||
num_collected_bytes += rc;
|
||||
if (rc > 0)
|
||||
{
|
||||
DEBUG(PRLog("Collected bytes: %d\n", rc));
|
||||
DEBUG(PRLog(kPRLogVerbose, "Collected bytes: %d\n", rc));
|
||||
}
|
||||
return (rc);
|
||||
}
|
||||
@@ -643,7 +641,7 @@ PRResult PRDevice::SortReturningData()
|
||||
|
||||
while (num_words >= 2) {
|
||||
rc = ReadData(rd_buffer, 1);
|
||||
DEBUG(PRLog("New returning word: 0x%x\n", rd_buffer[0]));
|
||||
DEBUG(PRLog(kPRLogVerbose, "New returning word: 0x%x\n", rd_buffer[0]));
|
||||
|
||||
switch ( (rd_buffer[0] & P_ROC_COMMAND_MASK) >> P_ROC_COMMAND_SHIFT)
|
||||
{
|
||||
@@ -659,7 +657,7 @@ PRResult PRDevice::SortReturningData()
|
||||
}
|
||||
case P_ROC_UNREQUESTED_DATA: {
|
||||
ReadData(rd_buffer,1);
|
||||
DEBUG(PRLog("Pushing onto unreq Q 0x%x\n", rd_buffer[0]));
|
||||
DEBUG(PRLog(kPRLogVerbose, "Pushing onto unreq Q 0x%x\n", rd_buffer[0]));
|
||||
unrequestedDataQueue.push(rd_buffer[0]);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -143,7 +143,6 @@ int32_t CreateWatchdogConfigBurst ( uint32_t * burst, bool_t watchdogExpired,
|
||||
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 );
|
||||
@@ -265,7 +264,7 @@ PRResult PRHardwareOpen()
|
||||
// Open the FTDI device
|
||||
if (ftdi_init(&ftdic) != 0)
|
||||
{
|
||||
DEBUG(PRLog("Failed to initialize FTDI.\n"));
|
||||
PRSetLastErrorText("Failed to initialize FTDI.");
|
||||
return kPRFailure;
|
||||
}
|
||||
|
||||
@@ -279,22 +278,22 @@ PRResult PRHardwareOpen()
|
||||
// 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)));
|
||||
PRSetLastErrorText("ftdi_usb_find_all failed: %d: %s", numDevices, ftdi_get_error_string(&ftdic));
|
||||
ftdi_deinit(&ftdic);
|
||||
return kPRFailure;
|
||||
}
|
||||
else {
|
||||
DEBUG(PRLog("Number of FTDI devices found: %d\n", numDevices));
|
||||
DEBUG(PRLog(kPRLogInfo, "Number of FTDI devices found: %d\n", numDevices));
|
||||
|
||||
for (curdev = devlist; curdev != NULL; i++) {
|
||||
DEBUG(PRLog("Checking device %d\n", i));
|
||||
DEBUG(PRLog(kPRLogInfo, "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)));
|
||||
DEBUG(PRLog(kPRLogInfo, " 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));
|
||||
DEBUG(PRLog(kPRLogInfo, " Device #%d:\n", i));
|
||||
DEBUG(PRLog(kPRLogInfo, " Manufacturer: %s\n", manufacturer));
|
||||
DEBUG(PRLog(kPRLogInfo, " Description: %s\n", description));
|
||||
}
|
||||
curdev = curdev->next;
|
||||
}
|
||||
@@ -306,7 +305,7 @@ PRResult PRHardwareOpen()
|
||||
|
||||
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)));
|
||||
PRSetLastErrorText("Unable to open ftdi device: %d: %s", rc, ftdi_get_error_string(&ftdic));
|
||||
return kPRFailure;
|
||||
}
|
||||
else
|
||||
@@ -315,7 +314,7 @@ PRResult PRHardwareOpen()
|
||||
if (ftdic.type == TYPE_R) {
|
||||
uint32_t chipid;
|
||||
ftdi_read_chipid(&ftdic,&chipid);
|
||||
DEBUG(PRLog("FTDI chip_id = 0x%x\n", chipid));
|
||||
DEBUG(PRLog(kPRLogInfo, "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.
|
||||
@@ -324,7 +323,7 @@ PRResult PRHardwareOpen()
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG(PRLog("FTDI type != TYPE_R: 0x%x\n", ftdic.type));
|
||||
PRSetLastErrorText("FTDI type != TYPE_R: 0x%x", ftdic.type);
|
||||
return kPRFailure;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,19 +31,24 @@
|
||||
#include "../include/pinproc.h"
|
||||
#include "PRDevice.h"
|
||||
|
||||
typedef void (*PRLogCallback)(const char *text);
|
||||
#define MAX_TEXT (1024)
|
||||
|
||||
typedef void (*PRLogCallback)(PRLogLevel level, const char *text);
|
||||
|
||||
PRLogCallback logCallback = NULL;
|
||||
PRLogLevel logLevel = kPRLogError;
|
||||
|
||||
void PRLog(const char *format, ...)
|
||||
void PRLog(PRLogLevel level, const char *format, ...)
|
||||
{
|
||||
const int maxLogLineLength = 1024;
|
||||
char line[maxLogLineLength];
|
||||
if (level < logLevel)
|
||||
return;
|
||||
|
||||
char line[MAX_TEXT];
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vsnprintf(line, maxLogLineLength, format, ap);
|
||||
vsnprintf(line, MAX_TEXT, format, ap);
|
||||
if (logCallback)
|
||||
logCallback(line);
|
||||
logCallback(level, line);
|
||||
else
|
||||
fprintf(stderr, line);
|
||||
}
|
||||
@@ -53,6 +58,25 @@ void PRLogSetCallback(PRLogCallback callback)
|
||||
logCallback = callback;
|
||||
}
|
||||
|
||||
void PRLogSetLevel(PRLogLevel level)
|
||||
{
|
||||
logLevel = level;
|
||||
}
|
||||
|
||||
char lastErrorText[MAX_TEXT];
|
||||
|
||||
void PRSetLastErrorText(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vsnprintf(lastErrorText, MAX_TEXT, format, ap);
|
||||
PRLog(kPRLogError, "%s\n", lastErrorText);
|
||||
}
|
||||
|
||||
PR_EXPORT const char *PRGetLastErrorText()
|
||||
{
|
||||
return lastErrorText;
|
||||
}
|
||||
|
||||
#define handleAsDevice ((PRDevice*)handle)
|
||||
|
||||
@@ -124,7 +148,7 @@ PR_EXPORT PRResult PRDriverDisable(PRHandle handle, uint16_t driverNum)
|
||||
PRDriverStateDisable(&driver);
|
||||
return handleAsDevice->DriverUpdateState(&driver);
|
||||
}
|
||||
PR_EXPORT PRResult PRDriverPulse(PRHandle handle, uint16_t driverNum, int milliseconds)
|
||||
PR_EXPORT PRResult PRDriverPulse(PRHandle handle, uint16_t driverNum, uint8_t milliseconds)
|
||||
{
|
||||
PRDriverState driver;
|
||||
handleAsDevice->DriverGetState(driverNum, &driver);
|
||||
@@ -160,7 +184,7 @@ PR_EXPORT void PRDriverStateDisable(PRDriverState *driver)
|
||||
driver->patterOffTime = 0;
|
||||
driver->patterEnable = false;
|
||||
}
|
||||
PR_EXPORT void PRDriverStatePulse(PRDriverState *driver, int milliseconds)
|
||||
PR_EXPORT void PRDriverStatePulse(PRDriverState *driver, uint8_t milliseconds)
|
||||
{
|
||||
driver->state = 1;
|
||||
driver->timeslots = 0;
|
||||
|
||||
Reference in New Issue
Block a user