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

Initial commit.

This commit is contained in:
Adam Preble
2009-05-19 21:08:38 -04:00
commit 0a0756c2b5
13 changed files with 3633 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
build/
*/*.pbxuser
*/*.perspectivev3

1543
Doxyfile Normal file

File diff suppressed because it is too large Load Diff

23
Makefile Normal file
View File

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

29
README.markdown Normal file
View File

@@ -0,0 +1,29 @@
## libpinproc
Library for Gerry Stellenberg's [P-ROC](http://pinballcontrollers.com/) (Pinball Remote Operations Controller).
### License
The MIT License
Copyright (c) 2009 Gerry Stellenberg, Adam Preble
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,28 @@
#
# File: Makefile for application
#
CC=g++
LDFLAGS=-L../.. -L/usr/local/lib
LIBS=-lpinproc -lusb -lftdi
SRC=pinproctest.cpp
CXXFLAGS=-I../../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) ../../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,188 @@
/*
* The MIT License
* Copyright (c) 2009 Gerry Stellenberg, Adam Preble
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* pinproctest.cpp
* libpinproc
*/
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include "pinproc.h" // Include libpinproc's header.
/** Demonstration of the custom logging callback. */
void TestLogger(const char *text)
{
fprintf(stderr, "TEST: %s", text);
}
void ConfigureDrivers(PRHandle proc)
{
int i;
PRDriverGlobalConfig globals;
globals.enableOutputs = false;
globals.globalPolarity = false;
globals.useClear = false;
globals.strobeStartSelect = false;
globals.startStrobeTime = 4; // milliseconds per output loop
globals.matrixRowEnableIndex1 = 12;
globals.matrixRowEnableIndex0 = 6;
globals.activeLowMatrixRows = true;
globals.tickleWatchdog = false;
globals.encodeEnables = false;
// We want to start up safely, so we'll update the global driver config twice.
// When we toggle enableOutputs like this P-ROC will reset the polarity:
// Enable now without the outputs enabled:
PRDriverUpdateGlobalConfig(proc, &globals);
// Now enable the outputs: (TODO: Why?)
globals.enableOutputs = true;
PRDriverUpdateGlobalConfig(proc, &globals);
// Configure the groups:
PRDriverGroupConfig group;
for (i = 0; i < 6; i++)
{
PRDriverGetGroupConfig(proc, i + 4, &group);
group.slowTime = 0;
group.enableIndex = i;
group.rowActivateIndex = i;
group.rowEnableSelect = 0;
group.matrixed = false;
group.polarity = false;
group.active = 1;
group.disableStrobeAfter = false;
PRDriverUpdateGroupConfig(proc, &group);
}
for (i = 6; i < 14; i++) {
PRDriverGetGroupConfig(proc, i + 4, &group);
group.slowTime = 400;
group.enableIndex = 7;
group.rowActivateIndex = i - 6;
group.rowEnableSelect = 0;
group.matrixed = 1;
group.polarity = 0;
group.active = 1;
group.disableStrobeAfter = 1;
PRDriverUpdateGroupConfig(proc, &group);
}
}
void ConfigureSwitches(PRHandle proc)
{
int i;
// Create a basic driver for all of the switches to default to:
PRDriverState defaultDriver;
memset(&defaultDriver, 0x0, sizeof(defaultDriver)); // Set all fields to 0.
for (i = 0; i <= kPRSwitchPhysicalLast; i++)
{
PRSwitchRule sw;
sw.switchNum = i;
sw.notifyHost = true;
sw.changeOutput = false;
sw.linkActive = false;
sw.linkAddress = 0;
sw.eventType = kPREventTypeSwitchClosedDebounced;
sw.driver = defaultDriver;
PRSwitchesUpdateRules(proc, &sw, 1);
sw.eventType = kPREventTypeSwitchOpenDebounced;
PRSwitchesUpdateRules(proc, &sw, 1);
}
}
bool runLoopRun = true;
void RunLoop(PRHandle proc)
{
const int maxEvents = 16;
PREvent events[maxEvents];
while (runLoopRun)
{
int numEvents = PRGetEvents(proc, events, maxEvents);
for (int i = 0; i < numEvents; i++)
{
PREvent *event = &events[i];
const char *stateText = "Unknown";
switch (event->type)
{
case kPREventTypeSwitchOpenDebounced: stateText = "open"; break;
case kPREventTypeSwitchClosedDebounced: stateText = "closed"; break;
case kPREventTypeSwitchOpenNondebounced: stateText = "open(ndb)"; break;
case kPREventTypeSwitchClosedNondebounced: stateText = "closed(ndb)"; break;
}
printf("switch % 3d: %s\n", event->value, stateText);
}
usleep(10*1000); // Sleep for 10ms so we aren't pegging the CPU.
}
}
void sigint(int)
{
runLoopRun = false;
signal(SIGINT, SIG_DFL); // Re-install the default signal handler.
printf("Exiting...\n");
}
int main(const char **argv, int argc)
{
// Set a signal handler so that we can exit gracefully on Ctrl-C:
signal(SIGINT, sigint);
// Assign a custom logging callback to demonstrate capturing log information from P-ROC:
PRLogSetCallback(TestLogger);
// Finally instantiate the P-ROC device:
PRHandle proc = PRCreate(kPRMachineWPC);
if (proc == kPRHandleInvalid)
return 1;
printf("Configuring P-ROC...\n");
ConfigureDrivers(proc);
ConfigureSwitches(proc);
printf("Running. Hit Ctrl-C to exit.\n");
// Pulse a coil to test:
// PRDriverDisable(proc, 80);
// PRDriverPulse(proc, 53, 100);
RunLoop(proc);
// Destroy the P-ROC device handle:
PRDelete(proc);
proc = kPRHandleInvalid;
return 0;
}

225
include/pinproc.h Normal file
View File

