1
0
mirror of https://github.com/preble/libpinproc synced 2026-02-24 18:25:23 +01:00

Merge branch 'master' into ruby

This commit is contained in:
Adam Preble
2009-05-30 11:14:22 -04:00
16 changed files with 685 additions and 307 deletions

View File

@@ -1,18 +1,18 @@
cmake_minimum_required(VERSION 2.6) cmake_minimum_required(VERSION 2.6)
#set( CMAKE_OSX_ARCHITECTURES ppc;i386 ) #Comment out if not universal binary #set( CMAKE_OSX_ARCHITECTURES ppc;i386 ) # Uncomment for universal binary
#set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ../bin) #set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ../bin)
#set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ../bin) #set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ../bin)
#set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ../bin) #set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ../bin)
include_directories(/usr/local/include ./include) include_directories(/usr/local/include $ENV{EXTRA_INC})
link_directories(/usr/local/lib) link_directories(/usr/local/lib $ENV{EXTRA_LINK})
set(FILES src/pinproc.cpp src/PRDevice.cpp src/PRHardware.cpp) set(FILES src/pinproc.cpp src/PRDevice.cpp src/PRHardware.cpp)
add_library(pinproc ${FILES}) add_library(pinproc ${FILES})
add_executable(pinproctest examples/pinproctest/pinproctest.cpp) add_executable(pinproctest examples/pinproctest/pinproctest.cpp)
target_link_libraries(pinproctest pinproc usb ftdi) target_link_libraries(pinproctest pinproc usb ftdi yaml-cpp)

View File

@@ -1,23 +0,0 @@
#
# File: Makefile (for library)
#
CC=g++
LIB=libpinproc.a
LIBDEST=./bin/
LIBSRC=src/pinproc.cpp src/PRDevice.cpp src/PRHardware.cpp
LIBOBJ=$(LIBSRC:.cpp=.o)
CXXFLAGS=
$(LIB): $(LIBOBJ)
@echo lib Makefile - archiving $(LIB)
$(AR) r $(LIBDEST)$(LIB) $(LIBOBJ)
.cpp.o:
@echo lib Makefile - compiling $<
$(CC) $(CXXFLAGS) -c $< -o $@
clean:
rm -f $(LIBOBJ) $(LIBDEST)$(LIB)

View File

