/**
 ******************************************************************************
 * @file SevenSegDisplays.h
 * @brief Header file for the SevenSegDisplays_ESP32 library 
 * 
 * @details The library provides a common API and tools to generate and manage contents formatting for seven segments displays.
 * 
 * The library processes the information provided as input and displays the resulting data in a two stages process:
 * - A SevenSegDisplays class object manages the data generation from the user provided information into a hardware display valid input format.  
 * - A SevenSegDispHw subclass object will manage the hardware required actions to exhibit the information generated by the SevenSegDisplays object.    
 * - For this mechanism to work the SevenSegDispHw subclass object will compose the SevenSegDisplays class object.  
 * The chosen design lets the information generated by the SevenSegDisplays class objects to be displayed in any kind of display architecture, as long as a SevenSegDispHw subclass implements the hardware communications protocols to receive the available processed data and to keep it exhibited and updated.  
 * 
 * Repository: https://github.com/GabyGold67/SevenSegDisplays_ESP32  
 * 
 * Framework: Arduino  
 * Platform: ESP32  
 * 
 * @author Gabriel D. Goldman  
 * mail <gdgoldman67@hotmail.com>  
 * Github <https://github.com/GabyGold67>  
 * 
 * @version 3.2.0
 * 
 * @date First release: 20/12/2023  
 *       Last update:   27/04/2025 17:10 (GMT+0200) DST  
 * 
 * @copyright Copyright (c) 2025  GPL-3.0 license  
 *******************************************************************************
  * @attention	This library was originally developed as part of the refactoring
  * process for an industrial machines security enforcement and productivity control
  * (hardware & firmware update). As such every class included complies **AT LEAST**
  * with the provision of the attributes and methods to make the hardware & firmware
  * replacement transparent to the controlled machines. Generic use attributes and
  * methods were added to extend the usability to other projects and application
  * environments, but no fitness nor completeness of those are given but for the
  * intended refactoring project, and for the author's projects requirements.  
  * 
  * @warning **Use of this library is under your own responsibility**
  * 
  * @warning The use of this library falls in the category described by The Alan 
  * Parsons Project (c) 1980 Games People play disclaimer:   
  * Games people play, you take it or you leave it  
  * Things that they say aren't alright  
  * If I promised you the moon and the stars, would you believe it?  
 *******************************************************************************
 */
//FFDR For Future Development Reminder!!
//FTPO For Testing Purposes Only code!!

#ifndef _SevenSegDisplays_ESP32_H_
#define _SevenSegDisplays_ESP32_H_

#include <Arduino.h>
#include <stdint.h>
#include <./SevenSegDispHw/SevenSegDispHw.h>

class SevenSegDisplays {
   static uint8_t _displaysCount;
   static uint16_t _dspLastSerialNum;
   static SevenSegDisplays** _ssdInstancesLstPtr;

   static TimerHandle_t _blinkTmrHndl;
   static TimerHandle_t _waitTmrHndl;

   static void tmrCbBlink(TimerHandle_t blinkTmrCbArg);
   static void tmrCbWait(TimerHandle_t waitTmrCbArg);

   static const uint32_t _minBlinkRate{100};  //unsigned long for ESP32 in Arduino enviornment
   static const uint32_t _maxBlinkRate{2000};   //unsigned long for ESP32 in Arduino enviornment

private:
   bool _begun{false};
   bool _isWaiting {false};
   uint8_t _waitChar {0xBF};
   uint8_t _waitCount {0};
   uint32_t _waitRate {250};
   uint32_t _waitTimer {0};

protected:
   bool* _blinkMaskPtr{nullptr};
   uint8_t* _dspAuxBuffPtr{nullptr};
   uint8_t* _dspBuffPtr{nullptr};
   uint8_t _dspDigitsQty{};
   SevenSegDispHw* _dspUndrlHwPtr{};
   SevenSegDisplays* _dspInstance{nullptr};
   uint16_t _dspSerialNbr{0};
   int32_t _dspValMax{};
   int32_t _dspValMin{};
   bool _dspUndrlHwCommAnode{};
    
   bool _isBlinking{false};
   bool _blinkShowOn{false};
   uint32_t _blinkTimer{0};
   uint32_t _blinkOffRate{500};
   uint32_t _blinkOnRate{500};
   uint32_t _blinkRatesGCD{500};  //Holds the value for the minimum timer checking the change ON/OFF of the blinking, saving unneeded timer interruptions, and without the need of the std::gcd function
   String _charSet{"0123456789AabCcdEeFGHhIiJLlnOoPqrStUuY-_=~* ."}; // for using indexOf() method
   uint8_t _charLeds[45] = {   //Values valid for a Common Anode display. For a Common Cathode display values must be logically bit negated
      0xC0, // 0
      0xF9, // 1
      0xA4, // 2
      0xB0, // 3
      0x99, // 4
      0x92, // 5
      0x82, // 6
      0xF8, // 7
      0x80, // 8
      0x90, // 9
      0x88, // A
      0xA0, // a
      0x83, // b
      0xC6, // C
      0xA7, // c
      0xA1, // d
      0x86, // E
      0x84, // e
      0x8E, // F
      0xC2, // G
      0x89, // H
      0x8B, // h
      0xF9, // I
      0xFB, // i
      0xF1, // J
      0xC7, // L
      0xCF, // l
      0xAB, // n
      0xC0, // O
      0xA3, // o
      0x8C, // P
      0x98, // q
      0xAF, // r
      0x92, // S
      0x87, // t
      0xC1, // U
      0xE3, // u
      0x91, // Y
      0xBF, // Minus -
      0xF7, // Underscore _
      0xB7, // Low =
      0xB6, //~ for Equivalent symbol
      0x9C, // °
      0xFF, // Space
      0x7F  //.
   };    
    
   uint8_t _space {0xFF};
   uint8_t _dot {0x7F};
   String _zeroPadding{""};
   String _spacePadding{""};