@@ -0,0 +1,225 @@
/*
* The MIT License
* Copyright (c) 2009 Gerry Stellenberg, Adam Preble
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/** @file pinproc.h
* @brief libpinproc, P-ROC Layer 1 API (Preliminary)
*
*/
#ifndef _PINPROC_H_
#define _PINPROC_H_
#include <stdint.h>
/** @cond */
#if defined(__WIN32__)
#undef PR_EXPORT
#if defined(PR_BUILDING_PR)
#define PR_EXPORT __declspec(dllexport) extern
#else
#define PR_EXPORT __declspec(dllimport) extern
#endif
#endif
#if !defined(PR_EXPORT)
#define PR_EXPORT extern
#endif
#if !defined(PR_EXTERN_C_BEGIN)
#if defined(__cplusplus)
#define PR_EXTERN_C_BEGIN extern "C" {
#define PR_EXTERN_C_END }
#else
#define PR_EXTERN_C_BEGIN
#define PR_EXTERN_C_END
#endif
#endif
/** @endcond */
/** @cond */
PR_EXTERN_C_BEGIN
/** @endcond */
// Types
typedef int32_t bool_t; // FIXME: This needs better platform independence.
typedef int32_t PRResult; /**< See: #kPRSuccess and #kPRFailure. */
#define kPRSuccess (1) /**< Success value for #PRResult. */
#define kPRFailure (0) /**< Failure value for #PRResult. */
typedef void * PRHandle; /**< Opaque type used to reference an individual P-ROC device. Created with PRCreate() and destroyed with PRDelete(). This value is used as the first parameter to all P-ROC API function calls. */
#define kPRHandleInvalid (0) /**< Value returned by PRCreate() on failure. Indicates an invalid #PRHandle. */
typedef void (*PRLogCallback)(const char *text); /**< Function pointer type for a custom logging callback. See: PRLogSetCallback(). */
PR_EXPORT void PRLogSetCallback(PRLogCallback callback); /**< Replaces the default logging handler with the given callback function. */
typedef enum PRMachineType {
kPRMachineInvalid = 0,
kPRMachineCustom = 1,
kPRMachineWPC = 2,
kPRMachineStern = 3, // May be split into kPRMachineWhitestar and kPRMachineSAM.
} PRMachineType;
// PRHandle Creation and Deletion
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. */
// Events
// Closed == 0, Open == 1
typedef enum PREventType {
kPREventTypeInvalid = 0,
kPREventTypeSwitchClosedDebounced = 1, /**< The switch has gone from open to closed and the signal has been debounced. */
kPREventTypeSwitchOpenDebounced = 2, /**< The switch has gone from closed to open and the signal has been debounced. */
kPREventTypeSwitchClosedNondebounced = 3, /**< The switch has gone from open to closed and the signal has not been debounced. */
kPREventTypeSwitchOpenNondebounced = 4, /**< The switch has gone from closed to open and the signal has not been debounced. */
kPREventTypetLast = kPREventTypeSwitchOpenNondebounced
} PREventType;
typedef struct PREvent {
PREventType type; /**< The type of event that has occurred. Usually a switch event at this point. */
uint32_t value; /**< For switch events, the switch number that has changed. */
uint32_t time; /**< Time (in milliseconds) that this event occurred. */
} PREvent;
/** Get all of the available events that have been received. */
PR_EXPORT int PRGetEvents(PRHandle handle, PREvent *eventsOut, int maxEvents);
// Drivers
typedef struct PRDriverGlobalConfig {
bool_t enableOutputs; // Formerly enable_direct_outputs
bool_t globalPolarity;
bool_t useClear;
bool_t strobeStartSelect;
uint8_t startStrobeTime;
uint8_t matrixRowEnableIndex1;
uint8_t matrixRowEnableIndex0;
bool_t activeLowMatrixRows;
bool_t encodeEnables;
bool_t tickleWatchdog;
} PRDriverGlobalConfig;
typedef struct PRDriverGroupConfig {
uint8_t groupNum;
uint16_t slowTime;
uint8_t enableIndex;
uint8_t rowActivateIndex;
uint8_t rowEnableSelect;
bool_t matrixed;
bool_t polarity;
bool_t active;
bool_t disableStrobeAfter;
} PRDriverGroupConfig;
typedef struct PRDriverState {
uint16_t driverNum;
uint32_t outputDriveTime;
bool_t polarity;
bool_t state;
bool_t waitForFirstTimeSlot;
uint32_t timeslots;
uint8_t patterOnTime;
uint8_t patterOffTime;
bool_t patterEnable;
} PRDriverState;
/** Update registers for the global driver configuration. */
PR_EXPORT PRResult PRDriverUpdateGlobalConfig(PRHandle handle, PRDriverGlobalConfig *driverGlobalConfig);
PR_EXPORT PRResult PRDriverGetGroupConfig(PRHandle handle, uint8_t groupNum, PRDriverGroupConfig *driverGroupConfig);
/** Update registers for the given driver group configuration. */
PR_EXPORT PRResult PRDriverUpdateGroupConfig(PRHandle handle, PRDriverGroupConfig *driverGroupConfig);
PR_EXPORT PRResult PRDriverGetState(PRHandle handle, uint8_t driverNum, PRDriverState *driverState);
/** Sets the state of the given driver (lamp, coil, etc.). */
PR_EXPORT PRResult PRDriverUpdateState(PRHandle handle, PRDriverState *driverState);
// Driver Helper functions:
/** Disables (turns off) the given driver. */
PR_EXPORT PRResult PRDriverDisable(PRHandle handle, uint16_t driverNum);
/** Pulses the given driver for a number of milliseconds. */
PR_EXPORT PRResult PRDriverPulse(PRHandle handle, uint16_t driverNum, int milliseconds);
/** Assigns a repeating schedule to the given driver. */
PR_EXPORT PRResult PRDriverSchedule(PRHandle handle, uint16_t driverNum, uint32_t schedule, uint8_t cycleSeconds, bool_t now);
PR_EXPORT PRResult PRDriverPatter(PRHandle handle, uint16_t driverNum, uint16_t millisecondsOn, uint16_t millisecondsOff, uint16_t originalOnTime);
// Switches
/** @defgroup switchconsts Switch Constants
* @{
*/
#define kPRSwitchPhysicalFirst (0) /**< Switch number of the first physical switch. */
#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. */
/** @} */
typedef struct PRSwitchRule {
uint16_t switchNum; /**< Number of the physical switch, or for linked driver changes the virtual switch number (224 and up). */
PREventType eventType; /**< The event type that this rule generates. Determines closed/open, debounced/non-debounced. */
bool_t notifyHost;
bool_t changeOutput; /**< True if this switch rule should affect a driver output change. */
bool_t linkActive; /**< True if this switch rule has additional linked driver updates. */
uint32_t linkAddress; /**< Switch number of the linked driver update. */
PRDriverState driver; /**< Driver state change to affect once this rule is triggered. */
} PRSwitchRule;
/** Updates the rules for the given switch and PREventType combinations. */
PR_EXPORT PRResult PRSwitchesUpdateRules(PRHandle handle, PRSwitchRule *rules, int numRules);
// DMD
typedef struct PRDMDGlobalConfig {
uint8_t numRows;
uint16_t numColumns;
uint8_t numSubFrames;
uint16_t cyclesPerRow;
bool_t enable;
uint8_t rclkLowCycles[8];
uint8_t latchHighCycles[8];
uint16_t deHighCycles[8];
uint8_t dotclkHalfPeriod[8];
} PRDMDConfig;
/** Sets the configuration registers for the DMD driver. */
PR_EXPORT int32_t PRDMDUpdateGlobalConfig(PRHandle handle, PRDMDGlobalConfig *dmdGlobalConfig);
/** Updates the DMD frame buffer with the given data. */
PR_EXPORT PRResult PRDMDDraw(PRHandle handle, uint8_t * dots, uint16_t columns, uint8_t rows, uint8_t numSubFrames);
/** @cond */
PR_EXTERN_C_END
/** @endcond */
#endif // _PINPROC_H_

View File

