[P157] Add Circular scroll option

This commit is contained in:
Ton Huisman
2026-06-15 23:22:36 +02:00
parent f989c33cc1
commit 55fb73afab
3 changed files with 208 additions and 32 deletions
+41
View File
@@ -30,6 +30,7 @@
//
/** History
* 2026-06-14 tonhuisman: Add Circular scroll option, guarded with define P157_SCROLL_CIRCULAR, settings collapsed by default
* 2026-06-13 tonhuisman: Add Scroll Always option to also scroll content <= display width
* Add Zero with slash option
* Add Delay to next scroll-start option
@@ -76,6 +77,9 @@ boolean Plugin_157(uint8_t function, struct EventStruct *event, String& string)
uint32_t lSettings{};
bitWrite(lSettings, P157_OPTION_ZEROSLASH, true); // Enable zero with slash by default
P157_CFG_FLAGS = lSettings;
# if P157_SCROLL_TEXT && P157_SCROLL_CIRCULAR
P157_SET_SEPARATOR_COUNT(1);
# endif
break;
}
@@ -168,6 +172,36 @@ boolean Plugin_157(uint8_t function, struct EventStruct *event, String& string)
addUnit(F("1..600 = 0.1..60 sec/step"));
addFormNumericBox(F("Delay to next scroll-start"), F("scrolldelay"), P157_CFG_SCROLLDELAY, 0, 6000);
addUnit(F("0.1 sec"));
# if P157_SCROLL_CIRCULAR
{
addFormDetailsStart(F("Circular scroll options"), P157_GET_CIRCULAR_SCROLL);
addFormCheckBox(F("Circular scroll"), F("sc_cir"), P157_GET_CIRCULAR_SCROLL);
const __FlashStringHelper *sepChars[] = {
F("(Space)"),
F("-"),
F("/"),
F("|"),
F("\\"),
};
const int sepCharOptions[] = {
' ',
'-',
'/',
'|',
'\\',
};
if (0 == P157_GET_CIRCULAR_SEPARATOR) { P157_SET_CIRCULAR_SEPARATOR(sepCharOptions[0]); }
constexpr size_t optionCount = NR_ELEMENTS(sepCharOptions);
const FormSelectorOptions selector(optionCount, sepChars, sepCharOptions);
selector.addFormSelector(F("Separator character"), F("sep_char"), P157_GET_CIRCULAR_SEPARATOR);
addFormNumericBox(F("Nr. of separator characters"), F("sep_cnt"), P157_GET_SEPARATOR_COUNT, 0, 15);
addFormCheckBox(F("Wrap separator with spaces"), F("sc_wrap"), P157_GET_SEPARATOR_WRAP);
addFormDetailsEnd();
}
# endif // if P157_SCROLL_CIRCULAR
# endif // if P157_SCROLL_TEXT
// addFormCheckBox(F("Right-align Temperature (7dt)"), F("temp_rightalign"), bitRead(P157_CFG_FLAGS, P157_OPTION_RIGHTALIGN));
@@ -211,6 +245,13 @@ boolean Plugin_157(uint8_t function, struct EventStruct *event, String& string)
# endif // if P157_SUPPRESS_ZERO
P157_CFG_FLAGS = lSettings;
# if P157_SCROLL_CIRCULAR
P157_SET_CIRCULAR_SCROLL(isFormItemChecked(F("sc_cir")));
P157_SET_CIRCULAR_SEPARATOR(getFormItemInt(F("sep_char")));
P157_SET_SEPARATOR_COUNT(getFormItemInt(F("sep_cnt")));
P157_SET_SEPARATOR_WRAP(isFormItemChecked(F("sc_wrap")));
# endif // if P157_SCROLL_CIRCULAR
success = true;
break;
}
+138 -28
View File
@@ -74,6 +74,15 @@ bool P157_data_struct::init(struct EventStruct *event)
scrollAll = bitRead(P157_CFG_FLAGS, P157_OPTION_SCROLL_ALL);
scrollDelay = P157_CFG_SCROLLDELAY;
setScrollSpeed(P157_CFG_SCROLLSPEED);
# if P157_SCROLL_CIRCULAR
scrollCircular = P157_GET_CIRCULAR_SCROLL;
circularSeparator = (char)P157_GET_CIRCULAR_SEPARATOR;
circularCharCount = P157_GET_SEPARATOR_COUNT;
circularWrapSpace = P157_GET_SEPARATOR_WRAP;
if (scrollCircular) { scrollDelay = 0; } // No delay when using Serpentine scroll
# endif // if P157_SCROLL_CIRCULAR
# endif // if P157_SCROLL_TEXT
suppressLeading0 = bitRead(P157_CFG_FLAGS, P157_OPTION_SUPPRESS0);
timesep = true;
@@ -384,7 +393,8 @@ int P157_data_struct::getEffectiveTextLength(const String& text) {
# if P157_SCROLL_TEXT
bool P157_data_struct::nextScroll() {
bool result = false;
bool result = false;
uint16_t maxPart = bufLen;
if (scrollWait && (--scrollWait > 0)) {
return result;
@@ -406,7 +416,13 @@ bool P157_data_struct::nextScroll() {
if (binData.size() > 0) {
scrollPos++;
if (scrollPos > (binData.size() - bufLen)) {
if (scrollPos > binData.size() -
(
# if P157_SCROLL_CIRCULAR
scrollCircular ? 1 :
# endif
bufLen)
) {
scrollPos = 0; // Redisplay
scrollWait = scrollDelay; // Restart delay counter
}
@@ -422,17 +438,41 @@ bool P157_data_struct::nextScroll() {
String part = _textToScroll.substring(scrollPos, scrollPos + 1.5 * bufLen);
while (getEffectiveTextLength(part) > bufLen && !part.isEmpty()) {
# if P157_SCROLL_CIRCULAR
if (scrollCircular) {
maxPart = _textToScroll.length();
}
# endif // if P157_SCROLL_CIRCULAR
while (getEffectiveTextLength(part) > maxPart && !part.isEmpty()) {
part = part.substring(0, part.length() - 1);
}
# if P157_SCROLL_CIRCULAR
if (scrollCircular) {
while (part.length() < bufLen) {
for (uint16_t i = 0; i < _textToScroll.length() && part.length() < bufLen; ++i) {
part += _textToScroll.charAt(i);
}
}
}
# endif // if P157_SCROLL_CIRCULAR
for (uint16_t i = 0; i < bufLen && i < part.length(); ++i) {
showbuffer[i] = part.charAt(i);
}
scrollPos++;
if (scrollPos > _textToScroll.length() - bufLen) {
if (scrollPos > _textToScroll.length() -
(
# if P157_SCROLL_CIRCULAR
scrollCircular ? 1 :
# endif
bufLen)
) {
scrollPos = 0; // Restart when all text displayed
scrollWait = scrollDelay; // Restart delay counter
}
@@ -450,15 +490,32 @@ void P157_data_struct::setTextToScroll(const String& text) {
free_string(_textToScroll);
if (!text.isEmpty()) {
_textToScroll.reserve(text.length() + bufLen + (scrollFull ? bufLen : 0));
# if P157_SCROLL_CIRCULAR
for (int i = 0; scrollFull && i < bufLen; ++i) { // Scroll text in from the right, so start with all spaces
_textToScroll += ' ';
}
_textToScroll += text;
if (scrollCircular) {
_textToScroll.reserve(text.length() + circularCharCount + (circularWrapSpace ? 2 : 0));
_textToScroll = text;
for (int i = 0; i < bufLen; ++i) { // Scroll text off completely before restarting
_textToScroll += ' ';
if (circularWrapSpace) { _textToScroll += ' '; }
for (uint8_t i = 0; i < circularCharCount; ++i) {
_textToScroll += circularSeparator;
}
if (circularWrapSpace) { _textToScroll += ' '; }
} else
# endif // if P157_SCROLL_CIRCULAR
{
_textToScroll.reserve(text.length() + bufLen + (scrollFull ? bufLen : 0));
for (int i = 0; scrollFull && i < bufLen; ++i) { // Scroll text in from the right, so start with all spaces
_textToScroll += ' ';
}
_textToScroll += text;
for (int i = 0; i < bufLen; ++i) { // Scroll text off completely before restarting
_textToScroll += ' ';
}
}
}
scrollCount = _scrollSpeed;
@@ -491,6 +548,8 @@ void P157_data_struct::logBufferContent(String prefix) {
log += ',';
log += showperiods[i] ? F(".") : F("");
}
log += 's';
log += scrollPos;
addLogMove(LOG_LEVEL_INFO, log);
}
}
@@ -514,12 +573,28 @@ void P157_data_struct::printBuffer() {
String log;
# endif // ifdef P157_DEBUG
for (uint16_t j = 0; j < bufLen && (scrollPos + j) < binData.size(); ++j) {
ht16k33->writeLowLevel(j, binData[scrollPos + j]);
# ifdef P157_DEBUG
log += formatToHex(binData[scrollPos + j]);
log += ',';
# endif // ifdef P157_DEBUG
uint16_t j = 0;
# if P157_SCROLL_CIRCULAR
uint16_t k = 0;
# endif
for (; j < bufLen; ++j) {
if ((scrollPos + j) < binData.size()) {
ht16k33->writeLowLevel(j, binData[scrollPos + j]);
# ifdef P157_DEBUG
log += formatToHex(binData[scrollPos + j]);
log += ',';
# endif // ifdef P157_DEBUG
}
# if P157_SCROLL_CIRCULAR
else if (scrollCircular) {
ht16k33->writeLowLevel(j, binData[k]);
++k;
if (k >= binData.size()) { k = 0; }
}
# endif // if P157_SCROLL_CIRCULAR
}
# ifdef P157_DEBUG
@@ -1056,7 +1131,11 @@ bool P157_data_struct::plugin_write_7dtext(const String& text) {
_lastArgument = text;
setTextToScroll(EMPTY_STRING);
setScrollEnabled(scrollAll || getEffectiveTextLength(text) > bufLen);
setScrollEnabled(
# if P157_SCROLL_CIRCULAR
scrollCircular ||
# endif
scrollAll || getEffectiveTextLength(text) > bufLen);
if (isScrollEnabled()) {
setTextToScroll(text);
@@ -1114,8 +1193,8 @@ bool P157_data_struct::plugin_write_7dbin(const String& text,
scrollPos = 0;
uint32_t wordValue{};
uint8_t arg = 1;
String argValue = parseStringKeepCaseNoTrim(text, offset + arg);
uint8_t arg = offset + 1;
String argValue = parseStringKeepCaseNoTrim(text, arg);
while (!argValue.isEmpty()) {
NumericalType numType;
@@ -1167,22 +1246,53 @@ bool P157_data_struct::plugin_write_7dbin(const String& text,
}
}
arg++;
argValue = parseStringKeepCaseNoTrim(text, offset + arg);
argValue = parseStringKeepCaseNoTrim(text, arg);
}
if (binData.size() > 0) {
# if P157_SCROLL_TEXT
setScrollEnabled(scrollAll || binData.size() > bufLen);
setScrollEnabled(
# if P157_SCROLL_CIRCULAR
scrollCircular ||
# endif
scrollAll || binData.size() > bufLen);
if (isScrollEnabled()) {
uint8_t i = 0;
# if P157_SCROLL_CIRCULAR
for (; scrollFull && i < bufLen; ++i) { // prepend to start display empty
binData.insert(binData.begin(), 0);
}
if (scrollCircular) {
uint16_t bitmap;
for (i = 0; i < bufLen; ++i) { // append empty to scroll until empty
binData.push_back(0);
if (circularWrapSpace) { binData.push_back(0); }
# if P157_EXTRA_FONTS
if (P157_is7SegmentDisplay(displayModel)) {
// Re-use the fonts from P073, but they use the MAX7219 layout, that has bits 0..6 reverted
bitmap = P073_revert7bits(P073_getFontChar(P073_mapCharToFontPosition(circularSeparator, fontSet), fontSet));
} else
# endif // if P157_EXTRA_FONTS
{
bitmap = ht16k33->getCharacterBitmap(circularSeparator);
}
for (uint8_t i = 0; i < circularCharCount; ++i) {
binData.push_back(bitmap);
}
if (circularWrapSpace) { binData.push_back(0); }
} else
# endif // if P157_SCROLL_CIRCULAR
{
uint8_t i = 0;
for (; scrollFull && i < bufLen; ++i) { // prepend to start display empty
binData.insert(binData.begin(), 0);
}
for (i = 0; i < bufLen; ++i) { // append empty to scroll until empty
binData.push_back(0);
}
}
} else
# endif // if P157_SCROLL_TEXT
+29 -4
View File
@@ -39,9 +39,22 @@
# define P157_OPTION_SCROLLFULL 4 // Scroll text from the right in, starting with a blank display
# define P157_OPTION_SUPPRESS0 5 // Suppress leading zero on day/hour of Date/Time display
# define P157_OPTION_BLINK_DOT 6 // Use dot on second digit for flashing instead of colon
# define P157_OPTION_CIRCULAR 7 // Enable circular scrolling (continuous)
# define P157_OPTION_CIR_SEPAR 8 // 8 bit Separator character
# define P157_OPTION_CIR_COUNT 16 // 4 bit Separator character count
# define P157_OPTION_CIR_WRAP 20 // Separator wrap with spaces
# define P157_GET_CIRCULAR_SCROLL bitRead(P157_CFG_FLAGS, P157_OPTION_CIRCULAR)
# define P157_SET_CIRCULAR_SCROLL(V) bitWrite(P157_CFG_FLAGS, P157_OPTION_CIRCULAR, V)
# define P157_GET_CIRCULAR_SEPARATOR get8BitFromUL(P157_CFG_FLAGS, P157_OPTION_CIR_SEPAR)
# define P157_SET_CIRCULAR_SEPARATOR(V) set8BitToUL(P157_CFG_FLAGS, P157_OPTION_CIR_SEPAR, V)
# define P157_GET_SEPARATOR_COUNT get4BitFromUL(P157_CFG_FLAGS, P157_OPTION_CIR_COUNT)
# define P157_SET_SEPARATOR_COUNT(V) set4BitToUL(P157_CFG_FLAGS, P157_OPTION_CIR_COUNT, V)
# define P157_GET_SEPARATOR_WRAP bitRead(P157_CFG_FLAGS, P157_OPTION_CIR_WRAP)
# define P157_SET_SEPARATOR_WRAP(V) bitWrite(P157_CFG_FLAGS, P157_OPTION_CIR_WRAP, V)
# ifdef USES_P073
# define P157_FEATURE_P073 1 // Use P073 shared functions and fonts when available
# define P157_FEATURE_P073 1 // Use P073 shared functions and fonts when available
# else // ifdef USES_P073
# define P157_FEATURE_P073 0
# endif // ifdef USES_P073
@@ -67,6 +80,9 @@
# ifndef P157_SCROLL_TEXT
# define P157_SCROLL_TEXT 1 // Enable scrolling of 7dtext by default
# endif // ifndef P157_SCROLL_TEXT
# ifndef P157_SCROLL_CIRCULAR
# define P157_SCROLL_CIRCULAR 1 // Enable continuous scrolling by default
# endif // ifndef P157_SCROLL_CIRCULAR
# ifndef P157_7DBIN_COMMAND
# define P157_7DBIN_COMMAND 1 // Enable input of binary data via 7dbin,uint8_t,... command
# endif // ifndef P157_7DBIN_COMMAND
@@ -87,6 +103,10 @@
# undef P157_SCROLL_TEXT // Optionally activate if .bin file space is problematic, remove the scrolling text feature
# define P157_SCROLL_TEXT 0
# endif // if P157_SCROLL_TEXT
# if P157_SCROLL_CIRCULAR
# undef P157_SCROLL_CIRCULAR // Optionally activate if .bin file space is problematic, remove the circular scrolling feature
# define P157_SCROLL_CIRCULAR 0
# endif // if P157_SCROLL_CIRCULAR
# if P157_7DBIN_COMMAND
# undef P157_7DBIN_COMMAND // Optionally activate if .bin file space is problematic, remove the 7dbin command
# define P157_7DBIN_COMMAND 0
@@ -120,6 +140,8 @@ public:
bool plugin_ten_per_second(struct EventStruct *event);
# endif // if P157_SCROLL_TEXT
private:
void printBuffer();
void fillBufferWithTime(bool sevendgt_now,
uint8_t sevendgt_hours,
@@ -202,7 +224,12 @@ public:
bool scrollAll = false;
bool zeroSlash = false;
private:
# if P157_SCROLL_CIRCULAR
bool scrollCircular = false;
bool circularWrapSpace = false;
char circularSeparator{};
uint8_t circularCharCount{};
# endif // if P157_SCROLL_CIRCULAR
uint16_t _scrollSpeed = 0;
# endif // P157_SCROLL_TEXT
@@ -211,8 +238,6 @@ private:
# endif // if defined(P157_SCROLL_TEXT) || defined(P157_7DBIN_COMMAND)
String _lastArgument; // Keep last argument for 7dtext and 7dbin
private:
Noiasca_ht16k33*ht16k33 = nullptr;
uint8_t bufLen{};