Files
edgetx-gx12/companion/src/firmwares/boardjson.cpp
T

1318 lines
38 KiB
C++

/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "boardjson.h"
#include "datahelpers.h"
#include "constants.h"
#include <QMessageBox>
static const StringTagMappingTable inputTypesLookupTable = {
{std::to_string(Board::AIT_NONE), "NONE"},
{std::to_string(Board::AIT_STICK), "STICK"},
{std::to_string(Board::AIT_FLEX), "FLEX"},
{std::to_string(Board::AIT_VBAT), "VBAT"},
{std::to_string(Board::AIT_RTC_BAT), "RTC_BAT"},
{std::to_string(Board::AIT_LUX), "LUX"},
{std::to_string(Board::AIT_SWITCH), "SWITCH"},
};
static const StringTagMappingTable flexTypesLookupTable = {
{std::to_string(Board::FLEX_NONE), "NONE"},
{std::to_string(Board::FLEX_POT), "POT"},
{std::to_string(Board::FLEX_POT_CENTER), "POT_CENTER"},
{std::to_string(Board::FLEX_SLIDER), "SLIDER"},
{std::to_string(Board::FLEX_MULTIPOS), "MULTIPOS"},
{std::to_string(Board::FLEX_AXIS_X), "AXIS_X"},
{std::to_string(Board::FLEX_AXIS_Y), "AXIS_Y"},
{std::to_string(Board::FLEX_SWITCH), "SWITCH"},
};
static const StringTagMappingTable switchTypesLookupTable = {
{std::to_string(Board::SWITCH_NOT_AVAILABLE), "NONE"},
{std::to_string(Board::SWITCH_TOGGLE), "TOGGLE"},
{std::to_string(Board::SWITCH_2POS), "2POS"},
{std::to_string(Board::SWITCH_3POS), "3POS"},
{std::to_string(Board::SWITCH_ADC), "ADC"},
};
static const StringTagMappingTable stickNamesLookupTable = {
{QCoreApplication::translate("BoardJson", "Rud").toStdString(), "LH"}, // air
{QCoreApplication::translate("BoardJson", "Ele").toStdString(), "LV"}, // air
{QCoreApplication::translate("BoardJson", "Thr").toStdString(), "RV"}, // air
{QCoreApplication::translate("BoardJson", "Ail").toStdString(), "RH"}, // air
{QCoreApplication::translate("BoardJson", "ST").toStdString(), "ST"}, // surface
{QCoreApplication::translate("BoardJson", "TH").toStdString(), "TH"}, // surface
};
BoardJson::BoardJson(Board::Type board, QString hwdefn) :
m_board(board),
m_hwdefn(hwdefn),
m_inputs(new InputsTable),
m_switches(new SwitchesTable),
m_trims(new TrimsTable),
m_keys(new KeysTable),
m_display({0, 0, 0, 0, 0, 0, 0, 0}),
m_cfs({0, 0}),
m_hardware({0, 0, 0}),
m_inputCnt({0, 0, 0, 0, 0, 0, 0, 0, 0}),
m_switchCnt({0, 0, 0})
{
}
BoardJson::~BoardJson()
{
delete m_inputs;
delete m_switches;
delete m_trims;
delete m_keys;
}
// static
void BoardJson::afterLoadFixups(Board::Type board, InputsTable * inputs, SwitchesTable * switches,
KeysTable * keys, TrimsTable * trims)
{
// TODO json files do not contain gyro defs
// Radio cmake directive IMU is currently used
if (IS_TARANIS_XLITES(board) || IS_FAMILY_HORUS_OR_T16(board) || IS_RADIOMASTER_TX15(board)) {
if (getInputIndex(inputs, "TILT_X", Board::LVT_TAG) < 0) {
InputDefn defn;
defn.type = AIT_FLEX;
defn.tag = "TILT_X";
defn.name = "Tltx";
defn.shortName = "X";
defn.flexType = FLEX_AXIS_X;
defn.inverted = false;
defn.cfgYaml = Board::LVT_TAG;
defn.refYaml = Board::LVT_TAG; // non-default
inputs->insert(inputs->end(), defn);
}
if (getInputIndex(inputs, "TILT_Y", Board::LVT_TAG) < 0) {
InputDefn defn;
defn.type = AIT_FLEX;
defn.tag = "TILT_Y";
defn.name = "Tlty";
defn.shortName = "Y";
defn.flexType = FLEX_AXIS_Y;
defn.inverted = false;
defn.cfgYaml = Board::LVT_TAG;
defn.refYaml = Board::LVT_TAG; // non-default
inputs->insert(inputs->end(), defn);
}
}
// Set default labels for LUX inputs if not provided by JSON
for (auto &defn : *inputs) {
if (defn.type == AIT_LUX) {
if (defn.name.empty())
defn.name = "Ambient light";
if (defn.shortName.empty())
defn.shortName = "Light";
}
}
// Flex switches are not listed in json file for these radios
int count = IS_RADIOMASTER_TX16S(board) || IS_RADIOMASTER_MT12(board) ? 2 : 0;
for (int i = 1; i <= count; i++) {
QString tag = QString("FL%1").arg(i);
if (getSwitchIndex(switches, tag, Board::LVT_TAG) < 0) {
SwitchDefn defn;
defn.tag = tag.toStdString();
defn.name = defn.tag;
switches->insert(switches->end(), defn);
}
}
}
// called from Boards::getCapability if no capability match
// WARNING - potential for infinite loop if Boards::getCapability(m_board, capability) called from here!!!!!
const int BoardJson::getCapability(const Board::Capability capability) const
{
switch (capability) {
case Board::Air:
return !m_hardware.surface;
case Board::FlexInputs:
return (m_inputCnt.flexGyroAxes +
m_inputCnt.flexJoystickAxes +
m_inputCnt.flexPots +
m_inputCnt.flexSliders +
m_inputCnt.flexSwitches);
case Board::FlexSwitches:
return m_switchCnt.flex;
case Board::FunctionSwitchColors:
return m_cfs.rgb_led;
case Board::FunctionSwitches:
return m_switchCnt.func;
case Board::FunctionSwitchGroups:
return m_cfs.groups;
case Board::GyroAxes:
return m_inputCnt.flexGyroAxes;
case Board::Gyros:
return getCapability(Board::GyroAxes) / 2;
case Board::HasAudioMuteGPIO:
return m_hardware.has_audio_mute;
case Board::HasBacklightColor:
return m_display.backlight_color;
case Board::HasBlingLEDS:
return m_hardware.has_bling_leds;
case Board::HasColorLcd:
return m_display.color;
case Board::HasExternalModuleSupport:
return m_hardware.has_ext_module_support;
case Board::HasInternalModuleSupport:
return m_hardware.has_int_module_support;
case Board::HasRTC:
return m_inputCnt.rtcbat;
case Board::HasSDCard:
return true;
case Board::HasVBat:
return m_inputCnt.vbat;
case Board::Inputs:
return m_inputs->size();
case Board::InputSwitches:
return m_inputCnt.switches;
case Board::IsF4:
return m_hardware.cpu_type == "STM32F4";
case Board::IsH5:
return m_hardware.cpu_type == "STM32H5";
case Board::IsH7:
return m_hardware.cpu_type == "STM32H7";
case Board::JoystickAxes:
return m_inputCnt.flexJoystickAxes;
case Board::Keys:
return m_keys->size();
case Board::LcdDepth:
return m_display.depth;
case Board::LcdHeight:
return m_display.h;
case Board::LcdOLED:
return m_display.oled;
case Board::LcdWidth:
return m_display.w;
case Board::MultiposPots:
// assumes every input has potential to be one
// index used for mapping 6 pos switches back to input
return getCapability(Board::Inputs);
case Board::MultiposPotsPositions:
return 6;
case Board::NumFunctionSwitchesPositions:
return getCapability(Board::FunctionSwitches) * 3;
case Board::NumTrims:
return m_trims->size();
case Board::NumTrimSwitches:
return getCapability(Board::NumTrims) * 2;
case Board::Pots:
return m_inputCnt.flexPots;
case Board::Sliders:
return m_inputCnt.flexSliders;
case Board::SportMaxBaudRate:
return m_hardware.sport_max_baudrate;
case Board::StandardSwitches:
return m_switchCnt.std;
case Board::Sticks:
return m_inputCnt.sticks;
case Board::Surface:
return m_hardware.surface;
case Board::Switches:
return (m_switchCnt.std +
m_switchCnt.flex +
m_switchCnt.func);
case Board::SwitchesPositions:
return getCapability(Board::Switches) * 3;
default:
return 0;
}
}
const int BoardJson::getInputIndex(const QString val, Board::LookupValueType lvt) const
{
return getInputIndex(m_inputs, val, lvt);
}
// static
int BoardJson::getInputIndex(const InputsTable * inputs, QString val, Board::LookupValueType lvt)
{
for (int i = 0; i < (int)inputs->size(); i++) {
if ((lvt == Board::LVT_TAG && inputs->at(i).tag.c_str() == val) ||
(lvt == Board::LVT_NAME && inputs->at(i).name.c_str() == val))
return i;
}
return -1;
}
const QString BoardJson::getInputName(int index) const
{
return getInputName(m_inputs, index);
}
// static
QString BoardJson::getInputName(const InputsTable * inputs, int index)
{
if (index > -1 && index < (int)inputs->size())
return inputs->at(index).name.c_str();
return CPN_STR_UNKNOWN_ITEM;
}
const QString BoardJson::getInputTag(int index) const
{
return getInputTag(m_inputs, index);
}
// static
QString BoardJson::getInputTag(const InputsTable * inputs, int index)
{
if (index > -1 && index < (int)inputs->size())
return inputs->at(index).tag.c_str();
return CPN_STR_UNKNOWN_ITEM;
}
const int BoardJson::getInputYamlIndex(const QString val, YamlLookupType ylt) const
{
for (int i = 0; i < (int)m_inputs->size(); i++) {
Board::LookupValueType type = (ylt == YLT_CONFIG ? m_inputs->at(i).cfgYaml : m_inputs->at(i).refYaml);
QString tmp = (type == Board::LVT_NAME ? getInputName(m_inputs, i) : getInputTag(m_inputs, i));
if (val == tmp)
return getInputIndex(m_inputs, val, type);
}
return -1;
}
const QString BoardJson::getInputYamlName(int index, YamlLookupType ylt) const
{
if (index > -1 && index < (int)m_inputs->size()) {
if (ylt == YLT_CONFIG)
return m_inputs->at(index).cfgYaml == Board::LVT_NAME ? getInputName(m_inputs, index) : getInputTag(m_inputs, index);
else
return m_inputs->at(index).refYaml == Board::LVT_NAME ? getInputName(m_inputs, index) : getInputTag(m_inputs, index);
}
return CPN_STR_UNKNOWN_ITEM;
}
const int BoardJson::getInputsCalibrated() const
{
return getInputsCalibrated(m_inputs);
}
// static
int BoardJson::getInputsCalibrated(const InputsTable * inputs)
{
unsigned int cnt = 0;
for (const auto &defn : *inputs) {
if (isInputCalibrated(defn)) cnt++;
}
return cnt;
}
const int BoardJson::getInputTagOffset(QString tag)
{
return getInputTagOffset(m_inputs, tag);
}
// static
int BoardJson::getInputTagOffset(const InputsTable * inputs, QString tag)
{
for (int i = 0; i < (int)inputs->size(); i++) {
if (tag == inputs->at(i).tag.c_str())
return i;
}
return -1;
}
const int BoardJson::getInputExtIndex(int index)
{
if (getCapability(Board::Pots) > 0)
return getInputTagOffset(m_inputs, QString("EXT%1").arg(index));
return -1;
}
const int BoardJson::getInputPotIndex(int index)
{
if (getCapability(Board::Pots) > 0)
return getInputTagOffset(m_inputs, QString("P%1").arg(index));
return -1;
}
const int BoardJson::getInputSliderIndex(int index)
{
if (getCapability(Board::Sliders) > 0)
return getInputTagOffset(m_inputs, QString("SL%1").arg(index));
return -1;
}
const int BoardJson::getInputThrottleIndex()
{
if (getCapability(Board::Sticks) > 0)
return getInputTagOffset(m_inputs, Boards::getCapability(m_board, Board::Air) ? "RV" : "TH");
return -1;
}
const int BoardJson::getInputTypeOffset(Board::AnalogInputType type)
{
return getInputTypeOffset(m_inputs, type);
}
// static
int BoardJson::getInputTypeOffset(const InputsTable * inputs, Board::AnalogInputType type)
{
for (int i = 0; i < (int)inputs->size(); i++) {
if (type == inputs->at(i).type)
return i;
}
return -1;
}
const Board::InputInfo BoardJson::getInputInfo(int index) const
{
return getInputInfo(m_inputs, index);
}
// static
Board::InputInfo BoardJson::getInputInfo(const InputsTable * inputs, int index)
{
Board::InputInfo info;
if (index >= 0 && index < (int)inputs->size()) {
InputDefn defn = inputs->at(index);
info.type = defn.type;
info.tag = defn.tag;
info.name = defn.name;
info.shortName = defn.shortName;
info.flexType = defn.flexType;
info.inverted = defn.inverted;
}
return info;
}
const int BoardJson::getKeyIndex(const QString key) const
{
return getKeyIndex(m_keys, key);
}
// static
int BoardJson::getKeyIndex(const KeysTable * keys, QString key)
{
for (int i = 0; i < (int)keys->size(); i++) {
if (keys->at(i).key.c_str() == key)
return i;
}
return -1;
}
const Board::KeyInfo BoardJson::getKeyInfo(int index) const
{
return getKeyInfo(m_keys, index);
}
// static
Board::KeyInfo BoardJson::getKeyInfo(const KeysTable * keys, int index)
{
Board::KeyInfo info;
if (index >= 0 && index < (int)keys->size()) {
KeyDefn defn = keys->at(index);
info.name = defn.name;
info.key = defn.key;
info.label = defn.label;
}
return info;
}
// static
int BoardJson::getNumericSuffix(const std::string str)
{
std::string suffix = std::string();
for (int i = 0; i < (int)str.size(); i++) {
if (str.substr(i, 1) >= "0" && str.substr(i, 1) <= "9")
suffix.append(str.substr(i, 1));
}
if (!suffix.empty())
return std::stoi(suffix);
return -1;
}
const int BoardJson::getCFSIndexForSwitch(int offset) const
{
return getCFSIndexForSwitch(m_switches, offset);
}
// static
int BoardJson::getCFSIndexForSwitch(const SwitchesTable * switches, int sw)
{
if (sw < (int)switches->size() && switches->at(sw).isCustomSwitch)
return switches->at(sw).customSwitchIdx;
return -1;
}
const int BoardJson::getSwitchIndexForCFS(int offset) const
{
return getSwitchIndexForCFS(m_switches, offset);
}
// static
int BoardJson::getSwitchIndexForCFS(const SwitchesTable * switches, int cfsIdx)
{
for (int i = 0; i < (int)switches->size(); i++) {
if (switches->at(i).isCustomSwitch && switches->at(i).customSwitchIdx == cfsIdx)
return i;
}
return -1;
}
const int BoardJson::getCFSOffsetForCFSIndex(int index) const
{
return getCFSOffsetForCFSIndex(m_switches, index);
}
// static
int BoardJson::getCFSOffsetForCFSIndex(const SwitchesTable * switches, const int index)
{
int cnt = 0;
for (int i = 0; i < (int)switches->size(); i++) {
if (switches->at(i).isCustomSwitch) {
if (switches->at(i).customSwitchIdx == index)
return cnt;
else
cnt++;
}
}
return -1;
}
const int BoardJson::getSwitchIndexForCFSOffset(int offset) const
{
return getSwitchIndexForCFSOffset(m_switches, offset);
}
// static
int BoardJson::getSwitchIndexForCFSOffset(const SwitchesTable * switches, const int offset)
{
int cnt = 0;
for (int i = 0; i < (int)switches->size(); i++) {
if (switches->at(i).isCustomSwitch) {
if (cnt == offset)
return i;
else
cnt++;
}
}
return -1;
}
const int BoardJson::getSwitchIndex(const QString val, Board::LookupValueType lvt) const
{
return getSwitchIndex(m_switches, val, lvt);
}
// static
int BoardJson::getSwitchIndex(const SwitchesTable * switches, QString val, Board::LookupValueType lvt)
{
for (int i = 0; i < (int)switches->size(); i++) {
if ((lvt == Board::LVT_TAG && switches->at(i).tag.c_str() == val) ||
(lvt == Board::LVT_NAME && switches->at(i).name.c_str() == val))
return i;
}
return -1;
}
const Board::SwitchInfo BoardJson::getSwitchInfo(int index) const
{
return getSwitchInfo(m_switches, index);
}
// static
Board::SwitchInfo BoardJson::getSwitchInfo(const SwitchesTable * switches, int index)
{
Board::SwitchInfo info;
if (index >= 0 && index < (int)switches->size()) {
SwitchDefn defn = switches->at(index);
info.type = defn.type;
info.tag = defn.tag;
info.name = defn.name;
info.dflt = defn.dflt;
info.inverted = defn.inverted;
}
return info;
}
const QString BoardJson::getSwitchName(int index) const
{
return getSwitchName(m_switches, index);
}
// static
QString BoardJson::getSwitchName(const SwitchesTable * switches, int index)
{
if (index > -1 && index < (int)switches->size())
return switches->at(index).name.c_str();
return CPN_STR_UNKNOWN_ITEM;
}
const QString BoardJson::getSwitchTag(int index) const
{
return getSwitchTag(m_switches, index);
}
// static
QString BoardJson::getSwitchTag(const SwitchesTable * switches, int index)
{
if (index > -1 && index < (int)switches->size())
return switches->at(index).tag.c_str();
return CPN_STR_UNKNOWN_ITEM;
}
const int BoardJson::getSwitchTagNum(int index) const
{
return getSwitchTagNum(m_switches, index);
}
// static
int BoardJson::getSwitchTagNum(const SwitchesTable * switches, int index)
{
if (index > -1 && index < (int)switches->size())
return getNumericSuffix(switches->at(index).tag.c_str());
return -1;
}
const int BoardJson::getSwitchTypeOffset(Board::SwitchType type)
{
return getSwitchTypeOffset(m_switches, type);
}
// static
int BoardJson::getSwitchTypeOffset(const SwitchesTable * switches, Board::SwitchType type)
{
for (int i = 0; i < (int)switches->size(); i++) {
if (type == switches->at(i).type)
return i;
}
return -1;
}
const int BoardJson::getSwitchYamlIndex(const QString val, YamlLookupType ylt) const
{
for (int i = 0; i < (int)m_switches->size(); i++) {
Board::LookupValueType type = (ylt == YLT_CONFIG ? m_switches->at(i).cfgYaml : m_switches->at(i).refYaml);
QString tmp = (type == Board::LVT_NAME ? getSwitchName(m_switches, i) : getSwitchTag(m_switches, i));
if (val == tmp)
return getSwitchIndex(m_switches, val, type);
}
return -1;
}
const QString BoardJson::getSwitchYamlName(int index, YamlLookupType ylt) const
{
if (index > -1 && index < (int)m_switches->size()) {
if (ylt == YLT_CONFIG)
return m_switches->at(index).cfgYaml == Board::LVT_NAME ? getSwitchName(m_switches, index) : getSwitchTag(m_switches, index);
else
return m_switches->at(index).refYaml == Board::LVT_NAME ? getSwitchName(m_switches, index) : getSwitchTag(m_switches, index);
}
return CPN_STR_UNKNOWN_ITEM;
}
const int BoardJson::getTrimIndex(const QString val, Board::LookupValueType lvt) const
{
return getTrimIndex(m_trims, val, lvt);
}
// static
int BoardJson::getTrimIndex(const TrimsTable * trims, QString val, Board::LookupValueType lvt)
{
for (int i = 0; i < (int)trims->size(); i++) {
if ((lvt == Board::LVT_TAG && trims->at(i).tag.c_str() == val) ||
(lvt == Board::LVT_NAME && trims->at(i).name.c_str() == val))
return i;
}
return -1;
}
const QString BoardJson::getTrimName(int index) const
{
return getTrimName(m_trims, index);
}
// static
QString BoardJson::getTrimName(const TrimsTable * trims, int index)
{
if (index > -1 && index < (int)trims->size())
return trims->at(index).name.c_str();
return CPN_STR_UNKNOWN_ITEM;
}
const QString BoardJson::getTrimTag(int index) const
{
return getTrimTag(m_trims, index);
}
// static
QString BoardJson::getTrimTag(const TrimsTable * trims, int index)
{
if (index > -1 && index < (int)trims->size())
return trims->at(index).tag.c_str();
return CPN_STR_UNKNOWN_ITEM;
}
const int BoardJson::getTrimYamlIndex(const QString val, YamlLookupType ylt) const
{
for (int i = 0; i < (int)m_trims->size(); i++) {
Board::LookupValueType type = (ylt == YLT_CONFIG ? m_trims->at(i).cfgYaml : m_trims->at(i).refYaml);
QString tmp = (type == Board::LVT_NAME ? getTrimName(m_trims, i) : getTrimTag(m_trims, i));
if (val == tmp)
return getTrimIndex(m_trims, val, type);
}
return -1;
}
const QString BoardJson::getTrimYamlName(int index, YamlLookupType ylt) const
{
if (index > -1 && index < (int)m_trims->size()) {
if (ylt == YLT_CONFIG)
return m_trims->at(index).cfgYaml == Board::LVT_NAME ? getTrimName(m_trims, index) : getTrimTag(m_trims, index);
else
return m_trims->at(index).refYaml == Board::LVT_NAME ? getTrimName(m_trims, index) : getTrimTag(m_trims, index);
}
return CPN_STR_UNKNOWN_ITEM;
}
const bool BoardJson::isInputAvailable(int index) const
{
return (index >=0 && index < (int)m_inputs->size()) ? isInputAvailable(m_inputs->at(index)) : false;
}
// static
bool BoardJson::isInputAvailable(const InputDefn & defn)
{
return (defn.type == Board::AIT_STICK ||
(defn.type == Board::AIT_FLEX && defn.flexType != Board::FLEX_NONE && !isInputFlexJoystickAxis(defn)));
}
const bool BoardJson::isInputCalibrated(int index) const
{
return (index >=0 && index < (int)m_inputs->size()) ? isInputCalibrated(m_inputs->at(index)) : false;
}
// static
bool BoardJson::isInputCalibrated(const InputDefn & defn)
{
return (isInputStick(defn) || isInputFlexPot(defn) || isInputFlexSlider(defn));
}
const bool BoardJson::isInputConfigurable(int index) const
{
return (index >=0 && index < (int)m_inputs->size()) ? isInputConfigurable(m_inputs->at(index)) : false;
}
// static
bool BoardJson::isInputConfigurable(const InputDefn & defn)
{
return (isInputStick(defn) || isInputFlexPot(defn) || isInputFlexSlider(defn));
}
const bool BoardJson::isInputIgnored(int index) const
{
return (index >=0 && index < (int)m_inputs->size()) ? isInputIgnored(m_inputs->at(index)) : true;
}
// static
bool BoardJson::isInputIgnored(const InputDefn & defn)
{
return (isInputFlexJoystickAxis(defn) || isInputSwitch(defn));
}
// static
bool BoardJson::isInputFlex(const InputDefn & defn)
{
return defn.type == Board::AIT_FLEX;
}
const bool BoardJson::isInputFlexGyroAxis(int index) const
{
return (index >=0 && index < (int)m_inputs->size()) ? isInputFlexGyroAxis(m_inputs->at(index)) : false;
}
// static
bool BoardJson::isInputFlexGyroAxis(const InputDefn & defn)
{
const char* val = defn.tag.data();
return (defn.type == Board::AIT_FLEX && defn.tag.size() > 5 &&
val[0] == 'T' && val[1] == 'I' && val[2] == 'L' && val[3] == 'T' && val[4] == '_' && (val[5] == 'X' || val[5] == 'Y'));
}
const bool BoardJson::isInputFlexJoystickAxis(int index) const
{
return (index >=0 && index < (int)m_inputs->size()) ? isInputFlexJoystickAxis(m_inputs->at(index)) : false;
}
// static
bool BoardJson::isInputFlexJoystickAxis(const InputDefn & defn)
{
const char* val = defn.tag.data();
return (defn.type == Board::AIT_FLEX && defn.tag.size() > 2 &&
val[0] == 'J' && val[1] == 'S' && (val[2] == 'x' || val[2] == 'y'));
}
const bool BoardJson::isInputFlexPot(int index) const
{
return (index >=0 && index < (int)m_inputs->size()) ? isInputFlexPot(m_inputs->at(index)) : false;
}
// static
bool BoardJson::isInputFlexPot(const InputDefn & defn)
{
const char* val = defn.tag.data();
size_t len = defn.tag.size();
return (defn.type == Board::AIT_FLEX &&
((len > 1 && val[0] == 'P' && val[1] >= '0' && val[1] <= '9') ||
(len > 3 && val[0] == 'E' && val[1] == 'X' && val[2] == 'T' && val[3] >= '0' && val[3] <= '9')));
}
// static
bool BoardJson::isInputFlexPotMultipos(const InputDefn & defn)
{
return defn.type == Board::AIT_FLEX && defn.flexType == Board::FLEX_MULTIPOS;
}
// static
bool BoardJson::isInputFlexSlider(const InputDefn & defn)
{
const char* val = defn.tag.data();
return (defn.type == Board::AIT_FLEX && defn.tag.size() > 2 &&
val[0] == 'S' && val[1] == 'L' && val[2] >= '0' && val[2] <= '9');
}
// static
bool BoardJson::isInputFlexSwitch(const InputDefn & defn)
{
return defn.type == Board::AIT_FLEX && defn.flexType == Board::FLEX_SWITCH;
}
// static
bool BoardJson::isInputRTCBat(const InputDefn & defn)
{
return defn.type == Board::AIT_RTC_BAT;
}
const bool BoardJson::isInputStick(int index) const
{
return (index >=0 && index < (int)m_inputs->size()) ? isInputStick(m_inputs->at(index)) : false;
}
// static
bool BoardJson::isInputStick(const InputDefn & defn)
{
return defn.type == Board::AIT_STICK;
}
const bool BoardJson::isInputSwitch(int index) const
{
return (index >=0 && index < (int)m_inputs->size()) ? isInputSwitch(m_inputs->at(index)) : false;
}
// static
bool BoardJson::isInputSwitch(const InputDefn & defn)
{
return defn.type == Board::AIT_SWITCH;
}
// static
bool BoardJson::isInputVBat(const InputDefn & defn)
{
return defn.type == Board::AIT_VBAT;
}
const bool BoardJson::isSwitchConfigurable(int index) const
{
if (index >= 0 && index < getCapability(Board::Switches)) {
SwitchDefn &defn = m_switches->at(index);
if (isSwitchStd(defn) || isSwitchFunc(defn))
return true;
if (isSwitchFlex(defn)) {
int sfx = getNumericSuffix(defn.tag);
if (sfx > 0 && sfx <= getCapability(Board::FlexSwitches))
return true;
}
}
return false;
}
// static
bool BoardJson::isSwitchStd(const SwitchDefn & defn)
{
return !(isSwitchFlex(defn) || isSwitchFunc(defn));
}
const bool BoardJson::isSwitchFlex(int index) const
{
return (index >=0 && index < (int)m_switches->size()) ? isSwitchFlex(m_switches->at(index)) : false;
}
// static
bool BoardJson::isSwitchFlex(const SwitchDefn & defn)
{
const char* val = defn.tag.data();
return (defn.tag.size() > 2 &&
val[0] == 'F' && val[1] == 'L' && val[2] >= '0' && val[2] <= '9');
}
const bool BoardJson::isSwitchFunc(int index) const
{
return (index >=0 && index < (int)m_switches->size()) ? isSwitchFunc(m_switches->at(index)) : false;
}
// static
bool BoardJson::isSwitchFunc(const SwitchDefn & defn)
{
return defn.customSwitchIdx >= 0;
}
bool BoardJson::loadDefinition()
{
// safety net for BoardFactory::instance
if (m_board == Board::BOARD_UNKNOWN)
return true;
if (!loadFile(m_board, m_hwdefn, m_inputs, m_switches, m_keys, m_trims, m_display, m_cfs, m_hardware))
return false;
afterLoadFixups(m_board, m_inputs, m_switches, m_keys, m_trims);
setInputCounts(m_inputs, m_inputCnt);
setSwitchCounts(m_switches, m_switchCnt);
// json files do not normally specify stick labels so load legacy labels
for (int i = 0; i < getCapability(Board::Sticks); i++) {
if (m_inputs->at(i).name.empty())
m_inputs->at(i).name = DataHelpers::getStringTagMappingName(stickNamesLookupTable, m_inputs->at(i).tag.c_str());
}
qDebug() << "Board:" << Boards::getBoardName(m_board) <<
"inputs:" << getCapability(Board::Inputs) <<
"sticks:" << getCapability(Board::Sticks) <<
"pots:" << getCapability(Board::Pots) <<
"sliders:" << getCapability(Board::Sliders) <<
"gyro axes:" << getCapability(Board::GyroAxes) <<
"joystick axes:" << getCapability(Board::JoystickAxes) <<
"flex inputs:" << getCapability(Board::FlexInputs) <<
"input switches:" << getCapability(Board::InputSwitches) <<
"trims:" << getCapability(Board::NumTrims) <<
"keys:" << getCapability(Board::Keys) <<
"std switches:" << getCapability(Board::StandardSwitches) <<
"flex switches:" << getCapability(Board::FlexSwitches) <<
"func switches:" << getCapability(Board::FunctionSwitches) <<
"rtcbat:" << getCapability(Board::HasRTC) <<
"vbat:" << getCapability(Board::HasVBat);
return true;
}
// static
bool BoardJson::loadFile(Board::Type board, QString hwdefn, InputsTable * inputs, SwitchesTable * switches,
KeysTable * keys, TrimsTable * trims, DisplayDefn & display, CustomSwitchesDefn & cfs,
HardwareDefn & hardware)
{
if (board == Board::BOARD_UNKNOWN) {
return false;
}
// required because of the way the Firmware class is used
if (hwdefn.isEmpty()) {
return false;
}
QString path = QString(":/hwdefs/%1.json").arg(hwdefn);
QFile file(path);
if (!file.exists()) {
QMessageBox::critical(nullptr, tr("Load Board Hardware Definition"),
tr("Board: %1\nError: Unable to load file %2").arg(Boards::getBoardName(board)).arg(path));
return false;
}
if (!file.open(QIODevice::ReadOnly)) {
QMessageBox::critical(nullptr, tr("Load Board Hardware Definition"),
tr("Board: %1\nError: Unable to open file %2").arg(Boards::getBoardName(board)).arg(path));
return false;
}
QByteArray buffer = file.readAll();
file.close();
if (buffer.isEmpty()) {
QMessageBox::critical(nullptr, tr("Load Board Hardware Definition"),
tr("Board: %1\nError: Unable to read file %2").arg(Boards::getBoardName(board)).arg(path));
return false;
}
QJsonParseError res;
QJsonDocument *json = new QJsonDocument();
*json = QJsonDocument::fromJson(buffer, &res);
if (res.error || json->isNull() || !json->isObject()) {
QMessageBox::critical(nullptr, tr("Load Board Hardware Definition"),
tr("Board: %1\nError: %2 is not a valid json formatted file.\nError code: %3\nError description: %4").arg(Boards::getBoardName(board)).arg(path).arg(res.error).arg(res.errorString()));
delete json;
return false;
}
const QJsonObject &obj = json->object();
if (obj.value("adc_inputs").isObject()) {
const QJsonObject &adcinputs = obj.value("adc_inputs").toObject();
if (adcinputs.value("inputs").isArray()) {
const QJsonArray &in = adcinputs.value("inputs").toArray();
for (const QJsonValue &input : in)
{
if (input.isObject()) {
const QJsonObject &o = input.toObject();
InputDefn defn;
if (!o.value("name").isUndefined())
defn.tag = o.value("name").toString().toStdString();
if (!o.value("type").isUndefined()) {
std::string type = o.value("type").toString().toStdString();
defn.type = (AnalogInputType)DataHelpers::getStringTagMappingIndex(inputTypesLookupTable, type.c_str());
if (defn.type == AIT_STICK)
defn.refYaml = LVT_NAME;
}
if (!o.value("inverted").isUndefined())
defn.inverted = o.value("inverted").toBool();
if (!o.value("label").isUndefined())
defn.name = o.value("label").toString().toStdString();
if (!o.value("short_label").isUndefined())
defn.shortName = o.value("short_label").toString().toStdString();
if (!o.value("default").isUndefined()) {
std::string dflt = o.value("default").toString().toStdString();
if (defn.type == AIT_FLEX) {
int idx = DataHelpers::getStringTagMappingIndex(flexTypesLookupTable, dflt.c_str());
defn.flexType = (FlexType)(idx < 0 ? FLEX_NONE : idx);
}
}
inputs->insert(inputs->end(), defn);
// qDebug() << "name:" << defn.name.c_str() <<
// "type:" << defn.stype.c_str() << ">" <<
// DataHelpers::getStringNameMappingTag(inputTypesLookupTable, std::to_string(defn.type).c_str()).c_str() <<
// "label:" << defn.label.c_str() << "short:" << defn.shortLabel.c_str() << "inverted:" << defn.inverted <<
// "dflt:" << defn.dflt.c_str() << ">" <<
// DataHelpers::getStringNameMappingTag(flexTypesLookupTable, std::to_string(defn.flexType).c_str()).c_str();
}
}
}
}
if (obj.value("switches").isArray()) {
const QJsonArray &swtchs = obj.value("switches").toArray();
for (const QJsonValue &swtch : swtchs)
{
if (swtch.isObject()) {
const QJsonObject &o = swtch.toObject();
SwitchDefn sw;
if (!o.value("name").isUndefined()) {
sw.name = o.value("name").toString().toStdString();
sw.tag = sw.name;
}
if (!o.value("type").isUndefined()) {
std::string type = o.value("type").toString().toStdString();
int idx = DataHelpers::getStringTagMappingIndex(switchTypesLookupTable, type.c_str());
sw.type = idx < 0 ? Board::SWITCH_NOT_AVAILABLE : (Board::SwitchType)idx;
}
if (!o.value("flags").isUndefined())
sw.flags = o.value("flags").toInt();
if (!o.value("inverted").isUndefined())
sw.inverted = o.value("inverted").toBool();
if (!o.value("default").isUndefined()) {
std::string dflt = o.value("default").toString().toStdString();
int idx = DataHelpers::getStringTagMappingIndex(switchTypesLookupTable, dflt.c_str());
sw.dflt = idx < 0 ? Board::SWITCH_NOT_AVAILABLE : (Board::SwitchType)idx;
}
if (o.value("display").isArray()) {
const QJsonArray &d = obj.value("display").toArray();
sw.display.x = (unsigned int)d.at(0).toInt(0);
sw.display.y = (unsigned int)d.at(1).toInt(0);
}
if (!o.value("is_cfs").isUndefined())
sw.isCustomSwitch = o.value("is_cfs").toBool();
if (!o.value("cfs_idx").isUndefined())
sw.customSwitchIdx = o.value("cfs_idx").toInt();
// special handing for ADC
if (sw.type == Board::SWITCH_ADC) {
if (sw.dflt == Board::SWITCH_TOGGLE) {
// this could be 2 or 3 position toggle so play safe
// it therefore has an impact on configuring hardware, available switches, simulator widget, yaml encode and decode
sw.dflt = Board::SWITCH_3POS;
}
// make the same
sw.type = sw.dflt;
}
switches->insert(switches->end(), sw);
// qDebug() << "tag:" << sw.tag.c_str() << "name:" << sw.name.c_str() << "type:" << sw.type << ">" << Boards::switchTypeToString(sw.type) <<
// "flags:" << sw.flags << "default:" << sw.dflt << ">" << Boards::switchTypeToString(sw.dflt) <<
// "inverted:" << sw.inverted << "display:" << QString("%1").arg(sw.display.x) << "," << QString("%1").arg(sw.display.y);
}
}
}
if (obj.value("keys").isArray()) {
const QJsonArray &kys = obj.value("keys").toArray();
for (const QJsonValue &key : kys)
{
if (key.isObject()) {
const QJsonObject &o = key.toObject();
KeyDefn k;
if (!o.value("name").isUndefined()) {
k.name = o.value("name").toString().toStdString();
k.key = o.value("key").toString().toStdString();
k.label = o.value("label").toString().toStdString();
k.tag = k.name;
}
keys->insert(keys->end(), k);
// qDebug() << "name:" << k.name.c_str() << "key:" << k.key.c_str() << "label:" << k.label.c_str();
}
}
}
if (obj.value("trims").isArray()) {
const QJsonArray &trms = obj.value("trims").toArray();
for (const QJsonValue &trm : trms)
{
if (trm.isObject()) {
const QJsonObject &o = trm.toObject();
TrimDefn t;
if (!o.value("name").isUndefined()) {
t.name = o.value("name").toString().toStdString();
t.tag = t.name;
}
trims->insert(trims->end(), t);
// qDebug() << "name:" << t.name.c_str();
}
}
}
if (obj.value("display").isObject()) {
const QJsonObject &o = obj.value("display").toObject();
display.w = o.value("lcd_w").toInt();
display.h = o.value("lcd_h").toInt();
display.phys_w = o.value("lcd_phys_w").toInt();
display.phys_h = o.value("lcd_phys_h").toInt();
display.depth = o.value("lcd_depth").toInt();
display.color = display.depth == 16 ? 1 : 0;
display.oled = o.value("oled_screen").toBool();
}
if (obj.value("backlight").isObject()) {
const QJsonObject &o = obj.value("backlight").toObject();
display.backlight_color = o.value("has_backlight_color").toBool();
}
if (obj.value("leds").isObject()) {
const QJsonObject &o = obj.value("leds").toObject();
int cfs_led_strip_length = o.value("cfs_led_strip_length").toInt();
int cfs_leds_per_switch = o.value("cfs_leds_per_switch").toInt();
cfs.groups = cfs_leds_per_switch ? cfs_led_strip_length / (2 * cfs_leds_per_switch) : 0;
cfs.rgb_led = cfs.groups > 0;
hardware.has_bling_leds = o.value("bling_led_strip_length").toInt();
}
if (obj.value("hardware").isObject()) {
const QJsonObject &o = obj.value("hardware").toObject();
hardware.has_audio_mute = o.value("has_audio_mute").toBool();
hardware.has_ext_module_support = o.value("has_ext_module_support").toBool();
hardware.has_int_module_support = o.value("has_int_module_support").toBool();
hardware.sport_max_baudrate = o.value("sport_max_baudrate").toInt();
hardware.surface = o.value("surface").toBool();
hardware.cpu = o.value("cpu").toString().toStdString();
hardware.cpu_type = o.value("cpu_type").toString().toStdString();
}
delete json;
return true;
}
// static
void BoardJson::setInputCounts(const InputsTable * inputs, InputCounts & inputCounts)
{
for (const auto &defn : *inputs) {
if (isInputStick(defn))
inputCounts.sticks++;
else if (isInputFlexPot(defn))
inputCounts.flexPots++;
else if (isInputFlexSlider(defn))
inputCounts.flexSliders++;
else if (isInputFlexGyroAxis(defn))
inputCounts.flexGyroAxes++;
else if (isInputFlexJoystickAxis(defn))
inputCounts.flexJoystickAxes++;
else if (isInputFlexSwitch(defn))
inputCounts.flexSwitches++;
else if (isInputRTCBat(defn))
inputCounts.rtcbat++;
else if (isInputVBat(defn))
inputCounts.vbat++;
else if (isInputSwitch(defn))
inputCounts.switches++;
}
}
// static
void BoardJson::setSwitchCounts(const SwitchesTable * switches, SwitchCounts & switchCounts)
{
for (const auto &swtch : *switches) {
if (isSwitchStd(swtch))
switchCounts.std++;
else if (isSwitchFlex(swtch))
switchCounts.flex++;
else if (isSwitchFunc(swtch))
switchCounts.func++;
}
}
const QString BoardJson::getCapabilityStr(const Board::Capability capability) const
{
switch (capability) {
case Board::CPU:
return m_hardware.cpu.c_str();
case Board::CPUType:
return m_hardware.cpu_type.c_str();
default:
return QString();
}
}