@@ -0,0 +1,333 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 45;
objects = {
/* Begin PBXBuildFile section */
6682492C0FC079050051560E /* pinproc.h in Headers */ = {isa = PBXBuildFile; fileRef = 6682492B0FC079050051560E /* pinproc.h */; };
6682493A0FC07B2A0051560E /* pinproc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 668249390FC07B2A0051560E /* pinproc.cpp */; };
668249420FC07D900051560E /* PRDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 668249400FC07D900051560E /* PRDevice.h */; };
668249430FC07D900051560E /* PRDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 668249410FC07D900051560E /* PRDevice.cpp */; };
6682494B0FC0870B0051560E /* PRHardware.h in Headers */ = {isa = PBXBuildFile; fileRef = 6682494A0FC0870B0051560E /* PRHardware.h */; };
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 */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
668249E40FC0A3C40051560E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
proxyType = 1;
remoteGlobalIDString = D2AAC045055464E500DB518D;
remoteInfo = libpinproc;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
6682492B0FC079050051560E /* pinproc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pinproc.h; path = include/pinproc.h; sourceTree = "<group>"; };
668249390FC07B2A0051560E /* pinproc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = pinproc.cpp; path = src/pinproc.cpp; sourceTree = "<group>"; };
668249400FC07D900051560E /* PRDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PRDevice.h; path = src/PRDevice.h; sourceTree = "<group>"; };
668249410FC07D900051560E /* PRDevice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PRDevice.cpp; path = src/PRDevice.cpp; sourceTree = "<group>"; };
6682494A0FC0870B0051560E /* PRHardware.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PRHardware.h; path = src/PRHardware.h; sourceTree = "<group>"; };
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>"; };
D2AAC046055464E500DB518D /* libpinproc.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libpinproc.a; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
668249D70FC0A30A0051560E /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
668249EA0FC0A4280051560E /* libpinproc.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D289987405E68DCB004EDB86 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
08FB7794FE84155DC02AAC07 /* libpinproc */ = {
isa = PBXGroup;
children = (
08FB7795FE84155DC02AAC07 /* Source */,
C6A0FF2B0290797F04C91782 /* Documentation */,
1AB674ADFE9D54B511CA2CBB /* Products */,
);
name = libpinproc;
sourceTree = "<group>";
};
08FB7795FE84155DC02AAC07 /* Source */ = {
isa = PBXGroup;
children = (
668249D30FC0A2C10051560E /* pinproctest */,
668249D20FC0A29E0051560E /* libpinproc */,
);
name = Source;
sourceTree = "<group>";
};
1AB674ADFE9D54B511CA2CBB /* Products */ = {
isa = PBXGroup;
children = (
D2AAC046055464E500DB518D /* libpinproc.a */,
668249D90FC0A30A0051560E /* pinproctest */,
);
name = Products;
sourceTree = "<group>";
};
668249D20FC0A29E0051560E /* libpinproc */ = {
isa = PBXGroup;
children = (
6682492B0FC079050051560E /* pinproc.h */,
668249390FC07B2A0051560E /* pinproc.cpp */,
668249400FC07D900051560E /* PRDevice.h */,
668249410FC07D900051560E /* PRDevice.cpp */,
6682494A0FC0870B0051560E /* PRHardware.h */,
668249EC0FC0A4CD0051560E /* PRHardware.cpp */,
);
name = libpinproc;
sourceTree = "<group>";
};
668249D30FC0A2C10051560E /* pinproctest */ = {
isa = PBXGroup;
children = (
668249E20FC0A3960051560E /* pinproctest.cpp */,
);
name = pinproctest;
sourceTree = "<group>";
};
C6A0FF2B0290797F04C91782 /* Documentation */ = {
isa = PBXGroup;
children = (
);
name = Documentation;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
D2AAC043055464E500DB518D /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
6682492C0FC079050051560E /* pinproc.h in Headers */,
668249420FC07D900051560E /* PRDevice.h in Headers */,
6682494B0FC0870B0051560E /* PRHardware.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
668249D80FC0A30A0051560E /* pinproctest */ = {
isa = PBXNativeTarget;
buildConfigurationList = 668249DD0FC0A32A0051560E /* Build configuration list for PBXNativeTarget "pinproctest" */;
buildPhases = (
668249D60FC0A30A0051560E /* Sources */,
668249D70FC0A30A0051560E /* Frameworks */,
);
buildRules = (
);
dependencies = (
668249E50FC0A3C40051560E /* PBXTargetDependency */,
);
name = pinproctest;
productName = pinproctest;
productReference = 668249D90FC0A30A0051560E /* pinproctest */;
productType = "com.apple.product-type.tool";
};
D2AAC045055464E500DB518D /* libpinproc */ = {
isa = PBXNativeTarget;
buildConfigurationList = 1DEB91EB08733DB70010E9CD /* Build configuration list for PBXNativeTarget "libpinproc" */;
buildPhases = (
D2AAC043055464E500DB518D /* Headers */,
D2AAC044055464E500DB518D /* Sources */,
D289987405E68DCB004EDB86 /* Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = libpinproc;
productName = libpinproc;
productReference = D2AAC046055464E500DB518D /* libpinproc.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
08FB7793FE84155DC02AAC07 /* Project object */ = {
isa = PBXProject;
buildConfigurationList = 1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "libpinproc" */;
compatibilityVersion = "Xcode 3.1";
hasScannedForEncodings = 1;
mainGroup = 08FB7794FE84155DC02AAC07 /* libpinproc */;
projectDirPath = "";
projectRoot = "";
targets = (
D2AAC045055464E500DB518D /* libpinproc */,
668249D80FC0A30A0051560E /* pinproctest */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
668249D60FC0A30A0051560E /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
668249E30FC0A3960051560E /* pinproctest.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D2AAC044055464E500DB518D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
6682493A0FC07B2A0051560E /* pinproc.cpp in Sources */,
668249430FC07D900051560E /* PRDevice.cpp in Sources */,
668249ED0FC0A4CD0051560E /* PRHardware.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
668249E50FC0A3C40051560E /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = D2AAC045055464E500DB518D /* libpinproc */;
targetProxy = 668249E40FC0A3C40051560E /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
1DEB91EC08733DB70010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_FIX_AND_CONTINUE = YES;
GCC_MODEL_TUNING = G5;
GCC_OPTIMIZATION_LEVEL = 0;
HEADER_SEARCH_PATHS = /usr/local/include;
INSTALL_PATH = /usr/local/lib;
PRODUCT_NAME = pinproc;
};
name = Debug;
};
1DEB91ED08733DB70010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_MODEL_TUNING = G5;
HEADER_SEARCH_PATHS = /usr/local/include;
INSTALL_PATH = /usr/local/lib;
PRODUCT_NAME = pinproc;
};
name = Release;
};
1DEB91F008733DB70010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
GCC_C_LANGUAGE_STANDARD = c99;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
ONLY_ACTIVE_ARCH = YES;
PREBINDING = NO;
SDKROOT = macosx10.5;
};
name = Debug;
};
1DEB91F108733DB70010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
GCC_C_LANGUAGE_STANDARD = c99;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
PREBINDING = NO;
SDKROOT = macosx10.5;
};
name = Release;
};
668249DB0FC0A30A0051560E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_FIX_AND_CONTINUE = YES;
GCC_MODEL_TUNING = G5;
GCC_OPTIMIZATION_LEVEL = 0;
INSTALL_PATH = /usr/local/bin;
OTHER_LDFLAGS = "-lftdi";
PREBINDING = NO;
PRODUCT_NAME = pinproctest;
};
name = Debug;
};
668249DC0FC0A30A0051560E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_MODEL_TUNING = G5;
INSTALL_PATH = /usr/local/bin;
OTHER_LDFLAGS = "-lftdi";
PREBINDING = NO;
PRODUCT_NAME = pinproctest;
ZERO_LINK = NO;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
1DEB91EB08733DB70010E9CD /* Build configuration list for PBXNativeTarget "libpinproc" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1DEB91EC08733DB70010E9CD /* Debug */,
1DEB91ED08733DB70010E9CD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "libpinproc" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1DEB91F008733DB70010E9CD /* Debug */,
1DEB91F108733DB70010E9CD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
668249DD0FC0A32A0051560E /* Build configuration list for PBXNativeTarget "pinproctest" */ = {
isa = XCConfigurationList;
buildConfigurations = (
668249DB0FC0A30A0051560E /* Debug */,
668249DC0FC0A30A0051560E /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
}

652
src/PRDevice.cpp Normal file
View File

@@ -0,0 +1,652 @@
/*
* The MIT License
* Copyright (c) 2009 Gerry Stellenberg, Adam Preble
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* PRDevice.cpp
* libpinproc
*/
#include "PRDevice.h"
PRDevice::PRDevice(PRMachineType machineType) : machineType(machineType), ftdiInitialized(false)
{
Reset();
}
PRDevice::~PRDevice()
{
Close();
}
PRDevice* PRDevice::Create(PRMachineType machineType)
{
PRDevice *dev = new PRDevice(machineType);
if (dev == NULL)
{
DEBUG(PRLog("Error allocating memory for P-ROC device\n"));
return NULL;
}
if (!dev->Open())
{
DEBUG(PRLog("Error opening P-ROC device.\n"));
delete dev;
return NULL;
}
dev->Reset();
return dev;
}
void PRDevice::Reset()
{
bool defaultPolarity = machineType != kPRMachineWPC;
int i;
memset(&driverGlobalConfig, 0x00, sizeof(PRDriverGlobalConfig));
for (i = 0; i < maxDrivers; i++)
{
PRDriverState *driver = &drivers[i];
memset(driver, 0x00, sizeof(PRDriverState));
driver->driverNum = i;
driver->polarity = defaultPolarity;
}
for (i = 0; i < maxDriverGroups; i++)
{
PRDriverGroupConfig *group = &driverGroups[i];
memset(group, 0x00, sizeof(PRDriverGroupConfig));
group->groupNum = i;
group->polarity = defaultPolarity;
}
for (i = 0; i < maxSwitchRules; i++)
{
PRSwitchRule *switchRule = &switchRules[i];
memset(switchRule, 0x00, sizeof(PRSwitchRule));
switchRule->switchNum = i;
switchRule->driver.polarity = defaultPolarity;
}
unrequestedDataQueue.empty();
requestedDataQueue.empty();
num_collected_bytes = 0;
// TODO: Assign defaults based on machineType. Some may have already been done above.
}
int PRDevice::GetEvents(PREvent *events, int maxEvents)
{
SortReturningData();
// The unrequestedDataQueue only has unrequested switch event data. Pop
// events out 1 at a time, interpret them, and populate the outgoing list with them.
int i;
for (i = 0; (i < maxEvents) && !unrequestedDataQueue.empty(); i++)
{
uint32_t event_data = unrequestedDataQueue.front();
unrequestedDataQueue.pop();
events[i].value = event_data & P_ROC_EVENT_SWITCH_NUM_MASK;
bool open = (event_data & P_ROC_EVENT_SWITCH_STATE_MASK) >> P_ROC_EVENT_SWITCH_STATE_SHIFT;
bool debounced = (event_data & P_ROC_EVENT_SWITCH_DEBOUNCED_MASK) >> P_ROC_EVENT_SWITCH_DEBOUNCED_SHIFT;
if (open)
events[i].type = debounced ? kPREventTypeSwitchOpenDebounced : kPREventTypeSwitchOpenNondebounced;
else
events[i].type = debounced ? kPREventTypeSwitchClosedDebounced : kPREventTypeSwitchOpenNondebounced;
}
return i;
}
PRResult PRDevice::DriverUpdateGlobalConfig(PRDriverGlobalConfig *driverGlobalConfig)
{
const int burstWords = 2;
uint32_t burst[burstWords];
int32_t rc;
DEBUG(PRLog("Installing driver globals\n"));
this->driverGlobalConfig = *driverGlobalConfig;
rc = CreateDriverUpdateGlobalConfigBurst(burst, driverGlobalConfig);
DEBUG(PRLog("Words: %x %x\n", burst[0], burst[1]));
return WriteData(burst, burstWords);
}
PRResult PRDevice::DriverGetGroupConfig(uint8_t groupNum, PRDriverGroupConfig *driverGroupConfig)
{
*driverGroupConfig = driverGroups[groupNum];
return kPRSuccess;
}
PRResult PRDevice::DriverUpdateGroupConfig(PRDriverGroupConfig *driverGroupConfig)
{
const int burstWords = 2;
uint32_t burst[burstWords];
int32_t rc;
driverGroups[driverGroupConfig->groupNum] = *driverGroupConfig;
DEBUG(PRLog("Installing driver group\n"));
rc = CreateDriverUpdateGroupConfigBurst(burst, driverGroupConfig);
DEBUG(PRLog("Words: %x %x\n", burst[0], burst[1]));
return WriteData(burst, burstWords);
}
PRResult PRDevice::DriverGetState(uint8_t driverNum, PRDriverState *driverState)
{
*driverState = drivers[driverNum];
return kPRSuccess;
}
PRResult PRDevice::DriverUpdateState(PRDriverState *driverState)
{
const int burstWords = 3;
uint32_t burst[burstWords];
int32_t rc;
DEBUG(PRLog("Updating driver #%d\n", driverState->driverNum));
if (driverState->polarity != drivers[driverState->driverNum].polarity && machineType != kPRMachineCustom)
{
DEBUG(PRLog("Refusing to update driver #%d; polarity differs on non-custom machine.\n", driverState->driverNum));
return kPRFailure;
}
drivers[driverState->driverNum] = *driverState;
rc = CreateDriverUpdateBurst(burst, &drivers[driverState->driverNum]);
DEBUG(PRLog("Words: %x %x %x\n", burst[0], burst[1], burst[2]));
return WriteData(burst, burstWords);
}
PRResult PRDevice::DriverDisable(uint16_t driverNum)
{
PRDriverState driver;
DriverGetState(driverNum, &driver);
driver.state = 0;
driver.timeslots = 0;
driver.waitForFirstTimeSlot = false;
driver.outputDriveTime = 0;
driver.patterOnTime = 0;
driver.patterOffTime = 0;
driver.patterEnable = false;
return DriverUpdateState(&driver);
}
PRResult PRDevice::DriverPulse(uint16_t driverNum, int milliseconds)
{
PRDriverState driver;
DriverGetState(driverNum, &driver);
driver.state = 1;
driver.timeslots = 0;
driver.waitForFirstTimeSlot = false;
driver.outputDriveTime = milliseconds;
driver.patterOnTime = 0;
driver.patterOffTime = 0;
driver.patterEnable = false;
return DriverUpdateState(&driver);
}
PRResult PRDevice::DriverSchedule(uint16_t driverNum, uint32_t schedule, uint8_t cycleSeconds, bool now)
{
PRDriverState driver;
DriverGetState(driverNum, &driver);
driver.state = 1;
driver.timeslots = schedule;
driver.waitForFirstTimeSlot = !now;
driver.outputDriveTime = cycleSeconds;
driver.patterOnTime = 0;
driver.patterOffTime = 0;
driver.patterEnable = false;
return DriverUpdateState(&driver);
}
PRResult PRDevice::DriverPatter(uint16_t driverNum, uint16_t millisecondsOn, uint16_t millisecondsOff, uint16_t originalOnTime)
{
PRDriverState driver;
DriverGetState(driverNum, &driver);
driver.state = originalOnTime != 0;
driver.timeslots = 0;
driver.waitForFirstTimeSlot = false;
driver.outputDriveTime = originalOnTime;
driver.patterOnTime = millisecondsOn;
driver.patterOffTime = millisecondsOff;
driver.patterEnable = true;
return DriverUpdateState(&driver);
}
PRResult PRDevice::SwitchesUpdateRules(PRSwitchRule *rules, int numRules)
{
int32_t i,rc;
DEBUG(PRLog("SwitchesUpdateRules: numRules: %d\n", numRules));
// Iterate through the array of rules, install each in the P-ROC
for (i=0; i < numRules; i++) {
uint16_t switchNum = rules[i].switchNum;
switchRules[switchNum] = rules[i];
PRSwitchRule *rule = &switchRules[switchNum];
PRSwitchRule *nextRule = NULL;
// See if this is the last item. If not, need to add a link to the current item
if (i != numRules - 1) {
nextRule = &rules[i+1];
// Link address is the switch number assigned to the next rule as that's where
// the next rule will be installed
rule->linkAddress = nextRule->switchNum;
rule->linkActive = true;
}
else {
rule->linkActive = false;
rule->linkAddress = 0;
}
DEBUG(PRLog("Installing switch rule: switchNum: %d, eventType: %d\n link: %d, link address: %d\n",
rule->switchNum, rule->eventType, rule->linkActive, rule->linkAddress));
uint32_t rule_burst[4];
rc = CreateSwitchesUpdateRulesBurst (rule_burst, rule);
DEBUG(PRLog("words: %d:%d:%d:%d\n", rule_burst[0], rule_burst[1], rule_burst[2], rule_burst[3]));
rc = WriteData(rule_burst, 4);
}
return rc;
}
int32_t PRDevice::DMDUpdateGlobalConfig(PRDMDGlobalConfig *dmdGlobalConfig)
{
uint32_t rc;
uint32_t burst[10];
CreateDMDUpdateGlobalConfigBurst(burst, dmdGlobalConfig);
DEBUG(PRLog("DMD config packet: "));
for (int i=0; i<10; i++) {
DEBUG(PRLog("%d ", burst[i]));
}
DEBUG(PRLog("\n"));
rc = WriteData(burst, 9);
return rc;
}
PRResult PRDevice::DMDDraw(uint8_t * dots, uint16_t columns, uint8_t rows, uint8_t numSubFrames)
{
int32_t k; //i,x,y,j,k,m;
//uint8_t color;
uint16_t words_per_sub_frame = (columns*rows) / 32;
uint16_t words_per_frame = words_per_sub_frame * numSubFrames;
uint32_t dmd_command_buffer[1024];
uint32_t * p_dmd_frame_buffer_words;
p_dmd_frame_buffer_words = (uint32_t *)dots;
dmd_command_buffer[0] = CreateBurstCommand(P_ROC_BUS_DMD_SELECT, P_ROC_DMD_DOT_TABLE_BASE_ADDR, words_per_frame);
for (k=0; k<words_per_frame; k++) {
dmd_command_buffer[k+1] = p_dmd_frame_buffer_words[k];
}
return WriteData(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.
//if (print_dots) {
//print_dots = false;
//for (i=0; i<4; i++) {
// std::cout << "For memory: "<< i << "\n";
// // Need 4 lines to get 1 frame (4*256*4 = 4096)
// // The rest will be all 0.
// for (y=0; y<4; y++) {
// std::cout << "defparam blockram.INIT_00 = 256'b";
// for (j=31; j>=0; j--) {
// for (x=7; x>=0; x--) {
// std::cout << ((dmd_frame_buffer[(y*32)+j] >> ((i*8)+x)) & 1);
// }
// }
// std::cout << ";\n";
// }
// std::cout << "\n\n\n";
//}
//}
}
/////////////////////////////////////////////////////////////////////////////////////////////
// Device I/O
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)
{
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
// 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;
}
}
}
if (rc == kPRSuccess)
ftdiInitialized = true;
return rc;
}
PRResult PRDevice::Close()
{
// TODO: Add protection against closing a not-open ftdic.
if (ftdiInitialized)
{
ftdi_usb_close(&ftdic);
ftdi_deinit(&ftdic);
}
return kPRSuccess;
}
PRResult PRDevice::VerifyChipID()
{
PRResult rc;
const int bufferWords = 5;
uint32_t buffer[bufferWords];
//uint32_t temp_word;
uint32_t max_count;
//std::cout << "Requesting FPGA Chip ID: ";
rc = RequestData(P_ROC_MANAGER_SELECT, P_ROC_REG_CHIP_ID_ADDR, 4);
max_count = 0;
//std::cout << "Waiting for read data ";
while (num_collected_bytes < (bufferWords*4) && max_count < 10) {
sleep(.01);
//std::cout << ". ";
rc = CollectReadData();
max_count++;
}
//std::cout << "\n";
if (max_count != 10) {
int wordsRead = ReadData(buffer, bufferWords);
if (wordsRead == 5) {
//std::cout << rc << " words read. \n"
DEBUG(PRLog("FPGA Chip ID: 0x%x\n", buffer[1]));
DEBUG(PRLog("FPGA Chip Version/Rev: %d.%d\n", buffer[2] >> 16, buffer[2] & 0xffff));
DEBUG(PRLog("Watchdog Settings: 0x%x\n", buffer[3]));
DEBUG(PRLog("Switches: 0x%x\n", buffer[4]));
rc = kPRSuccess;
}
else {
DEBUG(PRLog("Error reading Chip IP and Version. Incorrect number of bytes received from read_data().\n"));
rc = kPRFailure;
}
}
else {
DEBUG(PRLog("Unable to read Chip ID - P-ROC not yet initialized.\n"));
rc = kPRFailure;
}
return (rc);
}
PRResult PRDevice::RequestData(uint32_t module_select, uint32_t start_addr, int32_t num_words)
{
uint32_t requestWord = CreateRegRequestWord(module_select, start_addr, num_words);
return WriteData(&requestWord, 1);
}
PRResult PRDevice::WriteData(uint32_t * words, int32_t numWords)
{
int32_t j,k;
// int32_t item;
if (numWords == 0)
return kPRSuccess;
// The 32-bit words coming in are in the same byte order they need to be in the P-ROC.
// However, due to Intel endian-ness, simply casting the words to 4 bytes changes the
// byte order. So, the conversion to bytes is done here manually to preserve the byte
// order. Might want to add a parameter for endian-ness at some point to make it
// work on big endian architectures.
for (j = 0; j < numWords; j++) {
uint32_t temp_word = words[j];
for (k = 3; k >= 0; k--)
{
wr_buffer[(j*4)+k] = (uint8_t)(temp_word & 0x000000ff);
temp_word = temp_word >> 8;
}
// for (k=0; k<4; k++)
// {
// item = wr_buffer[(j*4)+k];
// }
}
int bytesToWrite = numWords * 4;
int bytesWritten = (int32_t)ftdi_write_data(&ftdic, wr_buffer, bytesToWrite);
if (bytesWritten != bytesToWrite)
{
DEBUG(PRLog("Error in WriteData: wrote %d of %d bytes\n", bytesWritten, bytesToWrite));
return kPRFailure;
}
else
{
return kPRSuccess;
}
}
int32_t PRDevice::ReadData(uint32_t *buffer, int32_t num_words)
{
int32_t rc,i,j;
// Just like in the write_data method, the bytes are ordered here manually to put
// them in the right order. They are pulled from the collected_bytes_fifo 1 at a time
// and stuffed into 32-bit words, high byte to low byte.
if ((num_words * 4) <= num_collected_bytes) {
for (j=0; j<num_words; j++) {
// Initialize buffer position
buffer[j] = 0;
for (i=0; i<4; i++) {
buffer[j] = (collected_bytes_fifo[collected_bytes_rd_addr] << (24-(i*8))) |
buffer[j];
if (collected_bytes_rd_addr == (FTDI_BUFFER_SIZE-1))
collected_bytes_rd_addr = 0;
else
collected_bytes_rd_addr++;
}
}
num_collected_bytes -= (num_words * 4);
rc = num_words;
}
else {
rc = 0;
}
DEBUG(PRLog("Read num bytes: %d\n", rc));
return (rc);
}
PRResult PRDevice::FlushReadBuffer()
{
int32_t numBytes,rc,k;
uint32_t rd_buffer[3];
numBytes = CollectReadData();
k = 0;
//std::cout << "Flushing rd buffer of " << num_words << "words\n";
while (k < numBytes) {
rc = ReadData(rd_buffer, 1);
k++;
}
return rc;
}
int32_t PRDevice::CollectReadData()
{
int32_t rc,i;
rc = ftdi_read_data(&ftdic, 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))
collected_bytes_wr_addr = 0;
else
collected_bytes_wr_addr++;
}
num_collected_bytes += rc;
if (rc > 0)
{
DEBUG(PRLog("Collected bytes: %d\n", rc));
}
return (rc);
}
PRResult PRDevice::SortReturningData()
{
uint32_t num_bytes, num_words, rc;
uint32_t rd_buffer[512];
num_bytes = CollectReadData();
num_words = num_collected_bytes/4;
while (num_words >= 2) {
rc = ReadData(rd_buffer, 1);
DEBUG(PRLog("New returning word: 0x%x\n", rd_buffer[0]));
switch ( (rd_buffer[0] & P_ROC_COMMAND_MASK) >> P_ROC_COMMAND_SHIFT)
{
// Must be a bug in the P-ROC. Unrequested packets are returning looking
// like requested packets. Commenting out requested packets for now.
case P_ROC_REQUESTED_DATA: {
int bytesRead = ReadData(rd_buffer,
(rd_buffer[0] & P_ROC_HEADER_LENGTH_MASK) >>
P_ROC_HEADER_LENGTH_SHIFT);
for (int i = 0; i < bytesRead; i++)
requestedDataQueue.push(rd_buffer[i]);
break;
}
case P_ROC_UNREQUESTED_DATA: {
ReadData(rd_buffer,1);
DEBUG(PRLog("Pushing onto unreq Q 0x%x\n", rd_buffer[0]));
unrequestedDataQueue.push(rd_buffer[0]);
break;
}
}
num_words = num_collected_bytes/4;
}
return kPRSuccess;
}

