diff --git a/sdk/Windows/SMX.vcxproj b/sdk/Windows/SMX.vcxproj
index 2052e98..f6d82ad 100644
--- a/sdk/Windows/SMX.vcxproj
+++ b/sdk/Windows/SMX.vcxproj
@@ -14,6 +14,7 @@
+
@@ -28,6 +29,7 @@
+
@@ -146,4 +148,4 @@
-
+
\ No newline at end of file
diff --git a/sdk/Windows/SMX.vcxproj.filters b/sdk/Windows/SMX.vcxproj.filters
index 4ca4d76..b220650 100644
--- a/sdk/Windows/SMX.vcxproj.filters
+++ b/sdk/Windows/SMX.vcxproj.filters
@@ -46,6 +46,9 @@
Source Files
+
+ Source Files
+
@@ -84,5 +87,8 @@
Source Files
+
+ Source Files
+
-
+
\ No newline at end of file
diff --git a/sdk/Windows/SMXConfigPacket.cpp b/sdk/Windows/SMXConfigPacket.cpp
new file mode 100644
index 0000000..fe53b85
--- /dev/null
+++ b/sdk/Windows/SMXConfigPacket.cpp
@@ -0,0 +1,169 @@
+#include "SMXConfigPacket.h"
+#include
+#include
+
+// The config packet format changed in version 5. This handles compatibility with
+// the old configuration packet. The config packet in SMX.h matches the new format.
+//
+
+
+#pragma pack(push, 1)
+struct OldSMXConfig
+{
+ uint8_t unused1 = 0xFF, unused2 = 0xFF;
+ uint8_t unused3 = 0xFF, unused4 = 0xFF;
+ uint8_t unused5 = 0xFF, unused6 = 0xFF;
+
+ uint16_t masterDebounceMilliseconds = 0;
+ uint8_t panelThreshold7Low = 0xFF, panelThreshold7High = 0xFF; // was "cardinal"
+ uint8_t panelThreshold4Low = 0xFF, panelThreshold4High = 0xFF; // was "center"
+ uint8_t panelThreshold2Low = 0xFF, panelThreshold2High = 0xFF; // was "corner"
+
+ uint16_t panelDebounceMicroseconds = 4000;
+ uint16_t autoCalibrationPeriodMilliseconds = 1000;
+ uint8_t autoCalibrationMaxDeviation = 100;
+ uint8_t badSensorMinimumDelaySeconds = 15;
+ uint16_t autoCalibrationAveragesPerUpdate = 60;
+
+ uint8_t unused7 = 0xFF, unused8 = 0xFF;
+
+ uint8_t panelThreshold1Low = 0xFF, panelThreshold1High = 0xFF; // was "up"
+
+ uint8_t enabledSensors[5];
+
+ uint8_t autoLightsTimeout = 1000/128; // 1 second
+
+ uint8_t stepColor[3*9];
+
+ uint8_t panelRotation;
+
+ uint16_t autoCalibrationSamplesPerAverage = 500;
+
+ uint8_t masterVersion = 0xFF;
+ uint8_t configVersion = 0x03;
+
+ uint8_t unused9[10];
+ uint8_t panelThreshold0Low, panelThreshold0High;
+ uint8_t panelThreshold3Low, panelThreshold3High;
+ uint8_t panelThreshold5Low, panelThreshold5High;
+ uint8_t panelThreshold6Low, panelThreshold6High;
+ uint8_t panelThreshold8Low, panelThreshold8High;
+
+ uint16_t debounceDelayMilliseconds = 0;
+
+ uint8_t padding[164];
+};
+#pragma pack(pop)
+static_assert(offsetof(OldSMXConfig, padding) == 86, "Incorrect padding alignment");
+static_assert(sizeof(OldSMXConfig) == 250, "Expected 250 bytes");
+
+void ConvertToNewConfig(const vector &oldConfigData, SMXConfig &newConfig)
+{
+ // Copy data in its order within OldSMXConfig. This lets us easily stop at each
+ // known packet version. Any fields that aren't present in oldConfigData will be
+ // left at their default values in SMXConfig.
+ const OldSMXConfig &oldConfig = (OldSMXConfig &) *oldConfigData.data();
+
+ newConfig.debounceNodelayMilliseconds = oldConfig.masterDebounceMilliseconds;
+
+ newConfig.panelSettings[7].loadCellLowThreshold = oldConfig.panelThreshold7Low;
+ newConfig.panelSettings[4].loadCellLowThreshold = oldConfig.panelThreshold4Low;
+ newConfig.panelSettings[2].loadCellLowThreshold = oldConfig.panelThreshold2Low;
+
+ newConfig.panelSettings[7].loadCellHighThreshold = oldConfig.panelThreshold7High;
+ newConfig.panelSettings[4].loadCellHighThreshold = oldConfig.panelThreshold4High;
+ newConfig.panelSettings[2].loadCellHighThreshold = oldConfig.panelThreshold2High;
+
+ newConfig.panelDebounceMicroseconds = oldConfig.panelDebounceMicroseconds;
+ newConfig.autoCalibrationMaxDeviation = oldConfig.autoCalibrationMaxDeviation;
+ newConfig.badSensorMinimumDelaySeconds = oldConfig.badSensorMinimumDelaySeconds;
+ newConfig.autoCalibrationAveragesPerUpdate = oldConfig.autoCalibrationAveragesPerUpdate;
+
+ newConfig.panelSettings[1].loadCellLowThreshold = oldConfig.panelThreshold1Low;
+ newConfig.panelSettings[1].loadCellHighThreshold = oldConfig.panelThreshold1High;
+
+ memcpy(newConfig.enabledSensors, oldConfig.enabledSensors, sizeof(newConfig.enabledSensors));
+ newConfig.autoLightsTimeout = oldConfig.autoLightsTimeout;
+ memcpy(newConfig.stepColor, oldConfig.stepColor, sizeof(newConfig.stepColor));
+ newConfig.panelRotation = oldConfig.panelRotation;
+ newConfig.autoCalibrationSamplesPerAverage = oldConfig.autoCalibrationSamplesPerAverage;
+
+ if(oldConfig.configVersion == 0xFF)
+ return;
+
+ newConfig.masterVersion = oldConfig.masterVersion;
+ newConfig.configVersion = oldConfig.configVersion;
+
+ if(oldConfig.configVersion < 2)
+ return;
+
+ newConfig.panelSettings[0].loadCellLowThreshold = oldConfig.panelThreshold0Low;
+ newConfig.panelSettings[3].loadCellLowThreshold = oldConfig.panelThreshold3Low;
+ newConfig.panelSettings[5].loadCellLowThreshold = oldConfig.panelThreshold5Low;
+ newConfig.panelSettings[6].loadCellLowThreshold = oldConfig.panelThreshold6Low;
+ newConfig.panelSettings[8].loadCellLowThreshold = oldConfig.panelThreshold8Low;
+
+ newConfig.panelSettings[0].loadCellHighThreshold = oldConfig.panelThreshold0High;
+ newConfig.panelSettings[3].loadCellHighThreshold = oldConfig.panelThreshold3High;
+ newConfig.panelSettings[5].loadCellHighThreshold = oldConfig.panelThreshold5High;
+ newConfig.panelSettings[6].loadCellHighThreshold = oldConfig.panelThreshold6High;
+ newConfig.panelSettings[8].loadCellHighThreshold = oldConfig.panelThreshold8High;
+
+ if(oldConfig.configVersion < 3)
+ return;
+
+ newConfig.debounceDelayMilliseconds = oldConfig.debounceDelayMilliseconds;
+}
+
+// oldConfigData contains the data we're replacing. Any fields that exist in the old
+// config format and not the new one will be left unchanged.
+void ConvertToOldConfig(const SMXConfig &newConfig, vector &oldConfigData)
+{
+ OldSMXConfig &oldConfig = (OldSMXConfig &) *oldConfigData.data();
+
+ // We don't need to check configVersion here. It's safe to set all fields in
+ // the output config packet. If oldConfigData isn't 128 bytes, extend it.
+ if(oldConfigData.size() < 128)
+ oldConfigData.resize(128, 0xFF);
+
+ oldConfig.masterDebounceMilliseconds = newConfig.debounceNodelayMilliseconds;
+
+ oldConfig.panelThreshold7Low = newConfig.panelSettings[7].loadCellLowThreshold;
+ oldConfig.panelThreshold4Low = newConfig.panelSettings[4].loadCellLowThreshold;
+ oldConfig.panelThreshold2Low = newConfig.panelSettings[2].loadCellLowThreshold;
+
+ oldConfig.panelThreshold7High = newConfig.panelSettings[7].loadCellHighThreshold;
+ oldConfig.panelThreshold4High = newConfig.panelSettings[4].loadCellHighThreshold;
+ oldConfig.panelThreshold2High = newConfig.panelSettings[2].loadCellHighThreshold;
+
+ oldConfig.panelDebounceMicroseconds = newConfig.panelDebounceMicroseconds;
+ oldConfig.autoCalibrationMaxDeviation = newConfig.autoCalibrationMaxDeviation;
+ oldConfig.badSensorMinimumDelaySeconds = newConfig.badSensorMinimumDelaySeconds;
+ oldConfig.autoCalibrationAveragesPerUpdate = newConfig.autoCalibrationAveragesPerUpdate;
+
+ oldConfig.panelThreshold1Low = newConfig.panelSettings[1].loadCellLowThreshold;
+ oldConfig.panelThreshold1High = newConfig.panelSettings[1].loadCellHighThreshold;
+
+ memcpy(oldConfig.enabledSensors, newConfig.enabledSensors, sizeof(newConfig.enabledSensors));
+ oldConfig.autoLightsTimeout = newConfig.autoLightsTimeout;
+ memcpy(oldConfig.stepColor, newConfig.stepColor, sizeof(newConfig.stepColor));
+ oldConfig.panelRotation = newConfig.panelRotation;
+ oldConfig.autoCalibrationSamplesPerAverage = newConfig.autoCalibrationSamplesPerAverage;
+
+ oldConfig.masterVersion = newConfig.masterVersion;
+ oldConfig.configVersion= newConfig.configVersion;
+
+ oldConfig.panelThreshold0Low = newConfig.panelSettings[0].loadCellLowThreshold;
+ oldConfig.panelThreshold3Low = newConfig.panelSettings[3].loadCellLowThreshold;
+ oldConfig.panelThreshold5Low = newConfig.panelSettings[5].loadCellLowThreshold;
+ oldConfig.panelThreshold6Low = newConfig.panelSettings[6].loadCellLowThreshold;
+ oldConfig.panelThreshold8Low = newConfig.panelSettings[8].loadCellLowThreshold;
+
+ oldConfig.panelThreshold0High = newConfig.panelSettings[0].loadCellHighThreshold;
+ oldConfig.panelThreshold3High = newConfig.panelSettings[3].loadCellHighThreshold;
+ oldConfig.panelThreshold5High = newConfig.panelSettings[5].loadCellHighThreshold;
+ oldConfig.panelThreshold6High = newConfig.panelSettings[6].loadCellHighThreshold;
+ oldConfig.panelThreshold8High = newConfig.panelSettings[8].loadCellHighThreshold;
+
+ oldConfig.debounceDelayMilliseconds = newConfig.debounceDelayMilliseconds;
+}
diff --git a/sdk/Windows/SMXConfigPacket.h b/sdk/Windows/SMXConfigPacket.h
new file mode 100644
index 0000000..563a9af
--- /dev/null
+++ b/sdk/Windows/SMXConfigPacket.h
@@ -0,0 +1,12 @@
+#ifndef SMXConfigPacket_h
+#define SMXConfigPacket_h
+
+#include
+using namespace std;
+
+#include "../SMX.h"
+
+void ConvertToNewConfig(const vector &oldConfig, SMXConfig &newConfig);
+void ConvertToOldConfig(const SMXConfig &newConfig, vector &oldConfigData);
+
+#endif
diff --git a/sdk/Windows/SMXDevice.cpp b/sdk/Windows/SMXDevice.cpp
index 2304559..1c904ae 100644
--- a/sdk/Windows/SMXDevice.cpp
+++ b/sdk/Windows/SMXDevice.cpp
@@ -4,6 +4,7 @@
#include "Helpers.h"
#include "SMXDeviceConnection.h"
#include "SMXDeviceSearch.h"
+#include "SMXConfigPacket.h"
#include
#include
#include
@@ -283,12 +284,28 @@ void SMX::SMXDevice::HandlePackets()
continue;
}
- // Copy in the configuration.
- // Log(ssprintf("Read back configuration: %i bytes, first byte %i", iSize, buf[2]));
- memcpy(&config, buf.data()+2, min(iSize, sizeof(config)));
+ // Store the raw config data in rawConfig. For V1-4 firmwares, this is the
+ // old config format.
+ rawConfig.resize(iSize);
+ memcpy(rawConfig.data(), buf.data()+2, min(iSize, sizeof(config)));
+
+ if(buf[0] == 'g')
+ {
+ // Convert the old config format to the new one, so the rest of the SDK and
+ // user code doesn't need to deal with multiple formats.
+ ConvertToNewConfig(rawConfig, config);
+ }
+ else
+ {
+ // This is the new config format. Copy it directly into config.
+ memcpy(&config, buf.data()+2, min(iSize, sizeof(config)));
+ }
+
m_bHaveConfig = true;
buf.erase(buf.begin(), buf.begin()+iSize+2);
+ // Log(ssprintf("Read back configuration: %i bytes, first byte %i", iSize, buf[2]));
+
CallUpdateCallback(SMXUpdateCallback_Updated);
break;
}
@@ -322,18 +339,24 @@ void SMX::SMXDevice::SendConfig()
// Write configuration command. This is "w" in versions 1-4, and "W" in versions 5
// and newer.
string sData = ssprintf(deviceInfo.m_iFirmwareVersion >= 5? "W":"w");
- int8_t iSize = sizeof(SMXConfig);
-
- // Firmware through version 3 allowed config packets up to 128 bytes. Additions
- // to the packet later on brought it up to 126, so the maximum was raised to 250.
- // Older firmware won't use the extra fields, but will ignore the packet if it's
- // larger than it supports, so just truncate the packet for these devices to make
- // sure this doesn't happen.
- if(config.masterVersion <= 3)
- iSize = min(iSize, offsetof(SMXConfig, flags));
-
- sData.append((char *) &iSize, sizeof(iSize));
- sData.append((char *) &wanted_config, sizeof(wanted_config));
+
+ // Append the config packet.
+ if(deviceInfo.m_iFirmwareVersion < 5)
+ {
+ // Convert wanted_config to the old configuration format.
+ vector outputConfig = rawConfig;
+ ConvertToOldConfig(wanted_config, outputConfig);
+
+ uint8_t iSize = (uint8_t) outputConfig.size();
+ sData.append((char *) &iSize, sizeof(iSize));
+ sData.append((char *) outputConfig.data(), outputConfig.size());
+ }
+ else
+ {
+ int8_t iSize = sizeof(SMXConfig);
+ sData.append((char *) &iSize, sizeof(iSize));
+ sData.append((char *) &wanted_config, sizeof(wanted_config));
+ }
// Don't send another config packet until this one finishes, so if we get a bunch of
// SetConfig calls quickly we won't spam the device, which can get slow.
diff --git a/sdk/Windows/SMXDevice.h b/sdk/Windows/SMXDevice.h
index ce9ef9c..44c2f0f 100644
--- a/sdk/Windows/SMXDevice.h
+++ b/sdk/Windows/SMXDevice.h
@@ -103,6 +103,7 @@ private:
// The configuration we've read from the device. m_bHaveConfig is true if we've received
// a configuration from the device since we've connected to it.
SMXConfig config;
+ vector rawConfig;
bool m_bHaveConfig = false;
// This is the configuration the user has set, if he's changed anything. We send this to