Merge branch '0_15' into blending-styles
This commit is contained in:
		| @@ -7,6 +7,7 @@ This Usermod is designed to read a `BME280` or `BMP280` sensor and output the fo | ||||
| - Dew Point (`BME280` only) | ||||
|  | ||||
| Configuration is performed via the Usermod menu.  There are no parameters to set in code!  The following settings can be configured in the Usermod Menu: | ||||
| - The i2c address in decimal. Set it to either 118 (0x76, the default) or 119 (0x77). | ||||
| - Temperature Decimals (number of decimal places to output) | ||||
| - Humidity Decimals | ||||
| - Pressure Decimals | ||||
|   | ||||
| @@ -24,6 +24,7 @@ private: | ||||
|   uint8_t  PressureDecimals = 0;    // Number of decimal places in published pressure values | ||||
|   uint16_t TemperatureInterval = 5; // Interval to measure temperature (and humidity, dew point if available) in seconds | ||||
|   uint16_t PressureInterval = 300;  // Interval to measure pressure in seconds | ||||
|   BME280I2C::I2CAddr I2CAddress = BME280I2C::I2CAddr_0x76;  // i2c address, defaults to 0x76 | ||||
|   bool PublishAlways = false;             // Publish values even when they have not changed | ||||
|   bool UseCelsius = true;                 // Use Celsius for Reporting | ||||
|   bool HomeAssistantDiscovery = false;    // Publish Home Assistant Device Information | ||||
| @@ -35,20 +36,7 @@ private: | ||||
|   #endif | ||||
|   bool initDone = false; | ||||
|  | ||||
|   // BME280 sensor settings | ||||
|   BME280I2C::Settings settings{ | ||||
|       BME280::OSR_X16, // Temperature oversampling x16 | ||||
|       BME280::OSR_X16, // Humidity oversampling x16 | ||||
|       BME280::OSR_X16, // Pressure oversampling x16 | ||||
|       // Defaults | ||||
|       BME280::Mode_Forced, | ||||
|       BME280::StandbyTime_1000ms, | ||||
|       BME280::Filter_Off, | ||||
|       BME280::SpiEnable_False, | ||||
|       BME280I2C::I2CAddr_0x76 // I2C address. I2C specific. Default 0x76 | ||||
|   }; | ||||
|  | ||||
|   BME280I2C bme{settings}; | ||||
|   BME280I2C bme; | ||||
|  | ||||
|   uint8_t sensorType; | ||||
|  | ||||
| @@ -181,34 +169,52 @@ private: | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     void initializeBmeComms() | ||||
|     { | ||||
|       BME280I2C::Settings settings{ | ||||
|             BME280::OSR_X16,    // Temperature oversampling x16 | ||||
|             BME280::OSR_X16,    // Humidity oversampling x16 | ||||
|             BME280::OSR_X16,    // Pressure oversampling x16 | ||||
|             BME280::Mode_Forced, | ||||
|             BME280::StandbyTime_1000ms, | ||||
|             BME280::Filter_Off, | ||||
|             BME280::SpiEnable_False, | ||||
|             I2CAddress | ||||
|         }; | ||||
|  | ||||
|       bme.setSettings(settings); | ||||
|        | ||||
|       if (!bme.begin()) | ||||
|       { | ||||
|         sensorType = 0; | ||||
|         DEBUG_PRINTLN(F("Could not find BME280 I2C sensor!")); | ||||
|       } | ||||
|       else | ||||
|       { | ||||
|         switch (bme.chipModel()) | ||||
|         { | ||||
|         case BME280::ChipModel_BME280: | ||||
|           sensorType = 1; | ||||
|           DEBUG_PRINTLN(F("Found BME280 sensor! Success.")); | ||||
|           break; | ||||
|         case BME280::ChipModel_BMP280: | ||||
|           sensorType = 2; | ||||
|           DEBUG_PRINTLN(F("Found BMP280 sensor! No Humidity available.")); | ||||
|           break; | ||||
|         default: | ||||
|           sensorType = 0; | ||||
|           DEBUG_PRINTLN(F("Found UNKNOWN sensor! Error!")); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
| public: | ||||
|   void setup() | ||||
|   { | ||||
|     if (i2c_scl<0 || i2c_sda<0) { enabled = false; sensorType = 0; return; } | ||||
|      | ||||
|     if (!bme.begin()) | ||||
|     { | ||||
|       sensorType = 0; | ||||
|       DEBUG_PRINTLN(F("Could not find BME280 I2C sensor!")); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|       switch (bme.chipModel()) | ||||
|       { | ||||
|       case BME280::ChipModel_BME280: | ||||
|         sensorType = 1; | ||||
|         DEBUG_PRINTLN(F("Found BME280 sensor! Success.")); | ||||
|         break; | ||||
|       case BME280::ChipModel_BMP280: | ||||
|         sensorType = 2; | ||||
|         DEBUG_PRINTLN(F("Found BMP280 sensor! No Humidity available.")); | ||||
|         break; | ||||
|       default: | ||||
|         sensorType = 0; | ||||
|         DEBUG_PRINTLN(F("Found UNKNOWN sensor! Error!")); | ||||
|       } | ||||
|     } | ||||
|     initDone=true; | ||||
|     initializeBmeComms(); | ||||
|     initDone = true; | ||||
|   } | ||||
|  | ||||
|   void loop() | ||||
| @@ -365,7 +371,6 @@ public: | ||||
|     } | ||||
|     else if (sensorType==2) //BMP280 | ||||
|     { | ||||
|        | ||||
|       JsonArray temperature_json = user.createNestedArray(F("Temperature")); | ||||
|       JsonArray pressure_json = user.createNestedArray(F("Pressure")); | ||||
|       temperature_json.add(roundf(sensorTemperature * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals)); | ||||
| @@ -399,6 +404,7 @@ public: | ||||
|   { | ||||
|     JsonObject top = root.createNestedObject(FPSTR(_name)); | ||||
|     top[FPSTR(_enabled)] = enabled; | ||||
|     top[F("I2CAddress")] = static_cast<uint8_t>(I2CAddress); | ||||
|     top[F("TemperatureDecimals")] = TemperatureDecimals; | ||||
|     top[F("HumidityDecimals")] = HumidityDecimals; | ||||
|     top[F("PressureDecimals")] = PressureDecimals; | ||||
| @@ -426,6 +432,10 @@ public: | ||||
|  | ||||
|     configComplete &= getJsonValue(top[FPSTR(_enabled)], enabled); | ||||
|     // A 3-argument getJsonValue() assigns the 3rd argument as a default value if the Json value is missing | ||||
|     uint8_t tmpI2cAddress; | ||||
|     configComplete &= getJsonValue(top[F("I2CAddress")], tmpI2cAddress, 0x76); | ||||
|     I2CAddress = static_cast<BME280I2C::I2CAddr>(tmpI2cAddress); | ||||
|  | ||||
|     configComplete &= getJsonValue(top[F("TemperatureDecimals")], TemperatureDecimals, 1); | ||||
|     configComplete &= getJsonValue(top[F("HumidityDecimals")], HumidityDecimals, 0); | ||||
|     configComplete &= getJsonValue(top[F("PressureDecimals")], PressureDecimals, 0); | ||||
| @@ -440,8 +450,23 @@ public: | ||||
|       // first run: reading from cfg.json | ||||
|       DEBUG_PRINTLN(F(" config loaded.")); | ||||
|     } else { | ||||
|       DEBUG_PRINTLN(F(" config (re)loaded.")); | ||||
|       // changing parameters from settings page | ||||
|       DEBUG_PRINTLN(F(" config (re)loaded.")); | ||||
|  | ||||
|       // Reset all known values | ||||
|       sensorType = 0; | ||||
|       sensorTemperature = 0; | ||||
|       sensorHumidity = 0; | ||||
|       sensorHeatIndex = 0; | ||||
|       sensorDewPoint = 0; | ||||
|       sensorPressure = 0; | ||||
|       lastTemperature = 0; | ||||
|       lastHumidity = 0; | ||||
|       lastHeatIndex = 0; | ||||
|       lastDewPoint = 0; | ||||
|       lastPressure = 0; | ||||
|        | ||||
|       initializeBmeComms(); | ||||
|     } | ||||
|  | ||||
|     return configComplete; | ||||
|   | ||||
| @@ -5054,25 +5054,25 @@ uint16_t mode_2Dfirenoise(void) {               // firenoise2d. By Andrew Tuline | ||||
|     SEGMENT.fill(BLACK); | ||||
|   } | ||||
|  | ||||
|   uint16_t xscale = SEGMENT.intensity*4; | ||||
|   uint32_t yscale = SEGMENT.speed*8; | ||||
|   uint8_t indexx = 0; | ||||
|   unsigned xscale = SEGMENT.intensity*4; | ||||
|   unsigned yscale = SEGMENT.speed*8; | ||||
|   unsigned indexx = 0; | ||||
|  | ||||
|   SEGPALETTE = CRGBPalette16( CRGB(0,0,0), CRGB(0,0,0), CRGB(0,0,0), CRGB(0,0,0), | ||||
|                               CRGB::Red, CRGB::Red, CRGB::Red, CRGB::DarkOrange, | ||||
|                               CRGB::DarkOrange,CRGB::DarkOrange, CRGB::Orange, CRGB::Orange, | ||||
|                               CRGB::Yellow, CRGB::Orange, CRGB::Yellow, CRGB::Yellow); | ||||
|   CRGBPalette16 pal = SEGMENT.check1 ? SEGPALETTE : CRGBPalette16(CRGB::Black,     CRGB::Black,      CRGB::Black,  CRGB::Black, | ||||
|                                                                   CRGB::Red,       CRGB::Red,        CRGB::Red,    CRGB::DarkOrange, | ||||
|                                                                   CRGB::DarkOrange,CRGB::DarkOrange, CRGB::Orange, CRGB::Orange, | ||||
|                                                                   CRGB::Yellow,    CRGB::Orange,     CRGB::Yellow, CRGB::Yellow); | ||||
|  | ||||
|   for (int j=0; j < cols; j++) { | ||||
|     for (int i=0; i < rows; i++) { | ||||
|       indexx = inoise8(j*yscale*rows/255, i*xscale+strip.now/4);                                           // We're moving along our Perlin map. | ||||
|       SEGMENT.setPixelColorXY(j, i, ColorFromPalette(SEGPALETTE, min(i*(indexx)>>4, 255), i*255/cols, LINEARBLEND)); // With that value, look up the 8 bit colour palette value and assign it to the current LED. | ||||
|       indexx = inoise8(j*yscale*rows/255, i*xscale+strip.now/4);                                               // We're moving along our Perlin map. | ||||
|       SEGMENT.setPixelColorXY(j, i, ColorFromPalette(pal, min(i*(indexx)>>4, 255U), i*255/cols, LINEARBLEND)); // With that value, look up the 8 bit colour palette value and assign it to the current LED. | ||||
|     } // for i | ||||
|   } // for j | ||||
|  | ||||
|   return FRAMETIME; | ||||
| } // mode_2Dfirenoise() | ||||
| static const char _data_FX_MODE_2DFIRENOISE[] PROGMEM = "Firenoise@X scale,Y scale;;!;2"; | ||||
| static const char _data_FX_MODE_2DFIRENOISE[] PROGMEM = "Firenoise@X scale,Y scale,,,,Palette;;!;2;pal=66"; | ||||
|  | ||||
|  | ||||
| ////////////////////////////// | ||||
|   | ||||
							
								
								
									
										11
									
								
								wled00/FX.h
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								wled00/FX.h
									
									
									
									
									
								
							| @@ -90,7 +90,7 @@ | ||||
| //#define SEGCOLOR(x)      strip._segments[strip.getCurrSegmentId()].currentColor(x, strip._segments[strip.getCurrSegmentId()].colors[x]) | ||||
| //#define SEGLEN           strip._segments[strip.getCurrSegmentId()].virtualLength() | ||||
| #define SEGCOLOR(x)      strip.segColor(x) /* saves us a few kbytes of code */ | ||||
| #define SEGPALETTE       strip._currentPalette | ||||
| #define SEGPALETTE       Segment::getCurrentPalette() | ||||
| #define SEGLEN           strip._virtualSegmentLength /* saves us a few kbytes of code */ | ||||
| #define SPEED_FORMULA_L  (5U + (50U*(255U - SEGMENT.speed))/SEGLEN) | ||||
|  | ||||
| @@ -343,7 +343,8 @@ typedef enum mapping1D2D { | ||||
|   M12_Pixels = 0, | ||||
|   M12_pBar = 1, | ||||
|   M12_pArc = 2, | ||||
|   M12_pCorner = 3 | ||||
|   M12_pCorner = 3, | ||||
|   M12_sPinwheel = 4 | ||||
| } mapping1D2D_t; | ||||
|  | ||||
| // segment, 80 bytes | ||||
| @@ -436,6 +437,7 @@ typedef struct Segment { | ||||
|     static uint16_t _usedSegmentData; | ||||
|  | ||||
|     // perhaps this should be per segment, not static | ||||
|     static CRGBPalette16 _currentPalette;     // palette used for current effect (includes transition, used in color_from_palette()) | ||||
|     static CRGBPalette16 _randomPalette;      // actual random palette | ||||
|     static CRGBPalette16 _newRandomPalette;   // target random palette | ||||
|     static uint16_t _lastPaletteChange;       // last random palette change time in millis()/1000 | ||||
| @@ -556,6 +558,7 @@ typedef struct Segment { | ||||
|     static void     modeBlend(bool blend)       { _modeBlend = blend; } | ||||
|     #endif | ||||
|     static void     handleRandomPalette(); | ||||
|     inline static const CRGBPalette16 &getCurrentPalette(void) { return Segment::_currentPalette; } | ||||
|  | ||||
|     void    setUp(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1); | ||||
|     bool    setColor(uint8_t slot, uint32_t c); //returns true if changed | ||||
| @@ -593,7 +596,7 @@ typedef struct Segment { | ||||
|     uint8_t  currentMode(void);                 // currently active effect/mode (while in transition) | ||||
|     uint32_t currentColor(uint8_t slot);        // currently active segment color (blended while in transition) | ||||
|     CRGBPalette16 &loadPalette(CRGBPalette16 &tgt, uint8_t pal); | ||||
|     CRGBPalette16 ¤tPalette(CRGBPalette16 &tgt, uint8_t paletteID); | ||||
|     void     setCurrentPalette(void); | ||||
|  | ||||
|     // 1D strip | ||||
|     uint16_t virtualLength(void) const; | ||||
| @@ -732,7 +735,6 @@ class WS2812FX {  // 96 bytes | ||||
|       panels(1), | ||||
| #endif | ||||
|       // semi-private (just obscured) used in effect functions through macros | ||||
|       _currentPalette(CRGBPalette16(CRGB::Black)), | ||||
|       _colors_t{0,0,0}, | ||||
|       _virtualSegmentLength(0), | ||||
|       // true private variables | ||||
| @@ -926,7 +928,6 @@ class WS2812FX {  // 96 bytes | ||||
|   // end 2D support | ||||
|  | ||||
|     void loadCustomPalettes(void); // loads custom palettes from JSON | ||||
|     CRGBPalette16 _currentPalette; // palette used for current effect (includes transition) | ||||
|     std::vector<CRGBPalette16> customPalettes; // TODO: move custom palettes out of WS2812FX class | ||||
|  | ||||
|     // using public variables to reduce code size increase due to inline function getSegment() (with bounds checking) | ||||
|   | ||||
| @@ -77,6 +77,7 @@ uint16_t Segment::_usedSegmentData = 0U; // amount of RAM all segments use for t | ||||
| uint16_t Segment::maxWidth = DEFAULT_LED_COUNT; | ||||
| uint16_t Segment::maxHeight = 1; | ||||
|  | ||||
| CRGBPalette16 Segment::_currentPalette    = CRGBPalette16(CRGB::Black); | ||||
| CRGBPalette16 Segment::_randomPalette     = generateRandomPalette();  // was CRGBPalette16(DEFAULT_COLOR); | ||||
| CRGBPalette16 Segment::_newRandomPalette  = generateRandomPalette();  // was CRGBPalette16(DEFAULT_COLOR); | ||||
| uint16_t      Segment::_lastPaletteChange = 0; // perhaps it should be per segment | ||||
| @@ -207,7 +208,7 @@ void Segment::resetIfRequired() { | ||||
|  | ||||
| CRGBPalette16 IRAM_ATTR &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) { | ||||
|   if (pal < 245 && pal > GRADIENT_PALETTE_COUNT+13) pal = 0; | ||||
|   if (pal > 245 && (strip.customPalettes.size() == 0 || 255U-pal > strip.customPalettes.size()-1)) pal = 0; | ||||
|   if (pal > 245 && (strip.customPalettes.size() == 0 || 255U-pal > strip.customPalettes.size()-1)) pal = 0; // TODO remove strip dependency by moving customPalettes out of strip | ||||
|   //default palette. Differs depending on effect | ||||
|   if (pal == 0) switch (mode) { | ||||
|     case FX_MODE_FIRE_2012  : pal = 35; break; // heat palette | ||||
| @@ -334,8 +335,8 @@ void Segment::handleTransition() { | ||||
| // transition progression between 0-65535 | ||||
| uint16_t IRAM_ATTR Segment::progress() { | ||||
|   if (isInTransition()) { | ||||
|     unsigned long timeNow = millis(); | ||||
|     if (_t->_dur > 0 && timeNow - _t->_start < _t->_dur) return (timeNow - _t->_start) * 0xFFFFU / _t->_dur; | ||||
|     unsigned diff = millis() - _t->_start; | ||||
|     if (_t->_dur > 0 && diff < _t->_dur) return diff * 0xFFFFU / _t->_dur; | ||||
|   } | ||||
|   return 0xFFFFU; | ||||
| } | ||||
| @@ -448,11 +449,11 @@ uint32_t IRAM_ATTR Segment::currentColor(uint8_t slot) { | ||||
| #endif | ||||
| } | ||||
|  | ||||
| CRGBPalette16 IRAM_ATTR &Segment::currentPalette(CRGBPalette16 &targetPalette, uint8_t pal) { | ||||
|   loadPalette(targetPalette, pal); | ||||
| void Segment::setCurrentPalette() { | ||||
|   loadPalette(_currentPalette, palette); | ||||
|   unsigned prog = progress(); | ||||
| #ifndef WLED_DISABLE_MODE_BLEND | ||||
|   if (prog < 0xFFFFU && blendingStyle > BLEND_STYLE_FADE && _modeBlend && mode != _t->_modeT) targetPalette = _t->_palT; // not fade/blend transition, each effect uses its palette | ||||
|   if (prog < 0xFFFFU && blendingStyle > BLEND_STYLE_FADE && _modeBlend && mode != _t->_modeT) _currentPalette = _t->_palT; // not fade/blend transition, each effect uses its palette | ||||
|   else | ||||
| #endif | ||||
|   if (prog < 0xFFFFU) { | ||||
| @@ -460,10 +461,9 @@ CRGBPalette16 IRAM_ATTR &Segment::currentPalette(CRGBPalette16 &targetPalette, u | ||||
|     // there are about 255 blend passes of 48 "blends" to completely blend two palettes (in _dur time) | ||||
|     // minimum blend time is 100ms maximum is 65535ms | ||||
|     unsigned noOfBlends = ((255U * prog) / 0xFFFFU) - _t->_prevPaletteBlends; | ||||
|     for (unsigned i=0; i<noOfBlends; i++, _t->_prevPaletteBlends++) nblendPaletteTowardPalette(_t->_palT, targetPalette, 48); | ||||
|     targetPalette = _t->_palT; // copy transitioning/temporary palette | ||||
|     for (unsigned i = 0; i < noOfBlends; i++, _t->_prevPaletteBlends++) nblendPaletteTowardPalette(_t->_palT, _currentPalette, 48); | ||||
|     _currentPalette = _t->_palT; // copy transitioning/temporary palette | ||||
|   } | ||||
|   return targetPalette; | ||||
| } | ||||
|  | ||||
| // relies on WS2812FX::service() to call it for each frame | ||||
| @@ -648,6 +648,42 @@ uint16_t IRAM_ATTR Segment::nrOfVStrips() const { | ||||
|   return vLen; | ||||
| } | ||||
|  | ||||
| // Constants for mapping mode "Pinwheel" | ||||
| #ifndef WLED_DISABLE_2D | ||||
| constexpr int Pinwheel_Steps_Small = 72;       // no holes up to 16x16 | ||||
| constexpr int Pinwheel_Size_Small  = 16;       // larger than this -> use "Medium" | ||||
| constexpr int Pinwheel_Steps_Medium = 192;     // no holes up to 32x32 | ||||
| constexpr int Pinwheel_Size_Medium  = 32;      // larger than this -> use "Big" | ||||
| constexpr int Pinwheel_Steps_Big = 304;        // no holes up to 50x50 | ||||
| constexpr int Pinwheel_Size_Big  = 50;         // larger than this -> use "XL" | ||||
| constexpr int Pinwheel_Steps_XL  = 368; | ||||
| constexpr float Int_to_Rad_Small = (DEG_TO_RAD * 360) / Pinwheel_Steps_Small;  // conversion: from 0...72 to Radians | ||||
| constexpr float Int_to_Rad_Med =   (DEG_TO_RAD * 360) / Pinwheel_Steps_Medium; // conversion: from 0...192 to Radians | ||||
| constexpr float Int_to_Rad_Big =   (DEG_TO_RAD * 360) / Pinwheel_Steps_Big;    // conversion: from 0...304 to Radians | ||||
| constexpr float Int_to_Rad_XL =    (DEG_TO_RAD * 360) / Pinwheel_Steps_XL;     // conversion: from 0...368 to Radians | ||||
|  | ||||
| constexpr int Fixed_Scale = 512;               // fixpoint scaling factor (9bit for fraction) | ||||
|  | ||||
| // Pinwheel helper function: pixel index to radians | ||||
| static float getPinwheelAngle(int i, int vW, int vH) { | ||||
|   int maxXY = max(vW, vH); | ||||
|   if (maxXY <= Pinwheel_Size_Small)  return float(i) * Int_to_Rad_Small; | ||||
|   if (maxXY <= Pinwheel_Size_Medium) return float(i) * Int_to_Rad_Med; | ||||
|   if (maxXY <= Pinwheel_Size_Big)    return float(i) * Int_to_Rad_Big; | ||||
|   // else | ||||
|   return float(i) * Int_to_Rad_XL; | ||||
| } | ||||
| // Pinwheel helper function: matrix dimensions to number of rays | ||||
| static int getPinwheelLength(int vW, int vH) { | ||||
|   int maxXY = max(vW, vH); | ||||
|   if (maxXY <= Pinwheel_Size_Small)  return Pinwheel_Steps_Small; | ||||
|   if (maxXY <= Pinwheel_Size_Medium) return Pinwheel_Steps_Medium; | ||||
|   if (maxXY <= Pinwheel_Size_Big)    return Pinwheel_Steps_Big; | ||||
|   // else | ||||
|   return Pinwheel_Steps_XL; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| // 1D strip | ||||
| uint16_t IRAM_ATTR Segment::virtualLength() const { | ||||
| #ifndef WLED_DISABLE_2D | ||||
| @@ -663,6 +699,9 @@ uint16_t IRAM_ATTR Segment::virtualLength() const { | ||||
|       case M12_pArc: | ||||
|         vLen = max(vW,vH); // get the longest dimension | ||||
|         break; | ||||
|       case M12_sPinwheel: | ||||
|         vLen = getPinwheelLength(vW, vH); | ||||
|         break; | ||||
|     } | ||||
|     return vLen; | ||||
|   } | ||||
| @@ -755,6 +794,52 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col) | ||||
|         for (int x = 0; x <= i; x++) setPixelColorXY(x, i, col); | ||||
|         for (int y = 0; y <  i; y++) setPixelColorXY(i, y, col); | ||||
|         break; | ||||
|       case M12_sPinwheel: { | ||||
|         // i = angle --> 0 - 296  (Big), 0 - 192  (Medium), 0 - 72 (Small) | ||||
|         float centerX = roundf((vW-1) / 2.0f); | ||||
|         float centerY = roundf((vH-1) / 2.0f); | ||||
|         float angleRad = getPinwheelAngle(i, vW, vH); // angle in radians | ||||
|         float cosVal = cos_t(angleRad); | ||||
|         float sinVal = sin_t(angleRad); | ||||
|  | ||||
|         // avoid re-painting the same pixel | ||||
|         int lastX = INT_MIN; // impossible position | ||||
|         int lastY = INT_MIN; // impossible position | ||||
|         // draw line at angle, starting at center and ending at the segment edge | ||||
|         // we use fixed point math for better speed. Starting distance is 0.5 for better rounding | ||||
|         // int_fast16_t and int_fast32_t types changed to int, minimum bits commented | ||||
|         int posx = (centerX + 0.5f * cosVal) * Fixed_Scale; // X starting position in fixed point 18 bit | ||||
|         int posy = (centerY + 0.5f * sinVal) * Fixed_Scale; // Y starting position in fixed point 18 bit | ||||
|         int inc_x = cosVal * Fixed_Scale; // X increment per step (fixed point) 10 bit | ||||
|         int inc_y = sinVal * Fixed_Scale; // Y increment per step (fixed point) 10 bit | ||||
|  | ||||
|         int32_t maxX = vW * Fixed_Scale; // X edge in fixedpoint | ||||
|         int32_t maxY = vH * Fixed_Scale; // Y edge in fixedpoint | ||||
|  | ||||
|         // Odd rays start further from center if prevRay started at center. | ||||
|         static int prevRay = INT_MIN; // previous ray number | ||||
|         if ((i % 2 == 1) && (i - 1 == prevRay || i + 1 == prevRay)) { | ||||
|           int jump = min(vW/3, vH/3); // can add 2 if using medium pinwheel  | ||||
|           posx += inc_x * jump; | ||||
|           posy += inc_y * jump; | ||||
|         } | ||||
|         prevRay = i; | ||||
|  | ||||
|         // draw ray until we hit any edge | ||||
|         while ((posx >= 0) && (posy >= 0) && (posx < maxX)  && (posy < maxY))  { | ||||
|           // scale down to integer (compiler will replace division with appropriate bitshift) | ||||
|           int x = posx / Fixed_Scale; | ||||
|           int y = posy / Fixed_Scale; | ||||
|           // set pixel | ||||
|           if (x != lastX || y != lastY) setPixelColorXY(x, y, col);  // only paint if pixel position is different | ||||
|           lastX = x; | ||||
|           lastY = y; | ||||
|           // advance to next position | ||||
|           posx += inc_x; | ||||
|           posy += inc_y; | ||||
|         } | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|     return; | ||||
|   } else if (Segment::maxHeight!=1 && (width()==1 || height()==1)) { | ||||
| @@ -874,7 +959,36 @@ uint32_t IRAM_ATTR Segment::getPixelColor(int i) | ||||
|         // use longest dimension | ||||
|         return vW>vH ? getPixelColorXY(i, 0) : getPixelColorXY(0, i); | ||||
|         break; | ||||
|     } | ||||
|       case M12_sPinwheel: | ||||
|         // not 100% accurate, returns pixel at outer edge | ||||
|         // i = angle --> 0 - 296  (Big), 0 - 192  (Medium), 0 - 72 (Small) | ||||
|         float centerX = roundf((vW-1) / 2.0f); | ||||
|         float centerY = roundf((vH-1) / 2.0f); | ||||
|         float angleRad = getPinwheelAngle(i, vW, vH); // angle in radians | ||||
|         float cosVal = cos_t(angleRad); | ||||
|         float sinVal = sin_t(angleRad); | ||||
|  | ||||
|         int posx = (centerX + 0.5f * cosVal) * Fixed_Scale; // X starting position in fixed point 18 bit | ||||
|         int posy = (centerY + 0.5f * sinVal) * Fixed_Scale; // Y starting position in fixed point 18 bit | ||||
|         int inc_x = cosVal * Fixed_Scale; // X increment per step (fixed point) 10 bit | ||||
|         int inc_y = sinVal * Fixed_Scale; // Y increment per step (fixed point) 10 bit | ||||
|         int32_t maxX = vW * Fixed_Scale; // X edge in fixedpoint | ||||
|         int32_t maxY = vH * Fixed_Scale; // Y edge in fixedpoint | ||||
|  | ||||
|         // trace ray from center until we hit any edge - to avoid rounding problems, we use the same method as in setPixelColor | ||||
|         int x = INT_MIN; | ||||
|         int y = INT_MIN; | ||||
|         while ((posx >= 0) && (posy >= 0) && (posx < maxX)  && (posy < maxY))  { | ||||
|           // scale down to integer (compiler will replace division with appropriate bitshift) | ||||
|           x = posx / Fixed_Scale; | ||||
|           y = posy / Fixed_Scale; | ||||
|           // advance to next position | ||||
|           posx += inc_x; | ||||
|           posy += inc_y; | ||||
|         } | ||||
|         return getPixelColorXY(x, y); | ||||
|         break; | ||||
|       } | ||||
|     return 0; | ||||
|   } | ||||
| #endif | ||||
| @@ -1112,9 +1226,7 @@ uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_ | ||||
|   if (mapping && virtualLength() > 1) paletteIndex = (i*255)/(virtualLength() -1); | ||||
|   // paletteBlend: 0 - wrap when moving, 1 - always wrap, 2 - never wrap, 3 - none (undefined) | ||||
|   if (!wrap && strip.paletteBlend != 3) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end" | ||||
|   CRGBPalette16 curPal; | ||||
|   currentPalette(curPal, palette); | ||||
|   CRGB fastled_col = ColorFromPalette(curPal, paletteIndex, pbri, (strip.paletteBlend == 3)? NOBLEND:LINEARBLEND); // NOTE: paletteBlend should be global | ||||
|   CRGB fastled_col = ColorFromPalette(_currentPalette, paletteIndex, pbri, (strip.paletteBlend == 3)? NOBLEND:LINEARBLEND); // NOTE: paletteBlend should be global | ||||
|  | ||||
|   return RGBW32(fastled_col.r, fastled_col.g, fastled_col.b, W(color)); | ||||
| } | ||||
| @@ -1227,7 +1339,7 @@ void WS2812FX::service() { | ||||
|         _colors_t[0] = gamma32(seg.currentColor(0)); | ||||
|         _colors_t[1] = gamma32(seg.currentColor(1)); | ||||
|         _colors_t[2] = gamma32(seg.currentColor(2)); | ||||
|         seg.currentPalette(_currentPalette, seg.palette); // we need to pass reference | ||||
|         seg.setCurrentPalette();              // load actual palette | ||||
|         // when correctWB is true we need to correct/adjust RGB value according to desired CCT value, but it will also affect actual WW/CW ratio | ||||
|         // when cctFromRgb is true we implicitly calculate WW and CW from RGB values | ||||
|         if (cctFromRgb) BusManager::setSegmentCCT(-1); | ||||
|   | ||||
| @@ -17,6 +17,11 @@ | ||||
| #if !defined(WLED_NO_I2S1_PIXELBUS) && (defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2)) | ||||
| #define WLED_NO_I2S1_PIXELBUS | ||||
| #endif | ||||
| #ifndef WLED_NO_I2S1_PIXELBUS | ||||
|   #ifdef WLED_USE_PARALLEL_I2S | ||||
|     #warning Use less than 300 pixels per bus. | ||||
|   #endif | ||||
| #endif | ||||
| // temporary end | ||||
|  | ||||
| //Hardware SPI Pins | ||||
| @@ -224,8 +229,11 @@ | ||||
| //#define B_32_I0_NEO_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s0X8Ws2812xMethod, NeoGammaNullMethod> // parallel I2S | ||||
| #endif | ||||
| #ifndef WLED_NO_I2S1_PIXELBUS | ||||
|   #ifndef WLED_USE_PARALLEL_I2S | ||||
| #define B_32_I1_NEO_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s1Ws2812xMethod, NeoGammaNullMethod> | ||||
| //#define B_32_I1_NEO_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s1X8Ws2812xMethod, NeoGammaNullMethod> // parallel I2S | ||||
|   #else | ||||
| #define B_32_I1_NEO_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s1X8Ws2812xMethod, NeoGammaNullMethod> // parallel I2S | ||||
|   #endif | ||||
| #endif | ||||
| //RGBW | ||||
| #define B_32_RN_NEO_4 NeoPixelBusLg<NeoGrbwFeature, NeoEsp32RmtNSk6812Method, NeoGammaNullMethod> | ||||
| @@ -234,8 +242,11 @@ | ||||
| //#define B_32_I0_NEO_4 NeoPixelBusLg<NeoGrbwFeature, NeoEsp32I2s0X8Sk6812Method, NeoGammaNullMethod> // parallel I2S | ||||
| #endif | ||||
| #ifndef WLED_NO_I2S1_PIXELBUS | ||||
|   #ifndef WLED_USE_PARALLEL_I2S | ||||
| #define B_32_I1_NEO_4 NeoPixelBusLg<NeoGrbwFeature, NeoEsp32I2s1Sk6812Method, NeoGammaNullMethod> | ||||
| //#define B_32_I1_NEO_4 NeoPixelBusLg<NeoGrbwFeature, NeoEsp32I2s1X8Sk6812Method, NeoGammaNullMethod> // parallel I2S | ||||
|   #else | ||||
| #define B_32_I1_NEO_4 NeoPixelBusLg<NeoGrbwFeature, NeoEsp32I2s1X8Sk6812Method, NeoGammaNullMethod> // parallel I2S | ||||
|   #endif | ||||
| #endif | ||||
| //400Kbps | ||||
| #define B_32_RN_400_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32RmtN400KbpsMethod, NeoGammaNullMethod> | ||||
| @@ -244,8 +255,11 @@ | ||||
| //#define B_32_I0_400_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s0X8400KbpsMethod, NeoGammaNullMethod> // parallel I2S | ||||
| #endif | ||||
| #ifndef WLED_NO_I2S1_PIXELBUS | ||||
|   #ifndef WLED_USE_PARALLEL_I2S | ||||
| #define B_32_I1_400_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s1400KbpsMethod, NeoGammaNullMethod> | ||||
| //#define B_32_I1_400_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s1X8400KbpsMethod, NeoGammaNullMethod> // parallel I2S | ||||
|   #else | ||||
| #define B_32_I1_400_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s1X8400KbpsMethod, NeoGammaNullMethod> // parallel I2S | ||||
|   #endif | ||||
| #endif | ||||
| //TM1814 (RGBW) | ||||
| #define B_32_RN_TM1_4 NeoPixelBusLg<NeoWrgbTm1814Feature, NeoEsp32RmtNTm1814Method, NeoGammaNullMethod> | ||||
| @@ -254,8 +268,11 @@ | ||||
| //#define B_32_I0_TM1_4 NeoPixelBusLg<NeoWrgbTm1814Feature, NeoEsp32I2s0X8Tm1814Method, NeoGammaNullMethod> // parallel I2S | ||||
| #endif | ||||
| #ifndef WLED_NO_I2S1_PIXELBUS | ||||
|   #ifndef WLED_USE_PARALLEL_I2S | ||||
| #define B_32_I1_TM1_4 NeoPixelBusLg<NeoWrgbTm1814Feature, NeoEsp32I2s1Tm1814Method, NeoGammaNullMethod> | ||||
| //#define B_32_I1_TM1_4 NeoPixelBusLg<NeoWrgbTm1814Feature, NeoEsp32I2s1X8Tm1814Method, NeoGammaNullMethod> // parallel I2S | ||||
|   #else | ||||
| #define B_32_I1_TM1_4 NeoPixelBusLg<NeoWrgbTm1814Feature, NeoEsp32I2s1X8Tm1814Method, NeoGammaNullMethod> // parallel I2S | ||||
|   #endif | ||||
| #endif | ||||
| //TM1829 (RGB) | ||||
| #define B_32_RN_TM2_3 NeoPixelBusLg<NeoBrgFeature, NeoEsp32RmtNTm1829Method, NeoGammaNullMethod> | ||||
| @@ -264,8 +281,11 @@ | ||||
| //#define B_32_I0_TM2_3 NeoPixelBusLg<NeoBrgFeature, NeoEsp32I2s0X8Tm1829Method, NeoGammaNullMethod> // parallel I2S | ||||
| #endif | ||||
| #ifndef WLED_NO_I2S1_PIXELBUS | ||||
|   #ifndef WLED_USE_PARALLEL_I2S | ||||
| #define B_32_I1_TM2_3 NeoPixelBusLg<NeoBrgFeature, NeoEsp32I2s1Tm1829Method, NeoGammaNullMethod> | ||||
| //#define B_32_I1_TM2_3 NeoPixelBusLg<NeoBrgFeature, NeoEsp32I2s1X8Tm1829Method, NeoGammaNullMethod> // parallel I2S | ||||
|   #else | ||||
| #define B_32_I1_TM2_3 NeoPixelBusLg<NeoBrgFeature, NeoEsp32I2s1X8Tm1829Method, NeoGammaNullMethod> // parallel I2S | ||||
|   #endif | ||||
| #endif | ||||
| //UCS8903 | ||||
| #define B_32_RN_UCS_3 NeoPixelBusLg<NeoRgbUcs8903Feature, NeoEsp32RmtNWs2812xMethod, NeoGammaNullMethod> | ||||
| @@ -274,8 +294,11 @@ | ||||
| //#define B_32_I0_UCS_3 NeoPixelBusLg<NeoRgbUcs8903Feature, NeoEsp32I2s0X8800KbpsMethod, NeoGammaNullMethod> // parallel I2S | ||||
| #endif | ||||
| #ifndef WLED_NO_I2S1_PIXELBUS | ||||
|   #ifndef WLED_USE_PARALLEL_I2S | ||||
| #define B_32_I1_UCS_3 NeoPixelBusLg<NeoRgbUcs8903Feature, NeoEsp32I2s1800KbpsMethod, NeoGammaNullMethod> | ||||
| //#define B_32_I1_UCS_3 NeoPixelBusLg<NeoRgbUcs8903Feature, NeoEsp32I2s1X8800KbpsMethod, NeoGammaNullMethod> // parallel I2S | ||||
|   #else | ||||
| #define B_32_I1_UCS_3 NeoPixelBusLg<NeoRgbUcs8903Feature, NeoEsp32I2s1X8800KbpsMethod, NeoGammaNullMethod> // parallel I2S | ||||
|   #endif | ||||
| #endif | ||||
| //UCS8904 | ||||
| #define B_32_RN_UCS_4 NeoPixelBusLg<NeoRgbwUcs8904Feature, NeoEsp32RmtNWs2812xMethod, NeoGammaNullMethod> | ||||
| @@ -284,8 +307,11 @@ | ||||
| //#define B_32_I0_UCS_4 NeoPixelBusLg<NeoRgbwUcs8904Feature, NeoEsp32I2s0X8800KbpsMethod, NeoGammaNullMethod>// parallel I2S | ||||
| #endif | ||||
| #ifndef WLED_NO_I2S1_PIXELBUS | ||||
|   #ifndef WLED_USE_PARALLEL_I2S | ||||
| #define B_32_I1_UCS_4 NeoPixelBusLg<NeoRgbwUcs8904Feature, NeoEsp32I2s1800KbpsMethod, NeoGammaNullMethod> | ||||
| //#define B_32_I1_UCS_4 NeoPixelBusLg<NeoRgbwUcs8904Feature, NeoEsp32I2s1X8800KbpsMethod, NeoGammaNullMethod>// parallel I2S | ||||
|   #else | ||||
| #define B_32_I1_UCS_4 NeoPixelBusLg<NeoRgbwUcs8904Feature, NeoEsp32I2s1X8800KbpsMethod, NeoGammaNullMethod>// parallel I2S | ||||
|   #endif | ||||
| #endif | ||||
| #define B_32_RN_APA106_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32RmtNApa106Method, NeoGammaNullMethod> | ||||
| #ifndef WLED_NO_I2S0_PIXELBUS | ||||
| @@ -293,8 +319,11 @@ | ||||
| //#define B_32_I0_APA106_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s0X8Apa106Method, NeoGammaNullMethod> // parallel I2S | ||||
| #endif | ||||
| #ifndef WLED_NO_I2S1_PIXELBUS | ||||
|   #ifndef WLED_USE_PARALLEL_I2S | ||||
| #define B_32_I1_APA106_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s1Apa106Method, NeoGammaNullMethod> | ||||
| //#define B_32_I1_APA106_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s1X8Apa106Method, NeoGammaNullMethod> // parallel I2S | ||||
|   #else | ||||
| #define B_32_I1_APA106_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s1X8Apa106Method, NeoGammaNullMethod> // parallel I2S | ||||
|   #endif | ||||
| #endif | ||||
| //FW1906 GRBCW | ||||
| #define B_32_RN_FW6_5 NeoPixelBusLg<NeoGrbcwxFeature, NeoEsp32RmtNWs2812xMethod, NeoGammaNullMethod> | ||||
| @@ -303,8 +332,11 @@ | ||||
| //#define B_32_I0_FW6_5 NeoPixelBusLg<NeoGrbcwxFeature, NeoEsp32I2s0X8800KbpsMethod, NeoGammaNullMethod> // parallel I2S | ||||
| #endif | ||||
| #ifndef WLED_NO_I2S1_PIXELBUS | ||||
|   #ifndef WLED_USE_PARALLEL_I2S | ||||
| #define B_32_I1_FW6_5 NeoPixelBusLg<NeoGrbcwxFeature, NeoEsp32I2s1800KbpsMethod, NeoGammaNullMethod> | ||||
| //#define B_32_I1_FW6_5 NeoPixelBusLg<NeoGrbcwxFeature, NeoEsp32I2s1X8800KbpsMethod, NeoGammaNullMethod> // parallel I2S | ||||
|   #else | ||||
| #define B_32_I1_FW6_5 NeoPixelBusLg<NeoGrbcwxFeature, NeoEsp32I2s1X8800KbpsMethod, NeoGammaNullMethod> // parallel I2S | ||||
|   #endif | ||||
| #endif | ||||
| //WS2805 RGBWC | ||||
| #define B_32_RN_2805_5 NeoPixelBusLg<NeoGrbwwFeature, NeoEsp32RmtNWs2805Method, NeoGammaNullMethod> | ||||
| @@ -313,8 +345,11 @@ | ||||
| //#define B_32_I0_2805_5 NeoPixelBusLg<NeoGrbwwFeature, NeoEsp32I2s0X8Ws2805Method, NeoGammaNullMethod> // parallel I2S | ||||
| #endif | ||||
| #ifndef WLED_NO_I2S1_PIXELBUS | ||||
|   #ifndef WLED_USE_PARALLEL_I2S | ||||
| #define B_32_I1_2805_5 NeoPixelBusLg<NeoGrbwwFeature, NeoEsp32I2s1Ws2805Method, NeoGammaNullMethod> | ||||
| //#define B_32_I1_2805_5 NeoPixelBusLg<NeoGrbwwFeature, NeoEsp32I2s1X8Ws2805Method, NeoGammaNullMethod> // parallel I2S | ||||
|   #else | ||||
| #define B_32_I1_2805_5 NeoPixelBusLg<NeoGrbwwFeature, NeoEsp32I2s1X8Ws2805Method, NeoGammaNullMethod> // parallel I2S | ||||
|   #endif | ||||
| #endif | ||||
| //TM1914 (RGB) | ||||
| #define B_32_RN_TM1914_3 NeoPixelBusLg<NeoGrbTm1914Feature, NeoEsp32RmtNTm1914Method, NeoGammaNullMethod> | ||||
| @@ -323,8 +358,11 @@ | ||||
| //#define B_32_I0_TM1914_3 NeoPixelBusLg<NeoGrbTm1914Feature, NeoEsp32I2s0X8Tm1914Method, NeoGammaNullMethod> | ||||
| #endif | ||||
| #ifndef WLED_NO_I2S1_PIXELBUS | ||||
|   #ifndef WLED_USE_PARALLEL_I2S | ||||
| #define B_32_I1_TM1914_3 NeoPixelBusLg<NeoGrbTm1914Feature, NeoEsp32I2s1Tm1914Method, NeoGammaNullMethod> | ||||
| //#define B_32_I1_TM1914_3 NeoPixelBusLg<NeoGrbTm1914Feature, NeoEsp32I2s1X8Tm1914Method, NeoGammaNullMethod> | ||||
|   #else | ||||
| #define B_32_I1_TM1914_3 NeoPixelBusLg<NeoGrbTm1914Feature, NeoEsp32I2s1X8Tm1914Method, NeoGammaNullMethod> | ||||
|   #endif | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| @@ -541,7 +579,11 @@ class PolyBus { | ||||
|     #if defined(ARDUINO_ARCH_ESP32) && !(defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3)) | ||||
|     // NOTE: "channel" is only used on ESP32 (and its variants) for RMT channel allocation | ||||
|     // since 0.15.0-b3 I2S1 is favoured for classic ESP32 and moved to position 0 (channel 0) so we need to subtract 1 for correct RMT allocation | ||||
|       #ifdef WLED_USE_PARALLEL_I2S | ||||
|     if (channel > 7) channel -= 8; // accommodate parallel I2S1 which is used 1st on classic ESP32 | ||||
|       #else | ||||
|     if (channel > 0) channel--; // accommodate I2S1 which is used as 1st bus on classic ESP32 | ||||
|       #endif | ||||
|     #endif | ||||
|     void* busPtr = nullptr; | ||||
|     switch (busType) { | ||||
| @@ -1619,9 +1661,15 @@ class PolyBus { | ||||
|       //if (num > 3) offset = num -4; // I2S not supported yet | ||||
|       #else | ||||
|       // standard ESP32 has 8 RMT and 2 I2S channels | ||||
|         #ifdef WLED_USE_PARALLEL_I2S | ||||
|       if (num > 16) return I_NONE; | ||||
|       if (num < 8) offset = 2;  // prefer 8 parallel I2S1 channels | ||||
|       if (num == 16) offset = 1; | ||||
|         #else | ||||
|       if (num > 9) return I_NONE; | ||||
|       if (num > 8) offset = 1; | ||||
|       if (num == 0) offset = 2; // prefer I2S1 for 1st bus (less flickering but more RAM needed) | ||||
|         #endif | ||||
|       #endif | ||||
|       switch (busType) { | ||||
|         case TYPE_WS2812_1CH_X3: | ||||
|   | ||||
| @@ -124,7 +124,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { | ||||
|     CJSON(strip.panels, matrix[F("mpc")]); | ||||
|     strip.panel.clear(); | ||||
|     JsonArray panels = matrix[F("panels")]; | ||||
|     uint8_t s = 0; | ||||
|     int s = 0; | ||||
|     if (!panels.isNull()) { | ||||
|       strip.panel.reserve(max(1U,min((size_t)strip.panels,(size_t)WLED_MAX_PANELS)));  // pre-allocate memory for panels | ||||
|       for (JsonObject pnl : panels) { | ||||
| @@ -156,7 +156,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { | ||||
|   JsonArray ins = hw_led["ins"]; | ||||
|  | ||||
|   if (fromFS || !ins.isNull()) { | ||||
|     uint8_t s = 0;  // bus iterator | ||||
|     int s = 0;  // bus iterator | ||||
|     if (fromFS) BusManager::removeAll(); // can't safely manipulate busses directly in network callback | ||||
|     uint32_t mem = 0, globalBufMem = 0; | ||||
|     uint16_t maxlen = 0; | ||||
| @@ -787,7 +787,7 @@ void serializeConfig() { | ||||
|     JsonObject matrix = hw_led.createNestedObject(F("matrix")); | ||||
|     matrix[F("mpc")] = strip.panels; | ||||
|     JsonArray panels = matrix.createNestedArray(F("panels")); | ||||
|     for (uint8_t i=0; i<strip.panel.size(); i++) { | ||||
|     for (size_t i = 0; i < strip.panel.size(); i++) { | ||||
|       JsonObject pnl = panels.createNestedObject(); | ||||
|       pnl["b"] = strip.panel[i].bottomStart; | ||||
|       pnl["r"] = strip.panel[i].rightStart; | ||||
| @@ -803,7 +803,7 @@ void serializeConfig() { | ||||
|  | ||||
|   JsonArray hw_led_ins = hw_led.createNestedArray("ins"); | ||||
|  | ||||
|   for (uint8_t s = 0; s < BusManager::getNumBusses(); s++) { | ||||
|   for (size_t s = 0; s < BusManager::getNumBusses(); s++) { | ||||
|     Bus *bus = BusManager::getBus(s); | ||||
|     if (!bus || bus->getLength()==0) break; | ||||
|     JsonObject ins = hw_led_ins.createNestedObject(); | ||||
| @@ -812,7 +812,7 @@ void serializeConfig() { | ||||
|     JsonArray ins_pin = ins.createNestedArray("pin"); | ||||
|     uint8_t pins[5]; | ||||
|     uint8_t nPins = bus->getPins(pins); | ||||
|     for (uint8_t i = 0; i < nPins; i++) ins_pin.add(pins[i]); | ||||
|     for (int i = 0; i < nPins; i++) ins_pin.add(pins[i]); | ||||
|     ins[F("order")] = bus->getColorOrder(); | ||||
|     ins["rev"] = bus->isReversed(); | ||||
|     ins[F("skip")] = bus->skippedLeds(); | ||||
| @@ -826,7 +826,7 @@ void serializeConfig() { | ||||
|  | ||||
|   JsonArray hw_com = hw.createNestedArray(F("com")); | ||||
|   const ColorOrderMap& com = BusManager::getColorOrderMap(); | ||||
|   for (uint8_t s = 0; s < com.count(); s++) { | ||||
|   for (size_t s = 0; s < com.count(); s++) { | ||||
|     const ColorOrderMapEntry *entry = com.get(s); | ||||
|     if (!entry) break; | ||||
|  | ||||
| @@ -843,7 +843,7 @@ void serializeConfig() { | ||||
|   JsonArray hw_btn_ins = hw_btn.createNestedArray("ins"); | ||||
|  | ||||
|   // configuration for all buttons | ||||
|   for (uint8_t i=0; i<WLED_MAX_BUTTONS; i++) { | ||||
|   for (int i = 0; i < WLED_MAX_BUTTONS; i++) { | ||||
|     JsonObject hw_btn_ins_0 = hw_btn_ins.createNestedObject(); | ||||
|     hw_btn_ins_0["type"] = buttonType[i]; | ||||
|     JsonArray hw_btn_ins_0_pin = hw_btn_ins_0.createNestedArray("pin"); | ||||
|   | ||||
| @@ -60,8 +60,12 @@ | ||||
|       #define WLED_MAX_BUSSES 6               // will allow 4 digital & 2 analog | ||||
|       #define WLED_MIN_VIRTUAL_BUSSES 4 | ||||
|     #else | ||||
|       // the 10th digital bus (I2S0) will prevent Audioreactive usermod from functioning (it is last used though) | ||||
|       // the last digital bus (I2S0) will prevent Audioreactive usermod from functioning | ||||
|       #ifndef WLED_USE_PARALLEL_I2S | ||||
|       #define WLED_MAX_BUSSES 10 | ||||
|       #else | ||||
|       #define WLED_MAX_BUSSES 17 | ||||
|       #endif | ||||
|       #define WLED_MIN_VIRTUAL_BUSSES 0 | ||||
|     #endif | ||||
|   #endif | ||||
|   | ||||
| @@ -801,6 +801,7 @@ function populateSegments(s) | ||||
| 							`<option value="1" ${inst.m12==1?' selected':''}>Bar</option>`+ | ||||
| 							`<option value="2" ${inst.m12==2?' selected':''}>Arc</option>`+ | ||||
| 							`<option value="3" ${inst.m12==3?' selected':''}>Corner</option>`+ | ||||
| 							`<option value="4" ${inst.m12==4?' selected':''}>Pinwheel</option>`+ | ||||
| 						`</select></div>`+ | ||||
| 					`</div>`; | ||||
| 		let sndSim = `<div data-snd="si" class="lbl-s hide">Sound sim<br>`+ | ||||
|   | ||||
| @@ -5,12 +5,12 @@ | ||||
| 	<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"> | ||||
| 	<title>LED Settings</title> | ||||
| 	<script> | ||||
| 		var d=document,laprev=55,maxB=1,maxV=0,maxM=4000,maxPB=4096,maxL=1333,maxLbquot=0; //maximum bytes for LED allocation: 4kB for 8266, 32kB for 32 | ||||
| 		var d=document,laprev=55,maxB=1,maxV=0,maxM=4000,maxPB=4096,maxL=1333,maxCO=10,maxLbquot=0; //maximum bytes for LED allocation: 4kB for 8266, 32kB for 32 | ||||
| 		d.um_p = []; | ||||
| 		d.rsvd = []; | ||||
| 		d.ro_gpio = []; | ||||
| 		d.max_gpio = 50; | ||||
| 		var customStarts=false,startsDirty=[],maxCOOverrides=5; | ||||
| 		var customStarts=false,startsDirty=[]; | ||||
| 		var loc = false, locip, locproto = "http:"; | ||||
| 		function H(){window.open("https://kno.wled.ge/features/settings/#led-settings");} | ||||
| 		function B(){window.open(getURL("/settings"),"_self");} | ||||
| @@ -57,8 +57,8 @@ | ||||
| 			x.style.animation = 'none'; | ||||
| 			timeout = setTimeout(function(){ x.className = x.className.replace("show", ""); }, 2900); | ||||
| 		} | ||||
| 		function bLimits(b,v,p,m,l) { | ||||
| 			maxB = b; maxV = v; maxM = m; maxPB = p; maxL = l; | ||||
| 		function bLimits(b,v,p,m,l,o) { | ||||
| 			maxB = b; maxV = v; maxM = m; maxPB = p; maxL = l; maxCO = o; | ||||
| 		} | ||||
| 		function pinsOK() { | ||||
| 			var ok = true; | ||||
| @@ -138,7 +138,8 @@ | ||||
| 			gId("psuMA").style.display = ppl ? 'none' : 'inline'; | ||||
| 			gId("ppldis").style.display = ppl ? 'inline' : 'none'; | ||||
| 			// set PPL minimum value and clear actual PPL limit if ABL disabled | ||||
| 			d.Sf.querySelectorAll("#mLC input[name^=MA]").forEach((i,n)=>{ | ||||
| 			d.Sf.querySelectorAll("#mLC input[name^=MA]").forEach((i,x)=>{ | ||||
| 				var n = String.fromCharCode((x<10?48:55)+x); | ||||
| 				gId("PSU"+n).style.display = ppl ? "inline" : "none"; | ||||
| 				const t = parseInt(d.Sf["LT"+n].value); // LED type SELECT | ||||
| 				const c = parseInt(d.Sf["LC"+n].value); //get LED count | ||||
| @@ -164,8 +165,9 @@ | ||||
| 				if (parseInt(i.value) > 0) d.Sf.ABL.checked = true; | ||||
| 			}); | ||||
| 			// select appropriate LED current | ||||
| 			d.Sf.querySelectorAll("#mLC select[name^=LAsel]").forEach((sel,n)=>{ | ||||
| 			d.Sf.querySelectorAll("#mLC select[name^=LAsel]").forEach((sel,x)=>{ | ||||
| 				sel.value = 0; // set custom | ||||
| 				var n = String.fromCharCode((x<10?48:55)+x); | ||||
| 				switch (parseInt(d.Sf["LA"+n].value)) { | ||||
| 					case 0: break; // disable ABL | ||||
| 					case 15: sel.value = 15; break; | ||||
| @@ -358,10 +360,11 @@ | ||||
| 			gId("json").style.display = d.Sf.IT.value==8 ? "" : "none"; | ||||
| 		} | ||||
| 		function lastEnd(i) { | ||||
| 			if (i<1) return 0; | ||||
| 			v = parseInt(d.getElementsByName("LS"+(i-1))[0].value) + parseInt(d.getElementsByName("LC"+(i-1))[0].value); | ||||
| 			var t = parseInt(d.getElementsByName("LT"+(i-1))[0].value); | ||||
| 			if (t > 31 && t < 48) v = 1; //PWM busses | ||||
| 			if (i-- < 1) return 0; | ||||
| 			var s = String.fromCharCode((i<10?48:55)+i); | ||||
| 			v = parseInt(d.getElementsByName("LS"+s)[0].value) + parseInt(d.getElementsByName("LC"+s)[0].value); | ||||
| 			var t = parseInt(d.getElementsByName("LT"+s)[0].value); | ||||
| 			if (isPWM(t)) v = 1; //PWM busses | ||||
| 			if (isNaN(v)) return 0; | ||||
| 			return v; | ||||
| 		} | ||||
| @@ -371,6 +374,7 @@ | ||||
| 			var i = o.length; | ||||
|  | ||||
| 			if ((n==1 && i>=maxB+maxV) || (n==-1 && i==0)) return; | ||||
| 			var s = String.fromCharCode((i<10?48:55)+i); | ||||
|  | ||||
| 			var f = gId("mLC"); | ||||
| 			if (n==1) { | ||||
| @@ -378,7 +382,7 @@ | ||||
| 				var cn = `<div class="iST"> | ||||
| <hr class="sml"> | ||||
| ${i+1}: | ||||
| <select name="LT${i}" onchange="UI(true)">${i>=maxB ? '' : | ||||
| <select name="LT${s}" onchange="UI(true)">${i>=maxB ? '' : | ||||
| '<option value="22" selected>WS281x</option>\ | ||||
| <option value="30">SK6812/WS2814 RGBW</option>\ | ||||
| <option value="31">TM1814</option>\ | ||||
| @@ -409,8 +413,8 @@ ${i+1}: | ||||
| <option value="88">DDP RGBW (network)</option> | ||||
| <option value="89">Art-Net RGBW (network)</option> | ||||
| </select><br> | ||||
| <div id="abl${i}"> | ||||
| mA/LED: <select name="LAsel${i}" onchange="enLA(this,${i});UI();"> | ||||
| <div id="abl${s}"> | ||||
| mA/LED: <select name="LAsel${s}" onchange="enLA(this,'${s}');UI();"> | ||||
| <option value="55" selected>55mA (typ. 5V WS281x)</option> | ||||
| <option value="35">35mA (eco WS2812)</option> | ||||
| <option value="30">30mA (typ. 12V)</option> | ||||
| @@ -418,11 +422,11 @@ mA/LED: <select name="LAsel${i}" onchange="enLA(this,${i});UI();"> | ||||
| <option value="15">15mA (seed/fairy pixels)</option> | ||||
| <option value="0">Custom</option> | ||||
| </select><br> | ||||
| <div id="LAdis${i}" style="display: none;">max. mA/LED: <input name="LA${i}" type="number" min="1" max="255" oninput="UI()"> mA<br></div> | ||||
| <div id="PSU${i}">PSU: <input name="MA${i}" type="number" class="xl" min="250" max="65000" oninput="UI()" value="250"> mA<br></div> | ||||
| <div id="LAdis${s}" style="display: none;">max. mA/LED: <input name="LA${s}" type="number" min="1" max="255" oninput="UI()"> mA<br></div> | ||||
| <div id="PSU${s}">PSU: <input name="MA${s}" type="number" class="xl" min="250" max="65000" oninput="UI()" value="250"> mA<br></div> | ||||
| </div> | ||||
| <div id="co${i}" style="display:inline">Color Order: | ||||
| <select name="CO${i}"> | ||||
| <div id="co${s}" style="display:inline">Color Order: | ||||
| <select name="CO${s}"> | ||||
| <option value="0">GRB</option> | ||||
| <option value="1">RGB</option> | ||||
| <option value="2">BRG</option> | ||||
| @@ -430,21 +434,21 @@ mA/LED: <select name="LAsel${i}" onchange="enLA(this,${i});UI();"> | ||||
| <option value="4">BGR</option> | ||||
| <option value="5">GBR</option> | ||||
| </select></div> | ||||
| <div id="dig${i}w" style="display:none">Swap: <select name="WO${i}"><option value="0">None</option><option value="1">W & B</option><option value="2">W & G</option><option value="3">W & R</option></select></div> | ||||
| <div id="dig${i}l" style="display:none">Clock: <select name="SP${i}"><option value="0">Slowest</option><option value="1">Slow</option><option value="2">Normal</option><option value="3">Fast</option><option value="4">Fastest</option></select></div> | ||||
| <div id="dig${s}w" style="display:none">Swap: <select name="WO${s}"><option value="0">None</option><option value="1">W & B</option><option value="2">W & G</option><option value="3">W & R</option></select></div> | ||||
| <div id="dig${s}l" style="display:none">Clock: <select name="SP${s}"><option value="0">Slowest</option><option value="1">Slow</option><option value="2">Normal</option><option value="3">Fast</option><option value="4">Fastest</option></select></div> | ||||
| <div> | ||||
| <span id="psd${i}">Start:</span> <input type="number" name="LS${i}" id="ls${i}" class="l starts" min="0" max="8191" value="${lastEnd(i)}" oninput="startsDirty[${i}]=true;UI();" required />  | ||||
| <div id="dig${i}c" style="display:inline">Length: <input type="number" name="LC${i}" class="l" min="1" max="${maxPB}" value="1" required oninput="UI()" /></div><br> | ||||
| <span id="psd${s}">Start:</span> <input type="number" name="LS${s}" id="ls${s}" class="l starts" min="0" max="8191" value="${lastEnd(i)}" oninput="startsDirty[${i}]=true;UI();" required />  | ||||
| <div id="dig${s}c" style="display:inline">Length: <input type="number" name="LC${s}" class="l" min="1" max="${maxPB}" value="1" required oninput="UI()" /></div><br> | ||||
| </div> | ||||
| <span id="p0d${i}">GPIO:</span><input type="number" name="L0${i}" required class="s" onchange="UI();pinUpd(this);"/> | ||||
| <span id="p1d${i}"></span><input type="number" name="L1${i}" class="s" onchange="UI();pinUpd(this);"/> | ||||
| <span id="p2d${i}"></span><input type="number" name="L2${i}" class="s" onchange="UI();pinUpd(this);"/> | ||||
| <span id="p3d${i}"></span><input type="number" name="L3${i}" class="s" onchange="UI();pinUpd(this);"/> | ||||
| <span id="p4d${i}"></span><input type="number" name="L4${i}" class="s" onchange="UI();pinUpd(this);"/> | ||||
| <div id="dig${i}r" style="display:inline"><br><span id="rev${i}">Reversed</span>: <input type="checkbox" name="CV${i}"></div> | ||||
| <div id="dig${i}s" style="display:inline"><br>Skip first LEDs: <input type="number" name="SL${i}" min="0" max="255" value="0" oninput="UI()"></div> | ||||
| <div id="dig${i}f" style="display:inline"><br>Off Refresh: <input id="rf${i}" type="checkbox" name="RF${i}"></div> | ||||
| <div id="dig${i}a" style="display:inline"><br>Auto-calculate white channel from RGB:<br><select name="AW${i}"><option value=0>None</option><option value=1>Brighter</option><option value=2>Accurate</option><option value=3>Dual</option><option value=4>Max</option></select> </div> | ||||
| <span id="p0d${s}">GPIO:</span><input type="number" name="L0${s}" required class="s" onchange="UI();pinUpd(this);"/> | ||||
| <span id="p1d${s}"></span><input type="number" name="L1${s}" class="s" onchange="UI();pinUpd(this);"/> | ||||
| <span id="p2d${s}"></span><input type="number" name="L2${s}" class="s" onchange="UI();pinUpd(this);"/> | ||||
| <span id="p3d${s}"></span><input type="number" name="L3${s}" class="s" onchange="UI();pinUpd(this);"/> | ||||
| <span id="p4d${s}"></span><input type="number" name="L4${s}" class="s" onchange="UI();pinUpd(this);"/> | ||||
| <div id="dig${s}r" style="display:inline"><br><span id="rev${s}">Reversed</span>: <input type="checkbox" name="CV${s}"></div> | ||||
| <div id="dig${s}s" style="display:inline"><br>Skip first LEDs: <input type="number" name="SL${s}" min="0" max="255" value="0" oninput="UI()"></div> | ||||
| <div id="dig${s}f" style="display:inline"><br>Off Refresh: <input id="rf${s}" type="checkbox" name="RF${s}"></div> | ||||
| <div id="dig${s}a" style="display:inline"><br>Auto-calculate white channel from RGB:<br><select name="AW${s}"><option value=0>None</option><option value=1>Brighter</option><option value=2>Accurate</option><option value=3>Dual</option><option value=4>Max</option></select> </div> | ||||
| </div>`; | ||||
| 				f.insertAdjacentHTML("beforeend", cn); | ||||
| 			} | ||||
| @@ -462,14 +466,14 @@ mA/LED: <select name="LAsel${i}" onchange="enLA(this,${i});UI();"> | ||||
|  | ||||
| 		function addCOM(start=0,len=1,co=0) { | ||||
| 			var i = d.getElementsByClassName("com_entry").length; | ||||
| 			if (i >= 10) return; | ||||
|  | ||||
| 			if (i >= maxCO) return; | ||||
| 			var s = String.fromCharCode((i<10?48:55)+i); | ||||
| 			var b = `<div class="com_entry"> | ||||
| <hr class="sml"> | ||||
| ${i+1}: Start: <input type="number" name="XS${i}" id="xs${i}" class="l starts" min="0" max="65535" value="${start}" oninput="UI();" required="">  | ||||
| Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65535" value="${len}" required="" oninput="UI()"> | ||||
| ${i+1}: Start: <input type="number" name="XS${s}" id="xs${s}" class="l starts" min="0" max="65535" value="${start}" oninput="UI();" required="">  | ||||
| Length: <input type="number" name="XC${s}" id="xc${s}" class="l" min="1" max="65535" value="${len}" required="" oninput="UI()"> | ||||
| <div>Color Order: | ||||
| <select id="xo${i}" name="XO${i}"> | ||||
| <select id="xo${s}" name="XO${s}"> | ||||
| <option value="0">GRB</option> | ||||
| <option value="1">RGB</option> | ||||
| <option value="2">BRG</option> | ||||
| @@ -477,7 +481,7 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65 | ||||
| <option value="4">BGR</option> | ||||
| <option value="5">GBR</option> | ||||
| </select> | ||||
| Swap: <select id="xw${i}" name="XW${i}"> | ||||
| Swap: <select id="xw${s}" name="XW${s}"> | ||||
| <option value="0">Use global</option> | ||||
| <option value="1">W & B</option> | ||||
| <option value="2">W & G</option> | ||||
| @@ -485,8 +489,8 @@ Swap: <select id="xw${i}" name="XW${i}"> | ||||
| </select> | ||||
| </div></div>`; | ||||
| 			gId("com_entries").insertAdjacentHTML("beforeend", b); | ||||
| 			gId("xo"+i).value = co & 0x0F; | ||||
| 			gId("xw"+i).value = co >> 4; | ||||
| 			gId("xo"+s).value = co & 0x0F; | ||||
| 			gId("xw"+s).value = co >> 4; | ||||
| 			btnCOM(i+1); | ||||
| 			UI(); | ||||
| 		} | ||||
| @@ -502,7 +506,7 @@ Swap: <select id="xw${i}" name="XW${i}"> | ||||
|  | ||||
| 		function resetCOM(_newMaxCOOverrides=undefined) { | ||||
| 			if (_newMaxCOOverrides) { | ||||
| 				maxCOOverrides = _newMaxCOOverrides; | ||||
| 				maxCO = _newMaxCOOverrides; | ||||
| 			} | ||||
| 			for (let e of d.getElementsByClassName("com_entry")) { | ||||
| 				e.remove(); | ||||
| @@ -511,16 +515,15 @@ Swap: <select id="xw${i}" name="XW${i}"> | ||||
| 		} | ||||
|  | ||||
| 		function btnCOM(i) { | ||||
| 			gId("com_add").style.display = (i<maxCOOverrides) ? "inline":"none"; | ||||
| 			gId("com_add").style.display = (i<maxCO) ? "inline":"none"; | ||||
| 			gId("com_rem").style.display = (i>0) ? "inline":"none"; | ||||
| 		} | ||||
|  | ||||
| 		function addBtn(i,p,t) { | ||||
| 			var c = gId("btns").innerHTML; | ||||
| 			var bt = "BT" + String.fromCharCode((i<10?48:55)+i); | ||||
| 			var be = "BE" + String.fromCharCode((i<10?48:55)+i); | ||||
| 			c += `Button ${i} GPIO: <input type="number" name="${bt}" onchange="UI()" class="xs" value="${p}">`; | ||||
| 			c += ` <select name="${be}">` | ||||
| 			var s = String.fromCharCode((i<10?48:55)+i); | ||||
| 			c += `Button ${i} GPIO: <input type="number" name="BT${s}" onchange="UI()" class="xs" value="${p}">`; | ||||
| 			c += ` <select name="BE${s}">` | ||||
| 			c += `<option value="0" ${t==0?"selected":""}>Disabled</option>`; | ||||
| 			c += `<option value="2" ${t==2?"selected":""}>Pushbutton</option>`; | ||||
| 			c += `<option value="3" ${t==3?"selected":""}>Push inverted</option>`; | ||||
| @@ -531,7 +534,7 @@ Swap: <select id="xw${i}" name="XW${i}"> | ||||
| 			c += `<option value="8" ${t==8?"selected":""}>Analog inverted</option>`; | ||||
| 			c += `<option value="9" ${t==9?"selected":""}>Touch (switch)</option>`; | ||||
| 			c += `</select>`; | ||||
| 			c += `<span style="cursor: pointer;" onclick="off('${bt}')"> ✕</span><br>`; | ||||
| 			c += `<span style="cursor: pointer;" onclick="off('BT${s}')"> ✕</span><br>`; | ||||
| 			gId("btns").innerHTML = c; | ||||
| 		} | ||||
| 		function tglSi(cs) { | ||||
|   | ||||
| @@ -136,27 +136,28 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) | ||||
|     useGlobalLedBuffer = request->hasArg(F("LD")); | ||||
|  | ||||
|     bool busesChanged = false; | ||||
|     for (uint8_t s = 0; s < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; s++) { | ||||
|       char lp[4] = "L0"; lp[2] = 48+s; lp[3] = 0; //ascii 0-9 //strip data pin | ||||
|       char lc[4] = "LC"; lc[2] = 48+s; lc[3] = 0; //strip length | ||||
|       char co[4] = "CO"; co[2] = 48+s; co[3] = 0; //strip color order | ||||
|       char lt[4] = "LT"; lt[2] = 48+s; lt[3] = 0; //strip type | ||||
|       char ls[4] = "LS"; ls[2] = 48+s; ls[3] = 0; //strip start LED | ||||
|       char cv[4] = "CV"; cv[2] = 48+s; cv[3] = 0; //strip reverse | ||||
|       char sl[4] = "SL"; sl[2] = 48+s; sl[3] = 0; //skip first N LEDs | ||||
|       char rf[4] = "RF"; rf[2] = 48+s; rf[3] = 0; //refresh required | ||||
|       char aw[4] = "AW"; aw[2] = 48+s; aw[3] = 0; //auto white mode | ||||
|       char wo[4] = "WO"; wo[2] = 48+s; wo[3] = 0; //channel swap | ||||
|       char sp[4] = "SP"; sp[2] = 48+s; sp[3] = 0; //bus clock speed (DotStar & PWM) | ||||
|       char la[4] = "LA"; la[2] = 48+s; la[3] = 0; //LED mA | ||||
|       char ma[4] = "MA"; ma[2] = 48+s; ma[3] = 0; //max mA | ||||
|     for (int s = 0; s < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; s++) { | ||||
|       int offset = s < 10 ? 48 : 55; | ||||
|       char lp[4] = "L0"; lp[2] = offset+s; lp[3] = 0; //ascii 0-9 //strip data pin | ||||
|       char lc[4] = "LC"; lc[2] = offset+s; lc[3] = 0; //strip length | ||||
|       char co[4] = "CO"; co[2] = offset+s; co[3] = 0; //strip color order | ||||
|       char lt[4] = "LT"; lt[2] = offset+s; lt[3] = 0; //strip type | ||||
|       char ls[4] = "LS"; ls[2] = offset+s; ls[3] = 0; //strip start LED | ||||
|       char cv[4] = "CV"; cv[2] = offset+s; cv[3] = 0; //strip reverse | ||||
|       char sl[4] = "SL"; sl[2] = offset+s; sl[3] = 0; //skip first N LEDs | ||||
|       char rf[4] = "RF"; rf[2] = offset+s; rf[3] = 0; //refresh required | ||||
|       char aw[4] = "AW"; aw[2] = offset+s; aw[3] = 0; //auto white mode | ||||
|       char wo[4] = "WO"; wo[2] = offset+s; wo[3] = 0; //channel swap | ||||
|       char sp[4] = "SP"; sp[2] = offset+s; sp[3] = 0; //bus clock speed (DotStar & PWM) | ||||
|       char la[4] = "LA"; la[2] = offset+s; la[3] = 0; //LED mA | ||||
|       char ma[4] = "MA"; ma[2] = offset+s; ma[3] = 0; //max mA | ||||
|       if (!request->hasArg(lp)) { | ||||
|         DEBUG_PRINT(F("No data for ")); | ||||
|         DEBUG_PRINTLN(s); | ||||
|         break; | ||||
|       } | ||||
|       for (uint8_t i = 0; i < 5; i++) { | ||||
|         lp[1] = 48+i; | ||||
|       for (int i = 0; i < 5; i++) { | ||||
|         lp[1] = offset+i; | ||||
|         if (!request->hasArg(lp)) break; | ||||
|         pins[i] = (request->arg(lp).length() > 0) ? request->arg(lp).toInt() : 255; | ||||
|       } | ||||
| @@ -210,11 +211,12 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) | ||||
|     //doInitBusses = busesChanged; // we will do that below to ensure all input data is processed | ||||
|  | ||||
|     ColorOrderMap com = {}; | ||||
|     for (uint8_t s = 0; s < WLED_MAX_COLOR_ORDER_MAPPINGS; s++) { | ||||
|       char xs[4] = "XS"; xs[2] = 48+s; xs[3] = 0; //start LED | ||||
|       char xc[4] = "XC"; xc[2] = 48+s; xc[3] = 0; //strip length | ||||
|       char xo[4] = "XO"; xo[2] = 48+s; xo[3] = 0; //color order | ||||
|       char xw[4] = "XW"; xw[2] = 48+s; xw[3] = 0; //W swap | ||||
|     for (int s = 0; s < WLED_MAX_COLOR_ORDER_MAPPINGS; s++) { | ||||
|       int offset = s < 10 ? 48 : 55; | ||||
|       char xs[4] = "XS"; xs[2] = offset+s; xs[3] = 0; //start LED | ||||
|       char xc[4] = "XC"; xc[2] = offset+s; xc[3] = 0; //strip length | ||||
|       char xo[4] = "XO"; xo[2] = offset+s; xo[3] = 0; //color order | ||||
|       char xw[4] = "XW"; xw[2] = offset+s; xw[3] = 0; //W swap | ||||
|       if (request->hasArg(xs)) { | ||||
|         start = request->arg(xs).toInt(); | ||||
|         length = request->arg(xc).toInt(); | ||||
| @@ -249,9 +251,10 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) | ||||
|  | ||||
|     disablePullUp = (bool)request->hasArg(F("IP")); | ||||
|     touchThreshold = request->arg(F("TT")).toInt(); | ||||
|     for (uint8_t i=0; i<WLED_MAX_BUTTONS; i++) { | ||||
|       char bt[4] = "BT"; bt[2] = (i<10?48:55)+i; bt[3] = 0; // button pin (use A,B,C,... if WLED_MAX_BUTTONS>10) | ||||
|       char be[4] = "BE"; be[2] = (i<10?48:55)+i; be[3] = 0; // button type (use A,B,C,... if WLED_MAX_BUTTONS>10) | ||||
|     for (int i = 0; i < WLED_MAX_BUTTONS; i++) { | ||||
|       int offset = i < 10 ? 48 : 55; | ||||
|       char bt[4] = "BT"; bt[2] = offset+i; bt[3] = 0; // button pin (use A,B,C,... if WLED_MAX_BUTTONS>10) | ||||
|       char be[4] = "BE"; be[2] = offset+i; be[3] = 0; // button type (use A,B,C,... if WLED_MAX_BUTTONS>10) | ||||
|       int hw_btn_pin = request->arg(bt).toInt(); | ||||
|       if (hw_btn_pin >= 0 && pinManager.allocatePin(hw_btn_pin,false,PinOwner::Button)) { | ||||
|         btnPin[i] = hw_btn_pin; | ||||
|   | ||||
| @@ -350,7 +350,8 @@ void getSettingsJS(byte subPage, char* dest) | ||||
|     oappend(itoa(WLED_MIN_VIRTUAL_BUSSES,nS,10));  oappend(","); | ||||
|     oappend(itoa(MAX_LEDS_PER_BUS,nS,10)); oappend(","); | ||||
|     oappend(itoa(MAX_LED_MEMORY,nS,10));   oappend(","); | ||||
|     oappend(itoa(MAX_LEDS,nS,10)); | ||||
|     oappend(itoa(MAX_LEDS,nS,10));         oappend(","); | ||||
|     oappend(itoa(WLED_MAX_COLOR_ORDER_MAPPINGS,nS,10)); | ||||
|     oappend(SET_F(");")); | ||||
|  | ||||
|     sappend('c',SET_F("MS"),autoSegments); | ||||
| @@ -362,28 +363,29 @@ void getSettingsJS(byte subPage, char* dest) | ||||
|     sappend('v',SET_F("AW"),Bus::getGlobalAWMode()); | ||||
|     sappend('c',SET_F("LD"),useGlobalLedBuffer); | ||||
|  | ||||
|     uint16_t sumMa = 0; | ||||
|     for (uint8_t s=0; s < BusManager::getNumBusses(); s++) { | ||||
|     unsigned sumMa = 0; | ||||
|     for (int s = 0; s < BusManager::getNumBusses(); s++) { | ||||
|       Bus* bus = BusManager::getBus(s); | ||||
|       if (bus == nullptr) continue; | ||||
|       char lp[4] = "L0"; lp[2] = 48+s; lp[3] = 0; //ascii 0-9 //strip data pin | ||||
|       char lc[4] = "LC"; lc[2] = 48+s; lc[3] = 0; //strip length | ||||
|       char co[4] = "CO"; co[2] = 48+s; co[3] = 0; //strip color order | ||||
|       char lt[4] = "LT"; lt[2] = 48+s; lt[3] = 0; //strip type | ||||
|       char ls[4] = "LS"; ls[2] = 48+s; ls[3] = 0; //strip start LED | ||||
|       char cv[4] = "CV"; cv[2] = 48+s; cv[3] = 0; //strip reverse | ||||
|       char sl[4] = "SL"; sl[2] = 48+s; sl[3] = 0; //skip 1st LED | ||||
|       char rf[4] = "RF"; rf[2] = 48+s; rf[3] = 0; //off refresh | ||||
|       char aw[4] = "AW"; aw[2] = 48+s; aw[3] = 0; //auto white mode | ||||
|       char wo[4] = "WO"; wo[2] = 48+s; wo[3] = 0; //swap channels | ||||
|       char sp[4] = "SP"; sp[2] = 48+s; sp[3] = 0; //bus clock speed | ||||
|       char la[4] = "LA"; la[2] = 48+s; la[3] = 0; //LED current | ||||
|       char ma[4] = "MA"; ma[2] = 48+s; ma[3] = 0; //max per-port PSU current | ||||
|       int offset = s < 10 ? 48 : 55; | ||||
|       char lp[4] = "L0"; lp[2] = offset+s; lp[3] = 0; //ascii 0-9 //strip data pin | ||||
|       char lc[4] = "LC"; lc[2] = offset+s; lc[3] = 0; //strip length | ||||
|       char co[4] = "CO"; co[2] = offset+s; co[3] = 0; //strip color order | ||||
|       char lt[4] = "LT"; lt[2] = offset+s; lt[3] = 0; //strip type | ||||
|       char ls[4] = "LS"; ls[2] = offset+s; ls[3] = 0; //strip start LED | ||||
|       char cv[4] = "CV"; cv[2] = offset+s; cv[3] = 0; //strip reverse | ||||
|       char sl[4] = "SL"; sl[2] = offset+s; sl[3] = 0; //skip 1st LED | ||||
|       char rf[4] = "RF"; rf[2] = offset+s; rf[3] = 0; //off refresh | ||||
|       char aw[4] = "AW"; aw[2] = offset+s; aw[3] = 0; //auto white mode | ||||
|       char wo[4] = "WO"; wo[2] = offset+s; wo[3] = 0; //swap channels | ||||
|       char sp[4] = "SP"; sp[2] = offset+s; sp[3] = 0; //bus clock speed | ||||
|       char la[4] = "LA"; la[2] = offset+s; la[3] = 0; //LED current | ||||
|       char ma[4] = "MA"; ma[2] = offset+s; ma[3] = 0; //max per-port PSU current | ||||
|       oappend(SET_F("addLEDs(1);")); | ||||
|       uint8_t pins[5]; | ||||
|       uint8_t nPins = bus->getPins(pins); | ||||
|       for (uint8_t i = 0; i < nPins; i++) { | ||||
|         lp[1] = 48+i; | ||||
|       int nPins = bus->getPins(pins); | ||||
|       for (int i = 0; i < nPins; i++) { | ||||
|         lp[1] = offset+i; | ||||
|         if (pinManager.isPinOk(pins[i]) || IS_VIRTUAL(bus->getType())) sappend('v',lp,pins[i]); | ||||
|       } | ||||
|       sappend('v',lc,bus->getLength()); | ||||
| @@ -395,7 +397,7 @@ void getSettingsJS(byte subPage, char* dest) | ||||
|       sappend('c',rf,bus->isOffRefreshRequired()); | ||||
|       sappend('v',aw,bus->getAutoWhiteMode()); | ||||
|       sappend('v',wo,bus->getColorOrder() >> 4); | ||||
|       uint16_t speed = bus->getFrequency(); | ||||
|       unsigned speed = bus->getFrequency(); | ||||
|       if (IS_PWM(bus->getType())) { | ||||
|         switch (speed) { | ||||
|           case WLED_PWM_FREQ/2    : speed = 0; break; | ||||
| @@ -428,7 +430,7 @@ void getSettingsJS(byte subPage, char* dest) | ||||
|     oappend(itoa(WLED_MAX_COLOR_ORDER_MAPPINGS,nS,10)); | ||||
|     oappend(SET_F(");")); | ||||
|     const ColorOrderMap& com = BusManager::getColorOrderMap(); | ||||
|     for (uint8_t s=0; s < com.count(); s++) { | ||||
|     for (int s = 0; s < com.count(); s++) { | ||||
|       const ColorOrderMapEntry* entry = com.get(s); | ||||
|       if (entry == nullptr) break; | ||||
|       oappend(SET_F("addCOM(")); | ||||
| @@ -456,7 +458,7 @@ void getSettingsJS(byte subPage, char* dest) | ||||
|     sappend('v',SET_F("RL"),rlyPin); | ||||
|     sappend('c',SET_F("RM"),rlyMde); | ||||
|     sappend('c',SET_F("RO"),rlyOpenDrain); | ||||
|     for (uint8_t i=0; i<WLED_MAX_BUTTONS; i++) { | ||||
|     for (int i = 0; i < WLED_MAX_BUTTONS; i++) { | ||||
|       oappend(SET_F("addBtn(")); | ||||
|       oappend(itoa(i,nS,10)); oappend(","); | ||||
|       oappend(itoa(btnPin[i],nS,10)); oappend(","); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Blaz Kristan
					Blaz Kristan