Commit 569d7a56c4ec704a79af00d770d67062dfe00863
1 parent
b53c48f6a7
Exists in
master
and in
2 other branches
기능 구현
- 세척 중 강제로 종료될 경우 다음 실행 때 강제로 세척 진행
Showing
4 changed files
with
214 additions
and
97 deletions
Show diff stats
app/gui/oven_control/mainwindow.cpp
| @@ -11,6 +11,8 @@ | @@ -11,6 +11,8 @@ | ||
| 11 | #include "programmingwindow.h" | 11 | #include "programmingwindow.h" |
| 12 | #include "washwindow.h" | 12 | #include "washwindow.h" |
| 13 | #include "configwindow.h" | 13 | #include "configwindow.h" |
| 14 | +#include "ovenstatics.h" | ||
| 15 | +#include "notipopupdlg.h" | ||
| 14 | 16 | ||
| 15 | MainWindow *MainWindow::instance = NULL; | 17 | MainWindow *MainWindow::instance = NULL; |
| 16 | 18 | ||
| @@ -31,6 +33,8 @@ MainWindow::MainWindow(QWidget *parent) : | @@ -31,6 +33,8 @@ MainWindow::MainWindow(QWidget *parent) : | ||
| 31 | connect(button, &QPushButton::pressed, SoundPlayer::playClick); | 33 | connect(button, &QPushButton::pressed, SoundPlayer::playClick); |
| 32 | connect(button, SIGNAL(clicked()), SLOT(setFocus())); | 34 | connect(button, SIGNAL(clicked()), SLOT(setFocus())); |
| 33 | } | 35 | } |
| 36 | + | ||
| 37 | + QTimer::singleShot(0, this, SLOT(checkPrevWash())); | ||
| 34 | } | 38 | } |
| 35 | 39 | ||
| 36 | MainWindow::~MainWindow() | 40 | MainWindow::~MainWindow() |
| @@ -117,6 +121,18 @@ void MainWindow::onEncoderClicked(QWidget *clicked) | @@ -117,6 +121,18 @@ void MainWindow::onEncoderClicked(QWidget *clicked) | ||
| 117 | b->click(); | 121 | b->click(); |
| 118 | } | 122 | } |
| 119 | 123 | ||
| 124 | +void MainWindow::checkPrevWash() | ||
| 125 | +{ | ||
| 126 | + if (OvenStatistics::getInstance()->loadWashState()) | ||
| 127 | + { | ||
| 128 | + NotiPopupDlg *d = new NotiPopupDlg(this, tr("세척이 정상적으로 종료되지 않아\n반드시 세척통을 자동 세척해야 합니다.\n내부를 비워주세요")); | ||
| 129 | + d->setWindowModality(Qt::WindowModal); | ||
| 130 | + d->show(); | ||
| 131 | + | ||
| 132 | + connect(d, SIGNAL(accepted()), SLOT(on_washButton_clicked())); | ||
| 133 | + } | ||
| 134 | +} | ||
| 135 | + | ||
| 120 | void MainWindow::showManualCookWindow(Define::Mode mode) | 136 | void MainWindow::showManualCookWindow(Define::Mode mode) |
| 121 | { | 137 | { |
| 122 | ManualCookWindow *w = new ManualCookWindow(this, mode); | 138 | ManualCookWindow *w = new ManualCookWindow(this, mode); |
app/gui/oven_control/mainwindow.h
| @@ -38,6 +38,8 @@ private: | @@ -38,6 +38,8 @@ private: | ||
| 38 | void onEncoderClicked(QWidget *clicked); | 38 | void onEncoderClicked(QWidget *clicked); |
| 39 | 39 | ||
| 40 | private slots: | 40 | private slots: |
| 41 | + void checkPrevWash(); | ||
| 42 | + | ||
| 41 | void showManualCookWindow(Define::Mode mode); | 43 | void showManualCookWindow(Define::Mode mode); |
| 42 | void showAutoCookSelectionWindow(Define::CookType type); | 44 | void showAutoCookSelectionWindow(Define::CookType type); |
| 43 | 45 |
app/gui/oven_control/washwindow.cpp
| @@ -8,6 +8,7 @@ | @@ -8,6 +8,7 @@ | ||
| 8 | #include "dirtylevel.h" | 8 | #include "dirtylevel.h" |
| 9 | #include "configwindow.h" | 9 | #include "configwindow.h" |
| 10 | #include "mainwindow.h" | 10 | #include "mainwindow.h" |
| 11 | +#include "ovenstatics.h" | ||
| 11 | 12 | ||
| 12 | WashWindow::WashWindow(QWidget *parent) : | 13 | WashWindow::WashWindow(QWidget *parent) : |
| 13 | QMainWindow(parent), | 14 | QMainWindow(parent), |
| @@ -56,6 +57,30 @@ WashWindow::WashWindow(QWidget *parent) : | @@ -56,6 +57,30 @@ WashWindow::WashWindow(QWidget *parent) : | ||
| 56 | updateGauge(); | 57 | updateGauge(); |
| 57 | 58 | ||
| 58 | setFocus(); | 59 | setFocus(); |
| 60 | + | ||
| 61 | + if (OvenStatistics::getInstance()->loadWashState()) | ||
| 62 | + { | ||
| 63 | + // Start Cleaning Steam Generator | ||
| 64 | + state = RequestClean; | ||
| 65 | + | ||
| 66 | + udp->set(TG_OVEN_MODE, 2); | ||
| 67 | + udp->set(TG_CLEAN_TYPE, 6); | ||
| 68 | + udp->turnOn(TG_CLEANING); | ||
| 69 | + | ||
| 70 | + ui->animation->clear(); | ||
| 71 | + | ||
| 72 | + ui->animation->load(":/images/animation/wash_01.png"); | ||
| 73 | + ui->animation->load(":/images/animation/wash_02.png"); | ||
| 74 | + ui->animation->load(":/images/animation/wash_03.png"); | ||
| 75 | + ui->animation->load(":/images/animation/wash_04.png"); | ||
| 76 | + ui->washStepGauge->setValue(0); | ||
| 77 | + ui->titleLabel->setText(tr("스팀통헹굼 진행 중입니다.")); | ||
| 78 | + ui->descLabel->setText(tr("완료될 때까지 문을 열지 마세요.")); | ||
| 79 | + ui->washStepTypeLabel->setText(""); | ||
| 80 | + ui->washStepCountLabel->setText(""); | ||
| 81 | + | ||
| 82 | + ui->upperStack->setCurrentIndex(1); | ||
| 83 | + } | ||
| 59 | } | 84 | } |
| 60 | 85 | ||
| 61 | WashWindow::~WashWindow() | 86 | WashWindow::~WashWindow() |
| @@ -100,13 +125,13 @@ void WashWindow::keyReleaseEvent(QKeyEvent *event) | @@ -100,13 +125,13 @@ void WashWindow::keyReleaseEvent(QKeyEvent *event) | ||
| 100 | 125 | ||
| 101 | void WashWindow::start(int type) | 126 | void WashWindow::start(int type) |
| 102 | { | 127 | { |
| 103 | - if (selected) | 128 | + if (state != Idle) |
| 104 | return; | 129 | return; |
| 105 | 130 | ||
| 106 | if (type < 1 || type > 5) | 131 | if (type < 1 || type > 5) |
| 107 | return; | 132 | return; |
| 108 | 133 | ||
| 109 | - selected = true; | 134 | + state = OpenDoor; |
| 110 | 135 | ||
| 111 | this->type = type; | 136 | this->type = type; |
| 112 | 137 | ||
| @@ -125,13 +150,11 @@ void WashWindow::start(int type) | @@ -125,13 +150,11 @@ void WashWindow::start(int type) | ||
| 125 | 150 | ||
| 126 | void WashWindow::stop() | 151 | void WashWindow::stop() |
| 127 | { | 152 | { |
| 128 | - if (!started) | 153 | + if (state != Request && state != Running) |
| 129 | return; | 154 | return; |
| 130 | 155 | ||
| 131 | - if (canceled) | ||
| 132 | - return; | 156 | + state = Stopping; |
| 133 | 157 | ||
| 134 | - canceled = true; | ||
| 135 | udp->turnOff(TG_CLEANING); | 158 | udp->turnOff(TG_CLEANING); |
| 136 | } | 159 | } |
| 137 | 160 | ||
| @@ -146,22 +169,69 @@ void WashWindow::updateGauge() | @@ -146,22 +169,69 @@ void WashWindow::updateGauge() | ||
| 146 | ui->stateSlider->setValue(DirtyLevel::state()); | 169 | ui->stateSlider->setValue(DirtyLevel::state()); |
| 147 | } | 170 | } |
| 148 | 171 | ||
| 172 | +void WashWindow::updateView() | ||
| 173 | +{ | ||
| 174 | + const oven_control_t &control = udp->getControl(); | ||
| 175 | + if (control.clean_total != 0 && control.clean_step != 0 && control.clean_step_type != 0) | ||
| 176 | + { | ||
| 177 | + ui->washStepGauge->setMaximum(control.clean_total); | ||
| 178 | + ui->washStepGauge->setValue(control.clean_step); | ||
| 179 | + ui->washStepCountLabel->setText(QString().sprintf("%d/%d", control.clean_step, control.clean_total)); | ||
| 180 | + | ||
| 181 | + switch (control.clean_step_type) | ||
| 182 | + { | ||
| 183 | + case 1: | ||
| 184 | + ui->washStepTypeLabel->setText(tr("내부 헹굼 진행 중입니다.")); | ||
| 185 | + break; | ||
| 186 | + case 2: | ||
| 187 | + ui->washStepTypeLabel->setText(tr("스팀 급수 진행 중입니다.")); | ||
| 188 | + break; | ||
| 189 | + case 3: | ||
| 190 | + ui->washStepTypeLabel->setText(tr("내부 팬 세척 진행 중입니다.")); | ||
| 191 | + break; | ||
| 192 | + case 4: | ||
| 193 | + ui->washStepTypeLabel->setText(tr("내부 스팀 불림 진행 중입니다.")); | ||
| 194 | + break; | ||
| 195 | + case 5: | ||
| 196 | + ui->washStepTypeLabel->setText(tr("내부 강 세척 진행 중입니다.")); | ||
| 197 | + break; | ||
| 198 | + case 6: | ||
| 199 | + ui->washStepTypeLabel->setText(tr("내부 상부 세척 진행 중입니다.")); | ||
| 200 | + break; | ||
| 201 | + case 7: | ||
| 202 | + ui->washStepTypeLabel->setText(tr("내부 스팀 세척 진행 중입니다.")); | ||
| 203 | + break; | ||
| 204 | + case 8: | ||
| 205 | + ui->washStepTypeLabel->setText(tr("세척 종료 진행 중입니다.")); | ||
| 206 | + break; | ||
| 207 | + case 9: | ||
| 208 | + ui->washStepTypeLabel->setText(tr("세제 세척수 만들기 진행 중입니다.")); | ||
| 209 | + break; | ||
| 210 | + case 10: | ||
| 211 | + ui->washStepTypeLabel->setText(tr("세제 세척수 헹굼 진행 중입니다.")); | ||
| 212 | + break; | ||
| 213 | + case 11: | ||
| 214 | + ui->washStepTypeLabel->setText(tr("하부 탱크 세척수 만들기 진행 중입니다.")); | ||
| 215 | + break; | ||
| 216 | + } | ||
| 217 | + } | ||
| 218 | +} | ||
| 219 | + | ||
| 149 | void WashWindow::onChanged() | 220 | void WashWindow::onChanged() |
| 150 | { | 221 | { |
| 151 | - if (!selected) | 222 | + if (state == Idle) |
| 152 | return; | 223 | return; |
| 153 | 224 | ||
| 154 | - oven_state_t state; | ||
| 155 | - udp->fillData(state); | ||
| 156 | - | ||
| 157 | - if (!opened) | 225 | + switch (state) |
| 158 | { | 226 | { |
| 159 | - if (state.door_state) | 227 | + case Idle: |
| 228 | + return; | ||
| 229 | + case OpenDoor: | ||
| 230 | + if (udp->getData().door_state) | ||
| 160 | { | 231 | { |
| 161 | - opened = true; | 232 | + state = CloseDoor; |
| 162 | 233 | ||
| 163 | ui->animation->clear(); | 234 | ui->animation->clear(); |
| 164 | - | ||
| 165 | ui->animation->load(":/images/animation/door_big_09.png"); | 235 | ui->animation->load(":/images/animation/door_big_09.png"); |
| 166 | ui->animation->load(":/images/animation/door_big_08.png"); | 236 | ui->animation->load(":/images/animation/door_big_08.png"); |
| 167 | ui->animation->load(":/images/animation/door_big_07.png"); | 237 | ui->animation->load(":/images/animation/door_big_07.png"); |
| @@ -173,12 +243,11 @@ void WashWindow::onChanged() | @@ -173,12 +243,11 @@ void WashWindow::onChanged() | ||
| 173 | ui->animation->load(":/images/animation/door_big_01.png"); | 243 | ui->animation->load(":/images/animation/door_big_01.png"); |
| 174 | ui->closeDoorArrow->show(); | 244 | ui->closeDoorArrow->show(); |
| 175 | } | 245 | } |
| 176 | - } | ||
| 177 | - else if (!started) | ||
| 178 | - { | ||
| 179 | - if (!state.door_state) | 246 | + break; |
| 247 | + case CloseDoor: | ||
| 248 | + if (!udp->getData().door_state) | ||
| 180 | { | 249 | { |
| 181 | - started = true; | 250 | + state = Request; |
| 182 | 251 | ||
| 183 | SoundPlayer::playStart(); | 252 | SoundPlayer::playStart(); |
| 184 | 253 | ||
| @@ -199,104 +268,118 @@ void WashWindow::onChanged() | @@ -199,104 +268,118 @@ void WashWindow::onChanged() | ||
| 199 | 268 | ||
| 200 | udp->set(TG_CLEAN_TYPE, type); | 269 | udp->set(TG_CLEAN_TYPE, type); |
| 201 | udp->turnOn(TG_CLEANING); | 270 | udp->turnOn(TG_CLEANING); |
| 202 | - } | ||
| 203 | - } | ||
| 204 | - else if (state.cleaning_sate) | ||
| 205 | - { | ||
| 206 | - if (!run) | ||
| 207 | - run = true; | ||
| 208 | 271 | ||
| 209 | - oven_control_t control; | ||
| 210 | - udp->fillControl(control); | 272 | + OvenStatistics::getInstance()->setWashState(true); |
| 273 | + } | ||
| 274 | + break; | ||
| 275 | + case Request: | ||
| 276 | + if (udp->getData().cleaning_sate) | ||
| 277 | + { | ||
| 278 | + state = Running; | ||
| 211 | 279 | ||
| 212 | - if (control.clean_total != 0 && control.clean_step != 0 && control.clean_step_type != 0) | 280 | + updateView(); |
| 281 | + } | ||
| 282 | + else | ||
| 283 | + updateView(); | ||
| 284 | + break; | ||
| 285 | + case Running: | ||
| 286 | + if (udp->getData().cleaning_sate) | ||
| 213 | { | 287 | { |
| 214 | - ui->washStepGauge->setMaximum(control.clean_total); | ||
| 215 | - ui->washStepGauge->setValue(control.clean_step); | ||
| 216 | - ui->washStepCountLabel->setText(QString().sprintf("%d/%d", control.clean_step, control.clean_total)); | ||
| 217 | - | ||
| 218 | - switch (control.clean_step_type) | ||
| 219 | - { | ||
| 220 | - case 1: | ||
| 221 | - ui->washStepTypeLabel->setText(tr("내부 헹굼 진행 중입니다.")); | ||
| 222 | - break; | ||
| 223 | - case 2: | ||
| 224 | - ui->washStepTypeLabel->setText(tr("스팀 급수 진행 중입니다.")); | ||
| 225 | - break; | ||
| 226 | - case 3: | ||
| 227 | - ui->washStepTypeLabel->setText(tr("내부 팬 세척 진행 중입니다.")); | ||
| 228 | - break; | ||
| 229 | - case 4: | ||
| 230 | - ui->washStepTypeLabel->setText(tr("내부 스팀 불림 진행 중입니다.")); | ||
| 231 | - break; | ||
| 232 | - case 5: | ||
| 233 | - ui->washStepTypeLabel->setText(tr("내부 강 세척 진행 중입니다.")); | ||
| 234 | - break; | ||
| 235 | - case 6: | ||
| 236 | - ui->washStepTypeLabel->setText(tr("내부 상부 세척 진행 중입니다.")); | ||
| 237 | - break; | ||
| 238 | - case 7: | ||
| 239 | - ui->washStepTypeLabel->setText(tr("내부 스팀 세척 진행 중입니다.")); | ||
| 240 | - break; | ||
| 241 | - case 8: | ||
| 242 | - ui->washStepTypeLabel->setText(tr("세척 종료 진행 중입니다.")); | ||
| 243 | - break; | ||
| 244 | - case 9: | ||
| 245 | - ui->washStepTypeLabel->setText(tr("세제 세척수 만들기 진행 중입니다.")); | ||
| 246 | - break; | ||
| 247 | - case 10: | ||
| 248 | - ui->washStepTypeLabel->setText(tr("세제 세척수 헹굼 진행 중입니다.")); | ||
| 249 | - break; | ||
| 250 | - case 11: | ||
| 251 | - ui->washStepTypeLabel->setText(tr("하부 탱크 세척수 만들기 진행 중입니다.")); | ||
| 252 | - break; | ||
| 253 | - } | 288 | + updateView(); |
| 254 | } | 289 | } |
| 255 | - } | ||
| 256 | - else if (canceled) | ||
| 257 | - { | ||
| 258 | - SoundPlayer::playStop(); | 290 | + else |
| 291 | + { | ||
| 292 | + state = Idle; | ||
| 259 | 293 | ||
| 260 | - close(); | ||
| 261 | - } | ||
| 262 | - else if (run) | ||
| 263 | - { | ||
| 264 | - SoundPlayer::playStop(); | ||
| 265 | - DirtyLevel::wash(type); | 294 | + SoundPlayer::playStop(); |
| 295 | + DirtyLevel::wash(type); | ||
| 296 | + OvenStatistics::getInstance()->setWashState(false); | ||
| 266 | 297 | ||
| 267 | - ui->titleLabel->setText(tr("세척이 종료되었습니다")); | ||
| 268 | - ui->descLabel->setText(""); | ||
| 269 | - ui->washStepTypeLabel->setText(""); | ||
| 270 | - ui->washStepCountLabel->setText(""); | 298 | + ui->titleLabel->setText(tr("세척이 종료되었습니다")); |
| 299 | + ui->descLabel->setText(""); | ||
| 300 | + ui->washStepTypeLabel->setText(""); | ||
| 301 | + ui->washStepCountLabel->setText(""); | ||
| 271 | 302 | ||
| 272 | - ui->animation->stop(); | ||
| 273 | - ui->animation->clear(); | ||
| 274 | - ui->animation->load(":/images/animation/wash_04.png"); | 303 | + ui->animation->stop(); |
| 304 | + ui->animation->clear(); | ||
| 305 | + ui->animation->load(":/images/animation/wash_04.png"); | ||
| 275 | 306 | ||
| 276 | - returnToClockTimer.start(); | 307 | + returnToClockTimer.start(); |
| 277 | 308 | ||
| 278 | - selected = false; | ||
| 279 | - opened = false; | ||
| 280 | - started = false; | ||
| 281 | - run = false; | 309 | + updateGauge(); |
| 310 | + } | ||
| 311 | + break; | ||
| 312 | + case Stopping: | ||
| 313 | + if (!udp->getData().cleaning_sate) | ||
| 314 | + { | ||
| 315 | + SoundPlayer::playStop(); | ||
| 316 | + OvenStatistics::getInstance()->setWashState(false); | ||
| 282 | 317 | ||
| 283 | - updateGauge(); | 318 | + close(); |
| 319 | + } | ||
| 320 | + else | ||
| 321 | + updateView(); | ||
| 322 | + break; | ||
| 323 | + case RequestClean: | ||
| 324 | + if (udp->getData().cleaning_sate) | ||
| 325 | + { | ||
| 326 | + state = RunningClean; | ||
| 327 | + | ||
| 328 | + updateView(); | ||
| 329 | + } | ||
| 330 | + else | ||
| 331 | + updateView(); | ||
| 332 | + break; | ||
| 333 | + case RunningClean: | ||
| 334 | + if (udp->getData().cleaning_sate) | ||
| 335 | + { | ||
| 336 | + updateView(); | ||
| 337 | + } | ||
| 338 | + else | ||
| 339 | + { | ||
| 340 | + OvenStatistics::getInstance()->setWashState(false); | ||
| 341 | + | ||
| 342 | + ui->titleLabel->setText(tr("세척이 종료되었습니다")); | ||
| 343 | + ui->descLabel->setText(""); | ||
| 344 | + ui->washStepTypeLabel->setText(""); | ||
| 345 | + ui->washStepCountLabel->setText(""); | ||
| 346 | + | ||
| 347 | + ui->animation->stop(); | ||
| 348 | + ui->animation->clear(); | ||
| 349 | + ui->animation->load(":/images/animation/wash_04.png"); | ||
| 350 | + | ||
| 351 | + returnToClockTimer.start(); | ||
| 352 | + } | ||
| 284 | } | 353 | } |
| 285 | } | 354 | } |
| 286 | 355 | ||
| 287 | void WashWindow::on_backButton_clicked() | 356 | void WashWindow::on_backButton_clicked() |
| 288 | { | 357 | { |
| 289 | - if (started) | ||
| 290 | - stop(); | ||
| 291 | - else | 358 | + switch (state) |
| 359 | + { | ||
| 360 | + case Idle: | ||
| 361 | + case OpenDoor: | ||
| 362 | + case CloseDoor: | ||
| 292 | close(); | 363 | close(); |
| 364 | + break; | ||
| 365 | + case Request: | ||
| 366 | + case Running: | ||
| 367 | + stop(); | ||
| 368 | + break; | ||
| 369 | + case Stopping: | ||
| 370 | + case RequestClean: | ||
| 371 | + case RunningClean: | ||
| 372 | + return; | ||
| 373 | + } | ||
| 293 | } | 374 | } |
| 294 | 375 | ||
| 295 | void WashWindow::on_configButton_clicked() | 376 | void WashWindow::on_configButton_clicked() |
| 296 | { | 377 | { |
| 297 | - if (started) | ||
| 298 | - stop(); | ||
| 299 | - else | 378 | + switch (state) |
| 379 | + { | ||
| 380 | + case Idle: | ||
| 381 | + case OpenDoor: | ||
| 382 | + case CloseDoor: | ||
| 300 | { | 383 | { |
| 301 | ConfigWindow *w = new ConfigWindow(MainWindow::getInstance()); | 384 | ConfigWindow *w = new ConfigWindow(MainWindow::getInstance()); |
| 302 | w->setWindowModality(Qt::WindowModal); | 385 | w->setWindowModality(Qt::WindowModal); |
| @@ -304,6 +387,16 @@ void WashWindow::on_configButton_clicked() | @@ -304,6 +387,16 @@ void WashWindow::on_configButton_clicked() | ||
| 304 | w->raise(); | 387 | w->raise(); |
| 305 | 388 | ||
| 306 | MainWindow::jump(w); | 389 | MainWindow::jump(w); |
| 390 | + break; | ||
| 391 | + } | ||
| 392 | + case Request: | ||
| 393 | + case Running: | ||
| 394 | + stop(); | ||
| 395 | + break; | ||
| 396 | + case Stopping: | ||
| 397 | + case RequestClean: | ||
| 398 | + case RunningClean: | ||
| 399 | + return; | ||
| 307 | } | 400 | } |
| 308 | } | 401 | } |
| 309 | 402 |
app/gui/oven_control/washwindow.h
| @@ -27,6 +27,7 @@ private slots: | @@ -27,6 +27,7 @@ private slots: | ||
| 27 | void stop(); | 27 | void stop(); |
| 28 | void returnToClock(); | 28 | void returnToClock(); |
| 29 | void updateGauge(); | 29 | void updateGauge(); |
| 30 | + void updateView(); | ||
| 30 | 31 | ||
| 31 | void onChanged(); | 32 | void onChanged(); |
| 32 | 33 | ||
| @@ -38,6 +39,11 @@ private: | @@ -38,6 +39,11 @@ private: | ||
| 38 | Ui::WashWindow *ui; | 39 | Ui::WashWindow *ui; |
| 39 | UdpHandler *udp; | 40 | UdpHandler *udp; |
| 40 | 41 | ||
| 42 | + enum State { | ||
| 43 | + Idle, OpenDoor, CloseDoor, Request, Running, Stopping, | ||
| 44 | + RequestClean, RunningClean | ||
| 45 | + } state = Idle; | ||
| 46 | + | ||
| 41 | bool selected; | 47 | bool selected; |
| 42 | bool opened; | 48 | bool opened; |
| 43 | bool started; | 49 | bool started; |