1
0
Fork 0
mirror of https://github.com/EdgeTX/edgetx.git synced 2025-07-24 00:35:14 +03:00
This commit is contained in:
Bertrand Songis 2017-02-05 22:01:44 +01:00 committed by GitHub
parent 93781748c3
commit b0eeeb4dbc
15 changed files with 134 additions and 85 deletions

View file

@ -97,3 +97,46 @@ Board::SwitchInfo getSwitchInfo(Board::Type board, unsigned index)
return {Board::SWITCH_NOT_AVAILABLE, "???"};
}
int getBoardCapability(Board::Type board, Board::Capability capability)
{
switch (capability) {
case Pots:
if (IS_HORUS(board))
return 3;
else if (IS_TARANIS_X7(board))
return 2;
else if (IS_TARANIS_X9E(board))
return 4;
else if (IS_TARANIS(board))
return 3;
else
return 3;
case Sliders:
if (IS_HORUS(board))
return 4;
else if (IS_TARANIS_X7(board))
return 0;
else if (IS_TARANIS_X9E(board))
return 4;
else if (IS_TARANIS(board))
return 2;
else
return 0;
case FactoryInstalledSwitches:
if (IS_TARANIS_X9E(board))
return 8;
// no break
case Switches:
if (IS_TARANIS_X9E(board))
return 18;
else if (IS_TARANIS_X7(board))
return 6;
else if (IS_HORUS_OR_TARANIS(board))
return 8;
else
return 7;
}
return 0;
}

View file