143
src/PRDevice.h Normal file
View File

@@ -0,0 +1,143 @@
/*
* The MIT License
* Copyright (c) 2009 Gerry Stellenberg, Adam Preble
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* PRDevice.h
* libpinproc
*/
#include "../include/pinproc.h"
#include "PRHardware.h"
#include <queue>
#include <ftdi.h>
using namespace std;
#define maxDriverGroups (26)
#define maxDrivers (256)
#define maxSwitchRules (256)
#ifdef NDEBUG
# define DEBUG(block)
#else
# define DEBUG(block) block
#endif
extern void PRLog(const char *format, ...);
class PRDevice
{
public:
static PRDevice *Create(PRMachineType machineType);
~PRDevice();
protected:
PRDevice(PRMachineType machineType);
public:
// public libpinproc API:
int GetEvents(PREvent *events, int maxEvents);
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 DriverDisable(uint16_t driverNum);
PRResult DriverPulse(uint16_t driverNum, int milliseconds);
PRResult DriverSchedule(uint16_t driverNum, uint32_t schedule, uint8_t cycleSeconds, bool now);
PRResult DriverPatter(uint16_t driverNum, uint16_t millisecondsOn, uint16_t millisecondsOff, uint16_t originalOnTime);
PRResult SwitchesUpdateRules(PRSwitchRule *rules, int numRules);
PRResult DMDUpdateGlobalConfig(PRDMDGlobalConfig *dmdGlobalConfig);
PRResult DMDDraw(uint8_t * dots, uint16_t columns, uint8_t rows, uint8_t numSubFrames);
protected:
// Device I/O
PRResult Open();
PRResult Close();
PRResult VerifyChipID();
// Raw write and read methods
/** Writes data to P-ROC.
* Returns #kPFailure if the number of words read does not match the number requested.
*/
PRResult WriteData(uint32_t * buffer, int32_t numWords);
/**
* Reads data from the buffer that was previously collected by CollectReadData().
* Returns the number of bytes read.
*/
int32_t ReadData(uint32_t *buffer, int32_t maxWords);
// Collection of methods to get data returning from the P-ROC
/**
* Request a block of data from the P-ROC.
*/
PRResult RequestData(uint32_t module_select, uint32_t start_addr, int32_t num_words);
/**
* Actually reads the data off of the FTDI chip.
* This is called by SortReturningData() in order to get some data to process.
*/
int32_t CollectReadData();
/**
* Processes data into unrequestedDataQueue and requestedDataQueue.
* Calls CollectReadData() to obtain the data and then uses ReadData() to read it out.
*/
PRResult SortReturningData();
/**
* Empties out the read buffer.
* Calls CollectReadData() and then ReadData() until it's empty.
*/
PRResult FlushReadBuffer();
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;
uint8_t collected_bytes_fifo[FTDI_BUFFER_SIZE];
int32_t collected_bytes_rd_addr;
int32_t collected_bytes_wr_addr;
int32_t num_collected_bytes;
uint8_t wr_buffer[16384];
uint8_t collect_buffer[FTDI_BUFFER_SIZE];
// Local Device State
void Reset();
PRMachineType machineType;
PRDriverGlobalConfig driverGlobalConfig;
PRDriverGroupConfig driverGroups[maxDriverGroups];
PRDriverState drivers[maxDrivers];
PRSwitchRule switchRules[maxSwitchRules];
};