   uint32_t _blinkTmrGCD(uint32_t blnkOnTm, uint32_t blnkOffTm);
   void _ntfyToHwBuffChng();
   void _popSsd(SevenSegDisplays** &ssdInstncObjLst, SevenSegDisplays* ssdToPop);
   void _pushSsd(SevenSegDisplays** &ssdInstncObjLst, SevenSegDisplays* ssdToPush);
   void _restoreDspBuff();
   void _setAttrbts();
   void _setDspBuffChng();
   void _saveDspBuff();
   void _updBlinkState();
   void _updWaitState();

public:
   /**
    * @brief Default constructor
    * 
    * @class SevenSegDisplays
    */
   SevenSegDisplays();
   /**
    * @brief Class constructor
    * 
    * Instantiates a SevenSegDisplays class object
    * 
    * @param dspUndrlHw A pointer to an instantiated SevenSegDispHw subclass object that models the hardware display that composes the SevenSegDisplays object
    * 
    * @note The library structure design, built on the idea of keeping the API and the services provided consistent, and connecting to the hardware managing level through specific subclasses of the SevenSegDispHw class gives a variety of valid instantiation procedures, through different code but with the same result. This might help the developer to keep his/hers most comfortable practices to get the object needed created. Some examples of this are:  
    * 
    * A three lines step by step code example:  
    * @code {.cpp}
    * SevenSegDynHC595 myLedDispHw(myDispIOPins, 4, true);  // Instantiation of the underlying hardware object
    * SevenSegDispHw* myLedDispHwPtr = &myLedDispHw;        // Creation of a pointer to the instantiated hardware object
    * SevenSegDisplays myLedDisp(myLedDispHwPtr);           // Instantiation of the SevenSegDisplays object using the pointer created
    * @endcode
    *
    * A two lines example using the & operand to pass the pointer to the constructor
    * @code {.cpp}
    * SevenSegDynHC595 myLedDispHw(myDispIOPins, 4, true);  // Instantiation of the underlying hardware object
    * SevenSegDisplays myLedDisp(&myLedDispHw);             // Instantiation of the SevenSegDisplays object using the & operand over the hardware object created
    * @endcode
    * 
    * A two lines example using a sub-class pointer to a dynamic instantiated object
    * @code {.cpp}
    * SevenSegDynHC595* myLedDispPtr {new SevenSegDynHC595 (myDispIOPins, 4, true)};   // Dynamic instantiation of the underlying hardware object, pointed by a subclass pointer
    * SevenSegDisplays myLedDisp(myLedDispPtr);    // Instantiation of the SevenSegDisplays object using the subclass pointer to the hardware object dynamically created
    * @endcode
    * 
    * A two lines example using a base class pointer to a dynamic instantiated object
    * @code {.cpp}
    * SevenSegDispHw* myLedDispPtr {new SevenSegDynHC595 (myDispIOPins, 4, true)};  // Dynamic instantiation of the underlying hardware object, pointed by a base class pointer
    * SevenSegDisplays myLedDisp(myLedDispPtr); // Instantiation of the SevenSegDisplays object using the base class pointer to the hardware object dynamically created
    * @endcode 
    * 
    * 
    * A one liner example using as argument the pointer returned from dynamic instantiated object
    * @code {.cpp}
    * SevenSegDisplays myLedDisp(new SevenSegDynHC595 (myDispIOPins, 4, true));  // Easy to understand reading from right to left, as usual!!
    * @endcode
    * 
    * @attention Note that two or more lines instantiations will be needed when specific display hardware configuration is required before the hardware use: semicolon setting, starting brightness levels, etc. Making use of the one, two, three or more lines instantiation is not a sign of smartness or elegance, but options to be taken by the development need.  
    */
   SevenSegDisplays(SevenSegDispHw* dspUndrlHwPtr);
   /**
     * @brief Class destructor
     */
   ~SevenSegDisplays();
   /**
    * @brief Sets up the hardware display to work, and starts the display activities.  
    * 
    * Depending on the display controller characteristics the setup procedure may include different defined steps, each class will execute the needed steps for each display controller.  
    * 
    * @attention The **begin()** method is different from the **turnOn()** method. The first one ensures the display controller unit is ready to receive data to be displayed, including communications and internal memory management, while the second enables the display to turn on the corresponding leds to exhibit the data received. The fact that some display technologies needs no configuration and/or not explicit turning on the display is hidden for the user benefit: all displays must invoke the begin() method, all displays have acces to a end(), turnOn() and turnOff(). Executing a begin() method will invoke automatically the turnOn() method. Invoking a turnOff() in a begun display will let the display to keep receiving data, but it will not be visible untila a new turnOn() is invoked.
    * 
    * @param updtLps Optional parameter, sets the rate needed by the dynamic type displays, will be ignored by othe types of displays. Is no value is passed to the dynamic displays they will used a preset stantard parameter. 
    * 
    * @retval true The display was initialized without errors. 
    * @retval false The display couldn't be initialized due to an error. 
    */
   virtual bool begin(uint32_t updtLps = 0);
    /**
    * @brief Makes the display blink the contents it is showing.
    * 
    * The display will blink the contents it is showing until a **`noBlink()`** method is invoked. The display will continue blinking even if the contents are changed.  
    * By default all the digits will be set to blink, but each digit might be configured individually to blink or not by using the **`setBlinkMask(const bool*)`** method.  
    * When invoking the **`blink()`** method with no parameters the blinking pace (timings) previously set will be used. If no **`setBlinkRate(const unsigned long, const unsigned long)`** and no **`blink(const unsigned long, const unsigned long)`** with parameters was used before this call, the blinking will be symmetrical, meaning that the time the display shows the contents and the time the display is blank are equal. The on time and the off time of the blinking starts at a preset rate this first time the method is invoked.    
    * The blinking rate can be changed by using the **`setBlinkRate(const unsigned long, const unsigned long)`** method. After changing the blinking rate, the new blinking rate will be kept after a **`noBlink()`** call is done, until it is modified with a new **`setBlinkRate(const unsigned long, const unsigned long)`** call, or it is restarted by a **`blink(const unsigned long, const unsigned long)`** with parameters.  
    * @note To restart the blinking with a **`blink()`** or a **`blink(const unsigned long, const unsigned long)`** the service must first be stopped, as the method call makes no changes if the blinking service was already running.  
    * 
    * @retval true: If the display blinking process started ok, or was already set to blink
    * @retval false: The display blinking failed to start.  
    * 
    * Use example:  
    * @code {.cpp}
    * myLedDisp.blink(); // Begin blinking at the already set rate
    * @endcode
    */
   bool blink();
   /**
    * @brief Makes the display blink the contents it is showing.
    * 
    * Makes the display blink the contents it shows until a **`noBlink()`** method is invoked. The blinking is **symmetrical** if only one parameter is passed, **asymmetrical** if two **different** parameters are passed, meaning that the time the display shows the contents and the time the display is blank will be equal (symmetrical) or not (asymmetrical), depending of those two parameters. The blinking starts at a passed rate when the method is invoked. The blinking rate can be changed by using the **`.setBlinkRate(const unsigned long, const unsigned long)`** method. The blink rate set will be kept after a **`.noBlink()`**, until it is modified with a new **`.setBlinkRate(const unsigned long, const unsigned long)`** call, or it is restarted by a **`.blink(const unsigned long, const unsigned long)`** with parameters.  
    *   
    * @note To restart the blinking with a **`blink()`** or a **`blink(const unsigned long, const unsigned long)`** the service must first be stopped, as the method call makes no changes if the blinking service was already running.  

   * @param onRate Value indicating the time (in milliseconds) the display must stay on, the value must be in the range _minBlinkRate <= onRate <= _maxBlinkRate. Those preset values can be known by the use of the **`getMinBlinkRate()`** and the **`getMaxBlinkRate()`** methods.
   * @param offRate Optional value indicating the time (in milliseconds) the display must stay off, the value must be in the range _minBlinkRate <= offRate <= _maxBlinkRate. Those preset values might be known by the use of the **`getMinBlinkRate()`** and the **`getMaxBlinkRate()`** methods. If no offRate value is provided the method will assume it's a symmetric blink call and use a value for offRate equal to the value passed for onRate. 
   * 
   * @retval true If the display was already set to blink, or was not blinking and the blinking started with the provided parameters. If the display was already blinking no change will be made to the blinking rate.  
   * @retval false One or more of the parameters passed were out of range.  
   * 
   * Use examples:  
   * @code {.cpp}
   * myLedDisp.blink(400); // Starts blinking setting the rate to 400 millisecs on, 400 millisecs off (symmetrical blink). And returns true.  
   * @endcode
   * 
   * @code {.cp}
   * myLedDisp.blink(800, 200); // Sets the blinking rate to 800 millisecs on, 200 millisecs off (asymmetrical blink), starts blinking, and returns true.  
   * @endcode
   * 
   * @code {.cpp}
   * unsigned long rateTooBig {myLedDisp.getMaxBlinkRate() + 10} // Saves in a variable a blinking rate out of accepted range
   * myLedDisp.blink(rateTooBig); //Returns false and the display stays without change.  
   * @endcode
   */
   bool blink(const uint32_t &onRate, const uint32_t &offRate = 0);
   /**
    * @brief Clears the display, turning off all the segments and dots.
    * 
    * To ensure success the method must also clean auxiliary buffers used to save the main buffer contents while blinking, as the backup buffer will be restored, so the display clear() would be reverted  
    * 
    * @note The method will not produce any change if it's in "Waiting mode" as the blanked ports will be immediately overwritten by the waiting process, so it makes no sense. Consider, though, that the "Waiting mode" clears the display at it's exit.  
    * 
    * Use example:  
    * 
    * @code {.cpp}
    * myLedDisp.clear();
    * @endcode
    * 
    */
   void clear();
   /**
    * @brief Displays a basic graphical representation of the level of fulfillment or completeness of two segmented values or tasks
    * 
    * The data displayed gives a general fast notion on the matter, as a battery charge level, liquids deposit level, time remaining, tasks completeness and so on. The levels are represented by the horizontal segments (0, 1, 2 or 3 from bottom to top), and a character might be added before each of the graphical representations to give an indication of what the display is showing, passed through the **labelLeft** and **labelRight** parameters. As four 7 segments digit ports will be used, this method only applies to displays with 4 to 8 LED digits, the display is splitted in two sectors, the left side and the right side, and each one of them must have a valid value (0 <= value <= 3) to enable them to be displayed, and might have (or not) a single displayable character to give a visual hint to what the value is showing. For more information check the **`gauge(const int, char)`** method.
    * 
    * @param levelLeft The integer value to display must be in the range 0 <= level <= 3 for the two leftside 7 segments displays.  
    * @param levelRight The integer value to display must be in the range 0 <= level <= 3 for the two rightside 7 segments displays.  
    * @param labelLeft A char, optional parameter (if not specified the default value, a Space, will be assumed), that will be displayed in the leftmost digit of the display. The character must be one of the "displayable" characters, as listed in the **`print()`** method description.  
    * @param labelRight A char, optional parameter (if not specified the default value, a Space, will be assumed), that will be displayed in the position left to the **levelRight** display, just before the levelRight value. The character must be one of the "displayable" characters, as listed in the **`.print(String)`** method description.
    * 
    * @retval true: If the values could be represented.  
    * @retval false: Otherwise, being that the **levelLeft** and/or **levelRight** parameter was out of range and/or the **labelLeft** and/or **labelRight** parameter was not in the list of displayable characters. The display will be blanked.  
    * 
    * Use example:  
    * @code {.cpp}
    * myLedDisp.gauge(3, 2); // Displays a double gauge with no labels, the left level in the fourth (higher) level, the right level in it's third level.  
    * @endcode
    * 
    * @code {.cpp}
    * myLedDisp.gauge(2, 1, 'b', 't');  // Displays a double gauge, the left indicator with a **b** letter as label and a third level value, and the right side indicator with a **t** label and a second level value.  
    * @endcode
    * 
    * @code {.cpp}
    * myLedDisp.gauge(1, 3, 'F');  // Displays a double gauge, the left indicator with a **F** letter as label and a second level value, and the right side indicator with a no label and a fourth level value.  
    * @endcode
    * 
    * @code {.cpp}
    * myLedDisp.gauge(4, 2,'d', 'b'); // Error: the left level is outside valid range (value 4, valid range is 0<=value<=3). The method will return false and the display will be cleared.  
    * @endcode
    * 
    * @code {.cpp}
    * myLedDisp.gauge(3, 0, 'X');  // Error: 'X' (the left indicator label) is not a "displayable" character. The method will return false and the display will be cleared.  
    * @endcode
    */
   bool doubleGauge(const int &levelLeft, const int &levelRight, char labelLeft = ' ', char labelRight = ' ');
   /**
    * @brief Ends the activity of the display.  
    * 
    * After the end() is invoked, the display will stop accepting new data, stop it's refreshing and all activities involved in keeping it's contents updated. To keep the expected level of accuracy and security the display will be cleaned before stopping it's activity. 
    * 
    * @return True
    */
   bool end();
   /**
    * @brief Displays a basic graphical representation of the level of fulfillment or completeness of a segmented value or task.
    * 
    * The displayed data gives a general fast notion on the matter, as a battery charge level, liquids deposit level, time remaining, tasks completeness and so on. The levels are represented by the horizontal segments (0, 1, 2 or 3 from bottom to top, and from left to right), and a character might be added before the graphical representation to give an indication of what the display is showing, passed through the **label** parameter. This method is usable in displays which have from 4 and up to 8 digits, and the representation always makes use of exactly 4 digits. 
    * 
    * @param level The integer value to display must be in the range 0 <= level <= 3.  
    * @param label char, optional parameter (if not specified the default value, a Space, will be assumed), that will be displayed in the leftmost digit of the display. The character must be one of the "displayable" characters, as listed in the **`print(String)`** method description.
    * 
    * @return true If the value could be represented.  
    * @return false Otherwise, being that the **level** parameter was out of range and/or the **label** parameter was not in the list of displayable characters. The display will be blanked.
    * 
    * Use example:  
    * 
    * @code {.cpp}
    * `myLedDisp.gauge(2, 'b');` // Displays a gauge with a label **b** in it's leftmost position, the next two positions with level indicators for second and third levels
    * @endcode
    * 
    * @code {.cpp}
    * `myLedDisp.gauge(3);`   // Displays a gauge with a blank space as label and the next three positions with their respective levels indicators
    * @endcode
    * 
    * @code {.cpp}
    * `myLedDisp.gauge(1, 'F');` // Displays a gauge with a **F** as label in it's leftmost position, and the next position holding the second level indicator
    * @endcode
    * 
    * @code {.cpp}
    * `myLedDisp.**gauge(4, 'd');`  // Error, the value 4 is outside valid range, the method will return **false** and the display will be cleared.  
    * @endcode
    * 
    * @code {.cpp}
    * `myLedDisp.gauge(3, 'X');` // Error, **X** is not a displayable character, the method will return **false** and the display will be cleared
    * @endcode
    */
   bool gauge(const int &level, char label = ' ');
   /**
    * @brief Displays a basic graphical representation of the level of fulfillment or completeness of a segmented value or task
    * 
    * The data displayed gives a general fast notion on the matter, as a battery charge level, liquids deposit level, time remaining, tasks completeness and so on. The levels are represented by the horizontal segments (0, 1, 2 or 3 from bottom to top, and from left to right), and a character might be added before the graphical representation to give an indication of what the display is showing, passed through the **label** parameter. 
    * 
    * @param level The double value to display must be in the range 0.0 <= level <= 1.0, being the range the representation of the percentage of the 'full' level, so that the ranges are:  
    * 0.0 <= level < 0.25 for the first level,  
    * 0.25 <= level < 0.50 for the second level,  
    * 0.50 <= level < 0.75 for the third level, and  
    * 0.75 <= level <= 1.00 for the fourth and upper level.  
    * 
    * @param label char, optional parameter (if not specified the default value, a Space, will be assumed), that will be displayed in the leftmost digit of the display. The character must be one of the "displayable" characters, as listed in the **`print(String)`** method description.  
    *
    * @return true If the value could be represented.  
    * @return false Otherwise, being that the **level** parameter was out of range and/or the **label** parameter was not in the list of displayable characters. The display will be blanked.  
    * 
    * Use example:  
    * 
    * @code {.cpp}
    * myLedDisp.gauge(0.0);   // Generates a display with no label and 0 level indication, so it will be a blank display  
    * @endcode
    * 
    * @code {.cpp}
    * myLedDisp.gauge(0.4);   // Generates a display with no label, and level 1 indicator  
    * @endcode
    * 
    * @code {.cpp}
    * myLedDisp.gauge(0.55, 'b');   // Generates a display with a letter b as label, the level 1 and level 2 indicators  
    * @endcode
    * 
    * @code {.cpp}
    * myLedDisp.gauge(1.0, 'F'); // Generates a display with a letter F as label, the level 1 level 2 and level 3 indicators  
    * @endcode
    * 
    * @code {.cpp}
    * myLedDisp.gauge(1.5, 'd'); //Error: 4 is outside the accepted values range  
    * @endcode
    * 
    * @code {.cpp}
    * myLedDisp.gauge(3.0, 'X'); //Error: 'X' is not a "displayable" character  
    * @endcode
    */
   bool gauge(const double &level, char label = ' ');
   /**
    * @brief Returns the current brightness level of the display
    * 
    * @return uint8_t Brightness level
    */
   uint8_t getCurBrghtnssLvl();   
   /**
    * @brief Return the number of digits of the display hardware.  
    * 
    * Returns an unsigned short integer value indicating the the quantity of digits (ports), the display have as declared at the object instantiation. Each time the class is instantiated the object is created with the needed resources and the range of values it's capable of displaying are calculated based on the dspDigits parameter, and that value is the one returned by this method.  
    * 
    * @return The unsigned short number indicating the quantity of digits of the instantiated display.
    * 
    * Use example:  
    * 
    * @code {.cpp}
    * uint8_t portsQty = myLedDisp.getDigitsQty(); // Saves in the portsQty variable the number of display ports (digits) of the display
    * @endcode
    * 
    */
   uint8_t getDigitsQty();
   /**
    * @brief Returns the quantity of instantiated SevenSegDisplays class objects at invocation moment.  
    * 
    * @return The quantity of instantiated displays.  
    */
   uint8_t getDspCount();
   /**
    * @brief Returns the logic value indicating if the display is dimmable.  
    * 
    * @retval true The display is dimmable (variable brightness configuration)  
    * @retval false The display is not dimmable (only constant brightness)
    */
   bool getDspIsDmmbl();
   /**
    * @brief Returns a pointer to the underlying hardware display object
    * 
    * The pointer returned is of the type SevenSegDispHw*, i.e. a base class pointer. One of the most important and practical use for this method is to give direct access to exclusive attributes, properties and characteristics some of the hardware display models have, and functions they may execute that have no way of being used through the SevenDisplays class methods. Some of those attributes known to exist are: 
    * - Activation and deactivation of semicolons
    * - Change the level of brightness
    * - Change the display color
    * - Some kind of contents animations
    * - Reading the state of pushbuttons managed by the driver chip
    * 
    * @return A SevenSegDispHw* type pointer to the underlying display object
    */
   SevenSegDispHw* getDspUndrlHwPtr();
   /**
    * @brief Returns a value equivalent to the greatest displayable number for the display.  
    * 
    * The value indicates the greatest displayable number according to the quantity of digits (ports) the display have as indicated at the object instantiation.  
    * 
    * @return The integer number indicating the maximum value that the display might display according to the quantity of digits of the instantiated display.  
    * Use example:  
    * 
    * Use example:  
    * 
    * @code {.cpp}
    * int32_t maxLimit = myLedDisp.getDspMax();  // Sets the variable maxLimit to the maximum displayable value for the display
    * @endcode
    */
   int32_t getDspValMax();
   /**
    * @brief Returns a value equivalent to the smallest displayable number for the display. 
    * 
    * The value indicates the smallest displayable number according to the quantity of digits (ports) the display have as indicated at the object instantiation.
    * 
    * @return The integer number indicating the minimum value that the display might display according to the quantity of digits of the instantiated display.  
    * 
    * Use example:  
    * 
    * @code {.cpp}
    * `uint32_t minLimit = myLedDisp.getDspMin();` // Sets the variable minLimit to the minimum displayable value for the display
    * @endcode
    */
   int32_t getDspValMin();
   /**
    * @brief Returns a logic value indicating if the display is in On state.
    * 
    * @retval true The display is on
    * @retval false The display is off
    */
   bool getIsOn();
   /**
    * @brief Returns the maximum rate the display can be configured to blink at. 
    * 
    * The maximum rate the display can be configured to blink at helps keeping the blinkRate setters inside the accepted range. At least two aspects of the blinking process are involved in the determination if this value.  
    * - The technical aspect is related to the hardware possibility to manage the display contents change to show the blinking effect. 
    * - The perception aspect is related to keep the blinking effect range in a rhythm at which the display turns on and off as part of the information that it provides, and doesn't make it look like a display failure or any other kind of bug.  
    * 
    * @return The maximum time, in milliseconds, the display can be set to blink. This value is the maximum to set as the turned-on or the turned-off stage of the blinking process started by a **`blink()`** or a **`blink(const unsigned long, const unsigned long)`** method.  
    * 
    * @attention Opposite to the concept of Hertz, that designates how many times an action happens in a fixed period of time (a second), the value used in the `blink()` and all related methods is **the time set to elapse before the next action happens**.  
    * 
    * Use example:  
    * 
    * @code {.cpp}
    * unsigned long myDispMaxBlnkRt = myLedDisp.getMaxBlinkRate();
    * @endcode
    */
   uint32_t getMaxBlinkRate();
   /**
    * @brief Returns the maximum brightness value setting for the display.  
    * 
    * @return uint8_t Maximum brightness value setting.  
    * 
    * @note If the display has no brightness configuration control then getMaxBrghtnssLvl() = getMinBrghtnssLvl() = getCurBrghtnssLvl() = 0, and getDspIsDmmbl() returns false  
    */
   uint8_t getMaxBrghtnssLvl();
   /**
    * @brief Returns the minimum rate the display can be configured to blink at. 
    * 
    * The minimum rate the display can be configured to blink at helps keeping the blinkRate setters inside the accepted range. At least two aspects of the blinking process are involved in the determination if this value.  
    * - The technical aspect is related to the hardware possibility to manage the display contents change to show the blinking effect. 
    * - The perception aspect is related to keep the blinking effect range in a rhythm at which the display turns on and off as part of the information that it provides, and doesn't make it look like a display failure or any other kind of bug.  
    * 
    * @return The minimum time, in milliseconds, the display can be set to blink. This value is the minimum to set as the turned-on or the turned-off stage of the blinking process started by a **`.blink()`** or a **`blink(const unsigned long, const unsigned long)`** method.  
    * 
    * @attention Opposite to the concept of Hertz, that designates how many times an action happens in a fixed period of time (a second), the value used in the `blink()` and all related methods is **the time set to elapse before the next action happens**.  
    * 
    * Use example:  
    * 
    * @code {.cpp}
    * unsigned long myDispMinBlnkRt = myLedDisp.getMinBlinkRate();
    * @endcode
    */
   uint32_t getMinBlinkRate();
   /**
    * @brief Returns the minimum brightness value setting for the display.  
    * 
    * @return uint8_t Minimum brightness value setting.  
    * 
    * @note If the display has no brightness configuration control then getMaxBrghtnssLvl() = getMinBrghtnssLvl() = getCurBrghtnssLvl() = 0, and getDspIsDmmbl() returns false  
    */
   uint8_t getMinBrghtnssLvl();
   /**
    * @brief Returns a unique numeric identification of the object
    * 
    * The Returned unsigned integer value identifies the object. Each time the class is instantiated the created object receives a serial instantiation number that can be used in order to identify each object in case of need.
    * 
    * @return The unsigned number indicating the identification Instance Number. 
    * 
    * @note As SevenSegDisplays objects might be constructed and destructed at need, the largest Instance number is not necessarily coincidental with the quantity of objects instantiated at any given moment, as the numeric identification of the object is an always increasing value incremented every time a new object is instantiated, but never decremented due to destructions. To know the quantity of instantiated displays at any given moment see uint8_t getDspCount()  
    * 
    * @attention Not to be confused with a pointer to the object or other internal unique identification mechanism results  
    * 
    * Use example:  
    * 
    * @code {.cpp}
    * uint8_t dspNmbr = myLedDisp.getSerialNbr();
    * @endcode
    */
   uint16_t getSerialNbr();
   /**
    * @brief Returns a value indicating if the display is blank. 
    * 
    * The condition of blank is the one in which "All the display ports/digits of the display show spaces, and no decimal points or semicolons are active". This definition is important as it not refers to the display buffer holding any specific arbitrary value (0x00 or 0xFF) but the value designated as **_space**.  
    * 
    * @retval true The display buffer is filled with _space values
    * @retval false At least one memory element of the buffer is filled with a value that is not a _space
    * 
    * Use example:  
    * @code {.cpp}
    * if(!myDisplay.isBlank())
    *    myDisplay.clear();
    * @endcode
    */
   bool isBlank();
   /**
    * @brief Returns a boolean value indicating if the display is set to blink or not.
    * 
    * @retval true The display is set to blink.  
    * @retval false The display is set not to blink. 
    * 
    * Use example:  
    *   
    * @code {.cpp}
    * if(myDisplay.isBlinking)
    *    myDisplay.noBlink();
    * @endcode
    */
   bool isBlinking();
   /**
    * @brief Returns a boolean value indicating if the display is set to "waiting mode" or not.
    * 
    * Knowing if the display is set to "waiting mode" might be useful as the display will force the mode disabling if a **`print()`**, **`write()`**, **`gauge()`**, etc. methods is invoked.
    * 
    * @return true If the display is set to **Waiting mode**.  
    * @return false If the display is not set to **Waiting mode**.   
    * 
    * Use example:  
    * 
    * @code {.cpp}
    * if(myDisplay.isWaiting)
    *    myDisplay.noWait();
    * @endcode
    */
   bool isWaiting();
   /**
    * @brief Stops the display blinking, if it was doing so, leaving the display turned on.
    * 
    * Stoping the blinking process includes retrieving the original contents from the _dspAuxPtr pointed memory (the Auxiliary Buffer), freeing the Auxiliary Buffer memory, stoping the timer attached to the process and cleaning the blinking state related flags  
    * 
    * @retval true The display was set to not blinking, either becauseIf display was set to blink and was stopped, either the display was not set to blink.  
    * @retval false The display was set to blink, and the blink stopping failed.  
    * 
    * Code example:  
    * 
    * @code {.cpp}
    * myLedDisp.noBlink();
    * @endcode
    */
   bool noBlink();
   /**
    * @brief Stops the **Waiting mode**, if it was doing so, leaving the display turned on. 
    * 
    * Stoping the "Waiting mode" process includes retrieving the original contents from the _dspAuxPtr pointed memory (the Auxiliary Buffer), freeing the Auxiliary Buffer memory, stoping the timer attached to the process and cleaning the waiting state related flags    
    * 
    * @retval true If the display was set to wait, the **Waiting mode** is stopped.  
    * @retval false If the display was not set to wait, no changes will be done.  
    * 
    * Code example:  
    * @code {.cpp}
    * myLedDisp.noWait();
    * @endcode
    * 
    */
   bool noWait();
   /**
    * @brief Displays a text string.
    * 
    * The text string must contains all "displayable" characters, which are the ones included in the following list: **0123456789AabCcdEeFGHhIiJLlnOoPqrStUuY-_.** and the **space**. There are other special characters displayable, details in the notes.  
    * 
    * @param text String, up to **dspDigits** displayable characters long PLUS usable dots, all characters included in the representable characters list. Each valid character might be followed by a "." if needed, without being counted as a character, even spaces and special chars. If two or more consecutive dots are passed, an intermediate space is considered to be included between each pair of them, and that space counts as one of the available characters to display.  
    * 
    * @retval true If the text complies with the requirements to be represented. The text string will be displayed.   
    * @retval false Otherwise. The display will be blanked.  
    * 
    * @note There are other 3 characters that can be represented in the display, but the conversion from a character to use while programming is "host language setting dependant", so those where assigned to available ASCII non displayable characters of easy access in any keyboard layout in most languages, they can be used as part of the text string to display, and they are:  
    * **=** Builds a character formed by lighting the lower 2 horizontal segments (the d and g segments) of the digit display, can be described as a "lower equal" symbol.    
    * **~** Builds a character formed by lighting the 3 horizontal segments (the a, d and g segments) of the digit display, can be described as an "equivalent" symbol.  
    * **'*'** (asterisk) Builds a character by lighting the upper 4 segments (the a, b, f and g segments), forming a little square, can be described as the "degrees" symbol or º. 
    * 
    * Code example:  
    * 
    * @code {.cpp}
    * myLedDisp.print("Hi");  // Valid for 2 or more digits displays  
    * myLedDisp.print("Strt");   // Valid for 4 or more digits displays  
    * myLedDisp.print("L.A.X."); // Error, as 'X' is a not displayable character  
    * myLedDisp.print("36.70*"); // Valid for 5 or more digits displays  
    * myLedDisp.print("........");  // Valid for 8 digits displays  
    * @endcode
    */
   bool print(String text);
   /**
    * @brief Displays an integer value as long as the length representation fits the available space of the display.  
    * 
    * @param value The integer value to display which must be in the range (-1)*(pow(10, (dspDigits - 1)) - 1) <= value <= (pow(10, dspDigits) - 1), or _dspValMin <= value <= _dspValMax.  
    * @param rgtAlgn Boolean, optional parameter (if not specified the default value, false, will be assumed), indicates if the represented value must be displayed right aligned, with the missing heading characters being completed with spaces or zeros, depending in the **zeroPad** optional parameter. When a negative value is displayed and it's less than (dspDigits - 1) digits long, a right aligned display will keep the '-' sign in the leftmost position, and the free space to the leftmost digit will be filled with spaces or zeros, depending in the **zeroPad** optional parameter.  
    * @param zeroPad Boolean, optional parameter (if not specified the default value, false, will be assumed), indicates if the heading free spaces of the integer right aligned displayed must be filled with zeros (true) or spaces (false). In the case of a negative integer the spaces or zeros will fill the gap between the '-' sign kept in the leftmost position, and the first digit.  
    * @return true If the value could be represented.  
    * @return false If the value couldn't be represented as it was out of the valid range. The display will be blanked.  
    * 
    * Code example
    * 
    * @code {.cpp}
    * myLedDisp.print(12);  //Displays '12  ' on a 4 digits display  
    * myLedDisp.print(12, true); //Displays '  12' on a 4 digits display  
    * myLedDisp.print(12, true, true); //Displays '0012' on a 4 digits display  
    * myLedDisp.print(-12);   //Displays '-12     ' on a 8 digits display  
    * myLedDisp.print(-12, true);   //Displays '-   12' on a 6 digits display  
    * myLedDisp.print(-12, true, true);   //Displays '-012' on a 4 digits display    
    * @endcode

    */
   bool print(const int32_t &value, bool rgtAlgn = false, bool zeroPad = false);
   /**
    * @brief Displays a floating point value.  
    * 
    * The floating point value will be displayed as long as the length representation fits the available space of the display. If the integer part of value is not in the displayable range or if the sum of the spaces needed by the integer part plus the indicated decimal places to display is greater than the available digits space, the **`print()`** will fail, returning a false value and clearing the display.
    * 
    * @param value The floating point value which must be in the range ((-1)*(pow(10, ((dspDigits - decPlaces) - 1)) - 1)) <= value <= (pow(10, (dspDigits - decPlaces)) - 1), or _dspValMin <= value <= _dspValMax.  
    * @param decPlaces Decimal places to be displayed after the decimal point, ranging 0 <= decPlaces < dspDigits, selecting 0 value will display the number as an integer, with no '.' displayed. In any case the only modification that will be applied if value has a decimal part longer than the decPlaces number of digits is **truncation**, if any other rounding criteria is desired the developer must apply it to **value** before calling this method.  
    * @param rgtAlgn Boolean, optional parameter (if not specified the default value, false, will be assumed), indicates if the represented value must be displayed right aligned, with the missing heading characters being completed with spaces or zeros, depending in the zeroPad optional parameter. When a negative value is displayed and it's less than (dspDigits - 1) digits long, a right aligned display will keep the '-' sign in the leftmost position, and the free space to the leftmost digit will be filled with spaces or zeros, depending in the zeroPad optional parameter.  
    * @param zeroPad Boolean, optional parameter (if not specified the default value, false, will be assumed), indicates if the heading free spaces of the value right aligned displayed must be filled with zeros (true) or spaces (false). In the case of a negative value the spaces or zeros will fill the gap between the '-' sign kept in the leftmost position, and the first digit.  
    * 
    * @retval true The value could be represented.  
    * @retval false The value couldn't be represented. The display is blanked.  
    * 
    * Code example (on a 4-bits display):  
    * 
    * @code {.cpp}
    * myLedDisp.print(1.2, 2);   //Displays '1.20 '  
    * myLedDisp.print(1.2, 2, true);   //Displays ' 1.20'  
    * myLedDisp.print(12, 2, true, true); //Displays '01.20'    
    * myLedDisp.print(-1.2, 2);  //Displays '-1.20'  
    * myLedDisp.print(-1.28, 1, true); //Displays '- 1.2'  
    * myLedDisp.print(-1.28, 1, true, true); //Displays '-01.2'    
    * myLedDisp.print(-1.28, 3, true, true); //Error
    * @endcode
    */
   bool print(const double &value, const unsigned int &decPlaces, bool rgtAlgn = false, bool zeroPad = false);
   /**
    * @brief Resets the blinking mask.  
    * 
    * The blinking mask configures which digits of the display will be affected by the **`.blink()`** method. This method resets the mask so that **all** the digits will be affected when blinking is active.  
    * 
    * Code example
    * 
    * @code {.cpp}
    * myLedDisp.resetBlinkMask();  
    * @endcode
    */
   void resetBlinkMask();
   /**
    * @brief Sets a new **blinking mask** for the display.  
    * 
    * The blinking mask indicates which digits will be involved when a **`blink()`** method is invoked. Indicating true for a digit makes it blink when the method is called, indicating false makes it display steady independently of the other digits. The parameter is positional referenced to the display, and for ease of use the index numbers of the array indicate their position relative to the rightmost digit (blnkPort0). The mask might be reset to its original value (all digits set to blink) by using this method with all parameters set to **true** or by using the **`resetBlinkMask()`** method.  
    * 
    * @param newBlnkMsk Array of booleans of length **dspDigits**, indexes are positional referenced to the display, indicating each one which digits must blink after a **`blink()`** method is invoked (true) or stay steady (false). The indexes valid range is 0 <= index <= (dspDigits-1), corresponding the [0] position withe the rightmost display port, the [1] position the second from the right and so on.  
    * 
    * Code example  
    * 
    * @code {.cpp}
    * bool tstMask[4]{true, true, true, true};  
    * testResult = myLedDisp.blink();  //Sets all the  digits to blink in a 4 digits display  
    * tstMask[0] = true;  
    * tstMask[1] = false;  
    * tstMask[2] = false;  
    * tstMask[3] = false;  
    * myLedDisp.setBlinkMask(tstMask); //Sets only the rightmost digit to blink in a 4 digits display  
    * tstMask[0] = false;  
    * tstMask[1] = true;  
    * tstMask[2] = true;  
    * myLedDisp.setBlinkMask(tstMask); //Sets the two central digits to blink in a 4 digits display
    * @endcode
    */
   void setBlinkMask(const bool* newBlnkMsk);
   /**
    * @brief Changes the time parameters to use for the display blinking of the contents it shows.  
    * 
    * The parameters change will take immediate effect, either if the display is already blinking or not, in the latter case the parameters will be the ones used when a **`blink()`** method is called without parameters. The blinking will be **symmetrical** if only one parameter is passed, **asymmetrical** if two different parameters are passed, meaning that the time the display shows the contents and the time the display is blank will be equal (symmetrical) or not equal (asymmetrical), depending of those two parameters. The blink rate set will be kept after a **`noBlink()`** or new **`blink()`** without parameters call is done, until it is modified with a new **`setBlinkRate()`** call, or it is restarted by a **`blink()`** with parameters. Note that to restart the blinking with a **`blink()`** the service must first be stopped, as the method makes no changes if the blinking service was already running.  
    * 
    * @param newOnRate unsigned long integer containing the time (in milliseconds) the display must stay on, the value must be in the range _minBlinkRate <= onRate <= _maxBlinkRate. Those built-in values can be known by the use of the **`getMinBlinkRate()`** and the **`getMaxBlinkRate()`** methods.  
    * @param newOffRate optional unsigned long integer containing the time (in milliseconds) the display must stay off, the value must be in the range _minBlinkRate <= offRate <= _maxBlinkRate. Those built-in values can be known by the use of the **`getMinBlinkRate()`** and the **`getMaxBlinkRate()`** methods. If no offRate value is provided the method will assume it's a symmetric blink call and use a value of offRate equal to the value passed by onRate.  
    * 
    * @return true The parameter or parameters passed are within the valid range, The change will take effect immediately.  
    * @return false One or more of the parameters passed were out of range. The rate change would not be made for none of the parameters.  
    * 
    * Code example
    * 
    * @code {.cpp}
    * myLedDisp.setBlinkRate(400);  //Returns true and sets the blinking rate to 400 millisecs on, 400 millisecs off (symmetrical blink).  
    * myLedDisp.setBlinkRate(800, 200);   //Returns true and sets the blinking rate to 800 millisecs on, 200 millisecs off (asymmetrical blink)  
    * myLedDisp.setBlinkRate(3000); //Returns false and the display blinking rate stays without change.  
    * myLedDisp.setBlinkRate(600, 3500);  //Returns false and the display blinking rate stays without change.  
    * @endcode
    */
   bool setBlinkRate(const uint32_t &newOnRate, const uint32_t &newOffRate = 0);
   /**
    * @brief Set the brightness level for the display
    * 
    * For the brightness level settin to succeed two conditions must be met:  
    * 1) The display must be dimmable (see setBrghtnssLvl() )
    * 2) The new brightness level must be in the valid range for the display: getMinBrghtnssLvl() <= newBrghtnssLvl <= getMaxBrghtnssLvl()
    * 
    * @param newBrghtnssLvl The new value setting for the brightness level
    * @return true The display is dimmable, and the newBrghtnssLvl is in the valid range, the change is made
    * @return false The display is not dimmable, or the newBrghtnssLvl is outside the valid range, no change is made
    */
   bool setBrghtnssLvl(const uint8_t &newBrghtnssLvl);    
   /**
    * @brief Sets the "Waiting" character.  
    * 
    * The character used by the display to show the "process ongoing" a.k.a. "Waiting mode" can be changed. The default character set is the "-" (minus sign). The parameters change will take immediate effect, either if the display is already in wait mode or not. The new character will be changed for further calls of the method until a new setWaitChar is invoked with a valid argument, that means a "displayable character".  
    * 
    * @param newChar A character the display must use for symbolizing the progress, the value must be in the displayable characters group as explained in the print() method.  
    * @return true The character passed is within the displayable characters range, the change will take effect immediately.  
    * @return false The parameter passed was invalid, i.e. it was a non displayable character, the character change will not be made.  
    * 
    * Code example  
    * 
    * @code {.cpp}
    * myLedDisp.setWaitRate('_');   // Returns true and sets the wait character to '_'.  
    * myLedDisp.setWaitRate('#');   // Error, returns false and the display wait character stays without change.  
    * @endcode
    */
   bool setWaitChar (const char &newChar);
   /**
    * @brief Changes the timing parameter used to show the "progress ongoing bar advancement" speed.  
    * 
    * The parameter change will take immediate effect, either if the display is already in wait mode or not, in the latter case the parameter will be the one used when a **`wait()`** method is called without parameters. The wait rate set will be kept after a **`noWait()`** or new **`wait()`** without parameters call is done, until it is modified with a new **`setWaitRate()`** call, or it is restarted by a **`wait()`** with parameters. Note that to restart the waiting with a **`wait()`** the service must first be stopped, as the method makes no changes if the waiting service was already running.  
    * 
    * @param newWaitRate unsigned long integer containing the time (in milliseconds) the display must take to advance the next character symbolizing the progress, the value must be in the range _minBlinkRate <= newWaitRate <= _maxBlinkRate. Those values can be known by the use of the **`getMinBlinkRate()`** and the **`getMaxBlinkRate()`** methods.  
    * 
    * @retval true The parameter passed is within the valid range, the change takes effect.
    * @retval false The parameter passed was out of range, the rate change will not be made.  
    * 
    * Code example  
    * 
    * @code {.cpp}
    * myLedDisp.setWaitRate(400);   //Returns true and sets the advancement rate to 400 millisecs.  
    * myLedDisp.setWaitRate(myLedDisp.getMinBlinkRate() - 10); //Returns false and the display wait rate stays without change.  
    * @endcode
    */
   bool setWaitRate(const uint32_t &newWaitRate);
   /**
    * @brief Turns the display module off.  
    * 
    * The display module will be cleared and will keep that status until a turnOn(), or turnOn(const uint8_t &) is invoked. 
    */ 
   void turnOff();
   /**
    * @brief Turns the display module on.  
    * 
    * The display module will be turned on and it's content displayed, and will keep that status until a turnOff() is invoked.  
    */
   void turnOn();
   /**
    * @brief Turns the display module on.  
    * 
    * The display module will be turned on, it's brightness level set to the requested level, it's content displayed, and will keep that status until a turnOff() is invoked. 
    * 
    * @param newBrghtnssLvl The new brightness level for the display. See setBrghtnssLvl(const uint8_t &) for details
    */
   void turnOn(const uint8_t &newBrghtnssLvl);
   /**
    * @brief Makes the display enter the "Waiting mode"  
    * 
    * While in "Waiting mode" the display shows a simple animated progress bar or "process ongoing bar" until a **`noWait()`** method is invoked. The speed rate for the progress animation starts at a parameter passed rate when the method is invoked, or the last speed set will be used, having a preset value for the first time it's invoked if no parameter is passed. The animation rate can be changed by using the **`setWaitRate()`** method. The speed rate set will be kept after a **`noWait()`** or new **`wait()`** without parameters call is done, until it is modified with a new **`setWaitRate()`** call, or it is restarted by a **`wait()`** with a parameter. Note that to restart the waiting with a **`wait()`** the service must first be stopped, as the method makes no changes if the waiting service was already running.  
    * 
    * @return true The display was not already set to wait (so now the "Waiting state" was started).  
    * @return false The display was already set to wait, and/or the parameter passed was out of range. 
    * 
    * @attention The **Waiting state** is considered transitory state (or situation), as in most systems a "progression bar" is used it's main target is to show the system is not stalled or crashed, it's just waiting for a process to end. As a transitory state, the value displayed before entering the "Waiting state" will be saved, and will be restored automaticaly when the "Waiting state" is ended by the use of the `noWait()` method.  
    * 
    * Code example  
    * 
    * @code {.cpp}
    * myLedDisp.wait(); //Returns true and shows advancement animation to the already set value.  
    * myLedDisp.wait(800); //Returns true and sets the advancement animation rate to 800 millisecs.  
    * myLedDisp.wait(getMaxBlinkRate() + 10);   //Returns false and the display stays without change.  
    * @endcode
    */
   bool wait();
   /**
    * @brief Makes the display enter the "Waiting mode" with a specific wait rate 
    * 
    * The method is similar to the **`wait()`** method, the only difference is that before entering the "Waiting state" a **`setWaitRate()`** is executed, using the provided argument to set the new wait rate.  
    * 
    * @param newWaitRate A new rate for the animated progress bar or "process ongoing bar".  
    * 
    * @return true The display was not already set to wait (so now the "Waiting state" was started).  
    * @return false The display was already set to wait, and/or the parameter passed was out of range.  
    * 
    * @attention The **Waiting state** is considered transitory state (or situation), as in most systems a "progression bar" is used it's main target is to show the system is not stalled or crashed, it's just waiting for a process to end. As a transitory state, the value displayed before entering the "Waiting state" will be saved, and will be restored automaticaly when the "Waiting state" is ended by the use of the `noWait()` method. 
    */
   bool wait(const uint32_t &newWaitRate);
   /**
    * @brief Prints one character to the display, at a designated position (digit or port), without affecting the rest of the characters displayed.
    * 
    * @param segments An unsigned short integer value representing which segments to turn on and which off to get the graphic representation of a character in the seven segment display, the corresponding value can be looked up in the **_charLeds[]** array definition in the header file of the library. In the case of a common cathode display the values there listed must be complemented. Any other uint8_t (char or unsigned short int is the same here) value is admissible, but the displayed result might not be easily recognized as a known ASCII character.  
    * @param port unsigned short integer value representing the position or digit where the character will be sent, being the range of valid values 0 <= port <= (dspDigits - 1), the 0 value is the rightmost digit, the 1 value the second from the right and so on.
    * 
    * @retval true The parameters are within the acceptable range, in this case 0 <= port <= (dspDigits - 1).  
    * @retval false: The port value was outside the acceptable range.  
    * 
    * Code example
    * 
    * @code {.cpp}
    * myLedDisp.write(0xA4, 1);  // Modifies the displayed data, placing a '2' in the second digit from right to left in a common anode display.
    * myLedDisp.write(0xB9, 0);  // Modifies the displayed data, placing a non ASCII identifiable shape, with the central horizontal (g segment) and the two vertical rightside segments (b & c) lit, in the first digit from right to left in a common anode display.
    * @endcode
    */
   bool write(const uint8_t &segments, const uint8_t &port);
   /**
    * @brief Prints one character to the display, at a designated position (digit or port), without affecting the rest of the characters displayed.
    * 
    * @param character A single character string that must be displayable, as defined in the **`print()`** method.  
    * @param port unsigned short integer value representing the position or digit where the character will be sent, being the range of valid values 0 <= port <= (dspDigits - 1), the 0 value is the rightmost digit, the 1 value the second from the right and so on.
    * 
    * @retval true **character** is a displayable one char string, and **port** value is in the range 0 <= value <= (dspDigits - 1).  
    * @retval false **character** was not "displayable" or the **port** value was out of range.   
    * 
    * Use example
    * 
    * @code {.cpp}
    * myLedDisp.write("A", 1);   // Modifies the displayed data, placing a 'A' in the second digit from right to left, returns true  
    * myLedDisp.write("X", 1);   // Fails as "X" is not a displayable character, returns false.  
    * @endcode
    */
   bool write(const String &character, const uint8_t &port);
};

#endif  //_SevenSegDisplays_H_