Program Listing for File M41T62_regs.hpp

Return to documentation for file (include/library/M41T62_regs.hpp)

#pragma once

#include <cstdint>
#include <ctime>

namespace M41T62Regs {

enum registerAddresses {
    FractionsOfSeconds = 0,
    Seconds,
    Minutes,
    Hours,
    Day,
    Date,
    CenturyMonth,
    Year,
    Calibration,
    Watchdog,
    AlarmMonth,
    AlarmDate,
    AlarmHour,
    AlarmMinute,
    AlarmSecond,
    Flags,
    MaxAddress,
};

union M41T62_dev_t {
    struct {
        struct {
            std::uint8_t hundredthsOfSecond : 4;
            std::uint8_t tenthsOfSecond : 4;
        };

        struct {
            std::uint8_t second : 4;
            std::uint8_t tensOfSeconds : 3;
            std::uint8_t stopBit : 1;
        };

        struct {
            std::uint8_t minute : 4;
            std::uint8_t tensOfMinutes : 3;
            std::uint8_t oscillatorFailInterruptEnable : 1;
        };

        struct {
            std::uint8_t hour : 4;
            std::uint8_t tensOfHours : 2;
            std::uint8_t zeros0 : 2;
        };

        struct {
            std::uint8_t dayOfWeek : 3;
            std::uint8_t zero1 : 1;
            std::uint8_t sqwResolution : 4;
        };

        struct {
            std::uint8_t day : 4;
            std::uint8_t tensOfDays : 2;
            std::uint8_t zeros2 : 2;
        };

        struct {
            std::uint8_t month : 4;
            std::uint8_t tensOfMonths : 1;
            std::uint8_t zero3 : 1;
            std::uint8_t century : 2; //These bits are arbitrary, they get incremented at the turn of century, but they do not have defined meaning...
        };

        struct {
            std::uint8_t year : 4;
            std::uint8_t tensOfYears : 4;
        };

        struct {
            std::uint8_t calibration : 5;
            std::uint8_t signBit : 1;
            std::uint8_t zero4 : 1;
            std::uint8_t outputLevel : 1;
        };

        struct {
            std::uint8_t resolution01 : 2;
            std::uint8_t multiplier : 5;
            std::uint8_t resolution2 : 1;
            // FIXME: add method to parse the values (possibly operator=)
        } watchdog;

        struct {
            struct {
                std::uint8_t month : 4;
                std::uint8_t tensOfMonths : 1;
                std::uint8_t zero5 : 1;
                std::uint8_t sqwEnable : 1;
                std::uint8_t alarmFlagEnable : 1;
            };

            struct {
                std::uint8_t day : 4;
                std::uint8_t tensOfDays : 2;
                std::uint8_t repeatMode45 : 2;
            };

            struct {
                std::uint8_t hour : 4;
                std::uint8_t tensOfHours : 2;
                std::uint8_t zero6 : 1;
                std::uint8_t repeatMode3 : 1;
            };

            struct {
                std::uint8_t minute : 4;
                std::uint8_t tensOfMinutes : 3;
                std::uint8_t repeatMode2 : 1;
            };

            struct {
                std::uint8_t second : 4;
                std::uint8_t tensOfSeconds : 3;
                std::uint8_t repeatMode1 : 1; // For some reason it starts with 1, see datasheet
            };

        } alarm;

        struct {
            std::uint8_t zeros7 : 2;
            std::uint8_t oscillatorFail : 1;
            std::uint8_t zeros8 : 3;
            std::uint8_t alarmFlag : 1;
            std::uint8_t watchdogFlag : 1;
        };
    };

    std::uint8_t regs[MaxAddress];

    std::tm time() const {
        std::tm newTime;

        newTime.tm_sec = (tensOfSeconds * 10) + second;
        newTime.tm_min = (tensOfMinutes * 10) + minute;
        newTime.tm_hour = (tensOfHours * 10) + hour;
        newTime.tm_wday = dayOfWeek - 1;
        newTime.tm_mday = (tensOfDays * 10) + day;
        newTime.tm_mon = (tensOfMonths * 10) + month - 1;
        newTime.tm_year = (century * 100) + (tensOfYears * 10) + year;
        return newTime;
    }
    void time(std::tm time) {
        second = time.tm_sec % 10;
        tensOfSeconds = time.tm_sec / 10;

        minute = time.tm_min % 10;
        tensOfMinutes = time.tm_min / 10;

        hour = time.tm_hour % 10;
        tensOfHours = time.tm_hour / 10;

        dayOfWeek = time.tm_wday + 1;
        day = time.tm_mday % 10;
        tensOfDays = time.tm_mday / 10;

        month = (time.tm_mon + 1) % 10;
        tensOfSeconds = (time.tm_mon + 1) / 10;

        year = time.tm_year % 10;
        tensOfYears = (time.tm_year % 100) / 10;
        century = ((time.tm_year % 1000) / 100);
    }
};

constexpr std::uint8_t defaultValues[MaxAddress] = {
    0,
    0,
    0,
    0,
    1 << 4,
    0,
    0,
    0,
    0,
    0,
    1 << 6,
    0,
    0,
    0,
    0,
    0
};

enum class AlarmRepeatMode {
    OncePerYear = 0b00000,
    OncePerMonth = 0b10000,
    OncePerDay = 0b11000,
    OncePerHour = 0b11100,
    OncePerMinute = 0b11110,
    OncePerSecond = 0b11111,
};

enum class WatchdogResolution {
    SixteenthOfSecond = 0b000,
    FourthOfSecond = 0b001,
    OneSecond = 0b010,
    FourSeconds = 0b011,
    OneMinute = 0b010,
};

constexpr std::uint8_t sqwBits(unsigned frequency) {
    if (frequency >= 32768)
        return 0b0001;
    if (frequency == 0)
        return 0;
    std::uint8_t out = 1;
    while (frequency >>= 1)
        out++;
    return out;
}
} // namespace M41T62Regs