C
Qt Quick Ultralite Automotive Cluster Demo
/****************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Quick Ultralite module. ** ** $QT_BEGIN_LICENSE:COMM$ ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see http://www.qt.io/terms-conditions. For further ** information use the contact form at http://www.qt.io/contact-us. ** ** $QT_END_LICENSE$ ** ******************************************************************************/#include "simulation/states.h" #include "Automotive/TellTalesModel.h" #include "Automotive/NormalModeModel.h" #include "Automotive/PhoneModel.h" #include "Automotive/MediaPlayerModel.h" #include "Automotive/SettingsMenuModel.h" #include "Automotive/SportModeModel.h" #include "mathutils.h" using namespace Automotive; namespace { MainModel &mainModel = MainModel::instance(); TellTalesModel &tellTalesModel = TellTalesModel::instance(); NormalModeModel &normalModeModel = NormalModeModel::instance(); PhoneModel &phoneModel = PhoneModel::instance(); MediaPlayerModel &mediaPlayerModel = MediaPlayerModel::instance(); SportModeModel &sportModeModel = SportModeModel::instance(); SettingsMenuModel &settingsMenuModel = SettingsMenuModel::instance(); } // namespace namespace IntroStateConstants { #ifdef __ghs__ // Additional delay for Renesas to compensate HDMI initialization time const uint32_t InitialDelay = 1500; #else const uint32_t InitialDelay = 0; #endif const uint32_t TellTalesResetParkDelay = 500; const uint32_t TellTalesResetAirbagDelay = 300; const uint32_t FinalDelay = 500; } // namespace IntroStateConstants namespace SettingsMenuStateConsts { const unsigned SwitchOptionDelay = 1500; const unsigned ChangeDriveModeDelay = 2000; const unsigned SportModeDurationMin = 15000; const unsigned SportModeDurationMax = 25000; const unsigned DriveModeStateFinalizeDelay = 1500; const unsigned SwitchToCarStatusDelay = 3000; const unsigned ReDisplayMenuDelay = 0; const unsigned MenuPresentationDelayMin = 3000; const unsigned MenuPresentationDelayMax = 6000; } // namespace SettingsMenuStateConsts namespace MediaPlayerConstants { const uint16_t ChangeTracksDurationMin = 10000; const uint16_t ChangeTracksDurationMax = 20000; const uint16_t InitialPlayDurationMin = 2000; const uint16_t InitialPlayDurationMax = 7500; const uint16_t FinalPlayDurationMin = 5000; const uint16_t FinalPlayDurationMax = 10000; const uint16_t ChangeTrackDelayMin = 1000; const uint16_t ChangeTrackDelayMax = 3000; } // namespace MediaPlayerConstants namespace PhoneStateConstants { const uint16_t InitialListDisplay = 3000; const uint16_t ChangeTabToContactScrollDelay = 800; const uint16_t StartCallDelay = 2000; const uint16_t EndCallToStateSwitchDelay = 2800; } // namespace PhoneStateConstants namespace NaviStateConstants { const uint16_t DurationMin = 7500; const uint16_t DurationMax = 15000; } // namespace NaviStateConstants namespace Simulation { MenuState::MenuState(const StateId &nextState) : _nextState(nextState) {} // -- ClusterModeState ClusterModeState::ClusterModeState(MainModel::ClusterMode mode_) : mode(mode_) {} void ClusterModeState::onEnter(const StateId &, const Layer &, Machine &) { MainModel::instance().clusterMode.setValue(mode); } // --- Intro state IntroState::IntroState(IntroFinishedCallback finishedCallback) : ClusterModeState(MainModel::ModeNormal) , _finishedCallback(finishedCallback) {} void IntroState::onEnter(const StateId &prevState, const Layer &layer, Machine &sm) { ClusterModeState::onEnter(prevState, layer, sm); _step = Step_Blank; mainModel.telltalesVisible.setValue(false); mainModel.clusterVisible.setValue(false); mainModel.clusterOpacity.setValue(0); mainModel.gaugesOpacity.setValue(0); tellTalesModel.turnLeftActive.setValue(true); tellTalesModel.turnRightActive.setValue(true); tellTalesModel.beamActive.setValue(true); tellTalesModel.highBeamsActive.setValue(true); tellTalesModel.parkedActive.setValue(true); tellTalesModel.airbagActive.setValue(true); tellTalesModel.qtLogoOpacity.setValue(0); tellTalesModel.indicatorOpacity.setValue(0); mainModel.speed.setValue(0); mainModel.rpm.setValue(0); mainModel.fuelLevel.setValue(0); mainModel.batteryLevel.setValue(0); mainModel.gaugesValueChangeDuration.setValue(mainModel.gaugesValueChangeDurationSlow.value()); mainModel.introSequenceStarted.setValue(true); sm.requestUpdate(IntroStateConstants::InitialDelay, false, layer); } void IntroState::onUpdate(uint32_t, const Layer &layer, Machine &sm) { using namespace IntroStateConstants; _step = static_cast<Step>(_step + 1); switch (_step) { case Step_ShowQtLogo: mainModel.telltalesVisible.setValue(true); tellTalesModel.qtLogoOpacity.setValue(1); sm.requestUpdate(int(tellTalesModel.opacityChangeDuration.value() * 1.25), false, layer); break; case Step_ShowTellTales: tellTalesModel.indicatorOpacity.setValue(1); sm.requestUpdate(int(tellTalesModel.opacityChangeDuration.value() * 1.25), false, layer); break; case Step_ShowCluster: mainModel.clusterVisible.setValue(true); mainModel.clusterOpacity.setValue(1); sm.requestUpdate(int(mainModel.clusterOpacityChangeDuration.value() * 0.5), false, layer); break; case Step_ShowGauges: mainModel.gaugesOpacity.setValue(1); sm.requestUpdate(mainModel.gaugesOpacityChangeDuration.value(), false, layer); break; case Step_MaxGauges: mainModel.speed.setValue(mainModel.maxSpeed.value()); mainModel.rpm.setValue(mainModel.maxRpm.value()); mainModel.fuelLevel.setValue(mainModel.initialFuelLevel.value()); mainModel.batteryLevel.setValue(mainModel.initialBatteryLevel.value()); sm.requestUpdate(mainModel.gaugesValueChangeDuration.value(), false, layer); break; case Step_ResetGauges: mainModel.speed.setValue(0); mainModel.rpm.setValue(0); sm.requestUpdate(int(mainModel.gaugesValueChangeDuration.value() * 0.1), false, layer); break; case Step_TellTalesResetLights: tellTalesModel.turnLeftActive.setValue(false); tellTalesModel.turnRightActive.setValue(false); tellTalesModel.beamActive.setValue(true); // As designed tellTalesModel.highBeamsActive.setValue(false); sm.requestUpdate(TellTalesResetParkDelay, false, layer); break; case Step_TellTalesResetPark: tellTalesModel.parkedActive.setValue(false); sm.requestUpdate(TellTalesResetAirbagDelay, false, layer); break; case Step_TellTalesResetAirbag: tellTalesModel.airbagActive.setValue(false); sm.requestUpdate(FinalDelay, false, layer); break; case Step_Done: if (_finishedCallback) { _finishedCallback(sm); } break; case Step_Blank: break; } } void IntroState::onLeave(const StateId &, const Layer &, Machine &) { mainModel.gaugesValueChangeDuration.setValue(mainModel.gaugesValueChangeDurationNormal.value()); mainModel.introSequenceCompleted.setValue(true); } // --- EndSate EndState::EndState(const StateId &nextState) : _nextState(nextState) {} void EndState::onEnter(const StateId &, const Layer &layer, Machine &sm) { tellTalesModel.qtLogoOpacity.setValue(0); tellTalesModel.indicatorOpacity.setValue(0); mainModel.clusterOpacity.setValue(0); mainModel.gaugesOpacity.setValue(0); sm.changeState(_nextState, layer, mainModel.clusterOpacityChangeDuration.value() * 3); } PhoneState::PhoneState(const StateId &nextState) : MenuState(nextState) {} void PhoneState::onEnter(const StateId &, const Layer &layer, Machine &sm) { _step = Step_Blank; _contactsToScroll = -1; phoneModel.contactTabIndex.setValue(1); phoneModel.inCall.setValue(false); sm.requestUpdate(1, false, layer); } void PhoneState::onUpdate(uint32_t, const Layer &layer, Machine &sm) { if (_step != Step_ScrollToNextContact || _contactsToScroll == -1) { _step = static_cast<Step>(_step + 1); } using namespace PhoneStateConstants; switch (_step) { case Step_ShowMenu: normalModeModel.menu.setValue(NormalModeModel::PhoneMenu); sm.requestUpdate(InitialListDisplay, false, layer); break; case Step_ChangeTab: phoneModel.contactTabIndex.setValue(randomChoice(phoneModel.phoneTabCount.value() - 1)); sm.requestUpdate(phoneModel.contactTabSwitchDuration.value() + ChangeTabToContactScrollDelay, false, layer); break; case Step_ChooseNextContact: switch (phoneModel.contactTabIndex.value()) { case 0: _contactsToScroll = randomChoice(phoneModel.favContactsCount.value() - 1, 1); QUL_FALLTHROUGH(); case 1: _contactsToScroll = randomChoice(phoneModel.recentContactsCount.value() - 1, 1); QUL_FALLTHROUGH(); case 2: _contactsToScroll = randomChoice(phoneModel.allContactsCount.value() - 1, 1); QUL_FALLTHROUGH(); default: break; } sm.requestUpdate(0, false, layer); break; case Step_ScrollToNextContact: _contactsToScroll--; if (_contactsToScroll >= 0) { phoneModel.nextContact(); sm.requestUpdate(phoneModel.contactScrollDuration.value(), false, layer); } else { sm.requestUpdate(StartCallDelay, false, layer); } break; case Step_StartCall: phoneModel.inCall.setValue(true); sm.requestUpdate(randomize(phoneModel.minCallDuration.value(), phoneModel.maxCallDuration.value()), false, layer); break; case Step_EndCall: phoneModel.inCall.setValue(false); sm.requestUpdate(EndCallToStateSwitchDelay, false, layer); break; case Step_Done: sm.changeState(_nextState, layer); break; case Step_Blank: break; } } MediaPlayerState::MediaPlayerState(const StateId &nextState) : MenuState(nextState) , _cumulatedTime(0) , _changeTracksDuration(0) {} void MediaPlayerState::onEnter(const StateId &, const Layer &layer, Machine &sm) { using namespace MediaPlayerConstants; nextStep(Step_Play); _changeTracksDuration = randomize(ChangeTracksDurationMin, ChangeTracksDurationMax); normalModeModel.menu.setValue(NormalModeModel::MediaPlayerMenu); sm.requestUpdate(1, false, layer); } void MediaPlayerState::onUpdate(uint32_t tick, const Layer &layer, Machine &sm) { using namespace MediaPlayerConstants; _cumulatedTime += tick; switch (_step) { case Step_Play: mediaPlayerModel.play(); nextStep(Step_ChangeTracks); sm.requestUpdate(randomize(InitialPlayDurationMin, InitialPlayDurationMax), false, layer); break; case Step_ChangeTracks: randomChoice(1u) == 0u ? mediaPlayerModel.nextSong() : mediaPlayerModel.previousSong(); if (_cumulatedTime > _changeTracksDuration) { sm.requestUpdate(mediaPlayerModel.changeSongDuration.value() + randomize(FinalPlayDurationMin, FinalPlayDurationMax), false, layer); nextStep(Step_Done); } else { sm.requestUpdate(mediaPlayerModel.changeSongDuration.value() + randomize(ChangeTrackDelayMin, ChangeTrackDelayMax), false, layer); } break; case Step_Done: sm.changeState(_nextState, layer); break; } } void MediaPlayerState::nextStep(Step step) { _step = step; _cumulatedTime = 0; } NaviState::NaviState(const StateId &nextState) : MenuState(nextState) {} void NaviState::onEnter(const StateId &, const Layer &layer, Machine &sm) { _cumulatedTime = 0; _step = Step_Navi; normalModeModel.menu.setValue(NormalModeModel::NavigationMenu); sm.requestUpdate(100, false, layer); } void NaviState::onUpdate(uint32_t, const Layer &layer, Machine &sm) { switch (_step) { case Step_Navi: sm.requestUpdate(randomize(NaviStateConstants::DurationMin, NaviStateConstants::DurationMax), false, layer); break; case Step_Done: sm.changeState(_nextState, layer); break; } _step = static_cast<Step>(_step + 1); } void DriveModeMenuState::onEnter(const StateId &, const Layer &layer, Machine &sm) { _step = Step_Blank; sm.requestUpdate(0, false, layer); } void DriveModeMenuState::onUpdate(uint32_t, const Layer &layer, Machine &sm) { using namespace SettingsMenuStateConsts; _step = static_cast<Step>(_step + 1); switch (_step) { case Step_DisplayDriveModeMenu: if (sm.getCurrentStateId(Layer_Gauges) == State_NormalDrive) { normalModeModel.menu.setValue(NormalModeModel::CarStatusMenu); settingsMenuModel.currentDriveModeSelected.setValue(SettingsMenuModel::NormalDrive); settingsMenuModel.currentTab.setValue(SettingsMenuModel::DriveModeTab); } else { sportModeModel.menuActive.setValue(true); } sm.requestUpdate(SwitchOptionDelay, false, layer); break; case Step_SwitchDriveModeOption: if (sm.getCurrentStateId(Layer_Gauges) == State_NormalDrive) { settingsMenuModel.currentDriveModeSelected.setValue(SettingsMenuModel::SportDrive); } else { settingsMenuModel.currentDriveModeSelected.setValue(SettingsMenuModel::NormalDrive); } sm.requestUpdate(ChangeDriveModeDelay, false, layer); break; case Step_ChangeDriveMode: if (sm.getCurrentStateId(Layer_Gauges) == State_NormalDrive) { sm.changeState(State_SportDrive, Layer_Gauges); sm.requestUpdate(randomize(SportModeDurationMin, SportModeDurationMax), false, layer); } else { sm.changeState(State_NormalDrive, Layer_Gauges); sm.requestUpdate(DriveModeStateFinalizeDelay, false, layer); } break; case Step_Done: if (sm.getCurrentStateId(Layer_Gauges) == State_NormalDrive) { sm.changeState(State_CarStatus, layer, SwitchToCarStatusDelay); } else { _step = Step_Blank; sm.requestUpdate(ReDisplayMenuDelay, false, layer); } break; default: break; } } void CarStatusMenuState::onEnter(const StateId &, const Layer &layer, Machine &sm) { using namespace SettingsMenuStateConsts; settingsMenuModel.currentTab.setValue(SettingsMenuModel::CarStatusTab); sm.changeState(State_LastTrip, layer, randomize(MenuPresentationDelayMin, MenuPresentationDelayMax)); } void LastTripMenuState::onEnter(const StateId &, const Layer &layer, Machine &sm) { using namespace SettingsMenuStateConsts; settingsMenuModel.currentTab.setValue(SettingsMenuModel::LastTripTab); sm.changeState(State_MediaPlayer, layer, randomize(MenuPresentationDelayMin, MenuPresentationDelayMax)); } void InteractiveModeState::onUpdate(uint32_t, const Layer &layer, Machine &sm) { if (mainModel.clusterMode.value() == MainModel::ModeNormal) { switch (normalModeModel.menu.value()) { case NormalModeModel::MediaPlayerMenu: sm.changeState(State_MediaPlayer, layer); break; case NormalModeModel::PhoneMenu: sm.changeState(State_Phone, layer); break; case NormalModeModel::NavigationMenu: sm.changeState(State_Navi, layer); break; case NormalModeModel::CarStatusMenu: { switch (settingsMenuModel.currentTab.value()) { case SettingsMenuModel::DriveModeTab: sm.changeState(State_DriveModeMenu, layer); break; case SettingsMenuModel::CarStatusTab: sm.changeState(State_CarStatus, layer); break; case SettingsMenuModel::LastTripTab: sm.changeState(State_LastTrip, layer); break; default: break; } } break; default: break; } } else { sm.changeState(State_DriveModeMenu, layer); } } } // namespace Simulation