mirror of
https://github.com/preble/libpinproc
synced 2026-02-22 18:15:25 +01:00
Merge branch 'master' into ruby
This commit is contained in:
@@ -1,18 +1,18 @@
|
||||
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_RUNTIME_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)
|
||||
add_library(pinproc ${FILES})
|
||||
|
||||
add_executable(pinproctest examples/pinproctest/pinproctest.cpp)
|
||||
target_link_libraries(pinproctest pinproc usb ftdi)
|
||||
target_link_libraries(pinproctest pinproc usb ftdi yaml-cpp)
|
||||
|
||||
|
||||
23
Makefile
23
Makefile
@@ -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)
|
||||
@@ -11,14 +11,16 @@ libpinproc requires:
|
||||
- [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.
|
||||
|
||||
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.
|
||||
|
||||
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 lib/libyaml-cpp.a /usr/local/lib/
|
||||
sudo mkdir /usr/local/include/yaml-cpp
|
||||
sudo cp include/*.h /usr/local/include/yaml-cpp/
|
||||
|
||||
#### Building with CMake
|
||||
|
||||
Download and install [CMake](http://www.cmake.org/cmake/resources/software.html). Then:
|
||||
|
||||
cd libpinproc
|
||||
mkdir build; cd build
|
||||
cmake ..
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
PRGameName: My Great Pin
|
||||
PRDrivers:
|
||||
1: driver one
|
||||
2: driver two
|
||||
PRSwitches:
|
||||
1: switch one
|
||||
2: switch two
|
||||
45
examples/pinproctest/JD.yaml
Normal file
45
examples/pinproctest/JD.yaml
Normal 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
|
||||
@@ -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)
|
||||
48
examples/pinproctest/TZ.yaml
Normal file
48
examples/pinproctest/TZ.yaml
Normal 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
|
||||
@@ -32,29 +32,16 @@
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#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 kFlipperLwRightSw (1)
|
||||
#define kFlipperLwLeftSw (3)
|
||||
#define kFlipperUpRightSw (5)
|
||||
#define kFlipperUpLeftSw (7)
|
||||
|
||||
#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 kFlippersSection "PRFlippers"
|
||||
#define kBumpersSection "PRBumpers"
|
||||
#define kCoilsSection "PRCoils"
|
||||
#define kSwitchesSection "PRSwitches"
|
||||
#define kNumberField "number"
|
||||
|
||||
#define kFlipperPulseTime (34) // 34 ms
|
||||
#define kBumperPulseTime (25) // 25 ms
|
||||
@@ -69,24 +56,85 @@ void TestLogger(const char *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 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 = false;
|
||||
globals.globalPolarity = globalPolarity;
|
||||
globals.useClear = false;
|
||||
globals.strobeStartSelect = false;
|
||||
globals.startStrobeTime = 4; // milliseconds per output loop
|
||||
globals.matrixRowEnableIndex1 = 12;
|
||||
globals.matrixRowEnableIndex0 = 6;
|
||||
globals.activeLowMatrixRows = true;
|
||||
globals.tickleSternWatchdog = 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 = 1000; // milliseconds
|
||||
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:
|
||||
@@ -100,13 +148,14 @@ void ConfigureDrivers(PRHandle proc)
|
||||
|
||||
// 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 = 0; i < 6; i++)
|
||||
for (i = 4; i < 10; i++)
|
||||
{
|
||||
PRDriverGetGroupConfig(proc, i + 4, &group);
|
||||
PRDriverGetGroupConfig(proc, i, &group);
|
||||
group.slowTime = 0;
|
||||
group.enableIndex = i;
|
||||
group.rowActivateIndex = i;
|
||||
group.enableIndex = mappedDriverGroupEnableIndex[i];
|
||||
group.rowActivateIndex = 0;
|
||||
group.rowEnableSelect = 0;
|
||||
group.matrixed = false;
|
||||
group.polarity = false;
|
||||
@@ -117,11 +166,11 @@ void ConfigureDrivers(PRHandle proc)
|
||||
}
|
||||
|
||||
// The following 8 groups are configured for the feature lamp matrix.
|
||||
for (i = 6; i < 14; i++) {
|
||||
PRDriverGetGroupConfig(proc, i + 4, &group);
|
||||
group.slowTime = 400;
|
||||
group.enableIndex = 7;
|
||||
group.rowActivateIndex = i - 6;
|
||||
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;
|
||||
@@ -131,18 +180,17 @@ void ConfigureDrivers(PRHandle proc)
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigureSwitches(PRHandle proc)
|
||||
void ConfigureSwitches(PRHandle proc, YAML::Node& yamlDoc)
|
||||
{
|
||||
int i;
|
||||
|
||||
// Configures rules to notify the host for every debounced switch event.
|
||||
for (i = 0; i <= kPRSwitchPhysicalLast; i++)
|
||||
{
|
||||
PRSwitchRule sw;
|
||||
sw.notifyHost = true;
|
||||
PRSwitchesUpdateRule(proc, i, kPREventTypeSwitchClosedDebounced, &sw, NULL, 0);
|
||||
PRSwitchesUpdateRule(proc, i, kPREventTypeSwitchOpenDebounced, &sw, NULL, 0);
|
||||
}
|
||||
// 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)
|
||||
@@ -157,7 +205,9 @@ void ConfigureWPCFlipperSwitchRule (PRHandle proc, int swNum, int mainCoilNum, i
|
||||
PRDriverGetState(proc, holdCoilNum, &drivers[1]);
|
||||
PRDriverStatePulse(&drivers[1],0); // Turn on indefintely (set pulse for 0ms)
|
||||
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
|
||||
PRDriverGetState(proc, mainCoilNum, &drivers[0]);
|
||||
@@ -165,7 +215,9 @@ void ConfigureWPCFlipperSwitchRule (PRHandle proc, int swNum, int mainCoilNum, i
|
||||
PRDriverGetState(proc, holdCoilNum, &drivers[1]);
|
||||
PRDriverStateDisable(&drivers[1]); // Disable hold coil
|
||||
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)
|
||||
@@ -178,20 +230,37 @@ void ConfigureBumperRule (PRHandle proc, int swNum, int coilNum, int pulseTime)
|
||||
PRDriverGetState(proc, coilNum, &drivers[0]);
|
||||
PRDriverStatePulse(&drivers[0],pulseTime); // Pulse coil for 34ms.
|
||||
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
|
||||
ConfigureWPCFlipperSwitchRule (proc, kFlipperLwRightSw, kFlipperLwRightMain, kFlipperLwRightHold, kFlipperPulseTime); // Lower Right WPC Flipper
|
||||
ConfigureWPCFlipperSwitchRule (proc, kFlipperLwLeftSw, kFlipperLwLeftMain, kFlipperLwLeftHold, kFlipperPulseTime); // Lower Left WPC Flipper
|
||||
ConfigureWPCFlipperSwitchRule (proc, kFlipperUpRightSw, kFlipperUpRightMain, kFlipperUpRightHold, kFlipperPulseTime); // Upper Right WPC Flipper
|
||||
ConfigureWPCFlipperSwitchRule (proc, kFlipperUpLeftSw, kFlipperUpLeftMain, kFlipperUpLeftHold, kFlipperPulseTime); // Upper Left WPC Flipper
|
||||
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);
|
||||
}
|
||||
|
||||
// WPC Slingshots
|
||||
ConfigureBumperRule (proc, kSlingRightSw, kSlingRightCoil, kBumperPulseTime); // WPC Right Slingshot
|
||||
ConfigureBumperRule (proc, kSlingLeftSw, kSlingLeftCoil, kBumperPulseTime); // WPC Left Slingshot
|
||||
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)
|
||||
@@ -226,7 +295,7 @@ void ConfigureDMD(PRHandle proc)
|
||||
// starting with dim dots at the top.
|
||||
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;
|
||||
|
||||
loopCtr = dotOffset/rate_reduction_divisor;
|
||||
@@ -243,33 +312,34 @@ void UpdateDots( unsigned char * dots, unsigned int dotOffset )
|
||||
memset(dots,0,((kDMDColumns*kDMDRows)/8)*kDMDSubFrames);
|
||||
|
||||
// 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
|
||||
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 (j = 0; j < kDMDColumns / 8; j++)
|
||||
for (col = 0; col < kDMDColumns / 8; col++)
|
||||
{
|
||||
// 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
|
||||
// active for the color code.
|
||||
if ((mappedColor >> k) & 1 == 1)
|
||||
dots[k*(kDMDColumns*kDMDRows/8)+((i%kDMDRows)*(kDMDColumns / 8))+j] = byte_shifter;
|
||||
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 (i % (int)((kDMDRows/pow(2,kDMDSubFrames))) == 0) 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;
|
||||
|
||||
void RunLoop(PRHandle proc)
|
||||
@@ -302,8 +372,11 @@ void RunLoop(PRHandle proc)
|
||||
case kPREventTypeSwitchOpenNondebounced: stateText = "open(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.
|
||||
}
|
||||
}
|
||||
@@ -315,26 +388,56 @@ void sigint(int)
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
PRHandle proc = PRCreate(kPRMachineWPC);
|
||||
PRHandle proc = PRCreate(machineType);
|
||||
if (proc == kPRHandleInvalid)
|
||||
return 1;
|
||||
|
||||
|
||||
PRReset(proc, kPRResetFlagUpdateDevice); // Reset the device structs and write them into the device.
|
||||
|
||||
ConfigureDMD(proc);
|
||||
ConfigureSwitches(proc); // Notify host for all debounced switch events.
|
||||
ConfigureSwitchRules(proc); // Flippers, slingshots
|
||||
ConfigureSwitches(proc, yamlDoc); // Notify host for all debounced switch events.
|
||||
ConfigureSwitchRules(proc, yamlDoc); // Flippers, slingshots
|
||||
|
||||
// Make Drivers the last thing to configure so watchdog doesn't expire
|
||||
// before the RunLoop begins.
|
||||
ConfigureDrivers(proc);
|
||||
ConfigureDrivers(proc, machineType, yamlDoc);
|
||||
|
||||
printf("Running. Hit Ctrl-C to exit.\n");
|
||||
|
||||
@@ -347,6 +450,10 @@ int main(const char **argv, int argc)
|
||||
|
||||
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:
|
||||
PRDelete(proc);
|
||||
proc = kPRHandleInvalid;
|
||||
|
||||
@@ -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 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
|
||||
|
||||
// I/O
|
||||
|
||||
/** Flush all pending write data out to the P-ROC */
|
||||
PR_EXPORT PRResult PRFlushWriteData(PRHandle handle);
|
||||
|
||||
// Drivers
|
||||
/** @defgroup drivers Driver Manipulation
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define kPRDriverGroupsMax (26) /**< Number of available driver groups. */
|
||||
#define kPRDriverCount (256) /**< Total number of drivers */
|
||||
|
||||
typedef struct PRDriverGlobalConfig {
|
||||
bool_t enableOutputs; // Formerly enable_direct_outputs
|
||||
bool_t globalPolarity;
|
||||
@@ -178,25 +195,25 @@ PR_EXPORT PRResult PRDriverWatchdogTickle(PRHandle handle);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
/**
|
||||
* Changes the given #PRDriverState to reflect a pulse state.
|
||||
* @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);
|
||||
/**
|
||||
* Changes the given #PRDriverState to reflect a scheduled state.
|
||||
* 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);
|
||||
/**
|
||||
* @brief Changes the given #PRDriverState to reflect a pitter-patter schedule state.
|
||||
* 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.
|
||||
*/
|
||||
@@ -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 kPRSwitchVirtualFirst (224) /**< Switch number of the first 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 {
|
||||
bool_t notifyHost; /**< If true this switch change event will provided to the user via PRGetEvents(). */
|
||||
} 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.
|
||||
*
|
||||
@@ -264,7 +295,7 @@ typedef struct PRSwitchRule {
|
||||
* @code
|
||||
* PRSwitchRule rule;
|
||||
* rule.notifyHost = true;
|
||||
* PRSwitchesUpdateRule(handle, switchNum, kPREventTypeSwitchOpenDebounced, &rule, NULL, 0);
|
||||
* PRSwitchUpdateRule(handle, switchNum, kPREventTypeSwitchOpenDebounced, &rule, NULL, 0);
|
||||
* @endcode
|
||||
*
|
||||
* 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]);
|
||||
* PRDriverStatePulse(&drivers[0], 50);
|
||||
* PRDriverStatePulse(&drivers[1], 50);
|
||||
* PRSwitchesUpdateRule(handle, swPopBumper1, kPREventTypeSwitchClosedNondebounced,
|
||||
* PRSwitchUpdateRule(handle, swPopBumper1, kPREventTypeSwitchClosedNondebounced,
|
||||
* &rule, drivers, 2);
|
||||
* // Now configure a switch rule to process scoring in software:
|
||||
* rule.notifyHost = true;
|
||||
* PRSwitchesUpdateRule(handle, swPopBumper1, kPREventTypeSwitchClosedDebounced,
|
||||
* PRSwitchUpdateRule(handle, swPopBumper1, kPREventTypeSwitchClosedDebounced,
|
||||
* &rule, NULL, 0);
|
||||
* @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 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
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
668249E30FC0A3960051560E /* pinproctest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 668249E20FC0A3960051560E /* pinproctest.cpp */; };
|
||||
668249EA0FC0A4280051560E /* libpinproc.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D2AAC046055464E500DB518D /* libpinproc.a */; };
|
||||
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 */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -36,6 +37,7 @@
|
||||
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>"; };
|
||||
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; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
@@ -95,6 +97,7 @@
|
||||
668249410FC07D900051560E /* PRDevice.cpp */,
|
||||
6682494A0FC0870B0051560E /* PRHardware.h */,
|
||||
668249EC0FC0A4CD0051560E /* PRHardware.cpp */,
|
||||
66824E7A0FCCBAFF0051560E /* PRCommon.h */,
|
||||
);
|
||||
name = libpinproc;
|
||||
sourceTree = "<group>";
|
||||
@@ -124,6 +127,7 @@
|
||||
6682492C0FC079050051560E /* pinproc.h in Headers */,
|
||||
668249420FC07D900051560E /* PRDevice.h in Headers */,
|
||||
6682494B0FC0870B0051560E /* PRHardware.h in Headers */,
|
||||
66824E7B0FCCBAFF0051560E /* PRCommon.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -222,10 +226,7 @@
|
||||
GCC_ENABLE_FIX_AND_CONTINUE = YES;
|
||||
GCC_MODEL_TUNING = G5;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
/usr/local/include,
|
||||
"../../yaml-cpp/include",
|
||||
);
|
||||
HEADER_SEARCH_PATHS = /usr/local/include;
|
||||
INSTALL_PATH = /usr/local/lib;
|
||||
OBJROOT = build;
|
||||
ONLY_ACTIVE_ARCH = NO;
|
||||
@@ -241,10 +242,7 @@
|
||||
CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)";
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
GCC_MODEL_TUNING = G5;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
/usr/local/include,
|
||||
"../../yaml-cpp/include",
|
||||
);
|
||||
HEADER_SEARCH_PATHS = /usr/local/include;
|
||||
INSTALL_PATH = /usr/local/lib;
|
||||
OBJROOT = build;
|
||||
PRODUCT_NAME = pinproc;
|
||||
@@ -287,8 +285,12 @@
|
||||
GCC_ENABLE_FIX_AND_CONTINUE = YES;
|
||||
GCC_MODEL_TUNING = G5;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
HEADER_SEARCH_PATHS = /usr/local/include;
|
||||
INSTALL_PATH = /usr/local/bin;
|
||||
OTHER_LDFLAGS = "-lftdi";
|
||||
OTHER_LDFLAGS = (
|
||||
"-lyaml-cpp",
|
||||
"-lftdi",
|
||||
);
|
||||
PREBINDING = NO;
|
||||
PRODUCT_NAME = pinproctest;
|
||||
};
|
||||
@@ -302,8 +304,12 @@
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
GCC_ENABLE_FIX_AND_CONTINUE = NO;
|
||||
GCC_MODEL_TUNING = G5;
|
||||
HEADER_SEARCH_PATHS = /usr/local/include;
|
||||
INSTALL_PATH = /usr/local/bin;
|
||||
OTHER_LDFLAGS = "-lftdi";
|
||||
OTHER_LDFLAGS = (
|
||||
"-lyaml-cpp",
|
||||
"-lftdi",
|
||||
);
|
||||
PREBINDING = NO;
|
||||
PRODUCT_NAME = pinproctest;
|
||||
ZERO_LINK = NO;
|
||||
|
||||
36
src/PRCommon.h
Normal file
36
src/PRCommon.h
Normal 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_
|
||||
238
src/PRDevice.cpp
238
src/PRDevice.cpp
@@ -30,9 +30,10 @@
|
||||
|
||||
#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()
|
||||
@@ -57,49 +58,69 @@ PRDevice* PRDevice::Create(PRMachineType machineType)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dev->Reset();
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
void PRDevice::Reset()
|
||||
PRResult PRDevice::Reset(uint32_t resetFlags)
|
||||
{
|
||||
bool defaultPolarity = machineType != kPRMachineWPC;
|
||||
int i;
|
||||
memset(&driverGlobalConfig, 0x00, sizeof(PRDriverGlobalConfig));
|
||||
for (i = 0; i < maxDrivers; i++)
|
||||
for (i = 0; i < kPRDriverCount; i++)
|
||||
{
|
||||
PRDriverState *driver = &drivers[i];
|
||||
memset(driver, 0x00, sizeof(PRDriverState));
|
||||
driver->driverNum = i;
|
||||
driver->polarity = defaultPolarity;
|
||||
if (resetFlags & kPRResetFlagUpdateDevice) DriverUpdateState(driver);
|
||||
}
|
||||
for (i = 0; i < maxDriverGroups; i++)
|
||||
for (i = 0; i < kPRDriverGroupsMax; i++)
|
||||
{
|
||||
PRDriverGroupConfig *group = &driverGroups[i];
|
||||
memset(group, 0x00, sizeof(PRDriverGroupConfig));
|
||||
group->groupNum = i;
|
||||
group->polarity = defaultPolarity;
|
||||
}
|
||||
for (i = 0; i < maxSwitchRules; i++)
|
||||
|
||||
freeSwitchRuleIndexes.empty();
|
||||
|
||||
for (i = 0; i < kPRSwitchRulesCount; i++)
|
||||
{
|
||||
PRSwitchRuleInternal *switchRule = &switchRules[i];
|
||||
memset(switchRule, 0x00, sizeof(PRSwitchRule));
|
||||
|
||||
uint16_t ruleIndex = i;
|
||||
ParseSwitchRuleIndex(ruleIndex, &switchRule->switchNum, &switchRule->eventType);
|
||||
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);
|
||||
}
|
||||
|
||||
// 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();
|
||||
requestedDataQueue.empty();
|
||||
num_collected_bytes = 0;
|
||||
numPreparedWriteWords = 0;
|
||||
|
||||
// TODO: Assign defaults based on machineType. Some may have already been done above.
|
||||
return kPRSuccess;
|
||||
}
|
||||
|
||||
|
||||
int PRDevice::GetEvents(PREvent *events, int maxEvents)
|
||||
{
|
||||
SortReturningData();
|
||||
@@ -139,7 +160,7 @@ PRResult PRDevice::DriverUpdateGlobalConfig(PRDriverGlobalConfig *driverGlobalCo
|
||||
|
||||
DEBUG(PRLog("Driver Global words: %x %x\n", burst[0], burst[1]));
|
||||
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)
|
||||
@@ -159,7 +180,7 @@ PRResult PRDevice::DriverUpdateGroupConfig(PRDriverGroupConfig *driverGroupConfi
|
||||
rc = CreateDriverUpdateGroupConfigBurst(burst, driverGroupConfig);
|
||||
|
||||
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)
|
||||
@@ -187,7 +208,7 @@ PRResult PRDevice::DriverUpdateState(PRDriverState *driverState)
|
||||
rc = CreateDriverUpdateBurst(burst, &drivers[driverState->driverNum]);
|
||||
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.watchdogResetTime);
|
||||
|
||||
return WriteData(burst, burstWords);
|
||||
return PrepareWriteData(burst, burstWords);
|
||||
}
|
||||
|
||||
|
||||
@@ -211,7 +232,23 @@ PRSwitchRuleInternal *PRDevice::GetSwitchRuleByIndex(uint16_t 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.
|
||||
const int burstSize = 4;
|
||||
@@ -265,7 +302,7 @@ PRResult PRDevice::SwitchesUpdateRule(uint8_t switchNum, PREventType eventType,
|
||||
newRule->linkIndex = freeSwitchRuleIndexes.front();
|
||||
freeSwitchRuleIndexes.pop();
|
||||
|
||||
CreateSwitchesUpdateRulesBurst(burst, newRule);
|
||||
CreateSwitchUpdateRulesBurst(burst, newRule);
|
||||
|
||||
// Prepare for the next rule:
|
||||
newRule = GetSwitchRuleByIndex(newRule->linkIndex);
|
||||
@@ -273,20 +310,20 @@ PRResult PRDevice::SwitchesUpdateRule(uint8_t switchNum, PREventType eventType,
|
||||
else
|
||||
{
|
||||
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]));
|
||||
// Write the rule:
|
||||
res = WriteData(burst, burstSize);
|
||||
res = PrepareWriteData(burst, burstSize);
|
||||
if (res != kPRSuccess)
|
||||
{
|
||||
DEBUG(PRLog("Error while writing switch update, attempting to revert switch rule to a safe state..."));
|
||||
newRule = GetSwitchRuleByIndex(firstRuleIndex);
|
||||
newRule->changeOutput = false;
|
||||
newRule->linkActive = false;
|
||||
CreateSwitchesUpdateRulesBurst(burst, newRule);
|
||||
if (WriteData(burst, burstSize) == kPRSuccess)
|
||||
CreateSwitchUpdateRulesBurst(burst, newRule);
|
||||
if (PrepareWriteData(burst, burstSize) == kPRSuccess)
|
||||
DEBUG(PRLog("Disabled successfully.\n"));
|
||||
else
|
||||
DEBUG(PRLog("Failed to disable.\n"));
|
||||
@@ -299,11 +336,11 @@ PRResult PRDevice::SwitchesUpdateRule(uint8_t switchNum, PREventType eventType,
|
||||
}
|
||||
else
|
||||
{
|
||||
CreateSwitchesUpdateRulesBurst(burst, newRule);
|
||||
CreateSwitchUpdateRulesBurst(burst, newRule);
|
||||
DEBUG(PRLog("Rule Words: %x %x %x %x\n", burst[0],burst[1],burst[2],burst[3]));
|
||||
|
||||
// Write the rule:
|
||||
res = WriteData(burst, burstSize);
|
||||
res = PrepareWriteData(burst, burstSize);
|
||||
}
|
||||
|
||||
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],
|
||||
burst[4],burst[5],burst[6]));
|
||||
|
||||
rc = WriteData(burst, burstWords);
|
||||
rc = PrepareWriteData(burst, burstWords);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -343,7 +380,7 @@ PRResult PRDevice::DMDDraw(uint8_t * dots)
|
||||
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
|
||||
// in the FPGA. It's used to make an image for the P-ROC to display on power-up.
|
||||
@@ -375,112 +412,39 @@ PRResult PRDevice::DMDDraw(uint8_t * dots)
|
||||
|
||||
PRResult PRDevice::Open()
|
||||
{
|
||||
int32_t i=0;
|
||||
PRResult rc;
|
||||
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)
|
||||
PRResult res = PRHardwareOpen();
|
||||
if (res == kPRSuccess)
|
||||
{
|
||||
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;
|
||||
// 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"));
|
||||
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"));
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 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
|
||||
// just in case it was already initialized from a previous application execution.
|
||||
DEBUG(PRLog("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"));
|
||||
rc = FlushReadBuffer();
|
||||
temp_word = P_ROC_INIT_PATTERN_A;
|
||||
rc = WriteData(&temp_word, 1);
|
||||
temp_word = P_ROC_INIT_PATTERN_B;
|
||||
rc = WriteData(&temp_word, 1);
|
||||
rc = VerifyChipID();
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG(PRLog("Failed to verify chip ID."));
|
||||
rc = kPRFailure;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG(PRLog("Failed to verify chip ID."));
|
||||
res = kPRFailure;
|
||||
}
|
||||
}
|
||||
|
||||
if (rc == kPRSuccess)
|
||||
ftdiInitialized = true;
|
||||
|
||||
return rc;
|
||||
return res;
|
||||
}
|
||||
|
||||
PRResult PRDevice::Close()
|
||||
{
|
||||
// TODO: Add protection against closing a not-open ftdic.
|
||||
if (ftdiInitialized)
|
||||
{
|
||||
ftdi_usb_close(&ftdic);
|
||||
ftdi_deinit(&ftdic);
|
||||
}
|
||||
PRHardwareClose();
|
||||
return kPRSuccess;
|
||||
}
|
||||
|
||||
@@ -534,6 +498,36 @@ PRResult PRDevice::RequestData(uint32_t module_select, uint32_t start_addr, int3
|
||||
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)
|
||||
{
|
||||
int32_t j,k;
|
||||
@@ -561,7 +555,7 @@ PRResult PRDevice::WriteData(uint32_t * words, int32_t numWords)
|
||||
}
|
||||
|
||||
int bytesToWrite = numWords * 4;
|
||||
int bytesWritten = (int32_t)ftdi_write_data(&ftdic, wr_buffer, bytesToWrite);
|
||||
int bytesWritten = PRHardwareWrite(wr_buffer, bytesToWrite);
|
||||
|
||||
if (bytesWritten != bytesToWrite)
|
||||
{
|
||||
@@ -623,7 +617,7 @@ PRResult PRDevice::FlushReadBuffer()
|
||||
int32_t PRDevice::CollectReadData()
|
||||
{
|
||||
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++) {
|
||||
collected_bytes_fifo[collected_bytes_wr_addr] = collect_buffer[i];
|
||||
if (collected_bytes_wr_addr == (FTDI_BUFFER_SIZE-1))
|
||||
|
||||
@@ -29,28 +29,23 @@
|
||||
*/
|
||||
|
||||
#include "../include/pinproc.h"
|
||||
#include "PRCommon.h"
|
||||
#include "PRHardware.h"
|
||||
#include <queue>
|
||||
#include <ftdi.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define maxDriverGroups (26)
|
||||
#define maxDrivers (256)
|
||||
#define maxSwitchRules (256<<2) // 8 bits of switchNum indicies plus bits for debounced and state.
|
||||
|
||||
#ifdef NDEBUG
|
||||
# define DEBUG(block)
|
||||
#else
|
||||
# define DEBUG(block) block
|
||||
#endif
|
||||
extern void PRLog(const char *format, ...);
|
||||
#define maxWriteWords (1536) // Hardware supports 2048 word bursts, but restrict to 1536 for margin.
|
||||
|
||||
class PRDevice
|
||||
{
|
||||
public:
|
||||
static PRDevice *Create(PRMachineType machineType);
|
||||
~PRDevice();
|
||||
PRResult Reset(uint32_t resetFlags);
|
||||
protected:
|
||||
PRDevice(PRMachineType machineType);
|
||||
|
||||
@@ -58,13 +53,16 @@ public:
|
||||
// public libpinproc API:
|
||||
int GetEvents(PREvent *events, int maxEvents);
|
||||
|
||||
PRResult FlushWriteData();
|
||||
|
||||
PRResult DriverUpdateGlobalConfig(PRDriverGlobalConfig *driverGlobalConfig);
|
||||
PRResult DriverGetGroupConfig(uint8_t groupNum, PRDriverGroupConfig *driverGroupConfig);
|
||||
PRResult DriverUpdateGroupConfig(PRDriverGroupConfig *driverGroupConfig);
|
||||
PRResult DriverGetState(uint8_t driverNum, 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();
|
||||
|
||||
@@ -81,6 +79,10 @@ protected:
|
||||
PRResult VerifyChipID();
|
||||
|
||||
// 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.
|
||||
* 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> requestedDataQueue; /**< Queue of words received from the device as the result of a call to RequestData(). */
|
||||
|
||||
bool ftdiInitialized;
|
||||
ftdi_context ftdic;
|
||||
uint32_t preparedWriteWords[maxWriteWords];
|
||||
int32_t numPreparedWriteWords;
|
||||
|
||||
uint8_t collected_bytes_fifo[FTDI_BUFFER_SIZE];
|
||||
int32_t collected_bytes_rd_addr;
|
||||
@@ -130,13 +132,13 @@ protected:
|
||||
|
||||
|
||||
// Local Device State
|
||||
void Reset();
|
||||
PRMachineType machineType;
|
||||
PRDriverGlobalConfig driverGlobalConfig;
|
||||
PRDriverGroupConfig driverGroups[maxDriverGroups];
|
||||
PRDriverState drivers[maxDrivers];
|
||||
PRDMDConfig dmdConfig;
|
||||
|
||||
PRSwitchConfig switchConfig;
|
||||
PRSwitchRuleInternal switchRules[maxSwitchRules];
|
||||
queue<uint32_t> freeSwitchRuleIndexes; /**< Indexes of available switch rules. */
|
||||
PRSwitchRuleInternal *GetSwitchRuleByIndex(uint16_t index);
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
|
||||
#include "PRHardware.h"
|
||||
#include "PRCommon.h"
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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 driver_command[3];
|
||||
|
||||
@@ -212,3 +235,115 @@ int32_t CreateDMDUpdateConfigBurst ( uint32_t * burst, PRDMDConfig *dmd_config)
|
||||
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
|
||||
|
||||
@@ -121,14 +121,21 @@ 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_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_SWITCH_NUM_SHIFT = 0;
|
||||
const uint32_t P_ROC_SWITCH_RULE_NUM_TO_ADDR_SHIFT = 2;
|
||||
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_NOTIFY_HOST_SHIFT = 23;
|
||||
const uint32_t P_ROC_SWITCH_RULE_LINK_ACTIVE_SHIFT = 10;
|
||||
const uint32_t P_ROC_SWITCH_RULE_LINK_ADDRESS_SHIFT = 11;
|
||||
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_SWITCH_NUM_SHIFT = 0;
|
||||
const uint32_t P_ROC_SWITCH_RULE_NUM_TO_ADDR_SHIFT = 2;
|
||||
|
||||
const uint32_t P_ROC_SWITCH_RULE_NOTIFY_HOST_SHIFT = 23;
|
||||
const uint32_t P_ROC_SWITCH_RULE_LINK_ACTIVE_SHIFT = 10;
|
||||
const uint32_t P_ROC_SWITCH_RULE_LINK_ADDRESS_SHIFT = 11;
|
||||
const uint32_t P_ROC_SWITCH_RULE_CHANGE_OUTPUT_SHIFT = 9;
|
||||
const uint32_t P_ROC_SWITCH_RULE_DRIVER_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 CreateDriverUpdateGroupConfigBurst ( uint32_t * burst, PRDriverGroupConfig *driver_group);
|
||||
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,
|
||||
bool_t watchdogEnable, uint16_t watchdogResetTime);
|
||||
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);
|
||||
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_
|
||||
|
||||
@@ -72,6 +72,20 @@ PR_EXPORT void PRDelete(PRHandle 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
|
||||
|
||||
/** 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);
|
||||
}
|
||||
|
||||
|
||||
// Drivers
|
||||
PR_EXPORT PRResult PRDriverUpdateGlobalConfig(PRHandle handle, PRDriverGlobalConfig *driverGlobalConfig)
|
||||
{
|
||||
@@ -181,9 +194,14 @@ PR_EXPORT void PRDriverStatePatter(PRDriverState *driver, uint16_t millisecondsO
|
||||
|
||||
// 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)
|
||||
|
||||
Reference in New Issue
Block a user