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
//