diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..8fd4d3ac --- /dev/null +++ b/.clang-format @@ -0,0 +1,6 @@ +BasedOnStyle: Google +ColumnLimit: 120 +IndentWidth: 4 +TabWidth: 4 +UseTab: ForContinuationAndIndentation +AccessModifierOffset: -4 diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..7cc83cf3 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +indent_style = tab +indent_size = 4 +charset = utf-8 +trim_trailing_whitespace = false +insert_final_newline = true + +[*.{yml,yaml}] +indent_style = space +indent_size = 2 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 00000000..ceef5292 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,22 @@ +name: Check Code Format + +on: [push, pull_request] + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + - name: Check src format + uses: DoozyX/clang-format-lint-action@v0.5 + with: + source: './src' + extensions: 'h,cpp' + clangFormatVersion: 9 + - name: Check examples format + uses: DoozyX/clang-format-lint-action@v0.5 + with: + source: './examples' + extensions: 'h,cpp,ino' + clangFormatVersion: 9 diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 1d2f18fc..0a2d4560 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -2,85 +2,65 @@ on: [push, pull_request] name: Test jobs: test: - name: Test ${{ matrix.sketch }} for ${{ matrix.board }} + name: Test for ${{ matrix.board }} runs-on: ubuntu-latest strategy: matrix: - sketch: [LightingNodePRO, SingleStripLightingNodePRO, CommanderPRO, DeviceIDTool, RepeatAndScale, TransformLLFansFormatToStrip, LS100, LightingNodeCORE, NonAddressable, AmbientBacklight] - board: ["arduino:avr:leonardo", "arduino:avr:micro", "SparkFun:avr:promicro:cpu=16MHzatmega32U4"] + board: + [ + "Legion2:avr:leonardoclp", + "Legion2:avr:promicro5vclp", + "Legion2:avr:promicro3vclp", + ] steps: - - uses: actions/checkout@master - - name: Install FastLED - uses: Legion2/download-release-action@master - with: - repository: FastLED/FastLED - tag: '3.2.0' - path: libraries - - name: Install SparkFun boards - if: contains(matrix.board, 'SparkFun') - run: | - mkdir -p hardware/SparkFun - cd hardware/SparkFun - wget https://github.com/sparkfun/Arduino_Boards/raw/master/IDE_Board_Manager/sparkfunboards.1.1.5.tar.bz2 - tar -xvjf sparkfunboards.1.1.5.tar.bz2 - rm sparkfunboards.1.1.5.tar.bz2 - mv avr-1.1.5 avr - - name: Build ${{ matrix.sketch }} for ${{ matrix.board }} - uses: Legion2/arduino-builder-action@v2.0.0 - with: - board: ${{ matrix.board }} - sketch: ./examples/${{ matrix.sketch }}/${{ matrix.sketch }}.ino + - uses: actions/checkout@master + - name: Build for ${{ matrix.board }} + uses: ArminJo/arduino-test-compile@v2.0.0 + with: + arduino-board-fqbn: ${{ matrix.board }} + platform-url: https://raw.githubusercontent.com/sparkfun/Arduino_Boards/master/IDE_Board_Manager/package_sparkfun_index.json,https://raw.githubusercontent.com/Legion2/CorsairLightingProtocolBoards/master/package_Legion2_CorsairLightingProtocolBoards_index.json + arduino-platform: arduino:avr@1.8.2,SparkFun:avr@1.1.5,Legion2:avr@0.1.3 + required-libraries: FastLED@3.2.0 + sketch-names: LightingNodePRO.ino, + SingleStripLightingNodePRO.ino, + CommanderPRO.ino, + DeviceIDTool.ino, + RepeatAndScale.ino, + TransformLLFansFormatToStrip.ino, + LS100.ino, + LightingNodeCORE.ino, + NonAddressable.ino, + AmbientBacklight.ino, + DebugSketch.ino + examples-build-properties: '{"DebugSketch": "-DDEBUG -DVERBOSE -DPRINT_COMMAND=true -DPRINT_RESPONSE=true -DPRINT_LOOP=true -DPRINT_UPDATE=true"}' testUnoMega: - name: Test UnoMega ${{ matrix.sketch }} for ${{ matrix.board }} + name: Test UnoMega sketches for ${{ matrix.board }} runs-on: ubuntu-latest strategy: matrix: - sketch: [HoodLoader2UnoMegaController] board: ["arduino:avr:uno", "arduino:avr:mega:cpu=atmega2560"] steps: - - uses: actions/checkout@master - - name: Install FastLED - uses: Legion2/download-release-action@master - with: - repository: FastLED/FastLED - tag: '3.2.0' - path: libraries - - name: Build ${{ matrix.sketch }} for ${{ matrix.board }} - uses: Legion2/arduino-builder-action@v2.0.0 - with: - board: ${{ matrix.board }} - sketch: ./examples/${{ matrix.sketch }}/${{ matrix.sketch }}.ino + - uses: actions/checkout@master + - name: Build for ${{ matrix.board }} + uses: ArminJo/arduino-test-compile@v2.0.0 + with: + arduino-board-fqbn: ${{ matrix.board }} + arduino-platform: arduino:avr@1.8.2 + required-libraries: FastLED@3.2.0 + sketch-names: HoodLoader2UnoMegaController.ino test16u2: - name: Test 16u2 ${{ matrix.sketch }} for ${{ matrix.board }} + name: Test 16u2 sketch for ${{ matrix.board }} runs-on: ubuntu-latest strategy: matrix: - sketch: [HoodLoader2CLPBridge] - board: ["HoodLoader2:avr:HoodLoader2atmega16u2:board=uno", "HoodLoader2:avr:HoodLoader2atmega16u2:board=mega2560"] + board: ["Legion2:avr:HoodLoader2atmega16u2clp"] steps: - - uses: actions/checkout@master - - name: Install FastLED - uses: Legion2/download-release-action@master - with: - repository: FastLED/FastLED - tag: '3.2.0' - path: libraries - - name: Download HoodLoader2 - uses: Legion2/download-release-action@master - with: - repository: NicoHood/HoodLoader2 - tag: '2.0.5' - path: hardware/HoodLoader2 - file: '2.0.5-boards_manager.zip' - - name: Install HoodLoader2 - run: | - cd hardware/HoodLoader2 - sudo mv 2.0.5-boards_manager.zip some.zip - sudo unzip some.zip - sudo rm some.zip - sudo mv * avr - - name: Build ${{ matrix.sketch }} for ${{ matrix.board }} - uses: Legion2/arduino-builder-action@v2.0.0 - with: - board: ${{ matrix.board }} - sketch: ./examples/${{ matrix.sketch }}/${{ matrix.sketch }}.ino + - uses: actions/checkout@master + - name: Build for ${{ matrix.board }} + uses: ArminJo/arduino-test-compile@v2.0.0 + with: + arduino-board-fqbn: ${{ matrix.board }} + platform-url: https://raw.githubusercontent.com/NicoHood/HoodLoader2/master/package_NicoHood_HoodLoader2_index.json,https://raw.githubusercontent.com/Legion2/CorsairLightingProtocolBoards/master/package_Legion2_CorsairLightingProtocolBoards_index.json + arduino-platform: arduino:avr@1.8.2,HoodLoader2:avr@2.0.5,Legion2:avr@0.1.3 + required-libraries: FastLED@3.2.0 + sketch-names: HoodLoader2CLPBridge.ino diff --git a/.gitignore b/.gitignore index be01b385..f3640dd6 100644 --- a/.gitignore +++ b/.gitignore @@ -272,3 +272,7 @@ __vm/ # VS Code settings .vscode/ + +# Arduino CLI +*.elf +*.hex diff --git a/README.md b/README.md index b0806f61..c49de354 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,11 @@ **This library can be used to integrate custom/unofficial RGB strips with iCUE.** ## Features -* Add support of the Lighting Node PRO protocol to Arduino. -* Control LEDs with the Corsair Link or the iCUE software. +* Add support of Corsair DIY device protocol to Arduino. +* Control LEDs with the [Corsair iCUE software](https://www.corsair.com/icue). * Easy to use with [FastLED](http://fastled.io/). -* [Supported LED chipsets](https://github.com/FastLED/FastLED/wiki/Overview#chipsets). +* [Supported LED chipsets](https://github.com/FastLED/FastLED/wiki/Overview#chipsets). (e.g. WS2812B, WS2801) +* Supported platform: Arduino AVR * Persistent settings for use without a USB connection. * Use multiple devices at the same time. * Repeat or scale LED channels to arbitrary size. diff --git a/examples/.clang-format b/examples/.clang-format new file mode 100644 index 00000000..4b647f12 --- /dev/null +++ b/examples/.clang-format @@ -0,0 +1,10 @@ +BasedOnStyle: Google +ColumnLimit: 120 +IndentWidth: 4 +TabWidth: 4 +UseTab: ForContinuationAndIndentation +AccessModifierOffset: -4 + +AllowShortBlocksOnASingleLine: false +AllowShortFunctionsOnASingleLine: false +AllowShortLambdasOnASingleLine: false diff --git a/examples/AmbientBacklight/AmbientBacklight.ino b/examples/AmbientBacklight/AmbientBacklight.ino index 9f7f6055..d6bbcf29 100644 --- a/examples/AmbientBacklight/AmbientBacklight.ino +++ b/examples/AmbientBacklight/AmbientBacklight.ino @@ -17,7 +17,7 @@ #include // Hint: The channels are swapped in iCUE, so the first channel in iCUE is here channel 2 -#define DATA_PIN_CHANNEL_1 2 // For the monitor backlight +#define DATA_PIN_CHANNEL_1 2 // For the monitor backlight #define DATA_PIN_CHANNEL_2 3 CRGB ledsChannel1[84]; @@ -36,7 +36,7 @@ void setup() { ledController.onUpdateHook(0, []() { // gamma correction with gamma value 2.0. Use napplyGamma_video for other gamma values. CLP::gammaCorrection(&ledController, 0); - //napplyGamma_video(ledsChannel1, 84, 2.2); + // napplyGamma_video(ledsChannel1, 84, 2.2); }); } diff --git a/examples/CommanderPRO/CommanderPRO.ino b/examples/CommanderPRO/CommanderPRO.ino index 58ca2de3..b0dca367 100644 --- a/examples/CommanderPRO/CommanderPRO.ino +++ b/examples/CommanderPRO/CommanderPRO.ino @@ -13,11 +13,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -#include "SimpleFanController.h" -#include "ThermistorTemperatureController.h" #include #include +#include "SimpleFanController.h" +#include "ThermistorTemperatureController.h" + #define DATA_PIN_CHANNEL_1 2 #define DATA_PIN_CHANNEL_2 3 @@ -35,7 +36,8 @@ CorsairLightingFirmware firmware = corsairCommanderPROFirmware(); ThermistorTemperatureController temperatureController; FastLEDController ledController(&temperatureController, true); -SimpleFanController fanController(&temperatureController, FAN_UPDATE_RATE, EEPROM_ADDRESS + ledController.getEEPROMSize()); +SimpleFanController fanController(&temperatureController, FAN_UPDATE_RATE, + EEPROM_ADDRESS + ledController.getEEPROMSize()); CorsairLightingProtocolController cLP(&ledController, &temperatureController, &fanController, &firmware); CorsairLightingProtocolHID cHID(&cLP); @@ -68,4 +70,4 @@ void loop() { FastLED.show(); } fanController.updateFans(); -} \ No newline at end of file +} diff --git a/examples/CommanderPRO/PWMFan.cpp b/examples/CommanderPRO/PWMFan.cpp index 93124774..e206c719 100644 --- a/examples/CommanderPRO/PWMFan.cpp +++ b/examples/CommanderPRO/PWMFan.cpp @@ -15,50 +15,46 @@ */ #include "PWMFan.h" -PWMFan::PWMFan(uint8_t pwmPin, uint16_t minRPM ,uint16_t maxRPM) : pwmPin(pwmPin), minRPM(minRPM), maxRPM(maxRPM) -{ +PWMFan::PWMFan(uint8_t pwmPin, uint16_t minRPM, uint16_t maxRPM) : pwmPin(pwmPin), minRPM(minRPM), maxRPM(maxRPM) { pinMode(pwmPin, OUTPUT); analogWrite(pwmPin, 0); switch (digitalPinToTimer(pwmPin)) { - case TIMER0B:/* 3 */ + case TIMER0B: /* 3 */ #ifdef DEBUG - Serial.println(F("Pin not supported as PWM fan pin")); - Serial.println(F("We don't want to mess up Arduino time functions")); -#endif // DEBUG - break; - case TIMER3A:/* 5 */ - TCCR3B = (TCCR3B & B11111000) | 0x01; - break; - case TIMER4D:/* 6 */ - //PLLFRQ = (PLLFRQ & B11001111) | (0x03 << PLLTM0); - TCCR4B = (TCCR4B & B11110000) | 0x01; - break; - case TIMER1A:/* 9 */ - TCCR1B = (TCCR1B & B11111000) | 0x01; - break; - case TIMER1B:/* 10 */ - TCCR1B = (TCCR1B & B11111000) | 0x01; - break; - default: + Serial.println(F("Pin not supported as PWM fan pin")); + Serial.println(F("We don't want to mess up Arduino time functions")); +#endif // DEBUG + break; + case TIMER3A: /* 5 */ + TCCR3B = (TCCR3B & B11111000) | 0x01; + break; + case TIMER4D: /* 6 */ + // PLLFRQ = (PLLFRQ & B11001111) | (0x03 << PLLTM0); + TCCR4B = (TCCR4B & B11110000) | 0x01; + break; + case TIMER1A: /* 9 */ + TCCR1B = (TCCR1B & B11111000) | 0x01; + break; + case TIMER1B: /* 10 */ + TCCR1B = (TCCR1B & B11111000) | 0x01; + break; + default: #ifdef DEBUG - Serial.println(F("Pin not supported as PWM fan pin")); -#endif // DEBUG - break; + Serial.println(F("Pin not supported as PWM fan pin")); +#endif // DEBUG + break; } } -void PWMFan::setPower(uint8_t percentage) -{ +void PWMFan::setPower(uint8_t percentage) { analogWrite(pwmPin, percentage); } -uint8_t PWMFan::calculatePowerFromSpeed(uint16_t rpm) -{ +uint8_t PWMFan::calculatePowerFromSpeed(uint16_t rpm) { rpm = constrain(rpm, minRPM, maxRPM); return ((float)(rpm - minRPM) / (float)(maxRPM - minRPM)) * 255; } -uint16_t PWMFan::calculateSpeedFromPower(uint8_t power) -{ +uint16_t PWMFan::calculateSpeedFromPower(uint8_t power) { return map(power, 0, 255, minRPM, maxRPM); } diff --git a/examples/CommanderPRO/PWMFan.h b/examples/CommanderPRO/PWMFan.h index be2a6727..2ffb643d 100644 --- a/examples/CommanderPRO/PWMFan.h +++ b/examples/CommanderPRO/PWMFan.h @@ -20,9 +20,9 @@ class PWMFan { public: /** - * PWM fan which maps speed to power using linear interpolation. - * This fan does not read the real RPM values. The Arduino timer for the given pin will be set to higher speed. - * + * PWM fan which maps speed to power using linear interpolation. This fan does not read the real RPM values. The + * Arduino timer for the given pin will be set to higher speed. + * * @param pwmPin the Arduino pwm pin for this fan. Not all PWM pins are supported. * @param minRPM the speed in RPM at 0% power * @param maxRPM the speed in RPM at 100% power @@ -31,6 +31,7 @@ class PWMFan { virtual void setPower(uint8_t percentage); virtual uint8_t calculatePowerFromSpeed(uint16_t rpm); virtual uint16_t calculateSpeedFromPower(uint8_t power); + protected: const uint8_t pwmPin; const uint16_t minRPM; diff --git a/examples/CommanderPRO/SimpleFanController.cpp b/examples/CommanderPRO/SimpleFanController.cpp index 89540f2c..b910ec5c 100644 --- a/examples/CommanderPRO/SimpleFanController.cpp +++ b/examples/CommanderPRO/SimpleFanController.cpp @@ -14,32 +14,31 @@ limitations under the License. */ #include "SimpleFanController.h" + #include -SimpleFanController::SimpleFanController(TemperatureController* temperatureController, uint16_t updateRate, uint16_t eEPROMAdress) : temperatureController(temperatureController), updateRate(updateRate), eEPROMAdress(eEPROMAdress) -{ +SimpleFanController::SimpleFanController(TemperatureController* temperatureController, uint16_t updateRate, + uint16_t eEPROMAdress) + : temperatureController(temperatureController), updateRate(updateRate), eEPROMAdress(eEPROMAdress) { load(); } -void SimpleFanController::addFan(uint8_t index, PWMFan* fan) -{ +void SimpleFanController::addFan(uint8_t index, PWMFan* fan) { if (index >= FAN_NUM) { return; } fans[index] = fan; - switch (fanData[index].mode) - { - case FAN_CONTROL_MODE_FIXED_POWER: - fanData[index].speed = fan->calculateSpeedFromPower(fanData[index].power); - break; - case FAN_CONTROL_MODE_FIXED_RPM: - fanData[index].power = fan->calculatePowerFromSpeed(fanData[index].speed); - break; + switch (fanData[index].mode) { + case FAN_CONTROL_MODE_FIXED_POWER: + fanData[index].speed = fan->calculateSpeedFromPower(fanData[index].power); + break; + case FAN_CONTROL_MODE_FIXED_RPM: + fanData[index].power = fan->calculatePowerFromSpeed(fanData[index].speed); + break; } } -bool SimpleFanController::updateFans() -{ +bool SimpleFanController::updateFans() { long currentUpdate = millis(); long lastUpdateNumber = lastUpdate / updateRate; long currentUpdateNumber = currentUpdate / updateRate; @@ -63,8 +62,7 @@ bool SimpleFanController::updateFans() const uint8_t& group = fanData[i].tempGroup; if (group == FAN_CURVE_TEMP_GROUP_EXTERNAL) { temp = externalTemp[i]; - } - else if (group < TEMPERATURE_NUM) { + } else if (group < TEMPERATURE_NUM) { temp = temperatureController->getTemperature(group); } @@ -73,16 +71,15 @@ bool SimpleFanController::updateFans() if (temp <= fanCurve.temperatures[0]) { speed = fanCurve.rpms[0]; - } - else if (temp > fanCurve.temperatures[FAN_CURVE_POINTS_NUM - 1]) { + } else if (temp > fanCurve.temperatures[FAN_CURVE_POINTS_NUM - 1]) { speed = fanCurve.rpms[FAN_CURVE_POINTS_NUM - 1]; - } - else { + } else { for (uint8_t p = 0; p < FAN_CURVE_POINTS_NUM - 1; p++) { if (temp > fanCurve.temperatures[p + 1]) { continue; } - speed = map(temp, fanCurve.temperatures[p], fanCurve.temperatures[p + 1], fanCurve.rpms[p], fanCurve.rpms[p + 1]); + speed = map(temp, fanCurve.temperatures[p], fanCurve.temperatures[p + 1], fanCurve.rpms[p], + fanCurve.rpms[p + 1]); break; } } @@ -96,71 +93,60 @@ bool SimpleFanController::updateFans() return false; } -uint16_t SimpleFanController::getFanSpeed(uint8_t fan) -{ +uint16_t SimpleFanController::getFanSpeed(uint8_t fan) { return fanData[fan].speed; } -void SimpleFanController::setFanSpeed(uint8_t fan, uint16_t speed) -{ +void SimpleFanController::setFanSpeed(uint8_t fan, uint16_t speed) { fanData[fan].speed = speed; fanData[fan].mode = FAN_CONTROL_MODE_FIXED_RPM; fanData[fan].power = fans[fan] != nullptr ? fans[fan]->calculatePowerFromSpeed(speed) : 0; triggerSave = true; } -uint8_t SimpleFanController::getFanPower(uint8_t fan) -{ +uint8_t SimpleFanController::getFanPower(uint8_t fan) { return fanData[fan].power; } -void SimpleFanController::setFanPower(uint8_t fan, uint8_t percentage) -{ +void SimpleFanController::setFanPower(uint8_t fan, uint8_t percentage) { fanData[fan].power = percentage; fanData[fan].mode = FAN_CONTROL_MODE_FIXED_POWER; fanData[fan].speed = fans[fan] != nullptr ? fans[fan]->calculateSpeedFromPower(percentage) : 0; triggerSave = true; } -void SimpleFanController::setFanCurve(uint8_t fan, uint8_t group, FanCurve& fanCurve) -{ +void SimpleFanController::setFanCurve(uint8_t fan, uint8_t group, FanCurve& fanCurve) { fanData[fan].fanCurve = fanCurve; fanData[fan].tempGroup = group; fanData[fan].mode = FAN_CONTROL_MODE_CURVE; triggerSave = true; } -void SimpleFanController::setFanExternalTemperature(uint8_t fan, uint16_t temp) -{ +void SimpleFanController::setFanExternalTemperature(uint8_t fan, uint16_t temp) { externalTemp[fan] = temp; } -void SimpleFanController::setFanForce3PinMode(bool flag) -{ +void SimpleFanController::setFanForce3PinMode(bool flag) { force3PinMode = flag; } -FanDetectionType SimpleFanController::getFanDetectionType(uint8_t fan) -{ +FanDetectionType SimpleFanController::getFanDetectionType(uint8_t fan) { return fanData[fan].detectionType; } -void SimpleFanController::setFanDetectionType(uint8_t fan, FanDetectionType type) -{ +void SimpleFanController::setFanDetectionType(uint8_t fan, FanDetectionType type) { if (fanData[fan].detectionType != type) { fanData[fan].detectionType = type; triggerSave = true; } } -bool SimpleFanController::load() -{ +bool SimpleFanController::load() { EEPROM.get(eEPROMAdress, fanData); return true; } -bool SimpleFanController::save() -{ +bool SimpleFanController::save() { #ifdef DEBUG Serial.println(F("Save fan data to EEPROM.")); #endif diff --git a/examples/CommanderPRO/SimpleFanController.h b/examples/CommanderPRO/SimpleFanController.h index 011cc09d..61eb2999 100644 --- a/examples/CommanderPRO/SimpleFanController.h +++ b/examples/CommanderPRO/SimpleFanController.h @@ -17,8 +17,8 @@ #include "Arduino.h" #include "FanController.h" -#include "TemperatureController.h" #include "PWMFan.h" +#include "TemperatureController.h" #define FAN_CONTROL_MODE_FIXED_POWER 0 #define FAN_CONTROL_MODE_FIXED_RPM 1 @@ -41,7 +41,7 @@ class SimpleFanController : public FanController { public: /** * Fan Controller must use the EEPROM else on startup the fans can't be controlled - * + * * @param temperatureController the TemperatureController used to get the temperature to control the fans * @param updateRate is the time between fan speed updates in ms * @param eEPROMAdress the address where the data is stored in EEPROM @@ -49,7 +49,7 @@ class SimpleFanController : public FanController { SimpleFanController(TemperatureController* temperatureController, uint16_t updateRate, uint16_t eEPROMAdress); /** * Add a fan to the Controller. - * + * * @param index the index of the fan * @param fan the fan object */ @@ -58,6 +58,7 @@ class SimpleFanController : public FanController { * Update the fan speeds based on the temperature and commands. */ virtual bool updateFans(); + protected: virtual uint16_t getFanSpeed(uint8_t fan) override; virtual void setFanSpeed(uint8_t fan, uint16_t speed) override; @@ -72,7 +73,7 @@ class SimpleFanController : public FanController { bool save(); TemperatureController* const temperatureController; - PWMFan* fans[FAN_NUM] = { nullptr }; + PWMFan* fans[FAN_NUM] = {nullptr}; bool force3PinMode = false; FanData fanData[FAN_NUM]; uint16_t externalTemp[FAN_NUM]; diff --git a/examples/CommanderPRO/ThermistorTemperatureController.cpp b/examples/CommanderPRO/ThermistorTemperatureController.cpp index 4fa78c82..060549d2 100644 --- a/examples/CommanderPRO/ThermistorTemperatureController.cpp +++ b/examples/CommanderPRO/ThermistorTemperatureController.cpp @@ -21,16 +21,14 @@ #define RESISTENCE_DIVIDER 10000 #define MAX_TEMP 150 -void ThermistorTemperatureController::addSensor(uint8_t index, uint8_t pin) -{ +void ThermistorTemperatureController::addSensor(uint8_t index, uint8_t pin) { if (index < sizeof(sensorPins)) { pinMode(pin, INPUT); sensorPins[index] = pin; } } -uint16_t ThermistorTemperatureController::getTemperatureValue(uint8_t temperatureSensor) -{ +uint16_t ThermistorTemperatureController::getTemperatureValue(uint8_t temperatureSensor) { if (!isTemperatureSensorConnected(temperatureSensor)) { return 0; } @@ -38,32 +36,28 @@ uint16_t ThermistorTemperatureController::getTemperatureValue(uint8_t temperatur double resistence = (RESISTENCE_DIVIDER * (double)(1023 - read)) / read; - double temp = resistence / RESISTENCE_REFERENCE; // (R/Ro) - temp = log(temp); // ln(R/Ro) - temp /= B_COEFFICIENT; // * (1/B) - temp += 1.0 / TEMPERATURE_REFERENCE; // + (1/To) - temp = 1.0 / temp; // invert - temp -= 273.15; // convert to °C + double temp = resistence / RESISTENCE_REFERENCE; // (R/Ro) + temp = log(temp); // ln(R/Ro) + temp /= B_COEFFICIENT; // * (1/B) + temp += 1.0 / TEMPERATURE_REFERENCE; // + (1/To) + temp = 1.0 / temp; // invert + temp -= 273.15; // convert to °C return constrain(temp, 0, MAX_TEMP) * 100; } -bool ThermistorTemperatureController::isTemperatureSensorConnected(uint8_t temperatureSensor) -{ +bool ThermistorTemperatureController::isTemperatureSensorConnected(uint8_t temperatureSensor) { return sensorPins[temperatureSensor] != 0; } -uint16_t ThermistorTemperatureController::getVoltageRail12V() -{ +uint16_t ThermistorTemperatureController::getVoltageRail12V() { return 0; } -uint16_t ThermistorTemperatureController::getVoltageRail5V() -{ +uint16_t ThermistorTemperatureController::getVoltageRail5V() { return 0; } -uint16_t ThermistorTemperatureController::getVoltageRail3V3() -{ +uint16_t ThermistorTemperatureController::getVoltageRail3V3() { return 0; } diff --git a/examples/CommanderPRO/ThermistorTemperatureController.h b/examples/CommanderPRO/ThermistorTemperatureController.h index 0e0f0b29..4de9651d 100644 --- a/examples/CommanderPRO/ThermistorTemperatureController.h +++ b/examples/CommanderPRO/ThermistorTemperatureController.h @@ -17,7 +17,8 @@ #include "TemperatureController.h" /** - * This TemperatureController uses Thermistors and Resistors to messure the temperature. It does not implement the voltage rail measurements. + * This TemperatureController uses Thermistors and Resistors to messure the temperature. It does not implement the + * voltage rail measurements. * * Thermistor Schematic: *
@@ -29,12 +30,14 @@
 class ThermistorTemperatureController : public TemperatureController {
 public:
 	/**
-	 * Add a Sensor to the TemperatureController using an Arduino analog pin connected as shown in {@link ThermistorTemperatureController}.
+	 * Add a Sensor to the TemperatureController using an Arduino analog pin connected as shown in {@link
+	 * ThermistorTemperatureController}.
 	 *
 	 * @param index the index of the sensorPins
 	 * @param pin the Arduino analog pin
 	 */
 	void addSensor(uint8_t index, uint8_t pin);
+
 protected:
 	virtual uint16_t getTemperatureValue(uint8_t temperatureSensor) override;
 	virtual bool isTemperatureSensorConnected(uint8_t temperatureSensor) override;
@@ -42,5 +45,5 @@ class ThermistorTemperatureController : public TemperatureController {
 	virtual uint16_t getVoltageRail5V() override;
 	virtual uint16_t getVoltageRail3V3() override;
 
-	uint8_t sensorPins[TEMPERATURE_NUM] = { 0 };
+	uint8_t sensorPins[TEMPERATURE_NUM] = {0};
 };
diff --git a/examples/DebugSketch/DebugSketch.ino b/examples/DebugSketch/DebugSketch.ino
index c92f89c4..664f26e7 100644
--- a/examples/DebugSketch/DebugSketch.ino
+++ b/examples/DebugSketch/DebugSketch.ino
@@ -67,18 +67,15 @@ void processCommand(String& cmd) {
 #ifdef VERBOSE
 	else if (cmd == F("toggle command")) {
 		printCommand = !printCommand;
-	}
-	else if (cmd == F("toggle response")) {
+	} else if (cmd == F("toggle response")) {
 		printResponse = !printResponse;
 	}
-#endif // VERBOSE
+#endif  // VERBOSE
 	else if (cmd == F("toggle loop")) {
 		printLoop = !printLoop;
-	}
-	else if (cmd == F("toggle update")) {
+	} else if (cmd == F("toggle update")) {
 		printUpdate = !printUpdate;
-	}
-	else {
+	} else {
 		Serial.println(F("Unknown command"));
 	}
 }
diff --git a/examples/DeviceIDTool/DeviceIDTool.ino b/examples/DeviceIDTool/DeviceIDTool.ino
index 48b46a8b..5d8aac87 100644
--- a/examples/DeviceIDTool/DeviceIDTool.ino
+++ b/examples/DeviceIDTool/DeviceIDTool.ino
@@ -16,8 +16,8 @@
 //
 // UPLOAD THIS TO THE ARDUINO AND OPEN SERIAL MONITOR WITH BOUDRATE 115200
 //
-#include 
 #include 
+#include 
 
 #define EEPROM_ADDRESS_DEVICE_ID 0
 
@@ -28,14 +28,15 @@ void setup() {
 	EEPROM.get(EEPROM_ADDRESS_DEVICE_ID, deviceID);
 
 	while (!Serial) {
-		; // wait for serial port to connect. Needed for native USB
+		;  // wait for serial port to connect. Needed for native USB
 	}
 	Serial.print(F("Current DeviceID: "));
 	CLP::printDeviceID(deviceID);
 	Serial.println();
-	Serial.println(F("Set a new DeviceID by typing it in the Serial Monitor. The new DeviceID must be in same format as above. 4 Blocks with 2 digits separated by white space."));
+	Serial.println(
+		F("Set a new DeviceID by typing it in the Serial Monitor. The new DeviceID must be in same format as above. 4 "
+		  "Blocks with 2 digits separated by white space."));
 	Serial.println();
-
 }
 
 void loop() {
@@ -45,8 +46,7 @@ void loop() {
 			Serial.println(F("Input is too short!"));
 			Serial.println(F("Do not forget the leading zeroes!"));
 			Serial.println();
-		}
-		else {
+		} else {
 			uint8_t newDeviceID[4];
 
 			newDeviceID[0] = strtol(&inputString[0], nullptr, 16);
@@ -57,10 +57,13 @@ void loop() {
 			CLP::printDeviceID(newDeviceID);
 			Serial.println();
 			if (CLP::isNullID(newDeviceID)) {
-				Serial.println(F("This is a special DeviceID, it will generate a new random DeviceID next time iCUE controls the device!"));
+				Serial.println(
+					F("This is a special DeviceID, it will generate a new random DeviceID next time iCUE controls the "
+					  "device!"));
 			}
 			if (CLP::isResetID(newDeviceID)) {
-				Serial.println(F("This is a special DeviceID, it will reset the device and then generate a new DeviceID!"));
+				Serial.println(
+					F("This is a special DeviceID, it will reset the device and then generate a new DeviceID!"));
 			}
 			Serial.println();
 			EEPROM.put(EEPROM_ADDRESS_DEVICE_ID, newDeviceID);
diff --git a/examples/HoodLoader2CLPBridge/CLPUSBSerialBridge.cpp b/examples/HoodLoader2CLPBridge/CLPUSBSerialBridge.cpp
index c37385ca..add601e9 100644
--- a/examples/HoodLoader2CLPBridge/CLPUSBSerialBridge.cpp
+++ b/examples/HoodLoader2CLPBridge/CLPUSBSerialBridge.cpp
@@ -15,27 +15,26 @@
 */
 
 #include "CLPUSBSerialBridge.h"
-#include 
+
 #include 
+#include 
 
 void resetIOMCU() {
 	digitalWrite(RESET_PIN, LOW);
 	delay(10);
 	digitalWrite(RESET_PIN, HIGH);
 #ifdef DEBUG
-		Serial.println(F("R"));
-#endif // DEBUG
+	Serial.println(F("R"));
+#endif  // DEBUG
 }
 
-CLPUSBSerialBridge::CLPUSBSerialBridge(const char* serialNumber)
-{
-	RawHID.setSerialNumber(serialNumber);
+CLPUSBSerialBridge::CLPUSBSerialBridge(const char* serialNumber) {
+	CLP::RawHID.setSerialNumber(serialNumber);
 }
 
-void CLPUSBSerialBridge::begin()
-{
+void CLPUSBSerialBridge::begin() {
 	Serial1.begin(SERIAL_BAUD);
-	RawHID.begin(rawHIDAndSerialBuffer, sizeof(rawHIDAndSerialBuffer));
+	CLP::RawHID.begin(rawHIDAndSerialBuffer, sizeof(rawHIDAndSerialBuffer));
 }
 
 bool waitForSynchronization() {
@@ -58,23 +57,22 @@ void CLPUSBSerialBridge::sendResponse() {
 #ifdef DEBUG
 	Serial.print(F("R"));
 	Serial.println(rawHIDAndSerialBuffer[0], HEX);
-#endif // DEBUG
-	RawHID.write(rawHIDAndSerialBuffer, sizeof(rawHIDAndSerialBuffer));
+#endif  // DEBUG
+	CLP::RawHID.write(rawHIDAndSerialBuffer, sizeof(rawHIDAndSerialBuffer));
 	// free the shared buffer to receive new data
-	RawHID.enable();
+	CLP::RawHID.enable();
 }
 
-void CLPUSBSerialBridge::handleHID()
-{
-	if (RawHID.available()) {
+void CLPUSBSerialBridge::handleHID() {
+	if (CLP::RawHID.available()) {
 #ifdef DEBUG
 		Serial.print(F("C"));
 		Serial.println(rawHIDAndSerialBuffer[0], HEX);
-#endif // DEBUG
+#endif  // DEBUG
 		if (!waitForSynchronization()) {
 #ifdef DEBUG
 			Serial.println(F("S"));
-#endif // DEBUG
+#endif  // DEBUG
 			sendError();
 			return;
 		}
@@ -87,7 +85,7 @@ void CLPUSBSerialBridge::handleHID()
 			Serial.print(F("T"));
 			Serial.println(read);
 			Serial.println(rawHIDAndSerialBuffer[0], HEX);
-#endif // DEBUG
+#endif  // DEBUG
 			sendError();
 			return;
 		}
diff --git a/examples/HoodLoader2CLPBridge/CLPUSBSerialBridge.h b/examples/HoodLoader2CLPBridge/CLPUSBSerialBridge.h
index 85fd7b04..51a5c295 100644
--- a/examples/HoodLoader2CLPBridge/CLPUSBSerialBridge.h
+++ b/examples/HoodLoader2CLPBridge/CLPUSBSerialBridge.h
@@ -15,11 +15,12 @@
 */
 #pragma once
 
-#include "Arduino.h"
 #include 
 
+#include "Arduino.h"
+
 #if (COMMAND_SIZE == RESPONSE_SIZE)
-	#define RAWHID_AND_SERIAL_BUFFER_SIZE COMMAND_SIZE
+#define RAWHID_AND_SERIAL_BUFFER_SIZE COMMAND_SIZE
 #endif
 
 #define SERIAL_SYNCHRONIZATION_TIMEOUT 20
@@ -33,7 +34,7 @@ class CLPUSBSerialBridge {
 	/**
 	 * Create a new CLPUSBSerialBridge with the default Serial Number.
 	 */
-	CLPUSBSerialBridge() {};
+	CLPUSBSerialBridge(){};
 	/**
 	 * Create a new CLPUSBSerialBridge and set a Serial Number.
 	 *
@@ -41,15 +42,15 @@ class CLPUSBSerialBridge {
 	 */
 	CLPUSBSerialBridge(const char* serialNumber);
 	/**
-	 * Setup the bridge connections. 
-	 * Must be called in the Arduino setup function.
+	 * Setup the bridge connections. Must be called in the Arduino setup function.
 	 */
 	virtual void begin();
 	/**
-	 * Reads data from USB and sents it via Serial to the main MCU. Wait for the response and set it back to the USB host.
-	 * MUST be called in the Arduino loop function.
+	 * Reads data from USB and sents it via Serial to the main MCU. Wait for the response and set it back to the USB
+	 * host. MUST be called in the Arduino loop function.
 	 */
 	virtual void handleHID();
+
 private:
 	byte rawHIDAndSerialBuffer[RAWHID_AND_SERIAL_BUFFER_SIZE];
 
diff --git a/examples/HoodLoader2CLPBridge/HoodLoader2CLPBridge.ino b/examples/HoodLoader2CLPBridge/HoodLoader2CLPBridge.ino
index 4f211780..3d29ce25 100644
--- a/examples/HoodLoader2CLPBridge/HoodLoader2CLPBridge.ino
+++ b/examples/HoodLoader2CLPBridge/HoodLoader2CLPBridge.ino
@@ -20,7 +20,7 @@ CLPUSBSerialBridge usbToSerialBridge;
 void setup() {
 #ifdef DEBUG
 	Serial.begin(1000000);
-#endif // DEBUG
+#endif  // DEBUG
 	usbToSerialBridge.begin();
 }
 
diff --git a/examples/HoodLoader2UnoMegaController/HoodLoader2UnoMegaController.ino b/examples/HoodLoader2UnoMegaController/HoodLoader2UnoMegaController.ino
index 302a3adc..dd282247 100644
--- a/examples/HoodLoader2UnoMegaController/HoodLoader2UnoMegaController.ino
+++ b/examples/HoodLoader2UnoMegaController/HoodLoader2UnoMegaController.ino
@@ -16,7 +16,8 @@
 #include 
 #include 
 
-// Hint: The Arduino Uno does not have as much memory as the Arduino Mega, it may be that problems occur when a higher value is set here.
+// Hint: The Arduino Uno does not have as much memory as the Arduino Mega, it may be that problems occur when a higher
+// value is set here.
 #define CHANNEL_LED_COUNT 60
 
 #define DATA_PIN_CHANNEL_1 2
diff --git a/extra/doxygen.conf b/extra/doxygen.conf
index 9b15e70d..2676e5d1 100644
--- a/extra/doxygen.conf
+++ b/extra/doxygen.conf
@@ -38,7 +38,7 @@ PROJECT_NAME           = "Corsair Lighting Protocol"
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 0.10.0
+PROJECT_NUMBER         = 0.11.0
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
diff --git a/library.properties b/library.properties
index 19f565e6..f641cf41 100644
--- a/library.properties
+++ b/library.properties
@@ -1,9 +1,9 @@
 name=Corsair Lighting Protocol
-version=0.10.0
+version=0.11.0
 author=Leon Kiefer
 maintainer=Leon Kiefer
-sentence=Allows iCUE to control RGB LEDs.
-paragraph=The library mimics a Lighting Node PRO and can be controlled as such in iCUE.
+sentence=Control LED strips via USB from a PC.
+paragraph=The library mimics Corsair LED Controller devices and can be controlled via USB in iCUE.
 category=Device Control
 url=https://github.com/Legion2/CorsairLightingProtocol
 architectures=avr
diff --git a/src/CLPAdditionalFeatures.cpp b/src/CLPAdditionalFeatures.cpp
index 09b49cc2..f180c218 100644
--- a/src/CLPAdditionalFeatures.cpp
+++ b/src/CLPAdditionalFeatures.cpp
@@ -14,6 +14,7 @@
    limitations under the License.
 */
 #include "CLPAdditionalFeatures.h"
+
 #include "CLPUtils.h"
 
 bool CLP::shouldReset(const CorsairLightingFirmware* firmware) {
@@ -23,6 +24,6 @@ bool CLP::shouldReset(const CorsairLightingFirmware* firmware) {
 }
 
 void CLP::reset(CorsairLightingFirmware* firmware) {
-	byte deviceId[4] = { 0x00 };
+	byte deviceId[4] = {0x00};
 	firmware->setDeviceID(deviceId);
 }
diff --git a/src/CLPAdditionalFeatures.h b/src/CLPAdditionalFeatures.h
index fd45d3ac..0d16bd1f 100644
--- a/src/CLPAdditionalFeatures.h
+++ b/src/CLPAdditionalFeatures.h
@@ -18,20 +18,19 @@
 #include "Arduino.h"
 #include "CorsairLightingFirmware.h"
 
-namespace CLP
-{
-	/**
-	 * Check if the device should be reseted. The check is based on the DeviceID from the firmware.
-	 *
-	 * @param firmware the firmware used by this device
-	 * @return if the device should be reset
-	 */
-	bool shouldReset(const CorsairLightingFirmware* firmware);
+namespace CLP {
+/**
+ * Check if the device should be reseted. The check is based on the DeviceID from the firmware.
+ *
+ * @param firmware the firmware used by this device
+ * @return if the device should be reset
+ */
+bool shouldReset(const CorsairLightingFirmware* firmware);
 
-	/**
-	 * Reset the DeviceID of the firmware.
-	 *
-	 * @param firmware reset this firmware
-	 */
-	void reset(CorsairLightingFirmware* firmware);
-}
+/**
+ * Reset the DeviceID of the firmware.
+ *
+ * @param firmware reset this firmware
+ */
+void reset(CorsairLightingFirmware* firmware);
+}  // namespace CLP
diff --git a/src/CLPUtils.cpp b/src/CLPUtils.cpp
index af6e1db6..5140ddea 100644
--- a/src/CLPUtils.cpp
+++ b/src/CLPUtils.cpp
@@ -22,8 +22,7 @@ uint16_t CLP::fromBigEndian(const byte& byte1, const byte& byte2) {
 	return t;
 }
 
-void CLP::disableBuildInLEDs()
-{
+void CLP::disableBuildInLEDs() {
 #ifndef DEBUG
 #ifdef LED_BUILTIN_RX
 	pinMode(LED_BUILTIN_RX, INPUT);
@@ -34,9 +33,7 @@ void CLP::disableBuildInLEDs()
 #endif
 }
 
-bool CLP::isNullID(const uint8_t* deviceId) {
-	return !(deviceId[0] | deviceId[1] | deviceId[2] | deviceId[3]);
-}
+bool CLP::isNullID(const uint8_t* deviceId) { return !(deviceId[0] | deviceId[1] | deviceId[2] | deviceId[3]); }
 
 bool CLP::isResetID(const uint8_t* deviceId) {
 	return deviceId[0] == 0xFF && deviceId[1] == 0xFF && deviceId[2] == 0xFF && deviceId[3] == 0xFF;
diff --git a/src/CLPUtils.h b/src/CLPUtils.h
index 010117a3..43b2788c 100644
--- a/src/CLPUtils.h
+++ b/src/CLPUtils.h
@@ -19,53 +19,46 @@
 
 #define toBigEndian(a) highByte(a), lowByte(a)
 
-namespace CLP
-{
-	uint16_t fromBigEndian(const byte& byte1, const byte& byte2);
+namespace CLP {
+uint16_t fromBigEndian(const byte& byte1, const byte& byte2);
 
-	/**
-	 * Convert value from range 0-100 to 0-255
-	 *
-	 * @param value the value which should be converted
-	 */
-	inline uint8_t convert100To255(uint8_t value)
-	{
-		return value * 2.5546875f;
-	}
+/**
+ * Convert value from range 0-100 to 0-255
+ *
+ * @param value the value which should be converted
+ */
+inline uint8_t convert100To255(uint8_t value) { return value * 2.5546875f; }
 
-	/**
-	 * Convert value from range 0-255 to 0-100.
-	 *
-	 * @param value the value which should be converted
-	 */
-	inline uint8_t convert255To100(uint8_t value)
-	{
-		return value / 2.5546875f;
-	}
+/**
+ * Convert value from range 0-255 to 0-100.
+ *
+ * @param value the value which should be converted
+ */
+inline uint8_t convert255To100(uint8_t value) { return value / 2.5546875f; }
 
-	/**
-	 * Check if a device id is the special null id (00 00 00 00).
-	 *
-	 * @param deviceId the device id to check
-	 */
-	bool isNullID(const uint8_t* deviceId);
+/**
+ * Check if a device id is the special null id (00 00 00 00).
+ *
+ * @param deviceId the device id to check
+ */
+bool isNullID(const uint8_t* deviceId);
 
-	/**
-	 * Check if a device id is the special reset id (FF FF FF FF).
-	 *
-	 * @param deviceId the device id to check
-	 */
-	bool isResetID(const uint8_t* deviceId);
+/**
+ * Check if a device id is the special reset id (FF FF FF FF).
+ *
+ * @param deviceId the device id to check
+ */
+bool isResetID(const uint8_t* deviceId);
 
-	/**
-	 * This will disable the RX and TX built in LEDs on Arduino Leonardo, Micro and Pro Micro.
-	 */
-	void disableBuildInLEDs();
+/**
+ * This will disable the RX and TX built in LEDs on Arduino Leonardo, Micro and Pro Micro.
+ */
+void disableBuildInLEDs();
 
-	/**
-	 * Print the given DeviceID to Serial
-	 *
-	 * @param deviceId the device id to print
-	 */
-	void printDeviceID(const uint8_t* deviceId);
-}
+/**
+ * Print the given DeviceID to Serial
+ *
+ * @param deviceId the device id to print
+ */
+void printDeviceID(const uint8_t* deviceId);
+}  // namespace CLP
diff --git a/src/CorsairLightingFirmware.cpp b/src/CorsairLightingFirmware.cpp
index af88a3c0..f7e5f060 100644
--- a/src/CorsairLightingFirmware.cpp
+++ b/src/CorsairLightingFirmware.cpp
@@ -13,95 +13,74 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 */
-#include 
 #include "CorsairLightingFirmware.h"
 
-const uint8_t bootloader_version[] PROGMEM = { 0x00, 0x02 };
+#include 
+
+const uint8_t bootloader_version[] PROGMEM = {0x00, 0x02};
 
-const uint8_t corsairLightingNodePROFirmwareVersion[FIRMWARE_VERSION_SIZE] PROGMEM = { 0x00, 0x0A, 0x04 };
+const uint8_t corsairLightingNodePROFirmwareVersion[FIRMWARE_VERSION_SIZE] PROGMEM = {0x00, 0x0A, 0x04};
 
-const uint8_t corsairCommanderPROFirmwareVersion[FIRMWARE_VERSION_SIZE] PROGMEM = { 0x00, 0x09, 0xD4 };
+const uint8_t corsairCommanderPROFirmwareVersion[FIRMWARE_VERSION_SIZE] PROGMEM = {0x00, 0x09, 0xD4};
 
-CorsairLightingFirmware::CorsairLightingFirmware(const uint8_t* firmwareVersion) : firmwareVersion(firmwareVersion)
-{
+CorsairLightingFirmware::CorsairLightingFirmware(const uint8_t* firmwareVersion) : firmwareVersion(firmwareVersion) {
 	EEPROM.get(EEPROM_ADDRESS_DEVICE_ID, deviceId);
 }
 
-void CorsairLightingFirmware::handleFirmwareCommand(const Command& command, const CorsairLightingProtocolResponse* response)
-{
-	switch (command.command)
-	{
-	case READ_STATUS:
-	{
-		uint8_t statusData[] = { status };
-		response->send(statusData, sizeof(statusData));
-		break;
-	}
-	case READ_FIRMWARE_VERSION:
-	{
-		response->send_P(firmwareVersion, FIRMWARE_VERSION_SIZE);
-		break;
-	}
-	case READ_DEVICE_ID:
-	{
-		response->send(deviceId, sizeof(deviceId));
-		break;
-	}
-	case WRITE_DEVICE_ID:
-	{
-		setDeviceID(command.data);
-		response->send(deviceId, sizeof(deviceId));
-		break;
-	}
-	case READ_BOOTLOADER_VERSION:
-	{
-		response->send_P(bootloader_version, sizeof(bootloader_version));
-		break;
-	}
-	default:
-	{
-		response->sendError();
-	}
+void CorsairLightingFirmware::handleFirmwareCommand(const Command& command,
+													const CorsairLightingProtocolResponse* response) {
+	switch (command.command) {
+		case READ_STATUS: {
+			uint8_t statusData[] = {status};
+			response->send(statusData, sizeof(statusData));
+			break;
+		}
+		case READ_FIRMWARE_VERSION: {
+			response->send_P(firmwareVersion, FIRMWARE_VERSION_SIZE);
+			break;
+		}
+		case READ_DEVICE_ID: {
+			response->send(deviceId, sizeof(deviceId));
+			break;
+		}
+		case WRITE_DEVICE_ID: {
+			setDeviceID(command.data);
+			response->send(deviceId, sizeof(deviceId));
+			break;
+		}
+		case READ_BOOTLOADER_VERSION: {
+			response->send_P(bootloader_version, sizeof(bootloader_version));
+			break;
+		}
+		default: {
+			response->sendError();
+		}
 	}
 }
 
-void CorsairLightingFirmware::getDeviceID(uint8_t* deviceID) const
-{
-	memcpy(deviceID, deviceId, sizeof(deviceId));
-}
+void CorsairLightingFirmware::getDeviceID(uint8_t* deviceID) const { memcpy(deviceID, deviceId, sizeof(deviceId)); }
 
-void CorsairLightingFirmware::setDeviceID(const uint8_t* deviceID)
-{
+void CorsairLightingFirmware::setDeviceID(const uint8_t* deviceID) {
 	memcpy(deviceId, deviceID, sizeof(deviceId));
 	EEPROM.put(EEPROM_ADDRESS_DEVICE_ID, deviceId);
 }
 
-uint8_t CorsairLightingFirmware::getStatus()
-{
-	return status;
-}
+uint8_t CorsairLightingFirmware::getStatus() { return status; }
 
-void CorsairLightingFirmware::setStatus(uint8_t a_status)
-{
-	status = a_status;
-}
+void CorsairLightingFirmware::setStatus(uint8_t a_status) { status = a_status; }
 
-CorsairLightingFirmware corsairLightingNodePROFirmware()
-{
+CorsairLightingFirmware corsairLightingNodePROFirmware() {
 	return CorsairLightingFirmware(corsairLightingNodePROFirmwareVersion);
 }
 
-CorsairLightingFirmware corsairLightingNodeCOREFirmware()
-{
+CorsairLightingFirmware corsairLightingNodeCOREFirmware() {
 	return CorsairLightingFirmware(corsairLightingNodePROFirmwareVersion);
 }
 
-CorsairLightingFirmware corsairLS100Firmware()
-{
+CorsairLightingFirmware corsairLS100Firmware() {
 	return CorsairLightingFirmware(corsairLightingNodePROFirmwareVersion);
 }
 
-CorsairLightingFirmware corsairCommanderPROFirmware()
-{
+CorsairLightingFirmware corsairCommanderPROFirmware() {
 	return CorsairLightingFirmware(corsairCommanderPROFirmwareVersion);
 }
diff --git a/src/CorsairLightingFirmware.h b/src/CorsairLightingFirmware.h
index d023cdd0..84de7e4d 100644
--- a/src/CorsairLightingFirmware.h
+++ b/src/CorsairLightingFirmware.h
@@ -16,9 +16,8 @@
 #pragma once
 
 #include "Arduino.h"
-
-#include "CorsairLightingProtocolResponse.h"
 #include "CorsairLightingProtocolConstants.h"
+#include "CorsairLightingProtocolResponse.h"
 
 #ifndef EEPROM_ADDRESS_DEVICE_ID
 #define EEPROM_ADDRESS_DEVICE_ID 0
@@ -37,9 +36,11 @@ class CorsairLightingFirmware {
 	void setDeviceID(const uint8_t* deviceID);
 	uint8_t getStatus();
 	void setStatus(uint8_t status);
+
 protected:
 	const uint8_t* firmwareVersion;
 	uint8_t deviceId[4];
+
 private:
 	uint8_t status = PROTOCOL_STATUS_OK;
 };
diff --git a/src/CorsairLightingNodePRO.cpp b/src/CorsairLightingNodePRO.cpp
index edc45c3d..c55aad1d 100644
--- a/src/CorsairLightingNodePRO.cpp
+++ b/src/CorsairLightingNodePRO.cpp
@@ -17,8 +17,8 @@
 
 #if defined(SUPPORT_RAW_HID)
 
-CorsairLightingNodePRO::CorsairLightingNodePRO() : ledController(true), cLP(&ledController, &firmware), connectionAdapter(&cLP)
-{
+CorsairLightingNodePRO::CorsairLightingNodePRO()
+	: ledController(true), cLP(&ledController, &firmware), connectionAdapter(&cLP) {
 	ledController.addLEDs(0, ledsChannel1, CHANNEL_LED_COUNT_DEFAULT);
 	ledController.addLEDs(1, ledsChannel2, CHANNEL_LED_COUNT_DEFAULT);
 }
@@ -31,9 +31,6 @@ void CorsairLightingNodePRO::update() {
 	}
 }
 
-FastLEDController* CorsairLightingNodePRO::getFastLEDController()
-{
-	return &ledController;
-}
+FastLEDController* CorsairLightingNodePRO::getFastLEDController() { return &ledController; }
 
 #endif
diff --git a/src/CorsairLightingNodePRO.h b/src/CorsairLightingNodePRO.h
index 47603dc4..3f04f065 100644
--- a/src/CorsairLightingNodePRO.h
+++ b/src/CorsairLightingNodePRO.h
@@ -15,12 +15,13 @@
 */
 #pragma once
 
+#include 
+
 #include "Arduino.h"
-#include "CorsairLightingFirmware.h" 
-#include "FastLEDController.h"
+#include "CorsairLightingFirmware.h"
 #include "CorsairLightingProtocolController.h"
 #include "CorsairLightingProtocolHID.h"
-#include 
+#include "FastLEDController.h"
 
 #if defined(SUPPORT_RAW_HID)
 
@@ -31,6 +32,7 @@ class CorsairLightingNodePRO {
 	CorsairLightingNodePRO();
 	void update();
 	FastLEDController* getFastLEDController();
+
 protected:
 	CRGB ledsChannel1[CHANNEL_LED_COUNT_DEFAULT];
 	CRGB ledsChannel2[CHANNEL_LED_COUNT_DEFAULT];
diff --git a/src/CorsairLightingProtocol.h b/src/CorsairLightingProtocol.h
index e195ce93..319c203b 100644
--- a/src/CorsairLightingProtocol.h
+++ b/src/CorsairLightingProtocol.h
@@ -19,6 +19,8 @@
  * @file
  * The central include file for CorsairLightingProtocol.
  */
+#include "CLPAdditionalFeatures.h"
+#include "CLPUtils.h"
 #include "CorsairLightingFirmware.h"
 #include "CorsairLightingNodePRO.h"
 #include "CorsairLightingProtocolConstants.h"
@@ -26,13 +28,11 @@
 #include "CorsairLightingProtocolHID.h"
 #include "CorsairLightingProtocolResponse.h"
 #include "CorsairLightingProtocolSerial.h"
-#include "IFanController.h"
 #include "FanController.h"
-#include "ILEDController.h"
-#include "LEDController.h"
 #include "FastLEDController.h"
+#include "FastLEDControllerUtils.h"
+#include "IFanController.h"
+#include "ILEDController.h"
 #include "ITemperatureController.h"
+#include "LEDController.h"
 #include "TemperatureController.h"
-#include "FastLEDControllerUtils.h"
-#include "CLPAdditionalFeatures.h"
-#include "CLPUtils.h"
diff --git a/src/CorsairLightingProtocolController.cpp b/src/CorsairLightingProtocolController.cpp
index 848712c7..3f4de55e 100644
--- a/src/CorsairLightingProtocolController.cpp
+++ b/src/CorsairLightingProtocolController.cpp
@@ -14,37 +14,44 @@
    limitations under the License.
 */
 #include "CorsairLightingProtocolController.h"
+
 #include "LEDController.h"
 
-CorsairLightingProtocolController::CorsairLightingProtocolController(ILEDController* aLEDController, CorsairLightingFirmware* corsairLightingFirmware) : corsairLightingFirmware(corsairLightingFirmware), ledController(aLEDController), temperatureController(nullptr), fanController(nullptr) {}
+CorsairLightingProtocolController::CorsairLightingProtocolController(ILEDController* aLEDController,
+																	 CorsairLightingFirmware* corsairLightingFirmware)
+	: corsairLightingFirmware(corsairLightingFirmware),
+	  ledController(aLEDController),
+	  temperatureController(nullptr),
+	  fanController(nullptr) {}
 
-CorsairLightingProtocolController::CorsairLightingProtocolController(ILEDController* aLEDController, ITemperatureController* temperatureController, IFanController* fanController, CorsairLightingFirmware* corsairLightingFirmware) : corsairLightingFirmware(corsairLightingFirmware), ledController(aLEDController), temperatureController(temperatureController), fanController(fanController) {}
+CorsairLightingProtocolController::CorsairLightingProtocolController(ILEDController* aLEDController,
+																	 ITemperatureController* temperatureController,
+																	 IFanController* fanController,
+																	 CorsairLightingFirmware* corsairLightingFirmware)
+	: corsairLightingFirmware(corsairLightingFirmware),
+	  ledController(aLEDController),
+	  temperatureController(temperatureController),
+	  fanController(fanController) {}
 
-void CorsairLightingProtocolController::handleCommand(const Command& command, CorsairLightingProtocolResponse* response)
-{
+void CorsairLightingProtocolController::handleCommand(const Command& command,
+													  CorsairLightingProtocolResponse* response) {
 	if (command.command < 0x10) {
 		corsairLightingFirmware->handleFirmwareCommand(command, response);
-	}
-	else if (command.command >= 0x10 && command.command < 0x20) {
+	} else if (command.command >= 0x10 && command.command < 0x20) {
 		if (temperatureController != nullptr) {
 			temperatureController->handleTemperatureControl(command, response);
-		}
-		else {
+		} else {
 			response->sendError();
 		}
-	}
-	else if (command.command >= 0x20 && command.command < 0x30) {
+	} else if (command.command >= 0x20 && command.command < 0x30) {
 		if (fanController != nullptr) {
 			fanController->handleFanControl(command, response);
-		}
-		else {
+		} else {
 			response->sendError();
 		}
-	}
-	else if (command.command >= 0x30 && command.command < 0x40) {
+	} else if (command.command >= 0x30 && command.command < 0x40) {
 		ledController->handleLEDControl(command, response);
-	}
-	else {
+	} else {
 		response->sendError();
 	}
 }
diff --git a/src/CorsairLightingProtocolController.h b/src/CorsairLightingProtocolController.h
index dbba9cc2..a05c9412 100644
--- a/src/CorsairLightingProtocolController.h
+++ b/src/CorsairLightingProtocolController.h
@@ -16,7 +16,6 @@
 #pragma once
 
 #include "Arduino.h"
-
 #include "CorsairLightingFirmware.h"
 #include "CorsairLightingProtocolConstants.h"
 #include "CorsairLightingProtocolResponse.h"
@@ -25,11 +24,11 @@
 #include "ITemperatureController.h"
 
 /**
- * The central Controller which integrates all components. The main components of the CorsairLightingProtocolController are the CorsairLightingFirmware
- * and the LEDController. There can also be an optional TemperatureController and FanController which are required if the device should be an Commander PRO.
+ * The central Controller which integrates all components. The main components of the CorsairLightingProtocolController
+ * are the CorsairLightingFirmware and the LEDController. There can also be an optional TemperatureController and
+ * FanController which are required if the device should be an Commander PRO.
  */
-class CorsairLightingProtocolController
-{
+class CorsairLightingProtocolController {
 public:
 	/**
 	 * The constructor used to create a Lighting only device.
@@ -39,22 +38,26 @@ class CorsairLightingProtocolController
 	 */
 	CorsairLightingProtocolController(ILEDController* l, CorsairLightingFirmware* c);
 	/**
-	 * The constructor used to create a device with lighting, temperature and fan controller functionality (Commander PRO).
+	 * The constructor used to create a device with lighting, temperature and fan controller functionality (Commander
+	 * PRO).
 	 *
 	 * @param l The LEDController which should be used to control the LEDs of the created Commander PRO
 	 * @param t The TemperatureController which used to messure the temperature of the created Commander PRO
 	 * @param f The FanController used to control the fans of the created Commander PRO
 	 * @param c The CorsairLightingFirmware used to handle Firmware related commands
 	 */
-	CorsairLightingProtocolController(ILEDController* l, ITemperatureController* t, IFanController* f, CorsairLightingFirmware* c);
+	CorsairLightingProtocolController(ILEDController* l, ITemperatureController* t, IFanController* f,
+									  CorsairLightingFirmware* c);
 	/**
-	 * The only public function of the CorsairLightingProtocolController. It must be called to process a command which was received from iCUE.
-	 * This function is normally called by CorsairLightingProtocolHID and CorsairLightingProtocolSerial adapters.
+	 * The only public function of the CorsairLightingProtocolController. It must be called to process a command which
+	 * was received from iCUE. This function is normally called by CorsairLightingProtocolHID and
+	 * CorsairLightingProtocolSerial adapters.
 	 *
 	 * @param command The command received from iCUE
 	 * @param response The response callback which can be called to response to the command
 	 */
 	void handleCommand(const Command& command, CorsairLightingProtocolResponse* response);
+
 private:
 	CorsairLightingFirmware* const corsairLightingFirmware;
 	ILEDController* const ledController;
diff --git a/src/CorsairLightingProtocolHID.cpp b/src/CorsairLightingProtocolHID.cpp
index 3e356567..1b8c9b52 100644
--- a/src/CorsairLightingProtocolHID.cpp
+++ b/src/CorsairLightingProtocolHID.cpp
@@ -26,37 +26,31 @@ bool printCommand = PRINT_COMMAND;
 bool printResponse = PRINT_RESPONSE;
 #endif
 
-CorsairLightingProtocolHID::CorsairLightingProtocolHID(CorsairLightingProtocolController* controller) : controller(controller)
-{
-	RawHID.begin(rawhidData, sizeof(rawhidData));
+CorsairLightingProtocolHID::CorsairLightingProtocolHID(CorsairLightingProtocolController* controller)
+	: controller(controller) {
+	CLP::RawHID.begin(rawhidData, sizeof(rawhidData));
 }
 
-CorsairLightingProtocolHID::CorsairLightingProtocolHID(CorsairLightingProtocolController* controller, const char* serialNumber) : CorsairLightingProtocolHID(controller)
-{
-	RawHID.setSerialNumber(serialNumber);
+CorsairLightingProtocolHID::CorsairLightingProtocolHID(CorsairLightingProtocolController* controller,
+													   const char* serialNumber)
+	: CorsairLightingProtocolHID(controller) {
+	CLP::RawHID.setSerialNumber(serialNumber);
 }
 
-void CorsairLightingProtocolHID::update()
-{
-	if (available())
-	{
+void CorsairLightingProtocolHID::update() {
+	if (available()) {
 		Command command;
 		getCommand(command);
 		controller->handleCommand(command, this);
 	}
 }
 
-bool CorsairLightingProtocolHID::available() const
-{
-	return RawHID.available() > 0;
-}
+bool CorsairLightingProtocolHID::available() const { return CLP::RawHID.available() > 0; }
 
-void CorsairLightingProtocolHID::getCommand(Command& command)
-{
-	auto bytesAvailable = RawHID.available();
-	if (bytesAvailable)
-	{
-		RawHID.readBytes(command.raw, sizeof(command.raw));
+void CorsairLightingProtocolHID::getCommand(Command& command) {
+	auto bytesAvailable = CLP::RawHID.available();
+	if (bytesAvailable) {
+		CLP::RawHID.readBytes(command.raw, sizeof(command.raw));
 #if defined(DEBUG) && defined(VERBOSE)
 		if (printCommand) {
 			Serial.print(F("Received Command: "));
@@ -68,15 +62,14 @@ void CorsairLightingProtocolHID::getCommand(Command& command)
 	}
 }
 
-void CorsairLightingProtocolHID::sendX(const uint8_t* data, const size_t x) const
-{
+void CorsairLightingProtocolHID::sendX(const uint8_t* data, const size_t x) const {
 #if defined(DEBUG) && defined(VERBOSE)
 	if (printResponse) {
 		Serial.print(F("Send Response: "));
 		Serial.println(data[0], HEX);
 	}
 #endif
-	RawHID.write(data, x);
+	CLP::RawHID.write(data, x);
 }
 
 #endif
diff --git a/src/CorsairLightingProtocolHID.h b/src/CorsairLightingProtocolHID.h
index 3a15c078..8e2ffdda 100644
--- a/src/CorsairLightingProtocolHID.h
+++ b/src/CorsairLightingProtocolHID.h
@@ -16,11 +16,9 @@
 #pragma once
 
 #include "Arduino.h"
-
+#include "CorsairLightingProtocolConstants.h"
 #include "CorsairLightingProtocolController.h"
 #include "CorsairLightingProtocolResponse.h"
-#include "CorsairLightingProtocolConstants.h"
-
 #include "RawHID.h"
 
 #if defined(SUPPORT_RAW_HID)
@@ -31,9 +29,8 @@ extern bool printResponse;
 #endif
 
 /**
- * The HID Adapter for CorsairLightingProtocolController. This adapter uses the USB HID interface
- * directly to mimic a corsair device. This adapter can only be used when the USB interface is
- * accessable by the sketch.
+ * The HID Adapter for CorsairLightingProtocolController. This adapter uses the USB HID interface directly to mimic a
+ * corsair device. This adapter can only be used when the USB interface is accessable by the sketch.
  */
 class CorsairLightingProtocolHID : CorsairLightingProtocolResponse {
 public:
@@ -51,10 +48,10 @@ class CorsairLightingProtocolHID : CorsairLightingProtocolResponse {
 	 */
 	CorsairLightingProtocolHID(CorsairLightingProtocolController* controller, const char* serialNumber);
 	/**
-	* Read commands form HID interface and pass them to the contoller.
-	* This function must be called in loop.
-	*/
+	 * Read commands form HID interface and pass them to the contoller. This function must be called in loop.
+	 */
 	void update();
+
 protected:
 	uint8_t rawhidData[COMMAND_SIZE];
 	CorsairLightingProtocolController* const controller;
diff --git a/src/CorsairLightingProtocolResponse.cpp b/src/CorsairLightingProtocolResponse.cpp
index 0ffe7940..5be39cc9 100644
--- a/src/CorsairLightingProtocolResponse.cpp
+++ b/src/CorsairLightingProtocolResponse.cpp
@@ -14,10 +14,11 @@
    limitations under the License.
 */
 #include "CorsairLightingProtocolResponse.h"
+
 #include "CorsairLightingProtocolConstants.h"
 
 void CorsairLightingProtocolResponse::send(const uint8_t* data, size_t size) const {
-	uint8_t response[RESPONSE_SIZE] = { 0x00 };
+	uint8_t response[RESPONSE_SIZE] = {0x00};
 	if (size + 1 > sizeof(response)) {
 		return;
 	}
@@ -27,13 +28,13 @@ void CorsairLightingProtocolResponse::send(const uint8_t* data, size_t size) con
 }
 
 void CorsairLightingProtocolResponse::sendError() const {
-	uint8_t response[RESPONSE_SIZE] = { 0x00 };
+	uint8_t response[RESPONSE_SIZE] = {0x00};
 	response[0] = PROTOCOL_RESPONSE_ERROR;
 	sendX(response, sizeof(response));
 }
 
 void CorsairLightingProtocolResponse::send_P(const uint8_t* data, size_t size) const {
-	uint8_t response[RESPONSE_SIZE] = { 0x00 };
+	uint8_t response[RESPONSE_SIZE] = {0x00};
 	if (size + 1 > sizeof(response)) {
 		return;
 	}
diff --git a/src/CorsairLightingProtocolSerial.cpp b/src/CorsairLightingProtocolSerial.cpp
index 02254141..d7c9d00a 100644
--- a/src/CorsairLightingProtocolSerial.cpp
+++ b/src/CorsairLightingProtocolSerial.cpp
@@ -15,27 +15,24 @@
 */
 #include "CorsairLightingProtocolSerial.h"
 
-CorsairLightingProtocolSerial::CorsairLightingProtocolSerial(CorsairLightingProtocolController* controller) : controller(controller) {}
+CorsairLightingProtocolSerial::CorsairLightingProtocolSerial(CorsairLightingProtocolController* controller)
+	: controller(controller) {}
 
-void CorsairLightingProtocolSerial::setup()
-{
+void CorsairLightingProtocolSerial::setup() {
 	Serial.begin(SERIAL_BAUD);
 	Serial.setTimeout(SERIAL_TIMEOUT);
 }
 
-void CorsairLightingProtocolSerial::update()
-{
+void CorsairLightingProtocolSerial::update() {
 	bool available = handleSerial();
-	if (available)
-	{
+	if (available) {
 		Command command;
 		memcpy(command.raw, rawCommand, sizeof(command.raw));
 		controller->handleCommand(command, this);
 	}
 }
 
-bool CorsairLightingProtocolSerial::handleSerial()
-{
+bool CorsairLightingProtocolSerial::handleSerial() {
 	if (Serial.available()) {
 		delay(SERIAL_TIMEOUT);
 		while (Serial.available()) {
@@ -51,16 +48,12 @@ bool CorsairLightingProtocolSerial::handleSerial()
 		size_t read = Serial.readBytes(rawCommand, sizeof(rawCommand));
 		if (read == sizeof(rawCommand)) {
 			return true;
-		}
-		else {
-			byte data[] = { PROTOCOL_RESPONSE_ERROR, (byte)read };
+		} else {
+			byte data[] = {PROTOCOL_RESPONSE_ERROR, (byte)read};
 			sendX(data, sizeof(data));
 		}
 	}
 	return false;
 }
 
-void CorsairLightingProtocolSerial::sendX(const uint8_t* data, const size_t x) const
-{
-	Serial.write(data, x);
-}
+void CorsairLightingProtocolSerial::sendX(const uint8_t* data, const size_t x) const { Serial.write(data, x); }
diff --git a/src/CorsairLightingProtocolSerial.h b/src/CorsairLightingProtocolSerial.h
index 40a52e16..588673d6 100644
--- a/src/CorsairLightingProtocolSerial.h
+++ b/src/CorsairLightingProtocolSerial.h
@@ -15,11 +15,11 @@
 */
 #pragma once
 
-#include 
 #include 
+#include 
 #include 
 
-//The maximum time in milliseconds needed to receive 64-byte data
+// The maximum time in milliseconds needed to receive 64-byte data
 #define SERIAL_TIMEOUT 2
 #define SERIAL_BAUD 1000000
 
@@ -46,6 +46,7 @@ class CorsairLightingProtocolSerial : CorsairLightingProtocolResponse {
 	 * This function must be called in loop.
 	 */
 	void update();
+
 private:
 	byte rawCommand[COMMAND_SIZE];
 	CorsairLightingProtocolController* const controller;
diff --git a/src/FanController.cpp b/src/FanController.cpp
index 10efdaf1..e8e5e874 100644
--- a/src/FanController.cpp
+++ b/src/FanController.cpp
@@ -14,6 +14,7 @@
    limitations under the License.
 */
 #include "FanController.h"
+
 #include "CLPUtils.h"
 
 bool isValidFanMask(const FanMask fanMask) {
@@ -21,166 +22,152 @@ bool isValidFanMask(const FanMask fanMask) {
 }
 
 bool isValidFanDetectionType(const FanDetectionType type) {
-	return type == FanDetectionType::Auto || type == FanDetectionType::ThreePin || type == FanDetectionType::FourPin || type == FanDetectionType::Disconnected;
+	return type == FanDetectionType::Auto || type == FanDetectionType::ThreePin || type == FanDetectionType::FourPin ||
+		   type == FanDetectionType::Disconnected;
 }
 
-void FanController::handleFanControl(const Command& command, const CorsairLightingProtocolResponse* response)
-{
-	switch (command.command)
-	{
-	case READ_FAN_MASK:
-	{
-		FanMask mask[FAN_NUM];
-		for (uint8_t i = 0; i < FAN_NUM; i++) {
-			switch (getFanDetectionType(i))
-			{
-			case FanDetectionType::Auto:
-				mask[i] = FanMask::Disconnected;//TODO
-				break;
-			case FanDetectionType::ThreePin:
-				mask[i] = FanMask::ThreePin;
-				break;
-			case FanDetectionType::FourPin:
-				mask[i] = FanMask::FourPin;
-				break;
-			case FanDetectionType::Disconnected:
-				mask[i] = FanMask::Disconnected;
-				break;
+void FanController::handleFanControl(const Command& command, const CorsairLightingProtocolResponse* response) {
+	switch (command.command) {
+		case READ_FAN_MASK: {
+			FanMask mask[FAN_NUM];
+			for (uint8_t i = 0; i < FAN_NUM; i++) {
+				switch (getFanDetectionType(i)) {
+					case FanDetectionType::Auto:
+						mask[i] = FanMask::Disconnected;  // TODO
+						break;
+					case FanDetectionType::ThreePin:
+						mask[i] = FanMask::ThreePin;
+						break;
+					case FanDetectionType::FourPin:
+						mask[i] = FanMask::FourPin;
+						break;
+					case FanDetectionType::Disconnected:
+						mask[i] = FanMask::Disconnected;
+						break;
+				}
 			}
+			response->send(reinterpret_cast(mask), sizeof(mask));
+			break;
+		}
+		case READ_FAN_SPEED: {
+			const uint8_t& fan = command.data[0];
+			if (fan >= FAN_NUM) {
+				response->sendError();
+				return;
+			}
+			uint16_t speed = getFanSpeed(fan);
+			uint8_t fanData[] = {toBigEndian(speed)};
+			response->send(fanData, sizeof(fanData));
+			break;
+		}
+		case READ_FAN_POWER: {
+			const uint8_t& fan = command.data[0];
+			if (fan >= FAN_NUM) {
+				response->sendError();
+				return;
+			}
+			uint8_t power = getFanPower(fan);
+			uint8_t powerData[] = {CLP::convert255To100(power)};
+			response->send(powerData, sizeof(powerData));
+			break;
+		}
+		case WRITE_FAN_POWER: {
+			const uint8_t& fan = command.data[0];
+			if (fan >= FAN_NUM) {
+				response->sendError();
+				return;
+			}
+			uint8_t percentage = CLP::convert100To255(command.data[1]);
+			setFanPower(fan, percentage);
+			response->send(nullptr, 0);
+			break;
+		}
+		case WRITE_FAN_SPEED: {
+			const uint8_t& fan = command.data[0];
+			if (fan >= FAN_NUM) {
+				response->sendError();
+				return;
+			}
+			uint16_t speed = CLP::fromBigEndian(command.data[1], command.data[2]);
+			setFanSpeed(fan, speed);
+			response->send(nullptr, 0);
+			break;
+		}
+		case WRITE_FAN_CURVE: {
+			const uint8_t& fan = command.data[0];
+			if (fan >= FAN_NUM) {
+				response->sendError();
+				return;
+			}
+			const uint8_t& group = command.data[1];
+			FanCurve fanCurve;
+			for (uint8_t i = 0; i < FAN_CURVE_POINTS_NUM; i++) {
+				fanCurve.temperatures[i] = CLP::fromBigEndian(command.data[2 + i * 2], command.data[3 + i * 2]);
+				fanCurve.rpms[i] = CLP::fromBigEndian(command.data[14 + i * 2], command.data[15 + i * 2]);
+			}
+			setFanCurve(fan, group, fanCurve);
+			response->send(nullptr, 0);
+			break;
+		}
+		case WRITE_FAN_EXTERNAL_TEMP: {
+			const uint8_t& fan = command.data[0];
+			if (fan >= FAN_NUM) {
+				response->sendError();
+				return;
+			}
+			uint16_t temp = CLP::fromBigEndian(command.data[1], command.data[2]);
+			setFanExternalTemperature(fan, temp);
+			response->send(nullptr, 0);
+			break;
+		}
+		case WRITE_FAN_FORCE_THREE_PIN_MODE: {
+			if (command.data[0] == FAN_FORCE_THREE_PIN_MODE_ON) {
+				setFanForce3PinMode(true);
+			} else if (command.data[0] == FAN_FORCE_THREE_PIN_MODE_OFF) {
+				setFanForce3PinMode(false);
+			} else {
+				response->sendError();
+				return;
+			}
+
+			response->send(nullptr, 0);
+			break;
 		}
-		response->send(reinterpret_cast(mask), sizeof(mask));
-		break;
-	}
-	case READ_FAN_SPEED:
-	{
-		const uint8_t& fan = command.data[0];
-		if (fan >= FAN_NUM) {
-			response->sendError();
-			return;
-		}
-		uint16_t speed = getFanSpeed(fan);
-		uint8_t fanData[] = { toBigEndian(speed) };
-		response->send(fanData, sizeof(fanData));
-		break;
-	}
-	case READ_FAN_POWER:
-	{
-		const uint8_t& fan = command.data[0];
-		if (fan >= FAN_NUM) {
-			response->sendError();
-			return;
-		}
-		uint8_t power = getFanPower(fan);
-		uint8_t powerData[] = { CLP::convert255To100(power) };
-		response->send(powerData, sizeof(powerData));
-		break;
-	}
-	case WRITE_FAN_POWER:
-	{
-		const uint8_t& fan = command.data[0];
-		if (fan >= FAN_NUM) {
-			response->sendError();
-			return;
-		}
-		uint8_t percentage = CLP::convert100To255(command.data[1]);
-		setFanPower(fan, percentage);
-		response->send(nullptr, 0);
-		break;
-	}
-	case WRITE_FAN_SPEED:
-	{
-		const uint8_t& fan = command.data[0];
-		if (fan >= FAN_NUM) {
-			response->sendError();
-			return;
-		}
-		uint16_t speed = CLP::fromBigEndian(command.data[1], command.data[2]);
-		setFanSpeed(fan, speed);
-		response->send(nullptr, 0);
-		break;
-	}
-	case WRITE_FAN_CURVE:
-	{
-		const uint8_t& fan = command.data[0];
-		if (fan >= FAN_NUM) {
-			response->sendError();
-			return;
-		}
-		const uint8_t& group = command.data[1];
-		FanCurve fanCurve;
-		for (uint8_t i = 0; i < FAN_CURVE_POINTS_NUM; i++) {
-			fanCurve.temperatures[i] = CLP::fromBigEndian(command.data[2 + i * 2], command.data[3 + i * 2]);
-			fanCurve.rpms[i] = CLP::fromBigEndian(command.data[14 + i * 2], command.data[15 + i * 2]);
-		}
-		setFanCurve(fan, group, fanCurve);
-		response->send(nullptr, 0);
-		break;
-	}
-	case WRITE_FAN_EXTERNAL_TEMP:
-	{
-		const uint8_t& fan = command.data[0];
-		if (fan >= FAN_NUM) {
-			response->sendError();
-			return;
-		}
-		uint16_t temp = CLP::fromBigEndian(command.data[1], command.data[2]);
-		setFanExternalTemperature(fan, temp);
-		response->send(nullptr, 0);
-		break;
-	}
-	case WRITE_FAN_FORCE_THREE_PIN_MODE:
-	{
-		if (command.data[0] == FAN_FORCE_THREE_PIN_MODE_ON) {
-			setFanForce3PinMode(true);
-		}
-		else if (command.data[0] == FAN_FORCE_THREE_PIN_MODE_OFF) {
-			setFanForce3PinMode(false);
-		}
-		else {
-			response->sendError();
-			return;
-		}
-		
-		response->send(nullptr, 0);
-		break;
-	}
-	case WRITE_FAN_DETECTION_TYPE:
-	{
-		if (command.data[0] != 0x02) {
-			response->sendError();
-			return;
-		}
-		const uint8_t& fan = command.data[1];
-		if (fan >= FAN_NUM) {
-			response->sendError();
-			return;
-		}
-		const FanDetectionType type = static_cast(command.data[2]);
-		if (!isValidFanDetectionType(type)) {
-			response->sendError();
-			return;
-		}
-		setFanDetectionType(fan, type);
-		response->send(nullptr, 0);
-		break;
-	}
-	case READ_FAN_DETECTION_TYPE:
-	{
-		if (command.data[0] != 0x01) {
-			response->sendError();
-			return;
+		case WRITE_FAN_DETECTION_TYPE: {
+			if (command.data[0] != 0x02) {
+				response->sendError();
+				return;
+			}
+			const uint8_t& fan = command.data[1];
+			if (fan >= FAN_NUM) {
+				response->sendError();
+				return;
+			}
+			const FanDetectionType type = static_cast(command.data[2]);
+			if (!isValidFanDetectionType(type)) {
+				response->sendError();
+				return;
+			}
+			setFanDetectionType(fan, type);
+			response->send(nullptr, 0);
+			break;
+		}
+		case READ_FAN_DETECTION_TYPE: {
+			if (command.data[0] != 0x01) {
+				response->sendError();
+				return;
+			}
+			const uint8_t& fan = command.data[1];
+			if (fan >= FAN_NUM) {
+				response->sendError();
+				return;
+			}
+			FanDetectionType type = getFanDetectionType(fan);
+			byte typeData[] = {static_cast(type)};
+			response->send(typeData, sizeof(typeData));
+			break;
 		}
-		const uint8_t& fan = command.data[1];
-		if (fan >= FAN_NUM) {
+		default:
 			response->sendError();
-			return;
-		}
-		FanDetectionType type = getFanDetectionType(fan);
-		byte typeData[] = { static_cast(type) };
-		response->send(typeData, sizeof(typeData));
-		break;
-	}
-	default:
-		response->sendError();
 	}
 }
diff --git a/src/FanController.h b/src/FanController.h
index ccef28ee..514f62cf 100644
--- a/src/FanController.h
+++ b/src/FanController.h
@@ -21,16 +21,15 @@
  */
 
 #include "Arduino.h"
-
 #include "IFanController.h"
 
 #define FAN_NUM 6
 
- /**
-  * The actual state of a fan port.
-  *
-  * @see FanDetectionType
-  */
+/**
+ * The actual state of a fan port.
+ *
+ * @see FanDetectionType
+ */
 enum class FanMask : byte {
 	/** No fan connected */
 	Disconnected = 0x00,
@@ -83,11 +82,13 @@ struct FanCurve {
 };
 
 /**
- * The abstract implementation of IFanController. This implementation handles the parsing and interpretation of incoming commands.
+ * The abstract implementation of IFanController. This implementation handles the parsing and interpretation of incoming
+ * commands.
  */
 class FanController : public IFanController {
 public:
 	virtual void handleFanControl(const Command& command, const CorsairLightingProtocolResponse* response) override;
+
 protected:
 	/**
 	 * Get the fan speed.
diff --git a/src/FastLEDController.cpp b/src/FastLEDController.cpp
index 1f9f609e..1a0e01ab 100644
--- a/src/FastLEDController.cpp
+++ b/src/FastLEDController.cpp
@@ -14,20 +14,17 @@
    limitations under the License.
 */
 #include "FastLEDController.h"
+
 #include 
 
-FastLEDController::FastLEDController(bool useEEPROM) : temperatureController(nullptr), useEEPROM(useEEPROM)
-{
-	load();
-}
+FastLEDController::FastLEDController(bool useEEPROM) : temperatureController(nullptr), useEEPROM(useEEPROM) { load(); }
 
-FastLEDController::FastLEDController(TemperatureController* temperatureController, bool useEEPROM) : temperatureController(temperatureController), useEEPROM(useEEPROM)
-{
+FastLEDController::FastLEDController(TemperatureController* temperatureController, bool useEEPROM)
+	: temperatureController(temperatureController), useEEPROM(useEEPROM) {
 	load();
 }
 
-FastLEDController::~FastLEDController()
-{
+FastLEDController::~FastLEDController() {
 	for (auto& data : channelData) {
 		for (uint8_t*& buffer : data.valuesBuffer) {
 			delete[] buffer;
@@ -46,16 +43,14 @@ void FastLEDController::addLEDs(uint8_t channel, CRGB* leds, uint8_t count) {
 	}
 }
 
-CRGB* FastLEDController::getLEDs(uint8_t channel)
-{
+CRGB* FastLEDController::getLEDs(uint8_t channel) {
 	if (channel >= CHANNEL_NUM) {
 		return nullptr;
 	}
 	return channelData[channel].leds;
 }
 
-uint8_t FastLEDController::getLEDCount(uint8_t channel)
-{
+uint8_t FastLEDController::getLEDCount(uint8_t channel) {
 	if (channel >= CHANNEL_NUM) {
 		return 0;
 	}
@@ -63,16 +58,15 @@ uint8_t FastLEDController::getLEDCount(uint8_t channel)
 }
 
 int FastLEDController::applySpeed(int duration, const GroupSpeed speed) {
-	switch (speed)
-	{
-	case GroupSpeed::High:
-		return duration / 2;
-	case GroupSpeed::Medium:
-		return duration;
-	case GroupSpeed::Low:
-		return duration * 2;
-	default:
-		return duration;
+	switch (speed) {
+		case GroupSpeed::High:
+			return duration / 2;
+		case GroupSpeed::Medium:
+			return duration;
+		case GroupSpeed::Low:
+			return duration * 2;
+		default:
+			return duration;
 	}
 }
 
@@ -90,10 +84,12 @@ int FastLEDController::animation_step_count(int duration, int steps) {
 	return currentStep - lastStep + (currentAnimationNumber - lastAnimationNumber) * steps;
 }
 
-bool FastLEDController::updateLEDs()
-{
+bool FastLEDController::updateLEDs() {
 	lastUpdate = currentUpdate;
 	currentUpdate = millis();
+	if (currentUpdate - lastCommand > LED_CONTROLLER_TIMEOUT) {
+		timeoutAction();
+	}
 
 	bool anyUpdate = false;
 
@@ -104,305 +100,288 @@ bool FastLEDController::updateLEDs()
 		bool updated = false;
 		LEDChannel& channel = channels[channelId];
 
-		switch (channel.mode)
-		{
-		case ChannelMode::Disabled:
-		{
-			break;
-		}
-		case ChannelMode::HardwarePlayback:
-		{
-			for (uint8_t groupIndex = 0; groupIndex < channel.groupsSet; groupIndex++) {
-				LEDGroup& group = channel.groups[groupIndex];
-				int groupLedCount = min((int)channelData[channelId].ledCount - group.ledIndex, (int)group.ledCount);
-				if (groupLedCount <= 0) {
-					continue;
-				}
-
-				switch (group.mode)
-				{
-				case GROUP_MODE_Rainbow_Wave:
-				{
-					int duration = applySpeed(3300, group.speed);
-					int count = animation_step_count(duration, 256);
-					if (count > 0) {
-						int step = animation_step(duration, 256);
-						int move = group.direction == GroupDirection::Forward ? -3 : 3;
-						for (int i = 0; i < groupLedCount; i++) {
-							channelData[channelId].leds[group.ledIndex + i] = CHSV(step + (i * move), 255, 255);
-						}
-						updated = true;
+		switch (channel.mode) {
+			case ChannelMode::Disabled: {
+				break;
+			}
+			case ChannelMode::HardwarePlayback: {
+				for (uint8_t groupIndex = 0; groupIndex < channel.groupsSet; groupIndex++) {
+					LEDGroup& group = channel.groups[groupIndex];
+					int groupLedCount = min((int)channelData[channelId].ledCount - group.ledIndex, (int)group.ledCount);
+					if (groupLedCount <= 0) {
+						continue;
 					}
-					break;
-				}
-				case GROUP_MODE_Color_Shift:
-				{
-					int duration = applySpeed(3000, group.speed);
-					int count = animation_step_count(duration, 512);
-					if (count > 0) {
-						int step = animation_step(duration, 512);
-						if (count > step) {
-							if (group.extra == GroupExtra::Random) {
-								group.color1 = group.color2;
-								group.color2 = CHSV(random8(), 255, 255);
-							}
-							else if (group.extra == GroupExtra::Alternating) {
-								group.color3 = group.color1;
-								group.color1 = group.color2;
-								group.color2 = group.color3;
+
+					switch (group.mode) {
+						case GROUP_MODE_Rainbow_Wave: {
+							int duration = applySpeed(3300, group.speed);
+							int count = animation_step_count(duration, 256);
+							if (count > 0) {
+								int step = animation_step(duration, 256);
+								int move = group.direction == GroupDirection::Forward ? -3 : 3;
+								for (int i = 0; i < groupLedCount; i++) {
+									channelData[channelId].leds[group.ledIndex + i] = CHSV(step + (i * move), 255, 255);
+								}
+								updated = true;
 							}
+							break;
 						}
-						uint8_t scale;
-						if (step < 128) {
-							scale = 0;
-						}
-						else if (step < 384) {
-							scale = ease8InOutApprox(step - 128);
-						}
-						else {
-							scale = 255;
+						case GROUP_MODE_Color_Shift: {
+							int duration = applySpeed(3000, group.speed);
+							int count = animation_step_count(duration, 512);
+							if (count > 0) {
+								int step = animation_step(duration, 512);
+								if (count > step) {
+									if (group.extra == GroupExtra::Random) {
+										group.color1 = group.color2;
+										group.color2 = CHSV(random8(), 255, 255);
+									} else if (group.extra == GroupExtra::Alternating) {
+										group.color3 = group.color1;
+										group.color1 = group.color2;
+										group.color2 = group.color3;
+									}
+								}
+								uint8_t scale;
+								if (step < 128) {
+									scale = 0;
+								} else if (step < 384) {
+									scale = ease8InOutApprox(step - 128);
+								} else {
+									scale = 255;
+								}
+
+								fill_solid(&channelData[channelId].leds[group.ledIndex], groupLedCount,
+										   group.color1.lerp8(group.color2, scale));
+								updated = true;
+							}
+							break;
 						}
-
-						fill_solid(&channelData[channelId].leds[group.ledIndex], groupLedCount, group.color1.lerp8(group.color2, scale));
-						updated = true;
-					}
-					break;
-				}
-				case GROUP_MODE_Color_Pulse:
-				{
-					int duration = applySpeed(3000, group.speed);
-					int count = animation_step_count(duration, 512);
-					if (count > 0) {
-						int step = animation_step(duration, 512);
-						if (count > step) {
-							if (group.extra == GroupExtra::Random) {
-								group.color1 = CHSV(random8(), 255, 255);
+						case GROUP_MODE_Color_Pulse: {
+							int duration = applySpeed(3000, group.speed);
+							int count = animation_step_count(duration, 512);
+							if (count > 0) {
+								int step = animation_step(duration, 512);
+								if (count > step) {
+									if (group.extra == GroupExtra::Random) {
+										group.color1 = CHSV(random8(), 255, 255);
+									} else if (group.extra == GroupExtra::Alternating) {
+										group.color3 = group.color1;
+										group.color1 = group.color2;
+										group.color2 = group.color3;
+									}
+								}
+								uint8_t scale = ease8InOutApprox((uint8_t)step);
+								if (step >= 256) {
+									scale = 255 - scale;
+								}
+
+								fill_solid(&channelData[channelId].leds[group.ledIndex], groupLedCount,
+										   group.color1 % scale);
+								updated = true;
 							}
-							else if (group.extra == GroupExtra::Alternating) {
-								group.color3 = group.color1;
-								group.color1 = group.color2;
-								group.color2 = group.color3;
+							break;
+						}
+						case GROUP_MODE_Color_Wave: {
+							int duration = applySpeed(3000, group.speed);
+							int count = animation_step_count(duration, 10000);
+							if (count > 0) {
+								int step = animation_step(duration, 10000);
+								if (count > step) {
+									if (group.extra == GroupExtra::Random) {
+										group.color1 = group.color2;
+										group.color2 = CHSV(random8(), 255, 255);
+									} else if (group.extra == GroupExtra::Alternating) {
+										group.color3 = group.color1;
+										group.color1 = group.color2;
+										group.color2 = group.color3;
+									}
+								}
+								float valley = step / 10000.0;
+								for (int i = 0; i < groupLedCount; i++) {
+									float pos = (i % 17) / 17.0;
+
+									float distanceWave;
+									CRGB color;
+									const bool flag = (i % 34) < 17;
+									if (pos < valley) {
+										color = flag ? group.color1 : group.color2;
+										distanceWave = abs(valley - 0.5 - pos);
+									} else {
+										color = flag ? group.color2 : group.color1;
+										distanceWave = abs(valley + 0.5 - pos);
+									}
+
+									uint8_t scale;
+									if (distanceWave > 0.25) {
+										scale = 0;
+									} else {
+										scale = 255 - ease8InOutApprox((distanceWave * 4) * 256);
+									}
+									channelData[channelId].leds[group.ledIndex + i] = (color % scale);
+								}
+								updated = true;
 							}
+							break;
 						}
-						uint8_t scale = ease8InOutApprox((uint8_t)step);
-						if (step >= 256) {
-							scale = 255 - scale;
+						case GROUP_MODE_Static: {
+							fill_solid(&channelData[channelId].leds[group.ledIndex], groupLedCount, group.color1);
+							updated = true;
+							break;
 						}
-
-						fill_solid(&channelData[channelId].leds[group.ledIndex], groupLedCount, group.color1 % scale);
-						updated = true;
-					}
-					break;
-				}
-				case GROUP_MODE_Color_Wave:
-				{
-					int duration = applySpeed(3000, group.speed);
-					int count = animation_step_count(duration, 10000);
-					if (count > 0) {
-						int step = animation_step(duration, 10000);
-						if (count > step) {
-							if (group.extra == GroupExtra::Random) {
-								group.color1 = group.color2;
-								group.color2 = CHSV(random8(), 255, 255);
-							}
-							else if (group.extra == GroupExtra::Alternating) {
-								group.color3 = group.color1;
-								group.color1 = group.color2;
-								group.color2 = group.color3;
+						case GROUP_MODE_Temperature: {
+							uint16_t currentTemperature;
+							const uint8_t& tempGroup = group.tempGroup;
+							if (tempGroup == GROUP_TEMP_GROUP_EXTERNAL) {
+								currentTemperature = channelData[channelId].temp;
+							} else if (tempGroup < TEMPERATURE_NUM && temperatureController != nullptr) {
+								currentTemperature = temperatureController->getTemperature(tempGroup);
+							} else {
+								break;
 							}
-						}
-						float valley = step / 10000.0;
-						for (int i = 0; i < groupLedCount; i++) {
-							float pos = (i % 17) / 17.0;
 
-							float distanceWave;
 							CRGB color;
-							const bool flag = (i % 34) < 17;
-							if (pos < valley) {
-								color = flag ? group.color1 : group.color2;
-								distanceWave = abs(valley - 0.5 - pos);
-							}
-							else {
-								color = flag ? group.color2 : group.color1;
-								distanceWave = abs(valley + 0.5 - pos);
+							if (currentTemperature < group.temp1) {
+								color = group.color1;
+							} else if (currentTemperature < group.temp2) {
+								color = group.color1.lerp16(group.color2, ((currentTemperature - group.temp1) /
+																		   ((float)(group.temp2 - group.temp1))) *
+																			  65535);
+							} else if (currentTemperature < group.temp3) {
+								color = group.color2.lerp16(group.color3, ((currentTemperature - group.temp2) /
+																		   ((float)(group.temp3 - group.temp2))) *
+																			  65535);
+							} else {
+								color = group.color3;
 							}
 
-							uint8_t scale;
-							if (distanceWave > 0.25) {
-								scale = 0;
-							}
-							else {
-								scale = 255 - ease8InOutApprox((distanceWave * 4) * 256);
-							}
-							channelData[channelId].leds[group.ledIndex + i] = (color % scale);
+							fill_solid(&channelData[channelId].leds[group.ledIndex], groupLedCount, color);
+							updated = true;
+							break;
 						}
-						updated = true;
-					}
-					break;
-				}
-				case GROUP_MODE_Static:
-				{
-					fill_solid(&channelData[channelId].leds[group.ledIndex], groupLedCount, group.color1);
-					updated = true;
-					break;
-				}
-				case GROUP_MODE_Temperature:
-				{
-					uint16_t currentTemperature;
-					const uint8_t& tempGroup = group.tempGroup;
-					if (tempGroup == GROUP_TEMP_GROUP_EXTERNAL) {
-						currentTemperature = channelData[channelId].temp;
-					}
-					else if (tempGroup < TEMPERATURE_NUM && temperatureController != nullptr) {
-						currentTemperature = temperatureController->getTemperature(tempGroup);
-					} else {
-						break;
-					}
-
-					CRGB color;
-					if (currentTemperature < group.temp1) {
-						color = group.color1;
-					}
-					else if (currentTemperature < group.temp2) {
-						color = group.color1.lerp16(group.color2, ((currentTemperature - group.temp1) / ((float)(group.temp2 - group.temp1))) * 65535);
-					}
-					else if (currentTemperature < group.temp3) {
-						color = group.color2.lerp16(group.color3, ((currentTemperature - group.temp2) / ((float)(group.temp3 - group.temp2))) * 65535);
-					}
-					else {
-						color = group.color3;
-					}
-
-					fill_solid(&channelData[channelId].leds[group.ledIndex], groupLedCount, color);
-					updated = true;
-					break;
-				}
-				case GROUP_MODE_Visor:
-				{
-					int duration = applySpeed(150 * groupLedCount, group.speed);
-					int steps = groupLedCount * 2;
-					int count = animation_step_count(duration, steps);
-					if (count > 0) {
-						int step = animation_step(duration, steps);
-						if (step >= groupLedCount ? count > step - groupLedCount : count > step) {
-							if (group.extra == GroupExtra::Random) {
-								group.color1 = CHSV(random8(), 255, 255);
-							}
-							else if (group.extra == GroupExtra::Alternating) {
-								group.color3 = group.color1;
-								group.color1 = group.color2;
-								group.color2 = group.color3;
+						case GROUP_MODE_Visor: {
+							int duration = applySpeed(150 * groupLedCount, group.speed);
+							int steps = groupLedCount * 2;
+							int count = animation_step_count(duration, steps);
+							if (count > 0) {
+								int step = animation_step(duration, steps);
+								if (step >= groupLedCount ? count > step - groupLedCount : count > step) {
+									if (group.extra == GroupExtra::Random) {
+										group.color1 = CHSV(random8(), 255, 255);
+									} else if (group.extra == GroupExtra::Alternating) {
+										group.color3 = group.color1;
+										group.color1 = group.color2;
+										group.color2 = group.color3;
+									}
+								}
+								fill_solid(&channelData[channelId].leds[group.ledIndex], groupLedCount, CRGB::Black);
+								for (int i = 0; i < 4; i++) {
+									int led = (((step - i) % steps) + steps) % steps;
+									if (led >= groupLedCount) {
+										led = steps - led - 1;
+									}
+									channelData[channelId].leds[group.ledIndex + led] = group.color1;
+								}
+								updated = true;
 							}
+							break;
 						}
-						fill_solid(&channelData[channelId].leds[group.ledIndex], groupLedCount, CRGB::Black);
-						for (int i = 0; i < 4; i++) {
-							int led = (((step - i) % steps) + steps) % steps;
-							if (led >= groupLedCount) {
-								led = steps - led - 1;
+						case GROUP_MODE_Marquee: {
+							int duration = applySpeed(700, group.speed);
+							int count = animation_step_count(duration, 3);
+							if (count > 0) {
+								int step = animation_step(duration, 3);
+								for (int i = 0; i < groupLedCount; i++) {
+									channelData[channelId].leds[group.ledIndex + i] =
+										(i + step) % 3 > 0 ? group.color1 : CRGB::Black;
+								}
+								updated = true;
 							}
-							channelData[channelId].leds[group.ledIndex + led] = group.color1;
-						}
-						updated = true;
-					}
-					break;
-				}
-				case GROUP_MODE_Marquee:
-				{
-					int duration = applySpeed(700, group.speed);
-					int count = animation_step_count(duration, 3);
-					if (count > 0) {
-						int step = animation_step(duration, 3);
-						for (int i = 0; i < groupLedCount; i++) {
-							channelData[channelId].leds[group.ledIndex + i] = (i + step) % 3 > 0 ? group.color1 : CRGB::Black;
+							break;
 						}
-						updated = true;
-					}
-					break;
-				}
-				case GROUP_MODE_Blink:
-				{
-					int duration = applySpeed(3000, group.speed);
-					int count = animation_step_count(duration, 2);
-					if (count > 0) {
-						int step = animation_step(duration, 2);
-						if (count > step) {
-							if (group.extra == GroupExtra::Random) {
-								group.color1 = CHSV(random8(), 255, 255);
-							}
-							else if (group.extra == GroupExtra::Alternating) {
-								group.color3 = group.color1;
-								group.color1 = group.color2;
-								group.color2 = group.color3;
+						case GROUP_MODE_Blink: {
+							int duration = applySpeed(3000, group.speed);
+							int count = animation_step_count(duration, 2);
+							if (count > 0) {
+								int step = animation_step(duration, 2);
+								if (count > step) {
+									if (group.extra == GroupExtra::Random) {
+										group.color1 = CHSV(random8(), 255, 255);
+									} else if (group.extra == GroupExtra::Alternating) {
+										group.color3 = group.color1;
+										group.color1 = group.color2;
+										group.color2 = group.color3;
+									}
+								}
+
+								fill_solid(&channelData[channelId].leds[group.ledIndex], groupLedCount,
+										   step == 0 ? group.color1 : CRGB::Black);
+								updated = true;
 							}
+							break;
 						}
-
-						fill_solid(&channelData[channelId].leds[group.ledIndex], groupLedCount, step == 0 ? group.color1 : CRGB::Black);
-						updated = true;
-					}
-					break;
-				}
-				case GROUP_MODE_Sequential:
-				{
-					int steps = groupLedCount;
-					int duration = applySpeed(60 * steps, group.speed);
-					int count = animation_step_count(duration, steps);
-					if (count > 0) {
-						int step = animation_step(duration, steps);
-						if (count > step) {
-							if (group.extra == GroupExtra::Random) {
-								group.color2 = group.color1;
-								group.color1 = CHSV(random8(), 255, 255);
+						case GROUP_MODE_Sequential: {
+							int steps = groupLedCount;
+							int duration = applySpeed(60 * steps, group.speed);
+							int count = animation_step_count(duration, steps);
+							if (count > 0) {
+								int step = animation_step(duration, steps);
+								if (count > step) {
+									if (group.extra == GroupExtra::Random) {
+										group.color2 = group.color1;
+										group.color1 = CHSV(random8(), 255, 255);
+									}
+								}
+
+								if (group.direction == GroupDirection::Forward) {
+									fill_solid(&channelData[channelId].leds[group.ledIndex], step + 1, group.color1);
+									fill_solid(&channelData[channelId].leds[group.ledIndex + step + 1],
+											   groupLedCount - (step + 1), group.color2);
+								} else {
+									fill_solid(
+										&channelData[channelId].leds[group.ledIndex + groupLedCount - (step + 1)],
+										step + 1, group.color1);
+									fill_solid(&channelData[channelId].leds[group.ledIndex], groupLedCount - (step + 1),
+											   group.color2);
+								}
+								updated = true;
 							}
+							break;
 						}
-
-						if (group.direction == GroupDirection::Forward) {
-							fill_solid(&channelData[channelId].leds[group.ledIndex], step + 1, group.color1);
-							fill_solid(&channelData[channelId].leds[group.ledIndex + step + 1], groupLedCount - (step + 1), group.color2);
-						}
-						else {
-							fill_solid(&channelData[channelId].leds[group.ledIndex + groupLedCount - (step + 1)], step + 1, group.color1);
-							fill_solid(&channelData[channelId].leds[group.ledIndex], groupLedCount - (step + 1), group.color2);
+						case GROUP_MODE_Rainbow: {
+							int duration = applySpeed(3000, group.speed);
+							int count = animation_step_count(duration, 256);
+							if (count > 0) {
+								int step = animation_step(duration, 256);
+								fill_solid(&channelData[channelId].leds[group.ledIndex], groupLedCount,
+										   CHSV(step, 255, 255));
+								updated = true;
+							}
+							break;
 						}
-						updated = true;
-					}
-					break;
-				}
-				case GROUP_MODE_Rainbow:
-				{
-					int duration = applySpeed(3000, group.speed);
-					int count = animation_step_count(duration, 256);
-					if (count > 0) {
-						int step = animation_step(duration, 256);
-						fill_solid(&channelData[channelId].leds[group.ledIndex], groupLedCount, CHSV(step, 255, 255));
-						updated = true;
-					}
-					break;
-				}
-				default:
-				{
+						default: {
 #ifdef DEBUG
-					Serial.print(F("unkown group mode: "));
-					Serial.print(group.mode, HEX);
-					Serial.println();
+							Serial.print(F("unkown group mode: "));
+							Serial.print(group.mode, HEX);
+							Serial.println();
 #endif
-					break;
-				}
-				nscale8_video(&channelData[channelId].leds[group.ledIndex], groupLedCount, channel.brightness);
+							break;
+						}
+							nscale8_video(&channelData[channelId].leds[group.ledIndex], groupLedCount,
+										  channel.brightness);
+					}
 				}
+				break;
 			}
-			break;
-		}
-		case ChannelMode::SoftwarePlayback:
-		{
-			if (trigger_update) {
-				auto& data = channelData[channelId];
-				for (int i = 0; i < data.ledCount; i++) {
-					data.leds[i] = CRGB(data.valuesBuffer[0][i], data.valuesBuffer[1][i], data.valuesBuffer[2][i]);
+			case ChannelMode::SoftwarePlayback: {
+				if (trigger_update) {
+					auto& data = channelData[channelId];
+					for (int i = 0; i < data.ledCount; i++) {
+						data.leds[i] = CRGB(data.valuesBuffer[0][i], data.valuesBuffer[1][i], data.valuesBuffer[2][i]);
+					}
+					updated = true;
 				}
-				updated = true;
+				break;
 			}
-			break;
-		}
 		}
 		if (updated) {
 			anyUpdate = true;
@@ -415,13 +394,9 @@ bool FastLEDController::updateLEDs()
 	return anyUpdate;
 }
 
-size_t FastLEDController::getEEPROMSize()
-{
-	return sizeof(channels);
-}
+size_t FastLEDController::getEEPROMSize() { return sizeof(channels); }
 
-void FastLEDController::onUpdateHook(uint8_t channel, void (*callback)(void))
-{
+void FastLEDController::onUpdateHook(uint8_t channel, void (*callback)(void)) {
 	channelData[channel].onUpdateCallback = callback;
 }
 
@@ -449,25 +424,25 @@ bool FastLEDController::save() {
 	return false;
 }
 
-void FastLEDController::triggerLEDUpdate()
-{
-	trigger_update = true;
-}
+void FastLEDController::triggerLEDUpdate() { trigger_update = true; }
 
-void FastLEDController::setLEDExternalTemperature(uint8_t channel, uint16_t temp)
-{
-	channelData[channel].temp = temp;
-}
+void FastLEDController::setLEDExternalTemperature(uint8_t channel, uint16_t temp) { channelData[channel].temp = temp; }
 
-void FastLEDController::setLEDColorValues(uint8_t channel, uint8_t color, uint8_t offset, const uint8_t* values, size_t len)
-{
+void FastLEDController::setLEDColorValues(uint8_t channel, uint8_t color, uint8_t offset, const uint8_t* values,
+										  size_t len) {
 	int copyLength = min((int)channelData[channel].ledCount - offset, (int)len);
 	if (copyLength > 0) {
 		memcpy(channelData[channel].valuesBuffer[color] + offset, values, copyLength);
 	}
 }
 
-void FastLEDController::clearLEDColorValues(uint8_t channel)
-{
+void FastLEDController::clearLEDColorValues(uint8_t channel) {
 	memset(channelData[channel].valuesBuffer[0], 0, channelData[channel].ledCount);
 }
+
+void FastLEDController::timeoutAction() {
+	for (int channelId = 0; channelId < CHANNEL_NUM; channelId++) {
+		triggerSave |= setLEDMode(channelId, ChannelMode::HardwarePlayback);
+	}
+	saveIfNeeded();
+}
diff --git a/src/FastLEDController.h b/src/FastLEDController.h
index 330ed35c..fb4a89c9 100644
--- a/src/FastLEDController.h
+++ b/src/FastLEDController.h
@@ -15,8 +15,9 @@
 */
 #pragma once
 
-#include "Arduino.h"
 #include 
+
+#include "Arduino.h"
 #include "LEDController.h"
 #include "TemperatureController.h"
 
@@ -24,10 +25,15 @@
 #define EEPROM_ADDRESS 4
 #endif
 
+#ifndef LED_CONTROLLER_TIMEOUT
+#define LED_CONTROLLER_TIMEOUT 30000
+#endif
+
 /**
- * The default LEDController. This controller uses the FastLED library to implement the Hardware Lighting effects. Also all RGB values
- * of the LEDs are stored into CRGB arrays which can be used by the FastLED library to show them on the real LED strips. This controller
- * can stores the internal state to EEPROM and support HW playback without USB connection.
+ * The default LEDController. This controller uses the FastLED library to implement the Hardware Lighting effects. Also
+ * all RGB values of the LEDs are stored into CRGB arrays which can be used by the FastLED library to show them on the
+ * real LED strips. This controller can stores the internal state to EEPROM and support HW playback without USB
+ * connection.
  *
  * @see FastLED
  */
@@ -41,7 +47,7 @@ class FastLEDController : public LEDController {
 		/**
 		 * store an array for each color, used for software playback
 		 */
-		uint8_t* valuesBuffer[3] = { nullptr };
+		uint8_t* valuesBuffer[3] = {nullptr};
 		/**
 		 * External temperature value used by this channel for temperature based lighting.
 		 */
@@ -51,15 +57,17 @@ class FastLEDController : public LEDController {
 
 public:
 	/**
-	 * Create a new FastLEDController and specify if the EEPROM of the Arduino should be used. See the other contructor for more details.
+	 * Create a new FastLEDController and specify if the EEPROM of the Arduino should be used. See the other contructor
+	 * for more details.
 	 *
 	 * @param useEEPROM specify if the EEPROM should be used
 	 */
 	FastLEDController(bool useEEPROM);
 	/**
-	 * Create a new FastLEDController and specify if the EEPROM of the Arduino should be used to store persistent information like
-	 * the Hardware Lighting. If enabled, the hardware lighting configured in iCUE works without a USB connection and even after a
-	 * restart of the Arduino. Also the the TemperatureController used for temperature related lighting can be passed here.
+	 * Create a new FastLEDController and specify if the EEPROM of the Arduino should be used to store persistent
+	 * information like the Hardware Lighting. If enabled, the hardware lighting configured in iCUE works without a USB
+	 * connection and even after a restart of the Arduino. Also the the TemperatureController used for temperature
+	 * related lighting can be passed here.
 	 *
 	 * @param temperatureController used for temperature based lighting
 	 * @param useEEPROM specify if the EEPROM should be used
@@ -67,8 +75,8 @@ class FastLEDController : public LEDController {
 	FastLEDController(TemperatureController* temperatureController, bool useEEPROM);
 	~FastLEDController();
 	/**
-	 * Add a LED array on a channel with a given length. The length define how many LEDs iCUE can control. The actual length of the array
-	 * can be longer, but iCUE only writes up to the specified length.
+	 * Add a LED array on a channel with a given length. The length define how many LEDs iCUE can control. The actual
+	 * length of the array can be longer, but iCUE only writes up to the specified length.
 	 *
 	 * @param channel the index of the channel
 	 * @param leds the array to store the LED data in
@@ -105,13 +113,14 @@ class FastLEDController : public LEDController {
 	 */
 	virtual size_t getEEPROMSize();
 	/**
-	 * Register an update hook, which is executed after a channel has been updated. This can be used to apply transforamtions to the
-	 * channel before the data is displayed by FastLED.
+	 * Register an update hook, which is executed after a channel has been updated. This can be used to apply
+	 * transforamtions to the channel before the data is displayed by FastLED.
 	 *
 	 * @param channel the channel for which the hook is registered
 	 * @param callback the callback, which is executed after the update
 	 */
 	void onUpdateHook(uint8_t channel, void (*callback)(void));
+
 protected:
 	TemperatureController* const temperatureController;
 
@@ -146,6 +155,11 @@ class FastLEDController : public LEDController {
 
 	virtual void triggerLEDUpdate() override;
 	virtual void setLEDExternalTemperature(uint8_t channel, uint16_t temp) override;
-	virtual void setLEDColorValues(uint8_t channel, uint8_t color, uint8_t offset, const uint8_t* values, size_t len) override;
+	virtual void setLEDColorValues(uint8_t channel, uint8_t color, uint8_t offset, const uint8_t* values,
+								   size_t len) override;
 	virtual void clearLEDColorValues(uint8_t channel) override;
+	/**
+	 * This function is called when a timeout occurs.
+	 */
+	virtual void timeoutAction();
 };
diff --git a/src/FastLEDControllerUtils.cpp b/src/FastLEDControllerUtils.cpp
index e183516e..bb1391fe 100644
--- a/src/FastLEDControllerUtils.cpp
+++ b/src/FastLEDControllerUtils.cpp
@@ -14,11 +14,11 @@
    limitations under the License.
 */
 #include "FastLEDControllerUtils.h"
-#include 
+
 #include 
+#include 
 
-void CLP::transformLLFanToStrip(FastLEDController* controller, uint8_t channelIndex)
-{
+void CLP::transformLLFanToStrip(FastLEDController* controller, uint8_t channelIndex) {
 	auto& channel = controller->getChannel(channelIndex);
 	if (channel.mode == ChannelMode::SoftwarePlayback) {
 		auto leds = controller->getLEDs(channelIndex);
@@ -32,8 +32,7 @@ void CLP::transformLLFanToStrip(FastLEDController* controller, uint8_t channelIn
 	}
 }
 
-void CLP::scale(FastLEDController* controller, uint8_t channelIndex, int scaleToSize)
-{
+void CLP::scale(FastLEDController* controller, uint8_t channelIndex, int scaleToSize) {
 	auto leds = controller->getLEDs(channelIndex);
 	const float scaleFactor = (float)controller->getLEDCount(channelIndex) / scaleToSize;
 	for (int ledIndex = scaleToSize - 1; ledIndex >= 0; ledIndex--) {
@@ -41,38 +40,54 @@ void CLP::scale(FastLEDController* controller, uint8_t channelIndex, int scaleTo
 	}
 }
 
-void CLP::repeat(FastLEDController* controller, uint8_t channelIndex, uint8_t times)
-{
+void CLP::repeat(FastLEDController* controller, uint8_t channelIndex, uint8_t times) {
 	auto leds = controller->getLEDs(channelIndex);
 	auto count = controller->getLEDCount(channelIndex);
-	//skip first iteration, because LEDs already contains the data at the first position
+	// skip first iteration, because LEDs already contains the data at the first position
 	for (int i = 1; i < times; i++) {
 		memcpy(leds + (count * i), leds, sizeof(CRGB) * count);
 	}
 }
 
-void CLP::scaleSegments(FastLEDController* controller, uint8_t channelIndex, const SegmentScaling* const segments, int segmentsCount)
-{
+void CLP::scaleSegments(FastLEDController* controller, uint8_t channelIndex, const SegmentScaling* const segments,
+						int segmentsCount) {
 	auto leds = controller->getLEDs(channelIndex);
 	int ledStripIndexAfterScaling = 0;
 	int ledStripIndexBeforeScaling = 0;
+	int totalLengthAfterScaling = 0;
+	SegmentScaling downScaledSegments[segmentsCount];
+	// scale down segments and move all segments together so there is space for upscaling
 	for (int i = 0; i < segmentsCount; i++) {
-		ledStripIndexAfterScaling += segments[i].scaleToSize;
-		ledStripIndexBeforeScaling += segments[i].segmentLength;
+		const int segmentLength = segments[i].segmentLength;
+		const int scaleToSize = segments[i].scaleToSize < segmentLength ? segments[i].scaleToSize : segmentLength;
+		const float scaleFactor = (float)segmentLength / scaleToSize;
+
+		for (int ledIndex = 0; ledIndex < scaleToSize; ledIndex++) {
+			leds[ledStripIndexAfterScaling + ledIndex] =
+				leds[ledStripIndexBeforeScaling + lround(ledIndex * scaleFactor)];
+		}
+		ledStripIndexAfterScaling += scaleToSize;
+		ledStripIndexBeforeScaling += segmentLength;
+		downScaledSegments[i].segmentLength = scaleToSize;
+		downScaledSegments[i].scaleToSize = segments[i].scaleToSize;
+		totalLengthAfterScaling += segments[i].scaleToSize;
 	}
 
+	ledStripIndexBeforeScaling = ledStripIndexAfterScaling;
+	ledStripIndexAfterScaling = totalLengthAfterScaling;
+	// scale up segments beginning with the last segment to not override other segments
 	for (int i = segmentsCount - 1; i >= 0; i--) {
-		const float scaleFactor = (float)segments[i].segmentLength / segments[i].scaleToSize;
-		ledStripIndexAfterScaling -= segments[i].scaleToSize;
-		ledStripIndexBeforeScaling -= segments[i].segmentLength;
-		for (int ledIndex = segments[i].scaleToSize - 1; ledIndex >= 0; ledIndex--) {
-			leds[ledStripIndexAfterScaling + ledIndex] = leds[ledStripIndexBeforeScaling + lround(ledIndex * scaleFactor)];
+		const float scaleFactor = (float)downScaledSegments[i].segmentLength / downScaledSegments[i].scaleToSize;
+		ledStripIndexAfterScaling -= downScaledSegments[i].scaleToSize;
+		ledStripIndexBeforeScaling -= downScaledSegments[i].segmentLength;
+		for (int ledIndex = downScaledSegments[i].scaleToSize - 1; ledIndex >= 0; ledIndex--) {
+			leds[ledStripIndexAfterScaling + ledIndex] =
+				leds[ledStripIndexBeforeScaling + lround(ledIndex * scaleFactor)];
 		}
 	}
 }
 
-void CLP::reverse(FastLEDController* controller, uint8_t channelIndex)
-{
+void CLP::reverse(FastLEDController* controller, uint8_t channelIndex) {
 	auto leds = controller->getLEDs(channelIndex);
 	auto maxIndex = controller->getLEDCount(channelIndex) - 1;
 	for (int ledIndex = 0; ledIndex < maxIndex - ledIndex; ledIndex++) {
diff --git a/src/FastLEDControllerUtils.h b/src/FastLEDControllerUtils.h
index 89b38d08..7988fa52 100644
--- a/src/FastLEDControllerUtils.h
+++ b/src/FastLEDControllerUtils.h
@@ -18,71 +18,75 @@
 #include "Arduino.h"
 #include "FastLEDController.h"
 
-namespace CLP
-{
-	/**
-	 * Make it possible to use up to 96 LEDs per channel from iCUE by using the LL Fan option. This function transforms the LL fans layout to a normal strip layout.
-	 * This function can be combined with scale and repeat function but must be invoked first.
-	 * 
-	 * @param controller the FastLEDController controlling the LEDs
-	 * @param channelIndex the index of the channel
-	 */
-	void transformLLFanToStrip(FastLEDController* controller, uint8_t channelIndex);
-	/**
-	 * Scales a channel's length to a given size, the size can be larger or smaller than the default length given to the FastLEDController::addLEDs function
-	 * Integer scaling is used, so no interpolation between color values is done and the animation don't look blurry.
-	 * 
-	 * @param controller the FastLEDController controlling the LEDs
-	 * @param channelIndex the index of the channel
-	 * @param scaleToSize the final size after scaling
-	 */
-	void scale(FastLEDController* controller, uint8_t channelIndex, int scaleToSize);
-	/**
-	 * Repeat a channel's LEDs color to control more LEDs than provided by iCUE.
-	 * 
-	 * @param controller the FastLEDController controlling the LEDs
-	 * @param channelIndex the index of the channel
-	 * @param times the number of time the colors should be repeated
-	 */
-	void repeat(FastLEDController* controller, uint8_t channelIndex, uint8_t times);
+namespace CLP {
+/**
+ * Make it possible to use up to 96 LEDs per channel from iCUE by using the LL Fan option. This function transforms the
+ * LL fans layout to a normal strip layout. This function can be combined with scale and repeat function but must be
+ * invoked first.
+ *
+ * @param controller the FastLEDController controlling the LEDs
+ * @param channelIndex the index of the channel
+ */
+void transformLLFanToStrip(FastLEDController* controller, uint8_t channelIndex);
+/**
+ * Scales a channel's length to a given size, the size can be larger or smaller than the default length given to the
+ * FastLEDController::addLEDs function Integer scaling is used, so no interpolation between color values is done and the
+ * animation don't look blurry.
+ *
+ * @param controller the FastLEDController controlling the LEDs
+ * @param channelIndex the index of the channel
+ * @param scaleToSize the final size after scaling
+ */
+void scale(FastLEDController* controller, uint8_t channelIndex, int scaleToSize);
+/**
+ * Repeat a channel's LEDs color to control more LEDs than provided by iCUE.
+ *
+ * @param controller the FastLEDController controlling the LEDs
+ * @param channelIndex the index of the channel
+ * @param times the number of time the colors should be repeated
+ */
+void repeat(FastLEDController* controller, uint8_t channelIndex, uint8_t times);
 
+/**
+ * Define the scaling information for a segment of a channel. A segment is a part of a channel that can be scale
+ * independently of other segments.
+ */
+struct SegmentScaling {
 	/**
-	 * Define the scaling information for a segment of a channel. A segment is a part of a channel that can be scale independently of other segments.
+	 * The length of the segment in iCUE for example 10 for the normal LED strips
 	 */
-	struct SegmentScaling {
-		/**
-		 * The length of the segment in iCUE for example 10 for the normal LED strips
-		 */
-		int segmentLength;
-		/**
-		 * The size to which the segment will be scaled using Integer scaling
-		 */
-		int scaleToSize;
-	};
+	int segmentLength;
 	/**
-	 * Scales a channel's segments to given sizes. This can be used to apply different scaling factors to the different parts of a LED strip.
-	 * Integer scaling is used.
-	 * 
-	 * @param controller the FastLEDController controlling the LEDs
-	 * @param channelIndex the index of the channel you want to scale the segments on
-	 * @param segments the segments defining the size before and after scaling
-	 * @param segmentsCount the number of segments
+	 * The size to which the segment will be scaled using Integer scaling
 	 */
-	void scaleSegments(FastLEDController* controller, uint8_t channelIndex, const SegmentScaling* const segments, int segmentsCount);
+	int scaleToSize;
+};
+/**
+ * Scales a channel's segments to given sizes. This can be used to apply different scaling factors to the different
+ * parts of a LED strip. Integer scaling is used.
+ *
+ * @param controller the FastLEDController controlling the LEDs
+ * @param channelIndex the index of the channel you want to scale the segments on
+ * @param segments the segments defining the size before and after scaling
+ * @param segmentsCount the number of segments
+ */
+void scaleSegments(FastLEDController* controller, uint8_t channelIndex, const SegmentScaling* const segments,
+				   int segmentsCount);
 
-	/**
-	 * Reverse the LEDs of a channel, after this operation, the first LED is the last and the last is the first.
-	 *
-	 * @param controller the FastLEDController controlling the LEDs
-	 * @param channelIndex the index of the channel you want to reverse
-	 */
-	void reverse(FastLEDController* controller, uint8_t channelIndex);
+/**
+ * Reverse the LEDs of a channel, after this operation, the first LED is the last and the last is the first.
+ *
+ * @param controller the FastLEDController controlling the LEDs
+ * @param channelIndex the index of the channel you want to reverse
+ */
+void reverse(FastLEDController* controller, uint8_t channelIndex);
 
-	/**
-	 * Simple gamma correction with gamma value 2. This approximation of the gamma correction is sufficient for most LED strips.
-	 *
-	 * @param controller the FastLEDController controlling the LEDs
-	 * @param channelIndex the index of the channel
-	 */
-	void gammaCorrection(FastLEDController* controller, uint8_t channelIndex);
-}
+/**
+ * Simple gamma correction with gamma value 2. This approximation of the gamma correction is sufficient for most LED
+ * strips.
+ *
+ * @param controller the FastLEDController controlling the LEDs
+ * @param channelIndex the index of the channel
+ */
+void gammaCorrection(FastLEDController* controller, uint8_t channelIndex);
+}  // namespace CLP
diff --git a/src/IFanController.h b/src/IFanController.h
index 7d16d368..e823c959 100644
--- a/src/IFanController.h
+++ b/src/IFanController.h
@@ -16,8 +16,8 @@
 #pragma once
 
 #include "Arduino.h"
-#include "CorsairLightingProtocolResponse.h"
 #include "CorsairLightingProtocolConstants.h"
+#include "CorsairLightingProtocolResponse.h"
 
 /**
  * The interface of a FanController.
@@ -25,7 +25,8 @@
 class IFanController {
 public:
 	/**
-	 * Handle a command and send back a response. This method is called if a new command for the FanController is received.
+	 * Handle a command and send back a response. This method is called if a new command for the FanController is
+	 * received.
 	 *
 	 * @param command the command which must be handled
 	 * @param response the callback used for the response
diff --git a/src/ILEDController.h b/src/ILEDController.h
index 224affe6..fbb74109 100644
--- a/src/ILEDController.h
+++ b/src/ILEDController.h
@@ -16,8 +16,8 @@
 #pragma once
 
 #include "Arduino.h"
-#include "CorsairLightingProtocolResponse.h"
 #include "CorsairLightingProtocolConstants.h"
+#include "CorsairLightingProtocolResponse.h"
 
 /**
  * The interface of a LEDController.
diff --git a/src/ITemperatureController.h b/src/ITemperatureController.h
index f694f798..420266d3 100644
--- a/src/ITemperatureController.h
+++ b/src/ITemperatureController.h
@@ -16,8 +16,8 @@
 #pragma once
 
 #include "Arduino.h"
-#include "CorsairLightingProtocolResponse.h"
 #include "CorsairLightingProtocolConstants.h"
+#include "CorsairLightingProtocolResponse.h"
 
 /**
  * The interface of a TemperatureController.
diff --git a/src/LEDController.cpp b/src/LEDController.cpp
index fcd23bcb..0859cd4f 100644
--- a/src/LEDController.cpp
+++ b/src/LEDController.cpp
@@ -14,177 +14,158 @@
    limitations under the License.
 */
 #include "LEDController.h"
+
 #include "TemperatureController.h"
 
-void LEDController::handleLEDControl(const Command& command, const CorsairLightingProtocolResponse* response)
-{
+void LEDController::handleLEDControl(const Command& command, const CorsairLightingProtocolResponse* response) {
+	lastCommand = millis();
 	auto& data = command.data;
 	if (command.command == WRITE_LED_TRIGGER) {
 		triggerLEDUpdate();
-		if (triggerSave) {
-			triggerSave = false;
-			save();
-		}
-	}
-	else {
+		saveIfNeeded();
+	} else {
 		if (data[0] >= CHANNEL_NUM) {
 			response->sendError();
 			return;
 		}
 		const uint8_t& channel = data[0];
-		switch (command.command)
-		{
-		case READ_LED_STRIP_MASK:
-		{
-			uint8_t ledMask[GROUPS_NUM];
-			for (uint8_t i = 0; i < GROUPS_NUM; i++) {
-				if (i < channels[channel].groupsSet) {
-					ledMask[i] = getLEDStripMask(channel, i);
-				}
-				else {
-					ledMask[i] = 0x00;
+		switch (command.command) {
+			case READ_LED_STRIP_MASK: {
+				uint8_t ledMask[GROUPS_NUM];
+				for (uint8_t i = 0; i < GROUPS_NUM; i++) {
+					if (i < channels[channel].groupsSet) {
+						ledMask[i] = getLEDStripMask(channel, i);
+					} else {
+						ledMask[i] = 0x00;
+					}
 				}
+				response->send(ledMask, sizeof(ledMask));
+				// don't send default response
+				return;
+				break;
 			}
-			response->send(ledMask, sizeof(ledMask));
-			// don't send default response
-			return;
-			break;
-		}
-		case WRITE_LED_RGB_VALUE:
-		{
+			case WRITE_LED_RGB_VALUE: {
 #ifdef DEBUG
-			Serial.println(F("WriteLedRgbValue"));
+				Serial.println(F("WriteLedRgbValue"));
 #endif
-			// TODO
-			response->sendError();
-			return;
-			break;
-		}
-		case WRITE_LED_COLOR_VALUES:
-		{
-			const uint8_t offset = data[1];
-			const size_t inputLength = min((size_t)data[2], sizeof(data) - 4);
-			const uint8_t color = data[3];
-			if (color >= 3) {
+				// TODO
 				response->sendError();
 				return;
+				break;
 			}
-			setLEDColorValues(channel, color, offset, data + 4, inputLength);
-			break;
-		}
-		case WRITE_LED_CLEAR:
-		{
-			clearLEDColorValues(channel);
-			break;
-		}
-		case WRITE_LED_GROUP_SET:
-		{
-			if (channels[channel].groupsSet >= GROUPS_NUM) {
-				response->sendError();
-				return;
+			case WRITE_LED_COLOR_VALUES: {
+				const uint8_t offset = data[1];
+				const size_t inputLength = min((size_t)data[2], sizeof(data) - 4);
+				const uint8_t color = data[3];
+				if (color >= 3) {
+					response->sendError();
+					return;
+				}
+				setLEDColorValues(channel, color, offset, data + 4, inputLength);
+				break;
+			}
+			case WRITE_LED_CLEAR: {
+				clearLEDColorValues(channel);
+				break;
 			}
-			LEDGroup group;
-			group.ledIndex = data[1];
-			group.ledCount = data[2];
-			group.mode = data[3];
-			group.speed = static_cast(data[4]);
-			group.direction = static_cast(data[5]);
-			group.extra = static_cast(data[6]);
-			group.tempGroup = data[7];
-			group.color1.r = data[8];
-			group.color1.g = data[9];
-			group.color1.b = data[10];
-			group.color2.r = data[11];
-			group.color2.g = data[12];
-			group.color2.b = data[13];
-			group.color3.r = data[14];
-			group.color3.g = data[15];
-			group.color3.b = data[16];
-			group.temp1 = CLP::fromBigEndian(data[17], data[18]);
-			group.temp2 = CLP::fromBigEndian(data[19], data[20]);
-			group.temp3 = CLP::fromBigEndian(data[21], data[22]);
+			case WRITE_LED_GROUP_SET: {
+				if (channels[channel].groupsSet >= GROUPS_NUM) {
+					response->sendError();
+					return;
+				}
+				LEDGroup group;
+				group.ledIndex = data[1];
+				group.ledCount = data[2];
+				group.mode = data[3];
+				group.speed = static_cast(data[4]);
+				group.direction = static_cast(data[5]);
+				group.extra = static_cast(data[6]);
+				group.tempGroup = data[7];
+				group.color1.r = data[8];
+				group.color1.g = data[9];
+				group.color1.b = data[10];
+				group.color2.r = data[11];
+				group.color2.g = data[12];
+				group.color2.b = data[13];
+				group.color3.r = data[14];
+				group.color3.g = data[15];
+				group.color3.b = data[16];
+				group.temp1 = CLP::fromBigEndian(data[17], data[18]);
+				group.temp2 = CLP::fromBigEndian(data[19], data[20]);
+				group.temp3 = CLP::fromBigEndian(data[21], data[22]);
+
+				if (!isValidLEDGroup(group)) {
+					response->sendError();
+					return;
+				}
 
-			if (!isValidLEDGroup(group)) {
-				response->sendError();
-				return;
+				triggerSave |= setLEDGroup(channel, channels[channel].groupsSet++, group);
+				break;
+			}
+			case WRITE_LED_EXTERNAL_TEMP: {
+				setLEDExternalTemperature(channel, CLP::fromBigEndian(data[2], data[3]));
+				break;
+			}
+			case WRITE_LED_GROUPS_CLEAR: {
+				triggerSave |= clearLEDGroups(channel);
+				break;
 			}
+			case WRITE_LED_MODE: {
+				const ChannelMode mode = static_cast(data[1]);
+				if (!isValidChannelMode(mode)) {
+#ifdef DEBUG
+					Serial.print(F("unkown LED channel mode: "));
+					Serial.print(data[1], HEX);
+					Serial.println();
+#endif
+					response->sendError();
+					return;
+				}
 
-			triggerSave |= setLEDGroup(channel, channels[channel].groupsSet++, group);
-			break;
-		}
-		case WRITE_LED_EXTERNAL_TEMP:
-		{
-			setLEDExternalTemperature(channel, CLP::fromBigEndian(data[2], data[3]));
-			break;
-		}
-		case WRITE_LED_GROUPS_CLEAR:
-		{
-			triggerSave |= clearLEDGroups(channel);
-			break;
-		}
-		case WRITE_LED_MODE:
-		{
-			const ChannelMode mode = static_cast(data[1]);
-			if (!isValidChannelMode(mode)) {
+				triggerSave |= setLEDMode(channel, mode);
+				break;
+			}
+			case WRITE_LED_BRIGHTNESS: {
+				uint8_t brightness = CLP::convert100To255(data[1]);
+				triggerSave |= setLEDBrightness(channel, brightness);
+				break;
+			}
+			case WRITE_LED_COUNT: {
 #ifdef DEBUG
-				Serial.print(F("unkown LED channel mode: "));
+				Serial.print(F("WRITE_LED_COUNT: "));
 				Serial.print(data[1], HEX);
 				Serial.println();
 #endif
-				response->sendError();
-				return;
+				// TODO
+				channels[channel].ledCount = data[1];
+				break;
 			}
-
-			triggerSave |= setLEDMode(channel, mode);
-			break;
-		}
-		case WRITE_LED_BRIGHTNESS:
-		{
-			uint8_t brightness = CLP::convert100To255(data[1]);
-			triggerSave |= setLEDBrightness(channel, brightness);
-			break;
-		}
-		case WRITE_LED_COUNT:
-		{
+			case WRITE_LED_PORT_TYPE: {
+				const PortType portType = static_cast(data[1]);
+				if (!isValidPortType(portType)) {
+					response->sendError();
+					return;
+				}
+				triggerSave |= setLEDPortType(channel, portType);
+				break;
+			}
+			default: {
 #ifdef DEBUG
-			Serial.print(F("WRITE_LED_COUNT: "));
-			Serial.print(data[1], HEX);
-			Serial.println();
+				Serial.print(F("unkown command: "));
+				Serial.print(command.command, HEX);
+				Serial.println();
 #endif
-			// TODO
-			channels[channel].ledCount = data[1];
-			break;
-		}
-		case WRITE_LED_PORT_TYPE:
-		{
-			const PortType portType = static_cast(data[1]);
-			if (!isValidPortType(portType)) {
 				response->sendError();
 				return;
 			}
-			triggerSave |= setLEDPortType(channel, portType);
-			break;
-		}
-		default:
-		{
-#ifdef DEBUG
-			Serial.print(F("unkown command: "));
-			Serial.print(command.command, HEX);
-			Serial.println();
-#endif
-			response->sendError();
-			return;
-		}
 		}
 	}
 	response->send(nullptr, 0);
 }
 
-bool LEDController::isValidLEDChannel(const LEDChannel& ledChannel)
-{
-	if (isValidChannelMode(ledChannel.mode)
-		&& isValidPortType(ledChannel.ledPortType)
-		&& ledChannel.groupsSet < GROUPS_NUM) {
+bool LEDController::isValidLEDChannel(const LEDChannel& ledChannel) {
+	if (isValidChannelMode(ledChannel.mode) && isValidPortType(ledChannel.ledPortType) &&
+		ledChannel.groupsSet < GROUPS_NUM) {
 		for (uint8_t i = 0; i < ledChannel.groupsSet; i++) {
 			if (!isValidLEDGroup(ledChannel.groups[i])) {
 				return false;
@@ -195,36 +176,26 @@ bool LEDController::isValidLEDChannel(const LEDChannel& ledChannel)
 	return false;
 }
 
-bool LEDController::isValidLEDGroup(const LEDGroup& ledGroup)
-{
-	return ledGroup.mode <= GROUP_MODE_Rainbow
-		&& isValidGroupSpeed(ledGroup.speed)
-		&& isValidGroupDirection(ledGroup.direction)
-		&& isValidGroupExtra(ledGroup.extra)
-		&& (ledGroup.tempGroup == GROUP_TEMP_GROUP_EXTERNAL
-			|| ledGroup.tempGroup < TEMPERATURE_NUM);
+bool LEDController::isValidLEDGroup(const LEDGroup& ledGroup) {
+	return ledGroup.mode <= GROUP_MODE_Rainbow && isValidGroupSpeed(ledGroup.speed) &&
+		   isValidGroupDirection(ledGroup.direction) && isValidGroupExtra(ledGroup.extra) &&
+		   (ledGroup.tempGroup == GROUP_TEMP_GROUP_EXTERNAL || ledGroup.tempGroup < TEMPERATURE_NUM);
 }
 
-const LEDChannel& LEDController::getChannel(uint8_t channelIndex)
-{
-	return channels[channelIndex];
-}
+const LEDChannel& LEDController::getChannel(uint8_t channelIndex) { return channels[channelIndex]; }
 
-void LEDController::reset()
-{
+void LEDController::reset() {
 	for (auto& channel : channels) {
 		channel = LEDChannel();
 	}
 	save();
 }
 
-uint8_t LEDController::getLEDStripMask(uint8_t channel, uint8_t groupIndex)
-{
+uint8_t LEDController::getLEDStripMask(uint8_t channel, uint8_t groupIndex) {
 	return channels[channel].groups[groupIndex].ledCount;
 }
 
-bool LEDController::setLEDGroup(uint8_t channel, uint8_t groupIndex, LEDGroup& group)
-{
+bool LEDController::setLEDGroup(uint8_t channel, uint8_t groupIndex, LEDGroup& group) {
 	channels[channel].groups[groupIndex] = group;
 	return true;
 }
@@ -237,8 +208,7 @@ bool LEDController::clearLEDGroups(uint8_t channel) {
 	return false;
 }
 
-bool LEDController::setLEDMode(uint8_t channel, ChannelMode mode)
-{
+bool LEDController::setLEDMode(uint8_t channel, ChannelMode mode) {
 	if (channels[channel].mode != mode) {
 		channels[channel].mode = mode;
 		return true;
@@ -246,8 +216,7 @@ bool LEDController::setLEDMode(uint8_t channel, ChannelMode mode)
 	return false;
 }
 
-bool LEDController::setLEDBrightness(uint8_t channel, uint8_t brightness)
-{
+bool LEDController::setLEDBrightness(uint8_t channel, uint8_t brightness) {
 	if (channels[channel].brightness != brightness) {
 		channels[channel].brightness = brightness;
 		return true;
@@ -255,11 +224,17 @@ bool LEDController::setLEDBrightness(uint8_t channel, uint8_t brightness)
 	return false;
 }
 
-bool LEDController::setLEDPortType(uint8_t channel, PortType ledPortType)
-{
+bool LEDController::setLEDPortType(uint8_t channel, PortType ledPortType) {
 	if (channels[channel].ledPortType != ledPortType) {
 		channels[channel].ledPortType = ledPortType;
 		return true;
 	}
 	return false;
-}
\ No newline at end of file
+}
+
+bool LEDController::saveIfNeeded() {
+	if (triggerSave) {
+		triggerSave = false;
+		save();
+	}
+}
diff --git a/src/LEDController.h b/src/LEDController.h
index 170692bf..02cdfcaf 100644
--- a/src/LEDController.h
+++ b/src/LEDController.h
@@ -20,35 +20,39 @@
  * Defines types and constants of the LED part of the protocol
  */
 
-#include "Arduino.h"
 #include 
-#include "ILEDController.h"
+
+#include "Arduino.h"
 #include "CLPUtils.h"
+#include "ILEDController.h"
 
 #define CHANNEL_NUM 2
 #define GROUPS_NUM 6
 
- /**
-  * The mode of an LEDChannel. The mode describes how the LED lighting is done.
-  *
-  * @see LEDController#setLEDMode()
-  */
+/**
+ * The mode of an LEDChannel. The mode describes how the LED lighting is done.
+ *
+ * @see LEDController#setLEDMode()
+ */
 enum class ChannelMode : byte {
 	/** No lighting is active for the channel. The LEDs will not be updated. */
 	Disabled = 0x00,
-	/** The Hardware Playback uses lighting effects defined by LEDGroups and LEDController renders the effects themself. This mode works even without an USB connection.  */
+	/** The Hardware Playback uses lighting effects defined by LEDGroups and LEDController renders the effects themself.
+	   This mode works even without an USB connection.  */
 	HardwarePlayback = 0x01,
-	/** All lighting effects are rendered by iCUE and only the RGB values are transferred via USB to the device. This requires an USB connection. */
+	/** All lighting effects are rendered by iCUE and only the RGB values are transferred via USB to the device. This
+	   requires an USB connection. */
 	SoftwarePlayback = 0x02
 };
 
 bool inline isValidChannelMode(const ChannelMode channelMode) {
-	return channelMode == ChannelMode::Disabled || channelMode == ChannelMode::HardwarePlayback || channelMode == ChannelMode::SoftwarePlayback;
+	return channelMode == ChannelMode::Disabled || channelMode == ChannelMode::HardwarePlayback ||
+		   channelMode == ChannelMode::SoftwarePlayback;
 }
 
 /**
- * The type of LED Chipset connected to a channel. These are the types implicitly defined by iCUE when doing the lighting setup in iCUE.
- * These type is ignored by the LEDController.
+ * The type of LED Chipset connected to a channel. These are the types implicitly defined by iCUE when doing the
+ * lighting setup in iCUE. These type is ignored by the LEDController.
  */
 enum class PortType : byte {
 	/** WS2812B used by all new Corsair devices */
@@ -61,7 +65,7 @@ bool inline isValidPortType(const PortType portType) {
 	return portType == PortType::WS2812B || portType == PortType::UCS1903;
 }
 
-//LED group mode
+// LED group mode
 #define GROUP_MODE_Rainbow_Wave 0x00
 #define GROUP_MODE_Color_Shift 0x01
 #define GROUP_MODE_Color_Pulse 0x02
@@ -77,11 +81,7 @@ bool inline isValidPortType(const PortType portType) {
 /**
  * The animation speed of a LEDGroup.
  */
-enum class GroupSpeed : byte {
-	High = 0x00,
-	Medium = 0x01,
-	Low = 0x02
-};
+enum class GroupSpeed : byte { High = 0x00, Medium = 0x01, Low = 0x02 };
 
 bool inline isValidGroupSpeed(const GroupSpeed groupSpeed) {
 	return groupSpeed == GroupSpeed::High || groupSpeed == GroupSpeed::Medium || groupSpeed == GroupSpeed::Low;
@@ -90,10 +90,7 @@ bool inline isValidGroupSpeed(const GroupSpeed groupSpeed) {
 /**
  * The animation direction of a LEDGroup.
  */
-enum class GroupDirection : byte {
-	Backward = 0x00,
-	Forward = 0x01
-};
+enum class GroupDirection : byte { Backward = 0x00, Forward = 0x01 };
 
 bool inline isValidGroupDirection(const GroupDirection groupDirection) {
 	return groupDirection == GroupDirection::Backward || groupDirection == GroupDirection::Forward;
@@ -102,10 +99,7 @@ bool inline isValidGroupDirection(const GroupDirection groupDirection) {
 /**
  * Extra information for animations of a LEDGroup.
  */
-enum class GroupExtra : byte {
-	Alternating = 0x00,
-	Random = 0x01
-};
+enum class GroupExtra : byte { Alternating = 0x00, Random = 0x01 };
 
 bool inline isValidGroupExtra(const GroupExtra groupExtra) {
 	return groupExtra == GroupExtra::Alternating || groupExtra == GroupExtra::Random;
@@ -114,7 +108,8 @@ bool inline isValidGroupExtra(const GroupExtra groupExtra) {
 #define GROUP_TEMP_GROUP_EXTERNAL 255
 
 /**
- * A LEDGroup is a contiguous range of LEDs on a strip. The LEDGroup defines the size, position and lighting effects of the LED range.
+ * A LEDGroup is a contiguous range of LEDs on a strip. The LEDGroup defines the size, position and lighting effects of
+ * the LED range.
  */
 struct LEDGroup {
 	/**
@@ -160,21 +155,23 @@ struct LEDChannel {
 };
 
 /**
- * The abstract implemenation of an LEDController. This implementation handles the parsing and interpretation of incoming commands.
- * It also defines the data model to store the all required data from the commands.
+ * The abstract implemenation of an LEDController. This implementation handles the parsing and interpretation of
+ * incoming commands. It also defines the data model to store the all required data from the commands.
  */
 class LEDController : public ILEDController {
 public:
 	virtual void handleLEDControl(const Command& command, const CorsairLightingProtocolResponse* response) override;
 	/**
-	 * Validates a LEDChannel by checking all constrains on the values. This function should be used after non type-safe operations on a LEDChannel.
+	 * Validates a LEDChannel by checking all constrains on the values. This function should be used after non type-safe
+	 * operations on a LEDChannel.
 	 *
 	 * @param ledChannel the LEDChannel to validate
 	 * @return true if the LEDChannel is valid, false otherwise
 	 */
 	virtual bool isValidLEDChannel(const LEDChannel& ledChannel);
 	/**
-	 * Validates a LEDGroup by checking all constrains on the values. This function should be used after non type-safe operations on a LEDGroup.
+	 * Validates a LEDGroup by checking all constrains on the values. This function should be used after non type-safe
+	 * operations on a LEDGroup.
 	 *
 	 * @param ledGroup the LEDGroup to validate
 	 * @return true if the LEDGroup is valid, false otherwise
@@ -191,12 +188,17 @@ class LEDController : public ILEDController {
 	 * Reset all persistent data to default values of the LEDController.
 	 */
 	virtual void reset();
+
 protected:
 	LEDChannel channels[CHANNEL_NUM];
 	/**
 	 * Indicates that the configuration of the channels has been changed and should be saved.
 	 */
 	bool triggerSave = false;
+	/**
+	 * Stores the time at which the last command was received by the LEDController.
+	 */
+	long lastCommand = 0;
 
 	/**
 	 * Trigger update of the LEDs
@@ -218,7 +220,8 @@ class LEDController : public ILEDController {
 	 */
 	virtual void setLEDExternalTemperature(uint8_t channel, uint16_t temp) = 0;
 	virtual bool setLEDGroup(uint8_t channel, uint8_t groupIndex, LEDGroup& group);
-	virtual void setLEDColorValues(uint8_t channel, uint8_t color, uint8_t offset, const uint8_t* values, size_t len) = 0;
+	virtual void setLEDColorValues(uint8_t channel, uint8_t color, uint8_t offset, const uint8_t* values,
+								   size_t len) = 0;
 	/**
 	 * Set the Channel mode.
 	 *
@@ -247,4 +250,8 @@ class LEDController : public ILEDController {
 	virtual bool clearLEDGroups(uint8_t channel);
 	virtual bool save() = 0;
 	virtual bool load() = 0;
+	/**
+	 * Save if triggerSave is true and then reset triggerSave.
+	 */
+	bool saveIfNeeded();
 };
diff --git a/src/RawHID.cpp b/src/RawHID.cpp
index 8e60668a..efe991df 100644
--- a/src/RawHID.cpp
+++ b/src/RawHID.cpp
@@ -28,7 +28,7 @@ THE SOFTWARE.
 #ifndef HID_ENDPOINT_INTERVAL_RAWHID
 #define HID_ENDPOINT_INTERVAL_RAWHID 0x01
 #endif
-
+/* clang-format off */
 static const uint8_t  _hidReportDescriptorRawHID[] PROGMEM = {
 	/*    RAW HID */
     0x06, lowByte(RAWHID_USAGE_PAGE), highByte(RAWHID_USAGE_PAGE),      /* 30 */
@@ -48,46 +48,54 @@ static const uint8_t  _hidReportDescriptorRawHID[] PROGMEM = {
     0x91, 0x02,                  /* Output (array) */
     0xC0                         /* end collection */
 };
-
+/* clang-format on */
 #ifndef SERIAL_NUMBER
 #define SERIAL_NUMBER "FB66DF55421900F5"
 #endif
 
 const char defaultSerialNumber[] PROGMEM = SERIAL_NUMBER;
 
-RawHID_::RawHID_(void) : PluggableUSBModule(ENDPOINT_COUNT, 1, epType), protocol(HID_REPORT_PROTOCOL), idle(1), dataLength(0), dataAvailable(0), data(nullptr), serialNumber(defaultSerialNumber), featureReport(nullptr), featureLength(0)
-{
+CLP::RawHID_::RawHID_(void)
+	: PluggableUSBModule(ENDPOINT_COUNT, 1, epType),
+	  protocol(HID_REPORT_PROTOCOL),
+	  idle(1),
+	  dataLength(0),
+	  dataAvailable(0),
+	  data(nullptr),
+	  serialNumber(defaultSerialNumber),
+	  featureReport(nullptr),
+	  featureLength(0) {
 	setTimeout(10);
 	epType[0] = EP_TYPE_INTERRUPT_IN;
 	PluggableUSB().plug(this);
 }
 
-void RawHID_::setSerialNumber(const char* argSerialNumber)
-{
-	serialNumber = argSerialNumber;
-}
+void CLP::RawHID_::setSerialNumber(const char* argSerialNumber) { serialNumber = argSerialNumber; }
 
-int RawHID_::getInterface(uint8_t* interfaceCount)
-{
+int CLP::RawHID_::getInterface(uint8_t* interfaceCount) {
 	// Maybe as optional device FastRawHID with different USAGE PAGE
-	*interfaceCount += 1; // uses 1
-	HIDDescriptor hidInterface = {
-		D_INTERFACE(pluggedInterface, ENDPOINT_COUNT, USB_DEVICE_CLASS_HUMAN_INTERFACE, HID_SUBCLASS_NONE, HID_PROTOCOL_NONE),
-		D_HIDREPORT(sizeof(_hidReportDescriptorRawHID)),
-		D_ENDPOINT(USB_ENDPOINT_IN(HID_ENDPOINT_IN), USB_ENDPOINT_TYPE_INTERRUPT, RAWHID_TX_SIZE, HID_ENDPOINT_INTERVAL_RAWHID)
-	};
+	*interfaceCount += 1;  // uses 1
+	HIDDescriptor hidInterface = {D_INTERFACE(pluggedInterface, ENDPOINT_COUNT, USB_DEVICE_CLASS_HUMAN_INTERFACE,
+											  HID_SUBCLASS_NONE, HID_PROTOCOL_NONE),
+								  D_HIDREPORT(sizeof(_hidReportDescriptorRawHID)),
+								  D_ENDPOINT(USB_ENDPOINT_IN(pluggedEndpoint), USB_ENDPOINT_TYPE_INTERRUPT,
+											 RAWHID_TX_SIZE, HID_ENDPOINT_INTERVAL_RAWHID)};
 	return USB_SendControl(0, &hidInterface, sizeof(hidInterface));
-	
 }
 
-int RawHID_::getDescriptor(USBSetup& setup)
-{
+int CLP::RawHID_::getDescriptor(USBSetup& setup) {
 	// Check if this is a HID Class Descriptor request
-	if (setup.bmRequestType != REQUEST_DEVICETOHOST_STANDARD_INTERFACE) { return 0; }
-	if (setup.wValueH != HID_REPORT_DESCRIPTOR_TYPE) { return 0; }
+	if (setup.bmRequestType != REQUEST_DEVICETOHOST_STANDARD_INTERFACE) {
+		return 0;
+	}
+	if (setup.wValueH != HID_REPORT_DESCRIPTOR_TYPE) {
+		return 0;
+	}
 
 	// In a HID Class Descriptor wIndex cointains the interface number
-	if (setup.wIndex != pluggedInterface) { return 0; }
+	if (setup.wIndex != pluggedInterface) {
+		return 0;
+	}
 
 	// Reset the protocol on reenumeration. Normally the host should not assume the state of the protocol
 	// due to the USB specs, but Windows and Linux just assumes its in report mode.
@@ -96,8 +104,7 @@ int RawHID_::getDescriptor(USBSetup& setup)
 	return USB_SendControl(TRANSFER_PGM, _hidReportDescriptorRawHID, sizeof(_hidReportDescriptorRawHID));
 }
 
-bool RawHID_::setup(USBSetup& setup)
-{
+bool CLP::RawHID_::setup(USBSetup& setup) {
 	if (pluggedInterface != setup.wIndex) {
 		return false;
 	}
@@ -105,8 +112,7 @@ bool RawHID_::setup(USBSetup& setup)
 	uint8_t request = setup.bRequest;
 	uint8_t requestType = setup.bmRequestType;
 
-	if (requestType == REQUEST_DEVICETOHOST_CLASS_INTERFACE)
-	{
+	if (requestType == REQUEST_DEVICETOHOST_CLASS_INTERFACE) {
 		if (request == HID_GET_REPORT) {
 			// TODO: HID_GetReport();
 			return true;
@@ -117,8 +123,7 @@ bool RawHID_::setup(USBSetup& setup)
 		}
 	}
 
-	if (requestType == REQUEST_HOSTTODEVICE_CLASS_INTERFACE)
-	{
+	if (requestType == REQUEST_HOSTTODEVICE_CLASS_INTERFACE) {
 		if (request == HID_SET_PROTOCOL) {
 			protocol = setup.wValueL;
 			return true;
@@ -127,13 +132,12 @@ bool RawHID_::setup(USBSetup& setup)
 			idle = setup.wValueL;
 			return true;
 		}
-		if (request == HID_SET_REPORT)
-		{
+		if (request == HID_SET_REPORT) {
 			// Check if data has the correct length afterwards
 			int length = setup.wLength;
 
 			// Feature (set feature report)
-			if(setup.wValueH == HID_REPORT_TYPE_FEATURE){
+			if (setup.wValueH == HID_REPORT_TYPE_FEATURE) {
 				// No need to check for negative featureLength values,
 				// except the host tries to send more then 32k bytes.
 				// We dont have that much ram anyways.
@@ -147,8 +151,8 @@ bool RawHID_::setup(USBSetup& setup)
 			}
 
 			// Output (set out report)
-			else if(setup.wValueH == HID_REPORT_TYPE_OUTPUT){
-				if(!dataAvailable && length <= dataLength){
+			else if (setup.wValueH == HID_REPORT_TYPE_OUTPUT) {
+				if (!dataAvailable && length <= dataLength) {
 					// Write data to fit to the end (not the beginning) of the array
 					USB_RecvControl(data + dataLength - length, length);
 					dataAvailable = length;
@@ -161,12 +165,12 @@ bool RawHID_::setup(USBSetup& setup)
 	return false;
 }
 
-uint8_t RawHID_::getShortName(char *name)
-{
+uint8_t CLP::RawHID_::getShortName(char* name) {
 	name[0] = '\0';
 	strncat_P(name, serialNumber, ISERIAL_MAX_LEN - 1);
 	return strlen(name);
 }
-
+namespace CLP {
 RawHID_ RawHID;
+}
 #endif
diff --git a/src/RawHID.h b/src/RawHID.h
index 3368bce7..0755a3d2 100644
--- a/src/RawHID.h
+++ b/src/RawHID.h
@@ -37,28 +37,24 @@ THE SOFTWARE.
 // RawHID might never work with multireports, because of OS problems
 // therefore we have to make it a single report with no idea. No other HID device will be supported then.
 #undef RAWHID_USAGE_PAGE
-#define RAWHID_USAGE_PAGE	0xFFC0 // recommended: 0xFF00 to 0xFFFF
+#define RAWHID_USAGE_PAGE 0xFFC0  // recommended: 0xFF00 to 0xFFFF
 
 #undef RAWHID_USAGE
-#define RAWHID_USAGE		0x0C00 // recommended: 0x0100 to 0xFFFF
+#define RAWHID_USAGE 0x0C00  // recommended: 0x0100 to 0xFFFF
 
 #define RAWHID_TX_SIZE 64
 #define RAWHID_RX_SIZE 64
 
 #endif
 
-#if defined(ARDUINO_ARCH_AVR) && defined(USBCON) // Arduino Core
+#if defined(ARDUINO_ARCH_AVR) && defined(USBCON)  // Arduino Core
 
 #define EPTYPE_DESCRIPTOR_SIZE uint8_t
 // HID Functional Characteristics HID1.11 Page 10 4.4 Interfaces
 // Interrupt Out Endpoint is optional, contoll endpoint is used by default
 #define ENDPOINT_COUNT 1
-
-#define HID_ENDPOINT_IN	pluggedEndpoint
-#define HID_TX HID_ENDPOINT_IN
-
-class RawHID_ : public PluggableUSBModule, public Stream
-{
+namespace CLP {
+class RawHID_ : public PluggableUSBModule, public Stream {
 public:
 	RawHID_(void);
 	/**
@@ -68,101 +64,91 @@ class RawHID_ : public PluggableUSBModule, public Stream
 	 */
 	void setSerialNumber(const char* serialNumber);
 
-    void setFeatureReport(void* report, int length){
-        if(length > 0){
-            featureReport = (uint8_t*)report;
-            featureLength = length;
-
-            // Disable feature report by default
-            disableFeatureReport();
-        }
-    }
-
-    int availableFeatureReport(void){
-        if(featureLength < 0){
-            return featureLength & ~0x8000;
-        }
-        return 0;
-    }
-
-    void enableFeatureReport(void){
-        featureLength &= ~0x8000;
-    }
-
-    void disableFeatureReport(void){
-        featureLength |= 0x8000;
-    }
-
-	void begin(void* report, int length){
-        if(length > 0){
-            data = (uint8_t*)report;
-            dataLength = length;
-            dataAvailable = 0;
-        }
+	void setFeatureReport(void* report, int length) {
+		if (length > 0) {
+			featureReport = (uint8_t*)report;
+			featureLength = length;
+
+			// Disable feature report by default
+			disableFeatureReport();
+		}
 	}
 
-	void end(void){
-		disable();
-		dataLength = 0;
+	int availableFeatureReport(void) {
+		if (featureLength < 0) {
+			return featureLength & ~0x8000;
+		}
+		return 0;
 	}
 
-	void enable(void){
-		dataAvailable = 0;
+	void enableFeatureReport(void) { featureLength &= ~0x8000; }
+
+	void disableFeatureReport(void) { featureLength |= 0x8000; }
+
+	void begin(void* report, int length) {
+		if (length > 0) {
+			data = (uint8_t*)report;
+			dataLength = length;
+			dataAvailable = 0;
+		}
 	}
 
-	void disable(void){
-		dataAvailable = -1;
+	void end(void) {
+		disable();
+		dataLength = 0;
 	}
 
-	virtual int available(void){
-		if(dataAvailable < 0){
+	void enable(void) { dataAvailable = 0; }
+
+	void disable(void) { dataAvailable = -1; }
+
+	virtual int available(void) {
+		if (dataAvailable < 0) {
 			return 0;
 		}
 		return dataAvailable;
 	}
 
-	virtual int read(){
+	virtual int read() {
 		// Check if we have data available
-		if(dataAvailable > 0)
-		{
+		if (dataAvailable > 0) {
 			// Get next data byte (from the start to the end)
 			return data[dataLength - dataAvailable--];
 		}
 		return -1;
 	}
 
-	virtual int peek(){
+	virtual int peek() {
 		// Check if we have data available
-		if(dataAvailable > 0){
+		if (dataAvailable > 0) {
 			return data[dataLength - dataAvailable];
 		}
 		return -1;
 	}
 
-	virtual void flush(void){
+	virtual void flush(void) {
 		// Writing will always flush by the USB driver
 	}
 
-	// Wrapper for a single byte
-	//using Print::write;
-	virtual size_t write(uint8_t b){
-		return write(&b, 1);
-	}
+	/**
+	 * Wrapper for a single byte
+	 */
+	virtual size_t write(uint8_t b) { return write(&b, 1); }
 
-	virtual size_t write(const uint8_t *buffer, size_t size){
-		return USB_Send(HID_TX | TRANSFER_RELEASE, buffer, size);
+	virtual size_t write(const uint8_t* buffer, size_t size) {
+		return USB_Send(pluggedEndpoint | TRANSFER_RELEASE, buffer, size);
 	}
 
 protected:
-    // Implementation of the PUSBListNode
-    int getInterface(uint8_t* interfaceCount) override;
-    int getDescriptor(USBSetup& setup) override;
-    bool setup(USBSetup& setup) override;
+	// Implementation of the PUSBListNode
+	int getInterface(uint8_t* interfaceCount) override;
+	int getDescriptor(USBSetup& setup) override;
+	bool setup(USBSetup& setup) override;
 	uint8_t getShortName(char* name) override;
 
-    EPTYPE_DESCRIPTOR_SIZE epType[ENDPOINT_COUNT];
-    uint8_t protocol;
-    uint8_t idle;
+	EPTYPE_DESCRIPTOR_SIZE epType[ENDPOINT_COUNT];
+	uint8_t protocol;
+	uint8_t idle;
 
 	// Buffer pointers to hold the received data
 	int dataLength;
@@ -174,4 +160,5 @@ class RawHID_ : public PluggableUSBModule, public Stream
 	int featureLength;
 };
 extern RawHID_ RawHID;
+}  // namespace CLP
 #endif
diff --git a/src/TemperatureController.cpp b/src/TemperatureController.cpp
index e32d9bb6..ffc84760 100644
--- a/src/TemperatureController.cpp
+++ b/src/TemperatureController.cpp
@@ -14,72 +14,63 @@
    limitations under the License.
 */
 #include "TemperatureController.h"
+
 #include "CLPUtils.h"
 
-void TemperatureController::handleTemperatureControl(const Command& command, const CorsairLightingProtocolResponse* response)
-{
-	switch (command.command)
-	{
-	case READ_TEMPERATURE_MASK:
-	{
-		uint8_t mask[TEMPERATURE_NUM];
-		for (uint8_t i = 0; i < TEMPERATURE_NUM; i++) {
-			mask[i] = isTemperatureSensorConnected(i) ? TEMPERATURE_MASK_CONNECTED : TEMPERATURE_MASK_NOT_CONNECTED;
-		}
-		response->send(mask, sizeof(mask));
-		break;
-	}
-	case READ_TEMPERATURE_VALUE:
-	{
-		const uint8_t& tempSensor = command.data[0];
-		if (tempSensor >= TEMPERATURE_NUM) {
-			response->sendError();
-			return;
-		}
-		uint16_t temp = getTemperatureValue(tempSensor);
-		uint8_t tempData[] = { toBigEndian(temp) };
-		response->send(tempData, sizeof(tempData));
-		break;
-	}
-	case READ_VOLTAGE_VALUE:
-	{
-		const uint8_t& rail = command.data[0];
-		uint16_t voltage;
-		switch (rail)
-		{
-		case VOLTAGE_RAIL_12V:
-		{
-			voltage = getVoltageRail12V();
+void TemperatureController::handleTemperatureControl(const Command& command,
+													 const CorsairLightingProtocolResponse* response) {
+	switch (command.command) {
+		case READ_TEMPERATURE_MASK: {
+			uint8_t mask[TEMPERATURE_NUM];
+			for (uint8_t i = 0; i < TEMPERATURE_NUM; i++) {
+				mask[i] = isTemperatureSensorConnected(i) ? TEMPERATURE_MASK_CONNECTED : TEMPERATURE_MASK_NOT_CONNECTED;
+			}
+			response->send(mask, sizeof(mask));
 			break;
 		}
-		case VOLTAGE_RAIL_5V:
-		{
-			voltage = getVoltageRail5V();
+		case READ_TEMPERATURE_VALUE: {
+			const uint8_t& tempSensor = command.data[0];
+			if (tempSensor >= TEMPERATURE_NUM) {
+				response->sendError();
+				return;
+			}
+			uint16_t temp = getTemperatureValue(tempSensor);
+			uint8_t tempData[] = {toBigEndian(temp)};
+			response->send(tempData, sizeof(tempData));
 			break;
 		}
-		case VOLTAGE_RAIL_3V3:
-		{
-			voltage = getVoltageRail3V3();
+		case READ_VOLTAGE_VALUE: {
+			const uint8_t& rail = command.data[0];
+			uint16_t voltage;
+			switch (rail) {
+				case VOLTAGE_RAIL_12V: {
+					voltage = getVoltageRail12V();
+					break;
+				}
+				case VOLTAGE_RAIL_5V: {
+					voltage = getVoltageRail5V();
+					break;
+				}
+				case VOLTAGE_RAIL_3V3: {
+					voltage = getVoltageRail3V3();
+					break;
+				}
+				default: {
+					response->sendError();
+					return;
+				}
+			}
+
+			uint8_t voltageData[] = {toBigEndian(voltage)};
+			response->send(voltageData, sizeof(voltageData));
 			break;
 		}
 		default:
-		{
 			response->sendError();
-			return;
-		}
-		}
-
-		uint8_t voltageData[] = { toBigEndian(voltage) };
-		response->send(voltageData, sizeof(voltageData));
-		break;
-	}
-	default:
-		response->sendError();
 	}
 }
 
-uint16_t TemperatureController::getTemperature(uint8_t temperatureSensor)
-{
+uint16_t TemperatureController::getTemperature(uint8_t temperatureSensor) {
 	if (temperatureSensor >= TEMPERATURE_NUM) {
 		return 0;
 	}
diff --git a/src/TemperatureController.h b/src/TemperatureController.h
index 21963aca..a362a13d 100644
--- a/src/TemperatureController.h
+++ b/src/TemperatureController.h
@@ -20,7 +20,6 @@
  */
 
 #include "Arduino.h"
-
 #include "ITemperatureController.h"
 
 #define TEMPERATURE_NUM 4
@@ -32,12 +31,14 @@
 #define VOLTAGE_RAIL_5V 1
 #define VOLTAGE_RAIL_3V3 2
 
- /**
-  * The abstract implementation of the ITemperatureController. This implementation handles the commands parsing and processing. 
-  */
+/**
+ * The abstract implementation of the ITemperatureController. This implementation handles the commands parsing and
+ * processing.
+ */
 class TemperatureController : public ITemperatureController {
 public:
-	virtual void handleTemperatureControl(const Command& command, const CorsairLightingProtocolResponse* response) override;
+	virtual void handleTemperatureControl(const Command& command,
+										  const CorsairLightingProtocolResponse* response) override;
 	/**
 	 * Get the temperature of a sensor.
 	 *
@@ -45,6 +46,7 @@ class TemperatureController : public ITemperatureController {
 	 * @return the temperature in hundredths of a degree Celsius.
 	 */
 	virtual uint16_t getTemperature(uint8_t temperatureSensor);
+
 protected:
 	/**
 	 * Get the temperature of a sensor.