mirror of
https://github.com/preble/libpinproc
synced 2026-02-24 18:25:23 +01:00
409 lines
13 KiB
C++
409 lines
13 KiB
C++
/*
|
|
* 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 "pinproctest.h"
|
|
uint32_t board_id = 0;
|
|
|
|
PRMachineType machineType = kPRMachineInvalid;
|
|
|
|
/** Demonstration of the custom logging callback. */
|
|
void TestLogger(PRLogLevel level, const char *text)
|
|
{
|
|
printf("TEST: %s", text);
|
|
}
|
|
|
|
void ConfigureAccelerometerMotion(PRHandle proc)
|
|
{
|
|
uint32_t readData[5];
|
|
|
|
// Only the P3-ROC has an accelerometer.
|
|
if (board_id != P3_ROC_CHIP_ID) {
|
|
return;
|
|
}
|
|
|
|
PRReadData(proc, P3_ROC_BUS_ACCELEROMETER_SELECT, 0x10D, 1, readData);
|
|
printf("Accel chip id: %x\n", readData[0]);
|
|
fflush(stdout);
|
|
|
|
// Set FF_MT_COUNT (0x18)
|
|
readData[0] = 1;
|
|
PRWriteData(proc, P3_ROC_BUS_ACCELEROMETER_SELECT, 0x118, 1, readData);
|
|
|
|
// Set FF_MT_THRESH (0x17)
|
|
readData[0] = 1;
|
|
PRWriteData(proc, P3_ROC_BUS_ACCELEROMETER_SELECT, 0x117, 1, readData);
|
|
|
|
// Set FF_MT_CONFIG (0x15)
|
|
readData[0] = 0xD8;
|
|
PRWriteData(proc, P3_ROC_BUS_ACCELEROMETER_SELECT, 0x115, 1, readData);
|
|
|
|
// Enable Motion interrupts
|
|
readData[0] = 0x04;
|
|
PRWriteData(proc, P3_ROC_BUS_ACCELEROMETER_SELECT, 0x12D, 1, readData);
|
|
|
|
// Direct motion interrupt to int0 pin (default)
|
|
readData[0] = 0x04;
|
|
PRWriteData(proc, P3_ROC_BUS_ACCELEROMETER_SELECT, 0x12E, 1, readData);
|
|
|
|
readData[0] = 0x3D;
|
|
PRWriteData(proc, P3_ROC_BUS_ACCELEROMETER_SELECT, 0x12A, 1, readData);
|
|
|
|
readData[0] = 0x02;
|
|
PRWriteData(proc, P3_ROC_BUS_ACCELEROMETER_SELECT, 0x12B, 1, readData);
|
|
|
|
|
|
// Enable auto-polling of accelerometer every 128 ms (8 times a sec).
|
|
//readData[0] = 0x0F; // Enable polling, 8 times a second.
|
|
readData[0] = 0x00; // Disable polling
|
|
readData[0] = readData[0] | 0x1600; // Set IRQ status addr (FF_MT_SRC)
|
|
PRWriteData(proc, P3_ROC_BUS_ACCELEROMETER_SELECT, 0x000, 1, readData);
|
|
PRFlushWriteData(proc);
|
|
}
|
|
|
|
void ConfigureAccelerometerTransient(PRHandle proc)
|
|
{
|
|
uint32_t readData[5];
|
|
|
|
// Only the P3-ROC has an accelerometer.
|
|
if (board_id != P3_ROC_CHIP_ID) {
|
|
return;
|
|
}
|
|
|
|
PRReadData(proc, P3_ROC_BUS_ACCELEROMETER_SELECT, 0x10D, 1, readData);
|
|
printf("Accel chip id: %x\n", readData[0]);
|
|
fflush(stdout);
|
|
|
|
// Set to standby so register changes will take.
|
|
readData[0] = 0x0;
|
|
PRWriteData(proc, P3_ROC_BUS_ACCELEROMETER_SELECT, 0x12A, 1, readData);
|
|
|
|
// Set HPF_OUT bit in XYZ_DATA_CFG (0x0E)
|
|
//readData[0] = 0x10;
|
|
//PRWriteData(proc, P3_ROC_BUS_ACCELEROMETER_SELECT, 0x10E, 1, readData);
|
|
|
|
|
|
// Set HP_FILTER_CUTOFF (0x0F)
|
|
readData[0] = 0x03;
|
|
PRWriteData(proc, P3_ROC_BUS_ACCELEROMETER_SELECT, 0x10F, 1, readData);
|
|
|
|
// Set FF_TRANSIENT_COUNT (0x20)
|
|
readData[0] = 1;
|
|
PRWriteData(proc, P3_ROC_BUS_ACCELEROMETER_SELECT, 0x120, 1, readData);
|
|
|
|
// Set FF_TRANSIENT_THRESH (0x1F)
|
|
readData[0] = 1;
|
|
PRWriteData(proc, P3_ROC_BUS_ACCELEROMETER_SELECT, 0x11F, 1, readData);
|
|
|
|
// Set FF_TRANSIENT_CONFIG (0x1D)
|
|
readData[0] = 0x1E;
|
|
PRWriteData(proc, P3_ROC_BUS_ACCELEROMETER_SELECT, 0x11D, 1, readData);
|
|
|
|
// Enable Motion interrupts
|
|
readData[0] = 0x20;
|
|
PRWriteData(proc, P3_ROC_BUS_ACCELEROMETER_SELECT, 0x12D, 1, readData);
|
|
|
|
// Direct motion interrupt to int0 pin (default)
|
|
readData[0] = 0x20;
|
|
PRWriteData(proc, P3_ROC_BUS_ACCELEROMETER_SELECT, 0x12E, 1, readData);
|
|
|
|
//readData[0] = 0x3D;
|
|
readData[0] = 0x05;
|
|
PRWriteData(proc, P3_ROC_BUS_ACCELEROMETER_SELECT, 0x12A, 1, readData);
|
|
|
|
readData[0] = 0x02;
|
|
PRWriteData(proc, P3_ROC_BUS_ACCELEROMETER_SELECT, 0x12B, 1, readData);
|
|
|
|
|
|
// Enable auto-polling of accelerometer every 128 ms (8 times a sec).
|
|
//readData[0] = 0x0F; // Enable polling, 8 times a second.
|
|
readData[0] = 0x00; // Disable polling
|
|
readData[0] = readData[0] | 0x1E00; // Set IRQ status addr (FF_MT_SRC)
|
|
PRWriteData(proc, P3_ROC_BUS_ACCELEROMETER_SELECT, 0x000, 1, readData);
|
|
PRFlushWriteData(proc);
|
|
}
|
|
|
|
time_t startTime;
|
|
bool runLoopRun = true;
|
|
|
|
void RunLoop(PRHandle proc)
|
|
{
|
|
const int maxEvents = 16;
|
|
int i;
|
|
PREvent events[maxEvents];
|
|
uint32_t readData[5];
|
|
// Create dot array using an array of bytes. Each byte holds 8 dots. Need
|
|
// space for 4 sub-frames of 128/32 dots.
|
|
unsigned char dots[4*((128*32)/8)];
|
|
unsigned int dotOffset = 0;
|
|
|
|
// Retrieve and store initial switch states.
|
|
LoadSwitchStates(proc);
|
|
|
|
if (machineType != kPRMachineWPCAlphanumeric) {
|
|
// Send 3 frames
|
|
for (i=0; i<3; i++)
|
|
{
|
|
// Create a dot pattern to test the DMD
|
|
UpdateDots(dots,dotOffset++);
|
|
PRDMDDraw(proc,dots);
|
|
}
|
|
}
|
|
|
|
//ConfigureAccelerometerMotion(proc);
|
|
ConfigureAccelerometerTransient(proc);
|
|
|
|
int p = 0;
|
|
|
|
while (runLoopRun)
|
|
{
|
|
PRDriverWatchdogTickle(proc);
|
|
|
|
int numEvents = PRGetEvents(proc, events, maxEvents);
|
|
for (int i = 0; i < numEvents; i++)
|
|
{
|
|
PREvent *event = &events[i];
|
|
const char *stateText;
|
|
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;
|
|
default:
|
|
stateText = "Unknown";
|
|
}
|
|
#ifdef _MSC_VER
|
|
struct _timeb tv;
|
|
_ftime_s(&tv);
|
|
#else
|
|
struct timeval tv;
|
|
gettimeofday(&tv, NULL);
|
|
#endif
|
|
switch (event->type)
|
|
{
|
|
case kPREventTypeSwitchOpenDebounced:
|
|
case kPREventTypeSwitchClosedDebounced:
|
|
case kPREventTypeSwitchOpenNondebounced:
|
|
case kPREventTypeSwitchClosedNondebounced:
|
|
#ifdef _MSC_VER
|
|
printf("%d.%03d switch %3d: %s\n", (int)(tv.time-startTime), tv.millitm, event->value, stateText);
|
|
#else
|
|
printf("%d.%03d switch %3d: %s\n", (int)(tv.tv_sec-startTime), (int)tv.tv_usec/1000, event->value, stateText);
|
|
#endif
|
|
UpdateSwitchState( event );
|
|
break;
|
|
case kPREventTypeDMDFrameDisplayed:
|
|
if (machineType == kPRMachineWPCAlphanumeric) {
|
|
//UpdateAlphaDisplay(proc, dotOffset++);
|
|
}
|
|
else {
|
|
UpdateDots(dots,dotOffset++);
|
|
PRDMDDraw(proc,dots);
|
|
}
|
|
break;
|
|
case kPREventTypeAccelerometerX:
|
|
//readData[0] = event->value & 0x3FFF;
|
|
readData[0] = event->value;
|
|
break;
|
|
case kPREventTypeAccelerometerY:
|
|
//readData[1] = event->value & 0x3FFF;
|
|
readData[1] = event->value;
|
|
break;
|
|
case kPREventTypeAccelerometerZ:
|
|
//readData[2] = event->value & 0x3FFF;
|
|
readData[2] = event->value;
|
|
printf("Accel: X: %x, Y: %x, Z: %x\n", readData[0], readData[1],readData[2]);
|
|
break;
|
|
case kPREventTypeAccelerometerIRQ:
|
|
//readData[2] = event->value & 0x3FFF;
|
|
readData[3] = event->value;
|
|
printf("Accel IRQ: %x\n", readData[3]);
|
|
break;
|
|
default:
|
|
printf("Unknown event: %x:%x\n", event->type, event->value);
|
|
}
|
|
}
|
|
if (numEvents > 0) {
|
|
fflush(stdout);
|
|
}
|
|
PRFlushWriteData(proc);
|
|
#ifdef _MSC_VER
|
|
Sleep(10);
|
|
#else
|
|
usleep(10*1000); // Sleep for 10ms so we aren't pegging the CPU.
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void sigint(int)
|
|
{
|
|
runLoopRun = false;
|
|
signal(SIGINT, SIG_DFL); // Re-install the default signal handler.
|
|
printf("Exiting...\n");
|
|
}
|
|
|
|
const struct {
|
|
PRMachineType type;
|
|
const char *name;
|
|
} machine_types[] = {
|
|
{ kPRMachineCustom, "custom" },
|
|
{ kPRMachineWPCAlphanumeric, "wpcAlphanumeric" },
|
|
{ kPRMachineWPC, "wpc" },
|
|
{ kPRMachineWPC95, "wpc95" },
|
|
{ kPRMachineSternWhitestar, "sternWhitestar" },
|
|
{ kPRMachineSternSAM, "sternSAM" },
|
|
{ kPRMachinePDB, "pdb" },
|
|
};
|
|
#define MACHINE_TYPES (sizeof(machine_types) / sizeof(machine_types[0]))
|
|
|
|
int main(int argc, const char **argv)
|
|
{
|
|
int i;
|
|
|
|
// Set a signal handler so that we can exit gracefully on Ctrl-C:
|
|
signal(SIGINT, sigint);
|
|
startTime = time(NULL);
|
|
|
|
if (argc < 2) {
|
|
printf("Usage: %s <machine_type>\n\nWhere machine_type is one of:\n ", argv[0]);
|
|
for (i = 0; i < MACHINE_TYPES; i++) {
|
|
printf("%s %s", i ? "," : "", machine_types[i].name);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
// Assign a custom logging callback to demonstrate capturing log information from P-ROC:
|
|
PRLogSetCallback(TestLogger);
|
|
|
|
for (i = 0; i < MACHINE_TYPES; i++) {
|
|
if (strcmp(argv[1], machine_types[i].name) == 0) {
|
|
machineType = machine_types[i].type;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (machineType == kPRMachineInvalid) {
|
|
printf("Unknown machine type: %s\n", argv[1]);
|
|
return 1;
|
|
}
|
|
|
|
// Finally instantiate the P-ROC device:
|
|
PRHandle proc = PRCreate(machineType);
|
|
if (proc == kPRHandleInvalid) {
|
|
printf("Error during PRCreate: %s\n", PRGetLastErrorText());
|
|
return 1;
|
|
}
|
|
PRReadData(proc, P_ROC_MANAGER_SELECT, P_ROC_REG_CHIP_ID_ADDR, 1, &board_id);
|
|
if (board_id == P_ROC_CHIP_ID) {
|
|
printf("Connected to P-ROC\n");
|
|
}
|
|
else if (board_id == P3_ROC_CHIP_ID) {
|
|
printf("Connected to P3-ROC\n");
|
|
}
|
|
else {
|
|
printf("Warning: unrecognized board ID 0x%08X\n", board_id);
|
|
}
|
|
|
|
PRLogSetLevel(kPRLogInfo);
|
|
PRReset(proc, kPRResetFlagUpdateDevice); // Reset the device structs and write them into the device.
|
|
|
|
// Even if WPCAlphanumeric, configure the DMD at least to get frame events for
|
|
// timing purposes.
|
|
ConfigureDMD(proc);
|
|
if (machineType == kPRMachineCustom) {
|
|
ConfigureDrivers(proc);
|
|
}
|
|
ConfigureSwitches(proc); // Notify host for all debounced switch events.
|
|
|
|
if (machineType == kPRMachineWPCAlphanumeric) {
|
|
UpdateAlphaDisplay(proc, 0);
|
|
}
|
|
|
|
// Pulse a coil for testing purposes.
|
|
PRDriverPulse(proc, 47, 30);
|
|
// Schedule a feature lamp for testing purposes.
|
|
for (i=0; i<8; i++) {
|
|
PRDriverSchedule(proc, 80+i, 0xFF00FF00, 0, 0);
|
|
}
|
|
|
|
//PRDriverSchedule(proc, 80, 0xFF00FF00, 0, 0);
|
|
//PRDriverSchedule(proc, 0, 0xFF00AAAA, 1, 1);
|
|
|
|
// Pitter-patter lamp 84: on 127ms, off 127ms, forever.
|
|
//PRDriverPatter(proc, 84, 127, 127, 0);
|
|
|
|
//Pulsed Patter for coil 48: on 5ms, off 10ms, repeat for 45ms.
|
|
//PRDriverPulsedPatter(proc, 48, 5, 10, 45); // Coil 48: on 5ms, off 10ms, repeat for 45ms.
|
|
|
|
/*
|
|
PRDriverAuxCommand auxCommands[256];
|
|
|
|
// Disable the first entry so the Aux logic won't begin immediately.
|
|
PRDriverAuxPrepareDisable(&auxCommands[0]);
|
|
// Set up a sequence of outputs.
|
|
for (i=0; i<16; i++) {
|
|
PRDriverAuxPrepareOutput(&(auxCommands[i+1]), i, 0, 8, false);
|
|
}
|
|
// Disable the last command so the sequence stops.
|
|
// PRDriverAuxPrepareDisable(&auxCommands[17]);
|
|
// Jump from addr 17 to 1 to repeat.
|
|
PRDriverAuxPrepareDelay(&auxCommands[17],1000);
|
|
PRDriverAuxPrepareJump(&auxCommands[18],1);
|
|
|
|
// Send the commands.
|
|
PRDriverAuxSendCommands(proc, auxCommands, 19, 0);
|
|
|
|
// Jump from addr 0 to 1 to begin.
|
|
PRDriverAuxPrepareJump(&auxCommands[0],1);
|
|
PRDriverAuxSendCommands(proc, auxCommands, 1, 0);
|
|
*/
|
|
PRFlushWriteData(proc);
|
|
|
|
printf("Running. Hit Ctrl-C to exit.\n");
|
|
|
|
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.
|
|
PRFlushWriteData(proc);
|
|
|
|
// Destroy the P-ROC device handle:
|
|
PRDelete(proc);
|
|
proc = kPRHandleInvalid;
|
|
return 0;
|
|
}
|