Justin Howard / RTclock

Dependents:   AdaFruit_RGBLCD

RTclock.cpp

Committer:
vtraveller
Date:
2014-08-09
Revision:
1:8952befe5d36
Parent:
0:98b84d9c8c96
Child:
2:3dc63e48cb5d

File content as of revision 1:8952befe5d36:

#include "mbed.h"
#include "RTclock.h"

const char * RTclock::m_aWeekDays[] = { "Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" };

RTclock::RTclock(PinName in_nSDA, PinName in_nSCL, bool in_bHiSpeed)
    : RTclock_parent(in_nSDA,in_nSCL)
{        
    // Frequency depends on chip - most are 100KHz
    frequency(in_bHiSpeed ? 400000 : 100000);
}

RTclock::~RTclock()
{
}

int RTclock::BcdToDecimal(int in_nBCD)
{
    return ((in_nBCD & 0xF0) >> 4) * 10 + (in_nBCD & 0x0F);
}

int RTclock::DecimalToBcd(int in_nDecimal)
{
    return (in_nDecimal % 10) + ((in_nDecimal / 10) << 4);
}

bool RTclock::GetTime(tm & out_sTM)
{
    char aBuffer[7];
    bool b12hour = false;
    
    if (!read(0, aBuffer, 7)) return false;

    b12hour = ((aBuffer[2] & 64) == 64);
    out_sTM.tm_sec = BcdToDecimal(aBuffer[0] & 0x7F);
    out_sTM.tm_min = BcdToDecimal(aBuffer[1]);
    
    if (b12hour)
    {
        // add 12 hours if PM bit is set
        out_sTM.tm_hour = BcdToDecimal(aBuffer[2] & 31);
        if (aBuffer[2] & 32) out_sTM.tm_hour += 12;
    }
    else
    {
        out_sTM.tm_hour = BcdToDecimal(aBuffer[2] & 63);
    }
    
    out_sTM.tm_wday = aBuffer[3]; 
    out_sTM.tm_mday = BcdToDecimal(aBuffer[4]);
    out_sTM.tm_mon  = BcdToDecimal(aBuffer[5]);
    out_sTM.tm_year = (BcdToDecimal(aBuffer[6]) + 2000) - 1900;   //  Returns from 2000, need form 1900 for time function
    out_sTM.tm_isdst = 0;
    
    return true;
}

const char * RTclock::GetWeekday(int in_nWeekDay)
{
    return m_aWeekDays[in_nWeekDay];
}

bool RTclock::MapTime()
{
    tm sTM;
    if (!GetTime(sTM)) return false;
    
    // Convert and set internal time
    time_t nTime = ::mktime(&sTM);
    ::set_time(nTime);
    
    return true;
}

bool RTclock::read(int in_nAddress, char * out_pBuffer, int in_nLength)
{
    char aBuffer[2] = { (char)in_nAddress, 0 };
    
    if (0 != RTclock_parent::write(0xd0, aBuffer, 1)) return false;
    if (0 != RTclock_parent::read(0xd0, out_pBuffer, in_nLength)) return false;
    
    return true;
}

bool RTclock::SetTime(const tm  & in_sTM)
{
    char aBuffer[7];

    // Preserve flags that were in register
    if (!read(0,aBuffer,7)) return false;
    
    aBuffer[0] &= 0x7F;
    aBuffer[0] = (aBuffer[0] & 0x80) | (DecimalToBcd(in_sTM.tm_sec)& 0x7f);
    aBuffer[1] = DecimalToBcd(in_sTM.tm_min);    
    aBuffer[2] = (aBuffer[2] & 196) | (DecimalToBcd(in_sTM.tm_hour) & 0x3F);
    aBuffer[3] = in_sTM.tm_wday;
    aBuffer[4] = DecimalToBcd(in_sTM.tm_mday);
    aBuffer[5] = DecimalToBcd(in_sTM.tm_mon);
    aBuffer[6] = DecimalToBcd(in_sTM.tm_year-2000);

    // Write new date and time
    SetRunning(false);
    
    bool bSuccess = write(0, aBuffer, 7);
    
    if (bSuccess) SetRunning(true);

    return bSuccess;
}

bool RTclock::SetRunning(bool in_bEnable)
{
    char nRunning;
    
    if (!read(0, &nRunning, 1)) return false;

    // Set running
    if (in_bEnable)
    { 
        nRunning &= 0x7F;
    }
    else
    {
        nRunning |= 0x80;
    }
    
    return write(0, &nRunning, 1);
}

bool RTclock::SetSquareWaveOutput
(
    bool                in_bEnable,
    ESquareWaveRates    in_nRateSelect
)
{
    char nValue;
    
    // Read register    
    if (!read(7, &nValue, 1)) return false;
    
    //  Protect control bits
    nValue = (nValue & 0x80) | (in_bEnable ? 0x10 : 0) | ((char)in_nRateSelect & 0x03);
    
    return write(7, &nValue, 1);
}

bool RTclock::write(int in_nAddress, const char * in_pBuffer, int in_nLength)
{    
    char aBuffer[10];
    
    aBuffer[0] = in_nAddress & 0xff;
    
    for (size_t i = 0 ; i < in_nLength; i++)
        aBuffer[i + 1] = in_pBuffer[i];

    return RTclock_parent::write(0xd0, aBuffer, in_nLength + 1);
}