update for new CAN dbc (incomplete), add more NamedFields, allow mission select without confirmation, set default mission select state to manual
This commit is contained in:
@ -31,7 +31,7 @@ public:
|
||||
|
||||
void setMission(Mission mission);
|
||||
void setASState(ASState state);
|
||||
void setIniChkState(IniChkState state);
|
||||
void setIniChkState(InitialCheckupState state);
|
||||
|
||||
void updateDataFields();
|
||||
void setJetsonTimeout(bool timeout);
|
||||
@ -52,8 +52,6 @@ protected:
|
||||
|
||||
touchgfx::Unicode::UnicodeChar progressBuffer[16];
|
||||
touchgfx::Unicode::UnicodeChar asOKBuffer[16];
|
||||
touchgfx::Shape<3> cones[NUM_CONES] = {cone0, cone1, cone2, cone3, cone4,
|
||||
cone5, cone6, cone7, cone8, cone9};
|
||||
};
|
||||
|
||||
#endif // AMIVIEW_HPP
|
||||
|
||||
@ -9,17 +9,86 @@
|
||||
|
||||
#include "util.h"
|
||||
|
||||
CountedEnum(DataFieldType, size_t, DF_TSState, DF_ASState, DF_ActiveMission,
|
||||
DF_R2DProgress, DF_INVLReady, DF_INVRReady, DF_SDC, DF_ERR,
|
||||
DF_IniChkState, DF_LapCount, DF_TireTempFL, DF_TireTempFR,
|
||||
DF_TireTempRL, DF_TireTempRR, DF_MinCellVolt, DF_MaxCellTemp,
|
||||
DF_TSSoC, DF_LVSoC, DF_TSCurrent, DF_TSVoltageBat, DF_TSVoltageVeh,
|
||||
DF_Speed, DF_BBal, DF_BPF, DF_BPR, DF_DistanceTotal, DF_TempMotL,
|
||||
DF_TempMotR, DF_TempInvL, DF_TempInvR, DF_TempBrakeFL,
|
||||
DF_TempBrakeFR, DF_TempBrakeRL, DF_TempBrakeRR, DF_LapBest,
|
||||
DF_LapLast, DF_LVBatVoltage, DF_GitBuildHash);
|
||||
// clang-format off
|
||||
CountedEnum(DataFieldType, size_t,
|
||||
DF_SlavePanicID,
|
||||
DF_SlavePanicKind,
|
||||
DF_SlavePanicArg,
|
||||
DF_TSState,
|
||||
DF_SDCClosed,
|
||||
DF_TSSoC,
|
||||
DF_MinCellVolt,
|
||||
DF_MaxCellTemp,
|
||||
DF_IMDok,
|
||||
DF_TSALgreen,
|
||||
DF_IMDerr,
|
||||
DF_AMSerr,
|
||||
DF_AMSLastErrorKind,
|
||||
DF_AMSLastErrorArg,
|
||||
DF_DCDCTemp,
|
||||
DF_DCDCCurrent,
|
||||
DF_TSCurrent,
|
||||
DF_TSVoltageBat,
|
||||
DF_TSVoltageVeh,
|
||||
DF_ShuntTemp,
|
||||
DF_TireTempFL,
|
||||
DF_TireTempFR,
|
||||
DF_TireTempRL,
|
||||
DF_TireTempRR,
|
||||
DF_BrakeTempFL,
|
||||
DF_BrakeTempFR,
|
||||
DF_BrakeTempRL,
|
||||
DF_BrakeTempRR,
|
||||
DF_Inv1Temp,
|
||||
DF_Inv2Temp,
|
||||
DF_Mot1Temp,
|
||||
DF_Mot2Temp,
|
||||
DF_LapBest,
|
||||
DF_LapLast,
|
||||
DF_SectorBest,
|
||||
DF_SectorLast,
|
||||
DF_WSSFL,
|
||||
DF_WSSFR,
|
||||
DF_WSSRL,
|
||||
DF_WSSRR,
|
||||
DF_DistanceSession,
|
||||
DF_TankPressure1,
|
||||
DF_TankPressure2,
|
||||
DF_APPSPercent,
|
||||
DF_BPF,
|
||||
DF_BPR,
|
||||
DF_SteeringAngle,
|
||||
DF_Speed,
|
||||
DF_LapCount,
|
||||
DF_SectorCount,
|
||||
DF_R2DProgress,
|
||||
DF_ERR,
|
||||
DF_SDCStatus,
|
||||
DF_INV1Ready,
|
||||
DF_INV2Ready,
|
||||
DF_EnergyPerLap,
|
||||
DF_IniChkState,
|
||||
DF_ActiveMission,
|
||||
DF_ASState,
|
||||
DF_Inv1Velocity,
|
||||
DF_Inv2Velocity,
|
||||
DF_Inv1TorqueDemanded,
|
||||
DF_Inv2TorqueDemanded,
|
||||
DF_Inv1TorqueDesired,
|
||||
DF_Inv2TorqueDesired,
|
||||
DF_Inv1ControlWord,
|
||||
DF_Inv2ControlWord,
|
||||
DF_Inv1TorqueActual,
|
||||
DF_Inv2TorqueActual,
|
||||
DF_Inv1Errors,
|
||||
DF_Inv2Errors,
|
||||
DF_Inv1Warnings,
|
||||
DF_Inv2Warnings,
|
||||
DF_GitBuildHash,
|
||||
);
|
||||
// clang-format on
|
||||
|
||||
enum class NamedFieldKind { Float, Bool, Text, Int };
|
||||
enum class NamedFieldKind { Float, Bool, Text, Int, Hex };
|
||||
|
||||
struct NamedFieldDescription {
|
||||
NamedFieldKind kind;
|
||||
@ -72,6 +141,7 @@ private:
|
||||
void setFloatValue(float floatValue);
|
||||
void setBoolValue(int boolValue);
|
||||
void setIntValue(int intValue);
|
||||
void setHexValue(int hexValue);
|
||||
void setStrValue(const char *strValue);
|
||||
|
||||
void updateValueBuffer();
|
||||
|
||||
@ -16,26 +16,16 @@ void AMIPresenter::deactivate() {}
|
||||
void AMIPresenter::vehicleStateUpdated() {
|
||||
view.setMission(vehicle_state.active_mission);
|
||||
view.setASState(vehicle_state.as_state);
|
||||
view.setIniChkState(vehicle_state.ini_chk_state);
|
||||
view.setIniChkState(vehicle_state.initial_checkup_state);
|
||||
view.updateDataFields();
|
||||
#ifndef SIMULATOR
|
||||
view.setJetsonTimeout(HAL_GetTick() - vehicle_state.last_jetson_msg > 500);
|
||||
view.setEPSCTimeout(HAL_GetTick() - vehicle_state.last_epsc_msg > 500);
|
||||
// TODO
|
||||
// view.setJetsonTimeout(HAL_GetTick() - vehicle_state.last_jetson_msg > 500);
|
||||
// view.setEPSCTimeout(HAL_GetTick() - vehicle_state.last_epsc_msg > 500);
|
||||
#endif
|
||||
|
||||
size_t cone_count = 0;
|
||||
for (; cone_count < NUM_CONES; cone_count++) {
|
||||
// A cone position of 0xFF/0xFF indicates that there are no more cones
|
||||
if (vehicle_state.cone_pos[cone_count].x == 0xFF &&
|
||||
vehicle_state.cone_pos[cone_count].y == 0xFF) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
view.setConePositions(vehicle_state.cone_pos, cone_count);
|
||||
}
|
||||
|
||||
void AMIPresenter::nextScreen() {
|
||||
FrontendApplication *app =
|
||||
static_cast<FrontendApplication *>(FrontendApplication::getInstance());
|
||||
FrontendApplication *app = static_cast<FrontendApplication *>(FrontendApplication::getInstance());
|
||||
app->gotoSDCScreenNoTransition();
|
||||
}
|
||||
|
||||
@ -10,9 +10,7 @@
|
||||
#include "touchgfx/widgets/TextAreaWithWildcard.hpp"
|
||||
#include "vehicle_state.h"
|
||||
|
||||
AMIDataField::AMIDataField(touchgfx::TextAreaWithOneWildcard &textArea,
|
||||
const char *fmt)
|
||||
: fmt(fmt), textArea(textArea) {}
|
||||
AMIDataField::AMIDataField(touchgfx::TextAreaWithOneWildcard &textArea, const char *fmt) : fmt(fmt), textArea(textArea) {}
|
||||
|
||||
void AMIDataField::setValue(float value) {
|
||||
Unicode::snprintfFloat(buffer, sizeof(buffer) / sizeof(*buffer), fmt, value);
|
||||
@ -21,12 +19,9 @@ void AMIDataField::setValue(float value) {
|
||||
}
|
||||
|
||||
AMIView::AMIView()
|
||||
: AMIViewBase(), paField(pressA, "%5.1f"), pbField(pressB, "%5.1f"),
|
||||
pfField(pressFront, "%5.1f"), prField(pressRear, "%5.1f"),
|
||||
desiredAngleField(desiredAngle, "%5.2f"),
|
||||
measuredAngleField(measuredAngle, "%5.2f"),
|
||||
desiredSpeedField(desiredSpeed, "%5.1f"),
|
||||
measuredSpeedField(measuredSpeed, "%5.1f") {}
|
||||
: AMIViewBase(), paField(press1, "%5.1f"), pbField(press1, "%5.1f"), pfField(pressFront, "%5.1f"),
|
||||
prField(pressRear, "%5.1f"), desiredAngleField(desiredAngle, "%5.2f"), measuredAngleField(measuredAngle, "%5.2f"),
|
||||
desiredSpeedField(desiredSpeed, "%5.1f"), measuredSpeedField(measuredSpeed, "%5.1f") {}
|
||||
|
||||
void AMIView::setupScreen() { AMIViewBase::setupScreen(); }
|
||||
|
||||
@ -34,29 +29,29 @@ void AMIView::tearDownScreen() { AMIViewBase::tearDownScreen(); }
|
||||
|
||||
void AMIView::setMission(Mission mission) {
|
||||
switch (mission) {
|
||||
case MISSION_ACCEL:
|
||||
currentMission.setTypedText(TypedText(T_ACCEL_HUGE));
|
||||
break;
|
||||
case MISSION_SKIDPAD:
|
||||
currentMission.setTypedText(TypedText(T_SKIDPAD_HUGE));
|
||||
break;
|
||||
case MISSION_AUTOX:
|
||||
currentMission.setTypedText(TypedText(T_AUTOX_HUGE));
|
||||
break;
|
||||
case MISSION_TRACKDRIVE:
|
||||
currentMission.setTypedText(TypedText(T_TRACKDRIVE_HUGE));
|
||||
break;
|
||||
case MISSION_EBS:
|
||||
currentMission.setTypedText(TypedText(T_EBS_HUGE));
|
||||
break;
|
||||
case MISSION_INSPECTION:
|
||||
currentMission.setTypedText(TypedText(T_INSPECTION_HUGE));
|
||||
break;
|
||||
case MISSION_MANUAL:
|
||||
case MISSION_NONE:
|
||||
default:
|
||||
currentMission.setTypedText(TypedText(T_INVALID_HUGE));
|
||||
break;
|
||||
case MISSION_ACCEL:
|
||||
currentMission.setTypedText(TypedText(T_ACCEL_HUGE));
|
||||
break;
|
||||
case MISSION_SKIDPAD:
|
||||
currentMission.setTypedText(TypedText(T_SKIDPAD_HUGE));
|
||||
break;
|
||||
case MISSION_AUTOX:
|
||||
currentMission.setTypedText(TypedText(T_AUTOX_HUGE));
|
||||
break;
|
||||
case MISSION_TRACKDRIVE:
|
||||
currentMission.setTypedText(TypedText(T_TRACKDRIVE_HUGE));
|
||||
break;
|
||||
case MISSION_BRAKETEST:
|
||||
currentMission.setTypedText(TypedText(T_EBS_HUGE));
|
||||
break;
|
||||
case MISSION_INSPECTION:
|
||||
currentMission.setTypedText(TypedText(T_INSPECTION_HUGE));
|
||||
break;
|
||||
case MISSION_MANUAL:
|
||||
case MISSION_NONE:
|
||||
default:
|
||||
currentMission.setTypedText(TypedText(T_INVALID_HUGE));
|
||||
break;
|
||||
}
|
||||
currentMission.invalidate();
|
||||
}
|
||||
@ -73,7 +68,7 @@ void AMIView::setASState(ASState state) {
|
||||
driving.invalidate();
|
||||
}
|
||||
|
||||
void AMIView::setIniChkState(IniChkState state) {
|
||||
void AMIView::setIniChkState(InitialCheckupState state) {
|
||||
if (state == INICHK_ERROR) {
|
||||
progressBar.setColor(DriverViewStatusItem::COLOR_ERROR);
|
||||
progressBar.setValue(100);
|
||||
@ -83,36 +78,35 @@ void AMIView::setIniChkState(IniChkState state) {
|
||||
progressBar.setValue(100);
|
||||
} else {
|
||||
progressBar.setColor(DriverViewStatusItem::COLOR_OK);
|
||||
float prog = ((float)vehicle_state.ini_chk_state) / INICHK_DONE;
|
||||
float prog = ((float)vehicle_state.initial_checkup_state) / INICHK_DONE;
|
||||
progressBar.setValue(prog * 100);
|
||||
}
|
||||
}
|
||||
progressBar.invalidate();
|
||||
|
||||
const char *label = inichkstate_str(state);
|
||||
touchgfx::Unicode::strncpy(progressBuffer, label,
|
||||
sizeof(progressBuffer) / sizeof(*progressBuffer));
|
||||
touchgfx::Unicode::strncpy(progressBuffer, label, sizeof(progressBuffer) / sizeof(*progressBuffer));
|
||||
progressLabel.setWildcard(progressBuffer);
|
||||
progressLabel.invalidate();
|
||||
}
|
||||
|
||||
void AMIView::updateDataFields() {
|
||||
paField.setValue(vehicle_state.hyd_press_a);
|
||||
pbField.setValue(vehicle_state.hyd_press_b);
|
||||
pfField.setValue(vehicle_state.brake_press_f);
|
||||
prField.setValue(vehicle_state.brake_press_r);
|
||||
paField.setValue(vehicle_state.tank_pressure_1);
|
||||
pbField.setValue(vehicle_state.tank_pressure_2);
|
||||
pfField.setValue(vehicle_state.brake_pressure_f);
|
||||
prField.setValue(vehicle_state.brake_pressure_r);
|
||||
|
||||
desiredAngleField.setValue(vehicle_state.desired_angle);
|
||||
measuredAngleField.setValue(vehicle_state.measured_angle);
|
||||
desiredSpeedField.setValue(vehicle_state.desired_speed);
|
||||
measuredSpeedField.setValue(vehicle_state.speed);
|
||||
// TODO
|
||||
// desiredAngleField.setValue(vehicle_state.desired_angle);
|
||||
// measuredAngleField.setValue(vehicle_state.measured_angle);
|
||||
// desiredSpeedField.setValue(vehicle_state.desired_speed);
|
||||
// measuredSpeedField.setValue(vehicle_state.speed);
|
||||
}
|
||||
|
||||
void AMIView::setJetsonTimeout(bool timeout) {
|
||||
if (timeout) {
|
||||
desiredAngle.setColor(touchgfx::Color::getColorFromRGB(0xFF, 0, 0));
|
||||
touchgfx::Unicode::fromUTF8((const uint8_t *)"TIMEOUT", asOKBuffer,
|
||||
sizeof(asOKBuffer) / sizeof(*asOKBuffer));
|
||||
touchgfx::Unicode::fromUTF8((const uint8_t *)"TIMEOUT", asOKBuffer, sizeof(asOKBuffer) / sizeof(*asOKBuffer));
|
||||
asOK.setWildcard(asOKBuffer);
|
||||
} else {
|
||||
desiredAngle.setColor(touchgfx::Color::getColorFromRGB(0xFF, 0xFF, 0xFF));
|
||||
@ -126,16 +120,3 @@ void AMIView::setEPSCTimeout(bool timeout) {
|
||||
measuredAngle.setColor(touchgfx::Color::getColorFromRGB(0xFF, 0xFF, 0xFF));
|
||||
}
|
||||
}
|
||||
|
||||
void AMIView::setConePositions(ConePosition *cone_positions, size_t count) {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
cones[i].setX(cone_positions[i].x);
|
||||
cones[i].setY(cone_positions[i].y);
|
||||
cones[i].setVisible(true);
|
||||
cones[i].invalidate();
|
||||
}
|
||||
for (size_t i = count; i < NUM_CONES; i++) {
|
||||
cones[i].setVisible(false);
|
||||
cones[i].invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,321 +15,331 @@
|
||||
#ifndef COMPILER_GIT_BUILD_HASH
|
||||
#define COMPILER_GIT_BUILD_HASH "git id not found"
|
||||
#endif
|
||||
static const char* git_hash = STRINGIZE(COMPILER_GIT_BUILD_HASH);
|
||||
static const char *git_hash = STRINGIZE(COMPILER_GIT_BUILD_HASH);
|
||||
|
||||
#define VEH_FIELD(FIELD) []() { return (void *)&vehicle_state.FIELD; }
|
||||
#define VEH_BIT_FIELD(FIELD) \
|
||||
[]() { \
|
||||
static int x; \
|
||||
x = vehicle_state.FIELD; \
|
||||
return (void *)&x; \
|
||||
#define VEH_BIT_FIELD(FIELD) \
|
||||
[]() { \
|
||||
static int x; \
|
||||
x = vehicle_state.FIELD; \
|
||||
return (void *)&x; \
|
||||
}
|
||||
|
||||
void *get_tsstate_text()
|
||||
{
|
||||
void *get_slave_panic_kind_text() {
|
||||
const char *text;
|
||||
switch (vehicle_state.ts_state)
|
||||
{
|
||||
case TS_INACTIVE:
|
||||
text = "INACT";
|
||||
break;
|
||||
case TS_ACTIVE:
|
||||
text = "ACT";
|
||||
break;
|
||||
case TS_PRECHARGE:
|
||||
text = "PRECH";
|
||||
break;
|
||||
case TS_DISCHARGE:
|
||||
text = "DISCH";
|
||||
break;
|
||||
case TS_ERROR:
|
||||
text = "ERROR";
|
||||
break;
|
||||
case TS_CHARGING_CHECK:
|
||||
text = "CH_CHK";
|
||||
break;
|
||||
case TS_CHARGING:
|
||||
text = "CH";
|
||||
break;
|
||||
default:
|
||||
text = "UNKNOWN";
|
||||
switch (vehicle_state.last_ams_slave_panic.kind) {
|
||||
case AMS_SLAVEPANIC_OVERTEMP:
|
||||
text = "OV_TEMP";
|
||||
break;
|
||||
case AMS_SLAVEPANIC_UNDERTEMP:
|
||||
text = "UN_TEMP";
|
||||
break;
|
||||
case AMS_SLAVEPANIC_OVERVOLTAGE:
|
||||
text = "OV_VOLT";
|
||||
break;
|
||||
case AMS_SLAVEPANIC_UNDERVOLTAGE:
|
||||
text = "UN_VOLT";
|
||||
break;
|
||||
case AMS_SLAVEPANIC_TOO_FEW_TEMP:
|
||||
text = "FEWTEMP";
|
||||
break;
|
||||
case AMS_SLAVEPANIC_OPENWIRE:
|
||||
text = "O_WIRE";
|
||||
break;
|
||||
default:
|
||||
text = "UNKNOWN";
|
||||
}
|
||||
return (void *)text;
|
||||
}
|
||||
|
||||
void *get_asstate_text()
|
||||
{
|
||||
void *get_ams_error_kind_text() {
|
||||
const char *text;
|
||||
switch (vehicle_state.as_state)
|
||||
{
|
||||
case AS_OFF:
|
||||
text = "OFF";
|
||||
break;
|
||||
case AS_MANUAL:
|
||||
text = "MAN";
|
||||
break;
|
||||
case AS_READY:
|
||||
text = "RDY";
|
||||
break;
|
||||
case AS_DRIVING:
|
||||
text = "DRIVE";
|
||||
break;
|
||||
case AS_FINISHED:
|
||||
text = "FIN";
|
||||
break;
|
||||
case AS_EMERGENCY:
|
||||
text = "EMERG";
|
||||
break;
|
||||
default:
|
||||
text = "UNKNOWN";
|
||||
switch (vehicle_state.last_ams_slave_panic.kind) {
|
||||
case AMS_ERROR_NONE:
|
||||
text = "NONE";
|
||||
break;
|
||||
case AMS_ERROR_SLAVE_TIMEOUT:
|
||||
text = "SlTout";
|
||||
break;
|
||||
case AMS_ERROR_SHUNT_TIMEOUT:
|
||||
text = "ShTout";
|
||||
break;
|
||||
case AMS_ERROR_SHUNT_OVERCURRENT:
|
||||
text = "ShOCurr";
|
||||
break;
|
||||
case AMS_ERROR_SHUNT_OVERTEMP:
|
||||
text = "ShOTp";
|
||||
break;
|
||||
default:
|
||||
text = "UNKNOWN";
|
||||
}
|
||||
return (void *)text;
|
||||
}
|
||||
|
||||
void *get_mission_text()
|
||||
{
|
||||
void *get_tsstate_text() {
|
||||
const char *text;
|
||||
switch (vehicle_state.active_mission)
|
||||
{
|
||||
case MISSION_NONE:
|
||||
text = "NONE";
|
||||
break;
|
||||
case MISSION_ACCEL:
|
||||
text = "ACCEL";
|
||||
break;
|
||||
case MISSION_SKIDPAD:
|
||||
text = "SKIDPAD";
|
||||
break;
|
||||
case MISSION_AUTOX:
|
||||
text = "AUTOX";
|
||||
break;
|
||||
case MISSION_TRACKDRIVE:
|
||||
text = "TRACK";
|
||||
break;
|
||||
case MISSION_EBS:
|
||||
text = "EBS";
|
||||
break;
|
||||
case MISSION_INSPECTION:
|
||||
text = "INSPECT";
|
||||
break;
|
||||
case MISSION_MANUAL:
|
||||
text = "MAN";
|
||||
break;
|
||||
default:
|
||||
text = "UNKNOWN";
|
||||
switch (vehicle_state.ts_state) {
|
||||
case TS_INACTIVE:
|
||||
text = "INACT";
|
||||
break;
|
||||
case TS_ACTIVE:
|
||||
text = "ACT";
|
||||
break;
|
||||
case TS_PRECHARGE:
|
||||
text = "PRECH";
|
||||
break;
|
||||
case TS_DISCHARGE:
|
||||
text = "DISCH";
|
||||
break;
|
||||
case TS_ERROR:
|
||||
text = "ERROR";
|
||||
break;
|
||||
case TS_CHARGING_CHECK:
|
||||
text = "CH_CHK";
|
||||
break;
|
||||
case TS_CHARGING:
|
||||
text = "CH";
|
||||
break;
|
||||
default:
|
||||
text = "UNKNOWN";
|
||||
}
|
||||
return (void *)text;
|
||||
}
|
||||
|
||||
void *get_r2dprog_text()
|
||||
{
|
||||
void *get_asstate_text() {
|
||||
const char *text;
|
||||
switch (vehicle_state.r2d_progress)
|
||||
{
|
||||
case R2D_NONE:
|
||||
text = "NONE";
|
||||
break;
|
||||
case R2D_TSMS:
|
||||
text = "TSMS";
|
||||
break;
|
||||
case R2D_TSACTIVE:
|
||||
text = "TSACT";
|
||||
break;
|
||||
case R2D_RESETTING_NODES:
|
||||
text = "RST NODE";
|
||||
break;
|
||||
case R2D_RESETTING_COMMS:
|
||||
text = "RST COM";
|
||||
break;
|
||||
case R2D_WAITING_INIT:
|
||||
text = "WAIT INIT";
|
||||
break;
|
||||
case R2D_INIT_STAGE1:
|
||||
text = "INIT S1";
|
||||
break;
|
||||
case R2D_INIT_STAGE2:
|
||||
text = "INIT S2";
|
||||
break;
|
||||
case R2D_INIT_SUCCESS:
|
||||
text = "INIT SUCC";
|
||||
break;
|
||||
default:
|
||||
text = "UNKNOWN";
|
||||
switch (vehicle_state.as_state) {
|
||||
case AS_OFF:
|
||||
text = "OFF";
|
||||
break;
|
||||
case AS_MANUAL:
|
||||
text = "MAN";
|
||||
break;
|
||||
case AS_READY:
|
||||
text = "RDY";
|
||||
break;
|
||||
case AS_DRIVING:
|
||||
text = "DRIVE";
|
||||
break;
|
||||
case AS_FINISHED:
|
||||
text = "FIN";
|
||||
break;
|
||||
case AS_EMERGENCY:
|
||||
text = "EMERG";
|
||||
break;
|
||||
default:
|
||||
text = "UNKNOWN";
|
||||
}
|
||||
return (void *)text;
|
||||
}
|
||||
|
||||
void *get_inichk_text()
|
||||
{
|
||||
return (void *)inichkstate_str(vehicle_state.ini_chk_state);
|
||||
}
|
||||
|
||||
void *get_sdc_text()
|
||||
{
|
||||
void *get_mission_text() {
|
||||
const char *text;
|
||||
if (vehicle_state.errors.sdc_bfl)
|
||||
{
|
||||
text = "BFL";
|
||||
}
|
||||
else if (vehicle_state.errors.sdc_brl)
|
||||
{
|
||||
text = "BRL";
|
||||
}
|
||||
else if (vehicle_state.errors.sdc_acc)
|
||||
{
|
||||
text = "ACC";
|
||||
}
|
||||
else if (vehicle_state.errors.sdc_hvb)
|
||||
{
|
||||
text = "HVB";
|
||||
}
|
||||
else
|
||||
{
|
||||
text = "CLOSED";
|
||||
switch (vehicle_state.active_mission) {
|
||||
case MISSION_NONE:
|
||||
text = "NONE";
|
||||
break;
|
||||
case MISSION_ACCEL:
|
||||
text = "ACCEL";
|
||||
break;
|
||||
case MISSION_SKIDPAD:
|
||||
text = "SKIDPAD";
|
||||
break;
|
||||
case MISSION_AUTOX:
|
||||
text = "AUTOX";
|
||||
break;
|
||||
case MISSION_TRACKDRIVE:
|
||||
text = "TRACK";
|
||||
break;
|
||||
case MISSION_BRAKETEST:
|
||||
text = "EBS";
|
||||
break;
|
||||
case MISSION_INSPECTION:
|
||||
text = "INSPECT";
|
||||
break;
|
||||
case MISSION_MANUAL:
|
||||
text = "MAN";
|
||||
break;
|
||||
default:
|
||||
text = "UNKNOWN";
|
||||
}
|
||||
return (void *)text;
|
||||
}
|
||||
|
||||
void *get_err_text()
|
||||
{
|
||||
void *get_r2dprog_text() {
|
||||
const char *text;
|
||||
if (vehicle_state.errors.err_sdc)
|
||||
{
|
||||
text = "SDC";
|
||||
switch (vehicle_state.r2d_progress) {
|
||||
case R2D_NONE:
|
||||
text = "NONE";
|
||||
break;
|
||||
case R2D_SDC_CLOSED:
|
||||
text = "SDC CL";
|
||||
break;
|
||||
case R2D_TSACTIVE:
|
||||
text = "TSACT";
|
||||
break;
|
||||
case R2D_RESETTING_NODES:
|
||||
text = "RST NODE";
|
||||
break;
|
||||
case R2D_RESETTING_COMMS:
|
||||
text = "RST COM";
|
||||
break;
|
||||
case R2D_WAITING_INIT:
|
||||
text = "WAIT INIT";
|
||||
break;
|
||||
case R2D_INIT_STAGE1:
|
||||
text = "INIT S1";
|
||||
break;
|
||||
case R2D_INIT_STAGE2:
|
||||
text = "INIT S2";
|
||||
break;
|
||||
case R2D_INIT_SUCCESS:
|
||||
text = "INIT SUCC";
|
||||
break;
|
||||
default:
|
||||
text = "UNKNOWN";
|
||||
}
|
||||
else if (vehicle_state.errors.err_ams)
|
||||
{
|
||||
text = "AMS";
|
||||
}
|
||||
else if (vehicle_state.errors.err_pdu)
|
||||
{
|
||||
return (void *)text;
|
||||
}
|
||||
|
||||
void *get_inichk_text() { return (void *)inichkstate_str(vehicle_state.initial_checkup_state); }
|
||||
|
||||
void *get_sdc_text() {
|
||||
const char *text;
|
||||
// if (vehicle_state.errors.sdc_bfl) {
|
||||
// text = "BFL";
|
||||
// } else if (vehicle_state.errors.sdc_brl) {
|
||||
// text = "BRL";
|
||||
// } else if (vehicle_state.errors.sdc_acc) {
|
||||
// text = "ACC";
|
||||
// } else if (vehicle_state.errors.sdc_hvb) {
|
||||
// text = "HVB";
|
||||
// } else {
|
||||
// text = "CLOSED";
|
||||
// }
|
||||
// TODO
|
||||
text = "NA";
|
||||
return (void *)text;
|
||||
}
|
||||
|
||||
void *get_err_text() {
|
||||
const char *text;
|
||||
if (vehicle_state.errors.err_pdu) {
|
||||
text = "PDU";
|
||||
}
|
||||
else if (vehicle_state.errors.err_ini_chk)
|
||||
{
|
||||
text = "IniChk";
|
||||
}
|
||||
else if (vehicle_state.errors.err_con_mon)
|
||||
{
|
||||
text = "ConMon";
|
||||
}
|
||||
else if (vehicle_state.errors.err_scs)
|
||||
{
|
||||
text = "SCS";
|
||||
}
|
||||
else if (vehicle_state.errors.err_sbspd)
|
||||
{
|
||||
text = "sBSPD";
|
||||
}
|
||||
else if (vehicle_state.errors.err_appsp)
|
||||
{
|
||||
text = "APPSp";
|
||||
}
|
||||
else if (vehicle_state.errors.err_as)
|
||||
{
|
||||
text = "AS";
|
||||
}
|
||||
else if (vehicle_state.errors.err_ros)
|
||||
{
|
||||
text = "ROS";
|
||||
}
|
||||
else if (vehicle_state.errors.err_res)
|
||||
{
|
||||
} else if (vehicle_state.errors.err_res) {
|
||||
text = "RES";
|
||||
}
|
||||
else if (vehicle_state.errors.err_invl)
|
||||
{
|
||||
text = "INVL";
|
||||
}
|
||||
else if (vehicle_state.errors.err_invr)
|
||||
{
|
||||
text = "INVR";
|
||||
}
|
||||
else
|
||||
{
|
||||
} else if (vehicle_state.errors.err_as) {
|
||||
text = "AS";
|
||||
} else if (vehicle_state.errors.err_apps_plausible) {
|
||||
text = "APPSp";
|
||||
} else if (vehicle_state.errors.err_soft_bspd) {
|
||||
text = "sBSPD";
|
||||
} else if (vehicle_state.errors.err_scs) {
|
||||
text = "SCS";
|
||||
} else if (vehicle_state.errors.err_con_mon) {
|
||||
text = "ConMon";
|
||||
} else if (vehicle_state.errors.err_initial_checkup) {
|
||||
text = "IniChk";
|
||||
} else if (vehicle_state.errors.err_inv_1) {
|
||||
text = "INV1";
|
||||
} else if (vehicle_state.errors.err_inv_2) {
|
||||
text = "INV2";
|
||||
} else if (vehicle_state.errors.err_ams) {
|
||||
text = "AMS";
|
||||
} else if (vehicle_state.errors.err_sdc) {
|
||||
text = "SDC";
|
||||
} else {
|
||||
text = "NONE";
|
||||
}
|
||||
return (void *)text;
|
||||
}
|
||||
|
||||
void *get_compiler_build_hash()
|
||||
{
|
||||
return (void *)git_hash;
|
||||
}
|
||||
void *get_compiler_build_hash() { return (void *)git_hash; }
|
||||
|
||||
void *get_zero()
|
||||
{
|
||||
void *get_zero() {
|
||||
static float zero = 0.0f;
|
||||
return &zero;
|
||||
}
|
||||
|
||||
// max title length: 7 characters (limited by width of field select dropdown)
|
||||
NamedFieldDescription dataFieldDescs[] = {
|
||||
[DF_SlavePanicID] = {NamedFieldKind::Int, "TSSPID", 2, 0, VEH_FIELD(last_ams_slave_panic.id)},
|
||||
[DF_SlavePanicKind] = {NamedFieldKind::Text, "TSSPKIN", 1, 0, get_slave_panic_kind_text},
|
||||
[DF_SlavePanicArg] = {NamedFieldKind::Hex, "TSSPARG", 1, 0, VEH_FIELD(last_ams_slave_panic.arg)},
|
||||
[DF_TSState] = {NamedFieldKind::Text, "TSSTATE", 1, 0, get_tsstate_text},
|
||||
[DF_ASState] = {NamedFieldKind::Text, "ASSTATE", 1, 0, get_asstate_text},
|
||||
[DF_ActiveMission] = {NamedFieldKind::Text, "MISSION", 1, 0,
|
||||
get_mission_text},
|
||||
[DF_R2DProgress] = {NamedFieldKind::Text, "R2DPROG", 1, 0,
|
||||
get_r2dprog_text},
|
||||
[DF_INVLReady] = {NamedFieldKind::Bool, "INVLRDY", 0, 0,
|
||||
VEH_BIT_FIELD(errors.invl_ready)},
|
||||
[DF_INVRReady] = {NamedFieldKind::Bool, "INVRRDY", 0, 0,
|
||||
VEH_BIT_FIELD(errors.invr_ready)},
|
||||
[DF_SDC] = {NamedFieldKind::Text, "SDC", 0, 0, get_sdc_text},
|
||||
[DF_ERR] = {NamedFieldKind::Text, "ERROR", 0, 0, get_err_text},
|
||||
[DF_IniChkState] = {NamedFieldKind::Text, "ICSTATE", 1, 0, get_inichk_text},
|
||||
[DF_LapCount] = {NamedFieldKind::Int, "LAPS", 3, 0, VEH_FIELD(lap_count)},
|
||||
[DF_TireTempFL] = {NamedFieldKind::Float, "TTFL", 2, 1,
|
||||
VEH_FIELD(temps.tire_fl)},
|
||||
[DF_TireTempFR] = {NamedFieldKind::Float, "TTFR", 2, 1,
|
||||
VEH_FIELD(temps.tire_fr)},
|
||||
[DF_TireTempRL] = {NamedFieldKind::Float, "TTRL", 2, 1,
|
||||
VEH_FIELD(temps.tire_rl)},
|
||||
[DF_TireTempRR] = {NamedFieldKind::Float, "TTRR", 2, 1,
|
||||
VEH_FIELD(temps.tire_rr)},
|
||||
[DF_MinCellVolt] = {NamedFieldKind::Float, "VMIN", 1, 2,
|
||||
VEH_FIELD(min_cell_volt)},
|
||||
[DF_MaxCellTemp] = {NamedFieldKind::Float, "TBAT", 2, 1,
|
||||
VEH_FIELD(max_cell_temp)},
|
||||
[DF_TSSoC] = {NamedFieldKind::Int, "TSSOC", 3, 0, VEH_FIELD(soc_ts)},
|
||||
[DF_LVSoC] = {NamedFieldKind::Int, "LVSOC", 3, 0, VEH_FIELD(soc_lv)},
|
||||
[DF_TSCurrent] = {NamedFieldKind::Float, "ITS", 3, 0,
|
||||
VEH_FIELD(ts_current)},
|
||||
[DF_TSVoltageBat] = {NamedFieldKind::Float, "TSVBAT", 3, 1,
|
||||
VEH_FIELD(ts_voltage_bat)},
|
||||
[DF_TSVoltageVeh] = {NamedFieldKind::Float, "TSVVEH", 3, 1,
|
||||
VEH_FIELD(ts_voltage_veh)},
|
||||
[DF_SDCClosed] = {NamedFieldKind::Bool, "SDCCLOS", 0, 0, VEH_FIELD(sdc_closed)},
|
||||
[DF_TSSoC] = {NamedFieldKind::Int, "TS SoC", 3, 0, VEH_FIELD(soc_ts)},
|
||||
[DF_MinCellVolt] = {NamedFieldKind::Float, "VMIN", 1, 2, VEH_FIELD(min_cell_volt)},
|
||||
[DF_MaxCellTemp] = {NamedFieldKind::Float, "TBAT", 2, 1, VEH_FIELD(max_cell_temp)},
|
||||
[DF_IMDok] = {NamedFieldKind::Bool, "IMD ok", 0, 0, VEH_FIELD(imd_ok)},
|
||||
[DF_TSALgreen] = {NamedFieldKind::Bool, "TSAL gr", 0, 0, VEH_FIELD(tsal_green)},
|
||||
[DF_IMDerr] = {NamedFieldKind::Bool, "IMD err", 0, 0, VEH_FIELD(imd_error)},
|
||||
[DF_AMSerr] = {NamedFieldKind::Bool, "AMS err", 0, 0, VEH_FIELD(ams_error)},
|
||||
[DF_AMSLastErrorKind] = {NamedFieldKind::Text, "AMSeKIN", 1, 0, get_ams_error_kind_text},
|
||||
[DF_AMSLastErrorArg] = {NamedFieldKind::Hex, "AMSeARG", 1, 0, VEH_FIELD(last_ams_error.arg)},
|
||||
[DF_DCDCTemp] = {NamedFieldKind::Float, "TDCDC", 2, 2, VEH_FIELD(dcdc_temp)},
|
||||
[DF_DCDCCurrent] = {NamedFieldKind::Float, "DCDCCur", 2, 2, VEH_FIELD(dcdc_current)},
|
||||
[DF_TSCurrent] = {NamedFieldKind::Float, "I_TS", 3, 0, VEH_FIELD(ts_current)},
|
||||
[DF_TSVoltageBat] = {NamedFieldKind::Float, "TSVBAT", 3, 1, VEH_FIELD(ts_voltage_bat)},
|
||||
[DF_TSVoltageVeh] = {NamedFieldKind::Float, "TSVVEH", 3, 1, VEH_FIELD(ts_voltage_veh)},
|
||||
[DF_ShuntTemp] = {NamedFieldKind::Float, "TShunt", 3, 1, VEH_FIELD(shunt_temperature)},
|
||||
[DF_TireTempFL] = {NamedFieldKind::Float, "TTFL", 2, 1, VEH_FIELD(temps.tire_fl)},
|
||||
[DF_TireTempFR] = {NamedFieldKind::Float, "TTFR", 2, 1, VEH_FIELD(temps.tire_fr)},
|
||||
[DF_TireTempRL] = {NamedFieldKind::Float, "TTRL", 2, 1, VEH_FIELD(temps.tire_rl)},
|
||||
[DF_TireTempRR] = {NamedFieldKind::Float, "TTRR", 2, 1, VEH_FIELD(temps.tire_rr)},
|
||||
[DF_BrakeTempFL] = {NamedFieldKind::Float, "TBFL", 3, 0, VEH_FIELD(temps.brake_fl)},
|
||||
[DF_BrakeTempFR] = {NamedFieldKind::Float, "TBFR", 3, 0, VEH_FIELD(temps.brake_fr)},
|
||||
[DF_BrakeTempRL] = {NamedFieldKind::Float, "TBRL", 3, 0, VEH_FIELD(temps.brake_rl)},
|
||||
[DF_BrakeTempRR] = {NamedFieldKind::Float, "TBRR", 3, 0, VEH_FIELD(temps.brake_rr)},
|
||||
[DF_Inv1Temp] = {NamedFieldKind::Float, "TINV1", 2, 1, VEH_FIELD(temps.inv_1)},
|
||||
[DF_Inv2Temp] = {NamedFieldKind::Float, "TINV2", 2, 1, VEH_FIELD(temps.inv_2)},
|
||||
[DF_Mot1Temp] = {NamedFieldKind::Float, "TMOT1", 2, 1, VEH_FIELD(temps.mot_1)},
|
||||
[DF_Mot2Temp] = {NamedFieldKind::Float, "TMOT2", 2, 1, VEH_FIELD(temps.mot_2)},
|
||||
[DF_LapBest] = {NamedFieldKind::Float, "LAPBEST", 3, 1, VEH_FIELD(lap_time_best)},
|
||||
[DF_LapLast] = {NamedFieldKind::Float, "LAPLAST", 3, 1, VEH_FIELD(lap_time_last)},
|
||||
[DF_SectorBest] = {NamedFieldKind::Float, "SECBEST", 3, 1, VEH_FIELD(sector_time_best)},
|
||||
[DF_SectorLast] = {NamedFieldKind::Float, "SECLAST", 3, 1, VEH_FIELD(sector_time_last)},
|
||||
[DF_WSSFL] = {NamedFieldKind::Float, "WSSFL", 3, 1, VEH_FIELD(wheel_speeds.wss_fl)},
|
||||
[DF_WSSFR] = {NamedFieldKind::Float, "WSSFR", 3, 1, VEH_FIELD(wheel_speeds.wss_fr)},
|
||||
[DF_WSSRL] = {NamedFieldKind::Float, "WSSRL", 3, 1, VEH_FIELD(wheel_speeds.wss_rl)},
|
||||
[DF_WSSRR] = {NamedFieldKind::Float, "WSSRR", 3, 1, VEH_FIELD(wheel_speeds.wss_rr)},
|
||||
[DF_DistanceSession] = {NamedFieldKind::Float, "DIST", 3, 1, VEH_FIELD(distance_session)},
|
||||
[DF_TankPressure1] = {NamedFieldKind::Float, "TnkPrs1", 3, 1, VEH_FIELD(tank_pressure_1)},
|
||||
[DF_TankPressure2] = {NamedFieldKind::Float, "TnkPrs2", 3, 1, VEH_FIELD(tank_pressure_2)},
|
||||
[DF_APPSPercent] = {NamedFieldKind::Int, "APPS", 3, 0, VEH_FIELD(apps_percent)},
|
||||
[DF_BPF] = {NamedFieldKind::Float, "BPF", 3, 1, VEH_FIELD(brake_pressure_f)},
|
||||
[DF_BPR] = {NamedFieldKind::Float, "BPR", 3, 1, VEH_FIELD(brake_pressure_r)},
|
||||
[DF_SteeringAngle] = {NamedFieldKind::Int, "SAS", 3, 0, VEH_FIELD(steering_angle)},
|
||||
[DF_Speed] = {NamedFieldKind::Float, "SPEED", 3, 0, VEH_FIELD(speed)},
|
||||
[DF_BBal] = {NamedFieldKind::Float, "BBAL", 3, 1, get_zero},
|
||||
[DF_BPF] = {NamedFieldKind::Float, "BPF", 3, 1, VEH_FIELD(brake_press_f)},
|
||||
[DF_BPR] = {NamedFieldKind::Float, "BPR", 3, 1, VEH_FIELD(brake_press_r)},
|
||||
[DF_DistanceTotal] = {NamedFieldKind::Float, "DIST", 3, 1,
|
||||
VEH_FIELD(distance_total)},
|
||||
[DF_TempMotL] = {NamedFieldKind::Float, "TMOTL", 2, 1,
|
||||
VEH_FIELD(temps.mot_l)},
|
||||
[DF_TempMotR] = {NamedFieldKind::Float, "TMOTR", 2, 1,
|
||||
VEH_FIELD(temps.mot_r)},
|
||||
[DF_TempInvL] = {NamedFieldKind::Float, "TINVL", 2, 1,
|
||||
VEH_FIELD(temps.inv_l)},
|
||||
[DF_TempInvR] = {NamedFieldKind::Float, "TINVR", 2, 1,
|
||||
VEH_FIELD(temps.inv_r)},
|
||||
[DF_TempBrakeFL] = {NamedFieldKind::Float, "TBFL", 3, 0,
|
||||
VEH_FIELD(temps.brake_fl)},
|
||||
[DF_TempBrakeFR] = {NamedFieldKind::Float, "TBFR", 3, 0,
|
||||
VEH_FIELD(temps.brake_fr)},
|
||||
[DF_TempBrakeRL] = {NamedFieldKind::Float, "TBRL", 3, 0,
|
||||
VEH_FIELD(temps.brake_rl)},
|
||||
[DF_TempBrakeRR] = {NamedFieldKind::Float, "TBRR", 3, 0,
|
||||
VEH_FIELD(temps.brake_rr)},
|
||||
[DF_LapBest] = {NamedFieldKind::Float, "LAPBEST", 3, 1,
|
||||
VEH_FIELD(lap_best)},
|
||||
[DF_LapLast] = {NamedFieldKind::Float, "LAPLAST", 3, 1,
|
||||
VEH_FIELD(lap_last)},
|
||||
[DF_LVBatVoltage] = {NamedFieldKind::Float, "LVVBAT", 2, 2,
|
||||
VEH_FIELD(lv_bat_voltage)},
|
||||
[DF_GitBuildHash] = {NamedFieldKind::Text, "BLDHASH", 1, 0, get_compiler_build_hash}};
|
||||
[DF_LapCount] = {NamedFieldKind::Int, "LAPS", 3, 0, VEH_FIELD(lap_count)},
|
||||
[DF_SectorCount] = {NamedFieldKind::Int, "SECS", 3, 0, VEH_FIELD(sector_count)},
|
||||
[DF_R2DProgress] = {NamedFieldKind::Text, "R2DPROG", 1, 0, get_r2dprog_text},
|
||||
[DF_ERR] = {NamedFieldKind::Text, "ERROR", 0, 0, get_err_text},
|
||||
[DF_SDCStatus] = {NamedFieldKind::Text, "SDC", 0, 0, get_sdc_text},
|
||||
[DF_INV1Ready] = {NamedFieldKind::Bool, "INV1RDY", 0, 0, VEH_FIELD(inv_1_ready)},
|
||||
[DF_INV2Ready] = {NamedFieldKind::Bool, "INV2RDY", 0, 0, VEH_FIELD(inv_2_ready)},
|
||||
[DF_EnergyPerLap] = {NamedFieldKind::Float, "ENGYpLP", 3, 0, VEH_FIELD(energy_per_lap)},
|
||||
[DF_IniChkState] = {NamedFieldKind::Text, "ICSTATE", 1, 0, get_inichk_text},
|
||||
[DF_ActiveMission] = {NamedFieldKind::Text, "MISSION", 1, 0, get_mission_text},
|
||||
[DF_ASState] = {NamedFieldKind::Text, "ASSTATE", 1, 0, get_asstate_text},
|
||||
[DF_Inv1Velocity] = {NamedFieldKind::Int, "INV1Vel", 3, 0, VEH_FIELD(inv_velocity_1)},
|
||||
[DF_Inv2Velocity] = {NamedFieldKind::Int, "INV2Vel", 3, 0, VEH_FIELD(inv_velocity_2)},
|
||||
[DF_Inv1TorqueDemanded] = {NamedFieldKind::Int, "INV1TDe", 3, 0, VEH_FIELD(inv_torque_desired_1)},
|
||||
[DF_Inv2TorqueDemanded] = {NamedFieldKind::Int, "INV2TDe", 3, 0, VEH_FIELD(inv_torque_desired_2)},
|
||||
[DF_Inv1TorqueDesired] = {NamedFieldKind::Int, "INV1TDs", 3, 0, VEH_FIELD(inv_torque_demanded_1)},
|
||||
[DF_Inv2TorqueDesired] = {NamedFieldKind::Int, "INV2TDs", 3, 0, VEH_FIELD(inv_torque_demanded_2)},
|
||||
[DF_Inv1ControlWord] = {NamedFieldKind::Hex, "INV1CW", 3, 0, VEH_FIELD(inv_control_word_1)},
|
||||
[DF_Inv2ControlWord] = {NamedFieldKind::Hex, "INV2CW", 3, 0, VEH_FIELD(inv_control_word_2)},
|
||||
[DF_Inv1TorqueActual] = {NamedFieldKind::Int, "INV1TAc", 3, 0, VEH_FIELD(inv_torque_actual_1)},
|
||||
[DF_Inv2TorqueActual] = {NamedFieldKind::Int, "INV2TAc", 3, 0, VEH_FIELD(inv_torque_actual_2)},
|
||||
[DF_Inv1Errors] = {NamedFieldKind::Hex, "INV1Err", 3, 0, VEH_FIELD(inv_errors_1)},
|
||||
[DF_Inv2Errors] = {NamedFieldKind::Hex, "INV2Err", 3, 0, VEH_FIELD(inv_errors_2)},
|
||||
[DF_Inv1Warnings] = {NamedFieldKind::Hex, "INV1War", 3, 0, VEH_FIELD(inv_warnings_1)},
|
||||
[DF_Inv2Warnings] = {NamedFieldKind::Hex, "INV2War", 3, 0, VEH_FIELD(inv_warnings_2)},
|
||||
[DF_GitBuildHash] = {NamedFieldKind::Text, "BLDHASH", 1, 0, get_compiler_build_hash},
|
||||
};
|
||||
|
||||
static_assert(sizeof(dataFieldDescs) / sizeof(dataFieldDescs[0]) ==
|
||||
DataFieldType_COUNT,
|
||||
static_assert(sizeof(dataFieldDescs) / sizeof(dataFieldDescs[0]) == DataFieldType_COUNT,
|
||||
"Incorrect number of data field descriptions");
|
||||
|
||||
#define PARAM_FIELD(FIELD) []() { return (void *)¶ms.FIELD; }
|
||||
@ -343,8 +353,7 @@ NamedFieldDescription paramFieldDescs[] = {
|
||||
[PF_REKU] = {NamedFieldKind::Int, "REKU", 2, 0, PARAM_FIELD(reku)},
|
||||
};
|
||||
|
||||
static_assert(sizeof(paramFieldDescs) / sizeof(paramFieldDescs[0]) ==
|
||||
ParamType_COUNT,
|
||||
static_assert(sizeof(paramFieldDescs) / sizeof(paramFieldDescs[0]) == ParamType_COUNT,
|
||||
"Incorrect number of param field descriptions");
|
||||
|
||||
DataFieldType dataFieldByAlphaIndex[DataFieldType_COUNT];
|
||||
@ -352,148 +361,116 @@ size_t dataFieldAlphaIndexByField[DataFieldType_COUNT];
|
||||
ParamType paramByAlphaIndex[ParamType_COUNT];
|
||||
size_t paramAlphaIndexByParam[ParamType_COUNT];
|
||||
|
||||
template <class T>
|
||||
struct NFAlphabeticComp
|
||||
{
|
||||
NFAlphabeticComp(const NamedFieldDescription *fieldDescs)
|
||||
: fieldDescs{fieldDescs} {}
|
||||
template <class T> struct NFAlphabeticComp {
|
||||
NFAlphabeticComp(const NamedFieldDescription *fieldDescs) : fieldDescs{fieldDescs} {}
|
||||
|
||||
const NamedFieldDescription *fieldDescs;
|
||||
|
||||
bool operator()(const T &a, const T &b) const
|
||||
{
|
||||
return strcmp(fieldDescs[a].title, fieldDescs[b].title) < 0;
|
||||
}
|
||||
bool operator()(const T &a, const T &b) const { return strcmp(fieldDescs[a].title, fieldDescs[b].title) < 0; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void namedFieldSort(const NamedFieldDescription *fieldDescs, T *fieldByAlpha,
|
||||
size_t *alphaIndexByField, size_t numFields)
|
||||
{
|
||||
for (size_t i = 0; i < numFields; i++)
|
||||
{
|
||||
void namedFieldSort(const NamedFieldDescription *fieldDescs, T *fieldByAlpha, size_t *alphaIndexByField, size_t numFields) {
|
||||
for (size_t i = 0; i < numFields; i++) {
|
||||
fieldByAlpha[i] = static_cast<T>(i);
|
||||
}
|
||||
std::sort(fieldByAlpha, fieldByAlpha + numFields,
|
||||
NFAlphabeticComp<T>(fieldDescs));
|
||||
for (size_t i = 0; i < numFields; i++)
|
||||
{
|
||||
std::sort(fieldByAlpha, fieldByAlpha + numFields, NFAlphabeticComp<T>(fieldDescs));
|
||||
for (size_t i = 0; i < numFields; i++) {
|
||||
alphaIndexByField[fieldByAlpha[i]] = i;
|
||||
}
|
||||
}
|
||||
|
||||
void namedFieldSort()
|
||||
{
|
||||
namedFieldSort(dataFieldDescs, dataFieldByAlphaIndex,
|
||||
dataFieldAlphaIndexByField, DataFieldType_COUNT);
|
||||
namedFieldSort(paramFieldDescs, paramByAlphaIndex, paramAlphaIndexByParam,
|
||||
ParamType_COUNT);
|
||||
void namedFieldSort() {
|
||||
namedFieldSort(dataFieldDescs, dataFieldByAlphaIndex, dataFieldAlphaIndexByField, DataFieldType_COUNT);
|
||||
namedFieldSort(paramFieldDescs, paramByAlphaIndex, paramAlphaIndexByParam, ParamType_COUNT);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
NamedField<T>::NamedField(const NamedFieldDescription *fieldDescs)
|
||||
: fieldDescs{fieldDescs} {}
|
||||
template <class T> NamedField<T>::NamedField(const NamedFieldDescription *fieldDescs) : fieldDescs{fieldDescs} {}
|
||||
|
||||
template <class T>
|
||||
void NamedField<T>::setType(T type)
|
||||
{
|
||||
template <class T> void NamedField<T>::setType(T type) {
|
||||
this->type = type;
|
||||
desc = &fieldDescs[type];
|
||||
|
||||
touchgfx::Unicode::strncpy(titleBuffer, desc->title,
|
||||
sizeof(titleBuffer) / sizeof(*titleBuffer));
|
||||
touchgfx::Unicode::strncpy(titleBuffer, desc->title, sizeof(titleBuffer) / sizeof(*titleBuffer));
|
||||
titleBufferUpdated();
|
||||
|
||||
typeUpdated();
|
||||
updateValue();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
const T &NamedField<T>::getType() { return type; }
|
||||
template <class T> const T &NamedField<T>::getType() { return type; }
|
||||
|
||||
template <class T>
|
||||
void NamedField<T>::updateValue()
|
||||
{
|
||||
template <class T> void NamedField<T>::updateValue() {
|
||||
void *val = desc->getValue();
|
||||
switch (desc->kind)
|
||||
{
|
||||
case NamedFieldKind::Float:
|
||||
setFloatValue(*static_cast<float *>(val));
|
||||
break;
|
||||
case NamedFieldKind::Bool:
|
||||
setBoolValue(*static_cast<int *>(val));
|
||||
break;
|
||||
case NamedFieldKind::Text:
|
||||
setStrValue(static_cast<const char *>(val));
|
||||
break;
|
||||
case NamedFieldKind::Int:
|
||||
setIntValue(*static_cast<int *>(val));
|
||||
break;
|
||||
switch (desc->kind) {
|
||||
case NamedFieldKind::Float:
|
||||
setFloatValue(*static_cast<float *>(val));
|
||||
break;
|
||||
case NamedFieldKind::Bool:
|
||||
setBoolValue(*static_cast<int *>(val));
|
||||
break;
|
||||
case NamedFieldKind::Text:
|
||||
setStrValue(static_cast<const char *>(val));
|
||||
break;
|
||||
case NamedFieldKind::Int:
|
||||
setIntValue(*static_cast<int *>(val));
|
||||
break;
|
||||
case NamedFieldKind::Hex:
|
||||
setHexValue(*static_cast<int *>(val));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void NamedField<T>::setFloatValue(float floatValue)
|
||||
{
|
||||
template <class T> void NamedField<T>::setFloatValue(float floatValue) {
|
||||
fieldValue.f = floatValue;
|
||||
updateValueBuffer();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void NamedField<T>::setBoolValue(int boolValue)
|
||||
{
|
||||
template <class T> void NamedField<T>::setBoolValue(int boolValue) {
|
||||
fieldValue.b = boolValue;
|
||||
updateValueBuffer();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void NamedField<T>::setIntValue(int intValue)
|
||||
{
|
||||
template <class T> void NamedField<T>::setIntValue(int intValue) {
|
||||
fieldValue.i = intValue;
|
||||
updateValueBuffer();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void NamedField<T>::setStrValue(const char *strValue)
|
||||
{
|
||||
touchgfx::Unicode::strncpy(valueBuffer, strValue,
|
||||
sizeof(valueBuffer) / sizeof(*valueBuffer));
|
||||
template <class T> void NamedField<T>::setHexValue(int hexValue) {
|
||||
fieldValue.i = hexValue;
|
||||
updateValueBuffer();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void NamedField<T>::updateValueBuffer()
|
||||
{
|
||||
switch (desc->kind)
|
||||
{
|
||||
case NamedFieldKind::Float:
|
||||
{
|
||||
size_t width = desc->int_digits;
|
||||
if (desc->decimal_digits != 0)
|
||||
{
|
||||
width += desc->decimal_digits + 1; // 1 digit for the decimal point
|
||||
template <class T> void NamedField<T>::setStrValue(const char *strValue) {
|
||||
touchgfx::Unicode::strncpy(valueBuffer, strValue, sizeof(valueBuffer) / sizeof(*valueBuffer));
|
||||
updateValueBuffer();
|
||||
}
|
||||
|
||||
template <class T> void NamedField<T>::updateValueBuffer() {
|
||||
switch (desc->kind) {
|
||||
case NamedFieldKind::Float: {
|
||||
size_t width = desc->int_digits;
|
||||
if (desc->decimal_digits != 0) {
|
||||
width += desc->decimal_digits + 1; // 1 digit for the decimal point
|
||||
}
|
||||
float params[3] = {(float)width, (float)desc->decimal_digits, fieldValue.f};
|
||||
touchgfx::Unicode::snprintfFloats(valueBuffer, sizeof(valueBuffer) / sizeof(*valueBuffer), "%*.*f", params);
|
||||
break;
|
||||
}
|
||||
float params[3] = {(float)width, (float)desc->decimal_digits, fieldValue.f};
|
||||
touchgfx::Unicode::snprintfFloats(
|
||||
valueBuffer, sizeof(valueBuffer) / sizeof(*valueBuffer), "%*.*f",
|
||||
params);
|
||||
break;
|
||||
}
|
||||
case NamedFieldKind::Bool:
|
||||
{
|
||||
const char *str = fieldValue.b ? "YES" : "NO";
|
||||
touchgfx::Unicode::strncpy(valueBuffer, str,
|
||||
sizeof(valueBuffer) / sizeof(*valueBuffer));
|
||||
break;
|
||||
}
|
||||
case NamedFieldKind::Text:
|
||||
// This is handled by the child class in setValue()
|
||||
break;
|
||||
case NamedFieldKind::Int:
|
||||
touchgfx::Unicode::snprintf(valueBuffer,
|
||||
sizeof(valueBuffer) / sizeof(*valueBuffer),
|
||||
"%*d", desc->int_digits, fieldValue.i);
|
||||
break;
|
||||
case NamedFieldKind::Bool: {
|
||||
const char *str = fieldValue.b ? "YES" : "NO";
|
||||
touchgfx::Unicode::strncpy(valueBuffer, str, sizeof(valueBuffer) / sizeof(*valueBuffer));
|
||||
break;
|
||||
}
|
||||
case NamedFieldKind::Text:
|
||||
// This is handled by the child class in setValue()
|
||||
break;
|
||||
case NamedFieldKind::Int:
|
||||
touchgfx::Unicode::snprintf(valueBuffer, sizeof(valueBuffer) / sizeof(*valueBuffer), "%*d", desc->int_digits, fieldValue.i);
|
||||
break;
|
||||
case NamedFieldKind::Hex:
|
||||
touchgfx::Unicode::snprintf(valueBuffer, sizeof(valueBuffer) / sizeof(*valueBuffer), "%X", desc->int_digits, fieldValue.i);
|
||||
break;
|
||||
}
|
||||
valueBufferUpdated();
|
||||
}
|
||||
|
||||
@ -23,14 +23,15 @@ void ConfigItem::setDirty(bool dirty) {
|
||||
|
||||
void ConfigItem::typeUpdated() {
|
||||
switch (desc->kind) {
|
||||
case NamedFieldKind::Float:
|
||||
case NamedFieldKind::Int:
|
||||
value.setTypedText(T_NUMBERWILDCARD);
|
||||
break;
|
||||
case NamedFieldKind::Bool:
|
||||
case NamedFieldKind::Text:
|
||||
value.setTypedText(T_DEFAULTWILDCARD_CENTERED);
|
||||
break;
|
||||
case NamedFieldKind::Float:
|
||||
case NamedFieldKind::Int:
|
||||
value.setTypedText(T_NUMBERWILDCARD);
|
||||
break;
|
||||
case NamedFieldKind::Hex:
|
||||
case NamedFieldKind::Bool:
|
||||
case NamedFieldKind::Text:
|
||||
value.setTypedText(T_DEFAULTWILDCARD_CENTERED);
|
||||
break;
|
||||
}
|
||||
value.invalidate();
|
||||
}
|
||||
|
||||
@ -17,14 +17,15 @@ void DriverViewField::setSelected(int selected) {
|
||||
|
||||
void DriverViewField::typeUpdated() {
|
||||
switch (desc->kind) {
|
||||
case NamedFieldKind::Float:
|
||||
case NamedFieldKind::Int:
|
||||
value.setTypedText(T_NUMBERWILDCARD);
|
||||
break;
|
||||
case NamedFieldKind::Bool:
|
||||
case NamedFieldKind::Text:
|
||||
value.setTypedText(T_DEFAULTWILDCARD_CENTERED);
|
||||
break;
|
||||
case NamedFieldKind::Float:
|
||||
case NamedFieldKind::Int:
|
||||
value.setTypedText(T_NUMBERWILDCARD);
|
||||
break;
|
||||
case NamedFieldKind::Hex:
|
||||
case NamedFieldKind::Bool:
|
||||
case NamedFieldKind::Text:
|
||||
value.setTypedText(T_DEFAULTWILDCARD_CENTERED);
|
||||
break;
|
||||
}
|
||||
value.invalidate();
|
||||
}
|
||||
|
||||
@ -6,68 +6,65 @@
|
||||
|
||||
DriverViewStatusItem::DriverViewStatusItem() {}
|
||||
|
||||
void DriverViewStatusItem::initialize() {
|
||||
DriverViewStatusItemBase::initialize();
|
||||
}
|
||||
void DriverViewStatusItem::initialize() { DriverViewStatusItemBase::initialize(); }
|
||||
|
||||
void DriverViewStatusItem::setType(DriverViewStatusType type) {
|
||||
this->type = type;
|
||||
}
|
||||
void DriverViewStatusItem::setType(DriverViewStatusType type) { this->type = type; }
|
||||
|
||||
void DriverViewStatusItem::update() {
|
||||
switch (type) {
|
||||
case DriverViewStatusType::TS_R2D:
|
||||
if (vehicle_state.ts_state == TS_ERROR) {
|
||||
text.setTypedText(T_TS);
|
||||
bg.setColor(COLOR_ERROR);
|
||||
} else if (vehicle_state.ts_state == TS_INACTIVE) {
|
||||
text.setTypedText(T_TS);
|
||||
bg.setColor(COLOR_OFF);
|
||||
} else if (vehicle_state.r2d_progress == R2D_INIT_SUCCESS) {
|
||||
text.setTypedText(T_R2D);
|
||||
case DriverViewStatusType::TS_R2D:
|
||||
if (vehicle_state.ts_state == TS_ERROR) {
|
||||
text.setTypedText(T_TS);
|
||||
bg.setColor(COLOR_ERROR);
|
||||
} else if (vehicle_state.ts_state == TS_INACTIVE) {
|
||||
text.setTypedText(T_TS);
|
||||
bg.setColor(COLOR_OFF);
|
||||
} else if (vehicle_state.r2d_progress == R2D_INIT_SUCCESS) {
|
||||
text.setTypedText(T_R2D);
|
||||
bg.setColor(COLOR_OK);
|
||||
} else {
|
||||
text.setTypedText(T_TS);
|
||||
bg.setColor(COLOR_TS);
|
||||
}
|
||||
break;
|
||||
case DriverViewStatusType::AMS:
|
||||
text.setTypedText(T_AMS);
|
||||
bg.setColor(vehicle_state.ts_state == TS_ERROR ? COLOR_ERROR : COLOR_OK);
|
||||
break;
|
||||
case DriverViewStatusType::SDC:
|
||||
text.setTypedText(T_SDC);
|
||||
bg.setColor(vehicle_state.sdc_closed ? COLOR_OK : COLOR_WARNING);
|
||||
break;
|
||||
case DriverViewStatusType::SCS:
|
||||
text.setTypedText(T_SCS);
|
||||
bg.setColor(vehicle_state.errors.err_scs ? COLOR_ERROR : COLOR_OK);
|
||||
break;
|
||||
case DriverViewStatusType::PDU:
|
||||
text.setTypedText(T_PDU);
|
||||
bg.setColor(vehicle_state.errors.err_pdu ? COLOR_ERROR : COLOR_OK);
|
||||
break;
|
||||
case DriverViewStatusType::INV:
|
||||
text.setTypedText(T_INV);
|
||||
if (vehicle_state.errors.err_inv_1 || vehicle_state.errors.err_inv_2) {
|
||||
bg.setColor(COLOR_ERROR);
|
||||
} else if (vehicle_state.inv_1_ready && vehicle_state.inv_2_ready) {
|
||||
bg.setColor(COLOR_OK);
|
||||
} else {
|
||||
bg.setColor(COLOR_OFF);
|
||||
}
|
||||
break;
|
||||
case DriverViewStatusType::LV:
|
||||
text.setTypedText(T_LV);
|
||||
// if (vehicle_state.soc_lv < 10) {
|
||||
// bg.setColor(COLOR_ERROR);
|
||||
// } else if (vehicle_state.soc_lv < 30) {
|
||||
// bg.setColor(COLOR_WARNING);
|
||||
// } else {
|
||||
// bg.setColor(COLOR_OK);
|
||||
// }
|
||||
// TODO
|
||||
bg.setColor(COLOR_OK);
|
||||
} else {
|
||||
text.setTypedText(T_TS);
|
||||
bg.setColor(COLOR_TS);
|
||||
}
|
||||
break;
|
||||
case DriverViewStatusType::AMS:
|
||||
text.setTypedText(T_AMS);
|
||||
bg.setColor(vehicle_state.ts_state == TS_ERROR ? COLOR_ERROR : COLOR_OK);
|
||||
break;
|
||||
case DriverViewStatusType::SDC:
|
||||
text.setTypedText(T_SDC);
|
||||
bg.setColor(vehicle_state.sdc_closed ? COLOR_OK : COLOR_WARNING);
|
||||
break;
|
||||
case DriverViewStatusType::SCS:
|
||||
text.setTypedText(T_SCS);
|
||||
bg.setColor(vehicle_state.errors.err_scs ? COLOR_ERROR : COLOR_OK);
|
||||
break;
|
||||
case DriverViewStatusType::PDU:
|
||||
text.setTypedText(T_PDU);
|
||||
bg.setColor(vehicle_state.errors.err_pdu ? COLOR_ERROR : COLOR_OK);
|
||||
break;
|
||||
case DriverViewStatusType::INV:
|
||||
text.setTypedText(T_INV);
|
||||
if (vehicle_state.errors.err_invl || vehicle_state.errors.err_invr) {
|
||||
bg.setColor(COLOR_ERROR);
|
||||
} else if (vehicle_state.errors.invl_ready &&
|
||||
vehicle_state.errors.invr_ready) {
|
||||
bg.setColor(COLOR_OK);
|
||||
} else {
|
||||
bg.setColor(COLOR_OFF);
|
||||
}
|
||||
break;
|
||||
case DriverViewStatusType::LV:
|
||||
text.setTypedText(T_LV);
|
||||
if (vehicle_state.soc_lv < 10) {
|
||||
bg.setColor(COLOR_ERROR);
|
||||
} else if (vehicle_state.soc_lv < 30) {
|
||||
bg.setColor(COLOR_WARNING);
|
||||
} else {
|
||||
bg.setColor(COLOR_OK);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
text.invalidate();
|
||||
bg.invalidate();
|
||||
|
||||
@ -7,23 +7,21 @@
|
||||
#include "vehicle.h"
|
||||
#include "vehicle_state.h"
|
||||
|
||||
MissionSelectView::MissionSelectView()
|
||||
: selected{nullptr}, selectedMission{MISSION_NONE} {}
|
||||
MissionSelectView::MissionSelectView() : selected{nullptr}, selectedMission{MISSION_NONE} {}
|
||||
|
||||
void MissionSelectView::setupScreen() {
|
||||
MissionSelectViewBase::setupScreen();
|
||||
accel.setUp(0, T_ACCEL);
|
||||
skidpad.setUp(1, T_SKIDPAD);
|
||||
autox.setUp(2, T_AUTOX);
|
||||
trackdrive.setUp(3, T_TRACKDRIVE);
|
||||
ebs.setUp(4, T_EBS);
|
||||
inspection.setUp(5, T_INSPECTION);
|
||||
trackdrive.setUp(2, T_TRACKDRIVE);
|
||||
ebs.setUp(3, T_EBS);
|
||||
inspection.setUp(4, T_INSPECTION);
|
||||
autox.setUp(5, T_AUTOX);
|
||||
manual.setUp(6, T_MANUAL);
|
||||
decMission();
|
||||
}
|
||||
|
||||
void MissionSelectView::tearDownScreen() {
|
||||
MissionSelectViewBase::tearDownScreen();
|
||||
}
|
||||
void MissionSelectView::tearDownScreen() { MissionSelectViewBase::tearDownScreen(); }
|
||||
|
||||
void MissionSelectView::incMission() {
|
||||
int mission_int = static_cast<int>(selectedMission);
|
||||
@ -56,14 +54,14 @@ void MissionSelectView::confirmMission() {
|
||||
}
|
||||
vehicle_select_mission(selectedMission);
|
||||
|
||||
#ifdef DEMO_MODE
|
||||
// #ifdef DEMO_MODE
|
||||
vehicle_state.active_mission = selectedMission;
|
||||
presenter->vehicleStateUpdated();
|
||||
#endif
|
||||
// #endif
|
||||
|
||||
#ifdef SIMULATOR
|
||||
#ifdef SIMULATOR
|
||||
vehicle_state.active_mission = selectedMission;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void MissionSelectView::setSelectedMission(Mission mission) {
|
||||
@ -72,29 +70,29 @@ void MissionSelectView::setSelectedMission(Mission mission) {
|
||||
}
|
||||
|
||||
switch (mission) {
|
||||
case MISSION_NONE:
|
||||
break;
|
||||
case MISSION_ACCEL:
|
||||
selected = &accel;
|
||||
break;
|
||||
case MISSION_SKIDPAD:
|
||||
selected = &skidpad;
|
||||
break;
|
||||
case MISSION_AUTOX:
|
||||
selected = &autox;
|
||||
break;
|
||||
case MISSION_TRACKDRIVE:
|
||||
selected = &trackdrive;
|
||||
break;
|
||||
case MISSION_EBS:
|
||||
selected = &ebs;
|
||||
break;
|
||||
case MISSION_INSPECTION:
|
||||
selected = &inspection;
|
||||
break;
|
||||
case MISSION_MANUAL:
|
||||
selected = &manual;
|
||||
break;
|
||||
case MISSION_NONE:
|
||||
break;
|
||||
case MISSION_ACCEL:
|
||||
selected = &accel;
|
||||
break;
|
||||
case MISSION_SKIDPAD:
|
||||
selected = &skidpad;
|
||||
break;
|
||||
case MISSION_AUTOX:
|
||||
selected = &autox;
|
||||
break;
|
||||
case MISSION_TRACKDRIVE:
|
||||
selected = &trackdrive;
|
||||
break;
|
||||
case MISSION_BRAKETEST:
|
||||
selected = &ebs;
|
||||
break;
|
||||
case MISSION_INSPECTION:
|
||||
selected = &inspection;
|
||||
break;
|
||||
case MISSION_MANUAL:
|
||||
selected = &manual;
|
||||
break;
|
||||
}
|
||||
selected->setSelected(true);
|
||||
selectedMission = mission;
|
||||
|
||||
@ -10,18 +10,18 @@ void SDCPresenter::activate() { vehicleStateUpdated(); }
|
||||
void SDCPresenter::deactivate() {}
|
||||
|
||||
void SDCPresenter::vehicleStateUpdated() {
|
||||
view.setPDUClosed(vehicle_state.pdu_sdc_active);
|
||||
view.setInertiaClosed(vehicle_state.sdcl_state[1]);
|
||||
// TODO
|
||||
view.setPDUClosed(true);
|
||||
view.setInertiaClosed(true);
|
||||
view.setIMDClosed(vehicle_state.imd_ok);
|
||||
view.setAMSClosed(vehicle_state.ts_state != TS_ERROR);
|
||||
view.setSDCLClosed(vehicle_state.sdcl_state[0]);
|
||||
view.setHVBClosed(vehicle_state.sdcl_state[2]);
|
||||
view.setSDCLClosed(true);
|
||||
view.setHVBClosed(true);
|
||||
view.setTSMSClosed(true);
|
||||
view.setAccClosed(vehicle_state.sdc_closed);
|
||||
}
|
||||
|
||||
void SDCPresenter::nextScreen() {
|
||||
FrontendApplication *app =
|
||||
static_cast<FrontendApplication *>(FrontendApplication::getInstance());
|
||||
FrontendApplication *app = static_cast<FrontendApplication *>(FrontendApplication::getInstance());
|
||||
app->gotoDebugViewScreenNoTransition();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user