171
src/PRHardware.cpp Normal file
View File

@@ -0,0 +1,171 @@
/*
* The MIT License
* Copyright (c) 2009 Gerry Stellenberg, Adam Preble
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* PRHardware.cpp
* libpinproc
*/
#include "PRHardware.h"
uint32_t CreateRegRequestWord( uint32_t select, uint32_t addr, uint32_t num_words ) {
return ( (P_ROC_READ << P_ROC_COMMAND_SHIFT) |
(num_words << P_ROC_HEADER_LENGTH_SHIFT) |
(select << P_ROC_MODULE_SELECT_SHIFT) |
(addr << P_ROC_ADDR_SHIFT) );
};
uint32_t CreateBurstCommand ( uint32_t select, uint32_t addr, uint32_t num_words ) {
return ( (P_ROC_WRITE << P_ROC_COMMAND_SHIFT) |
(num_words << P_ROC_HEADER_LENGTH_SHIFT) |
(select << P_ROC_MODULE_SELECT_SHIFT) |
(addr << P_ROC_ADDR_SHIFT) );
}
int32_t CreateDriverUpdateGlobalConfigBurst ( uint32_t * burst, PRDriverGlobalConfig *driver_globals) {
uint32_t addr;
addr = 0;
addr = (P_ROC_DRIVER_CTRL_REG_DECODE << P_ROC_DRIVER_CTRL_DECODE_SHIFT);
burst[0] = CreateBurstCommand (P_ROC_BUS_DRIVER_CTRL_SELECT, addr, 1 );
burst[1] = ( (driver_globals->enableOutputs <<
P_ROC_DRIVER_GLOBAL_ENABLE_DIRECT_OUTPUTS_SHIFT) |
(driver_globals->globalPolarity <<
P_ROC_DRIVER_GLOBAL_GLOBAL_POLARITY_SHIFT) |
(driver_globals->useClear <<
P_ROC_DRIVER_GLOBAL_USE_CLEAR_SHIFT) |
(driver_globals->strobeStartSelect <<
P_ROC_DRIVER_GLOBAL_STROBE_START_SELECT_SHIFT) |
(driver_globals->startStrobeTime <<
P_ROC_DRIVER_GLOBAL_START_STROBE_TIME_SHIFT) |
(driver_globals->matrixRowEnableIndex1 <<
P_ROC_DRIVER_GLOBAL_MATRIX_ROW_ENABLE_INDEX_1_SHIFT) |
(driver_globals->matrixRowEnableIndex0 <<
P_ROC_DRIVER_GLOBAL_MATRIX_ROW_ENABLE_INDEX_0_SHIFT) |
(driver_globals->activeLowMatrixRows <<
P_ROC_DRIVER_GLOBAL_ACTIVE_LOW_MATRIX_ROWS_SHIFT) |
(driver_globals->encodeEnables <<
P_ROC_DRIVER_GLOBAL_ENCODE_ENABLES_SHIFT) |
(driver_globals->tickleWatchdog <<
P_ROC_DRIVER_GLOBAL_TICKLE_WATCHDOG_SHIFT) );
return kPRSuccess;
}
int32_t CreateDriverUpdateGroupConfigBurst ( uint32_t * burst, PRDriverGroupConfig *driver_group) {
uint32_t addr;
addr = 0;
addr = (P_ROC_DRIVER_CTRL_REG_DECODE << P_ROC_DRIVER_CTRL_DECODE_SHIFT) |
driver_group->groupNum;
burst[0] = CreateBurstCommand (P_ROC_BUS_DRIVER_CTRL_SELECT, addr, 1 );
burst[1] = ( (driver_group->slowTime <<
P_ROC_DRIVER_GROUP_SLOW_TIME_SHIFT) |
(driver_group->disableStrobeAfter <<
P_ROC_DRIVER_GROUP_DISABLE_STROBE_AFTER_SHIFT) |
(driver_group->enableIndex <<
P_ROC_DRIVER_GROUP_ENABLE_INDEX_SHIFT) |
(driver_group->rowActivateIndex <<
P_ROC_DRIVER_GROUP_ROW_ACTIVATE_INDEX_SHIFT) |
(driver_group->rowEnableSelect <<
P_ROC_DRIVER_GROUP_ROW_ENABLE_SELECT_SHIFT) |
(driver_group->matrixed <<
P_ROC_DRIVER_GROUP_MATRIXED_SHIFT) |
(driver_group->polarity <<
P_ROC_DRIVER_GROUP_POLARITY_SHIFT) |
(driver_group->active <<
P_ROC_DRIVER_GROUP_ACTIVE_SHIFT) );
return kPRSuccess;
}
int32_t CreateDriverUpdateBurst ( uint32_t * burst, PRDriverState *driver) {
uint32_t addr;
addr = 0;
addr = (P_ROC_DRIVER_CONFIG_TABLE_DECODE << P_ROC_DRIVER_CTRL_DECODE_SHIFT) |
(driver->driverNum << P_ROC_DRIVER_CONFIG_TABLE_DRIVER_NUM_SHIFT);
burst[0] = CreateBurstCommand (P_ROC_BUS_DRIVER_CTRL_SELECT, addr, 2 );
burst[1] = ( (driver->outputDriveTime << P_ROC_DRIVER_CONFIG_OUTPUT_DRIVE_TIME_SHIFT) |
(driver->polarity << P_ROC_DRIVER_CONFIG_POLARITY_SHIFT) |
(driver->state << P_ROC_DRIVER_CONFIG_STATE_SHIFT) |
(1 << P_ROC_DRIVER_CONFIG_UPDATE_SHIFT) |
(driver->waitForFirstTimeSlot << P_ROC_DRIVER_CONFIG_WAIT_4_1ST_SLOT_SHIFT) |
(driver->timeslots << P_ROC_DRIVER_CONFIG_TIMESLOT_SHIFT) );
burst[2] = (driver->timeslots >> P_ROC_DRIVER_CONFIG_TIMESLOT_SHIFT) |
(driver->patterOnTime << P_ROC_DRIVER_CONFIG_PATTER_ON_TIME_SHIFT) |
(driver->patterOffTime << P_ROC_DRIVER_CONFIG_PATTER_OFF_TIME_SHIFT) |
(driver->patterEnable << P_ROC_DRIVER_CONFIG_PATTER_ENABLE_SHIFT);
return kPRSuccess;
}
int32_t CreateSwitchesUpdateRulesBurst ( uint32_t * burst, PRSwitchRule *rule_record) {
uint32_t addr;
uint32_t driver_command[3];
CreateDriverUpdateBurst ( driver_command, &(rule_record->driver));
uint32_t debounce = (rule_record->eventType == kPREventTypeSwitchOpenDebounced) || (rule_record->eventType == kPREventTypeSwitchClosedDebounced) ? 1 : 0;
uint32_t state = (rule_record->eventType == kPREventTypeSwitchOpenDebounced) || (rule_record->eventType == kPREventTypeSwitchOpenNondebounced) ? 1 : 0;
addr = ( (debounce << P_ROC_SWITCH_RULE_ADDR_DEBOUNCE_SHIFT) |
(state << P_ROC_SWITCH_RULE_ADDR_STATE_SHIFT) |
(rule_record->switchNum << P_ROC_SWITCH_RULE_ADDR_SWITCH_NUM_SHIFT) );
burst[0] = CreateBurstCommand (P_ROC_BUS_STATE_CHANGE_PROC_SELECT, addr, 3 );
burst[1] = driver_command[1];
burst[2] = driver_command[2];
burst[3] = (rule_record->changeOutput << P_ROC_SWITCH_RULE_CHANGE_OUTPUT_SHIFT) |
(rule_record->driver.driverNum << P_ROC_SWITCH_RULE_DRIVER_NUM_SHIFT) |
(rule_record->linkActive << P_ROC_SWITCH_RULE_LINK_ACTIVE_SHIFT) |
(rule_record->linkAddress << P_ROC_SWITCH_RULE_LINK_ADDRESS_SHIFT) |
(rule_record->notifyHost << P_ROC_SWITCH_RULE_NOTIFY_HOST_SHIFT);
return kPRSuccess;
}
int32_t CreateDMDUpdateGlobalConfigBurst ( uint32_t * burst, PRDMDConfig *dmd_config)
{
uint32_t addr;
uint32_t i;
addr = 8;
burst[0] = CreateBurstCommand (P_ROC_BUS_DMD_SELECT, addr, 8 );
for (i=0; i<8; i++) {
burst[i+1] = 0;
burst[i+1] = (dmd_config->rclkLowCycles[i] << P_ROC_DMD_RCLK_LOW_CYCLES_SHIFT) |
(dmd_config->latchHighCycles[i] << P_ROC_DMD_LATCH_HIGH_CYCLES_SHIFT) |
(dmd_config->deHighCycles[i] << P_ROC_DMD_DE_HIGH_CYCLES_SHIFT) |
(dmd_config->dotclkHalfPeriod[i] << P_ROC_DMD_DOTCLK_HALF_PERIOD_SHIFT);
}
return kPRSuccess;
}

