kopia lustrzana https://github.com/Aircoookie/WLED
				
				
				
			Fix for transitions.
							rodzic
							
								
									d9f2c2b968
								
							
						
					
					
						commit
						588c7a81fc
					
				
							
								
								
									
										70
									
								
								wled00/FX.h
								
								
								
								
							
							
						
						
									
										70
									
								
								wled00/FX.h
								
								
								
								
							|  | @ -88,9 +88,10 @@ uint32_t color_add(uint32_t,uint32_t); | |||
| 
 | ||||
| #define NUM_COLORS       3 /* number of colors per segment */ | ||||
| #define SEGMENT          strip._segments[strip.getCurrSegmentId()] | ||||
| #define SEGENV           strip._segment_runtimes[strip.getCurrSegmentId()] | ||||
| #define SEGENV           strip._segments[strip.getCurrSegmentId()].runtime | ||||
| #define SEGCOLOR(x)      strip.segColor(x) | ||||
| #define SEGLEN           strip._virtualSegmentLength | ||||
| //#define SEGLEN           strip._segments[strip.getCurrSegmentId()].virtualLength()
 | ||||
| #define SEGLEN           strip._virtualSegmentLength  /* saves us a few kbytes of code */ | ||||
| #define SPEED_FORMULA_L  (5U + (50U*(255U - SEGMENT.speed))/SEGLEN) | ||||
| 
 | ||||
| // some common colors
 | ||||
