/*
* ds1302.cpp: part of the "VoluMaster(tm)" system
*
* An open-source arduino controller-based digital volume control and input/output selector
*
*
* LICENSE
* -------
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "ds1302.h"
#include // not needed yet
#include // needed for strlen()
#include
#include "WConstants.h" // all things wiring / arduino
#include "config.h"
const char DOWStr[8][4] = {" ", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
const char MonthStr[13][4] = {" ", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
// Max days for each month
const unsigned char MaxDays[13] = {99,31,29,31,30,31,30,31,31,30,31,30,31};
static void send1302cmd( unsigned char cmd1, unsigned char cmd2 );
static unsigned char get1302data( unsigned char cmd );
static void ds1302_init( void );
static unsigned char shiftin( void );
static unsigned char DayMap;
static unsigned char Hrs; // Hrs has 12/24 and AM/PM bits stripped
static unsigned char Mins;
static unsigned char Secs; // DS1302's BCD values
// ctor
DS1302::DS1302( void )
{
// init();
}
unsigned char
DS1302::GetHrs( void )
{
return Hrs;
}
unsigned char
DS1302::GetMins( void )
{
return Mins;
}
unsigned char
DS1302::GetSecs( void )
{
return Secs;
}
void
DS1302::SetHrs( unsigned char val )
{
Hrs = val;
}
void
DS1302::SetMins( unsigned char val )
{
Mins = val;
}
void
DS1302::SetSecs( unsigned char val )
{
Secs = val;
}
void
DS1302::init( void )
{
/*
* setup RTC (realtime hardware chip-based clock)
*/
pinMode(CE1302_PIN, OUTPUT);
pinMode(DAT1302_PIN, OUTPUT);
pinMode(CLK1302_PIN, OUTPUT);
// This routine is, most likely, called with the DS1302 running on the
// supercap or battery backup, so it is important to preserve its
// time values.
send1302cmd(WriteCtrl, 0); // Clear write protect
Secs = get1302data(ReadSecs); // Clear CH bit, preserving secs reg
Secs &= B01111111;
send1302cmd(WriteSecs, Secs);
#ifdef USE_12_HR_TIME_FORMAT
Hrs = get1302data(ReadHrs); // Set 12 hour format,
// preserving hrs reg value
(Hrs & B00100000) ? PMFlag = 1 : PMFlag = 0;
Hrs |= B10000000; // bit 7 in 1302's hours reg
// sets 12 hour format
send1302cmd(WriteHrs, Hrs);
Hrs &= B00011111; // Store Hrs locally
// without flag bits
#endif
send1302cmd(WriteTrickle, TrickleSet); // begin charging the supercap
#ifdef USE_12_HR_TIME_FORMAT
PMFlag = 0;
#endif
}
//======================= Service Routines ================================//
void
DS1302::GetTime(void)
{
Secs = get1302data(ReadSecs);
Mins = get1302data(ReadMins);
Hrs = get1302data(ReadHrs);
#ifdef USE_12_HR_TIME_FORMAT
// set PM flag
( (Hrs & B00100000) > 0) ? PMFlag = 1 : PMFlag = 0;
Hrs &= B00011111;
#endif
}
// Write time to DS1302
void
DS1302::SetTime(void)
{
#ifdef USE_12_HR_TIME_FORMAT
(PMFlag) ? temp = Hrs | B10100000 : temp = Hrs | B10000000;
DS1302::send1302cmd(WriteHrs, temp);
#endif
send1302cmd(WriteHrs, Hrs);
send1302cmd(WriteMins, Mins);
send1302cmd(WriteSecs, Secs);
}
static uint8_t
ds_bcd2bin( const uint8_t val )
{
return (((val >> 4) * 10) + (val & 0x0f));
}
unsigned long
DS1302::get_abs_time( void )
{
unsigned long total_time; // in minutes, ignoring seconds
GetTime(); // read all regs of the RTC chip
total_time = 60 * ds_bcd2bin(GetHrs()) + ds_bcd2bin(GetMins());
return total_time;
}
// =================== DS1302 Driver Routines ==============================//
static void
send1302cmd( unsigned char cmd1, unsigned char cmd2 )
{
digitalWrite(CE1302_PIN, 1); // Set CE1302 high
delayMicroseconds(2);
shiftOut(DAT1302_PIN, CLK1302_PIN, LSBFIRST, cmd1);
delayMicroseconds(2); // This delay might not be needed
shiftOut(DAT1302_PIN, CLK1302_PIN, LSBFIRST, cmd2);
digitalWrite(CE1302_PIN, 0); // Set CE1302 low
}
static unsigned char
get1302data( unsigned char cmd )
{
unsigned char dat;
digitalWrite(CE1302_PIN, 1); // CE1302 high
shiftOut(DAT1302_PIN, CLK1302_PIN, LSBFIRST, cmd);
dat = shiftin();
digitalWrite(CE1302_PIN, 0); // CE1302 low
return (dat);
}
// Shifts in a byte from the DS1302.
// This routine is called immediately after a shiftout. The first bit is
// present on DAT1302 at call, so only 7 additional clock pulses are
// required.
// Restores DAT1302 to OUTPUT prior to return.
static unsigned char
shiftin( void )
{
unsigned char dat = 0;
int i = 0;
pinMode(DAT1302_PIN, INPUT); // Set DAT1302 as input
for (i=0; i < 7; i++) {
if (digitalRead(DAT1302_PIN) == 1) {
dat |= B10000000; // we found a 1-bit, so add it to our collection ;)
}
dat >>= 1; // shift over so that we can logical-OR the next 1-bit (if any)
digitalWrite(CLK1302_PIN, 1); // Strobe in next data bit using CLK1302
delay(1);
digitalWrite(CLK1302_PIN, 0);
delay(1);
}
pinMode(DAT1302_PIN, OUTPUT); // Restore DAT1302 as output
return (dat);
}