@ -81,6 +81,13 @@ namespace Board {
unsigned int index;
unsigned int position;
};
enum Capability {
Pots,
Sliders,
Switches,
FactoryInstalledSwitches
};
}
// TODO remove all those constants
@ -105,6 +112,8 @@ namespace Board {
int getEEpromSize(Board::Type board);
Board::SwitchInfo getSwitchInfo(Board::Type board, unsigned index);
int getBoardCapability(Board::Type board, Board::Capability capability);
#define IS_9X(board) (board==Board::BOARD_STOCK || board==Board::BOARD_M128)
#define IS_STOCK(board) (board==Board::BOARD_STOCK)
#define IS_2560(board) (board==Board::BOARD_GRUVIN9X || board==Board::BOARD_MEGA2560)

View file

@ -582,14 +582,14 @@ bool RawSource::isPot() const
{
return (type == SOURCE_TYPE_STICK &&
index >= CPN_MAX_STICKS &&
index < CPN_MAX_STICKS+getCurrentFirmware()->getCapability(Pots));
index < CPN_MAX_STICKS + getBoardCapability(getCurrentBoard(), Board::Pots));
}
bool RawSource::isSlider() const
{
return (type == SOURCE_TYPE_STICK &&
index >= CPN_MAX_STICKS+getCurrentFirmware()->getCapability(Pots) &&
index < CPN_MAX_STICKS+getCurrentFirmware()->getCapability(Pots)+getCurrentFirmware()->getCapability(Sliders));
index >= CPN_MAX_STICKS + getBoardCapability(getCurrentBoard(), Board::Pots) &&
index < CPN_MAX_STICKS + getBoardCapability(getCurrentBoard(), Board::Pots) + getBoardCapability(getCurrentBoard(), Board::Sliders));
}
QString RawSwitch::toString(Board::Type board) const
@ -1045,13 +1045,13 @@ bool GeneralSettings::switchSourceAllowedTaranis(int index) const
bool GeneralSettings::isPotAvailable(int index) const
{
if (index<0 || index>getCurrentFirmware()->getCapability(Pots)) return false;
if (index<0 || index>getBoardCapability(getCurrentBoard(), Board::Pots)) return false;
return potConfig[index] != Board::POT_NONE;
}
bool GeneralSettings::isSliderAvailable(int index) const
{
if (index<0 || index>getCurrentFirmware()->getCapability(Sliders)) return false;
if (index<0 || index>getBoardCapability(getCurrentBoard(), Board::Sliders)) return false;
return sliderConfig[index] != Board::SLIDER_NONE;
}
@ -1071,7 +1071,7 @@ GeneralSettings::GeneralSettings()
Firmware * firmware = getCurrentFirmware();
Board::Type board = firmware->getBoard();
for (int i=0; i<firmware->getCapability(FactoryInstalledSwitches); i++) {
for (int i=0; i<getBoardCapability(board, Board::FactoryInstalledSwitches); i++) {
switchConfig[i] = getSwitchInfo(board, i).config;
}
@ -1124,7 +1124,7 @@ GeneralSettings::GeneralSettings()
stickMode = g.profile[g.sessionId()].defaultMode();
QString t_calib = g.profile[g.sessionId()].stickPotCalib();
int potsnum = getCurrentFirmware()->getCapability(Pots);
int potsnum = getBoardCapability(getCurrentBoard(), Board::Pots);
if (!t_calib.isEmpty()) {
QString t_trainercalib=g.profile[g.sessionId()].trainerCalib();
int8_t t_txVoltageCalibration=(int8_t)g.profile[g.sessionId()].txVoltageCalibration();

View file

@ -51,10 +51,6 @@ enum Capability {
VoicesMaxLength,
MultiLangVoice,
ModelImage,
Pots,
Sliders,
Switches,
FactoryInstalledSwitches,
SwitchesPositions,
NumTrimSwitches,
CustomFunctions,

View file

@ -436,7 +436,7 @@ Firmware * OpenTxFirmware::getFirmwareVariant(const QString &id)
}
}
int OpenTxFirmware::getCapability(Capability capability)
int OpenTxFirmware::getCapability(::Capability capability)
{
switch (capability) {
case Models:
@ -520,45 +520,9 @@ int OpenTxFirmware::getCapability(Capability capability)
return 0;
case PermTimers:
return (IS_2560(board) || IS_ARM(board));
case Pots:
if (IS_HORUS(board))
return 3;
else if (IS_TARANIS_X7(board))
return 2;
else if (IS_TARANIS_X9E(board))
return 4;
else if (IS_TARANIS(board))
return 3;
else
return 3;
case Sliders:
if (IS_HORUS(board))
return 4;
else if (IS_TARANIS_X7(board))
return 0;
else if (IS_TARANIS_X9E(board))
return 4;
else if (IS_TARANIS(board))
return 2;
else
return 0;
case Switches:
if (IS_TARANIS_X9E(board))
return 18;
else if (IS_TARANIS_X7(board))
return 6;
else if (IS_HORUS_OR_TARANIS(board))
return 8;
else
return 7;
case FactoryInstalledSwitches:
if (IS_TARANIS_X9E(board))
return 8;
else
return getCapability(Switches);
case SwitchesPositions:
if (IS_HORUS_OR_TARANIS(board))
return getCapability(Switches) * 3;
return getBoardCapability(board, Board::Switches) * 3;
else
return 9;
case NumTrimSwitches:

View file

@ -127,7 +127,7 @@ bool FlashEEpromDialog::patchCalibration()
{
QString calib = g.profile[g.id()].stickPotCalib();
QString trainercalib = g.profile[g.id()].trainerCalib();
int potsnum = getCurrentFirmware()->getCapability(Pots);
int potsnum = getBoardCapability(getCurrentBoard(), Board::Pots);
int8_t txVoltageCalibration = (int8_t) g.profile[g.id()].txVoltageCalibration();
int8_t txCurrentCalibration = (int8_t) g.profile[g.id()].txCurrentCalibration();
int8_t PPM_Multiplier = (int8_t) g.profile[g.id()].ppmMultiplier();

View file

@ -44,7 +44,7 @@ CalibrationPanel::CalibrationPanel(QWidget * parent, GeneralSettings & generalSe
headerLabels << QObject::tr("Negative span") << QObject::tr("Mid value") << QObject::tr("Positive span");
tableWidget->setHorizontalHeaderLabels(headerLabels);
int rows = CPN_MAX_STICKS + getCurrentFirmware()->getCapability(Pots) + getCurrentFirmware()->getCapability(Sliders);
int rows = CPN_MAX_STICKS + getBoardCapability(getCurrentBoard(), Board::Pots) + getBoardCapability(getCurrentBoard(), Board::Sliders);
tableWidget->setRowCount(rows);
for(int i = 0; i < rows; ++i) {

View file

@ -99,10 +99,11 @@ void GeneralEdit::on_tabWidget_currentChanged(int index)
void GeneralEdit::on_calretrieve_PB_clicked()
{
Board::Type board = getCurrentBoard();
int profile_id=ui->profile_CB->itemData(ui->profile_CB->currentIndex()).toInt();
QString calib=g.profile[profile_id].stickPotCalib();
int potsnum=getCurrentFirmware()->getCapability(Pots)+getCurrentFirmware()->getCapability(Sliders);
int numSwPots=getCurrentFirmware()->getCapability(Switches)+getCurrentFirmware()->getCapability(Pots)+getCurrentFirmware()->getCapability(Sliders);
int potsnum=getBoardCapability(board, Board::Pots)+getBoardCapability(board, Board::Sliders);
int numSwPots=getBoardCapability(board, Board::Switches)+getBoardCapability(board, Board::Pots)+getBoardCapability(board, Board::Sliders);
if (calib.isEmpty()) {
return;
}
@ -162,8 +163,8 @@ void GeneralEdit::on_calretrieve_PB_clicked()
qba = controlNames.mid(3*i,3).toLatin1();
strcpy(generalSettings.stickName[i], qba.data());
}
for (int i=0; i<(getCurrentFirmware()->getCapability(Switches)); i++) {
Byte=hwtypes.mid(i,1);
for (int i=0; i<getBoardCapability(board, Board::Switches); i++) {
Byte = hwtypes.mid(i, 1);
byte16=(int16_t)Byte.toInt(&ok,16);
qba=controlNames.mid(3*(i+CPN_MAX_STICKS),3).toLatin1();
if (ok) {
@ -171,8 +172,8 @@ void GeneralEdit::on_calretrieve_PB_clicked()
strcpy(generalSettings.switchName[i], qba.data());
}
}
offset = getCurrentFirmware()->getCapability(Switches);
for (int i=0; i<(getCurrentFirmware()->getCapability(Pots)); i++) {
offset = getBoardCapability(board, Board::Switches);
for (int i=0; i<getBoardCapability(board, Board::Pots); i++) {
Byte=hwtypes.mid(i+offset,1);
byte16=(int16_t)Byte.toInt(&ok,16);
qba=controlNames.mid(3*(i+CPN_MAX_STICKS+offset),3).toLatin1();
@ -181,8 +182,8 @@ void GeneralEdit::on_calretrieve_PB_clicked()
strcpy(generalSettings.potName[i], qba.data());
}
}
offset += getCurrentFirmware()->getCapability(Pots);
for (int i=0; i<(getCurrentFirmware()->getCapability(Sliders)); i++) {
offset += getBoardCapability(board, Board::Pots);
for (int i=0; i<getBoardCapability(board, Board::Sliders); i++) {
Byte=hwtypes.mid(i+offset,1);
byte16=(int16_t)Byte.toInt(&ok,16);
qba=controlNames.mid(3*(i+CPN_MAX_STICKS+offset),3).toLatin1();
@ -245,7 +246,7 @@ void GeneralEdit::on_calstore_PB_clicked()
int profile_id=ui->profile_CB->itemData(ui->profile_CB->currentIndex()).toInt();
QString name=g.profile[profile_id].name();
int potsnum=getCurrentFirmware()->getCapability(Pots)+getCurrentFirmware()->getCapability(Sliders);
int potsnum=getBoardCapability(getCurrentBoard(), Board::Pots)+getBoardCapability(getCurrentBoard(), Board::Sliders);
if (name.isEmpty()) {
ui->calstore_PB->setDisabled(true);
return;
@ -279,15 +280,15 @@ void GeneralEdit::on_calstore_PB_clicked()
for (int i=0; i<CPN_MAX_STICKS; i++) {
controlNames.append(QString("%1").arg(generalSettings.stickName[i], -3));
}
for (int i=0; i<(getCurrentFirmware()->getCapability(Switches)); i++) {
for (int i=0; i<getBoardCapability(getCurrentBoard(), Board::Switches); i++) {
hwtypes.append(QString("%1").arg((uint16_t)generalSettings.switchConfig[i], 1));
controlNames.append(QString("%1").arg(generalSettings.switchName[i], -3));
}
for (int i=0; i<(getCurrentFirmware()->getCapability(Pots)); i++) {
for (int i=0; i<getBoardCapability(getCurrentBoard(), Board::Pots); i++) {
hwtypes.append(QString("%1").arg((uint16_t)generalSettings.potConfig[i], 1));
controlNames.append(QString("%1").arg(generalSettings.potName[i], -3));
}
for (int i=0; i<(getCurrentFirmware()->getCapability(Sliders)); i++) {
for (int i=0; i<getBoardCapability(getCurrentBoard(), Board::Sliders); i++) {
hwtypes.append(QString("%1").arg((uint16_t)generalSettings.sliderConfig[i], 1));
controlNames.append(QString("%1").arg(generalSettings.sliderName[i], -3));
}

View file

@ -21,9 +21,10 @@
#include "hardware.h"
#include "ui_hardware.h"
void HardwarePanel::setupSwitchType(int index, QLabel *label, AutoLineEdit *name, AutoComboBox *type, bool threePos = true)
void HardwarePanel::setupSwitchType(int index, QLabel * label, AutoLineEdit * name, AutoComboBox * type, bool threePos = true)
{
if (IS_STM32(firmware->getBoard()) && index < firmware->getCapability(Switches)) {
Board::Type board = getCurrentBoard();
if (IS_STM32(board) && index < getBoardCapability(board, Board::Switches)) {
type->addItem(tr("None"), Board::SWITCH_NOT_AVAILABLE);
type->addItem(tr("2 Positions Toggle"), Board::SWITCH_TOGGLE);
type->addItem(tr("2 Positions"), Board::SWITCH_2POS);
@ -40,9 +41,11 @@ void HardwarePanel::setupSwitchType(int index, QLabel *label, AutoLineEdit *name
}
}
void HardwarePanel::setupPotType(int index, QLabel *label, AutoLineEdit *name, AutoComboBox *type)
void HardwarePanel::setupPotType(int index, QLabel * label, AutoLineEdit * name, AutoComboBox * type)
{
if (IS_STM32(firmware->getBoard()) && index < firmware->getCapability(Pots)) {
Board::Type board = firmware->getBoard();
if (IS_STM32(board) && index < getBoardCapability(board, Board::Pots)) {
label->setText(RawSource(SOURCE_TYPE_STICK, CPN_MAX_STICKS+index).toString());
type->addItem(tr("None"), Board::POT_NONE);
type->addItem(tr("Pot with detent"), Board::POT_WITH_DETENT);
@ -60,8 +63,10 @@ void HardwarePanel::setupPotType(int index, QLabel *label, AutoLineEdit *name, A
void HardwarePanel::setupSliderType(int index, QLabel *label, AutoLineEdit *name, AutoComboBox *type)
{
if (IS_STM32(firmware->getBoard()) && index < firmware->getCapability(Sliders)) {
label->setText(RawSource(SOURCE_TYPE_STICK, CPN_MAX_STICKS+firmware->getCapability(Pots)+index).toString());
Board::Type board = firmware->getBoard();
if (IS_STM32(board) && index < getBoardCapability(board, Board::Sliders)) {
label->setText(RawSource(SOURCE_TYPE_STICK, CPN_MAX_STICKS+getBoardCapability(board, Board::Pots)+index).toString());
type->addItem(tr("None"), Board::SLIDER_NONE);
type->addItem(tr("Slider with detent"), Board::SLIDER_WITH_DETENT);
name->setField(generalSettings.sliderName[index], 3, this);

View file

@ -579,11 +579,11 @@ void populateSourceCB(QComboBox *b, const RawSource & source, const GeneralSetti
}
if (flags & POPULATE_SOURCES) {
for (int i=0; i<CPN_MAX_STICKS+getCurrentFirmware()->getCapability(Pots)+getCurrentFirmware()->getCapability(Sliders); i++) {
for (int i=0; i<CPN_MAX_STICKS+getBoardCapability(getCurrentBoard(), Board::Pots)+getBoardCapability(getCurrentBoard(), Board::Sliders); i++) {
item = RawSource(SOURCE_TYPE_STICK, i);
// skip unavailable pots and sliders
if (item.isPot() && !generalSettings.isPotAvailable(i-CPN_MAX_STICKS)) continue;
if (item.isSlider() && !generalSettings.isSliderAvailable(i-CPN_MAX_STICKS-getCurrentFirmware()->getCapability(Pots))) continue;
if (item.isSlider() && !generalSettings.isSliderAvailable(i-CPN_MAX_STICKS-getBoardCapability(getCurrentBoard(), Board::Pots))) continue;
b->addItem(item.toString(model), item.toValue());
if (item == source) b->setCurrentIndex(b->count()-1);
}
@ -609,7 +609,7 @@ void populateSourceCB(QComboBox *b, const RawSource & source, const GeneralSetti
}
if (flags & POPULATE_SWITCHES) {
for (int i=0; i<getCurrentFirmware()->getCapability(Switches); i++) {
for (int i=0; i<getBoardCapability(board, Board::Switches); i++) {
item = RawSource(SOURCE_TYPE_SWITCH, i);
b->addItem(item.toString(model), item.toValue());
if (IS_HORUS_OR_TARANIS(board) && !generalSettings.switchSourceAllowedTaranis(i)) {

View file

@ -689,7 +689,7 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
// Beep Center checkboxes
prevFocus = ui->trimsDisplay;
int analogs = CPN_MAX_STICKS + firmware->getCapability(Pots) + firmware->getCapability(Sliders);
int analogs = CPN_MAX_STICKS + getBoardCapability(board, Board::Pots) + getBoardCapability(board, Board::Sliders);
for (int i=0; i<analogs+firmware->getCapability(RotaryEncoders); i++) {
QCheckBox * checkbox = new QCheckBox(this);
checkbox->setProperty("index", i);
@ -702,7 +702,7 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
if (src.isPot() && !generalSettings.isPotAvailable(i-CPN_MAX_STICKS)) {
checkbox->hide();
}
else if (src.isSlider() && !generalSettings.isSliderAvailable(i-CPN_MAX_STICKS-firmware->getCapability(Pots))) {
else if (src.isSlider() && !generalSettings.isSliderAvailable(i-CPN_MAX_STICKS-getBoardCapability(board, Board::Pots))) {
checkbox->hide();
}
}
@ -711,7 +711,7 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
}
// Startup switches warnings
for (int i=0; i<firmware->getCapability(Switches); i++) {
for (int i=0; i<getBoardCapability(board, Board::Switches); i++) {
Board::SwitchInfo switchInfo = getSwitchInfo(board, i);
if (IS_HORUS_OR_TARANIS(board)) {
switchInfo.config = Board::SwitchType(generalSettings.switchConfig[i]);
@ -753,7 +753,7 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
// Pot warnings
prevFocus = ui->potWarningMode;
if (IS_HORUS_OR_TARANIS(board)) {
for (int i=0; i<firmware->getCapability(Pots)+firmware->getCapability(Sliders); i++) {
for (int i=0; i<getBoardCapability(board, Board::Pots)+getBoardCapability(board, Board::Sliders); i++) {
QCheckBox * cb = new QCheckBox(this);
cb->setProperty("index", i);
cb->setText(firmware->getAnalogInputName(i+4));
@ -766,7 +766,7 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
}
}
else {
if (!generalSettings.isSliderAvailable(i-firmware->getCapability(Pots))) {
if (!generalSettings.isSliderAvailable(i-getBoardCapability(board, Board::Pots))) {
cb->hide();
}
}
@ -898,10 +898,11 @@ void SetupPanel::on_image_currentIndexChanged(int index)
void SetupPanel::populateThrottleSourceCB()
{
Board::Type board = firmware->getBoard();
lock = true;
ui->throttleSource->clear();
ui->throttleSource->addItem(QObject::tr("THR"));
for (int i=0; i<firmware->getCapability(Pots)+firmware->getCapability(Sliders); i++) {
for (int i=0; i<getBoardCapability(board, Board::Pots)+getBoardCapability(board, Board::Sliders); i++) {
ui->throttleSource->addItem(firmware->getAnalogInputName(4+i), i);
}
for (int i=0; i<firmware->getCapability(Outputs); i++) {

View file

@ -23,9 +23,34 @@
// TODO here we will move a lot of functions from eeprominterface.cpp when no merge risk
void RawSource::convert(Board::Type before, Board::Type after)
{
if (type == SOURCE_TYPE_STICK && index >= 4 + getBoardCapability(before, Board::Pots)) {
// 1st slider alignment
index += getBoardCapability(after, Board::Pots) - getBoardCapability(before, Board::Pots);
}
if (IS_HORUS(after)) {
if (IS_TARANIS_X9D(before) || IS_TARANIS_X7(before)) {
if (type == SOURCE_TYPE_STICK && index >= 7) {
// LS and RS on Horus are after sliders L1 and L2
index += 2;
}
}
}
}
void MixData::convert(Board::Type before, Board::Type after)
{
srcRaw.convert(before, after);
}
void ModelData::convert(Board::Type before, Board::Type after)
{
// Here we can add explicit conversions when moving from one board to another
for (int i=0; i<CPN_MAX_MIXERS; i++) {
mixData[i].convert(before, after);
}
}
void GeneralSettings::convert(Board::Type before, Board::Type after)

View file

@ -225,6 +225,8 @@ class RawSource {
{
}
void convert(Board::Type before, Board::Type after);
inline const int toValue() const
{
return index >= 0 ? (type * 65536 + index) : -(type * 65536 - index);
@ -405,6 +407,8 @@ enum MltpxValue {
class MixData {
public:
MixData() { clear(); }
void convert(Board::Type before, Board::Type after);
unsigned int destCh; // 1..CPN_MAX_CHNOUT
RawSource srcRaw;
int weight;
@ -1213,7 +1217,7 @@ class GeneralSettings {
unsigned int backlightColor;
CustomFunctionData customFn[CPN_MAX_CUSTOM_FUNCTIONS];
char switchName[18][3+1];
unsigned int switchConfig[18];
unsigned int switchConfig[CPN_MAX_SWITCHES];
char stickName[4][3+1];
char potName[4][3+1];
unsigned int potConfig[4];

View file

@ -468,8 +468,7 @@ void SimulatorDialog::setupRadioWidgets()
// switches
Board::SwitchInfo switchInfo;
Board::SwitchType swcfg;
// FIXME : CPN_MAX_SWITCHES == 32 but GeneralSettings::switchConfig[18] !!
for (i = 0; i < firmware->getCapability(Capability(Switches)) && i < 18 /*CPN_MAX_SWITCHES*/; ++i) {
for (i = 0; i < getBoardCapability(board, Board::Switches) && i < CPN_MAX_SWITCHES; ++i) {
if (radioSettings.switchConfig[i] == Board::SWITCH_NOT_AVAILABLE)
continue;
@ -489,7 +488,7 @@ void SimulatorDialog::setupRadioWidgets()
aIdx = 0;
// pots in middle of switches
for (i = 0; i < firmware->getCapability(Pots) && i < CPN_MAX_POTS; ++i) {
for (i = 0; i < getBoardCapability(board, Board::Pots) && i < CPN_MAX_POTS; ++i) {
if (!radioSettings.isPotAvailable(i))
continue;
@ -509,7 +508,7 @@ void SimulatorDialog::setupRadioWidgets()
// faders between sticks
int r = 0, c = 0;
for (i = 0; i < firmware->getCapability(Sliders) && i + aIdx < CPN_MAX_POTS; ++i) {
for (i = 0; i < getBoardCapability(board, Board::Sliders) && i + aIdx < CPN_MAX_POTS; ++i) {
if (!radioSettings.isSliderAvailable(i))
continue;

View file

@ -231,11 +231,13 @@ bool menuRadioSdManager(event_t _event)
else if (!strcasecmp(ext, TEXT_EXT)) {
POPUP_MENU_ADD_ITEM(STR_VIEW_TEXT);
}
#if defined(LUA)
else if (!READ_ONLY() && !strcasecmp(ext, SPORT_FIRMWARE_EXT)) {
POPUP_MENU_ADD_ITEM(STR_FLASH_EXTERNAL_DEVICE);
POPUP_MENU_ADD_ITEM(STR_FLASH_INTERNAL_MODULE);
}
else if (isExtensionMatching(ext, SCRIPTS_EXT)) {
POPUP_MENU_ADD_ITEM(STR_EXECUTE_FILE);
}
#endif
}
if (!READ_ONLY()) {
if (IS_FILE(line))