From 3cbc8fb9e1040b41a4111319ed9b5f1d12b778dd Mon Sep 17 00:00:00 2001 From: =?utf8?q?Michal=20Mal=C3=BD?= Date: Wed, 31 Jul 2013 21:56:48 +0200 Subject: [PATCH] Add support for condition effects (for now work only on X axis) --- FFBChecker.pro | 13 ++++- conditioneffectsettings.cpp | 77 +++++++++++++++++++++++++ conditioneffectsettings.h | 32 +++++++++++ conditioneffectsettings.ui | 98 ++++++++++++++++++++++++++++++++ constanteffectsettings.h | 2 +- ffbconditioneffect.cpp | 94 ++++++++++++++++++++++++++++++ ffbconditioneffect.h | 20 +++++++ ffbconditioneffectparameters.cpp | 43 ++++++++++++++ ffbconditioneffectparameters.h | 33 +++++++++++ ffbdevice.cpp | 58 +++++++++++++------ ffbdevice.h | 4 ++ ffbeffectfactory.cpp | 2 + ffbeffectfactory.h | 1 + globals.h | 3 +- mainwindow.cpp | 41 +++++++++++++ mainwindow.h | 2 + 16 files changed, 502 insertions(+), 21 deletions(-) create mode 100644 conditioneffectsettings.cpp create mode 100644 conditioneffectsettings.h create mode 100644 conditioneffectsettings.ui create mode 100644 ffbconditioneffect.cpp create mode 100644 ffbconditioneffect.h create mode 100644 ffbconditioneffectparameters.cpp create mode 100644 ffbconditioneffectparameters.h diff --git a/FFBChecker.pro b/FFBChecker.pro index e533784..5568fda 100644 --- a/FFBChecker.pro +++ b/FFBChecker.pro @@ -28,7 +28,10 @@ SOURCES += main.cpp\ ffbenvelopeparameters.cpp \ ffbperiodiceffectparameters.cpp \ ffbperiodiceffect.cpp \ - ffbnulleffect.cpp + ffbnulleffect.cpp \ + conditioneffectsettings.cpp \ + ffbconditioneffectparameters.cpp \ + ffbconditioneffect.cpp HEADERS += mainwindow.h \ deviceprober.h \ @@ -47,11 +50,15 @@ HEADERS += mainwindow.h \ ffbenvelopeparameters.h \ ffbperiodiceffectparameters.h \ ffbperiodiceffect.h \ - ffbnulleffect.h + ffbnulleffect.h \ + conditioneffectsettings.h \ + ffbconditioneffectparameters.h \ + ffbconditioneffect.h FORMS += mainwindow.ui \ constanteffectsettings.ui \ envelopesettings.ui \ - periodiceffectsettings.ui + periodiceffectsettings.ui \ + conditioneffectsettings.ui QMAKE_CXXFLAGS += -std=c++11 -Wall diff --git a/conditioneffectsettings.cpp b/conditioneffectsettings.cpp new file mode 100644 index 0000000..347237e --- /dev/null +++ b/conditioneffectsettings.cpp @@ -0,0 +1,77 @@ +#include "conditioneffectsettings.h" +#include "ui_conditioneffectsettings.h" + +ConditionEffectSettings::ConditionEffectSettings(QWidget* parent) : + EffectSettings(parent), + ui(new Ui::ConditionEffectSettings) +{ + ui->setupUi(this); +} + +void ConditionEffectSettings::fillAvailableSubtypesList(const QStringList& list) +{ + ui->cbox_subtype->clear(); + ui->cbox_subtype->addItems(list); +} + +bool ConditionEffectSettings::fillFromParameters(const std::shared_ptr params) +{ + try { + const std::shared_ptr cdParams = std::dynamic_pointer_cast(params); + return fillFromParameters(cdParams); + } catch (std::bad_cast& ex) { + qCritical(ex.what()); + return false; + } +} + +bool ConditionEffectSettings::fillFromParameters(const std::shared_ptr cdParams) +{ + ui->qle_center->setText(QString::number(cdParams->center)); + ui->qle_deadband->setText(QString::number(cdParams->deadband)); + ui->qle_leftCoeff->setText(QString::number(cdParams->leftCoeff)); + ui->qle_rightCoeff->setText(QString::number(cdParams->rightCoeff)); + ui->qle_leftSat->setText(QString::number(cdParams->leftSat)); + ui->qle_rightSat->setText(QString::number(cdParams->rightCoeff)); + return true; +} + +QString ConditionEffectSettings::center() const +{ + return ui->qle_center->text(); +} + +QString ConditionEffectSettings::deadband() const +{ + return ui->qle_deadband->text(); +} + +QString ConditionEffectSettings::leftCoeff() const +{ + return ui->qle_leftCoeff->text(); +} + +QString ConditionEffectSettings::rightCoeff() const +{ + return ui->qle_rightCoeff->text(); +} + +QString ConditionEffectSettings::leftSat() const +{ + return ui->qle_leftSat->text(); +} + +QString ConditionEffectSettings::rightSat() const +{ + return ui->qle_rightSat->text(); +} + +int ConditionEffectSettings::subtypeIdx() const +{ + return ui->cbox_subtype->currentIndex(); +} + +ConditionEffectSettings::~ConditionEffectSettings() +{ + delete ui; +} diff --git a/conditioneffectsettings.h b/conditioneffectsettings.h new file mode 100644 index 0000000..a6f5a28 --- /dev/null +++ b/conditioneffectsettings.h @@ -0,0 +1,32 @@ +#ifndef CONDITIONEFFECTSETTINGS_H +#define CONDITIONEFFECTSETTINGS_H + +#include "effectsettings.h" +#include "ffbconditioneffectparameters.h" + +namespace Ui { + class ConditionEffectSettings; +} + +class ConditionEffectSettings : public EffectSettings +{ + Q_OBJECT +public: + explicit ConditionEffectSettings(QWidget* parent = nullptr); + ~ConditionEffectSettings(); + void fillAvailableSubtypesList(const QStringList& list); + bool fillFromParameters(const std::shared_ptr params); + bool fillFromParameters(const std::shared_ptr cdParams); + QString center() const; + QString deadband() const; + QString leftCoeff() const; + QString rightCoeff() const; + QString leftSat() const; + QString rightSat() const; + int subtypeIdx() const; + +private: + Ui::ConditionEffectSettings* ui; +}; + +#endif // CONDITIONEFFECTSETTINGS_H diff --git a/conditioneffectsettings.ui b/conditioneffectsettings.ui new file mode 100644 index 0000000..d1a155e --- /dev/null +++ b/conditioneffectsettings.ui @@ -0,0 +1,98 @@ + + + ConditionEffectSettings + + + + 0 + 0 + 400 + 210 + + + + Form + + + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + Left saturation: + + + + + + + + + + Right saturation: + + + + + + + + + + Left coefficient: + + + + + + + + + + Right coefficient: + + + + + + + + + + Deadband: + + + + + + + Center: + + + + + + + + + + + + + Subtype: + + + + + + + + + + + + + diff --git a/constanteffectsettings.h b/constanteffectsettings.h index a6a4670..0b918de 100644 --- a/constanteffectsettings.h +++ b/constanteffectsettings.h @@ -14,7 +14,7 @@ class ConstantEffectSettings : public EffectSettings Q_OBJECT public: - explicit ConstantEffectSettings(QWidget* parent = 0); + explicit ConstantEffectSettings(QWidget* parent = nullptr); ~ConstantEffectSettings(); const EnvelopeSettings* envelopeSettings() const; bool fillFromParameters(const std::shared_ptr params); diff --git a/ffbconditioneffect.cpp b/ffbconditioneffect.cpp new file mode 100644 index 0000000..b282d7e --- /dev/null +++ b/ffbconditioneffect.cpp @@ -0,0 +1,94 @@ +#include "ffbconditioneffect.h" + +FFBConditionEffect::FFBConditionEffect() : + FFBEffect(FFBEffectTypes::CONDITION) +{} + +struct ff_effect* FFBConditionEffect::createFFStruct() +{ + struct ff_effect* eff = FFBEffect::createFFStruct(m_params); + + eff->u.condition[0].center = m_params->center; + eff->u.condition[0].deadband = m_params->deadband; + eff->u.condition[0].left_coeff = m_params->leftCoeff; + eff->u.condition[0].right_coeff = m_params->rightCoeff; + eff->u.condition[0].left_saturation = m_params->leftSat; + eff->u.condition[0].right_saturation = m_params->rightSat; + + switch (m_params->subtype) { + case ConditionSubtypes::DAMPER: + eff->type = FF_DAMPER; + break; + case ConditionSubtypes::FRICTION: + eff->type = FF_FRICTION; + break; + case ConditionSubtypes::INERTIA: + eff->type = FF_INERTIA; + break; + case ConditionSubtypes::SPRING: + eff->type = FF_SPRING; + break; + default: + qCritical("Unknown subtype"); + delete eff; + return nullptr; + } + + return eff; +} + +bool FFBConditionEffect::setParameters(const std::shared_ptr params) +{ + try { + const std::shared_ptr cdParams = std::dynamic_pointer_cast(params); + return setParameters(cdParams); + } catch (std::bad_cast& ex) { + qCritical(ex.what()); + return false; + } + return false; +} + +bool FFBConditionEffect::setParameters(const std::shared_ptr params) +{ + if (!checkGenericParameters(params)) + return false; + + if (!checkBoundsInclusive(m_params->center, -0x7FFF, 0x7FFF)) { + reportError("Center out of bounds,"); + return false; + } + + if (!checkBoundsInclusive(params->deadband, 0, 0xFFFF)) { + reportError("Deadband out of bounds."); + return false; + } + + if (!checkBoundsInclusive(params->leftCoeff, -0x7FFF, 0x7FFF)) { + reportError("Left coefficient out of bounds."); + return false; + } + + if (!checkBoundsInclusive(params->rightCoeff, -0x7FFF, 0x7FFF)) { + reportError("Right coefficient out of bounds."); + return false; + } + + if (!checkBoundsInclusive(params->leftSat, 0, 0xFFFF)) { + reportError("Left saturation out of bounds."); + return false; + } + + if (!checkBoundsInclusive(params->rightSat, 0, 0xFFFF)) { + reportError("Right saturation out of bounds."); + return false; + } + + if (params->subtype == ConditionSubtypes::NONE) { + reportError("Invalid subtype"); + return false; + } + + m_params = params; + return true; +} diff --git a/ffbconditioneffect.h b/ffbconditioneffect.h new file mode 100644 index 0000000..34a3699 --- /dev/null +++ b/ffbconditioneffect.h @@ -0,0 +1,20 @@ +#ifndef FFBCONDITIONEFFECT_H +#define FFBCONDITIONEFFECT_H + +#include "ffbeffect.h" +#include "ffbconditioneffectparameters.h" + +class FFBConditionEffect : public FFBEffect +{ +public: + explicit FFBConditionEffect(); + struct ff_effect* createFFStruct(); + inline const std::shared_ptr parameters() const { return m_params; } + bool setParameters(const std::shared_ptr params); + bool setParameters(const std::shared_ptr params); + +private: + std::shared_ptr m_params; +}; + +#endif // FFBCONDITIONEFFECT_H diff --git a/ffbconditioneffectparameters.cpp b/ffbconditioneffectparameters.cpp new file mode 100644 index 0000000..dc21949 --- /dev/null +++ b/ffbconditioneffectparameters.cpp @@ -0,0 +1,43 @@ +#include "ffbconditioneffectparameters.h" + +FFBConditionEffectParameters::FFBConditionEffectParameters() : + FFBEffectParameters(), + center(0), + deadband(0), + leftCoeff(0), + rightCoeff(0), + leftSat(0), + rightSat(0) +{} + +bool FFBConditionEffectParameters::centerFromString(const QString& center) +{ + return qstringToInt(this->center, center); +} + +bool FFBConditionEffectParameters::deadbandFromString(const QString& deadband) +{ + return qstringToInt(this->deadband, deadband); +} + +bool FFBConditionEffectParameters::leftCoeffFromString(const QString& leftCoeff) +{ + return qstringToInt(this->leftCoeff, leftCoeff); +} + +bool FFBConditionEffectParameters::rightCoeffFromString(const QString& rightCoeff) +{ + return qstringToInt(this->rightCoeff, rightCoeff); +} + +bool FFBConditionEffectParameters::leftSatFromString(const QString& leftSat) +{ + return qstringToInt(this->leftSat, leftSat); +} + +bool FFBConditionEffectParameters::rightSatFromString(const QString& rightSat) +{ + return qstringToInt(this->rightSat, rightSat); +} + + diff --git a/ffbconditioneffectparameters.h b/ffbconditioneffectparameters.h new file mode 100644 index 0000000..9805a7f --- /dev/null +++ b/ffbconditioneffectparameters.h @@ -0,0 +1,33 @@ +#ifndef FFBCONDITIONEFFECTPARAMETERS_H +#define FFBCONDITIONEFFECTPARAMETERS_H + +#include "ffbeffectparameters.h" + +class FFBConditionEffectParameters : public FFBEffectParameters +{ +public: + FFBConditionEffectParameters(); + bool centerFromString(const QString& center); + bool deadbandFromString(const QString& deadband); + bool leftCoeffFromString(const QString& leftCoeff); + bool rightCoeffFromString(const QString& rightCoeff); + bool leftSatFromString(const QString& leftSat); + bool rightSatFromString(const QString& rightSat); + inline void subtypeFromIdx(const ConditionSubtypes subtype) { this->subtype = subtype; } + + int center; + int deadband; + int leftCoeff; + int rightCoeff; + int leftSat; + int rightSat; + ConditionSubtypes subtype; +private: + inline bool qstringToInt(int& val, const QString& str) { + bool ok = false; + val = str.toInt(&ok); + return ok; + } +}; + +#endif // FFBCONDITIONEFFECTPARAMETERS_H diff --git a/ffbdevice.cpp b/ffbdevice.cpp index 4dfe712..33bb705 100644 --- a/ffbdevice.cpp +++ b/ffbdevice.cpp @@ -14,6 +14,16 @@ FFBDevice::FFBDevice(const int fd, const QString& id, const int maxEffectCount, m_effects.push_back(FFBEffectFactory::createEffect(FFBEffectTypes::NONE)); } +QStringList FFBDevice::availableConditionSubtypesList() const +{ + QStringList list; + + for (const ConditionSubtypes s : m_availableConditionSubtypes) + list << conditionSubtypeName(s); + + return list; +} + QStringList FFBDevice::availableEffectsList() const { QStringList list; @@ -33,6 +43,23 @@ QStringList FFBDevice::availableWaveformsList() const return list; } + +QString FFBDevice::conditionSubtypeName(const ConditionSubtypes subtype) const +{ + switch (subtype) { + case ConditionSubtypes::DAMPER: + return "Damper"; + case ConditionSubtypes::FRICTION: + return "Friction"; + case ConditionSubtypes::INERTIA: + return "Inertia"; + case ConditionSubtypes::SPRING: + return "Spring"; + default: + return "Unknown subtype"; + } +} + QString FFBDevice::effectName(const FFBEffectTypes effect) const { switch (effect) { @@ -42,16 +69,10 @@ QString FFBDevice::effectName(const FFBEffectTypes effect) const return "Periodic force"; case FFBEffectTypes::RAMP: return "Ramp"; - case FFBEffectTypes::SPRING: - return "Spring"; - case FFBEffectTypes::FRICTION: - return "Friction"; - case FFBEffectTypes::DAMPER: - return "Damper"; + case FFBEffectTypes::CONDITION: + return "Condition"; case FFBEffectTypes::RUMBLE: return "Rumble"; - case FFBEffectTypes::INERTIA: - return "Inertia"; default: return "Unknown effect"; } @@ -154,14 +175,9 @@ bool FFBDevice::queryDeviceCapabilities() m_availableEffects.push_back(FFBEffectTypes::PERIODIC); if (testBit(FF_RAMP, caps)) m_availableEffects.push_back(FFBEffectTypes::RAMP); - if (testBit(FF_SPRING, caps)) - m_availableEffects.push_back(FFBEffectTypes::SPRING); - if (testBit(FF_FRICTION, caps)) - m_availableEffects.push_back(FFBEffectTypes::FRICTION); - if (testBit(FF_DAMPER, caps)) - m_availableEffects.push_back(FFBEffectTypes::DAMPER); - if (testBit(FF_INERTIA, caps)) - m_availableEffects.push_back(FFBEffectTypes::INERTIA); + if (testBit(FF_SPRING, caps) || testBit(FF_FRICTION, caps) || + testBit(FF_DAMPER, caps) || testBit(FF_INERTIA, caps)) + m_availableEffects.push_back(FFBEffectTypes::CONDITION); /* Query waveforms for PERIODIC if the device supports it */ if (hasEffect(FFBEffectTypes::PERIODIC)) { @@ -177,6 +193,16 @@ bool FFBDevice::queryDeviceCapabilities() m_availablePeriodicWaveforms.push_back(PeriodicWaveforms::SAW_DOWN); } + /* Query condition effect subtypes */ + if (testBit(FF_SPRING, caps)) + m_availableConditionSubtypes.push_back(ConditionSubtypes::SPRING); + if (testBit(FF_FRICTION, caps)) + m_availableConditionSubtypes.push_back(ConditionSubtypes::FRICTION); + if (testBit(FF_DAMPER, caps)) + m_availableConditionSubtypes.push_back(ConditionSubtypes::DAMPER); + if (testBit(FF_INERTIA, caps)) + m_availableConditionSubtypes.push_back(ConditionSubtypes::INERTIA); + return true; } diff --git a/ffbdevice.h b/ffbdevice.h index f63e5ce..e366ca7 100644 --- a/ffbdevice.h +++ b/ffbdevice.h @@ -17,8 +17,11 @@ class FFBDevice : public QObject public: explicit FFBDevice(const int fd, const QString& id, const int maxEffectCount, QObject* parent = 0); + QStringList availableConditionSubtypesList() const; QStringList availableEffectsList() const; QStringList availableWaveformsList() const; + inline ConditionSubtypes conditionSubtypeByIdx(const int idx) { return m_availableConditionSubtypes[idx]; } + QString conditionSubtypeName(const ConditionSubtypes subtype) const; QString effectName(const FFBEffectTypes effect) const; const std::shared_ptr effectParameters(const int idx); FFBEffect::FFBEffectStatus effectStatusByIdx(const int idx) const; @@ -40,6 +43,7 @@ private: bool isEffectUpdateable(const std::shared_ptr effect, const std::shared_ptr params, const FFBEffectTypes type); bool removeEffect(const int idx); int uploadEffect(struct ff_effect* effect); + std::vector m_availableConditionSubtypes; std::vector m_availableEffects; std::vector m_availablePeriodicWaveforms; std::vector> m_effects; diff --git a/ffbeffectfactory.cpp b/ffbeffectfactory.cpp index 4501c2b..8b01a0f 100644 --- a/ffbeffectfactory.cpp +++ b/ffbeffectfactory.cpp @@ -13,6 +13,8 @@ std::shared_ptr FFBEffectFactory::createEffect(FFBEffectTypes type) return std::shared_ptr(new FFBConstantEffect()); case FFBEffectTypes::PERIODIC: return std::shared_ptr(new FFBPeriodicEffect()); + case FFBEffectTypes::CONDITION: + return std::shared_ptr(new FFBConditionEffect()); default: return nullptr; } diff --git a/ffbeffectfactory.h b/ffbeffectfactory.h index 78d0b41..6842d74 100644 --- a/ffbeffectfactory.h +++ b/ffbeffectfactory.h @@ -2,6 +2,7 @@ #define FFBEFFECTFACTORY_H #include "globals.h" +#include "ffbconditioneffect.h" #include "ffbconstanteffect.h" #include "ffbnulleffect.h" #include "ffbperiodiceffect.h" diff --git a/globals.h b/globals.h index 0f7483d..fb03c1f 100644 --- a/globals.h +++ b/globals.h @@ -6,8 +6,9 @@ static const int APP_VERSION_MAJOR(0); static const int APP_VERSION_MINOR(1); static const char APP_VERSION_REL('a'); -enum class FFBEffectTypes { NONE, CONSTANT, PERIODIC, RAMP, SPRING, FRICTION, DAMPER, RUMBLE, INERTIA }; +enum class FFBEffectTypes { NONE, CONSTANT, PERIODIC, RAMP, CONDITION, RUMBLE}; enum class PeriodicWaveforms { NONE, SQUARE, TRIANGLE, SINE, SAW_UP, SAW_DOWN }; +enum class ConditionSubtypes { NONE, SPRING, FRICTION, DAMPER, INERTIA }; template inline bool checkBoundsInclusive(const T& val, const T& min, const T& max) { diff --git a/mainwindow.cpp b/mainwindow.cpp index 7c246d0..8efde44 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -19,6 +19,8 @@ MainWindow::MainWindow(std::shared_ptr prober, const QString& titl m_constantEffSet = new ConstantEffectSettings(); m_periodicEffSet = new PeriodicEffectSettings(); + m_conditionEffSet = new ConditionEffectSettings(); + ui->qstw_effectSpecifics->addWidget(m_conditionEffSet); ui->qstw_effectSpecifics->addWidget(m_constantEffSet); ui->qstw_effectSpecifics->addWidget(m_periodicEffSet); @@ -39,6 +41,8 @@ EffectSettings* MainWindow::effectSettingsByType(FFBEffectTypes type) return m_constantEffSet; case FFBEffectTypes::PERIODIC: return m_periodicEffSet; + case FFBEffectTypes::CONDITION: + return m_conditionEffSet; default: abort(); } @@ -49,6 +53,7 @@ void MainWindow::fillDeviceList() ui->cbox_devices->clear(); ui->cbox_devices->addItems(m_prober->listDevicesByID()); } + void MainWindow::fillEffectSlotsList(const int idx) { ui->cbox_effectSlots->clear(); @@ -72,6 +77,7 @@ void MainWindow::onDeviceSelected(const QString& id) fillEffectSlotsList(m_activeDevice->maxEffectCount()); fillEffectTypesList(m_activeDevice->availableEffectsList()); + m_conditionEffSet->fillAvailableSubtypesList(m_activeDevice->availableConditionSubtypesList()); m_periodicEffSet->fillAvailableWaveformsList(m_activeDevice->availableWaveformsList()); } @@ -234,6 +240,41 @@ bool MainWindow::readEffectParameters(std::shared_ptr& para params = iparams; break; } + case FFBEffectTypes::CONDITION: + { + std::shared_ptr cdParams = std::shared_ptr(new FFBConditionEffectParameters); + if (!readGeneralEffectParameters(params)) + return false; + if (!cdParams->centerFromString(m_conditionEffSet->center())) { + QMessageBox::warning(this, res_inputFormatErrCap, "Invalid data in field \"Center\""); + return false; + } + if (!cdParams->deadbandFromString(m_conditionEffSet->deadband())) { + QMessageBox::warning(this, res_inputFormatErrCap, "Invalid data in field \"Deadband\""); + return false; + } + if (!cdParams->leftCoeffFromString(m_conditionEffSet->leftCoeff())) { + QMessageBox::warning(this, res_inputFormatErrCap, "Invalid data in field \"Left coefficient\""); + return false; + } + if (!cdParams->rightCoeffFromString(m_conditionEffSet->rightCoeff())) { + QMessageBox::warning(this, res_inputFormatErrCap, "Invalid data in field \"Right coefficient\""); + return false; + } + if (!cdParams->leftSatFromString(m_conditionEffSet->leftSat())) { + QMessageBox::warning(this, res_inputFormatErrCap, "Invalid data in field \"Left saturation\""); + return false; + } + if (!cdParams->rightSatFromString(m_conditionEffSet->rightSat())) { + QMessageBox::warning(this, res_inputFormatErrCap, "Invalid data in field \"Right saturation\""); + return false; + } + + ConditionSubtypes subtype = m_activeDevice->conditionSubtypeByIdx(m_conditionEffSet->subtypeIdx()); + cdParams->subtypeFromIdx(subtype); + + params = cdParams; + } default: qDebug() << "Unhandled type of effect"; return false; diff --git a/mainwindow.h b/mainwindow.h index 95d33f4..6c64e8b 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -1,6 +1,7 @@ #ifndef MAINWINDOW_H #define MAINWINDOW_H +#include "conditioneffectsettings.h" #include "constanteffectsettings.h" #include "deviceprober.h" #include "ffbconstanteffectparameters.h" @@ -33,6 +34,7 @@ private: void setEffectStatusText(const FFBEffect::FFBEffectStatus status); std::shared_ptr m_activeDevice; + ConditionEffectSettings* m_conditionEffSet; ConstantEffectSettings* m_constantEffSet; PeriodicEffectSettings* m_periodicEffSet; std::shared_ptr m_prober; -- 2.43.5