@@ -11,14 +11,16 @@ libpinproc requires:
- [libusb-0.1.12](http://libusb.wiki.sourceforge.net/): Install with the default /usr/local prefix. - [libusb-0.1.12](http://libusb.wiki.sourceforge.net/): Install with the default /usr/local prefix.
- [libftdi-0.16](http://www.intra2net.com/en/developer/libftdi/): Install with the default /usr/local prefix. - [libftdi-0.16](http://www.intra2net.com/en/developer/libftdi/): Install with the default /usr/local prefix.
Once required but not right now: The pinproctest example requires [yaml-cpp](http://code.google.com/p/yaml-cpp/). Follow the build instructions, creating the build subdirectory. After building, from the main source directory, run the following commands to manually install it:
- [yaml-cpp](http://code.google.com/p/yaml-cpp/): Should be checked out in the directory two levels below libpinproc in the full source tree (at the same level as ./P-ROC) in a directory named yaml-cpp. Follow the build instructions, creating the build subdirectory. The Makefiles and other project files expect to find libyaml-cpp.a in the yaml-cpp/build/bin directory. sudo cp lib/libyaml-cpp.a /usr/local/lib/
sudo mkdir /usr/local/include/yaml-cpp
We are presently experimenting with different build mechanisms. As such there are three ways to build libpinproc at this time: CMake, GNU Make, and the Xcode project (for Mac). As the preferred method is presently CMake, here's how. Before you get started, you will need CMake if you don't already have it. sudo cp include/*.h /usr/local/include/yaml-cpp/
#### Building with CMake #### Building with CMake
Download and install [CMake](http://www.cmake.org/cmake/resources/software.html). Then:
cd libpinproc cd libpinproc
mkdir build; cd build mkdir build; cd build
cmake .. cmake ..

View File

@@ -1,7 +0,0 @@
PRGameName: My Great Pin
PRDrivers:
1: driver one
2: driver two
PRSwitches:
1: switch one
2: switch two

View File

@@ -0,0 +1,45 @@
# P-ROC Game Description file for Judge Dredd
PRGame:
machineType: wpc
PRFlippers:
- flipperLwR
- flipperLwL
- flipperUpR
- flipperUpL
PRBumpers:
- slingL
- slingR
PRSwitches:
flipperLwR:
number: 1
flipperLwL:
number: 3
flipperUpR:
number: 5
flipperUpL:
number: 7
slingL:
number: 96
slingR:
number: 97
PRCoils:
flipperLwRMain:
number: 32
flipperLwRHold:
number: 33
flipperLwLMain:
number: 34
flipperLwLHold:
number: 35
flipperUpRMain:
number: 36
flipperUpRHold:
number: 37
flipperUpLMain:
number: 38
flipperUpLHold:
number: 39
slingL:
number: 54
slingR:
number: 55

View File

@@ -1,30 +0,0 @@
#
# File: Makefile for application
#
PINPROC_PATH=../..
CC=g++
LDFLAGS=-L$(PINPROC_PATH)/bin -L/usr/local/lib
LIBS=-lpinproc -lusb -lftdi
SRC=pinproctest.cpp
CXXFLAGS=-I$(PINPROC_PATH)/include
OBJS=$(SRC:.cpp=.o)
EXE=pinproctest
all: $(EXE)
# FIXME: This makes the exe require libpinproc but not in a very graceful way.
$(EXE): $(OBJS) $(PINPROC_PATH)/bin/libpinproc.a
@echo application Makefile - linking $<
$(CC) $^ $(LDFLAGS) $(LIBS) -o $@
.cpp.o:
@echo application Makefile - compiling $<
$(CC) $(CXXFLAGS) -c $< -o $@
clean:
rm -f $(OBJS) $(EXE)

View File

@@ -0,0 +1,48 @@
# P-ROC Game Description file for Twilight Zone
PRGame:
machineType: wpc
PRFlippers:
- flipperLwR
- flipperLwL
- flipperUpR
- flipperUpL
PRBumpers:
- slingL
- slingR
PRSwitches:
flipperLwR:
number: 1
flipperLwL:
number: 3
flipperUpR:
number: 5
flipperUpL:
number: 7
slingL:
number: 96
slingR:
number: 97
PRCoils:
flipperLwRMain:
number: 32
flipperLwRHold:
number: 33
flipperLwLMain:
number: 34
flipperLwLHold:
number: 35
flipperUpRMain:
number: 36
flipperUpRHold:
number: 37
flipperUpLMain:
number: 38
flipperUpLHold:
number: 39
slingL:
number: 54
slingR:
number: 55
PRLamps:
doorTheCamera:
number: 80

View File

@@ -32,29 +32,16 @@
#include <signal.h> #include <signal.h>
#include <unistd.h> #include <unistd.h>
#include <cmath> #include <cmath>
#include "pinproc.h" // Include libpinproc's header. #include "../../include/pinproc.h" // Include libpinproc's header.
#include <fstream>
#include <yaml-cpp/yaml.h>
#include <sys/time.h>
#define kFlippersSection "PRFlippers"
#define kFlipperLwRightSw (1) #define kBumpersSection "PRBumpers"
#define kFlipperLwLeftSw (3) #define kCoilsSection "PRCoils"
#define kFlipperUpRightSw (5) #define kSwitchesSection "PRSwitches"
#define kFlipperUpLeftSw (7) #define kNumberField "number"
#define kFlipperLwRightMain (32)
#define kFlipperLwLeftMain (34)
#define kFlipperUpRightMain (36)
#define kFlipperUpLeftMain (38)
#define kFlipperLwRightHold (33)
#define kFlipperLwLeftHold (35)
#define kFlipperUpRightHold (37)
#define kFlipperUpLeftHold (39)
#define kSlingLeftSw (96)
#define kSlingRightSw (97)
#define kSlingLeftCoil (70)
#define kSlingRightCoil (71)
#define kFlipperPulseTime (34) // 34 ms #define kFlipperPulseTime (34) // 34 ms
#define kBumperPulseTime (25) // 25 ms #define kBumperPulseTime (25) // 25 ms
@@ -69,24 +56,85 @@ void TestLogger(const char *text)
fprintf(stderr, "TEST: %s", text); fprintf(stderr, "TEST: %s", text);
} }
void ConfigureDrivers(PRHandle proc) PRResult LoadConfiguration(YAML::Node& yamlDoc, const char *yamlFilePath)
{
try
{
std::ifstream fin(yamlFilePath);
if (fin.is_open() == false)
{
fprintf(stderr, "YAML file not found: %s\n", yamlFilePath);
return kPRFailure;
}
YAML::Parser parser(fin);
while(parser)
{
parser.GetNextDocument(yamlDoc);
}
}
catch (YAML::ParserException& ex)
{
fprintf(stderr, "YAML parse error at line=%d col=%d: %s\n", ex.line, ex.column, ex.msg.c_str());
return kPRFailure;
}
catch (YAML::RepresentationException& ex)
{
fprintf(stderr, "YAML representation error at line=%d col=%d: %s\n", ex.line, ex.column, ex.msg.c_str());
return kPRFailure;
}
catch (...)
{
fprintf(stderr, "Unexpected exception while parsing YAML config.\n");
return kPRFailure;
}
return kPRSuccess;
}
void ConfigureDrivers(PRHandle proc, PRMachineType machineType, YAML::Node& yamlDoc)
{ {
int i; 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; PRDriverGlobalConfig globals;
globals.enableOutputs = false; globals.enableOutputs = false;
globals.globalPolarity = false; globals.globalPolarity = globalPolarity;
globals.useClear = false; globals.useClear = false;
globals.strobeStartSelect = false; globals.strobeStartSelect = false;
globals.startStrobeTime = 4; // milliseconds per output loop globals.startStrobeTime = driverLoopTime; // milliseconds per output loop
globals.matrixRowEnableIndex1 = 12; globals.matrixRowEnableIndex1 = rowEnableIndex1;
globals.matrixRowEnableIndex0 = 6; globals.matrixRowEnableIndex0 = rowEnableIndex0;
globals.activeLowMatrixRows = true; globals.activeLowMatrixRows = activeLowMatrixRows;
globals.tickleSternWatchdog = false; globals.tickleSternWatchdog = tickleSternWatchdog;
globals.encodeEnables = false; globals.encodeEnables = false;
globals.watchdogExpired = false; globals.watchdogExpired = false;
globals.watchdogEnable = true; globals.watchdogEnable = true;
globals.watchdogResetTime = 1000; // milliseconds globals.watchdogResetTime = watchdogResetTime;
// We want to start up safely, so we'll update the global driver config twice. // 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: // When we toggle enableOutputs like this P-ROC will reset the polarity:
@@ -100,13 +148,14 @@ void ConfigureDrivers(PRHandle proc)
// Configure the groups. Each group corresponds to 8 consecutive drivers, starting // Configure the groups. Each group corresponds to 8 consecutive drivers, starting
// with driver #32. The following 6 groups are configured for coils/flashlamps. // with driver #32. The following 6 groups are configured for coils/flashlamps.
PRDriverGroupConfig group; PRDriverGroupConfig group;
for (i = 0; i < 6; i++) for (i = 4; i < 10; i++)
{ {
PRDriverGetGroupConfig(proc, i + 4, &group); PRDriverGetGroupConfig(proc, i, &group);
group.slowTime = 0; group.slowTime = 0;
group.enableIndex = i; group.enableIndex = mappedDriverGroupEnableIndex[i];
group.rowActivateIndex = i; group.rowActivateIndex = 0;
group.rowEnableSelect = 0; group.rowEnableSelect = 0;
group.matrixed = false; group.matrixed = false;
group.polarity = false; group.polarity = false;
@@ -117,11 +166,11 @@ void ConfigureDrivers(PRHandle proc)
} }
// The following 8 groups are configured for the feature lamp matrix. // The following 8 groups are configured for the feature lamp matrix.
for (i = 6; i < 14; i++) { for (i = 10; i < 18; i++) {
PRDriverGetGroupConfig(proc, i + 4, &group); PRDriverGetGroupConfig(proc, i, &group);
group.slowTime = 400; group.slowTime = slowGroupTime;
group.enableIndex = 7; group.enableIndex = mappedDriverGroupEnableIndex[i];
group.rowActivateIndex = i - 6; group.rowActivateIndex = i - 10;
group.rowEnableSelect = 0; group.rowEnableSelect = 0;
group.matrixed = 1; group.matrixed = 1;
group.polarity = 0; group.polarity = 0;
@@ -131,18 +180,17 @@ void ConfigureDrivers(PRHandle proc)
} }
} }
void ConfigureSwitches(PRHandle proc) void ConfigureSwitches(PRHandle proc, YAML::Node& yamlDoc)
{ {
int i; // Configure switch controller registers (if the defaults aren't acceptable)
PRSwitchConfig switchConfig;
// Configures rules to notify the host for every debounced switch event. switchConfig.clear = false;
for (i = 0; i <= kPRSwitchPhysicalLast; i++) switchConfig.directMatrixScanLoopTime = 2; // milliseconds
{ switchConfig.pulsesBeforeCheckingRX = 10;
PRSwitchRule sw; switchConfig.inactivePulsesAfterBurst = 12;
sw.notifyHost = true; switchConfig.pulsesPerBurst = 6;
PRSwitchesUpdateRule(proc, i, kPREventTypeSwitchClosedDebounced, &sw, NULL, 0); switchConfig.pulseHalfPeriodTime = 13; // milliseconds
PRSwitchesUpdateRule(proc, i, kPREventTypeSwitchOpenDebounced, &sw, NULL, 0); PRSwitchUpdateConfig(proc, &switchConfig);
}
} }
void ConfigureWPCFlipperSwitchRule (PRHandle proc, int swNum, int mainCoilNum, int holdCoilNum, int pulseTime) void ConfigureWPCFlipperSwitchRule (PRHandle proc, int swNum, int mainCoilNum, int holdCoilNum, int pulseTime)
@@ -157,7 +205,9 @@ void ConfigureWPCFlipperSwitchRule (PRHandle proc, int swNum, int mainCoilNum, i
PRDriverGetState(proc, holdCoilNum, &drivers[1]); PRDriverGetState(proc, holdCoilNum, &drivers[1]);
PRDriverStatePulse(&drivers[1],0); // Turn on indefintely (set pulse for 0ms) PRDriverStatePulse(&drivers[1],0); // Turn on indefintely (set pulse for 0ms)
sw.notifyHost = false; sw.notifyHost = false;
PRSwitchesUpdateRule(proc,swNum, kPREventTypeSwitchClosedNondebounced, &sw, drivers, numDriverRules); PRSwitchUpdateRule(proc, swNum, kPREventTypeSwitchClosedNondebounced, &sw, drivers, numDriverRules);
sw.notifyHost = true;
PRSwitchUpdateRule(proc, swNum, kPREventTypeSwitchClosedDebounced, &sw, NULL, 0);
// Flipper off rules // Flipper off rules
PRDriverGetState(proc, mainCoilNum, &drivers[0]); PRDriverGetState(proc, mainCoilNum, &drivers[0]);
@@ -165,7 +215,9 @@ void ConfigureWPCFlipperSwitchRule (PRHandle proc, int swNum, int mainCoilNum, i
PRDriverGetState(proc, holdCoilNum, &drivers[1]); PRDriverGetState(proc, holdCoilNum, &drivers[1]);
PRDriverStateDisable(&drivers[1]); // Disable hold coil PRDriverStateDisable(&drivers[1]); // Disable hold coil
sw.notifyHost = false; sw.notifyHost = false;
PRSwitchesUpdateRule(proc,swNum, kPREventTypeSwitchOpenNondebounced, &sw, drivers, numDriverRules); 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) void ConfigureBumperRule (PRHandle proc, int swNum, int coilNum, int pulseTime)
@@ -178,20 +230,37 @@ void ConfigureBumperRule (PRHandle proc, int swNum, int coilNum, int pulseTime)
PRDriverGetState(proc, coilNum, &drivers[0]); PRDriverGetState(proc, coilNum, &drivers[0]);
PRDriverStatePulse(&drivers[0],pulseTime); // Pulse coil for 34ms. PRDriverStatePulse(&drivers[0],pulseTime); // Pulse coil for 34ms.
sw.notifyHost = false; sw.notifyHost = false;
PRSwitchesUpdateRule(proc,swNum, kPREventTypeSwitchClosedNondebounced, &sw, drivers, numDriverRules); PRSwitchUpdateRule(proc, swNum, kPREventTypeSwitchClosedNondebounced, &sw, drivers, numDriverRules);
sw.notifyHost = true;
PRSwitchUpdateRule(proc, swNum, kPREventTypeSwitchClosedDebounced, &sw, NULL, 0);
} }
void ConfigureSwitchRules(PRHandle proc) void ConfigureSwitchRules(PRHandle proc, YAML::Node& yamlDoc)
{ {
// WPC Flippers // WPC Flippers
ConfigureWPCFlipperSwitchRule (proc, kFlipperLwRightSw, kFlipperLwRightMain, kFlipperLwRightHold, kFlipperPulseTime); // Lower Right WPC Flipper const YAML::Node& flippers = yamlDoc[kFlippersSection];
ConfigureWPCFlipperSwitchRule (proc, kFlipperLwLeftSw, kFlipperLwLeftMain, kFlipperLwLeftHold, kFlipperPulseTime); // Lower Left WPC Flipper for (YAML::Iterator flippersIt = flippers.begin(); flippersIt != flippers.end(); ++flippersIt)
ConfigureWPCFlipperSwitchRule (proc, kFlipperUpRightSw, kFlipperUpRightMain, kFlipperUpRightHold, kFlipperPulseTime); // Upper Right WPC Flipper {
ConfigureWPCFlipperSwitchRule (proc, kFlipperUpLeftSw, kFlipperUpLeftMain, kFlipperUpLeftHold, kFlipperPulseTime); // Upper Left WPC Flipper 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 // WPC Slingshots
ConfigureBumperRule (proc, kSlingRightSw, kSlingRightCoil, kBumperPulseTime); // WPC Right Slingshot std::string bumperName;
ConfigureBumperRule (proc, kSlingLeftSw, kSlingLeftCoil, kBumperPulseTime); // WPC Left Slingshot *bumpersIt >> bumperName;
yamlDoc[kSwitchesSection][bumperName][kNumberField] >> swNum;
yamlDoc[kCoilsSection][bumperName][kNumberField] >> coilNum;
ConfigureBumperRule (proc, swNum, coilNum, kBumperPulseTime);
}
} }
void ConfigureDMD(PRHandle proc) void ConfigureDMD(PRHandle proc)
@@ -226,7 +295,7 @@ void ConfigureDMD(PRHandle proc)
// starting with dim dots at the top. // starting with dim dots at the top.
void UpdateDots( unsigned char * dots, unsigned int dotOffset ) void UpdateDots( unsigned char * dots, unsigned int dotOffset )
{ {
int i,j,k,color,mappedColor,loopCtr,byte_shifter; int row,col,subFrame,color,mappedColor,loopCtr,byte_shifter;
const int rate_reduction_divisor = 1; const int rate_reduction_divisor = 1;
loopCtr = dotOffset/rate_reduction_divisor; loopCtr = dotOffset/rate_reduction_divisor;
@@ -243,33 +312,34 @@ void UpdateDots( unsigned char * dots, unsigned int dotOffset )
memset(dots,0,((kDMDColumns*kDMDRows)/8)*kDMDSubFrames); memset(dots,0,((kDMDColumns*kDMDRows)/8)*kDMDSubFrames);
// Loop through all of the rows // Loop through all of the rows
for (i = kDMDRows - 1; i >= 0; i--) for (row = kDMDRows - 1; row >= 0; row--)
{ {
// Map the color index to the DMD's physical color map // 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}; int mappedColors[] = {0, 2, 8, 10, 1, 3, 9, 11, 4, 6, 12, 14, 5, 7, 13, 15};
mappedColor = mappedColors[color]; mappedColor = mappedColors[color];
// Loop through each of 16 bytes in a row // Loop through each of 16 bytes in a row
for (j = 0; j < kDMDColumns / 8; j++) for (col = 0; col < kDMDColumns / 8; col++)
{ {
// Loop through each subframe // Loop through each subframe
for (k = 0; k < kDMDSubFrames; k++) for (subFrame = 0; subFrame < kDMDSubFrames; subFrame++)
{ {
// Turn on the byte in each sub-frame that's enabled // Turn on the byte in each sub-frame that's enabled
// active for the color code. // active for the color code.
if ((mappedColor >> k) & 1 == 1) if ((mappedColor >> subFrame) & 1 == 1)
dots[k*(kDMDColumns*kDMDRows/8)+((i%kDMDRows)*(kDMDColumns / 8))+j] = byte_shifter; 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 // Determine where to change the color in order to progress from row 0 = color 0
// to the last row being the last color. // to the last row being the last color.
if (i % (int)((kDMDRows/pow(2,kDMDSubFrames))) == 0) color--; if (row % (int)((kDMDRows/pow(2,kDMDSubFrames))) == 0) color--;
if (byte_shifter == 1) byte_shifter = 0x80; if (byte_shifter == 1) byte_shifter = 0x80;
else byte_shifter = byte_shifter >> 1; else byte_shifter = byte_shifter >> 1;
} }
} }
} }
time_t startTime;
bool runLoopRun = true; bool runLoopRun = true;
void RunLoop(PRHandle proc) void RunLoop(PRHandle proc)
@@ -302,8 +372,11 @@ void RunLoop(PRHandle proc)
case kPREventTypeSwitchOpenNondebounced: stateText = "open(ndb)"; break; case kPREventTypeSwitchOpenNondebounced: stateText = "open(ndb)"; break;
case kPREventTypeSwitchClosedNondebounced: stateText = "closed(ndb)"; break; case kPREventTypeSwitchClosedNondebounced: stateText = "closed(ndb)"; break;
} }
printf("switch % 3d: %s\n", event->value, stateText); struct timeval tv;
gettimeofday(&tv, NULL);
printf("%d.%03d switch % 3d: %s\n", tv.tv_sec-startTime, tv.tv_usec/1000, event->value, stateText);
} }
PRFlushWriteData(proc);
usleep(10*1000); // Sleep for 10ms so we aren't pegging the CPU. usleep(10*1000); // Sleep for 10ms so we aren't pegging the CPU.
} }
} }
@@ -315,26 +388,56 @@ void sigint(int)
printf("Exiting...\n"); printf("Exiting...\n");
} }
int main(const char **argv, int argc) int main(int argc, const char **argv)
{ {
// Set a signal handler so that we can exit gracefully on Ctrl-C: // Set a signal handler so that we can exit gracefully on Ctrl-C:
signal(SIGINT, sigint); signal(SIGINT, sigint);
startTime = time(NULL);
if (argc < 2)
{
fprintf(stderr, "Usage: %s <yaml machine description>\n", argv[0]);
return 1;
}
const char *yamlFilename = argv[1];
// Assign a custom logging callback to demonstrate capturing log information from P-ROC: // Assign a custom logging callback to demonstrate capturing log information from P-ROC:
PRLogSetCallback(TestLogger); PRLogSetCallback(TestLogger);
YAML::Node yamlDoc;
if (LoadConfiguration(yamlDoc, yamlFilename) != kPRSuccess)
{
fprintf(stderr, "Failed to load configuration file %s\n", yamlFilename);
return 1;
}
PRMachineType machineType = kPRMachineInvalid;
std::string machineTypeString;
yamlDoc["PRGame"]["machineType"] >> machineTypeString;
if (machineTypeString == "wpc")
machineType = kPRMachineWPC;
else if(machineTypeString == "stern")
machineType = kPRMachineStern;
else
{
fprintf(stderr, "Unknown machine type: %s\n", machineTypeString.c_str());
return 1;
}
// Finally instantiate the P-ROC device: // Finally instantiate the P-ROC device:
PRHandle proc = PRCreate(kPRMachineWPC); PRHandle proc = PRCreate(machineType);
if (proc == kPRHandleInvalid) if (proc == kPRHandleInvalid)
return 1; return 1;
PRReset(proc, kPRResetFlagUpdateDevice); // Reset the device structs and write them into the device.
ConfigureDMD(proc); ConfigureDMD(proc);
ConfigureSwitches(proc); // Notify host for all debounced switch events. ConfigureSwitches(proc, yamlDoc); // Notify host for all debounced switch events.
ConfigureSwitchRules(proc); // Flippers, slingshots ConfigureSwitchRules(proc, yamlDoc); // Flippers, slingshots
// Make Drivers the last thing to configure so watchdog doesn't expire // Make Drivers the last thing to configure so watchdog doesn't expire
// before the RunLoop begins. // before the RunLoop begins.
ConfigureDrivers(proc); ConfigureDrivers(proc, machineType, yamlDoc);
printf("Running. Hit Ctrl-C to exit.\n"); printf("Running. Hit Ctrl-C to exit.\n");
@@ -347,6 +450,10 @@ int main(const char **argv, int argc)
RunLoop(proc); RunLoop(proc);
// Clean up P-ROC.
printf("Disabling P-ROC drivers and switch rules...\n");
PRReset(proc, kPRResetFlagUpdateDevice); // Reset the device structs and write them into the device.
// Destroy the P-ROC device handle: // Destroy the P-ROC device handle:
PRDelete(proc); PRDelete(proc);
proc = kPRHandleInvalid; proc = kPRHandleInvalid;

View File

@@ -91,13 +91,30 @@ typedef enum PRMachineType {
PR_EXPORT PRHandle PRCreate(PRMachineType machineType); /**< Create a new P-ROC device handle. Only one handle per device may be created. This handle must be destroyed with PRDelete() when it is no longer needed. Returns #kPRHandleInvalid if an error occurred. */ PR_EXPORT PRHandle PRCreate(PRMachineType machineType); /**< Create a new P-ROC device handle. Only one handle per device may be created. This handle must be destroyed with PRDelete() when it is no longer needed. Returns #kPRHandleInvalid if an error occurred. */
PR_EXPORT void PRDelete(PRHandle handle); /**< Destroys an existing P-ROC device handle. */ PR_EXPORT void PRDelete(PRHandle handle); /**< Destroys an existing P-ROC device handle. */
#define kPRResetFlagDefault (0) /**< Only resets state in memory and does not write changes to the device. */
#define kPRResetFlagUpdateDevice (1) /**< Instructs PRReset() to update the device once it has reset the configuration to its defaults. */
/**
* @brief Resets internally maintained driver and switch rule structures.
* @param resetFlags Specify #kPRResetFlagDefault to only reset the configuration in host memory. #kPRResetFlagUpdateDevice will write the default configuration to the device, effectively disabling all drivers and switch rules.
*/
PR_EXPORT PRResult PRReset(PRHandle handle, uint32_t resetFlags);
/** @} */ // End of Device Creation & Deletion /** @} */ // End of Device Creation & Deletion
// I/O
/** Flush all pending write data out to the P-ROC */
PR_EXPORT PRResult PRFlushWriteData(PRHandle handle);
// Drivers // Drivers
/** @defgroup drivers Driver Manipulation /** @defgroup drivers Driver Manipulation
* @{ * @{
*/ */
#define kPRDriverGroupsMax (26) /**< Number of available driver groups. */
#define kPRDriverCount (256) /**< Total number of drivers */
typedef struct PRDriverGlobalConfig { typedef struct PRDriverGlobalConfig {
bool_t enableOutputs; // Formerly enable_direct_outputs bool_t enableOutputs; // Formerly enable_direct_outputs
bool_t globalPolarity; bool_t globalPolarity;
@@ -178,25 +195,25 @@ PR_EXPORT PRResult PRDriverWatchdogTickle(PRHandle handle);
/** /**
* Changes the given #PRDriverState to reflect a disabled state. * Changes the given #PRDriverState to reflect a disabled state.
* @note The driver state structure must be applied using PRDriverUpdateState() or linked to a switch rule using PRSwitchesUpdateRule() to have any effect. * @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 PRDriverStateDisable(PRDriverState *driverState); PR_EXPORT void PRDriverStateDisable(PRDriverState *driverState);
/** /**
* Changes the given #PRDriverState to reflect a pulse state. * Changes the given #PRDriverState to reflect a pulse state.
* @param milliseconds Number of milliseconds to pulse the driver for. * @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 PRSwitchesUpdateRule() to have any effect. * @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, int milliseconds);
/** /**
* Changes the given #PRDriverState to reflect a scheduled state. * Changes the given #PRDriverState to reflect a scheduled state.
* Assigns a repeating schedule to the given driver. * Assigns a repeating schedule to the given driver.
* @note The driver state structure must be applied using PRDriverUpdateState() or linked to a switch rule using PRSwitchesUpdateRule() to have any effect. * @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 PRDriverStateSchedule(PRDriverState *driverState, uint32_t schedule, uint8_t cycleSeconds, bool_t now); PR_EXPORT void PRDriverStateSchedule(PRDriverState *driverState, uint32_t schedule, uint8_t cycleSeconds, bool_t now);
/** /**
* @brief Changes the given #PRDriverState to reflect a pitter-patter schedule state. * @brief Changes the given #PRDriverState to reflect a pitter-patter schedule state.
* Assigns a pitter-patter schedule (repeating on/off) to the given driver. * Assigns a pitter-patter schedule (repeating on/off) to the given driver.
* @note The driver state structure must be applied using PRDriverUpdateState() or linked to a switch rule using PRSwitchesUpdateRule() to have any effect. * @note The driver state structure must be applied using PRDriverUpdateState() or linked to a switch rule using PRSwitchUpdateRule() to have any effect.
* *
* Use originalOnTime to pulse the driver for a number of milliseconds before the pitter-patter schedule begins. * Use originalOnTime to pulse the driver for a number of milliseconds before the pitter-patter schedule begins.
*/ */
@@ -235,11 +252,25 @@ PR_EXPORT int PRGetEvents(PRHandle handle, PREvent *eventsOut, int maxEvents);
#define kPRSwitchPhysicalLast (223) /**< Switch number of the last physical switch. */ #define kPRSwitchPhysicalLast (223) /**< Switch number of the last physical switch. */
#define kPRSwitchVirtualFirst (224) /**< Switch number of the first virtual switch. */ #define kPRSwitchVirtualFirst (224) /**< Switch number of the first virtual switch. */
#define kPRSwitchVirtualLast (255) /**< Switch number of the last virtual switch. */ #define kPRSwitchVirtualLast (255) /**< Switch number of the last virtual switch. */
#define kPRSwitchCount (256)
#define kPRSwitchRulesCount (kPRSwitchCount << 2) /**< Total number of available switch rules. */
typedef struct PRSwitchConfig {
bool_t clear; // Drive the clear output
uint8_t directMatrixScanLoopTime; // milliseconds
uint8_t pulsesBeforeCheckingRX;
uint8_t inactivePulsesAfterBurst;
uint8_t pulsesPerBurst;
uint8_t pulseHalfPeriodTime; // milliseconds
} PRSwitchConfig;
typedef struct PRSwitchRule { typedef struct PRSwitchRule {
bool_t notifyHost; /**< If true this switch change event will provided to the user via PRGetEvents(). */ bool_t notifyHost; /**< If true this switch change event will provided to the user via PRGetEvents(). */
} PRSwitchRule; } PRSwitchRule;
/** Update the switch controller configurion registers */
PR_EXPORT PRResult PRSwitchUpdateConfig(PRHandle handle, PRSwitchConfig *switchConfig);
/** /**
* @brief Configures the handling of switch rules within P-ROC. * @brief Configures the handling of switch rules within P-ROC.
* *
@@ -264,7 +295,7 @@ typedef struct PRSwitchRule {
* @code * @code
* PRSwitchRule rule; * PRSwitchRule rule;
* rule.notifyHost = true; * rule.notifyHost = true;
* PRSwitchesUpdateRule(handle, switchNum, kPREventTypeSwitchOpenDebounced, &rule, NULL, 0); * PRSwitchUpdateRule(handle, switchNum, kPREventTypeSwitchOpenDebounced, &rule, NULL, 0);
* @endcode * @endcode
* *
* Configuring a pop bumper switch to pulse the coil and a flash lamp for 50ms each: * Configuring a pop bumper switch to pulse the coil and a flash lamp for 50ms each:
@@ -277,11 +308,11 @@ typedef struct PRSwitchRule {
* PRDriverGetState(handle, drvFlashLamp1, &drivers[1]); * PRDriverGetState(handle, drvFlashLamp1, &drivers[1]);
* PRDriverStatePulse(&drivers[0], 50); * PRDriverStatePulse(&drivers[0], 50);
* PRDriverStatePulse(&drivers[1], 50); * PRDriverStatePulse(&drivers[1], 50);
* PRSwitchesUpdateRule(handle, swPopBumper1, kPREventTypeSwitchClosedNondebounced, * PRSwitchUpdateRule(handle, swPopBumper1, kPREventTypeSwitchClosedNondebounced,
* &rule, drivers, 2); * &rule, drivers, 2);
* // Now configure a switch rule to process scoring in software: * // Now configure a switch rule to process scoring in software:
* rule.notifyHost = true; * rule.notifyHost = true;
* PRSwitchesUpdateRule(handle, swPopBumper1, kPREventTypeSwitchClosedDebounced, * PRSwitchUpdateRule(handle, swPopBumper1, kPREventTypeSwitchClosedDebounced,
* &rule, NULL, 0); * &rule, NULL, 0);
* @endcode * @endcode
* *
@@ -292,7 +323,7 @@ typedef struct PRSwitchRule {
* @param linkedDrivers An array of #PRDriverState structures describing the driver state changes to be made when this switch rule is triggered. May be NULL if numDrivers is 0. * @param linkedDrivers An array of #PRDriverState structures describing the driver state changes to be made when this switch rule is triggered. May be NULL if numDrivers is 0.
* @param numDrivers Number of elements in the linkedDrivers array. May be zero or more. * @param numDrivers Number of elements in the linkedDrivers array. May be zero or more.
*/ */
PR_EXPORT PRResult PRSwitchesUpdateRule(PRHandle handle, uint8_t switchNum, PREventType eventType, PRSwitchRule *rule, PRDriverState *linkedDrivers, int numDrivers); PR_EXPORT PRResult PRSwitchUpdateRule(PRHandle handle, uint8_t switchNum, PREventType eventType, PRSwitchRule *rule, PRDriverState *linkedDrivers, int numDrivers);
/** @} */ // End of Switches & Events /** @} */ // End of Switches & Events

View File

@@ -15,6 +15,7 @@
668249E30FC0A3960051560E /* pinproctest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 668249E20FC0A3960051560E /* pinproctest.cpp */; }; 668249E30FC0A3960051560E /* pinproctest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 668249E20FC0A3960051560E /* pinproctest.cpp */; };
668249EA0FC0A4280051560E /* libpinproc.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D2AAC046055464E500DB518D /* libpinproc.a */; }; 668249EA0FC0A4280051560E /* libpinproc.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D2AAC046055464E500DB518D /* libpinproc.a */; };
668249ED0FC0A4CD0051560E /* PRHardware.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 668249EC0FC0A4CD0051560E /* PRHardware.cpp */; }; 668249ED0FC0A4CD0051560E /* PRHardware.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 668249EC0FC0A4CD0051560E /* PRHardware.cpp */; };
66824E7B0FCCBAFF0051560E /* PRCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = 66824E7A0FCCBAFF0051560E /* PRCommon.h */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@@ -36,6 +37,7 @@
668249D90FC0A30A0051560E /* pinproctest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = pinproctest; sourceTree = BUILT_PRODUCTS_DIR; }; 668249D90FC0A30A0051560E /* pinproctest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = pinproctest; sourceTree = BUILT_PRODUCTS_DIR; };
668249E20FC0A3960051560E /* pinproctest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = pinproctest.cpp; path = examples/pinproctest/pinproctest.cpp; sourceTree = "<group>"; }; 668249E20FC0A3960051560E /* pinproctest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = pinproctest.cpp; path = examples/pinproctest/pinproctest.cpp; sourceTree = "<group>"; };
668249EC0FC0A4CD0051560E /* PRHardware.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PRHardware.cpp; path = src/PRHardware.cpp; sourceTree = "<group>"; }; 668249EC0FC0A4CD0051560E /* PRHardware.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PRHardware.cpp; path = src/PRHardware.cpp; sourceTree = "<group>"; };
66824E7A0FCCBAFF0051560E /* PRCommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PRCommon.h; path = src/PRCommon.h; sourceTree = "<group>"; };
D2AAC046055464E500DB518D /* libpinproc.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libpinproc.a; sourceTree = BUILT_PRODUCTS_DIR; }; D2AAC046055464E500DB518D /* libpinproc.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libpinproc.a; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */ /* End PBXFileReference section */
@@ -95,6 +97,7 @@
668249410FC07D900051560E /* PRDevice.cpp */, 668249410FC07D900051560E /* PRDevice.cpp */,
6682494A0FC0870B0051560E /* PRHardware.h */, 6682494A0FC0870B0051560E /* PRHardware.h */,
668249EC0FC0A4CD0051560E /* PRHardware.cpp */, 668249EC0FC0A4CD0051560E /* PRHardware.cpp */,
66824E7A0FCCBAFF0051560E /* PRCommon.h */,
); );
name = libpinproc; name = libpinproc;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -124,6 +127,7 @@
6682492C0FC079050051560E /* pinproc.h in Headers */, 6682492C0FC079050051560E /* pinproc.h in Headers */,
668249420FC07D900051560E /* PRDevice.h in Headers */, 668249420FC07D900051560E /* PRDevice.h in Headers */,
6682494B0FC0870B0051560E /* PRHardware.h in Headers */, 6682494B0FC0870B0051560E /* PRHardware.h in Headers */,
66824E7B0FCCBAFF0051560E /* PRCommon.h in Headers */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -222,10 +226,7 @@
GCC_ENABLE_FIX_AND_CONTINUE = YES; GCC_ENABLE_FIX_AND_CONTINUE = YES;
GCC_MODEL_TUNING = G5; GCC_MODEL_TUNING = G5;
GCC_OPTIMIZATION_LEVEL = 0; GCC_OPTIMIZATION_LEVEL = 0;
HEADER_SEARCH_PATHS = ( HEADER_SEARCH_PATHS = /usr/local/include;
/usr/local/include,
"../../yaml-cpp/include",
);
INSTALL_PATH = /usr/local/lib; INSTALL_PATH = /usr/local/lib;
OBJROOT = build; OBJROOT = build;
ONLY_ACTIVE_ARCH = NO; ONLY_ACTIVE_ARCH = NO;
@@ -241,10 +242,7 @@
CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)"; CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)";
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_MODEL_TUNING = G5; GCC_MODEL_TUNING = G5;
HEADER_SEARCH_PATHS = ( HEADER_SEARCH_PATHS = /usr/local/include;
/usr/local/include,
"../../yaml-cpp/include",
);
INSTALL_PATH = /usr/local/lib; INSTALL_PATH = /usr/local/lib;
OBJROOT = build; OBJROOT = build;
PRODUCT_NAME = pinproc; PRODUCT_NAME = pinproc;
@@ -287,8 +285,12 @@
GCC_ENABLE_FIX_AND_CONTINUE = YES; GCC_ENABLE_FIX_AND_CONTINUE = YES;
GCC_MODEL_TUNING = G5; GCC_MODEL_TUNING = G5;
GCC_OPTIMIZATION_LEVEL = 0; GCC_OPTIMIZATION_LEVEL = 0;
HEADER_SEARCH_PATHS = /usr/local/include;
INSTALL_PATH = /usr/local/bin; INSTALL_PATH = /usr/local/bin;
OTHER_LDFLAGS = "-lftdi"; OTHER_LDFLAGS = (
"-lyaml-cpp",
"-lftdi",
);
PREBINDING = NO; PREBINDING = NO;
PRODUCT_NAME = pinproctest; PRODUCT_NAME = pinproctest;
}; };
@@ -302,8 +304,12 @@
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_MODEL_TUNING = G5; GCC_MODEL_TUNING = G5;
HEADER_SEARCH_PATHS = /usr/local/include;
INSTALL_PATH = /usr/local/bin; INSTALL_PATH = /usr/local/bin;
OTHER_LDFLAGS = "-lftdi"; OTHER_LDFLAGS = (
"-lyaml-cpp",
"-lftdi",
);
PREBINDING = NO; PREBINDING = NO;
PRODUCT_NAME = pinproctest; PRODUCT_NAME = pinproctest;
ZERO_LINK = NO; ZERO_LINK = NO;