153
src/PRHardware.h Normal file
View File

@@ -0,0 +1,153 @@
/*
* The MIT License
* Copyright (c) 2009 Gerry Stellenberg, Adam Preble
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _PROC_HARDWARE_H_
#define _PROC_HARDWARE_H_
#include <stdint.h>
#include "../include/pinproc.h"
const int32_t FTDI_VENDOR_ID = 0x0403;
const int32_t FTDI_FT245RL_PRODUCT_ID = 0x6001;
const int32_t FTDI_BUFFER_SIZE = 2048;
const uint32_t P_ROC_INIT_PATTERN_A = 0x801F1122;
const uint32_t P_ROC_INIT_PATTERN_B = 0x345678AB;
const uint32_t P_ROC_CHIP_ID = 0xFEEDBEEF;
const uint32_t P_ROC_ADDR_MASK = 0x000FFFFF;
const uint32_t P_ROC_HEADER_LENGTH_MASK = 0x7FF00000;
const uint32_t P_ROC_COMMAND_MASK = 0x80000000;
const uint32_t P_ROC_ADDR_SHIFT = 0;
const uint32_t P_ROC_HEADER_LENGTH_SHIFT = 20;
const uint32_t P_ROC_COMMAND_SHIFT = 31;
const uint32_t P_ROC_READ = 0;
const uint32_t P_ROC_WRITE = 1;
const uint32_t P_ROC_REQUESTED_DATA = 0;
const uint32_t P_ROC_UNREQUESTED_DATA = 1;
const uint32_t P_ROC_REG_ADDR_MASK = 0x0000FFFF;
const uint32_t P_ROC_MODULE_SELECT_MASK = 0x000F0000;
const uint32_t P_ROC_REG_ADDR_SHIFT = 0;
const uint32_t P_ROC_MODULE_SELECT_SHIFT = 16;
const uint32_t P_ROC_MANAGER_SELECT = 0;
const uint32_t P_ROC_BUS_MASTER_SELECT = 1;
const uint32_t P_ROC_BUS_SWITCH_CTRL_SELECT = 2;
const uint32_t P_ROC_BUS_DRIVER_CTRL_SELECT = 3;
const uint32_t P_ROC_BUS_STATE_CHANGE_PROC_SELECT = 4;
const uint32_t P_ROC_BUS_DMD_SELECT = 5;
const uint32_t P_ROC_BUS_UNASSOCIATED_SELECT = 15;
const uint32_t P_ROC_REG_CHIP_ID_ADDR = 0;
const uint32_t P_ROC_REG_VERSION_ADDR = 1;
const uint32_t P_ROC_REG_WATCHDOG_ADDR = 2;
const uint32_t P_ROC_REG_DIPSWITCH_ADDR = 3;
const uint32_t P_ROC_EVENT_SWITCH_NUM_MASK = 0xFF;
const uint32_t P_ROC_EVENT_SWITCH_STATE_MASK = 0x100;
const uint32_t P_ROC_EVENT_SWITCH_STATE_SHIFT = 8;
const uint32_t P_ROC_EVENT_SWITCH_DEBOUNCED_MASK = 0x200;
const uint32_t P_ROC_EVENT_SWITCH_DEBOUNCED_SHIFT = 9;
const uint32_t P_ROC_DRIVER_CTRL_DECODE_SHIFT = 10;
const uint32_t P_ROC_DRIVER_CTRL_REG_DECODE = 0;
const uint32_t P_ROC_DRIVER_CONFIG_TABLE_DECODE = 1;
const uint32_t P_ROC_DRIVER_STATE_TABLE_DECODE = 2;
const uint32_t P_ROC_DRIVER_CATCHALL_DECODE = 3;
const uint32_t P_ROC_DRIVER_GLOBAL_ENABLE_DIRECT_OUTPUTS_SHIFT = 31;
const uint32_t P_ROC_DRIVER_GLOBAL_GLOBAL_POLARITY_SHIFT = 30;
const uint32_t P_ROC_DRIVER_GLOBAL_USE_CLEAR_SHIFT = 28;
const uint32_t P_ROC_DRIVER_GLOBAL_STROBE_START_SELECT_SHIFT = 27;
const uint32_t P_ROC_DRIVER_GLOBAL_START_STROBE_TIME_SHIFT = 20;
const uint32_t P_ROC_DRIVER_GLOBAL_START_STROBE_TIME_MASK = 0x07F00000;
const uint32_t P_ROC_DRIVER_GLOBAL_MATRIX_ROW_ENABLE_INDEX_1_SHIFT = 16;
const uint32_t P_ROC_DRIVER_GLOBAL_MATRIX_ROW_ENABLE_INDEX_1_MASK = 0x000F0000;
const uint32_t P_ROC_DRIVER_GLOBAL_MATRIX_ROW_ENABLE_INDEX_0_SHIFT = 12;
const uint32_t P_ROC_DRIVER_GLOBAL_MATRIX_ROW_ENABLE_INDEX_0_MASK = 0x0000F000;
const uint32_t P_ROC_DRIVER_GLOBAL_ACTIVE_LOW_MATRIX_ROWS_SHIFT = 11;
const uint32_t P_ROC_DRIVER_GLOBAL_ENCODE_ENABLES_SHIFT = 10;
const uint32_t P_ROC_DRIVER_GLOBAL_TICKLE_WATCHDOG_SHIFT = 9;
const uint32_t P_ROC_DRIVER_GROUP_SLOW_TIME_SHIFT = 12;
const uint32_t P_ROC_DRIVER_GROUP_DISABLE_STROBE_AFTER_SHIFT = 11;
const uint32_t P_ROC_DRIVER_GROUP_ENABLE_INDEX_SHIFT = 7;
const uint32_t P_ROC_DRIVER_GROUP_ROW_ACTIVATE_INDEX_SHIFT = 4;
const uint32_t P_ROC_DRIVER_GROUP_ROW_ENABLE_SELECT_SHIFT = 3;
const uint32_t P_ROC_DRIVER_GROUP_MATRIXED_SHIFT = 2;
const uint32_t P_ROC_DRIVER_GROUP_POLARITY_SHIFT = 1;
const uint32_t P_ROC_DRIVER_GROUP_ACTIVE_SHIFT = 0;
const uint32_t P_ROC_DRIVER_CONFIG_OUTPUT_DRIVE_TIME_SHIFT = 0;
const uint32_t P_ROC_DRIVER_CONFIG_POLARITY_SHIFT = 8;
const uint32_t P_ROC_DRIVER_CONFIG_STATE_SHIFT = 9;
const uint32_t P_ROC_DRIVER_CONFIG_UPDATE_SHIFT = 10;
const uint32_t P_ROC_DRIVER_CONFIG_WAIT_4_1ST_SLOT_SHIFT = 11;
const uint32_t P_ROC_DRIVER_CONFIG_TIMESLOT_SHIFT = 16;
const uint32_t P_ROC_DRIVER_CONFIG_PATTER_ON_TIME_SHIFT = 16;
const uint32_t P_ROC_DRIVER_CONFIG_PATTER_OFF_TIME_SHIFT = 23;
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_ADDR_DEBOUNCE_SHIFT = 11;
const uint32_t P_ROC_SWITCH_RULE_ADDR_STATE_SHIFT = 10;
const uint32_t P_ROC_SWITCH_RULE_ADDR_SWITCH_NUM_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;
const uint32_t P_ROC_DMD_NUM_COLUMNS_SHIFT = 0;
const uint32_t P_ROC_DMD_NUM_ROWS_SHIFT = 8;
const uint32_t P_ROC_DMD_NUM_SHADES_SHIFT = 16;
const uint32_t P_ROC_DMD_CYCLES_PER_ROW_SHIFT = 21;
const uint32_t P_ROC_DMD_ENABLE_SHIFT = 31;
const uint32_t P_ROC_DMD_DOTCLK_HALF_PERIOD_SHIFT = 0;
const uint32_t P_ROC_DMD_DE_HIGH_CYCLES_SHIFT = 8;
const uint32_t P_ROC_DMD_LATCH_HIGH_CYCLES_SHIFT = 16;
const uint32_t P_ROC_DMD_RCLK_LOW_CYCLES_SHIFT = 24;
const uint32_t P_ROC_DMD_DOT_TABLE_BASE_ADDR = 0x1000;
uint32_t CreateRegRequestWord( uint32_t select, uint32_t addr, uint32_t num_words);
uint32_t CreateBurstCommand ( uint32_t select, uint32_t addr, uint32_t num_words);
int32_t CreateDriverUpdateGlobalConfigBurst ( uint32_t * burst, PRDriverGlobalConfig *driver_globals);
int32_t CreateDriverUpdateGroupConfigBurst ( uint32_t * burst, PRDriverGroupConfig *driver_group);
int32_t CreateDriverUpdateBurst ( uint32_t * burst, PRDriverState *driver);
int32_t CreateSwitchesUpdateRulesBurst ( uint32_t * burst, PRSwitchRule *rule_record);
int32_t CreateDMDUpdateGlobalConfigBurst ( uint32_t * burst, PRDMDConfig *dmd_config);
#endif // _PROC_HARDWARE_H_

142
src/pinproc.cpp Normal file
View File

@@ -0,0 +1,142 @@
/*
* The MIT License
* Copyright (c) 2009 Gerry Stellenberg, Adam Preble
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* pinproc.cpp
* libpinproc
*/
#include "../include/pinproc.h"
#include "PRDevice.h"
typedef void (*PRLogCallback)(const char *text);
PRLogCallback logCallback = NULL;
void PRLog(const char *format, ...)
{
const int maxLogLineLength = 1024;
char line[maxLogLineLength];
va_list ap;
va_start(ap, format);
vsnprintf(line, maxLogLineLength, format, ap);
if (logCallback)
logCallback(line);
else
fprintf(stderr, line);
}
void PRLogSetCallback(PRLogCallback callback)
{
logCallback = callback;
}
#define handleAsDevice ((PRDevice*)handle)
/** 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. */
PR_EXPORT PRHandle PRCreate(PRMachineType machineType)
{
PRDevice *device = PRDevice::Create(machineType);
if (device == NULL)
return kPRHandleInvalid;
else
return device;
}
/** Destroys an existing P-ROC device handle. */
PR_EXPORT void PRDelete(PRHandle handle)
{
if (handle != kPRHandleInvalid)
delete (PRDevice*)handle;
}
// Events
/** Get all of the available events that have been received. */
PR_EXPORT int PRGetEvents(PRHandle handle, PREvent *eventsOut, int maxEvents)
{
return handleAsDevice->GetEvents(eventsOut, maxEvents);
}
// Drivers
PR_EXPORT PRResult PRDriverUpdateGlobalConfig(PRHandle handle, PRDriverGlobalConfig *driverGlobalConfig)
{
return handleAsDevice->DriverUpdateGlobalConfig(driverGlobalConfig);
}
PR_EXPORT PRResult PRDriverGetGroupConfig(PRHandle handle, uint8_t groupNum, PRDriverGroupConfig *driverGroupConfig)
{
return handleAsDevice->DriverGetGroupConfig(groupNum, driverGroupConfig);
}
PR_EXPORT PRResult PRDriverUpdateGroupConfig(PRHandle handle, PRDriverGroupConfig *driverGroupConfig)
{
return handleAsDevice->DriverUpdateGroupConfig(driverGroupConfig);
}
PR_EXPORT PRResult PRDriverGetState(PRHandle handle, uint8_t driverNum, PRDriverState *driverState)
{
return handleAsDevice->DriverGetState(driverNum, driverState);
}
PR_EXPORT PRResult PRDriverUpdateState(PRHandle handle, PRDriverState *driverState)
{
return handleAsDevice->DriverUpdateState(driverState);
}
// Driver Helper functions:
PR_EXPORT PRResult PRDriverDisable(PRHandle handle, uint16_t driverNum)
{
return handleAsDevice->DriverDisable(driverNum);
}
PR_EXPORT PRResult PRDriverPulse(PRHandle handle, uint16_t driverNum, int milliseconds)
{
return handleAsDevice->DriverPulse(driverNum, milliseconds);
}
PR_EXPORT PRResult PRDriverSchedule(PRHandle handle, uint16_t driverNum, uint32_t schedule, uint8_t cycleSeconds, bool_t now)
{
return handleAsDevice->DriverSchedule(driverNum, schedule, cycleSeconds, now);
}
PR_EXPORT PRResult PRDriverPatter(PRHandle handle, uint16_t driverNum, uint16_t millisecondsOn, uint16_t millisecondsOff, uint16_t originalOnTime)
{
return handleAsDevice->DriverPatter(driverNum, millisecondsOn, millisecondsOff, originalOnTime);
}
// Switches
PR_EXPORT PRResult PRSwitchesUpdateRules(PRHandle handle, PRSwitchRule *rules, int numRules)
{
return handleAsDevice->SwitchesUpdateRules(rules, numRules);
}
PR_EXPORT int32_t PRDMDUpdateGlobalConfig(PRHandle handle, PRDMDGlobalConfig *dmdGlobalConfig)
{
return handleAsDevice->DMDUpdateGlobalConfig(dmdGlobalConfig);
}
PR_EXPORT PRResult PRDMDDraw(PRHandle handle, uint8_t * dots, uint16_t columns, uint8_t rows, uint8_t numSubFrames)
{
return handleAsDevice->DMDDraw(dots, columns, rows, numSubFrames);
}