Mercurial > public > ostc_companion
comparison OSTCFrogOperations.cpp @ 1:0b3630a29ad8
Initial version based on previous repository.
Project was ported to QT6 and in now cmake based.
| author | Ideenmodellierer <tiefenrauscher@web.de> |
|---|---|
| date | Thu, 27 Nov 2025 18:40:28 +0100 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 0:76ccd6ce50c0 | 1:0b3630a29ad8 |
|---|---|
| 1 ////////////////////////////////////////////////////////////////////////////// | |
| 2 /// \file OSTCFrogOperations.cpp | |
| 3 /// \brief Implementing various operations for H&W Frog dive computer | |
| 4 /// \author JD Gascuel. | |
| 5 /// | |
| 6 /// \copyright (c) 2011-2016 JD Gascuel. All rights reserved. | |
| 7 /// $Id$ | |
| 8 ////////////////////////////////////////////////////////////////////////////// | |
| 9 // | |
| 10 // BSD 2-Clause License: | |
| 11 // | |
| 12 // Redistribution and use in source and binary forms, with or without | |
| 13 // modification, are permitted provided that the following conditions | |
| 14 // are met: | |
| 15 // | |
| 16 // 1. Redistributions of source code must retain the above copyright notice, | |
| 17 // this list of conditions and the following disclaimer. | |
| 18 // | |
| 19 // 2. Redistributions in binary form must reproduce the above copyright notice, | |
| 20 // this list of conditions and the following disclaimer in the documentation | |
| 21 // and/or other materials provided with the distribution. | |
| 22 // | |
| 23 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
| 24 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 25 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 26 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |
| 27 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
| 28 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
| 29 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
| 30 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
| 31 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
| 32 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
| 33 // THE POSSIBILITY OF SUCH DAMAGE. | |
| 34 // | |
| 35 ////////////////////////////////////////////////////////////////////////////// | |
| 36 | |
| 37 #include "OSTCFrogOperations.h" | |
| 38 | |
| 39 #include "Utils/Log.h" | |
| 40 #include "Utils/Exception.h" | |
| 41 | |
| 42 #include "HexFile.h" | |
| 43 #include "SettingsDialog.h" | |
| 44 | |
| 45 #include <QApplication> | |
| 46 #include <QDateTime> | |
| 47 #include <QProgressBar> | |
| 48 #include <QStringList> | |
| 49 | |
| 50 // Byte extration, compatible littleendian or bigendian. | |
| 51 #define LOW(x) ((unsigned char)((x) % 256)) | |
| 52 #define HIGH(x) ((unsigned char)((x / (1<<8)) % 256)) | |
| 53 #define UPPER(x) ((unsigned char)((x / (1<<16)) % 256)) | |
| 54 #define UP32(x) ((unsigned char)((x / (1<<24)) % 256)) | |
| 55 | |
| 56 #define IMAGE_ROUNDING 1024 | |
| 57 #define FIRMWARE_AREA 0x3E0000 | |
| 58 #define FIRMWARE_SIZE 0x01D000 | |
| 59 | |
| 60 extern QProgressBar* progress; | |
| 61 | |
| 62 ////////////////////////////////////////////////////////////////////////////// | |
| 63 | |
| 64 OSTCFrogOperations::OSTCFrogOperations() | |
| 65 : _firmware(0), | |
| 66 _serialNumber(0), | |
| 67 _isOpen(false), | |
| 68 _commandMode(false) | |
| 69 { | |
| 70 } | |
| 71 | |
| 72 OSTCFrogOperations::~OSTCFrogOperations() | |
| 73 { | |
| 74 if( _isOpen ) | |
| 75 disconnect(true); | |
| 76 } | |
| 77 | |
| 78 ////////////////////////////////////////////////////////////////////////////// | |
| 79 /// /// | |
| 80 /// PORT management /// | |
| 81 /// /// | |
| 82 ////////////////////////////////////////////////////////////////////////////// | |
| 83 | |
| 84 //QRegExp OSTCFrogOperations::portTemplate() const | |
| 85 QRegularExpression OSTCFrogOperations::portTemplate() const | |
| 86 { | |
| 87 #if defined(Q_OS_MAC) | |
| 88 return QRegExp("tty[.]frog.*", Qt::CaseInsensitive); | |
| 89 #elif defined(Q_OS_LINUX) | |
| 90 // Seems ok for debian, ubuntu, and SUSE (google dixit). | |
| 91 // Obviously, needs the rfcomm package. "hcitool scan" or lsusb to have | |
| 92 // a list of connected stuff... | |
| 93 return QRegExp("rfcomm.*", Qt::CaseInsensitive); | |
| 94 #elif defined(Q_OS_WIN) | |
| 95 // return QRegExp("COM.*", Qt::CaseSensitive); | |
| 96 return QRegularExpression( | |
| 97 "COM([0-9]+)", | |
| 98 QRegularExpression::CaseInsensitiveOption | |
| 99 ); | |
| 100 #endif | |
| 101 } | |
| 102 | |
| 103 QStringList OSTCFrogOperations::listPorts() const | |
| 104 { | |
| 105 return listBluetoothPorts(); | |
| 106 } | |
| 107 | |
| 108 QString OSTCFrogOperations::firmwareTemplate() const | |
| 109 { | |
| 110 return "*frog.firmware.hex"; | |
| 111 } | |
| 112 | |
| 113 QString OSTCFrogOperations::model() const | |
| 114 { | |
| 115 return "Frog"; | |
| 116 } | |
| 117 | |
| 118 QString OSTCFrogOperations::description() | |
| 119 { | |
| 120 return _description; | |
| 121 } | |
| 122 | |
| 123 QImage OSTCFrogOperations::dumpScreen() const | |
| 124 { | |
| 125 LOG_THROW("Not implemented..."); | |
| 126 return QImage(); | |
| 127 } | |
| 128 | |
| 129 HardwareOperations::CompanionFeatures OSTCFrogOperations::supported() const | |
| 130 { | |
| 131 // No ICON, no PARAMETER, no FIRMWARE, no DUMPSCREEN yet... | |
| 132 return CompanionFeatures(NAME|DATE); | |
| 133 } | |
| 134 | |
| 135 bool OSTCFrogOperations::connect() | |
| 136 { | |
| 137 try { | |
| 138 //---- Open the serial port------------------------------------------- | |
| 139 LOG_TRACE( QString("Open port %1...").arg(Settings::port) ); | |
| 140 _isOpen = false; | |
| 141 | |
| 142 //---- Execute the start protocol ------------------------------------ | |
| 143 static char animation[] = "/-\\|"; | |
| 144 | |
| 145 int reply = 0; | |
| 146 for(int retry=0; retry < 30; ++retry) { | |
| 147 _serial.open( Settings::port, "Frog"); | |
| 148 _serial.sleep(100); | |
| 149 _serial.purge(); | |
| 150 _serial.writeByte(0xBB); | |
| 151 try { | |
| 152 reply = _serial.readByte(); | |
| 153 if( reply == 0x4D ) | |
| 154 break; | |
| 155 } | |
| 156 catch(...) {} | |
| 157 LOG_TRACE( QString("Starting... %1").arg(animation[retry % sizeof animation])); | |
| 158 } | |
| 159 if( reply != 0x4D ) | |
| 160 LOG_THROW("Not started"); | |
| 161 | |
| 162 //---- Enquire about Frog id ----------------------------------------- | |
| 163 getIdentity(); | |
| 164 | |
| 165 //---- Everything is ok ---------------------------------------------- | |
| 166 _isOpen = true; | |
| 167 return true; | |
| 168 } | |
| 169 catch(const Exception& e) { | |
| 170 _serial.close(); | |
| 171 LOG_THROW("Cannot connect " << Settings::port << ": " << e.what()); | |
| 172 } | |
| 173 _isOpen = false; | |
| 174 return false; | |
| 175 } | |
| 176 | |
| 177 void OSTCFrogOperations::connectServiceMode() | |
| 178 { | |
| 179 connect(); | |
| 180 } | |
| 181 | |
| 182 bool OSTCFrogOperations::disconnect(bool /*closing*/) | |
| 183 { | |
| 184 if( !_isOpen ) return false; | |
| 185 | |
| 186 _serial.purge(); | |
| 187 _serial.writeByte(0xFF); | |
| 188 _serial.sleep(100); | |
| 189 | |
| 190 _serial.purge(); | |
| 191 _serial.close(); | |
| 192 | |
| 193 _description.clear(); // cleanup for interface updateStatus() | |
| 194 _isOpen = false; | |
| 195 | |
| 196 return true; | |
| 197 } | |
| 198 | |
| 199 ////////////////////////////////////////////////////////////////////////////// | |
| 200 /// /// | |
| 201 /// LOW Level commands /// | |
| 202 /// /// | |
| 203 ////////////////////////////////////////////////////////////////////////////// | |
| 204 | |
| 205 void OSTCFrogOperations::beginCommands() | |
| 206 { | |
| 207 Q_ASSERT( !_commandMode ); | |
| 208 static char animation[] = "/-\\|"; | |
| 209 for(int i=0;; ++i) | |
| 210 { | |
| 211 if( i == 100 ) // 20.0 sec loop ? | |
| 212 LOG_THROW("Bad reply to open command"); | |
| 213 | |
| 214 _serial.sleep(100); | |
| 215 _serial.purge(); | |
| 216 _serial.writeByte(0xAA); // Start byte | |
| 217 | |
| 218 int reply = 0; | |
| 219 try { | |
| 220 reply = _serial.readByte(); | |
| 221 } catch(...) {} | |
| 222 if( reply == 0x4B ) | |
| 223 goto Started; | |
| 224 | |
| 225 LOG_TRACE(QString("Connecting %1") | |
| 226 .arg(animation[i%4])); | |
| 227 _serial.sleep(200); | |
| 228 continue; | |
| 229 | |
| 230 Started: | |
| 231 unsigned char buffer[] = "\xAA\xAB\xAC"; | |
| 232 _serial.writeBlock(buffer, 3); | |
| 233 | |
| 234 try { | |
| 235 unsigned char reply = _serial.readByte(); | |
| 236 if( reply == 0x4C ) { | |
| 237 _commandMode = true; | |
| 238 return; | |
| 239 } | |
| 240 } catch(...) {} | |
| 241 | |
| 242 _serial.sleep(200); | |
| 243 } | |
| 244 } | |
| 245 | |
| 246 ////////////////////////////////////////////////////////////////////////////// | |
| 247 | |
| 248 void OSTCFrogOperations::endCommands() | |
| 249 { | |
| 250 Q_ASSERT( _commandMode ); | |
| 251 | |
| 252 _serial.sleep(100); | |
| 253 _serial.purge(); | |
| 254 _serial.writeByte(0xFF); // Exit service mode | |
| 255 _serial.sleep(10); | |
| 256 | |
| 257 unsigned char buffer = _serial.readByte(); | |
| 258 if( buffer != 0xFF ) | |
| 259 LOG_THROW("End failed"); | |
| 260 | |
| 261 _commandMode = false; | |
| 262 disconnect(); | |
| 263 } | |
| 264 | |
| 265 ////////////////////////////////////////////////////////////////////////////// | |
| 266 | |
| 267 void OSTCFrogOperations::eraseRange(unsigned int addr, unsigned int size) | |
| 268 { | |
| 269 Q_ASSERT( _commandMode ); | |
| 270 | |
| 271 // Convert size to number of pages, rounded up. | |
| 272 size = ((size + 4095) / 4096); | |
| 273 if( size < 256 || addr != 0x300000 ) | |
| 274 { | |
| 275 unsigned char buffer[4]; | |
| 276 // Erase just the needed pages. | |
| 277 buffer[0] = UPPER(addr); | |
| 278 buffer[1] = HIGH(addr); | |
| 279 buffer[2] = LOW(addr); | |
| 280 buffer[3] = LOW(size); | |
| 281 _serial.writeByte(0x42); // Command | |
| 282 _serial.sleep(10); | |
| 283 | |
| 284 _serial.writeBlock(buffer, 4); | |
| 285 // Wait (120/4)ms by block of 4K, plus 3% VAT to be sure. | |
| 286 _serial.sleep(40 + size * 31); | |
| 287 } | |
| 288 else | |
| 289 { | |
| 290 // Erase the whole 512KB of icon memory... | |
| 291 _serial.writeByte(0x41); | |
| 292 _serial.sleep(3000); | |
| 293 } | |
| 294 | |
| 295 try { | |
| 296 (void)_serial.readByte(); | |
| 297 } catch(...) {} | |
| 298 } | |
| 299 | |
| 300 ////////////////////////////////////////////////////////////////////////////// | |
| 301 | |
| 302 void OSTCFrogOperations::startWrite(unsigned int addr) | |
| 303 { | |
| 304 Q_ASSERT( _commandMode ); | |
| 305 | |
| 306 unsigned char buffer[3]; | |
| 307 buffer[0] = UPPER(addr); | |
| 308 buffer[1] = HIGH(addr); | |
| 309 buffer[2] = LOW(addr); | |
| 310 | |
| 311 _serial.writeByte(0x30); | |
| 312 _serial.sleep(10); | |
| 313 | |
| 314 _serial.writeBlock(buffer, 3); | |
| 315 _serial.sleep(10); | |
| 316 } | |
| 317 | |
| 318 ////////////////////////////////////////////////////////////////////////////// | |
| 319 | |
| 320 void OSTCFrogOperations::stopWrite() | |
| 321 { | |
| 322 Q_ASSERT( _commandMode ); | |
| 323 | |
| 324 _serial.flush(); | |
| 325 _serial.sleep(200); // Should be > 100ms. | |
| 326 | |
| 327 unsigned char reply = _serial.readByte(); | |
| 328 if( reply != 0x4C ) | |
| 329 LOG_THROW("stopWrite"); | |
| 330 } | |
| 331 | |
| 332 ////////////////////////////////////////////////////////////////////////////// | |
| 333 | |
| 334 void OSTCFrogOperations::readBytes(unsigned int addr, | |
| 335 unsigned char* ptr, | |
| 336 unsigned int size) | |
| 337 { | |
| 338 Q_ASSERT( _commandMode ); | |
| 339 | |
| 340 unsigned char buffer[6]; | |
| 341 buffer[0] = UPPER(addr); | |
| 342 buffer[1] = HIGH(addr); | |
| 343 buffer[2] = LOW(addr); | |
| 344 buffer[3] = UPPER(size); | |
| 345 buffer[4] = HIGH(size); | |
| 346 buffer[5] = LOW(size); | |
| 347 | |
| 348 _serial.writeByte(0x20); | |
| 349 _serial.sleep(10); | |
| 350 | |
| 351 _serial.writeBlock(buffer, 6); | |
| 352 _serial.sleep(10); | |
| 353 | |
| 354 unsigned int len = _serial.readBlock(ptr, size); | |
| 355 if( len < size ) | |
| 356 LOG_THROW("readBytes too short"); | |
| 357 | |
| 358 unsigned char reply = _serial.readByte(); | |
| 359 if( reply != 0x4C ) | |
| 360 LOG_THROW("readBytes"); | |
| 361 } | |
| 362 | |
| 363 ////////////////////////////////////////////////////////////////////////////// | |
| 364 /// /// | |
| 365 /// HIGH Level commands /// | |
| 366 /// /// | |
| 367 ////////////////////////////////////////////////////////////////////////////// | |
| 368 | |
| 369 void OSTCFrogOperations::getIdentity() | |
| 370 { | |
| 371 //---- get model | |
| 372 HardwareDescriptor hw = hardwareDescriptor(); | |
| 373 if( hw != HW_UNKNOWN_OSTC && hw != HW_Frog ) | |
| 374 LOG_THROW("Not a Frog."); | |
| 375 | |
| 376 //---- get identity | |
| 377 _serial.sleep(100); // Make sure last command is finished. | |
| 378 _serial.purge(); | |
| 379 _serial.writeByte('i'); // 0x63 | |
| 380 | |
| 381 unsigned char buffer[1+2+2+13+1] = {0}; | |
| 382 unsigned len = _serial.readBlock(buffer, sizeof buffer); | |
| 383 | |
| 384 if( len != sizeof buffer || buffer[0] != 'i' || buffer[18] != 0x4D ) | |
| 385 LOG_THROW("get identity data"); | |
| 386 | |
| 387 _serialNumber = buffer[1] + buffer[2]*256; | |
| 388 _firmware = buffer[3]*256 + buffer[4]; | |
| 389 | |
| 390 _description = QString("%1 #%2, v%3.%4, %5") | |
| 391 .arg(model()) | |
| 392 .arg(_serialNumber, 4, 10, QChar('0')) | |
| 393 .arg(_firmware / 256).arg(_firmware % 256) | |
| 394 .arg( QString::fromLatin1((char*)buffer+5, 13) | |
| 395 .replace(QChar('\0'), "") | |
| 396 .trimmed() ); | |
| 397 | |
| 398 LOG_TRACE("Found " << _description); | |
| 399 } | |
| 400 | |
| 401 ////////////////////////////////////////////////////////////////////////////// | |
| 402 | |
| 403 void OSTCFrogOperations::writeText(const QString& _msg) | |
| 404 { | |
| 405 // Pad to 15 chars: | |
| 406 QByteArray ascii = (_msg + QString(15, QChar(' '))).left(15).toLatin1(); | |
| 407 | |
| 408 _serial.sleep(100); // Make sure last command is finished. | |
| 409 _serial.purge(); | |
| 410 _serial.writeByte('n'); // 0x6E | |
| 411 | |
| 412 unsigned char reply = _serial.readByte(); | |
| 413 if( reply != 'n' ) | |
| 414 LOG_THROW("message start"); | |
| 415 | |
| 416 _serial.writeBlock((unsigned char *)ascii.constData(), 15); | |
| 417 reply = _serial.readByte(); | |
| 418 if( reply != 0x4D ) | |
| 419 LOG_THROW("message end"); | |
| 420 } | |
| 421 | |
| 422 ////////////////////////////////////////////////////////////////////////////// | |
| 423 | |
| 424 void OSTCFrogOperations::setDate(const QDateTime &date) | |
| 425 { | |
| 426 unsigned char buffer[6]; | |
| 427 buffer[0] = date.time().hour(); | |
| 428 buffer[1] = date.time().minute(); | |
| 429 buffer[2] = date.time().second(); | |
| 430 buffer[3] = date.date().month(); | |
| 431 buffer[4] = date.date().day(); | |
| 432 buffer[5] = date.date().year() % 100; | |
| 433 | |
| 434 _serial.sleep(100); // Make sure last command is finished. | |
| 435 _serial.purge(); | |
| 436 _serial.writeByte('b'); // 0x62 | |
| 437 | |
| 438 unsigned char reply = _serial.readByte(); | |
| 439 if( reply != 'b' ) | |
| 440 LOG_THROW("sync time"); | |
| 441 | |
| 442 _serial. writeBlock( buffer, sizeof buffer); | |
| 443 reply = _serial.readByte(); | |
| 444 if( reply != 0x4D ) | |
| 445 LOG_THROW("sync time end"); | |
| 446 | |
| 447 writeText("Set " + date.toString("MM/dd hh:mm")); | |
| 448 } | |
| 449 | |
| 450 ////////////////////////////////////////////////////////////////////////////// | |
| 451 | |
| 452 QSize OSTCFrogOperations::nameSize() const | |
| 453 { | |
| 454 return QSize(13, 1); | |
| 455 } | |
| 456 | |
| 457 ////////////////////////////////////////////////////////////////////////////// | |
| 458 | |
| 459 void OSTCFrogOperations::setName(const QString &newName) | |
| 460 { | |
| 461 QByteArray padded = (newName+QString(13, QChar(' '))).left(13).toLatin1(); | |
| 462 | |
| 463 _serial.sleep(100); // Make sure last command is finished. | |
| 464 _serial.purge(); | |
| 465 _serial.writeByte('c'); // 0x63 | |
| 466 | |
| 467 unsigned char reply = _serial.readByte(); | |
| 468 if( reply != 'c' ) | |
| 469 LOG_THROW("set custom text"); | |
| 470 | |
| 471 _serial.writeBlock((unsigned char*)padded.constData(), 13); | |
| 472 reply = _serial.readByte(); | |
| 473 if( reply != 0x4D ) | |
| 474 LOG_THROW("custom text end"); | |
| 475 | |
| 476 // Re-read new name: | |
| 477 getIdentity(); | |
| 478 writeText(customText()); | |
| 479 } | |
| 480 | |
| 481 ////////////////////////////////////////////////////////////////////////////// | |
| 482 | |
| 483 void OSTCFrogOperations::setIcons(const QString &/*fileName*/) | |
| 484 { | |
| 485 // beginCommands(); | |
| 486 // eraseRange(0x000000, 0x00000); | |
| 487 // startWrite(0x000000); | |
| 488 // stopWrite(); | |
| 489 // endCommands(); | |
| 490 | |
| 491 LOG_THROW( "Set icons: Not yet implemented." ); | |
| 492 } | |
| 493 | |
| 494 int OSTCFrogOperations::firmware() const | |
| 495 { | |
| 496 return _firmware; | |
| 497 } | |
| 498 | |
| 499 int OSTCFrogOperations::serialNumber() const | |
| 500 { | |
| 501 return _serialNumber; | |
| 502 } | |
| 503 | |
| 504 QString OSTCFrogOperations::customText() const | |
| 505 { | |
| 506 return _description.section(',', 2).trimmed(); | |
| 507 } | |
| 508 | |
| 509 /////////////////////////////////////////////////////////////////////////////// | |
| 510 | |
| 511 static unsigned char frogSecretKey[16] = { | |
| 512 111, 85, 190, 69, | |
| 513 108,254, 242, 19, | |
| 514 231, 49, 248,255, | |
| 515 233, 48, 176,241 | |
| 516 }; | |
| 517 | |
| 518 void OSTCFrogOperations::loadFirmware(HexFile &hex, const QString &fileName) const | |
| 519 { | |
| 520 hex.allocate(FIRMWARE_SIZE); | |
| 521 hex.loadEncrypted(fileName, frogSecretKey); | |
| 522 } | |
| 523 | |
| 524 /////////////////////////////////////////////////////////////////////////////// | |
| 525 | |
| 526 void OSTCFrogOperations::upgradeFW(const QString &fileName) | |
| 527 { | |
| 528 try { | |
| 529 //---- Load and check firmware --------------------------------------- | |
| 530 LOG_TRACE("Loading firmware..."); | |
| 531 | |
| 532 HexFile hex; | |
| 533 loadFirmware(hex, fileName); | |
| 534 unsigned int checksum = hex.checksum(); | |
| 535 | |
| 536 beginCommands(); | |
| 537 writeText("Frog Companion"); | |
| 538 getIdentity(); | |
| 539 | |
| 540 unsigned char buffer[5]; | |
| 541 buffer[0] = LOW(checksum); | |
| 542 buffer[1] = HIGH(checksum); | |
| 543 buffer[2] = UPPER(checksum); | |
| 544 buffer[3] = UP32(checksum); | |
| 545 | |
| 546 // Compute magic checksum's checksum. | |
| 547 buffer[4] = 0x55; | |
| 548 buffer[4] ^= buffer[0]; buffer[4] =(buffer[4]<<1 | buffer[4]>>7); | |
| 549 buffer[4] ^= buffer[1]; buffer[4] =(buffer[4]<<1 | buffer[4]>>7); | |
| 550 buffer[4] ^= buffer[2]; buffer[4] =(buffer[4]<<1 | buffer[4]>>7); | |
| 551 buffer[4] ^= buffer[3]; buffer[4] =(buffer[4]<<1 | buffer[4]>>7); | |
| 552 | |
| 553 _serial.sleep(100); // Make sure last command is finished. | |
| 554 _serial.purge(); | |
| 555 _serial.writeByte('P'); // 0x50 | |
| 556 | |
| 557 unsigned char reply = _serial.readByte(); | |
| 558 if( reply != 'P' ) | |
| 559 LOG_THROW( "Programming start" ); | |
| 560 | |
| 561 _serial.writeBlock(buffer, sizeof buffer); | |
| 562 _serial.sleep(4000); | |
| 563 | |
| 564 // NOTE: the device never return, because it always to a reset, | |
| 565 // with ot without reprogramming... | |
| 566 _serial.close(); | |
| 567 _isOpen = false; | |
| 568 } | |
| 569 catch(const Exception& e) { | |
| 570 LOG_TRACE(QString("Cannot upgrade: <font color='red'>%1</font>") | |
| 571 .arg(e.what())); | |
| 572 | |
| 573 // Unknown state: so make a hard cleanup: | |
| 574 _commandMode = false; | |
| 575 _isOpen = false; | |
| 576 _serial.close(); | |
| 577 } | |
| 578 } |