36
src/PRCommon.h Normal file
View File

@@ -0,0 +1,36 @@
/*
* 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.
*/
#ifndef _PRCOMMON_H_
#define _PRCOMMON_H_
#ifdef NDEBUG
# define DEBUG(block)
#else
# define DEBUG(block) block
#endif
extern void PRLog(const char *format, ...);
#endif // _PRCOMMON_H_

View File

@@ -30,9 +30,10 @@
#include "PRDevice.h" #include "PRDevice.h"
PRDevice::PRDevice(PRMachineType machineType) : machineType(machineType), ftdiInitialized(false) PRDevice::PRDevice(PRMachineType machineType) : machineType(machineType)
{ {
Reset(); // Reset internally maintainted driver and switch structures, but do not update the device.
Reset(kPRResetFlagDefault);
} }
PRDevice::~PRDevice() PRDevice::~PRDevice()
@@ -57,49 +58,69 @@ PRDevice* PRDevice::Create(PRMachineType machineType)
return NULL; return NULL;
} }
dev->Reset();
return dev; return dev;
} }
void PRDevice::Reset() PRResult PRDevice::Reset(uint32_t resetFlags)
{ {
bool defaultPolarity = machineType != kPRMachineWPC; bool defaultPolarity = machineType != kPRMachineWPC;
int i; int i;
memset(&driverGlobalConfig, 0x00, sizeof(PRDriverGlobalConfig)); memset(&driverGlobalConfig, 0x00, sizeof(PRDriverGlobalConfig));
for (i = 0; i < maxDrivers; i++) for (i = 0; i < kPRDriverCount; i++)
{ {
PRDriverState *driver = &drivers[i]; PRDriverState *driver = &drivers[i];
memset(driver, 0x00, sizeof(PRDriverState)); memset(driver, 0x00, sizeof(PRDriverState));
driver->driverNum = i; driver->driverNum = i;
driver->polarity = defaultPolarity; driver->polarity = defaultPolarity;
if (resetFlags & kPRResetFlagUpdateDevice) DriverUpdateState(driver);
} }
for (i = 0; i < maxDriverGroups; i++) for (i = 0; i < kPRDriverGroupsMax; i++)
{ {
PRDriverGroupConfig *group = &driverGroups[i]; PRDriverGroupConfig *group = &driverGroups[i];
memset(group, 0x00, sizeof(PRDriverGroupConfig)); memset(group, 0x00, sizeof(PRDriverGroupConfig));
group->groupNum = i; group->groupNum = i;
group->polarity = defaultPolarity; group->polarity = defaultPolarity;
} }
for (i = 0; i < maxSwitchRules; i++)
freeSwitchRuleIndexes.empty();
for (i = 0; i < kPRSwitchRulesCount; i++)
{ {
PRSwitchRuleInternal *switchRule = &switchRules[i]; PRSwitchRuleInternal *switchRule = &switchRules[i];
memset(switchRule, 0x00, sizeof(PRSwitchRule)); memset(switchRule, 0x00, sizeof(PRSwitchRule));
uint16_t ruleIndex = i; uint16_t ruleIndex = i;
ParseSwitchRuleIndex(ruleIndex, &switchRule->switchNum, &switchRule->eventType); ParseSwitchRuleIndex(ruleIndex, &switchRule->switchNum, &switchRule->eventType);
switchRule->driver.polarity = defaultPolarity; switchRule->driver.polarity = defaultPolarity;
if (switchRule->switchNum >= kPRSwitchVirtualFirst && switchRule->switchNum <= kPRSwitchVirtualLast) if (switchRule->switchNum >= kPRSwitchVirtualFirst) // Disabled for compiler warning (always true due to data type): && switchRule->switchNum <= kPRSwitchVirtualLast)
freeSwitchRuleIndexes.push(ruleIndex); freeSwitchRuleIndexes.push(ruleIndex);
} }
// Create empty switch rule for clearing the rules in the device.
PRSwitchRule emptySwitchRule;
memset(&emptySwitchRule, 0x00, sizeof(PRSwitchRule));
for (i = 0; i < kPRSwitchCount; i++)
{
// Send blank rule for each event type to Device if necessary
if ((resetFlags & kPRResetFlagUpdateDevice) && i <= kPRSwitchPhysicalLast)
{
SwitchUpdateRule(i, kPREventTypeSwitchOpenDebounced, &emptySwitchRule, NULL, 0);
SwitchUpdateRule(i, kPREventTypeSwitchClosedDebounced, &emptySwitchRule, NULL, 0);
SwitchUpdateRule(i, kPREventTypeSwitchOpenNondebounced, &emptySwitchRule, NULL, 0);
SwitchUpdateRule(i, kPREventTypeSwitchClosedNondebounced, &emptySwitchRule, NULL, 0);
}
}
unrequestedDataQueue.empty(); unrequestedDataQueue.empty();
requestedDataQueue.empty(); requestedDataQueue.empty();
num_collected_bytes = 0; num_collected_bytes = 0;
numPreparedWriteWords = 0;
// TODO: Assign defaults based on machineType. Some may have already been done above. // TODO: Assign defaults based on machineType. Some may have already been done above.
return kPRSuccess;
} }
int PRDevice::GetEvents(PREvent *events, int maxEvents) int PRDevice::GetEvents(PREvent *events, int maxEvents)
{ {
SortReturningData(); SortReturningData();
@@ -139,7 +160,7 @@ PRResult PRDevice::DriverUpdateGlobalConfig(PRDriverGlobalConfig *driverGlobalCo
DEBUG(PRLog("Driver Global words: %x %x\n", burst[0], burst[1])); 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("Watchdog words: %x %x\n", burst[2], burst[3]));
return WriteData(burst, burstWords); return PrepareWriteData(burst, burstWords);
} }
PRResult PRDevice::DriverGetGroupConfig(uint8_t groupNum, PRDriverGroupConfig *driverGroupConfig) PRResult PRDevice::DriverGetGroupConfig(uint8_t groupNum, PRDriverGroupConfig *driverGroupConfig)
@@ -159,7 +180,7 @@ PRResult PRDevice::DriverUpdateGroupConfig(PRDriverGroupConfig *driverGroupConfi
rc = CreateDriverUpdateGroupConfigBurst(burst, driverGroupConfig); rc = CreateDriverUpdateGroupConfigBurst(burst, driverGroupConfig);
DEBUG(PRLog("Words: %x %x\n", burst[0], burst[1])); DEBUG(PRLog("Words: %x %x\n", burst[0], burst[1]));
return WriteData(burst, burstWords); return PrepareWriteData(burst, burstWords);
} }
PRResult PRDevice::DriverGetState(uint8_t driverNum, PRDriverState *driverState) PRResult PRDevice::DriverGetState(uint8_t driverNum, PRDriverState *driverState)
@@ -187,7 +208,7 @@ PRResult PRDevice::DriverUpdateState(PRDriverState *driverState)
rc = CreateDriverUpdateBurst(burst, &drivers[driverState->driverNum]); rc = CreateDriverUpdateBurst(burst, &drivers[driverState->driverNum]);
DEBUG(PRLog("Words: %x %x %x\n", burst[0], burst[1], burst[2])); DEBUG(PRLog("Words: %x %x %x\n", burst[0], burst[1], burst[2]));
return WriteData(burst, burstWords); return PrepareWriteData(burst, burstWords);
} }
@@ -201,7 +222,7 @@ PRResult PRDevice::DriverWatchdogTickle()
driverGlobalConfig.watchdogEnable, driverGlobalConfig.watchdogEnable,
driverGlobalConfig.watchdogResetTime); driverGlobalConfig.watchdogResetTime);
return WriteData(burst, burstWords); return PrepareWriteData(burst, burstWords);
} }
@@ -211,7 +232,23 @@ PRSwitchRuleInternal *PRDevice::GetSwitchRuleByIndex(uint16_t index)
return &switchRules[index]; return &switchRules[index];
} }
PRResult PRDevice::SwitchesUpdateRule(uint8_t switchNum, PREventType eventType, PRSwitchRule *rule, PRDriverState *linkedDrivers, int numDrivers) PRResult PRDevice::SwitchUpdateConfig(PRSwitchConfig *switchConfig)
{
uint32_t rc;
const int burstWords = 2;
uint32_t burst[burstWords];
this->switchConfig = *switchConfig;
CreateSwitchUpdateConfigBurst(burst, switchConfig);
DEBUG(PRLog("Configuring Switch Logic"));
DEBUG(PRLog("Words: %x %x\n",burst[0],burst[1]));
rc = PrepareWriteData(burst, burstWords);
return rc;
}
PRResult PRDevice::SwitchUpdateRule(uint8_t switchNum, PREventType eventType, PRSwitchRule *rule, PRDriverState *linkedDrivers, int numDrivers)
{ {
// Updates a single rule with the associated linked driver state changes. // Updates a single rule with the associated linked driver state changes.
const int burstSize = 4; const int burstSize = 4;
@@ -265,7 +302,7 @@ PRResult PRDevice::SwitchesUpdateRule(uint8_t switchNum, PREventType eventType,
newRule->linkIndex = freeSwitchRuleIndexes.front(); newRule->linkIndex = freeSwitchRuleIndexes.front();
freeSwitchRuleIndexes.pop(); freeSwitchRuleIndexes.pop();
CreateSwitchesUpdateRulesBurst(burst, newRule); CreateSwitchUpdateRulesBurst(burst, newRule);
// Prepare for the next rule: // Prepare for the next rule:
newRule = GetSwitchRuleByIndex(newRule->linkIndex); newRule = GetSwitchRuleByIndex(newRule->linkIndex);
@@ -273,20 +310,20 @@ PRResult PRDevice::SwitchesUpdateRule(uint8_t switchNum, PREventType eventType,
else else
{ {
newRule->linkActive = false; newRule->linkActive = false;
CreateSwitchesUpdateRulesBurst(burst, newRule); CreateSwitchUpdateRulesBurst(burst, newRule);
} }
DEBUG(PRLog("Rule Words: %x %x %x %x\n", burst[0],burst[1],burst[2],burst[3])); DEBUG(PRLog("Rule Words: %x %x %x %x\n", burst[0],burst[1],burst[2],burst[3]));
// Write the rule: // Write the rule:
res = WriteData(burst, burstSize); res = PrepareWriteData(burst, burstSize);
if (res != kPRSuccess) if (res != kPRSuccess)
{ {
DEBUG(PRLog("Error while writing switch update, attempting to revert switch rule to a safe state...")); DEBUG(PRLog("Error while writing switch update, attempting to revert switch rule to a safe state..."));
newRule = GetSwitchRuleByIndex(firstRuleIndex); newRule = GetSwitchRuleByIndex(firstRuleIndex);
newRule->changeOutput = false; newRule->changeOutput = false;
newRule->linkActive = false; newRule->linkActive = false;
CreateSwitchesUpdateRulesBurst(burst, newRule); CreateSwitchUpdateRulesBurst(burst, newRule);
if (WriteData(burst, burstSize) == kPRSuccess) if (PrepareWriteData(burst, burstSize) == kPRSuccess)
DEBUG(PRLog("Disabled successfully.\n")); DEBUG(PRLog("Disabled successfully.\n"));
else else
DEBUG(PRLog("Failed to disable.\n")); DEBUG(PRLog("Failed to disable.\n"));
@@ -299,11 +336,11 @@ PRResult PRDevice::SwitchesUpdateRule(uint8_t switchNum, PREventType eventType,
} }
else else
{ {
CreateSwitchesUpdateRulesBurst(burst, newRule); CreateSwitchUpdateRulesBurst(burst, newRule);
DEBUG(PRLog("Rule Words: %x %x %x %x\n", burst[0],burst[1],burst[2],burst[3])); DEBUG(PRLog("Rule Words: %x %x %x %x\n", burst[0],burst[1],burst[2],burst[3]));
// Write the rule: // Write the rule:
res = WriteData(burst, burstSize); res = PrepareWriteData(burst, burstSize);
} }
return res; return res;
@@ -322,7 +359,7 @@ int32_t PRDevice::DMDUpdateConfig(PRDMDConfig *dmdConfig)
DEBUG(PRLog("Words: %x %x %x %x %x %x %x\n",burst[0],burst[1],burst[2],burst[3], DEBUG(PRLog("Words: %x %x %x %x %x %x %x\n",burst[0],burst[1],burst[2],burst[3],
burst[4],burst[5],burst[6])); burst[4],burst[5],burst[6]));
rc = WriteData(burst, burstWords); rc = PrepareWriteData(burst, burstWords);
return rc; return rc;
} }
@@ -343,7 +380,7 @@ PRResult PRDevice::DMDDraw(uint8_t * dots)
dmd_command_buffer[k+1] = p_dmd_frame_buffer_words[k]; dmd_command_buffer[k+1] = p_dmd_frame_buffer_words[k];
} }
return WriteData(dmd_command_buffer, words_per_frame+1); return PrepareWriteData(dmd_command_buffer, words_per_frame+1);
// The following code prints out the init lines for the 4 Xilinx BlockRAMs // The following code prints out the init lines for the 4 Xilinx BlockRAMs
// in the FPGA. It's used to make an image for the P-ROC to display on power-up. // in the FPGA. It's used to make an image for the P-ROC to display on power-up.
@@ -375,74 +412,9 @@ PRResult PRDevice::DMDDraw(uint8_t * dots)
PRResult PRDevice::Open() PRResult PRDevice::Open()
{ {
int32_t i=0; PRResult res = PRHardwareOpen();
PRResult rc; if (res == kPRSuccess)
struct ftdi_device_list *devlist, *curdev;
char manufacturer[128], description[128];
uint32_t temp_word;
ftdiInitialized = false;
// Open the FTDI device
if (ftdi_init(&ftdic) != 0)
{ {
DEBUG(PRLog("Failed to initialize FTDI.\n"));
return kPRFailure;
}
// Find all FTDI devices
// This is very basic and really only expects to see 1 device. It needs to be
// smarter. At the very least, it should check some register on the P-ROC versus
// an input parameter to ensure the software is set up for the same architecture as
// the P-ROC (Stern vs WPC). Otherwise, it's possible to drive the coils the wrong
// polarity and blow fuses or fry transistors and all other sorts of badness.
// 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)));
ftdi_deinit(&ftdic);
return kPRFailure;
}
else {
DEBUG(PRLog("Number of FTDI devices found: %d\n", numDevices));
for (curdev = devlist; curdev != NULL; i++) {
DEBUG(PRLog("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)));
}
else {
DEBUG(PRLog(" Device #%d:\n", i));
DEBUG(PRLog(" Manufacturer: %s\n", manufacturer));
DEBUG(PRLog(" Description: %s\n", description));
}
curdev = curdev->next;
}
}
// Don't need the device list anymore
ftdi_list_free (&devlist);
// Did previous logic leave ftdic clean? Probably
// Need to de-init and re-init before opening usb? Doubtful.
//ftdi_deinit(&ftdic);
//ftdi_init(&ftdic);
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)));
return kPRFailure;
}
else
{
rc = kPRSuccess;
if (ftdic.type == TYPE_R) {
uint32_t chipid;
ftdi_read_chipid(&ftdic,&chipid);
DEBUG(PRLog("FTDI chip_id = 0x%x\n", chipid));
// Try to verify the P-ROC IS in the FPGA before initializing the FPGA's FTDI interface // 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. // just in case it was already initialized from a previous application execution.
DEBUG(PRLog("Verifying P-ROC ID: \n")); DEBUG(PRLog("Verifying P-ROC ID: \n"));
@@ -452,35 +424,27 @@ PRResult PRDevice::Open()
// before it allows access deeper into the chip. This keeps garbage from getting // before it allows access deeper into the chip. This keeps garbage from getting
// in and wreaking havoc before software is up and running. // in and wreaking havoc before software is up and running.
DEBUG(PRLog("Initializing P-ROC...\n")); DEBUG(PRLog("Initializing P-ROC...\n"));
rc = FlushReadBuffer(); res = FlushReadBuffer();
temp_word = P_ROC_INIT_PATTERN_A; uint32_t temp_word = P_ROC_INIT_PATTERN_A;
rc = WriteData(&temp_word, 1); res = WriteData(&temp_word, 1);
temp_word = P_ROC_INIT_PATTERN_B; temp_word = P_ROC_INIT_PATTERN_B;
rc = WriteData(&temp_word, 1); res = WriteData(&temp_word, 1);
rc = VerifyChipID(); res = VerifyChipID();
} }
else else
{ {
DEBUG(PRLog("Failed to verify chip ID.")); DEBUG(PRLog("Failed to verify chip ID."));
rc = kPRFailure; res = kPRFailure;
}
} }
} }
if (rc == kPRSuccess) return res;
ftdiInitialized = true;
return rc;
} }
PRResult PRDevice::Close() PRResult PRDevice::Close()
{ {
// TODO: Add protection against closing a not-open ftdic. // TODO: Add protection against closing a not-open ftdic.
if (ftdiInitialized) PRHardwareClose();
{
ftdi_usb_close(&ftdic);
ftdi_deinit(&ftdic);
}
return kPRSuccess; return kPRSuccess;
} }
@@ -534,6 +498,36 @@ PRResult PRDevice::RequestData(uint32_t module_select, uint32_t start_addr, int3
return WriteData(&requestWord, 1); return WriteData(&requestWord, 1);
} }
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));
return kPRFailure;
}
// If there are already some words prepared to be written and the addition of the new
// words will be too many, flush the currently prepared words to the P-ROC now.
if (numPreparedWriteWords + numWords > maxWriteWords)
{
if (FlushWriteData() == kPRFailure);
return kPRFailure;
}
memcpy(preparedWriteWords + numPreparedWriteWords, words, numWords * 4);
numPreparedWriteWords += numWords;
return kPRSuccess;
}
PRResult PRDevice::FlushWriteData()
{
PRResult res;
res = WriteData(preparedWriteWords, numPreparedWriteWords);
numPreparedWriteWords = 0; // Reset word counter
return res;
}
PRResult PRDevice::WriteData(uint32_t * words, int32_t numWords) PRResult PRDevice::WriteData(uint32_t * words, int32_t numWords)
{ {
int32_t j,k; int32_t j,k;
@@ -561,7 +555,7 @@ PRResult PRDevice::WriteData(uint32_t * words, int32_t numWords)
} }
int bytesToWrite = numWords * 4; int bytesToWrite = numWords * 4;
int bytesWritten = (int32_t)ftdi_write_data(&ftdic, wr_buffer, bytesToWrite); int bytesWritten = PRHardwareWrite(wr_buffer, bytesToWrite);
if (bytesWritten != bytesToWrite) if (bytesWritten != bytesToWrite)
{ {
@@ -623,7 +617,7 @@ PRResult PRDevice::FlushReadBuffer()
int32_t PRDevice::CollectReadData() int32_t PRDevice::CollectReadData()
{ {
int32_t rc,i; int32_t rc,i;
rc = ftdi_read_data(&ftdic, collect_buffer, FTDI_BUFFER_SIZE-num_collected_bytes); rc = PRHardwareRead(collect_buffer, FTDI_BUFFER_SIZE-num_collected_bytes);
for (i=0; i<rc; i=i++) { for (i=0; i<rc; i=i++) {
collected_bytes_fifo[collected_bytes_wr_addr] = collect_buffer[i]; collected_bytes_fifo[collected_bytes_wr_addr] = collect_buffer[i];
if (collected_bytes_wr_addr == (FTDI_BUFFER_SIZE-1)) if (collected_bytes_wr_addr == (FTDI_BUFFER_SIZE-1))

View File

@@ -29,28 +29,23 @@
*/ */
#include "../include/pinproc.h" #include "../include/pinproc.h"
#include "PRCommon.h"
#include "PRHardware.h" #include "PRHardware.h"
#include <queue> #include <queue>
#include <ftdi.h>
using namespace std; using namespace std;
#define maxDriverGroups (26) #define maxDriverGroups (26)
#define maxDrivers (256) #define maxDrivers (256)
#define maxSwitchRules (256<<2) // 8 bits of switchNum indicies plus bits for debounced and state. #define maxSwitchRules (256<<2) // 8 bits of switchNum indicies plus bits for debounced and state.
#define maxWriteWords (1536) // Hardware supports 2048 word bursts, but restrict to 1536 for margin.
#ifdef NDEBUG
# define DEBUG(block)
#else
# define DEBUG(block) block
#endif
extern void PRLog(const char *format, ...);
class PRDevice class PRDevice
{ {
public: public:
static PRDevice *Create(PRMachineType machineType); static PRDevice *Create(PRMachineType machineType);
~PRDevice(); ~PRDevice();
PRResult Reset(uint32_t resetFlags);
protected: protected:
PRDevice(PRMachineType machineType); PRDevice(PRMachineType machineType);
@@ -58,13 +53,16 @@ public:
// public libpinproc API: // public libpinproc API:
int GetEvents(PREvent *events, int maxEvents); int GetEvents(PREvent *events, int maxEvents);
PRResult FlushWriteData();
PRResult DriverUpdateGlobalConfig(PRDriverGlobalConfig *driverGlobalConfig); PRResult DriverUpdateGlobalConfig(PRDriverGlobalConfig *driverGlobalConfig);
PRResult DriverGetGroupConfig(uint8_t groupNum, PRDriverGroupConfig *driverGroupConfig); PRResult DriverGetGroupConfig(uint8_t groupNum, PRDriverGroupConfig *driverGroupConfig);
PRResult DriverUpdateGroupConfig(PRDriverGroupConfig *driverGroupConfig); PRResult DriverUpdateGroupConfig(PRDriverGroupConfig *driverGroupConfig);
PRResult DriverGetState(uint8_t driverNum, PRDriverState *driverState); PRResult DriverGetState(uint8_t driverNum, PRDriverState *driverState);
PRResult DriverUpdateState(PRDriverState *driverState); PRResult DriverUpdateState(PRDriverState *driverState);
PRResult SwitchesUpdateRule(uint8_t switchNum, PREventType eventType, PRSwitchRule *rule, PRDriverState *linkedDrivers, int numDrivers); PRResult SwitchUpdateConfig(PRSwitchConfig *switchConfig);
PRResult SwitchUpdateRule(uint8_t switchNum, PREventType eventType, PRSwitchRule *rule, PRDriverState *linkedDrivers, int numDrivers);
PRResult DriverWatchdogTickle(); PRResult DriverWatchdogTickle();
@@ -81,6 +79,10 @@ protected:
PRResult VerifyChipID(); PRResult VerifyChipID();
// Raw write and read methods // Raw write and read methods
//
/** Schedules data to be written to the P-ROC. */
PRResult PrepareWriteData(uint32_t * buffer, int32_t numWords);
/** Writes data to P-ROC. /** Writes data to P-ROC.
* Returns #kPFailure if the number of words read does not match the number requested. * Returns #kPFailure if the number of words read does not match the number requested.
@@ -117,8 +119,8 @@ protected:
queue<uint32_t> unrequestedDataQueue; /**< Queue of words received from the device that were not requested via RequestData(). Usually switch events. */ queue<uint32_t> unrequestedDataQueue; /**< Queue of words received from the device that were not requested via RequestData(). Usually switch events. */
queue<uint32_t> requestedDataQueue; /**< Queue of words received from the device as the result of a call to RequestData(). */ queue<uint32_t> requestedDataQueue; /**< Queue of words received from the device as the result of a call to RequestData(). */
bool ftdiInitialized; uint32_t preparedWriteWords[maxWriteWords];
ftdi_context ftdic; int32_t numPreparedWriteWords;
uint8_t collected_bytes_fifo[FTDI_BUFFER_SIZE]; uint8_t collected_bytes_fifo[FTDI_BUFFER_SIZE];
int32_t collected_bytes_rd_addr; int32_t collected_bytes_rd_addr;
@@ -130,13 +132,13 @@ protected:
// Local Device State // Local Device State
void Reset();
PRMachineType machineType; PRMachineType machineType;
PRDriverGlobalConfig driverGlobalConfig; PRDriverGlobalConfig driverGlobalConfig;
PRDriverGroupConfig driverGroups[maxDriverGroups]; PRDriverGroupConfig driverGroups[maxDriverGroups];
PRDriverState drivers[maxDrivers]; PRDriverState drivers[maxDrivers];
PRDMDConfig dmdConfig; PRDMDConfig dmdConfig;
PRSwitchConfig switchConfig;
PRSwitchRuleInternal switchRules[maxSwitchRules]; PRSwitchRuleInternal switchRules[maxSwitchRules];
queue<uint32_t> freeSwitchRuleIndexes; /**< Indexes of available switch rules. */ queue<uint32_t> freeSwitchRuleIndexes; /**< Indexes of available switch rules. */
PRSwitchRuleInternal *GetSwitchRuleByIndex(uint16_t index); PRSwitchRuleInternal *GetSwitchRuleByIndex(uint16_t index);

View File

@@ -30,6 +30,7 @@
#include "PRHardware.h" #include "PRHardware.h"
#include "PRCommon.h"
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 ) {
@@ -139,6 +140,28 @@ int32_t CreateWatchdogConfigBurst ( uint32_t * burst, bool_t watchdogExpired,
return kPRSuccess; return kPRSuccess;
} }
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 );
burst[1] = (switchConfig->clear << P_ROC_SWITCH_CONFIG_CLEAR_SHIFT) |
(switchConfig->directMatrixScanLoopTime <<
P_ROC_SWITCH_CONFIG_MS_PER_DM_SCAN_LOOP_SHIFT) |
(switchConfig->pulsesBeforeCheckingRX <<
P_ROC_SWITCH_CONFIG_PULSES_BEFORE_CHECKING_RX_SHIFT) |
(switchConfig->inactivePulsesAfterBurst <<
P_ROC_SWITCH_CONFIG_INACTIVE_PULSES_AFTER_BURST_SHIFT) |
(switchConfig->pulsesPerBurst <<
P_ROC_SWITCH_CONFIG_PULSES_PER_BURST_SHIFT) |
(switchConfig->pulseHalfPeriodTime <<
P_ROC_SWITCH_CONFIG_MS_PER_PULSE_HALF_PERIOD_SHIFT);
return kPRSuccess;
}
int16_t CreateSwitchRuleIndex(uint8_t switchNum, PREventType eventType) int16_t CreateSwitchRuleIndex(uint8_t switchNum, PREventType eventType)
{ {
uint32_t debounce = (eventType == kPREventTypeSwitchOpenDebounced) || (eventType == kPREventTypeSwitchClosedDebounced) ? 1 : 0; uint32_t debounce = (eventType == kPREventTypeSwitchOpenDebounced) || (eventType == kPREventTypeSwitchClosedDebounced) ? 1 : 0;
@@ -169,7 +192,7 @@ void ParseSwitchRuleIndex(uint16_t index, uint8_t *switchNum, PREventType *event
*eventType = debounce ? kPREventTypeSwitchClosedDebounced : kPREventTypeSwitchClosedNondebounced; *eventType = debounce ? kPREventTypeSwitchClosedDebounced : kPREventTypeSwitchClosedNondebounced;
} }
int32_t CreateSwitchesUpdateRulesBurst ( uint32_t * burst, PRSwitchRuleInternal *rule_record) { int32_t CreateSwitchUpdateRulesBurst ( uint32_t * burst, PRSwitchRuleInternal *rule_record) {
uint32_t addr = CreateSwitchRuleAddr(rule_record->switchNum, rule_record->eventType); uint32_t addr = CreateSwitchRuleAddr(rule_record->switchNum, rule_record->eventType);
uint32_t driver_command[3]; uint32_t driver_command[3];
@@ -212,3 +235,115 @@ int32_t CreateDMDUpdateConfigBurst ( uint32_t * burst, PRDMDConfig *dmd_config)
return kPRSuccess; return kPRSuccess;
} }
/**
* This is where all FTDI driver-specific code should go.
* As we add support for other drivers (such as D2xx on Windows), we will add more implementations of the PRHardware*() functions here.
*/
#if !defined(USE_LIBFTDI)
#define USE_LIBFTDI 1
#endif
#if USE_LIBFTDI
#include <ftdi.h>
static bool ftdiInitialized;
static ftdi_context ftdic;
PRResult PRHardwareOpen()
{
int32_t i=0;
PRResult rc;
struct ftdi_device_list *devlist, *curdev;
char manufacturer[128], description[128];
ftdiInitialized = false;
// Open the FTDI device
if (ftdi_init(&ftdic) != 0)
{
DEBUG(PRLog("Failed to initialize FTDI.\n"));
return kPRFailure;
}
// Find all FTDI devices
// This is very basic and really only expects to see 1 device. It needs to be
// smarter. At the very least, it should check some register on the P-ROC versus
// an input parameter to ensure the software is set up for the same architecture as
// the P-ROC (Stern vs WPC). Otherwise, it's possible to drive the coils the wrong
// polarity and blow fuses or fry transistors and all other sorts of badness.
// 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)));
ftdi_deinit(&ftdic);
return kPRFailure;
}
else {
DEBUG(PRLog("Number of FTDI devices found: %d\n", numDevices));
for (curdev = devlist; curdev != NULL; i++) {
DEBUG(PRLog("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)));
}
else {
DEBUG(PRLog(" Device #%d:\n", i));
DEBUG(PRLog(" Manufacturer: %s\n", manufacturer));
DEBUG(PRLog(" Description: %s\n", description));
}
curdev = curdev->next;
}
}
// Don't need the device list anymore
ftdi_list_free (&devlist);
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)));
return kPRFailure;
}
else
{
rc = kPRSuccess;
if (ftdic.type == TYPE_R) {
uint32_t chipid;
ftdi_read_chipid(&ftdic,&chipid);
DEBUG(PRLog("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.
ftdiInitialized = true;
return kPRSuccess;
}
else
{
DEBUG(PRLog("FTDI type != TYPE_R: 0x%x\n", ftdic.type));
return kPRFailure;
}
}
}
void PRHardwareClose()
{
if (ftdiInitialized)
{
ftdi_usb_close(&ftdic);
ftdi_deinit(&ftdic);
}
}
int PRHardwareRead(uint8_t *buffer, int maxBytes)
{
return ftdi_read_data(&ftdic, buffer, maxBytes);
}
int PRHardwareWrite(uint8_t *buffer, int bytes)
{
return ftdi_write_data(&ftdic, buffer, bytes);
}
#endif // USE_LIBFTDI

View File

@@ -121,6 +121,13 @@ const uint32_t P_ROC_DRIVER_CONFIG_PATTER_ENABLE_SHIFT = 30;
const uint32_t P_ROC_DRIVER_CONFIG_TABLE_DRIVER_NUM_SHIFT = 1; const uint32_t P_ROC_DRIVER_CONFIG_TABLE_DRIVER_NUM_SHIFT = 1;
const uint32_t P_ROC_SWITCH_CONFIG_CLEAR_SHIFT = 31;
const uint32_t P_ROC_SWITCH_CONFIG_MS_PER_DM_SCAN_LOOP_SHIFT = 24;
const uint32_t P_ROC_SWITCH_CONFIG_PULSES_BEFORE_CHECKING_RX_SHIFT = 18;
const uint32_t P_ROC_SWITCH_CONFIG_INACTIVE_PULSES_AFTER_BURST_SHIFT = 12;
const uint32_t P_ROC_SWITCH_CONFIG_PULSES_PER_BURST_SHIFT = 6;
const uint32_t P_ROC_SWITCH_CONFIG_MS_PER_PULSE_HALF_PERIOD_SHIFT = 0;
const uint32_t P_ROC_SWITCH_RULE_NUM_DEBOUNCE_SHIFT = 9; const uint32_t P_ROC_SWITCH_RULE_NUM_DEBOUNCE_SHIFT = 9;
const uint32_t P_ROC_SWITCH_RULE_NUM_STATE_SHIFT = 8; const uint32_t P_ROC_SWITCH_RULE_NUM_STATE_SHIFT = 8;
const uint32_t P_ROC_SWITCH_RULE_NUM_SWITCH_NUM_SHIFT = 0; const uint32_t P_ROC_SWITCH_RULE_NUM_SWITCH_NUM_SHIFT = 0;
@@ -160,7 +167,8 @@ 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, PRSwitchRuleInternal *rule_record); int32_t CreateSwitchUpdateConfigBurst ( uint32_t * burst, PRSwitchConfig *switchConfig);
int32_t CreateSwitchUpdateRulesBurst ( uint32_t * burst, PRSwitchRuleInternal *rule_record);
int32_t CreateWatchdogConfigBurst ( uint32_t * burst, bool_t watchdogExpired, int32_t CreateWatchdogConfigBurst ( uint32_t * burst, bool_t watchdogExpired,
bool_t watchdogEnable, uint16_t watchdogResetTime); bool_t watchdogEnable, uint16_t watchdogResetTime);
int32_t CreateDMDUpdateConfigBurst ( uint32_t * burst, PRDMDConfig *dmd_config); int32_t CreateDMDUpdateConfigBurst ( uint32_t * burst, PRDMDConfig *dmd_config);
@@ -169,4 +177,10 @@ void ParseSwitchRuleIndex(uint16_t index, uint8_t *switchNum, PREventType *event
int16_t CreateSwitchRuleIndex(uint8_t switchNum, PREventType eventType); int16_t CreateSwitchRuleIndex(uint8_t switchNum, PREventType eventType);
int32_t CreateSwitchRuleAddr(uint8_t switchNum, PREventType eventType); int32_t CreateSwitchRuleAddr(uint8_t switchNum, PREventType eventType);
PRResult PRHardwareOpen();
void PRHardwareClose();
int PRHardwareRead(uint8_t *buffer, int maxBytes);
int PRHardwareWrite(uint8_t *buffer, int bytes);
#endif // _PROC_HARDWARE_H_ #endif // _PROC_HARDWARE_H_

View File

@@ -72,6 +72,20 @@ PR_EXPORT void PRDelete(PRHandle handle)
delete (PRDevice*)handle; delete (PRDevice*)handle;
} }
/** Resets internally maintained driver and switch rule structures and optionally writes those to the P-ROC device. */
PR_EXPORT PRResult PRReset(PRHandle handle, uint32_t resetFlags)
{
return handleAsDevice->Reset(resetFlags);
}
// I/O
/** Flush all pending write data out to the P-ROC */
PR_EXPORT PRResult PRFlushWriteData(PRHandle handle)
{
return handleAsDevice->FlushWriteData();
}
// Events // Events
/** Get all of the available events that have been received. */ /** Get all of the available events that have been received. */
@@ -80,7 +94,6 @@ PR_EXPORT int PRGetEvents(PRHandle handle, PREvent *eventsOut, int maxEvents)
return handleAsDevice->GetEvents(eventsOut, maxEvents); return handleAsDevice->GetEvents(eventsOut, maxEvents);
} }
// Drivers // Drivers
PR_EXPORT PRResult PRDriverUpdateGlobalConfig(PRHandle handle, PRDriverGlobalConfig *driverGlobalConfig) PR_EXPORT PRResult PRDriverUpdateGlobalConfig(PRHandle handle, PRDriverGlobalConfig *driverGlobalConfig)
{ {
@@ -181,9 +194,14 @@ PR_EXPORT void PRDriverStatePatter(PRDriverState *driver, uint16_t millisecondsO
// Switches // Switches
PR_EXPORT PRResult PRSwitchesUpdateRule(PRHandle handle, uint8_t switchNum, PREventType eventType, PRSwitchRule *rule, PRDriverState *linkedDrivers, int numDrivers) PR_EXPORT PRResult PRSwitchUpdateConfig(PRHandle handle, PRSwitchConfig *switchConfig)
{ {
return handleAsDevice->SwitchesUpdateRule(switchNum, eventType, rule, linkedDrivers, numDrivers); return handleAsDevice->SwitchUpdateConfig(switchConfig);
}
PR_EXPORT PRResult PRSwitchUpdateRule(PRHandle handle, uint8_t switchNum, PREventType eventType, PRSwitchRule *rule, PRDriverState *linkedDrivers, int numDrivers)
{
return handleAsDevice->SwitchUpdateRule(switchNum, eventType, rule, linkedDrivers, numDrivers);
} }
PR_EXPORT int32_t PRDMDUpdateConfig(PRHandle handle, PRDMDConfig *dmdConfig) PR_EXPORT int32_t PRDMDUpdateConfig(PRHandle handle, PRDMDConfig *dmdConfig)