diff --git a/VortexEngine/VortexEngine.vcxproj b/VortexEngine/VortexEngine.vcxproj index 7b3ec18bfb..b5453b3392 100644 --- a/VortexEngine/VortexEngine.vcxproj +++ b/VortexEngine/VortexEngine.vcxproj @@ -150,6 +150,7 @@ + @@ -221,6 +222,7 @@ + diff --git a/VortexEngine/VortexEngine.vcxproj.filters b/VortexEngine/VortexEngine.vcxproj.filters index d34b25504b..200ea0ec1a 100644 --- a/VortexEngine/VortexEngine.vcxproj.filters +++ b/VortexEngine/VortexEngine.vcxproj.filters @@ -339,6 +339,9 @@ Source Files + + Source Files + @@ -569,5 +572,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/VortexEngine/src/Leds/LedTypes.h b/VortexEngine/src/Leds/LedTypes.h index 59f519be88..9a71f3a000 100644 --- a/VortexEngine/src/Leds/LedTypes.h +++ b/VortexEngine/src/Leds/LedTypes.h @@ -99,6 +99,30 @@ enum Pair : uint8_t // Compile-time check on the number of pairs and leds static_assert(LED_COUNT == (PAIR_COUNT * 2), "Incorrect number of Pairs for Leds! Adjust the Led enum or Pair enum to match"); +enum Radial : uint8_t +{ + RADIAL_FIRST = 0, + + RADIAL_0 = RADIAL_FIRST, + RADIAL_1, + RADIAL_2, + RADIAL_3, + RADIAL_4, + RADIAL_5, + RADIAL_6, + RADIAL_7, + RADIAL_8, + RADIAL_9, + + RADIAL_COUNT, + RADIAL_LAST = (RADIAL_COUNT - 1), +}; + +static_assert(RADIAL_COUNT == (LED_COUNT / 2), "Incorrect number of Radials for Leds! Adjust the Led enum or Radial enum to match"); + +#define radialInner(radial) (LedPos)(LED_10 + radial) +#define radialOuter(radial) (LedPos)(LED_0 + radial) + // check if an led is even or odd #define isEven(pos) ((pos % 2) == 0) #define isOdd(pos) ((pos % 2) != 0) @@ -280,4 +304,25 @@ inline Pair operator-(Pair &c, int b) return (Pair)((uint32_t)c - b); } +// Radial operators +inline Radial &operator++(Radial &c) +{ + c = Radial(((uint32_t)c) + 1); + return c; +} +inline Radial operator++(Radial &c, int) +{ + Radial temp = c; + ++c; + return temp; +} +inline Radial operator+(Radial &c, int b) +{ + return (Radial)((uint32_t)c + b); +} +inline Radial operator-(Radial &c, int b) +{ + return (Radial)((uint32_t)c - b); +} + #endif diff --git a/VortexEngine/src/Leds/Leds.cpp b/VortexEngine/src/Leds/Leds.cpp index 38851915d6..43b92a975b 100644 --- a/VortexEngine/src/Leds/Leds.cpp +++ b/VortexEngine/src/Leds/Leds.cpp @@ -75,6 +75,19 @@ void Leds::setPairs(Pair first, Pair last, RGBColor col) setRange(pairEven(first), pairOdd(last), col); } +void Leds::setRadial(Radial radial, RGBColor col) +{ + setIndex(radialInner(radial), col); + setIndex(radialOuter(radial), col); +} + +void Leds::setRadials(Radial first, Radial last, RGBColor col) +{ + for (Radial rad = first; rad < last; rad++) { + setRadial(rad, col); + } +} + void Leds::setRangeEvens(Pair first, Pair last, RGBColor col) { for (Pair pos = first; pos <= last; pos++) { diff --git a/VortexEngine/src/Leds/Leds.h b/VortexEngine/src/Leds/Leds.h index d7e7cc7c41..3eecd1b328 100644 --- a/VortexEngine/src/Leds/Leds.h +++ b/VortexEngine/src/Leds/Leds.h @@ -37,6 +37,14 @@ class Leds static void clearPair(Pair pair) { setPair(pair, RGB_OFF); } static void clearPairs(Pair first, Pair last) { setPairs(first, last, RGB_OFF); } + // control two LEDs on a pair, these are appropriate for use in internal pattern logic + static void setRadial(Radial radial, RGBColor col); + static void setRadials(Radial first, Radial last, RGBColor col); + + // Turn off both LEDs on a pair, these are appropriate for use in internal pattern logic + static void clearRadial(Radial radial) { setRadial(radial, RGB_OFF); } + static void clearRadials(Radial first, Radial last) { setRadials(first, last, RGB_OFF); } + // Controll pair evens static void setRangeEvens(Pair first, Pair last, RGBColor); static void setAllEvens(RGBColor col); diff --git a/VortexEngine/src/Menus/MenuList/EditorConnection.cpp b/VortexEngine/src/Menus/MenuList/EditorConnection.cpp index 824cac59a0..1bdf60df12 100644 --- a/VortexEngine/src/Menus/MenuList/EditorConnection.cpp +++ b/VortexEngine/src/Menus/MenuList/EditorConnection.cpp @@ -9,6 +9,7 @@ #include "../../Time/TimeControl.h" #include "../../Time/Timings.h" #include "../../Colors/Colorset.h" +#include "../../Modes/DuoDefaultModes.h" #include "../../Modes/Modes.h" #include "../../Modes/Mode.h" #include "../../Leds/Leds.h" @@ -29,7 +30,8 @@ EditorConnection::EditorConnection(const RGBColor &col, bool advanced) : m_numModesToReceive(0), m_curStep(0), m_firmwareSize(0), - m_firmwareOffset(0) + m_firmwareOffset(0), + m_backupModes(true) { } @@ -332,12 +334,27 @@ void EditorConnection::handleState() m_state = STATE_IDLE; break; + // ------------------------------- + // Set Global Brightness + case STATE_SET_GLOBAL_BRIGHTNESS: + m_receiveBuffer.clear(); + SerialComs::write(EDITOR_VERB_READY); + m_state = STATE_SET_GLOBAL_BRIGHTNESS_RECEIVE; + break; + case STATE_SET_GLOBAL_BRIGHTNESS_RECEIVE: + // set the brightness of the device + if (!receiveBrightness()) { + break; + } + m_receiveBuffer.clear(); + m_state = STATE_IDLE; + break; + // ------------------------------- // Get Chromalinked Duo Header case STATE_PULL_HEADER_CHROMALINK: if (!pullHeaderChromalink()) { - // error? - break; + Leds::holdAll(RGB_RED); } // done m_receiveBuffer.clear(); @@ -355,6 +372,7 @@ void EditorConnection::handleState() case STATE_PULL_MODE_CHROMALINK_SEND: // send the stuff if (!pullModeChromalink()) { + // error? break; } // done @@ -380,9 +398,9 @@ void EditorConnection::handleState() // the trick is to send header after the modes so the reset comes at the end UPDI::reset(); UPDI::disable(); + m_receiveBuffer.clear(); // success modes were received send the done SerialComs::write(EDITOR_VERB_PUSH_CHROMA_HDR_ACK); - m_receiveBuffer.clear(); m_state = STATE_IDLE; break; @@ -408,9 +426,9 @@ void EditorConnection::handleState() if (!pushModeChromalink()) { break; } + m_receiveBuffer.clear(); SerialComs::write(EDITOR_VERB_PUSH_CHROMA_MODE_ACK); // done - m_receiveBuffer.clear(); m_state = STATE_IDLE; break; @@ -426,33 +444,55 @@ void EditorConnection::handleState() break; case STATE_CHROMALINK_FLASH_FIRMWARE_RECEIVE_SIZE: if (!receiveFirmwareSize(m_firmwareSize)) { + // continue waiting break; } - UPDI::eraseMemory(); - - m_curStep = 0; m_firmwareOffset = 0; + m_backupModeNum = 0; + Leds::setAll(RGB_ORANGE3); + m_state = STATE_CHROMALINK_FLASH_FIRMWARE_BACKUP_MODES; + break; + case STATE_CHROMALINK_FLASH_FIRMWARE_BACKUP_MODES: + if (backupDuoModes()) { + m_state = STATE_CHROMALINK_FLASH_FIRMWARE_ERASE_MEMORY; + } + break; + case STATE_CHROMALINK_FLASH_FIRMWARE_ERASE_MEMORY: + Leds::setAll(RGB_CYAN0); + UPDI::eraseMemory(); m_receiveBuffer.clear(); - Leds::setAll(RGB_YELLOW3); SerialComs::write(EDITOR_VERB_READY); - m_state = STATE_CHROMALINK_FLASH_FIRMWARE_RECEIVE; + m_state = STATE_CHROMALINK_FLASH_FIRMWARE_FLASH_CHUNKS; break; - case STATE_CHROMALINK_FLASH_FIRMWARE_RECEIVE: + case STATE_CHROMALINK_FLASH_FIRMWARE_FLASH_CHUNKS: // receive and write a chunk of firwmare - if (!writeDuoFirmware()) { - break; + if (writeDuoFirmware()) { + // done go to next state + m_state = STATE_CHROMALINK_FLASH_FIRMWARE_RESTORE_MODES; } - // send ack - SerialComs::write(EDITOR_VERB_FLASH_FIRMWARE_ACK); + break; + case STATE_CHROMALINK_FLASH_FIRMWARE_RESTORE_MODES: // only once the entire firmware is written - if (m_firmwareOffset >= m_firmwareSize) { - // then done - m_receiveBuffer.clear(); - m_curStep = 0; - m_state = STATE_IDLE; + if (restoreDuoModes()) { + m_state = STATE_CHROMALINK_FLASH_FIRMWARE_DONE; } break; + case STATE_CHROMALINK_FLASH_FIRMWARE_DONE: + // done reset everything + m_receiveBuffer.clear(); + m_firmwareOffset = 0; + m_backupModeNum = 0; + m_curStep = 0; + // done with updi + UPDI::reset(); + UPDI::disable(); + // show green + Leds::setAll(RGB_GREEN); + SerialComs::write(EDITOR_VERB_FLASH_FIRMWARE_DONE); + // go back to idle + m_state = STATE_IDLE; + break; } } @@ -509,23 +549,32 @@ bool EditorConnection::pullModeChromalink() { // try to receive the mode index uint8_t modeIdx = 0; + bool success = false; // only 9 modes on duo, maybe this should be a macro or something - if (!receiveModeIdx(modeIdx) || modeIdx >= 9) { - return false; + if (receiveModeIdx(modeIdx) && modeIdx < 9) { + ByteStream modeBuffer; + // same doesn't matter if this fails still need to send + success = UPDI::readMode(modeIdx, modeBuffer); + UPDI::reset(); + UPDI::disable(); + // lol just use the mode index as the radial to set + Leds::setRadial((Radial)modeIdx, success ? RGB_GREEN4 : RGB_RED4); + if (!success) { + // just send back a 0 if it failed + modeBuffer.init(1); + modeBuffer.serialize8(0); + } + // send the mode, could be empty buffer if reading failed + SerialComs::write(modeBuffer); } - ByteStream modeBuffer; - // same doesn't matter if this fails still need to send - bool success = UPDI::readMode(modeIdx, modeBuffer); - // send the mode, could be empty buffer if reading failed - SerialComs::write(modeBuffer); - UPDI::reset(); - UPDI::disable(); // return whether reading the mode was successful return success; } bool EditorConnection::pushModeChromalink() { + // lol just use the mode index as the radial to set + Leds::setRadials(RADIAL_0, (Radial)m_chromaModeIdx, RGB_GREEN4); // wait for the mode then write it via updi ByteStream buf; if (!receiveBuffer(buf)) { @@ -540,26 +589,92 @@ bool EditorConnection::pushModeChromalink() return true; } -bool EditorConnection::writeDuoFirmware() +bool EditorConnection::backupDuoModes() { + if (m_backupModeNum == 9) { + // reset counter for the restore step later + m_backupModeNum = 0; + // done + return true; + } + // backing up the first mode + if (m_backupModeNum == 0) { + // default this to true to begin + m_backupModes = true; + // double check the version and valid header before backing up modes + ByteStream duoHeader; + UPDI::readHeader(duoHeader); + if (duoHeader.size() >= 5) { + uint8_t major = duoHeader.data()[0]; + uint8_t minor = duoHeader.data()[1]; + if (major < 1 || minor < 3) { + // turn off mode backup the version isn't high enough + m_backupModes = false; + } + } + } + // may use the defaults if backing up fails, default is whether backup is enabled + bool useDefault = !m_backupModes; + if (m_backupModes) { + ByteStream &cur = m_modeBackups[m_backupModeNum]; + // if the mode cannot be loaded, or if it's CRC is bad then just use the default + if (!UPDI::readMode(m_backupModeNum, cur) || !cur.checkCRC() || !cur.size()) { + useDefault = true; + } + } + // if not backing up, or backup failed, then store the default mode data in + // the backup because we will always write out the backups after flashing + if (useDefault) { + m_modeBackups[m_backupModeNum].init(duo_default_sizes[m_backupModeNum], duo_default_modes[m_backupModeNum]); + } + Leds::setRadials(RADIAL_0, (Radial)m_backupModeNum, useDefault ? RGB_CYAN0 : RGB_PURPLE); + // go to next mode + m_backupModeNum++; + return false; +} + +bool EditorConnection::restoreDuoModes() +{ + Leds::setRadials(RADIAL_0, (Radial)m_backupModeNum, RGB_CYAN4); + if (m_backupModeNum == 9) { + // reset counter for the restore step later + m_backupModeNum = 0; + // done + return true; + } + // each pass write out the backups, these may be the defaults + UPDI::writeMode(m_backupModeNum, m_modeBackups[m_backupModeNum]); + // go to next mode + m_backupModeNum++; + return false; +} + +bool EditorConnection::writeDuoFirmware() +{ + // render some progress, do it before updating the offset so it starts at 0 + Leds::setAll(RGB_YELLOW3); + Leds::setRadials(RADIAL_0, (Radial)((m_firmwareOffset / (float)m_firmwareSize) * RADIAL_COUNT), RGB_GREEN3); + // first pass and backup modes is enabled + if (m_firmwareOffset >= m_firmwareSize) { + // done + return true; + } // wait for the mode then write it via updi ByteStream buf; if (!receiveBuffer(buf)) { return false; } + // write out the firmware and record it if successful if (!UPDI::writeFirmware(m_firmwareOffset, buf)) { + // big error? this shouldn't happen return false; } m_firmwareOffset += buf.size(); - if (m_firmwareOffset >= m_firmwareSize) { - // done - UPDI::reset(); - UPDI::disable(); - } - // create a progress bar I guess - Leds::setAll(RGB_RED0); - Leds::setRange(LED_0, (LedPos)((m_firmwareOffset / (float)m_firmwareSize) * LED_COUNT), RGB_GREEN3); - return true; + // send ack for each chunk + m_receiveBuffer.clear(); + SerialComs::write(EDITOR_VERB_FLASH_FIRMWARE_ACK); + // not done yet + return false; } void EditorConnection::onShortClickM() @@ -616,6 +731,8 @@ void EditorConnection::handleCommand() m_state = STATE_PUSH_MODE_CHROMALINK; } else if (receiveMessage(EDITOR_VERB_FLASH_FIRMWARE)) { m_state = STATE_CHROMALINK_FLASH_FIRMWARE; + } else if (receiveMessage(EDITOR_VERB_SET_GLOBAL_BRIGHTNESS)) { + m_state = STATE_SET_GLOBAL_BRIGHTNESS; } } @@ -702,7 +819,13 @@ bool EditorConnection::receiveBuffer(ByteStream &buffer) // clear the receive buffer m_receiveBuffer.clear(); if (!buffer.checkCRC()) { - return false; + // TODO: this needs a different return value or something, usually false + // just means keep listening but in this case it listened and received bad + // data so we need to report this somehow + Leds::holdAll(RGB_RED); + buffer.clear(); + // return true otherwise we'll get locked in this state forever + return true; } return true; } @@ -831,6 +954,25 @@ void EditorConnection::clearDemo() m_previewMode.init(); } + +bool EditorConnection::receiveBrightness() +{ + // create a new ByteStream that will hold the full buffer of data + ByteStream buf; + if (!receiveBuffer(buf)) { + return false; + } + if (!buf.size()) { + // failure but cannot return false we'll get stuck + return true; + } + uint8_t brightness = buf.data()[0]; + if (brightness > 0) { + Leds::setBrightness(brightness); + } + return true; +} + void EditorConnection::receiveModeVL() { // if reveiving new data set our last data time diff --git a/VortexEngine/src/Menus/MenuList/EditorConnection.h b/VortexEngine/src/Menus/MenuList/EditorConnection.h index e73e724cfc..109d819308 100644 --- a/VortexEngine/src/Menus/MenuList/EditorConnection.h +++ b/VortexEngine/src/Menus/MenuList/EditorConnection.h @@ -24,7 +24,10 @@ class EditorConnection : public Menu bool pushHeaderChromalink(); bool pullModeChromalink(); bool pushModeChromalink(); + bool writeDuoFirmware(); + bool backupDuoModes(); + bool restoreDuoModes(); // handlers for clicks void onShortClickM() override; @@ -49,6 +52,7 @@ class EditorConnection : public Menu bool receiveDemoMode(); bool receiveMessage(const char *message); void clearDemo(); + bool receiveBrightness(); void receiveModeVL(); void showReceiveModeVL(); bool receiveModeIdx(uint8_t &idx); @@ -104,6 +108,10 @@ class EditorConnection : public Menu STATE_PUSH_EACH_MODE_WAIT, STATE_PUSH_EACH_MODE_DONE, + // set global brightness + STATE_SET_GLOBAL_BRIGHTNESS, + STATE_SET_GLOBAL_BRIGHTNESS_RECEIVE, + // pull the header from the chromalinked duo STATE_PULL_HEADER_CHROMALINK, @@ -123,7 +131,14 @@ class EditorConnection : public Menu // flash the firmware of the chromalinked duo STATE_CHROMALINK_FLASH_FIRMWARE, STATE_CHROMALINK_FLASH_FIRMWARE_RECEIVE_SIZE, - STATE_CHROMALINK_FLASH_FIRMWARE_RECEIVE, + STATE_CHROMALINK_FLASH_FIRMWARE_BACKUP_MODES, + STATE_CHROMALINK_FLASH_FIRMWARE_ERASE_MEMORY, + STATE_CHROMALINK_FLASH_FIRMWARE_FLASH_CHUNKS, + STATE_CHROMALINK_FLASH_FIRMWARE_RESTORE_MODES, + STATE_CHROMALINK_FLASH_FIRMWARE_DONE, + + // toggle whether flashing firmware will backup modes + STATE_CHROMALINK_FLASH_FIRMWARE_TOGGLE_BACKUP, }; // state of the editor @@ -147,6 +162,13 @@ class EditorConnection : public Menu uint32_t m_firmwareSize; // how much firmware written so far uint32_t m_firmwareOffset; + + // whether to backup duo modes on firmware update + bool m_backupModes; + // backups of duo modes when flashing firmware + ByteStream m_modeBackups[9]; + // counter for reading/writing modes during firmware flash + uint8_t m_backupModeNum; }; #endif diff --git a/VortexEngine/src/Modes/DuoDefaultModes.cpp b/VortexEngine/src/Modes/DuoDefaultModes.cpp new file mode 100644 index 0000000000..9143d0da9a --- /dev/null +++ b/VortexEngine/src/Modes/DuoDefaultModes.cpp @@ -0,0 +1,83 @@ +#include "DuoDefaultModes.h" + +// 14 0 0 0 0 0 0 0 +// 51 31 69 110 2 6 6 3 +// 255 0 0 0 255 0 0 0 +// 255 0 +const uint8_t duo_mode1[] = { + 0x02, 0x06, 0x06, 0x03, + 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0xFF, 0x00 +}; +const uint8_t duo_mode2[] = { + 0x02, 0x02, 0x1C, 0x03, + 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0xFF, 0x00, 0x19, 0x03, 0xFF, 0x00, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00 +}; +const uint8_t duo_mode3[] = { + 0x02, 0x02, 0x00, 0x01, + 0x97, 0x70, 0x9F, 0x00, 0x07, 0x01, 0x4D, 0x00, + 0xB2, 0x00 +}; +const uint8_t duo_mode4[] = { + 0x02, 0x02, 0x00, 0x06, + 0xC4, 0x70, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x00, 0x17, 0x00, 0x00, 0x3B, 0x00, 0x00, 0xE9, + 0x4E, 0x00, 0x00, 0x03, 0x03, 0xC4, 0x4D, 0x00, + 0x00, 0x00, 0x17, 0x3B, 0xB2, 0xE9, 0x00 +}; +const uint8_t duo_mode5[] = { + 0x02, 0x06, 0x0E, 0x07, + 0xFF, 0x23, 0x00, 0x00, 0x06, 0x48, 0xFF, 0xC6, + 0x55, 0xFF, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x66, 0x55, 0xFF, 0x55, 0x57, 0x00 +}; +const uint8_t duo_mode6[] = { + 0x02, 0x06, 0x0D, 0x05, + 0x9F, 0x00, 0x00, 0x5A, 0xFF, 0xFF, 0xFF, 0x9F, + 0x00, 0x00, 0x00, 0x66, 0xFF, 0xFF, 0x9F, 0x00 +}; +const uint8_t duo_mode7[] = { + 0x02, 0x06, 0x05, 0x05, + 0x00, 0x00, 0x30, 0xFF, 0x54, 0xAA, 0xB1, 0x00, + 0x00, 0x1B, 0x90, 0xFF, 0x55, 0x2D, 0x00, 0x00 +}; +const uint8_t duo_mode8[] = { + 0x02, 0x02, 0x08, 0x05, + 0x00, 0x40, 0x54, 0x52, 0x26, 0x00, 0x00, 0x00, + 0x54, 0xAA, 0xFF, 0x55, 0x0B, 0x00, 0x00, 0x00, + 0x08, 0x07, 0xFF, 0x23, 0x00, 0x00, 0x06, 0x48, + 0xFF, 0xC6, 0x55, 0xFF, 0x43, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x55, 0xFF, 0x55, 0x57, 0x00 +}; +const uint8_t duo_mode9[] = { + 0x02, 0x02, 0x04, 0x02, + 0xFF, 0x00, 0xF6, 0x08, 0x00, 0x80, 0x00, 0x01, + 0x02, 0xFF, 0x00, 0xF6, 0x08, 0x00, 0x80, 0x00 +}; + +const uint8_t *duo_default_modes[9] = { + duo_mode1, + duo_mode2, + duo_mode3, + duo_mode4, + duo_mode5, + duo_mode6, + duo_mode7, + duo_mode8, + duo_mode9, +}; + +const uint32_t duo_default_sizes[9] = { + sizeof(duo_mode1), + sizeof(duo_mode2), + sizeof(duo_mode3), + sizeof(duo_mode4), + sizeof(duo_mode5), + sizeof(duo_mode6), + sizeof(duo_mode7), + sizeof(duo_mode8), + sizeof(duo_mode9), +}; + diff --git a/VortexEngine/src/Modes/DuoDefaultModes.h b/VortexEngine/src/Modes/DuoDefaultModes.h new file mode 100644 index 0000000000..9f03696bcd --- /dev/null +++ b/VortexEngine/src/Modes/DuoDefaultModes.h @@ -0,0 +1,6 @@ +#pragma once +#include + +// array of the default mode data and sizes +extern const uint8_t *duo_default_modes[9]; +extern const uint32_t duo_default_sizes[9]; diff --git a/VortexEngine/src/UPDI/updi.cpp b/VortexEngine/src/UPDI/updi.cpp index a4303794af..3acc522b72 100644 --- a/VortexEngine/src/UPDI/updi.cpp +++ b/VortexEngine/src/UPDI/updi.cpp @@ -104,7 +104,9 @@ bool UPDI::readHeader(ByteStream &header) if (!header.init(DUO_HEADER_SIZE)) { return false; } - enterProgrammingMode(); + if (!enterProgrammingMode()) { + return false; + } uint8_t *ptr = (uint8_t *)header.rawData(); uint16_t addr = DUO_EEPROM_BASE; stptr_p((const uint8_t *)&addr, 2); @@ -132,7 +134,6 @@ bool UPDI::readHeader(ByteStream &header) if (!header.checkCRC()) { header.clear(); ERROR_LOG("ERROR Header CRC Invalid!"); - reset(); return false; } // major.minor are the first two bytes of the buffer @@ -158,7 +159,9 @@ bool UPDI::readHeaderLegacy1(ByteStream &header) if (!header.init(LEGACY_DUO_HEADER_SIZE_1)) { return false; } - enterProgrammingMode(); + if (!enterProgrammingMode()) { + return false; + } uint8_t *ptr = (uint8_t *)header.rawData(); uint16_t addr = DUO_EEPROM_BASE; stptr_p((const uint8_t *)&addr, 2); @@ -191,7 +194,9 @@ bool UPDI::readHeaderLegacy2(ByteStream &header) if (!header.init(LEGACY_DUO_HEADER_SIZE_2)) { return false; } - //enterProgrammingMode(); + //if (!enterProgrammingMode()) { + // return false; + //} uint8_t *ptr = (uint8_t *)header.rawData(); uint16_t addr = DUO_EEPROM_BASE; stptr_p((const uint8_t *)&addr, 2); @@ -228,9 +233,13 @@ bool UPDI::readMode(uint8_t idx, ByteStream &modeBuffer) } // initialize mode buffer if (!modeBuffer.init(DUO_MODE_SIZE)) { + modeBuffer.clear(); + return false; + } + if (!enterProgrammingMode()) { + modeBuffer.clear(); return false; } - enterProgrammingMode(); // DUO_MODE_SIZE is the max duo mode size (the slot size) uint8_t *ptr = (uint8_t *)modeBuffer.rawData(); uint16_t numBytes = modeBuffer.rawSize(); @@ -259,7 +268,6 @@ bool UPDI::readMode(uint8_t idx, ByteStream &modeBuffer) if (!modeBuffer.checkCRC()) { modeBuffer.clear(); ERROR_LOG("ERROR Header CRC Invalid!"); - reset(); return false; } #endif @@ -273,7 +281,9 @@ bool UPDI::writeHeader(ByteStream &headerBuffer) // nope! return false; } - enterProgrammingMode(); + if (!enterProgrammingMode()) { + return false; + } // DUO_EEPROM_BASE is eeprom base // DUO_HEADER_FULL_SIZE is size of duo header // DUO_MODE_SIZE is size of each duo mode @@ -330,7 +340,9 @@ bool UPDI::writeMode(uint8_t idx, ByteStream &modeBuffer) #ifdef VORTEX_EMBEDDED bool UPDI::writeModeEeprom(uint8_t idx, ByteStream &modeBuffer) { - enterProgrammingMode(); + if (!enterProgrammingMode()) { + return false; + } // DUO_EEPROM_BASE is eeprom base // DUO_HEADER_FULL_SIZE is size of duo header // DUO_MODE_SIZE is size of each duo mode @@ -448,7 +460,9 @@ bool UPDI::writeModeEeprom(uint8_t idx, ByteStream &modeBuffer) bool UPDI::writeModeFlash(uint8_t idx, ByteStream &modeBuffer) { - enterProgrammingMode(); + if (!enterProgrammingMode()) { + return false; + } // there are 3 modes in the eeprom after the header // DUO_FLASH_STORAGE_BASE is the end of flash, 0x200 before uint16_t base = DUO_FLASH_STORAGE_BASE + ((idx - 3) * DUO_MODE_SIZE); @@ -652,7 +666,9 @@ bool UPDI::writeFirmware(uint32_t position, ByteStream &firmwareBuffer) reset(); return false; } - enterProgrammingMode(); + if (!enterProgrammingMode()) { + return false; + } // DUO_MODE_SIZE is the max duo mode size (the slot size) uint8_t *ptr = (uint8_t *)firmwareBuffer.data(); // there are 3 modes in the eeprom after the header @@ -720,20 +736,20 @@ bool UPDI::disable() } #ifdef VORTEX_EMBEDDED +#define MAX_TRIES 1000 -void UPDI::enterProgrammingMode() +bool UPDI::enterProgrammingMode() { uint8_t mode; - while (1) { + uint32_t tries = 0; + while (tries++ < MAX_TRIES) { sendDoubleBreak(); stcs(Control_A, 0x6); mode = cpu_mode<0xEF>(); if (mode != 0x82 && mode != 0x21 && mode != 0xA2 && mode != 0x08) { - //sendDoubleBreak(); + ERROR_LOGF("Bad CPU Mode 0x%02x... error: 0x%02x", mode, status); sendBreak(); uint8_t status = ldcs(Status_B); - ERROR_LOGF("Bad CPU Mode 0x%02x... error: 0x%02x", mode, status); - //reset(); continue; } if (mode != 0x08) { @@ -742,17 +758,23 @@ void UPDI::enterProgrammingMode() if (status != 0x10) { ERROR_LOGF("Bad prog key status: 0x%02x", status); reset(); + //sendBreak(); + //uint8_t status = ldcs(Status_B); continue; } reset(); } - // break the while (1) break; } + if (tries >= MAX_TRIES) { + Leds::holdAll(RGB_RED); + return false; + } mode = cpu_mode(); while (mode != 0x8) { mode = cpu_mode(); } + return true; } void UPDI::resetOn() diff --git a/VortexEngine/src/UPDI/updi.h b/VortexEngine/src/UPDI/updi.h index eac29a1f10..db675260bf 100644 --- a/VortexEngine/src/UPDI/updi.h +++ b/VortexEngine/src/UPDI/updi.h @@ -109,7 +109,7 @@ class UPDI NVM_WFU /* Write fuse */ }; - static void enterProgrammingMode(); + static bool enterProgrammingMode(); static void resetOn(); static bool resetOff(); diff --git a/VortexEngine/src/VortexConfig.h b/VortexEngine/src/VortexConfig.h index 55404c349a..8e7288aa88 100644 --- a/VortexEngine/src/VortexConfig.h +++ b/VortexEngine/src/VortexConfig.h @@ -540,6 +540,10 @@ // done flashing firmware #define EDITOR_VERB_FLASH_FIRMWARE_DONE "K" +// set the global brightness of the device +#define EDITOR_VERB_SET_GLOBAL_BRIGHTNESS "L" + + // =================================================================== // Manually Configured Sizes //