/*
 * Copyright (C) 2020-2021 Aloysius Indrayanto
 *
 * This file is part of the eCxx library, see LICENSE file for the license details.
 */


#ifndef ECXX_PLATFORM_MAX72XX_SEVEN_SEGMENT_DRIVER_H
#define ECXX_PLATFORM_MAX72XX_SEVEN_SEGMENT_DRIVER_H


#include "MAX72XXMatrixDriver.h"


namespace eCxx {


//
// A simple MAX7219/MAX7221-based 7-segment driver
//
// NOTE : This class is derived from the MAX72XXMatrixDriver class and thus inherits its characteristics.
//
class MAX72XXSevenSegmentDriver : public MAX72XXMatrixDriver {
    public:
        // The number of digits per module (it is always 8 seven-segments per module)
        static constexpr uint8_t DigitPerModule = MAX72XXMatrixDriver::RowPerModule;

        static constexpr uint8_t MaxIntensity   = MAX72XXMatrixDriver::MaxIntensity; // Maximum LED intensity (brightness)
        static constexpr uint8_t DefIntensity   = MAX72XXMatrixDriver::DefIntensity; // Default LED intensity (brightness)

    public:
        inline MAX72XXSevenSegmentDriver() = default;
        inline ~MAX72XXSevenSegmentDriver() = default;

        /*
         * Requirements on the memory pointed by the 'byteBuffer' parameter:
         *     # It can point to a static/global, stack, or heap memory; however, it cannot be a nullptr.
         *     # It must be available for use until end() is called.
         *     # It must be able to hold (numMod * DigitPerModule) bytes.
         *
         * Some MAX72XX 7-segment modules have the digit zero as the leftmost digit, while others may
         * have the digit zero as the rightmost digit. By default, 'reverseDigitDirection' is set to 'true'.
         * In practice, if the resulting display is reversed, set 'reverseDigitDirection' to 'false'.
         */
        bool begin(uint8_t pinData, uint8_t pinClock, uint8_t pinLatch, uint8_t numMod, uint8_t* byteBuffer, bool reverseDigitDirection = true);

        inline void end()
        { MAX72XXMatrixDriver::end(); }

        // Replace the raw byte buffer (it is needed when using double or custom buffering)
        // NOTE : The 'rawByteBuffer' parameter cannot be a nullptr
        void setRawByteBuffer(const uint8_t* rawByteBuffer);

        /*
         * Set digit at the given position (index)
         *     # index : valid digit index is from 0 to (numMod * DigitPerModule - 1)
         *     # value : valid values to be decoded are '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
         *                                              'A', 'b', 'c', 'd', 'E', 'F', '-', 'L', 'H', 'P', and ' '
         */
        bool setDigit(uint8_t index, char value, bool dot = false);

        /*
         * Set custom digit at the given position (index)
         *     Byte    : 7   6 5 4 3 2 1 0
         *     Segment : Dot A B C D E F G
         */
        void setCustomDigit(uint8_t index, uint8_t value);

        // Clear (blank) all digits
        void clearAllDigits();

        // Update (send new data bytes)
        inline void update()
        { MAX72XXMatrixDriver::packedUpdated(); }

    public:
        void updateExt() = delete;

        void packedUpdated(const uint8_t*) = delete;
        void packedUpdated(PGMCharPointer) = delete;
        void packedUpdated(PGMCharPointerFar) = delete;

    private:
        bool _reverseDigitDir;
};


} // namespace eCxx


#endif
