working on gomespace handlers
EIVE/eive-obsw/pipeline/head There was a failure building this commit Details

This commit is contained in:
Ulrich Mohr 2022-08-23 23:34:20 +02:00
parent dfb800f58a
commit 1f47c970af
9 changed files with 161 additions and 70 deletions

View File

@ -12,7 +12,7 @@ ACUHandler::ACUHandler(object_id_t objectId, object_id_t comIF, CookieIF *comCoo
ACUHandler::~ACUHandler() {}
ReturnValue_t ACUHandler::buildNormalDeviceCommand(DeviceCommandId_t *id) {
*id = GOMSPACE::REQUEST_HK_TABLE;
*id = GomspaceCommands::REQUEST_HK_TABLE;
return buildCommandFromCommand(*id, NULL, 0);
}
@ -190,7 +190,7 @@ void ACUHandler::setDebugMode(bool enable) { this->debugMode = enable; }
ReturnValue_t ACUHandler::printStatus(DeviceCommandId_t cmd) {
ReturnValue_t result = RETURN_OK;
switch (cmd) {
case (GOMSPACE::PRINT_SWITCH_V_I): {
case (GomspaceCommands::PRINT_SWITCH_V_I): {
PoolReadGuard pg(&coreHk);
result = pg.getReadResult();
if (result != HasReturnvaluesIF::RETURN_OK) {

View File

@ -33,49 +33,59 @@ ReturnValue_t GomspaceDeviceHandler::buildTransitionDeviceCommand(DeviceCommandI
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t GomspaceDeviceHandler::handleAction(NoneAction* action) {}
ReturnValue_t GomspaceDeviceHandler::handleAction(RebootAction* action) {}
ReturnValue_t GomspaceDeviceHandler::handleAction(GndwdtResetAction* action) {}
ReturnValue_t GomspaceDeviceHandler::handleAction(ParamGetAction* action) {}
ReturnValue_t GomspaceDeviceHandler::handleAction(ParamSetAction* action) {}
ReturnValue_t GomspaceDeviceHandler::handleAction(RequestHkTableAction* action) {}
ReturnValue_t GomspaceDeviceHandler::handleAction(PrintSwitchVIAction* action) {}
ReturnValue_t GomspaceDeviceHandler::handleAction(PrintLatchupsAction* action) {}
ReturnValue_t GomspaceDeviceHandler::buildCommandFromCommand(DeviceCommandId_t deviceCommand,
const uint8_t* commandData,
size_t commandDataLen) {
ReturnValue_t result = childCommandHook(deviceCommand, commandData, commandDataLen);
switch (deviceCommand) {
case (GOMSPACE::PING): {
result = generatePingCommand(commandData, commandDataLen);
case (GomspaceCommands::PING): {
//result = generatePingCommand(commandData, commandDataLen);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
break;
}
case (GOMSPACE::REBOOT): {
case (GomspaceCommands::REBOOT): {
generateRebootCommand();
break;
}
case (GOMSPACE::PARAM_SET): {
case (GomspaceCommands::PARAM_SET): {
result = generateSetParamCommand(commandData, commandDataLen);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
break;
}
case (GOMSPACE::PARAM_GET): {
case (GomspaceCommands::PARAM_GET): {
result = generateGetParamCommand(commandData, commandDataLen);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
break;
}
case (GOMSPACE::GNDWDT_RESET): {
case (GomspaceCommands::GNDWDT_RESET): {
result = generateResetWatchdogCmd();
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
break;
}
case (GOMSPACE::PRINT_SWITCH_V_I):
case (GOMSPACE::PRINT_LATCHUPS): {
case (GomspaceCommands::PRINT_SWITCH_V_I):
case (GomspaceCommands::PRINT_LATCHUPS): {
result = printStatus(deviceCommand);
break;
}
case (GOMSPACE::REQUEST_HK_TABLE): {
case (GomspaceCommands::REQUEST_HK_TABLE): {
result = generateRequestFullHkTableCmd(hkTableReplySize);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
@ -89,40 +99,40 @@ ReturnValue_t GomspaceDeviceHandler::buildCommandFromCommand(DeviceCommandId_t d
}
void GomspaceDeviceHandler::fillCommandAndReplyMap() {
this->insertInCommandAndReplyMap(GOMSPACE::PING, 3);
this->insertInCommandMap(GOMSPACE::REBOOT);
this->insertInCommandAndReplyMap(GOMSPACE::PARAM_SET, 3);
this->insertInCommandAndReplyMap(GOMSPACE::PARAM_GET, 3);
this->insertInCommandAndReplyMap(GOMSPACE::REQUEST_HK_TABLE, 3);
this->insertInCommandMap(GOMSPACE::GNDWDT_RESET);
this->insertInCommandMap(GOMSPACE::PRINT_SWITCH_V_I);
this->insertInCommandMap(GOMSPACE::PRINT_LATCHUPS);
this->insertInCommandAndReplyMap(GomspaceCommands::PING, 3);
this->insertInCommandMap(GomspaceCommands::REBOOT);
this->insertInCommandAndReplyMap(GomspaceCommands::PARAM_SET, 3);
this->insertInCommandAndReplyMap(GomspaceCommands::PARAM_GET, 3);
this->insertInCommandAndReplyMap(GomspaceCommands::REQUEST_HK_TABLE, 3);
this->insertInCommandMap(GomspaceCommands::GNDWDT_RESET);
this->insertInCommandMap(GomspaceCommands::PRINT_SWITCH_V_I);
this->insertInCommandMap(GomspaceCommands::PRINT_LATCHUPS);
}
ReturnValue_t GomspaceDeviceHandler::scanForReply(const uint8_t* start, size_t remainingSize,
DeviceCommandId_t* foundId, size_t* foundLen) {
switch (rememberCommandId) {
case (GOMSPACE::PING):
*foundId = GOMSPACE::PING;
case (GomspaceCommands::PING):
*foundId = GomspaceCommands::PING;
*foundLen = PING_REPLY_SIZE;
rememberCommandId = GOMSPACE::NONE;
rememberCommandId = GomspaceCommands::NONE;
break;
case (GOMSPACE::PARAM_GET): {
*foundId = GOMSPACE::PARAM_GET;
case (GomspaceCommands::PARAM_GET): {
*foundId = GomspaceCommands::PARAM_GET;
*foundLen = rememberRequestedSize + GOMSPACE::GS_HDR_LENGTH;
rememberCommandId = GOMSPACE::NONE;
rememberCommandId = GomspaceCommands::NONE;
break;
}
case (GOMSPACE::PARAM_SET): {
*foundId = GOMSPACE::PARAM_SET;
case (GomspaceCommands::PARAM_SET): {
*foundId = GomspaceCommands::PARAM_SET;
*foundLen = rememberRequestedSize;
rememberCommandId = GOMSPACE::NONE;
rememberCommandId = GomspaceCommands::NONE;
break;
}
case (GOMSPACE::REQUEST_HK_TABLE): {
*foundId = GOMSPACE::REQUEST_HK_TABLE;
case (GomspaceCommands::REQUEST_HK_TABLE): {
*foundId = GomspaceCommands::REQUEST_HK_TABLE;
*foundLen = rememberRequestedSize + GOMSPACE::GS_HDR_LENGTH;
rememberCommandId = GOMSPACE::NONE;
rememberCommandId = GomspaceCommands::NONE;
break;
}
default:
@ -134,12 +144,12 @@ ReturnValue_t GomspaceDeviceHandler::scanForReply(const uint8_t* start, size_t r
ReturnValue_t GomspaceDeviceHandler::interpretDeviceReply(DeviceCommandId_t id,
const uint8_t* packet) {
switch (id) {
case (GOMSPACE::PING): {
case (GomspaceCommands::PING): {
SerializeElement<uint32_t> replyTime = *packet;
handleDeviceTM(&replyTime, id, true);
break;
}
case (GOMSPACE::PARAM_GET): {
case (GomspaceCommands::PARAM_GET): {
// -2 to subtract address size from gomspace parameter reply packet
uint16_t payloadLength = (*(packet + 2) << 8 | *(packet + 3)) - 2;
if (payloadLength > sizeof(uint32_t)) {
@ -166,7 +176,7 @@ ReturnValue_t GomspaceDeviceHandler::interpretDeviceReply(DeviceCommandId_t id,
handleDeviceTM(&paramReply, id, true);
break;
}
case (GOMSPACE::PARAM_SET): {
case (GomspaceCommands::PARAM_SET): {
/* When setting a parameter, the p60dock sends back the state of the
* operation */
if (*packet != PARAM_SET_OK) {
@ -175,7 +185,7 @@ ReturnValue_t GomspaceDeviceHandler::interpretDeviceReply(DeviceCommandId_t id,
setParamCallback(setParamCacher, true);
break;
}
case (GOMSPACE::REQUEST_HK_TABLE): {
case (GomspaceCommands::REQUEST_HK_TABLE): {
letChildHandleHkReply(id, packet);
break;
}
@ -245,7 +255,7 @@ ReturnValue_t GomspaceDeviceHandler::generateSetParamCommand(const uint8_t* comm
rawPacket = cspPacket;
rawPacketLen = cspPacketLen;
rememberRequestedSize = querySize;
rememberCommandId = GOMSPACE::PARAM_SET;
rememberCommandId = GomspaceCommands::PARAM_SET;
return HasReturnvaluesIF::RETURN_OK;
}
@ -312,13 +322,12 @@ ReturnValue_t GomspaceDeviceHandler::generateGetParamCommand(const uint8_t* comm
rawPacket = cspPacket;
rawPacketLen = cspPacketLen;
rememberRequestedSize = querySize;
rememberCommandId = GOMSPACE::PARAM_GET;
rememberCommandId = GomspaceCommands::PARAM_GET;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t GomspaceDeviceHandler::generatePingCommand(const uint8_t* commandData,
size_t commandDataLen) {
CspPingCommand cspPingCommand(commandData, commandDataLen);
ReturnValue_t GomspaceDeviceHandler::handleAction(PingAction* action) {
/*CspPingCommand cspPingCommand(commandData, commandDataLen);
size_t cspPacketLen = 0;
uint8_t* buffer = cspPacket;
ReturnValue_t result = cspPingCommand.serialize(&buffer, &cspPacketLen, sizeof(cspPacket),
@ -332,8 +341,8 @@ ReturnValue_t GomspaceDeviceHandler::generatePingCommand(const uint8_t* commandD
return PACKET_TOO_LONG;
}
rawPacket = cspPacket;
rawPacketLen = cspPacketLen;
rememberCommandId = GOMSPACE::PING;
rawPacketLen = cspPacketLen;*/
rememberCommandId = GomspaceCommands::PING;
return HasReturnvaluesIF::RETURN_OK;
}
@ -411,7 +420,7 @@ ReturnValue_t GomspaceDeviceHandler::generateResetWatchdogCmd() {
rawPacketLen = cspPacketLen;
rememberRequestedSize = 0; // No bytes will be queried with the ground
// watchdog command.
rememberCommandId = GOMSPACE::GNDWDT_RESET;
rememberCommandId = GomspaceCommands::GNDWDT_RESET;
return HasReturnvaluesIF::RETURN_OK;
}
@ -433,7 +442,7 @@ ReturnValue_t GomspaceDeviceHandler::generateRequestFullHkTableCmd(uint16_t hkTa
rawPacket = cspPacket;
rawPacketLen = cspPacketLen;
rememberRequestedSize = querySize;
rememberCommandId = GOMSPACE::REQUEST_HK_TABLE;
rememberCommandId = GomspaceCommands::REQUEST_HK_TABLE;
return RETURN_OK;
}

View File

@ -4,6 +4,7 @@
#include <mission/devices/devicedefinitions/GomSpacePackets.h>
#include "fsfw/devicehandlers/DeviceHandlerBase.h"
#include "mission/devices/devicedefinitions/GomspaceActions.h"
#include "mission/devices/devicedefinitions/GomspaceDefinitions.h"
#include "returnvalues/classIds.h"
@ -48,6 +49,16 @@ class GomspaceDeviceHandler : public DeviceHandlerBase {
*/
void setModeNormal();
ReturnValue_t handleAction(PingAction *action);
ReturnValue_t handleAction(NoneAction *action);
ReturnValue_t handleAction(RebootAction *action);
ReturnValue_t handleAction(GndwdtResetAction *action);
ReturnValue_t handleAction(ParamGetAction *action);
ReturnValue_t handleAction(ParamSetAction *action);
ReturnValue_t handleAction(RequestHkTableAction *action);
ReturnValue_t handleAction(PrintSwitchVIAction *action);
ReturnValue_t handleAction(PrintLatchupsAction *action);
protected:
static const uint8_t MAX_PACKET_LEN = 36;
static const uint8_t PARAM_SET_OK = 1;
@ -56,7 +67,7 @@ class GomspaceDeviceHandler : public DeviceHandlerBase {
static const uint8_t HK_TABLE_ID = 4;
uint8_t rememberRequestedSize = 0;
uint8_t rememberCommandId = GOMSPACE::NONE;
uint8_t rememberCommandId = GomspaceCommands::NONE;
uint8_t cspPacket[MAX_PACKET_LEN];
uint16_t maxConfigTableAddress;
@ -67,6 +78,16 @@ class GomspaceDeviceHandler : public DeviceHandlerBase {
LocalPoolDataSetBase *hkTableDataset = nullptr;
PingAction pingAction = PingAction(this);
NoneAction noneAction = NoneAction(this);
RebootAction rebootAction = RebootAction(this);
GndwdtResetAction gndwdtResetAction = GndwdtResetAction(this);
ParamGetAction paramGetAction = ParamGetAction(this);
ParamSetAction paramSetAction = ParamSetAction(this);
RequestHkTableAction requestHkTableAction = RequestHkTableAction(this);
PrintSwitchVIAction printSwitchVIAction = PrintSwitchVIAction(this);
PrintLatchupsAction printLatchupsAction = PrintLatchupsAction(this);
void doStartUp() override;
void doShutDown() override;
virtual ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t *id) override;
@ -144,7 +165,7 @@ class GomspaceDeviceHandler : public DeviceHandlerBase {
/**
* @brief Function to generate the ping command for the ComIF.
*/
ReturnValue_t generatePingCommand(const uint8_t *commandData, size_t commandDataLen);
//ReturnValue_t generatePingCommand(const uint8_t *commandData, size_t commandDataLen);
/**
* @brief Function to generate the command to reboot a gomspace device

View File

@ -15,7 +15,7 @@ P60DockHandler::P60DockHandler(object_id_t objectId, object_id_t comIF, CookieIF
P60DockHandler::~P60DockHandler() {}
ReturnValue_t P60DockHandler::buildNormalDeviceCommand(DeviceCommandId_t *id) {
*id = GOMSPACE::REQUEST_HK_TABLE;
*id = GomspaceCommands::REQUEST_HK_TABLE;
return buildCommandFromCommand(*id, NULL, 0);
}
@ -233,7 +233,7 @@ ReturnValue_t P60DockHandler::initializeLocalDataPool(localpool::DataPool &local
ReturnValue_t P60DockHandler::printStatus(DeviceCommandId_t cmd) {
ReturnValue_t result = RETURN_OK;
switch (cmd) {
case (GOMSPACE::PRINT_SWITCH_V_I): {
case (GomspaceCommands::PRINT_SWITCH_V_I): {
PoolReadGuard pg0(&coreHk);
PoolReadGuard pg1(&auxHk);
if (pg0.getReadResult() != HasReturnvaluesIF::RETURN_OK or
@ -243,7 +243,7 @@ ReturnValue_t P60DockHandler::printStatus(DeviceCommandId_t cmd) {
printHkTableSwitchIV();
return HasReturnvaluesIF::RETURN_OK;
}
case (GOMSPACE::PRINT_LATCHUPS): {
case (GomspaceCommands::PRINT_LATCHUPS): {
PoolReadGuard pg(&auxHk);
result = pg.getReadResult();
printHkTableLatchups();

View File

@ -353,7 +353,7 @@ ReturnValue_t PCDUHandler::sendSwitchCommand(uint8_t switchNr, ReturnValue_t onO
result = IPCStore->addData(&storeAddress, command, sizeof(command));
CommandMessage message;
ActionMessage::setCommand(&message, GOMSPACE::PARAM_SET, storeAddress);
ActionMessage::setCommand(&message, GomspaceCommands::PARAM_SET, storeAddress);
result = commandQueue->sendMessage(pdu->getCommandQueue(), &message, 0);
if (result != RETURN_OK) {

View File

@ -15,7 +15,7 @@ PDU1Handler::PDU1Handler(object_id_t objectId, object_id_t comIF, CookieIF *comC
PDU1Handler::~PDU1Handler() {}
ReturnValue_t PDU1Handler::buildNormalDeviceCommand(DeviceCommandId_t *id) {
*id = GOMSPACE::REQUEST_HK_TABLE;
*id = GomspaceCommands::REQUEST_HK_TABLE;
return buildCommandFromCommand(*id, NULL, 0);
}
@ -103,7 +103,7 @@ LocalPoolDataSetBase *PDU1Handler::getDataSetHandle(sid_t sid) {
ReturnValue_t PDU1Handler::printStatus(DeviceCommandId_t cmd) {
ReturnValue_t result = RETURN_OK;
switch (cmd) {
case (GOMSPACE::PRINT_SWITCH_V_I): {
case (GomspaceCommands::PRINT_SWITCH_V_I): {
PoolReadGuard pg(&coreHk);
result = pg.getReadResult();
if (result != HasReturnvaluesIF::RETURN_OK) {
@ -112,7 +112,7 @@ ReturnValue_t PDU1Handler::printStatus(DeviceCommandId_t cmd) {
printHkTableSwitchVI();
break;
}
case (GOMSPACE::PRINT_LATCHUPS): {
case (GomspaceCommands::PRINT_LATCHUPS): {
PoolReadGuard pg(&auxHk);
result = pg.getReadResult();
if (result != HasReturnvaluesIF::RETURN_OK) {

View File

@ -15,7 +15,7 @@ PDU2Handler::PDU2Handler(object_id_t objectId, object_id_t comIF, CookieIF *comC
PDU2Handler::~PDU2Handler() {}
ReturnValue_t PDU2Handler::buildNormalDeviceCommand(DeviceCommandId_t *id) {
*id = GOMSPACE::REQUEST_HK_TABLE;
*id = GomspaceCommands::REQUEST_HK_TABLE;
return buildCommandFromCommand(*id, NULL, 0);
}
@ -57,7 +57,7 @@ ReturnValue_t PDU2Handler::initializeLocalDataPool(localpool::DataPool &localDat
ReturnValue_t PDU2Handler::printStatus(DeviceCommandId_t cmd) {
ReturnValue_t result = RETURN_OK;
switch (cmd) {
case (GOMSPACE::PRINT_SWITCH_V_I): {
case (GomspaceCommands::PRINT_SWITCH_V_I): {
PoolReadGuard pg(&coreHk);
result = pg.getReadResult();
if (result != HasReturnvaluesIF::RETURN_OK) {
@ -66,7 +66,7 @@ ReturnValue_t PDU2Handler::printStatus(DeviceCommandId_t cmd) {
printHkTableSwitchVI();
break;
}
case (GOMSPACE::PRINT_LATCHUPS): {
case (GomspaceCommands::PRINT_LATCHUPS): {
PoolReadGuard pg(&auxHk);
result = pg.getReadResult();
if (result != HasReturnvaluesIF::RETURN_OK) {

View File

@ -0,0 +1,65 @@
#pragma once
#include <fsfw/action/MinMaxParameter.h>
#include <fsfw/action/TemplateAction.h>
#include "GomspaceDefinitions.h"
class GomspaceDeviceHandler;
class PingAction : public TemplateAction<GomspaceDeviceHandler, PingAction, GomspaceCommands> {
public:
PingAction(GomspaceDeviceHandler* owner) : TemplateAction(owner, GomspaceCommands::PING) {}
};
class NoneAction : public TemplateAction<GomspaceDeviceHandler, NoneAction, GomspaceCommands> {
public:
NoneAction(GomspaceDeviceHandler* owner) : TemplateAction(owner, GomspaceCommands::NONE) {}
};
class RebootAction : public TemplateAction<GomspaceDeviceHandler, RebootAction, GomspaceCommands> {
public:
RebootAction(GomspaceDeviceHandler* owner) : TemplateAction(owner, GomspaceCommands::REBOOT) {}
};
class GndwdtResetAction
: public TemplateAction<GomspaceDeviceHandler, GndwdtResetAction, GomspaceCommands> {
public:
GndwdtResetAction(GomspaceDeviceHandler* owner)
: TemplateAction(owner, GomspaceCommands::GNDWDT_RESET) {}
};
class ParamGetAction
: public TemplateAction<GomspaceDeviceHandler, ParamGetAction, GomspaceCommands> {
public:
ParamGetAction(GomspaceDeviceHandler* owner)
: TemplateAction(owner, GomspaceCommands::PARAM_GET) {}
};
class ParamSetAction
: public TemplateAction<GomspaceDeviceHandler, ParamSetAction, GomspaceCommands> {
public:
ParamSetAction(GomspaceDeviceHandler* owner)
: TemplateAction(owner, GomspaceCommands::PARAM_SET) {}
};
class RequestHkTableAction
: public TemplateAction<GomspaceDeviceHandler, RequestHkTableAction, GomspaceCommands> {
public:
RequestHkTableAction(GomspaceDeviceHandler* owner)
: TemplateAction(owner, GomspaceCommands::REQUEST_HK_TABLE) {}
};
class PrintSwitchVIAction
: public TemplateAction<GomspaceDeviceHandler, PrintSwitchVIAction, GomspaceCommands> {
public:
PrintSwitchVIAction(GomspaceDeviceHandler* owner)
: TemplateAction(owner, GomspaceCommands::PRINT_SWITCH_V_I) {}
};
class PrintLatchupsAction
: public TemplateAction<GomspaceDeviceHandler, PrintLatchupsAction, GomspaceCommands> {
public:
PrintLatchupsAction(GomspaceDeviceHandler* owner)
: TemplateAction(owner, GomspaceCommands::PRINT_LATCHUPS) {}
};

View File

@ -4,6 +4,7 @@
#include <fsfw/datapoollocal/LocalPoolVariable.h>
#include <fsfw/datapoollocal/StaticLocalDataSet.h>
#include <fsfw/devicehandlers/DeviceHandlerIF.h>
#include <fsfw/introspection/Enum.h>
#include <fsfw/power/definitions.h>
#include <cstdint>
@ -26,24 +27,19 @@ static const uint8_t REBOOT_PORT = 4;
static const uint8_t PARAM_PORT = 7;
static const uint8_t P60_PORT_GNDWDT_RESET = 9;
} // namespace GOMSPACE
/**
* Device commands are derived from the rparam.h of the gomspace lib..
* IDs above 50 are reserved for device specific commands.
*/
static const DeviceCommandId_t PING = 1; //!< [EXPORT] : [COMMAND]
static const DeviceCommandId_t NONE = 2; // Set when no command is pending
static const DeviceCommandId_t REBOOT = 4; //!< [EXPORT] : [COMMAND]
static const DeviceCommandId_t GNDWDT_RESET = 9; //!< [EXPORT] : [COMMAND]
static const DeviceCommandId_t PARAM_GET = 0; //!< [EXPORT] : [COMMAND]
static const DeviceCommandId_t PARAM_SET = 255; //!< [EXPORT] : [COMMAND]
static const DeviceCommandId_t REQUEST_HK_TABLE = 16; //!< [EXPORT] : [COMMAND]
//! [EXPORT] : [COMMAND] Print switch states, voltages and currents to the console
//! For the ACU device, only print voltages and currents of the 6 ACU channels
static const DeviceCommandId_t PRINT_SWITCH_V_I = 32;
static const DeviceCommandId_t PRINT_LATCHUPS = 33;
} // namespace GOMSPACE
FSFW_ENUM(GomspaceCommands, DeviceCommandId_t,
((PING, 1, "Ping"))((NONE, 2, "None (used internally)"))((REBOOT, 4, "Reboot"))(
(GNDWDT_RESET, 9, "Reset Watchdog"))((PARAM_GET, 0, "Get Parameter"))(
(PARAM_SET, 255, "Set Parameter"))((REQUEST_HK_TABLE, 16,
"Request Housekeeping Table"))(
(PRINT_SWITCH_V_I, 32, "Print switch states, voltages and currents to the console"))(
(PRINT_LATCHUPS, 33, "Print Latchups to the console")))
namespace P60System {