|  | @ -371,7 +372,7 @@ typedef struct ColorTransition { // 20 bytes | |||
|   uint32_t transitionStart; | ||||
|   uint16_t transitionDur; | ||||
| 
 | ||||
|   void startTransition(Segment *seg, uint16_t dur, uint8_t oldBri, uint8_t oldCct, uint32_t *oldCol); | ||||
|   void startTransition(Segment *seg, uint16_t dur); // transition has to start before actual segment values change
 | ||||
|   void handleTransition(Segment *seg, uint8_t &newBri, uint8_t &newCct, uint32_t *newCol); | ||||
|   uint16_t progress(); //transition progression between 0-65535
 | ||||
|   uint8_t currentBri(uint8_t briNew, bool useCct = false); | ||||
|  | @ -381,6 +382,31 @@ typedef struct ColorTransition { // 20 bytes | |||
| } color_transition; | ||||
| 
 | ||||
| 
 | ||||
| // segment runtime parameters
 | ||||
| typedef struct Segmentruntime { // 23 (24 in memory) bytes
 | ||||
|   unsigned long next_time;  // millis() of next update
 | ||||
|   uint32_t step;  // custom "step" var
 | ||||
|   uint32_t call;  // call counter
 | ||||
|   uint16_t aux0;  // custom var
 | ||||
|   uint16_t aux1;  // custom var
 | ||||
|   byte* data = nullptr; | ||||
| 
 | ||||
|   bool allocateData(uint16_t len); | ||||
|   void deallocateData(); | ||||
|   void resetIfRequired(); | ||||
|   /** 
 | ||||
|     * Flags that before the next effect is calculated, | ||||
|     * the internal segment state should be reset.  | ||||
|     * Call resetIfRequired before calling the next effect function. | ||||
|     * Safe to call from interrupts and network requests. | ||||
|     */ | ||||
|   inline void markForReset() { _requiresReset = true; } | ||||
|   private: | ||||
|     uint16_t _dataLen = 0; | ||||
|     bool _requiresReset = false; | ||||
| } segmentruntime; | ||||
| 
 | ||||
| 
 | ||||
| // segment parameters
 | ||||
| typedef struct Segment { // 40 (44 in memory) bytes
 | ||||
|   uint16_t start; // start index / start X coordinate 2D (left)
 | ||||
|  | @ -400,6 +426,7 @@ typedef struct Segment { // 40 (44 in memory) bytes | |||
|   uint16_t startY;  // start Y coodrinate 2D (top)
 | ||||
|   uint16_t stopY;   // stop Y coordinate 2D (bottom)
 | ||||
|   char *name; | ||||
|   segmentruntime  runtime; | ||||
|   color_transition transition; | ||||
| 
 | ||||
|   inline bool     getOption(uint8_t n)   { return ((options >> n) & 0x01); } | ||||
|  | @ -473,32 +500,6 @@ typedef struct Segment { // 40 (44 in memory) bytes | |||
| } segment; | ||||
| 
 | ||||
| 
 | ||||
| // segment runtime parameters
 | ||||
| typedef struct Segment_runtime { // 23 (24 in memory) bytes
 | ||||
|   unsigned long next_time;  // millis() of next update
 | ||||
|   uint32_t step;  // custom "step" var
 | ||||
|   uint32_t call;  // call counter
 | ||||
|   uint16_t aux0;  // custom var
 | ||||
|   uint16_t aux1;  // custom var
 | ||||
|   byte* data = nullptr; | ||||
| 
 | ||||
|   bool allocateData(uint16_t len); | ||||
|   void deallocateData(); | ||||
|   void resetIfRequired(); | ||||
|   /** 
 | ||||
|     * Flags that before the next effect is calculated, | ||||
|     * the internal segment state should be reset.  | ||||
|     * Call resetIfRequired before calling the next effect function. | ||||
|     * Safe to call from interrupts and network requests. | ||||
|     */ | ||||
|   inline void markForReset() { _requiresReset = true; } | ||||
|   private: | ||||
|     uint16_t _dataLen = 0; | ||||
|     bool _requiresReset = false; | ||||
| } segment_runtime; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| // main "strip" class
 | ||||
| class WS2812FX {  // 96 bytes
 | ||||
|   typedef uint16_t (*mode_ptr)(void); // pointer to mode function
 | ||||
|  | @ -562,6 +563,7 @@ class WS2812FX {  // 96 bytes | |||
|     inline void trigger(void) { _triggered = true; } // Forces the next frame to be computed on all active segments.
 | ||||
|     inline void setShowCallback(show_callback cb) { _callback = cb; } | ||||
|     inline void setTransition(uint16_t t) { _transitionDur = t; } | ||||
|     inline void addUsedSegmentData(int16_t size) { _usedSegmentData += size; } | ||||
| 
 | ||||
|     bool | ||||
|       gammaCorrectBri = false, | ||||
|  | @ -605,6 +607,7 @@ class WS2812FX {  // 96 bytes | |||
|     inline uint16_t getMinShowDelay(void) { return MIN_SHOW_DELAY; } | ||||
|     inline uint16_t getLengthTotal(void) { return _length; } | ||||
|     inline uint16_t getTransition(void) { return _transitionDur; } | ||||
|     inline uint16_t getUsedSegmentData(void) { return _usedSegmentData; } | ||||
| 
 | ||||
|     uint32_t | ||||
|       now, | ||||
|  | @ -626,7 +629,6 @@ class WS2812FX {  // 96 bytes | |||
|     inline Segment& getFirstSelectedSeg(void) { return _segments[getFirstSelectedSegId()]; } | ||||
|     inline Segment& getMainSegment(void) { return _segments[getMainSegmentId()]; } | ||||
|     inline Segment* getSegments(void) { return _segments; } | ||||
|     inline Segment_runtime& getSegmentRuntime(uint8_t id) { return _segment_runtimes[id >= MAX_NUM_SEGMENTS ? getMainSegmentId() : id]; } | ||||
| 
 | ||||
|   // 2D support (panels)
 | ||||
|     bool | ||||
|  | @ -672,17 +674,19 @@ class WS2812FX {  // 96 bytes | |||
|     CRGBPalette16 currentPalette; | ||||
|     CRGBPalette16 targetPalette; | ||||
| 
 | ||||
|     uint32_t _colors_t[3]; | ||||
|     uint8_t _bri_t; // used for opacity transitions
 | ||||
|     uint32_t _colors_t[3]; // used for color transitions
 | ||||
|     uint16_t _virtualSegmentLength; | ||||
| 
 | ||||
|     // using public array to reduce code size increase due to inline function getSegment() (with bounds checking)
 | ||||
|     segment _segments[MAX_NUM_SEGMENTS] = { // SRAM footprint: 27 bytes per element
 | ||||
|       // start, stop, offset, speed, intensity, palette, mode, options, grouping, spacing, opacity (unused), color[], capabilities, custom 1, custom 2, custom 3
 | ||||
|       {0, 7, 0, DEFAULT_SPEED, DEFAULT_INTENSITY, 0, DEFAULT_MODE, NO_OPTIONS, 1, 0, 255, {DEFAULT_COLOR}, 0, DEFAULT_C1, DEFAULT_C2, DEFAULT_C3, 0, 1} | ||||
|     }; | ||||
|     friend class Segment; | ||||
| 
 | ||||
|     segment_runtime _segment_runtimes[MAX_NUM_SEGMENTS]; // SRAM footprint: 28 bytes per element
 | ||||
|     friend class Segment_runtime; | ||||
|     //segmentruntime _segmentruntimes[MAX_NUM_SEGMENTS]; // SRAM footprint: 28 bytes per element
 | ||||
|     //friend class Segmentruntime;
 | ||||
| 
 | ||||
|   private: | ||||
|     uint16_t _length; | ||||
|  |  | |||
|  | @ -152,7 +152,7 @@ void IRAM_ATTR Segment::setPixelColorXY(int x, int y, uint32_t col) | |||
| #ifndef WLED_DISABLE_2D | ||||
|   if (!strip.isMatrix) return; // not a matrix set-up
 | ||||
| 
 | ||||
|   uint8_t _bri_t = getOption(SEG_OPTION_TRANSITIONAL) ? transition.briOld : opacity; | ||||
|   uint8_t _bri_t = strip._bri_t; | ||||
|   if (_bri_t < 255) { | ||||
|     byte r = scale8(R(col), _bri_t); | ||||
|     byte g = scale8(G(col), _bri_t); | ||||
|  |  | |||
|  | @ -74,10 +74,12 @@ | |||
| // ColorTransition class implementation
 | ||||
| ///////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| void ColorTransition::startTransition(Segment *seg, uint16_t dur, uint8_t oldBri, uint8_t oldCct, uint32_t *oldCol) { | ||||
|   currentBri(oldBri); | ||||
|   currentBri(oldCct, true); | ||||
|   for (size_t i=0; i<NUM_COLORS; i++) colorOld[i] = currentColor(i, oldCol[i]); | ||||
| void ColorTransition::startTransition(Segment *seg, uint16_t dur) { | ||||
|   // starting a transition has to occur before change
 | ||||
|   if (!seg->isActive()) return; | ||||
|   briOld = currentBri(seg->getOption(SEG_OPTION_ON) ? seg->opacity : 0); | ||||
|   cctOld = currentBri(seg->cct, true); | ||||
|   for (size_t i=0; i<NUM_COLORS; i++) colorOld[i] = currentColor(i, seg->colors[i]); | ||||
|   transitionDur = dur; | ||||
|   transitionStart = millis(); | ||||
|   seg->setOption(SEG_OPTION_TRANSITIONAL, true); | ||||
|  | @ -92,16 +94,23 @@ uint16_t ColorTransition::progress() { //transition progression between 0-65535 | |||
| 
 | ||||
| uint8_t ColorTransition::currentBri(uint8_t briNew, bool useCct) { | ||||
|   uint32_t prog = progress() + 1; | ||||
|   if (useCct) return cctOld = ((briNew * prog) + cctOld * (0x10000 - prog)) >> 16; | ||||
|   else        return briOld = ((briNew * prog) + briOld * (0x10000 - prog)) >> 16; | ||||
|   if (useCct) return ((briNew * prog) + cctOld * (0x10000 - prog)) >> 16; | ||||
|   else        return ((briNew * prog) + briOld * (0x10000 - prog)) >> 16; | ||||
| } | ||||
| 
 | ||||
| void ColorTransition::handleTransition(Segment *seg, uint8_t &newBri, uint8_t &newCct, uint32_t *newCol) { | ||||
|   if (!seg->getOption(SEG_OPTION_TRANSITIONAL)) return; // if segment is not transitioning
 | ||||
|   newBri = currentBri(seg->opacity); | ||||
|   newCct = currentBri(seg->cct, true); | ||||
|   for (size_t i=0; i<NUM_COLORS; i++) newCol[i] = currentColor(i, seg->colors[i]); | ||||
|   if (progress() == 0xFFFFU) seg->setOption(SEG_OPTION_TRANSITIONAL, false); | ||||
|   newBri = currentBri(newBri); | ||||
|   newCct = currentBri(newCct, true); | ||||
|   for (size_t i=0; i<NUM_COLORS; i++) newCol[i] = currentColor(i, newCol[i]); | ||||
|   unsigned long maxWait = millis() + 22; | ||||
|   if (seg->mode == FX_MODE_STATIC && seg->runtime.next_time > maxWait) seg->runtime.next_time = maxWait; | ||||
|   if (progress() == 0xFFFFU && seg->getOption(SEG_OPTION_TRANSITIONAL)) { | ||||
|     // finish transition
 | ||||
|     briOld = newBri; | ||||
|     cctOld = newCct; | ||||
|     for (size_t i=0; i<NUM_COLORS; i++) colorOld[i] = newCol[i]; | ||||
|     seg->setOption(SEG_OPTION_TRANSITIONAL, false); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -111,7 +120,7 @@ void ColorTransition::handleTransition(Segment *seg, uint8_t &newBri, uint8_t &n | |||
| 
 | ||||
| bool Segment::setColor(uint8_t slot, uint32_t c) { //returns true if changed
 | ||||
|   if (slot >= NUM_COLORS || c == colors[slot]) return false; | ||||
|   transition.startTransition(this, strip.getTransition(), opacity, cct, colors); | ||||
|   transition.startTransition(this, strip.getTransition()); // start transition prior to change
 | ||||
|   colors[slot] = c; | ||||
|   return true; | ||||
| } | ||||
|  | @ -123,26 +132,21 @@ void Segment::setCCT(uint16_t k) { | |||
|     k = (k - 1900) >> 5; | ||||
|   } | ||||
|   if (cct == k) return; | ||||
|   transition.startTransition(this, strip.getTransition(), opacity, cct, colors); | ||||
|   transition.startTransition(this, strip.getTransition()); // start transition prior to change
 | ||||
|   cct = k; | ||||
| } | ||||
| 
 | ||||
| void Segment::setOpacity(uint8_t o) { | ||||
|   if (opacity == o) return; | ||||
|   transition.startTransition(this, strip.getTransition(), opacity, cct, colors); | ||||
|   transition.startTransition(this, strip.getTransition()); // start transition prior to change
 | ||||
|   opacity = o; | ||||
| } | ||||
| 
 | ||||
| void Segment::setOption(uint8_t n, bool val) { | ||||
|   bool prevOn = getOption(SEG_OPTION_ON); | ||||
|   if (n == SEG_OPTION_ON && !val && prevOn) { // fade out (off)
 | ||||
|     transition.startTransition(this, strip.getTransition(), opacity, cct, colors); | ||||
|   } | ||||
|   if (n == SEG_OPTION_ON && val != prevOn) transition.startTransition(this, strip.getTransition()); // start transition prior to change
 | ||||
|   if (val) options |=   0x01 << n; | ||||
|   else     options &= ~(0x01 << n); | ||||
|   if (n == SEG_OPTION_ON && val && !prevOn) { // fade in (on)
 | ||||
|     transition.startTransition(this, strip.getTransition(), opacity, cct, colors); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // 2D matrix
 | ||||
|  | @ -180,7 +184,7 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col) | |||
|   } | ||||
| 
 | ||||
|   uint16_t len = length(); | ||||
|   uint8_t _bri_t = getOption(SEG_OPTION_TRANSITIONAL) ? transition.briOld : opacity; | ||||
|   uint8_t _bri_t = strip._bri_t; | ||||
|   if (_bri_t < 255) { | ||||
|     byte r = scale8(R(col), _bri_t); | ||||
|     byte g = scale8(G(col), _bri_t); | ||||
|  | @ -484,14 +488,13 @@ uint32_t IRAM_ATTR Segment::color_from_palette(uint16_t i, bool mapping, bool wr | |||
| 
 | ||||
| 
 | ||||
| ///////////////////////////////////////////////////////////////////////////////
 | ||||
| // Segment_runtime class implementation
 | ||||
| // Segmentruntime class implementation
 | ||||
| ///////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| bool Segment_runtime::allocateData(uint16_t len){ | ||||
| bool Segmentruntime::allocateData(uint16_t len){ | ||||
|   if (data && _dataLen == len) return true; //already allocated
 | ||||
|   WS2812FX *instance = WS2812FX::getInstance(); | ||||
|   deallocateData(); | ||||
|   if (instance->_usedSegmentData + len > MAX_SEGMENT_DATA) return false; //not enough memory
 | ||||
|   if (strip.getUsedSegmentData() + len > MAX_SEGMENT_DATA) return false; //not enough memory
 | ||||
|   // if possible use SPI RAM on ESP32
 | ||||
|   #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM) | ||||
|   if (psramFound()) | ||||
|  | @ -500,16 +503,16 @@ bool Segment_runtime::allocateData(uint16_t len){ | |||
|   #endif | ||||
|     data = (byte*) malloc(len); | ||||
|   if (!data) return false; //allocation failed
 | ||||
|   instance->_usedSegmentData += len; | ||||
|   strip.addUsedSegmentData(len); | ||||
|   _dataLen = len; | ||||
|   memset(data, 0, len); | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| void Segment_runtime::deallocateData() { | ||||
| void Segmentruntime::deallocateData() { | ||||
|   free(data); | ||||
|   data = nullptr; | ||||
|   WS2812FX::getInstance()->_usedSegmentData -= _dataLen; | ||||
|   strip.addUsedSegmentData(-(int16_t)_dataLen); | ||||
|   _dataLen = 0; | ||||
| } | ||||
| 
 | ||||
|  | @ -520,7 +523,7 @@ void Segment_runtime::deallocateData() { | |||
|   * because it could access the data buffer and this method  | ||||
|   * may free that data buffer. | ||||
|   */ | ||||
| void Segment_runtime::resetIfRequired() { | ||||
| void Segmentruntime::resetIfRequired() { | ||||
|   if (_requiresReset) { | ||||
|     next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0;  | ||||
|     deallocateData(); | ||||
|  | @ -538,8 +541,8 @@ void WS2812FX::finalizeInit(void) | |||
| { | ||||
|   //reset segment runtimes
 | ||||
|   for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) { | ||||
|     _segment_runtimes[i].markForReset(); | ||||
|     _segment_runtimes[i].resetIfRequired(); | ||||
|     _segments[i].runtime.markForReset(); | ||||
|     _segments[i].runtime.resetIfRequired(); | ||||
|   } | ||||
| 
 | ||||
|   _hasWhiteChannel = _isOffRefreshRequired = false; | ||||
|  | @ -598,29 +601,29 @@ void WS2812FX::service() { | |||
|     //if (realtimeMode && useMainSegmentOnly && i == getMainSegmentId()) continue;
 | ||||
| 
 | ||||
|     _segment_index = i; | ||||
|     Segment &seg = _segments[_segment_index]; | ||||
| 
 | ||||
|     // reset the segment runtime data if needed, called before isActive to ensure deleted
 | ||||
|     // segment's buffers are cleared
 | ||||
|     _segment_runtimes[_segment_index].resetIfRequired(); | ||||
|     seg.runtime.resetIfRequired(); | ||||
| 
 | ||||
|     if (!_segments[_segment_index].isActive()) continue; | ||||
|     if (!seg.isActive()) continue; | ||||
| 
 | ||||
|     // last condition ensures all solid segments are updated at the same time
 | ||||
|     if(nowUp > _segment_runtimes[_segment_index].next_time || _triggered || (doShow && _segments[_segment_index].mode == 0)) | ||||
|     if(nowUp > seg.runtime.next_time || _triggered || (doShow && seg.mode == FX_MODE_STATIC)) | ||||
|     { | ||||
|       if (_segments[_segment_index].grouping == 0) _segments[_segment_index].grouping = 1; //sanity check
 | ||||
|       if (seg.grouping == 0) seg.grouping = 1; //sanity check
 | ||||
|       doShow = true; | ||||
|       uint16_t delay = FRAMETIME; | ||||
| 
 | ||||
|       if (!_segments[_segment_index].getOption(SEG_OPTION_FREEZE)) { //only run effect function if not frozen
 | ||||
|         Segment &seg = _segments[_segment_index]; | ||||
|       if (!seg.getOption(SEG_OPTION_FREEZE)) { //only run effect function if not frozen
 | ||||
|         _virtualSegmentLength = seg.virtualLength(); | ||||
|         uint8_t _bri_t = seg.getOption(SEG_OPTION_ON) ? seg.opacity : 0; | ||||
|         _bri_t = seg.getOption(SEG_OPTION_ON) ? seg.opacity : 0; | ||||
|         uint8_t _cct_t = seg.cct; | ||||
|         _colors_t[0] = seg.colors[0]; | ||||
|         _colors_t[1] = seg.colors[1]; | ||||
|         _colors_t[2] = seg.colors[2]; | ||||
|         if (seg.getOption(SEG_OPTION_TRANSITIONAL)) seg.transition.handleTransition(&seg, _bri_t, _cct_t, _colors_t); | ||||
|         seg.transition.handleTransition(&seg, _bri_t, _cct_t, _colors_t); | ||||
| 
 | ||||
|         if (!cctFromRgb || correctWB) busses.setSegmentCCT(_cct_t, correctWB); | ||||
|         for (uint8_t c = 0; c < NUM_COLORS; c++) { | ||||
|  | @ -629,10 +632,10 @@ void WS2812FX::service() { | |||
|         handle_palette(); | ||||
| 
 | ||||
|         delay = (*_mode[seg.mode])(); | ||||
|         if (seg.mode != FX_MODE_HALLOWEEN_EYES) _segment_runtimes[_segment_index].call++; | ||||
|         if (seg.mode != FX_MODE_HALLOWEEN_EYES) seg.runtime.call++; | ||||
|       } | ||||
| 
 | ||||
|       _segment_runtimes[_segment_index].next_time = nowUp + delay; | ||||
|       seg.runtime.next_time = nowUp + delay; | ||||
|     } | ||||
|   } | ||||
|   _virtualSegmentLength = 0; | ||||
|  | @ -650,34 +653,43 @@ void WS2812FX::setPixelColor(int i, uint32_t col) | |||
| 
 | ||||
|   // if realtime mode is active and applying to main segment
 | ||||
|   if (realtimeMode && useMainSegmentOnly) { | ||||
|     uint16_t len = _segments[_mainSegment].length();  // length of segment in number of pixels
 | ||||
|     Segment &seg = _segments[_mainSegment]; | ||||
|     uint16_t len = seg.length();  // length of segment in number of pixels
 | ||||
| 
 | ||||
|     if (seg.opacity < 255) { | ||||
|       byte r = scale8(R(col), seg.opacity); | ||||
|       byte g = scale8(G(col), seg.opacity); | ||||
|       byte b = scale8(B(col), seg.opacity); | ||||
|       byte w = scale8(W(col), seg.opacity); | ||||
|       col = RGBW32(r, g, b, w); | ||||
|     } | ||||
| 
 | ||||
|     // get physical pixel address (taking into account start, grouping, spacing [and offset])
 | ||||
|     i = i * _segments[_mainSegment].groupLength(); | ||||
|     if (_segments[_mainSegment].getOption(SEG_OPTION_REVERSED)) { // is segment reversed?
 | ||||
|       if (_segments[_mainSegment].getOption(SEG_OPTION_MIRROR)) { // is segment mirrored?
 | ||||
|     i = i * seg.groupLength(); | ||||
|     if (seg.getOption(SEG_OPTION_REVERSED)) { // is segment reversed?
 | ||||
|       if (seg.getOption(SEG_OPTION_MIRROR)) { // is segment mirrored?
 | ||||
|         i = (len - 1) / 2 - i;  //only need to index half the pixels
 | ||||
|       } else { | ||||
|         i = (len - 1) - i; | ||||
|       } | ||||
|     } | ||||
|     i += _segments[_mainSegment].start; // starting pixel in a group
 | ||||
|     i += seg.start; // starting pixel in a group
 | ||||
| 
 | ||||
|     // set all the pixels in the group
 | ||||
|     for (uint16_t j = 0; j < _segments[_mainSegment].grouping; j++) { | ||||
|       uint16_t indexSet = i + ((_segments[_mainSegment].getOption(SEG_OPTION_REVERSED)) ? -j : j); | ||||
|       if (indexSet >= _segments[_mainSegment].start && indexSet < _segments[_mainSegment].stop) { | ||||
|     for (uint16_t j = 0; j < seg.grouping; j++) { | ||||
|       uint16_t indexSet = i + ((seg.getOption(SEG_OPTION_REVERSED)) ? -j : j); | ||||
|       if (indexSet >= seg.start && indexSet < seg.stop) { | ||||
| 
 | ||||
|         if (_segments[_mainSegment].getOption(SEG_OPTION_MIRROR)) { //set the corresponding mirrored pixel
 | ||||
|           uint16_t indexMir = _segments[_mainSegment].stop - indexSet + _segments[_mainSegment].start - 1;           | ||||
|           indexMir += _segments[_mainSegment].offset; // offset/phase
 | ||||
|           if (indexMir >= _segments[_mainSegment].stop) indexMir -= len; // wrap
 | ||||
|         if (seg.getOption(SEG_OPTION_MIRROR)) { //set the corresponding mirrored pixel
 | ||||
|           uint16_t indexMir = seg.stop - indexSet + seg.start - 1;           | ||||
|           indexMir += seg.offset; // offset/phase
 | ||||
|           if (indexMir >= seg.stop) indexMir -= len; // wrap
 | ||||
|           if (indexMir < customMappingSize) indexMir = customMappingTable[indexMir]; | ||||
| 
 | ||||
|           busses.setPixelColor(indexMir, col); | ||||
|         } | ||||
|         indexSet += _segments[_mainSegment].offset; // offset/phase
 | ||||
|         if (indexSet >= _segments[_mainSegment].stop) indexSet -= len; // wrap
 | ||||
|         indexSet += seg.offset; // offset/phase
 | ||||
|         if (indexSet >= seg.stop) indexSet -= len; // wrap
 | ||||
|         if (indexSet < customMappingSize) indexSet = customMappingTable[indexSet]; | ||||
| 
 | ||||
|         busses.setPixelColor(indexSet, col); | ||||
|  | @ -832,7 +844,7 @@ void WS2812FX::setMode(uint8_t segid, uint8_t m) { | |||
| 
 | ||||
|   if (_segments[segid].mode != m)  | ||||
|   { | ||||
|     _segment_runtimes[segid].markForReset(); | ||||
|     _segments[segid].runtime.markForReset(); | ||||
|     _segments[segid].mode = m; | ||||
|   } | ||||
| } | ||||
|  | @ -873,7 +885,7 @@ void WS2812FX::setBrightness(uint8_t b, bool direct) { | |||
|     busses.setBrightness(b); | ||||
|   } else { | ||||
| 	  unsigned long t = millis(); | ||||
|     if (_segment_runtimes[0].next_time > t + 22 && t - _lastShow > MIN_SHOW_DELAY) show(); //apply brightness change immediately if no refresh soon
 | ||||
|     if (_segments[0].runtime.next_time > t + 22 && t - _lastShow > MIN_SHOW_DELAY) show(); //apply brightness change immediately if no refresh soon
 | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  | @ -1003,13 +1015,13 @@ void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, | |||
|     seg.spacing = spacing; | ||||
|   } | ||||
| 	if (offset < UINT16_MAX) seg.offset = offset; | ||||
|   _segment_runtimes[n].markForReset(); | ||||
|   _segments[n].runtime.markForReset(); | ||||
|   if (!boundsUnchanged) seg.refreshLightCapabilities(); | ||||
| } | ||||
| 
 | ||||
| void WS2812FX::restartRuntime() { | ||||
|   for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) { | ||||
|     _segment_runtimes[i].markForReset(); | ||||
|     _segments[i].runtime.markForReset(); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  | @ -1017,7 +1029,7 @@ void WS2812FX::resetSegments() { | |||
|   for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) if (_segments[i].name) delete[] _segments[i].name; | ||||
|   _mainSegment = 0; | ||||
|   memset(_segments, 0, sizeof(_segments)); | ||||
|   //memset(_segment_runtimes, 0, sizeof(_segment_runtimes));
 | ||||
|   //memset(_segmentruntimes, 0, sizeof(_segmentruntimes));
 | ||||
|   _segment_index = 0; | ||||
|   _segments[0].mode = DEFAULT_MODE; | ||||
|   _segments[0].colors[0] = DEFAULT_COLOR; | ||||
|  | @ -1046,9 +1058,9 @@ void WS2812FX::resetSegments() { | |||
|     _segments[i].custom1 = DEFAULT_C1; | ||||
|     _segments[i].custom2 = DEFAULT_C2; | ||||
|     _segments[i].custom3 = DEFAULT_C3; | ||||
|     _segment_runtimes[i].markForReset(); | ||||
|     _segments[i].runtime.markForReset(); | ||||
|   } | ||||
|   _segment_runtimes[0].markForReset(); | ||||
|   _segments[0].runtime.markForReset(); | ||||
| } | ||||
| 
 | ||||
| void WS2812FX::makeAutoSegments(bool forceReset) { | ||||
|  | @ -1143,7 +1155,7 @@ uint8_t WS2812FX::setPixelSegment(uint8_t n) | |||
|   uint8_t prevSegId = _segment_index; | ||||
|   if (n < MAX_NUM_SEGMENTS) { | ||||
|     _segment_index = n; | ||||
|     //_virtualSegmentLength = _segments[_segment_index].virtualLength();
 | ||||
|     _virtualSegmentLength = _segments[_segment_index].virtualLength(); | ||||
|   } | ||||
|   return prevSegId; | ||||
| } | ||||
|  | @ -1161,13 +1173,19 @@ void WS2812FX::setRange(uint16_t i, uint16_t i2, uint32_t col) | |||
| 
 | ||||
| void WS2812FX::setTransitionMode(bool t) | ||||
| { | ||||
| 	unsigned long waitMax = millis() + 20; //refresh after 20 ms if transition enabled
 | ||||
| 	unsigned long waitMax = millis() + 22; //refresh after 20 ms if transition enabled
 | ||||
|   for (uint16_t i = 0; i < MAX_NUM_SEGMENTS; i++) | ||||
|   { | ||||
|     _segments[i].setOption(SEG_OPTION_TRANSITIONAL, t); | ||||
| 
 | ||||
|     if (t && _segments[i].mode == FX_MODE_STATIC && _segment_runtimes[i].next_time > waitMax) | ||||
| 			_segment_runtimes[i].next_time = waitMax; | ||||
|     if (_segments[i].isActive() && !_segments[i].getOption(SEG_OPTION_TRANSITIONAL)) { | ||||
|       if (t) { | ||||
|         _segments[i].transition.transitionStart = millis(); | ||||
|         _segments[i].transition.transitionDur = strip.getTransition(); | ||||
|       } | ||||
|       _segments[i].setOption(SEG_OPTION_TRANSITIONAL, t); | ||||
|       if (t && _segments[i].mode == FX_MODE_STATIC && _segments[i].runtime.next_time > waitMax) { | ||||
|         _segments[i].runtime.next_time = waitMax; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  | @ -1295,7 +1313,7 @@ void WS2812FX::handle_palette(void) | |||
|       load_gradient_palette(paletteIndex -13); | ||||
|   } | ||||
|    | ||||
|   if (singleSegmentMode && paletteFade && _segment_runtimes[_segment_index].call > 0) //only blend if just one segment uses FastLED mode
 | ||||
|   if (singleSegmentMode && paletteFade && _segments[_segment_index].runtime.call > 0) //only blend if just one segment uses FastLED mode
 | ||||
|   { | ||||
|     nblendPaletteTowardPalette(currentPalette, targetPalette, 48); | ||||
|   } else | ||||
|  |  | |||
|  | @ -712,7 +712,7 @@ void initIR() | |||
| 
 | ||||
| void handleIR() | ||||
| { | ||||
|   if (irEnabled > 0 && millis() - irCheckedTime > 120) | ||||
|   if (irEnabled > 0 && millis() - irCheckedTime > 120 && !strip.isUpdating()) | ||||
|   { | ||||
|     irCheckedTime = millis(); | ||||
|     if (irEnabled > 0) | ||||
|  |  | |||
|  | @ -154,6 +154,7 @@ void initServer() | |||
|   }); | ||||
| 
 | ||||
|   server.on("/json", HTTP_GET, [](AsyncWebServerRequest *request){ | ||||
|     while (strip.isUpdating()) delay(1); | ||||
|     serveJson(request); | ||||
|   }); | ||||
| 
 | ||||
|  | @ -161,6 +162,8 @@ void initServer() | |||
|     bool verboseResponse = false; | ||||
|     bool isConfig = false; | ||||
| 
 | ||||
|     while (strip.isUpdating()) delay(1); | ||||
| 
 | ||||
|     if (!requestJSONBufferLock(14)) return; | ||||
| 
 | ||||
|     DeserializationError error = deserializeJson(doc, (uint8_t*)(request->_tempObject)); | ||||
|  |  | |||
|  | @ -96,7 +96,7 @@ void sendDataWs(AsyncWebSocketClient * client) | |||
|   if (!ws.count()) return; | ||||
|   AsyncWebSocketMessageBuffer * buffer; | ||||
| 
 | ||||
|   while (strip.isUpdating()) yield(); | ||||
|   while (strip.isUpdating()) delay(1); | ||||
|    | ||||
|   if (!requestJSONBufferLock(12)) return; | ||||
| 
 | ||||
|  |  | |||
		Ładowanie…
	
		Reference in New Issue
	
	 Blaz Kristan
						Blaz Kristan