62#ifndef SBK_BARDRIVE_WITH_ANIM
63#pragma message(" ⚠️ SBK_BARDRIVE_WITH_ANIM is not defined. SBK BarDrive Built-in animations are disabled and cannot be accessed, saving memory if they are not needed. If you do need the animations library, define SBK_BARDRIVE_WITH_ANIM before including SBK_BarDrive.h.")
68#if !defined(SBK_MAX72xx_IS_DEFINED) && !defined(SBK_HT16K33_IS_DEFINED)
69#pragma message(" ⚠️ SBK BarDrive library note: Include an SBK_MAX72xx or SBK_HT16K33 driver header and declare a driver before creating a bar meter instance.")
73#ifdef SBK_BARDRIVE_WITH_ANIM
124template <
typename DriverT>
145 uint8_t rowOffset = 0,
146 uint8_t colOffset = 0)
148 _devIdx(constrain(devIdx, 0, 7)),
149 _matrixPreset(matrixPreset),
150 _direction(direction)
152 _isMatrixMapped =
true;
153 if (_devIdx > (driver->devsNum() - 1))
155 _initializePresetMapping(MatrixPreset::NONE);
164 _initializePresetMapping(matrixPreset);
165 _rowOffset = constrain(rowOffset, 0, _driver->maxRows(_devIdx) - 1);
166 _colOffset = constrain(colOffset, 0, _driver->maxColumns() - 1);
194 uint8_t rowOffset = 0,
195 uint8_t colOffset = 0)
197 _devIdx(constrain(devIdx, 0, 7)),
198 _direction(direction)
200 _isMatrixMapped =
true;
201 if (_devIdx > (driver->devsNum() - 1))
211 _rowsNum = constrain(rowsNum, 1, 255);
212 _colsNum = constrain(colsNum, 1, driver->maxColumns());
213 _segsNum = _rowsNum * _colsNum;
214 _rowOffset = constrain(rowOffset, 0, _driver->maxRows(_devIdx) - 1);
215 _colOffset = constrain(colOffset, 0, _driver->maxColumns() - 1);
240 uint8_t segOffset = 0)
242 _devIdx(constrain(devIdx, 0, 7)),
243 _direction(direction),
246 _isMatrixMapped =
false;
247 if (_devIdx > (driver->devsNum() - 1))
256 _rowsNum = _driver->maxRows(_devIdx);
257 _colsNum = _driver->maxColumns();
258 _segOffset = constrain(segOffset, 0, _driver->maxSegments(_devIdx) - 1);
285 const uint8_t (&mapping)[N][3],
287 bool progmem =
false,
288 uint8_t rowOffset = 0,
289 uint8_t colOffset = 0)
291 _devIdx(constrain(devIdx, 0, 7)),
292 _customMapping(mapping),
293 _direction(direction),
294 _userMappingIsProgmem(progmem)
296 _isMatrixMapped =
true;
297 if (_devIdx > (driver->devsNum() - 1))
308 _rowsNum = _driver->maxRows(_devIdx);
309 _colsNum = _driver->maxColumns();
310 _rowOffset = constrain(rowOffset, 0, _driver->maxRows(_devIdx) - 1);
311 _colOffset = constrain(colOffset, 0, _driver->maxColumns() - 1);
326 void show() { _driver->show(); }
333 for (uint8_t i = 0; i < _segsNum; ++i)
370 for (uint8_t i = 0; i < _segsNum; ++i)
372 uint8_t devIdx = _devIdx;
373 uint8_t rowIdx, colIdx;
374 _getMappedDevRowCol(i, &devIdx, &rowIdx, &colIdx);
375 stream.print(F(
"Segment "));
377 stream.print(F(
" → Device "));
378 stream.print(devIdx);
379 stream.print(F(
", Row "));
380 stream.print(rowIdx);
381 stream.print(F(
", Col "));
382 stream.println(colIdx);
399 if (segment >= _segsNum || !_driver)
402 uint8_t devIdx = _devIdx;
403 uint8_t rowIdx, colIdx;
404 _getMappedDevRowCol(segment, &devIdx, &rowIdx, &colIdx);
405 _driver->setLed(devIdx, rowIdx, colIdx, state != 0);
422 if (segment >= _segsNum || !_driver)
425 uint8_t devIdx = _devIdx;
426 uint8_t rowIdx, colIdx;
428 _getMappedDevRowCol(segment, &devIdx, &rowIdx, &colIdx);
429 return _driver->getLed(devIdx, rowIdx, colIdx);
459 _rowOffset = rowOffset;
460 _colOffset = colOffset;
465 void _initializePresetMapping(
MatrixPreset matrixPreset)
473 switch (matrixPreset)
476 _rowsNum = _driver->maxRows(_devIdx);
477 _colsNum = _driver->maxColumns();
478 _segsNum = _rowsNum * _colsNum;
479 _isMatrixMapped =
false;
485 _isMatrixMapped =
true;
491 _isMatrixMapped =
true;
494 _rowsNum = _driver->maxRows(_devIdx);
495 _colsNum = _driver->maxColumns();
496 _segsNum = _rowsNum * _colsNum;
497 _isMatrixMapped =
false;
502 void _getMappedDevRowCol(uint8_t seg, uint8_t *devIdx, uint8_t *rowIdx, uint8_t *colIdx)
const
506 ? (_segsNum - 1 - seg)
510 mappedSeg += (_isMatrixMapped ? 0 : _segOffset);
515 if (_userMappingIsProgmem)
517 *devIdx = pgm_read_byte(&_customMapping[mappedSeg][0]);
518 *rowIdx = pgm_read_byte(&_customMapping[mappedSeg][1]);
519 *colIdx = pgm_read_byte(&_customMapping[mappedSeg][2]);
523 *devIdx = _customMapping[mappedSeg][0];
524 *rowIdx = _customMapping[mappedSeg][1] + _rowOffset;
525 *colIdx = _customMapping[mappedSeg][2] + _colOffset;
532 const uint8_t segPerDev = _driver->maxRows(*devIdx) * _driver->maxColumns();
533 const uint8_t baseDevIdx = *devIdx + (mappedSeg / segPerDev);
534 const uint8_t localIdx = mappedSeg % segPerDev;
539 uint8_t baseRowIdx = localIdx % _rowsNum;
540 uint8_t baseColIdx = localIdx / _rowsNum;
542 *devIdx = baseDevIdx;
543 *rowIdx = baseRowIdx + _rowOffset;
544 *colIdx = baseColIdx + _colOffset;
549 uint8_t baseRowIdx = localIdx / _driver->maxColumns();
550 uint8_t baseColIdx = localIdx % _driver->maxColumns();
552 *devIdx = baseDevIdx;
553 *rowIdx = baseRowIdx;
554 *colIdx = baseColIdx;
559 const uint8_t _devIdx;
561 const uint8_t (*_customMapping)[3] =
nullptr;
563 uint8_t _segOffset = 0;
564 uint8_t _rowOffset = 0;
565 uint8_t _colOffset = 0;
566 bool _isMatrixMapped =
false;
568 uint8_t _rowsNum = 0;
569 uint8_t _colsNum = 0;
570 bool _userMappingIsProgmem =
false;
589template <
typename DriverT>
610 uint8_t rowOffset = 0,
611 uint8_t colOffset = 0)
612 : _barMeter(driver, devIdx, matrixPreset, direction, rowOffset, colOffset)
613#ifdef SBK_BARDRIVE_WITH_ANIM
615 _barAnimations(_barMeter)
618#ifdef SBK_BARDRIVE_WITH_ANIM
619 _barAnimations.setSegsNum(_barMeter.getSegsNum());
647 uint8_t rowOffset = 0,
648 uint8_t colOffset = 0)
649 : _barMeter(driver, devIdx, rowsNum, colsNum, direction, rowOffset, colOffset)
650#ifdef SBK_BARDRIVE_WITH_ANIM
652 _barAnimations(_barMeter)
655#ifdef SBK_BARDRIVE_WITH_ANIM
656 _barAnimations.setSegsNum(_barMeter.getSegsNum());
681 uint8_t segOffset = 0)
682 : _barMeter(driver, devIdx, segsNum, direction, segOffset)
683#ifdef SBK_BARDRIVE_WITH_ANIM
685 _barAnimations(_barMeter)
688#ifdef SBK_BARDRIVE_WITH_ANIM
689 _barAnimations.setSegsNum(_barMeter.getSegsNum());
716 const uint8_t (&mapping)[N][3],
718 bool progmem =
false,
719 uint8_t rowOffset = 0,
720 uint8_t colOffset = 0)
721 : _barMeter(driver, devIdx, mapping, direction, progmem, rowOffset, colOffset)
722#ifdef SBK_BARDRIVE_WITH_ANIM
724 _barAnimations(_barMeter)
727#ifdef SBK_BARDRIVE_WITH_ANIM
728 _barAnimations.setSegsNum(_barMeter.getSegsNum());
739#ifdef SBK_BARDRIVE_WITH_ANIM
756 void show() { _barMeter.show(); }
806 void setPixel(uint8_t segment, uint8_t state) { _barMeter.setPixel(segment, state); }
820 uint8_t
getPixelState(uint8_t segment) {
return _barMeter.getPixelState(segment); }
855#ifdef SBK_BARDRIVE_WITH_ANIM
MatrixPreset
Enables built-in animation support for SBK_BarDrive.
@ SBK_BarMeter_SA28
Alias for SBK BarMeter SA28, uses the BL28_3005SA preset internally.
@ BL28_3005SK
Native mapping for BL28-3005SK (4 anodes × 7 cathodes), common cathode.
@ SBK_BarMeter_SK28
Alias for SBK BarMeter SK28, uses the BL28_3005SK preset internally.
@ NONE
No preset selected; manual segment mapping is required.
@ BL28_3005SA
Native mapping for BL28-3005SA (7 anodes × 4 cathodes), common anode.
BarDirection
Direction of bar fill or animation progression.
@ REVERSE
From last segment to first.
@ FORWARD
From first segment to last.
Built-in animation engine for SBK_BarMeter-based LED displays.
SBK_BarDrive(DriverT *driver, uint8_t devIdx, const uint8_t(&mapping)[N][3], BarDirection direction=BarDirection::FORWARD, bool progmem=false, uint8_t rowOffset=0, uint8_t colOffset=0)
Construct a SBK_BarDrive using a custom pixel mapping array.
void clear()
Clear all bar segments.
uint8_t getPixelState(uint8_t segment)
Get the current state of a bar segment (pixel).
uint8_t getSegsNum()
Get the total number of segments in the bar.
void show()
Push the current LED state buffer to the physical display.
void setDirection(BarDirection dir)
Set the bar fill direction.
SBK_BarDrive(DriverT *driver, uint8_t devIdx, MatrixPreset matrixPreset, BarDirection direction=BarDirection::FORWARD, uint8_t rowOffset=0, uint8_t colOffset=0)
Construct a SBK_BarDrive using a predefined matrix-style layout.
void setPixel(uint8_t segment, uint8_t state)
Set the on/off state of a logical segment (LED).
SBK_BarDrive & setSegmentOffset(uint8_t offset)
Apply a segment-wise offset (shifts segment index before mapping to row/col).
SBK_BarDrive & setMatrixOffset(uint8_t rowOffset, uint8_t colOffset)
Apply a matrix-style physical offset for row/column positioning.
SBK_BarDrive(DriverT *driver, uint8_t devIdx, uint8_t segsNum, BarDirection direction=BarDirection::FORWARD, uint8_t segOffset=0)
Construct a SBK_BarDrive with a fixed number of vertical segments (non-matrix layout).
void debugSegmentMapping(Stream &stream=Serial)
Print the segment-to-device mapping for debugging purposes.
SBK_BarDrive(DriverT *driver, uint8_t devIdx, uint8_t rowsNum, uint8_t colsNum, BarDirection direction=BarDirection::FORWARD, uint8_t rowOffset=0, uint8_t colOffset=0)
Construct a SBK_BarDrive with a custom matrix size (rows × columns layout).
BarDirection getDirection()
Get the current bar fill direction.
SBK_BarMeterAnimations< SBK_BarMeter< DriverT > > & animations()
Get the animation controller instance (if enabled).
SBK_BarMeter< DriverT > & barmeter()
Get the underlying SBK_BarMeter instance.
Templated animation controller for SBK_BarMeter<T>.
Template class for controlling segment-based LED bar meters using row/column mappings.
SBK_BarMeter & setMatrixOffset(uint8_t rowOffset, uint8_t colOffset)
Apply a matrix-style physical offset for row/column positioning.
void debugSegmentMapping(Stream &stream=Serial)
Print the segment-to-device mapping for debugging purposes.
void clear()
Clear all bar segments.
SBK_BarMeter(DriverT *driver, uint8_t devIdx, uint8_t rowsNum, uint8_t colsNum, BarDirection direction=BarDirection::FORWARD, uint8_t rowOffset=0, uint8_t colOffset=0)
Construct a SBK_BarMeter with a custom matrix size (rows × columns layout).
void show()
Push the current LED state buffer to the physical display.
SBK_BarMeter(DriverT *driver, uint8_t devIdx, const uint8_t(&mapping)[N][3], BarDirection direction=BarDirection::FORWARD, bool progmem=false, uint8_t rowOffset=0, uint8_t colOffset=0)
Construct a SBK_BarMeter using a custom pixel mapping array.
SBK_BarMeter(DriverT *driver, uint8_t devIdx, MatrixPreset matrixPreset=MatrixPreset::BL28_3005SK, BarDirection direction=BarDirection::FORWARD, uint8_t rowOffset=0, uint8_t colOffset=0)
Construct a SBK_BarMeter using a predefined matrix-style layout.
void setDirection(BarDirection dir)
Set the bar fill direction.
BarDirection getDirection() const
Get the current bar fill direction.
SBK_BarMeter & setSegmentOffset(uint8_t offset)
Apply a segment-wise offset (shifts segment index before mapping to row/col).
void setPixel(uint8_t segment, uint8_t state)
Set the on/off state of a logical segment (LED).
uint8_t getPixelState(uint8_t segment) const
Get the current state of a bar segment (pixel).
SBK_BarMeter(DriverT *driver, uint8_t devIdx, uint8_t segsNum, BarDirection direction=BarDirection::FORWARD, uint8_t segOffset=0)
Construct a SBK_BarMeter with a fixed number of vertical segments (non-matrix layout).
uint8_t getSegsNum() const
Get the total number of segments in the bar.