1
0
mirror of https://github.com/preble/libpinproc synced 2026-02-22 18:15:25 +01:00
Files
libpinproc/examples/pinproctest/pinproctest.cpp
Tom Collins 5ad464b167 pinproctest: use standard strcmp() vs. strcmpi()
While case-insensitive compare of the machine type passed on the
command line would be nice, the function to do so has different names
on different platforms, and its behavior may be impacted by the user's
locale setting.
2020-08-18 13:13:16 -05:00

415 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("\nAccel 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("\nAccel 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);
// if (numEvents > 0) printf("\nNum events: %x\n", numEvents);
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;
}
#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("\nAccel: X: %x, Y: %x, Z: %x", readData[0], readData[1],readData[2]);
break;
}
case kPREventTypeAccelerometerIRQ:
{
//readData[2] = event->value & 0x3FFF;
readData[3] = event->value;
printf("\nAccel IRQ: %x", readData[3]);
break;
}
default:
{
printf("\nUnknown event: %x:%x", 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;
}