x
Revision 0:04311b121ac4, committed 2018-07-23
- Comitter:
- JackB
- Date:
- Mon Jul 23 12:24:33 2018 +0000
- Commit message:
- MCP79412
Changed in this revision
diff -r 000000000000 -r 04311b121ac4 MCP79412.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MCP79412.cpp Mon Jul 23 12:24:33 2018 +0000 @@ -0,0 +1,1808 @@ +#include "MCP79412.h" + +MCP79412::MCP79412(PinName sda, PinName scl) : _i2c(sda, scl) +{ + _address_RTC = MCP79412_RTC_ADDR << 1; + squareWave(SQWAVE_1_HZ); +// setTimeZone(1); +// dayLightSaving = true; + setI2Cfrequency(400000); +} + +void MCP79412::setI2Cfrequency(int freq) +{ + _i2c.frequency(freq); +} + +// get a uint8_t containing just the requested bits +// pass the register address to read, a mask to apply to the register and +// an uint* for the output +// you can test this value directly as true/false for specific bit mask +// of use a mask of 0xff to just return the whole register uint8_t +// returns true to indicate success + /** Get flag + * @param reg : register address + * @param mask : flag mask + * @return The register content + */ +bool MCP79412::getFlag(char reg, char mask, char *flag) +{ + char buf[1]; + buf[0] = reg; + int w = _i2c.write(_address_RTC, buf, 1); + int r = _i2c.read(_address_RTC, buf, 1); + _error = ((w != 0) || (r != 0)); + // return only requested flag + *flag = (buf[0] & mask); + return flag == 0 ? false : true; +} + +// set/clear bits in a uint8_t register, or replace the uint8_t altogether +// pass the register address to modify, a uint8_t to replace the existing +// value with or containing the bits to set/clear and one of +// MCP79412_SET/MCP79412_CLEAR/MCP79412_REPLACE +// returns true to indicate success + /** Set flag + * @param reg : register address + * @param bits : bits to set or reset + * @param mode : MCP79412_REPLACE, MCP79412_SET, MCP79412_CLEAR + * @return none + */ +void MCP79412::setFlag(char reg, char bits, char mode) +{ + char buf[2]; + buf[0] = reg; + // get status register + int w = _i2c.write(_address_RTC, buf, 1); + int r = _i2c.read(_address_RTC, buf+1, 1); + // clear the flag + if (mode == MCP79412_REPLACE) + buf[1] = bits; + else if (mode == MCP79412_SET) + buf[1] |= bits; + else + buf[1] &= ~bits; + int w2 = _i2c.write(_address_RTC, buf, 2); + _error = ((w != 0) || (r != 0) || (w2 != 0)); +} + +// read a register +int MCP79412::readRegister(char reg) +{ +// int w = _i2c.write(_address_RTC, ®, 1); +// char rtn; +// int r = _i2c.read(_address_RTC, &rtn, 1); +// _error = ((w != 0) || (r != 0)); +// return rtn; + + char buf[1]; + buf[0] = reg; + int w = _i2c.write(_address_RTC, buf, 1); + int r = _i2c.read(_address_RTC, buf, 1); + _error = ((w != 0) || (r != 0)); + return(buf[0]); +} + +// read registers +void MCP79412::readRegisters(char reg, char *outbuf, char length) +{ + char buf[1]; + buf[0] = reg; + int w = _i2c.write(_address_RTC, buf, 1); + int r = _i2c.read(_address_RTC, outbuf, length); + _error = ((w != 0) || (r != 0)); +} + +// write a register +void MCP79412::writeRegister(int reg, char uint8_t) +{ + char buf[2]; + buf[0] = reg; + buf[1] = uint8_t; + int w = _i2c.write(_address_RTC, buf, 2); + _error = (w != 0); +} + +// write registers +void MCP79412::writeRegisters(int reg, char *inbuf, char length) +{ + char buf[32]; + buf[0] = reg; + for (int i = 1; i <= length; i++) { + buf[i] = inbuf[i-1]; + } + int w = _i2c.write(_address_RTC, buf, length+1); + _error = (w != 0); +} + + +// Function to read the mac address from the eeprom +void MCP79412::getMacAddress(char *mac_address) +{ + char buf[1]; + buf[0] = MAC_LOCATION; + int w = _i2c.write(MCP79412_EEPROM_ADDR, buf, 1); + int r = _i2c.read(MCP79412_EEPROM_ADDR, mac_address, 6); + _error = ((w != 0) || (r != 0)); +} + +// Unlock the unique id area and write in the mac address +void MCP79412::writeMacAddress(char *mac_address) +{ + char buf[7]; + unlockUniqueID(); + buf[0] = MAC_LOCATION; + for (int i = 1; i <= 6; i++) { + buf[i] = mac_address[i-1]; + } + int w = _i2c.write(MCP79412_EEPROM_ADDR, buf, 7); + + _error = (w != 0); +} + +// Unlock the unique id area ready for writing +void MCP79412::unlockUniqueID() +{ + // Write 0x55 to the memory location 0x09 + char buf[2]; + buf[0] = UNLOCK_ID_REG; + buf[1] = UNLOCK_ID_CODE1; + int w1 = _i2c.write(MCP79412_RTC_ADDR, buf, 2); + + // Write 0xAA to the memory location 0x09 + buf[0] = UNLOCK_ID_REG; + buf[1] = UNLOCK_ID_CODE2; + int w2 = _i2c.write(MCP79412_RTC_ADDR, buf, 2); + + _error = ((w1 != 0) || (w2 != 0)); +} + +// Set the date/time, set to 24hr and enable the clock +// (assumes you're passing in valid numbers) +void MCP79412::setRtcDateTime( + uint8_t second, // 0-59 + uint8_t minute, // 0-59 + uint8_t hour, // 1-23 + uint8_t dayOfWeek, // 1-7 + uint8_t dayOfMonth, // 1-31 + uint8_t month, // 1-12 + uint8_t year) // 0-99 +{ + char buf[8]; + buf[0] = RTC_LOCATION; + buf[1] = decToBcd(second) & 0x7f; // set seconds and disable clock (01111111, Bit 7, ST = 0) + buf[2] = decToBcd(minute) & 0x7f; // set minutes (01111111) + buf[3] = decToBcd(hour) & 0x3f; // set hours and to 24hr format (00111111, Bit 6 = 0) + buf[4] = _BV(VBATEN) | (decToBcd(dayOfWeek) & 0x07); // set the day and enable battery backup (00000111)|(00001000, Bit 3 = 1) + buf[5] = decToBcd(dayOfMonth) & 0x3f; // set the date in month (00111111) + buf[6] = decToBcd(month) & 0x1f; // set the month (00011111) + buf[7] = decToBcd(year); // set the year (11111111) + int w1 = _i2c.write(MCP79412_RTC_ADDR, buf, 8); + + // Start Clock: + buf[0] = RTC_LOCATION; + buf[1] = _BV(ST) | decToBcd(second); // set seconds and enable clock (10000000) + int w2 = _i2c.write(MCP79412_RTC_ADDR, buf, 2); + + _error = ((w1 != 0) || (w2 != 0)); +} + +// Get the date/time +void MCP79412::getRtcDateTime( + uint8_t *second, + uint8_t *minute, + uint8_t *hour, + uint8_t *dayOfWeek, + uint8_t *dayOfMonth, + uint8_t *month, + uint8_t *year) +{ + char buf[8]; + + buf[0] = RTC_LOCATION; + int w = _i2c.write(MCP79412_RTC_ADDR, buf, 1); + int r = _i2c.read(MCP79412_RTC_ADDR, buf, 7); + + _error = ((w != 0) || (r != 0)); + + // A few of these need masks because certain bits are control bits + *second = bcdToDec(buf[0] & 0x7f); // 01111111 0-59 + *minute = bcdToDec(buf[1] & 0x7f); // 01111111 0-59 + *hour = bcdToDec(buf[2] & 0x3f); // 00111111 1-23 + *dayOfWeek = bcdToDec(buf[3] & 0x07); // 00000111 1-7 + *dayOfMonth = bcdToDec(buf[4] & 0x3f); // 00111111 1-31 + *month = bcdToDec(buf[5] & 0x1f); // 00011111 1-12 + *year = bcdToDec(buf[6]); // 11111111 0-99 +} + +bool MCP79412::checkTimeLost(void) +{ + char buf[8]; + uint8_t second, minute, hour, dayOfWeek, dayOfMonth, month, year; + buf[0] = RTC_LOCATION; + int w = _i2c.write(MCP79412_RTC_ADDR, buf, 1); + int r = _i2c.read(MCP79412_RTC_ADDR, buf, 7); + + _error = ((w != 0) || (r != 0)); + + // A few of these need masks because certain bits are control bits + second = bcdToDec(buf[0] & 0x7f); // 01111111 0-59 + minute = bcdToDec(buf[1] & 0x7f); // 01111111 0-59 + hour = bcdToDec(buf[2] & 0x3f); // 00111111 1-23 + dayOfWeek = bcdToDec(buf[3] & 0x07); // 00000111 1-7 + dayOfMonth = bcdToDec(buf[4] & 0x3f); // 00111111 1-31 + month = bcdToDec(buf[5] & 0x1f); // 00011111 1-12 + year = bcdToDec(buf[6]); // 11111111 0-99 + return (year <= 15) ? true : false; +} + +// Enable the clock without changing the date/time +void MCP79412::enableClock() +{ + // Get the current seconds value as the enable/disable bit is in the same + // byte of memory as the seconds value: + char buf[2]; + buf[0] = RTC_LOCATION; + int w1 = _i2c.write(MCP79412_RTC_ADDR, buf, 1); + int r = _i2c.read(MCP79412_RTC_ADDR, buf, 1); + + int second = bcdToDec(buf[0] & 0x7f); // 01111111 + + // Start Clock: + buf[0] = RTC_LOCATION; + buf[1] = _BV(ST) | decToBcd(second); // set seconds and enable clock (10000000, Bit 7, ST = 1) + int w2 = _i2c.write(MCP79412_RTC_ADDR, buf, 2); + + _error = ((w1 != 0) || (r != 0) || (w2 != 0)); +} + +// Disable the clock without changing the date/time +void MCP79412::disableClock() +{ + // Get the current seconds value as the enable/disable bit is in the same + // uint8_t of memory as the seconds value: + char buf[2]; + buf[0] = RTC_LOCATION; + int w1 = _i2c.write(MCP79412_RTC_ADDR, buf, 1); + int r = _i2c.read(MCP79412_RTC_ADDR, buf, 1); + + int second = bcdToDec(buf[0] & 0x7f); // 01111111 + + // Stop Clock: + buf[0] = RTC_LOCATION; + buf[1] = decToBcd(second); // set seconds and disable clock (01111111, Bit 7, ST = 0) + int w2 = _i2c.write(MCP79412_RTC_ADDR, buf, 2); + + _error = ((w1 != 0) || (r != 0) || (w2 != 0)); +} + +// Enable the battery +void MCP79412::enableBattery() +{ + // Get the current day value as the enable/disable bit is in the same + // uint8_t of memory as the seconds value: + char buf[2]; + buf[0] = DAY_REG; + int w1 = _i2c.write(MCP79412_RTC_ADDR, buf, 1); + int r = _i2c.read(MCP79412_RTC_ADDR, buf, 1); + + int day = bcdToDec(buf[0] & 0x07); // 00000111 + + // Start Clock: + buf[0] = DAY_REG; + buf[1] = _BV(VBATEN) | decToBcd(day); // set day and enable battery (00001000) + int w2 = _i2c.write(MCP79412_RTC_ADDR, buf, 2); + + _error = ((w1 != 0) || (r != 0) || (w2 != 0)); +} + + +// Write a single byte of data to RAM +void MCP79412::writeRamByte(uint8_t location, uint8_t data) +{ + writeRamBytes(location, &data, 1); +// char buf[2]; +// if ((location >= SRAM_START_ADDR) && (location <= SRAM_END_ADDR)) +// { +// buf[0] = location; +// buf[1] = data; +// int w = _i2c.write(MCP79412_RTC_ADDR, buf, 2); +// _error = (w != 0); +// } +} + +// Write multiple bytes of data to RAM +uint8_t MCP79412::writeRamBytes(uint8_t location, uint8_t *data, uint8_t length) +{ + uint8_t bytesWritten = 0; + char buf[1]; + buf[0] = location; + int w = _i2c.write(MCP79412_RTC_ADDR, buf, 1); + _error = (w != 0); + for (uint8_t i = 0; i < length; i++) { + buf[0] = data[i]; + int w = _i2c.write(MCP79412_RTC_ADDR, buf, 1); // Returns 0 on success (ack), non-0 on failure (nack) + bytesWritten++; + if (_error == false) { + _error = (w != 0); + } + } + return bytesWritten; +} + +// Read a single byte of data from RAM +uint8_t MCP79412::readRamByte(uint8_t location) +{ + uint8_t data; + readRamBytes(location, &data, 1); + return data; +// char buf[2]; +// if ((location >= SRAM_START_ADDR) && (location <= SRAM_END_ADDR)) +// { +// buf[0] = location; +// int w = _i2c.write(MCP79412_RTC_ADDR, buf, 1); +// int r = _i2c.read(MCP79412_RTC_ADDR, buf, 1); +// +// _error = ((w != 0) || (r != 0)); +// +// return buf[0]; +// } +// return 0; +} + +// Read multiple bytes of data from RAM +uint8_t MCP79412::readRamBytes(uint8_t location, uint8_t *data, uint8_t length) +{ + uint8_t bytesRead = 0; + char buf[1]; + buf[0] = location; + int w = _i2c.write(MCP79412_RTC_ADDR, buf, 1); + _error = (w != 0); + for (uint8_t i = 0; i < length; i++) { + int r = _i2c.read(MCP79412_RTC_ADDR, buf, 1); + bytesRead++; + data[i] = buf[0]; + if (_error == false) { + _error = (r != 0); + } + } + return bytesRead; +} + +// 64 Bytes SRAM, Battery Backed +// Write a single byte of data to SRAM +void MCP79412::writeSramByte(uint8_t location, uint8_t data) +{ + writeSramBytes(location, &data, 1); +// char buf[2]; +// if ((location >= SRAM_START_ADDR) && (location <= SRAM_END_ADDR)) +// { +// buf[0] = location; +// buf[1] = data; +// int w = _i2c.write(MCP79412_RTC_ADDR, buf, 2); +// _error = (w != 0); +// } +} + +// 64 Bytes SRAM, Battery Backed +// Write multiple bytes of data to SRAM +uint8_t MCP79412::writeSramBytes(uint8_t location, uint8_t *data, uint8_t length) +{ + uint8_t bytesWritten = 0; + char buf[1]; + buf[0] = location; + int w = _i2c.write(MCP79412_RTC_ADDR, buf, 1); + _error = (w != 0); + for (uint8_t i = 0; i < length; i++) { + if ((location >= SRAM_START_ADDR) && (location <= SRAM_END_ADDR)) + { + buf[0] = data[i]; + int w = _i2c.write(MCP79412_RTC_ADDR, buf, 1); // Returns 0 on success (ack), non-0 on failure (nack) + bytesWritten++; + if (_error == false) { + _error = (w != 0); + } + } + location++; + } + return bytesWritten; +} + +// 64 Bytes SRAM, Battery Backed +// Read a single byte of data from SRAM +uint8_t MCP79412::readSramByte(uint8_t location) +{ + uint8_t data; + readSramBytes(location, &data, 1); + return data; +// char buf[2]; +// if ((location >= SRAM_START_ADDR) && (location <= SRAM_END_ADDR)) +// { +// buf[0] = location; +// int w = _i2c.write(MCP79412_RTC_ADDR, buf, 1); +// int r = _i2c.read(MCP79412_RTC_ADDR, buf, 1); +// +// _error = ((w != 0) || (r != 0)); +// +// return buf[0]; +// } +// return 0; +} + +// 64 Bytes SRAM, Battery Backed +// Read multiple bytes of data from SRAM +uint8_t MCP79412::readSramBytes(uint8_t location, uint8_t *data, uint8_t length) +{ + uint8_t bytesRead = 0; + char buf[1]; + buf[0] = location; + int w = _i2c.write(MCP79412_RTC_ADDR, buf, 1); + _error = (w != 0); + for (uint8_t i = 0; i < length; i++) { + if ((location >= SRAM_START_ADDR) && (location <= SRAM_END_ADDR)) + { + int r = _i2c.read(MCP79412_RTC_ADDR, buf, 1); + bytesRead++; + data[i] = buf[0]; + if (_error == false) { + _error = (r != 0); + } + } + location++; + } + return bytesRead; +} + +// 128 Bytes EEPROM +// Write a single byte of data to EEPROM +void MCP79412::writeEepromByte(uint8_t location, uint8_t data) +{ + writeEepromBytes(location, &data, 1); +// char buf[2]; +// unlockUniqueID(); +// buf[0] = location & (EEPROM_SIZE - 1); +// buf[1] = data; +// int w = _i2c.write(MCP79412_EEPROM_ADDR, buf, 2); +// _error = (w != 0); +} + +// 128 Bytes EEPROM +// Unlock the unique id area and write multiple of bytes to EEPROM +uint8_t MCP79412::writeEepromBytes(uint8_t location, uint8_t *data, uint8_t length) +{ + uint8_t bytesWritten = 0; + char buf[1]; + unlockUniqueID(); + buf[0] = location & (EEPROM_SIZE - 1); // location & 0x7f + int w = _i2c.write(MCP79412_EEPROM_ADDR, buf, 1); + _error = (w != 0); + for (uint8_t i = 0; i < length; i++) { + if (location < EEPROM_SIZE) + { + buf[0] = data[i]; + int w = _i2c.write(MCP79412_EEPROM_ADDR, buf, 1); // Returns 0 on success (ack), non-0 on failure (nack) + bytesWritten++; + if (_error == false) { + _error = (w != 0); + } + } + location++; + } + return bytesWritten; +} + +// 128 Bytes EEPROM +// Read a single byte of data from EEPROM +uint8_t MCP79412::readEepromByte(uint8_t location) +{ + uint8_t data; + readEepromBytes(location, &data, 1); + return data; +// char buf[2]; +// if ((location >= SRAM_START_ADDR) && (location <= SRAM_END_ADDR)) +// { +// buf[0] = location; +// int w = _i2c.write(MCP79412_RTC_ADDR, buf, 1); +// int r = _i2c.read(MCP79412_RTC_ADDR, buf, 1); +// +// _error = ((w != 0) || (r != 0)); +// +// return buf[0]; +// } +// return 0; +} + +// 128 Bytes EEPROM +// Read multiple bytes of data from EEPROM +uint8_t MCP79412::readEepromBytes(uint8_t location, uint8_t *data, uint8_t length) +{ + uint8_t bytesRead = 0; + char buf[1]; + buf[0] = location & (EEPROM_SIZE - 1); // location & 0x7f + int w = _i2c.write(MCP79412_EEPROM_ADDR, buf, 1); + _error = (w != 0); + for (uint8_t i = 0; i < length; i++) { + if (location < EEPROM_SIZE) + { + int r = _i2c.read(MCP79412_EEPROM_ADDR, buf, 1); + bytesRead++; + data[i] = buf[0]; + if (_error == false) { + _error = (r != 0); + } + } + location++; + } + return bytesRead; +} + +/*----------------------------------------------------------------------* + * Read the calibration register. * + * The calibration value is not a twos-complement number. The MSB is * + * the sign bit, and the 7 LSBs are an unsigned number, so we convert * + * it and return it to the caller as a regular twos-complement integer. * + *----------------------------------------------------------------------*/ +int MCP79412::calibRead(void) +{ + uint8_t val = readRamByte(CALIB_REG); + + if ( val & 0x80 ) { + return -(val & 0x7F); + } + return val; +} + +/*----------------------------------------------------------------------* + * Write the calibration register. * + * Calibration value must be between -127 and 127, others result * + * in no action. See note above on the format of the calibration value. * + *----------------------------------------------------------------------*/ +void MCP79412::calibWrite(int value) +{ + uint8_t calibVal; + + if (value >= -127 && value <= 127) { + calibVal = abs(value); + if (value < 0) { + calibVal += 128; + } + writeRamByte(CALIB_REG, calibVal); + } +} + +/*----------------------------------------------------------------------* + * Read the unique ID. * + * User or factory programmable, Protected area * + * For the MCP79411 (EUI-48), the first two bytes will contain 0xFF. * + * Caller must provide an 8-byte array to contain the results. * + *----------------------------------------------------------------------*/ +void MCP79412::readUniqueId(char *uniqueID) +{ + char buf[1]; + buf[0] = UNIQUE_ID_ADDR; + int w = _i2c.write(MCP79412_EEPROM_ADDR, buf, 1); + int r = _i2c.read(MCP79412_EEPROM_ADDR, uniqueID, UNIQUE_ID_SIZE); + _error = ((w != 0) || (r != 0)); +} + +/*----------------------------------------------------------------------------* + * Returns an EUI-64 ID. For an MCP79411, the EUI-48 ID is converted to * + * EUI-64. For an MCP79412, calling this function is equivalent to * + * calling readUniqueId(). For an MCP79412, if the RTC type is known, calling * + * readUniqueId() will be a bit more efficient. * + * Caller must provide an 8-byte array to contain the results. * + *----------------------------------------------------------------------------*/ +void MCP79412::getEUI64(char *uniqueID) +{ + char rtcID[8]; + + readUniqueId(rtcID); + if ((rtcID[0] == 0xFF) && (rtcID[1] == 0xFF)) { + rtcID[0] = rtcID[2]; + rtcID[1] = rtcID[3]; + rtcID[2] = rtcID[4]; + rtcID[3] = 0xFF; + rtcID[4] = 0xFE; + } + for (uint8_t i = 0; i < UNIQUE_ID_SIZE; i++) { + uniqueID[i] = rtcID[i]; + } +} + +/*----------------------------------------------------------------------* + * Check to see if a power failure has occurred. If so, returns TRUE * + * as the function value, and returns the power down and power up * + * timestamps. After returning the time stamps, the RTC's timestamp * + * registers are cleared and the VBAT bit which indicates a power * + * failure is reset. * + * * + * Note that the power down and power up timestamp registers do not * + * contain values for seconds or for the year. The returned time stamps * + * will therefore contain the current year from the RTC. However, there * + * is a chance that a power outage spans from one year to the next. * + * If we find the power down timestamp to be later (larger) than the * + * power up timestamp, we will assume this has happened, and well * + * subtract one year from the power down timestamp. * + * * + * Still, there is an assumption that the timestamps are being read * + * in the same year as that when the power up occurred. * + * * + * Finally, note that once the RTC records a power outage, it must be * + * cleared before another will be recorded. * + *----------------------------------------------------------------------*/ +bool MCP79412::powerFail(time_t *powerDown, time_t *powerUp) +{ + uint8_t day, yr; //copies of the RTC Day and Year registers + struct tm dn, up; //power down and power up times + char buf[8]; + + readRamBytes(DAY_REG, &day, 1); + readRamBytes(YEAR_REG, &yr, 1); + yr = y2kYearToTm(bcdToDec(yr)); + if ( day & _BV(VBAT) ) { + buf[0] = PWRDWN_TS_REG; + int w = _i2c.write(MCP79412_RTC_ADDR, buf, 1); + + int r = _i2c.read(MCP79412_RTC_ADDR, buf, 8); //read both timestamp registers, 8 bytes total + dn.tm_sec = 0; + dn.tm_min = bcdToDec(buf[0]); + dn.tm_hour = bcdToDec(buf[1] & ~_BV(HR1224)); //assumes 24hr clock + dn.tm_mday = bcdToDec(buf[2]); + dn.tm_mon = bcdToDec(buf[3] & 0x1F); //mask off the day, we don't need it + dn.tm_year = yr; //assume current year + up.tm_sec = 0; + up.tm_min = bcdToDec(buf[4]); + up.tm_hour = bcdToDec(buf[5] & ~_BV(HR1224)); //assumes 24hr clock + up.tm_mday = bcdToDec(buf[6]); + up.tm_mon = bcdToDec(buf[7] & 0x1F); //mask off the day, we don't need it + up.tm_year = yr; //assume current year + + *powerDown = mktime(&dn); + *powerUp = mktime(&up); + + //clear the VBAT bit, which causes the RTC hardware to clear the timestamps too. + //I suppose there is a risk here that the day has changed since we read it, + //but the Day of Week is actually redundant data and the makeTime() function + //does not use it. This could be an issue if someone is reading the RTC + //registers directly, but as this library is meant to be used with the Time library, + //and also because we don't provide a method to read the RTC clock/calendar + //registers directly, we won't lose any sleep about it at this point unless + //some issue is actually brought to our attention ;-) + day &= ~_BV(VBAT); + writeRamBytes(DAY_REG, &day , 1); + + //adjust the powerDown timestamp if needed (see notes above) + if (*powerDown > *powerUp) { + --dn.tm_year; + *powerDown = mktime(&dn); + } + return true; + } + return false; +} + +/*----------------------------------------------------------------------* + * Enable or disable the square wave output. * + *----------------------------------------------------------------------*/ +void MCP79412::squareWave(Sqwave freq) +{ + uint8_t ctrlReg; + + readRamBytes(CTRL_REG, &ctrlReg, 1); + if (freq > 3) { + ctrlReg &= ~_BV(SQWE); + } + else { + ctrlReg = (ctrlReg & 0xF8) | _BV(SQWE) | freq; + } + writeRamByte(CTRL_REG, ctrlReg); +} + +/*----------------------------------------------------------------------* + * Set an alarm time. Sets the alarm registers only, does not enable * + * the alarm. See enableAlarm(). * + *----------------------------------------------------------------------*/ +void MCP79412::setAlarm(uint8_t alarmNumber, time_t alarmTime) +{ + struct tm *t; + uint8_t day; // Need to preserve bits in the day (of week) register + + alarmNumber &= 0x01; // Ensure a valid alarm number + readRamBytes(ALM0_DAY + alarmNumber * (ALM1_REG - ALM0_REG) , &day, 1); + t = localtime(&alarmTime); // Put the time_t into the tm structure + + char buf[7]; + buf[0] = ALM0_REG + alarmNumber * (ALM1_REG - ALM0_REG); + buf[1] = dec2bcd(t->tm_sec); + buf[2] = dec2bcd(t->tm_min); + buf[3] = dec2bcd(t->tm_hour); // Sets 24 hour format (Bit 6 == 0) + buf[4] = (day & 0xF8) + t->tm_wday; + buf[5] = dec2bcd(t->tm_mday); + buf[6] = dec2bcd(t->tm_mon); + int w = _i2c.write(MCP79412_RTC_ADDR, buf, 7); + _error = (w != 0); +} + +/*----------------------------------------------------------------------* + * Enable or disable an alarm, and set the trigger criteria, * + * e.g. match only seconds, only minutes, entire time and date, etc. * + *----------------------------------------------------------------------*/ +void MCP79412::enableAlarm(uint8_t alarmNumber, uint8_t alarmType) +{ + uint8_t day; //alarm day register has config & flag bits + uint8_t ctrl; //control register has alarm enable bits + + alarmNumber &= 0x01; //ensure a valid alarm number + readRamBytes(CTRL_REG, &ctrl, 1); + if (alarmType < ALM_DISABLE) { + readRamBytes(ALM0_DAY + alarmNumber * (ALM1_REG - ALM0_REG), &day, 1); + day = ( day & 0x87 ) | alarmType << 4; //reset interrupt flag, OR in the config bits + writeRamByte(ALM0_DAY + alarmNumber * (ALM1_REG - ALM0_REG), day); + ctrl |= _BV(ALM0 + alarmNumber); //enable the alarm + } + else { + ctrl &= ~(_BV(ALM0 + alarmNumber)); //disable the alarm + } + writeRamByte(CTRL_REG, ctrl); +} + +/*----------------------------------------------------------------------* + * Returns true or false depending on whether the given alarm has been * + * triggered, and resets the alarm "interrupt" flag. This is not a real * + * interrupt, just a bit that's set when an alarm is triggered. * + *----------------------------------------------------------------------*/ +bool MCP79412::alarm(uint8_t alarmNumber) +{ + uint8_t day; //alarm day register has config & flag bits + + alarmNumber &= 0x01; //ensure a valid alarm number + readRamBytes( ALM0_DAY + alarmNumber * (ALM1_REG - ALM0_REG), &day, 1); + if (day & _BV(ALMIF)) { + day &= ~_BV(ALMIF); //turn off the alarm "interrupt" flag + writeRamByte(ALM0_DAY + alarmNumber * (ALM1_REG - ALM0_REG), day); + return true; + } + return false; +} + +/*----------------------------------------------------------------------* + * Sets the logic level on the MFP when it's not being used as a * + * square wave or alarm output. The default is HIGH. * + *----------------------------------------------------------------------*/ +void MCP79412::out(bool level) +{ + uint8_t ctrlReg; + + readRamBytes(CTRL_REG, &ctrlReg, 1); + if (level) + ctrlReg |= _BV(OUT); + else + ctrlReg &= ~_BV(OUT); + writeRamByte(CTRL_REG, ctrlReg); +} + +/*----------------------------------------------------------------------* + * Specifies the logic level on the Multi-Function Pin (MFP) when an * + * alarm is triggered. The default is LOW. When both alarms are * + * active, the two are ORed together to determine the level of the MFP. * + * With alarm polarity set to LOW (the default), this causes the MFP * + * to go low only when BOTH alarms are triggered. With alarm polarity * + * set to HIGH, the MFP will go high when EITHER alarm is triggered. * + * * + * Note that the state of the MFP is independent of the alarm * + * "interrupt" flags, and the alarm() function will indicate when an * + * alarm is triggered regardless of the polarity. * + *----------------------------------------------------------------------*/ +void MCP79412::alarmPolarity(bool polarity) +{ + uint8_t alm0Day; + + readRamBytes(ALM0_DAY, &alm0Day, 1); + if (polarity) + alm0Day |= _BV(OUT); + else + alm0Day &= ~_BV(OUT); + writeRamByte(ALM0_DAY, alm0Day); +} + +/*----------------------------------------------------------------------* + * Check to see if the RTC's oscillator is started (ST bit in seconds * + * register). Returns true if started. * + *----------------------------------------------------------------------*/ +bool MCP79412::isRunning(void) +{ + char buf[1]; + buf[0] = (uint8_t)TIME_REG; + int w = _i2c.write(MCP79412_RTC_ADDR, buf, 1); + int r = _i2c.read(MCP79412_RTC_ADDR, buf, 1); + _error = ((w != 0) || (r != 0)); + return buf[0] & _BV(ST); +} + +/*----------------------------------------------------------------------* + * Set or clear the VBATEN bit. Setting the bit powers the clock and * + * SRAM from the backup battery when Vcc falls. Note that setting the * + * time via set() or write() sets the VBATEN bit. * + *----------------------------------------------------------------------*/ +void MCP79412::vbaten(bool enable) +{ + uint8_t day; + + readRamBytes(DAY_REG, &day, 1); + if (enable) + day |= _BV(VBATEN); + else + day &= ~_BV(VBATEN); + + writeRamByte(DAY_REG, day); + return; +} + + + +//bool MCP79412::getSummerTime(void) +//{ +// getDateTime(&t); +// +// time_t secondsEpoch = mktime(&t); // seconds since the Epoch +// t = *localtime(&secondsEpoch); +// strftime(buffer, 32, "%j", localtime(&secondsEpoch)); +// int dayOfYearC = atoi(buffer); +// +// strftime(buffer, 32, "%Y", localtime(&secondsEpoch)); +// int year = atoi(buffer); +// +// int index = (year - 2011) * 5; +// if (index < 0) +// index = 0; +// if (index > 440) // (2099 - 2011) * 5 = 440 +// index = 440; +// +// int monthS = atoi(SummerTime[index+1]); +// int dayS = atoi(SummerTime[index+2]); +// +// t.tm_mon = monthS - 1; // adjust for tm structure required values +// t.tm_mday = dayS; +// secondsEpoch = mktime(&t); // seconds since the Epoch +// t = *localtime(&secondsEpoch); +// strftime(buffer, 32, "%j", localtime(&secondsEpoch)); +// int dayOfYearS = atoi(buffer); +// +// int monthE = atoi(SummerTime[index+3]); +// int dayE = atoi(SummerTime[index+4]); +// +// t.tm_mon = monthE - 1; // adjust for tm structure required values +// t.tm_mday = dayE; +// secondsEpoch = mktime(&t); // seconds since the Epoch +// t = *localtime(&secondsEpoch); +// strftime(buffer, 32, "%j", localtime(&secondsEpoch)); +// int dayOfYearE = atoi(buffer); +// +// return ((dayOfYearC >= dayOfYearS) && (dayOfYearC < dayOfYearE)) ? true : false; +//} +// +//int MCP79412::dayOfYearC(void) +//{ +// getDateTime(&t); +// +// time_t secondsEpoch = mktime(&t); // seconds since the Epoch +// strftime(buffer, 32, "%j", localtime(&secondsEpoch)); +// return atoi(buffer); +//} +// +//char * MCP79412::getSunRise(void) +//{ +// return (char*) SunRise[dayOfYearC()]; +//} +// +//char * MCP79412::getSunSet(void) +//{ +// return (char*) SunSet[dayOfYearC()]; +//} +// +//char * MCP79412::getDayLength(void) +//{ +// return (char*) DayLength[dayOfYearC()]; +//} +// +//int MCP79412::getSunRiseMinute(void) +//{ +// int doy = dayOfYearC(); +// int h = atoi(substr((char*)SunRise[doy], 0, 2)); +// int m = atoi(substr((char*)SunRise[doy], 3, 2)); +// return h * 60 + m; +//} +// +//int MCP79412::getSunSetMinute(void) +//{ +// int doy = dayOfYearC(); +// int h = atoi(substr((char*)SunSet[doy], 0, 2)); +// int m = atoi(substr((char*)SunSet[doy], 3, 2)); +// return h * 60 + m; +//} +// +//bool MCP79412::checkSunRise(void) +//{ +// int dayOfWeek, mday, month, year, hours, minutes, seconds; +// readDateTime(&dayOfWeek, &mday, &month, &year, &hours, &minutes, &seconds); +// +// int absMinute = hours * 60 + minutes; +// int SunRiseMinute = getSunRiseMinute(); +// int SunSetMinute = getSunSetMinute(); +// +// return ((absMinute >= SunRiseMinute) && (absMinute < SunSetMinute)) ? true : false; +//} + + +void MCP79412::substr(char *s, char *d, int pos, int len) +{ + char *t; + s = s+pos; + t = s+len; + while (s != t) { + *d=*s; + s++; + d++; + } + *d='\0'; +} + +char * MCP79412::substr(char *s, int pos, int len) +{ + char *t; + char *d; + d = buffer; + s = s+pos; + t = s+len; + while (s != t) { + *d=*s; + s++; + d++; + } + *d='\0'; + return buffer; +} + + + + +struct tm MCP79412::setSystemDateTime( + uint8_t second, // 0-59 + uint8_t minute, // 0-59 + uint8_t hour, // 1-23 + uint8_t dayOfMonth, // 1-31 + uint8_t month, // 1-12 + uint8_t year) // 0-99 +{ + uint8_t dayOfWeek = 1; // Will be determined + // Convert to unix time structure + t->tm_sec = second; // 0-59 + t->tm_min = minute; // 0-59 + t->tm_hour = hour; // 0-23 + t->tm_wday = dayOfWeek - 1; // 0-6 (0 = Sunday) + t->tm_mday = dayOfMonth; // 1-31 + t->tm_mon = month - 1; // 0-11 + t->tm_year = year + 100; // 100-199 year since 1900 + t->tm_isdst = 0; + +// printf("-> Debug %d %02d-%02d-%03d %02d:%02d:%02d\n", t->tm_wday, t->tm_mday, t->tm_mon, t->tm_year, t->tm_hour, t->tm_min, t->tm_sec); + + secondsEpoch = mktime(t); // seconds since the Epoch + set_time(secondsEpoch); + + // Get weekday 0-6, Sunday as 0 for RTC + t = localtime(&secondsEpoch); +// printf("-> Debug %d %02d-%02d-%03d %02d:%02d:%02d\n", t->tm_wday, t->tm_mday, t->tm_mon, t->tm_year, t->tm_hour, t->tm_min, t->tm_sec); + return *t; +} + +void MCP79412::getSystemDateTime( + uint8_t *second, // 0-59 + uint8_t *minute, // 0-59 + uint8_t *hour, // 0-23 + uint8_t *dayOfWeek, // 1-7 (1 = Sunday) + uint8_t *dayOfMonth, // 1-31 + uint8_t *month, // 1-12 + uint8_t *year) // 0-99 year since 2000 +{ +// struct tm *t; +// time_t secondsEpoch; + + // Get system DateTime + secondsEpoch = time(NULL); + t = localtime(&secondsEpoch); + + // time/date data + *second = (t->tm_sec); // 0-59 + *minute = (t->tm_min); // 0-59 + *hour = (t->tm_hour); // 0-23 + *dayOfWeek = (t->tm_wday + 1); // 1-7 (1 = Sunday) + *dayOfMonth = (t->tm_mday); // 1-31 + *month = (t->tm_mon + 1); // 1-12 + *year = (t->tm_year - 100); // 0-99 year since 2000 +} + +void MCP79412::setRtcToSystemDateTime(void) +{ + // Get system DateTime + secondsEpoch = time(NULL); + t = localtime(&secondsEpoch); + + // Convert from unix time structure + uint8_t second = (t->tm_sec); // 0-59 + uint8_t minute = (t->tm_min); // 0-59 + uint8_t hour = (t->tm_hour); // 0-23 + uint8_t dayOfWeek = (t->tm_wday + 1); // 1-7 (1 = Sunday) + uint8_t dayOfMonth = (t->tm_mday); // 1-31 + uint8_t month = (t->tm_mon + 1); // 1-12 + uint8_t year = (t->tm_year - 100); // 0-99 year since 2000 + + // Set RTC DateTime + setRtcDateTime(second, minute, hour, dayOfWeek, dayOfMonth, month, year); +} + +void MCP79412::setSystemToRtcDateTime(void) +{ + // Get RTC DateTime + getRtcDateTime(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); + + // Convert to unix time structure + t->tm_sec = second; // 0-59 + t->tm_min = minute; // 0-59 + t->tm_hour = hour; // 0-23 + t->tm_wday = dayOfWeek - 1; // 0-6 (0 = Sunday) + t->tm_mday = dayOfMonth; // 1-31 + t->tm_mon = month - 1; // 0-11 + t->tm_year = year + 100; // 100-199 year since 1900 + t->tm_isdst = 0; + + // Set system DateTime + secondsEpoch = mktime(t); // seconds since the Epoch + set_time(secondsEpoch); +} + +void MCP79412::setRtcFromTm(struct tm *t) +{ +// // Get system DateTime +// secondsEpoch = time(NULL); +// t = localtime(&secondsEpoch); + + // Convert from unix time structure + uint8_t second = (t->tm_sec); // 0-59 + uint8_t minute = (t->tm_min); // 0-59 + uint8_t hour = (t->tm_hour); // 0-23 + uint8_t dayOfWeek = (t->tm_wday + 1); // 1-7 (1 = Sunday) + uint8_t dayOfMonth = (t->tm_mday); // 1-31 + uint8_t month = (t->tm_mon + 1); // 1-12 + uint8_t year = (t->tm_year - 100); // 0-99 year since 2000 + +// printf("setRtcFromTm %d %02d-%02d-%03d %02d:%02d:%02d\n", dayOfWeek, dayOfMonth, month, year, hour, minute, second); + + // Set RTC DateTime + setRtcDateTime(second, minute, hour, dayOfWeek, dayOfMonth, month, year); +} + +struct tm MCP79412::getTmFromRtc(void) +{ + // Get RTC DateTime + getRtcDateTime(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); + + // Convert to unix time structure + t->tm_sec = second; // 0-59 + t->tm_min = minute; // 0-59 + t->tm_hour = hour; // 0-23 + t->tm_wday = dayOfWeek - 1; // 0-6 (0 = Sunday) + t->tm_mday = dayOfMonth; // 1-31 + t->tm_mon = month - 1; // 0-11 + t->tm_year = year + 100; // 100-199 year since 1900 + t->tm_isdst = 0; + + return *t; +// // Set system DateTime +// secondsEpoch = mktime(t); // seconds since the Epoch +// set_time(secondsEpoch); +} + +time_t MCP79412::getSecondsEpoch(void) +{ + secondsEpoch = time(NULL); + return secondsEpoch; +} + +void MCP79412::setSecondsEpoch(time_t t) +{ + secondsEpoch = t; + set_time(secondsEpoch); +} + +void MCP79412::getRtcDateTimeAsTm(void) +{ + // Get RTC DateTime + getRtcDateTime(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); + + // Convert to unix time structure + t->tm_sec = second; // 0-59 + t->tm_min = minute; // 0-59 + t->tm_hour = hour; // 0-23 + t->tm_wday = dayOfWeek - 1; // 0-6 (0 = Sunday) + t->tm_mday = dayOfMonth; // 1-31 + t->tm_mon = month - 1; // 0-11 + t->tm_year = year + 100; // 100-199 year since 1900 + t->tm_isdst = 0; + + // Set system DateTime + secondsEpoch = mktime(t); // seconds since the Epoch +// time_t t = time(secondsEpoch); + +// set_time(secondsEpoch); +} + +time_t MCP79412::convertDateTimeToTimestamp( + uint8_t second, // 0-59 + uint8_t minute, // 0-59 + uint8_t hour, // 0-23 + uint8_t dayOfMonth, // 1-31 + uint8_t month, // 1-12 + uint8_t year) // 0-99 year since 2000 +{ + // setup time structure for Wed, 28 Oct 2009 11:35:37 + struct tm t; + t.tm_sec = second; // 0-59 + t.tm_min = minute; // 0-59 + t.tm_hour = hour; // 0-23 + t.tm_mday = dayOfMonth; // 1-31 + t.tm_mon = month - 1; // 0-11 + t.tm_year = year + 100; // 100-199 year since 1900 + +// printf("Debug %d %02d-%02d-%03d %02d:%02d:%02d\n", t.tm_wday, t.tm_mday, t.tm_mon, t.tm_year, t.tm_hour, t.tm_min, t.tm_sec); + + // convert to timestamp and display (1256729737) + time_t seconds = mktime(&t); +// printf("Time as seconds since January 1, 1970 = %d\n", seconds); + +// char buffer[32]; +// strftime(buffer, 32, "%a %d-%m-%Y %H:%M:%S\n", localtime(&seconds)); +// printf("Time: %s", buffer); + + // Get weekday Sunday as 0 (0-6) for RTC + struct tm *t2; + t2 = localtime(&seconds); +// printf("Debug %d %02d-%02d-%03d %02d:%02d:%02d\n", t.tm_wday, t2->tm_mday, t2->tm_mon, t2->tm_year, t2->tm_hour, t2->tm_min, t2->tm_sec); +// printf("Weekday %d\n", t2->tm_wday); + + return seconds; +} + +uint8_t MCP79412::getWeekdayFromDate(uint8_t dayOfMonth, uint8_t month, uint8_t year) // year 0-99 +{ + // setup time structure for Wed, 28 Oct 2009 11:35:37 + struct tm t; + t.tm_sec = 0; // 0-59 + t.tm_min = 0; // 0-59 + t.tm_hour = 0; // 0-23 + t.tm_mday = dayOfMonth; // 1-31 + t.tm_mon = month - 1; // 0-11 + t.tm_year = year + 100; // 100-199 year since 1900 + +// printf("Debug %d %02d:%02d:%02d %02d-%02d-%02d\n", t.tm_wday, t.tm_mday, t.tm_mon, t.tm_year, t.tm_hour, t.tm_min, t.tm_sec); + + // convert to timestamp and display (1256729737) + time_t seconds = mktime(&t); +// printf("Time as seconds since January 1, 1970 = %d\n", seconds); + +// char buffer[32]; +// strftime(buffer, 32, "%a %d-%m-%Y %H:%M:%S\n", localtime(&seconds)); +// printf("Time: %s", buffer); + + // Get weekday Sunday as 0 (0-6) for RTC + struct tm *t2; + t2 = localtime(&seconds); +// printf("Debug %d %02d-%02d-%03d %02d:%02d:%02d\n", t2->tm_wday, t2->tm_mday, t2->tm_mon, t2->tm_year, t2->tm_hour, t2->tm_min, t2->tm_sec); +// printf("Weekday %d\n", t2->tm_wday); + + return t2->tm_wday; +} + + + + + + + + +//double MCP79412::clamp(double v) +//{ +// const double t = v < 0.0f ? 0.0f : v; +// return t > 1.0f ? 1.0f : t; +//} + + +//bool MCP79412::checkTimeLost(void) +//{ +//// return (atoi(getFormatedDateTime("%Y")) <= 2015) ? true : false; +// return false; +//} + +// +///*----------------------------------------------------------------------* +// * Read the current time from the RTC and return it in a tmElements_t * +// * structure. Returns false if RTC not present (I2C I/O error). * +// *----------------------------------------------------------------------*/ +//boolean MCP79412RTC::read(tmElements_t &tm) +//{ +// i2cBeginTransmission(RTC_ADDR); +// i2cWrite((uint8_t)TIME_REG); +// if (i2cEndTransmission() != 0) { +// return false; +// } +// else { +// //request 7 uint8_ts (secs, min, hr, dow, date, mth, yr) +// i2cRequestFrom(RTC_ADDR, tmNbrFields); +// tm.Second = bcd2dec(i2cRead() & ~_BV(ST)); +// tm.Minute = bcd2dec(i2cRead()); +// tm.Hour = bcd2dec(i2cRead() & ~_BV(HR1224)); //assumes 24hr clock +// tm.Wday = i2cRead() & ~(_BV(OSCON) | _BV(VBAT) | _BV(VBATEN)); //mask off OSCON, VBAT, VBATEN bits +// tm.Day = bcd2dec(i2cRead()); +// tm.Month = bcd2dec(i2cRead() & ~_BV(LP)); //mask off the leap year bit +// tm.Year = y2kYearToTm(bcd2dec(i2cRead())); +// return true; +// } +//} +// +///*----------------------------------------------------------------------* +// * Set the RTC's time from a tmElements_t structure. * +// *----------------------------------------------------------------------*/ +//void MCP79412RTC::write(tmElements_t &tm) +//{ +// i2cBeginTransmission(RTC_ADDR); +// i2cWrite((uint8_t)TIME_REG); +// i2cWrite((uint8_t)0x00); //stops the oscillator (Bit 7, ST == 0) +// i2cWrite(dec2bcd(tm.Minute)); +// i2cWrite(dec2bcd(tm.Hour)); //sets 24 hour format (Bit 6 == 0) +// i2cWrite(tm.Wday | _BV(VBATEN)); //enable battery backup operation +// i2cWrite(dec2bcd(tm.Day)); +// i2cWrite(dec2bcd(tm.Month)); +// i2cWrite(dec2bcd(tmYearToY2k(tm.Year))); +// i2cEndTransmission(); +// +// i2cBeginTransmission(RTC_ADDR); +// i2cWrite((uint8_t)TIME_REG); +// i2cWrite(dec2bcd(tm.Second) | _BV(ST)); //set the seconds and start the oscillator (Bit 7, ST == 1) +// i2cEndTransmission(); +//} +// +///*----------------------------------------------------------------------* +// * Write a single uint8_t to RTC RAM. * +// * Valid address range is 0x00 - 0x5F, no checking. * +// *----------------------------------------------------------------------*/ +//void MCP79412RTC::ramWrite(uint8_t addr, uint8_t value) +//{ +// ramWrite(addr, &value, 1); +//} +// +///*----------------------------------------------------------------------* +// * Write multiple uint8_ts to RTC RAM. * +// * Valid address range is 0x00 - 0x5F, no checking. * +// * Number of uint8_ts (nuint8_ts) must be between 1 and 31 (Wire library * +// * limitation). * +// *----------------------------------------------------------------------*/ +//void MCP79412RTC::ramWrite(uint8_t addr, uint8_t *values, uint8_t nuint8_ts) +//{ +// i2cBeginTransmission(RTC_ADDR); +// i2cWrite(addr); +// for (uint8_t i=0; i<nuint8_ts; i++) i2cWrite(values[i]); +// i2cEndTransmission(); +//} +// +///*----------------------------------------------------------------------* +// * Read a single uint8_t from RTC RAM. * +// * Valid address range is 0x00 - 0x5F, no checking. * +// *----------------------------------------------------------------------*/ +//uint8_t MCP79412RTC::ramRead(uint8_t addr) +//{ +// uint8_t value; +// +// ramRead(addr, &value, 1); +// return value; +//} +// +///*----------------------------------------------------------------------* +// * Read multiple uint8_ts from RTC RAM. * +// * Valid address range is 0x00 - 0x5F, no checking. * +// * Number of uint8_ts (nuint8_ts) must be between 1 and 32 (Wire library * +// * limitation). * +// *----------------------------------------------------------------------*/ +//void MCP79412RTC::ramRead(uint8_t addr, uint8_t *values, uint8_t nuint8_ts) +//{ +// i2cBeginTransmission(RTC_ADDR); +// i2cWrite(addr); +// i2cEndTransmission(); +// i2cRequestFrom( (uint8_t)RTC_ADDR, nuint8_ts ); +// for (uint8_t i=0; i<nuint8_ts; i++) values[i] = i2cRead(); +//} +// +///*----------------------------------------------------------------------* +// * Write a single uint8_t to Static RAM. * +// * Address (addr) is constrained to the range (0, 63). * +// *----------------------------------------------------------------------*/ +//void MCP79412RTC::sramWrite(uint8_t addr, uint8_t value) +//{ +// ramWrite( (addr & (SRAM_SIZE - 1) ) + SRAM_START_ADDR, &value, 1 ); +//} +// +///*----------------------------------------------------------------------* +// * Write multiple uint8_ts to Static RAM. * +// * Address (addr) is constrained to the range (0, 63). * +// * Number of uint8_ts (nuint8_ts) must be between 1 and 31 (Wire library * +// * limitation). * +// * Invalid values for nuint8_ts, or combinations of addr and nuint8_ts * +// * that would result in addressing past the last uint8_t of SRAM will * +// * result in no action. * +// *----------------------------------------------------------------------*/ +//void MCP79412RTC::sramWrite(uint8_t addr, uint8_t *values, uint8_t nuint8_ts) +//{ +//#if defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) +// if (nuint8_ts >= 1 && (addr + nuint8_ts) <= SRAM_SIZE) { +//#else +// if (nuint8_ts >= 1 && nuint8_ts <= (BUFFER_LENGTH - 1) && (addr + nuint8_ts) <= SRAM_SIZE) { +//#endif +// ramWrite( (addr & (SRAM_SIZE - 1) ) + SRAM_START_ADDR, values, nuint8_ts ); +// } +//} +// +///*----------------------------------------------------------------------* +// * Read a single uint8_t from Static RAM. * +// * Address (addr) is constrained to the range (0, 63). * +// *----------------------------------------------------------------------*/ +//uint8_t MCP79412RTC::sramRead(uint8_t addr) +//{ +// uint8_t value; +// +// ramRead( (addr & (SRAM_SIZE - 1) ) + SRAM_START_ADDR, &value, 1 ); +// return value; +//} +// +///*----------------------------------------------------------------------* +// * Read multiple uint8_ts from Static RAM. * +// * Address (addr) is constrained to the range (0, 63). * +// * Number of uint8_ts (nuint8_ts) must be between 1 and 32 (Wire library * +// * limitation). * +// * Invalid values for nuint8_ts, or combinations of addr and * +// * nuint8_ts that would result in addressing past the last uint8_t of SRAM * +// * result in no action. * +// *----------------------------------------------------------------------*/ +//void MCP79412RTC::sramRead(uint8_t addr, uint8_t *values, uint8_t nuint8_ts) +//{ +//#if defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) +// if (nuint8_ts >= 1 && (addr + nuint8_ts) <= SRAM_SIZE) { +//#else +// if (nuint8_ts >= 1 && nuint8_ts <= BUFFER_LENGTH && (addr + nuint8_ts) <= SRAM_SIZE) { +//#endif +// ramRead((addr & (SRAM_SIZE - 1) ) + SRAM_START_ADDR, values, nuint8_ts); +// } +//} +// +///*----------------------------------------------------------------------* +// * Write a single uint8_t to EEPROM. * +// * Address (addr) is constrained to the range (0, 127). * +// * Can't leverage page write function because a write can't start * +// * mid-page. * +// *----------------------------------------------------------------------*/ +//void MCP79412RTC::eepromWrite(uint8_t addr, uint8_t value) +//{ +// i2cBeginTransmission(MCP79412_EEPROM_ADDR); +// i2cWrite( addr & (EEPROM_SIZE - 1) ); +// i2cWrite(value); +// i2cEndTransmission(); +// eepromWait(); +//} +// +///*----------------------------------------------------------------------* +// * Write a page (or less) to EEPROM. An EEPROM page is 8 uint8_ts. * +// * Address (addr) should be a page start address (0, 8, ..., 120), but * +// * is ruthlessly coerced into a valid value. * +// * Number of uint8_ts (nuint8_ts) must be between 1 and 8, other values * +// * result in no action. * +// *----------------------------------------------------------------------*/ +//void MCP79412RTC::eepromWrite(uint8_t addr, uint8_t *values, uint8_t nuint8_ts) +//{ +// if (nuint8_ts >= 1 && nuint8_ts <= EEPROM_PAGE_SIZE) { +// i2cBeginTransmission(MCP79412_EEPROM_ADDR); +// i2cWrite( addr & ~(EEPROM_PAGE_SIZE - 1) & (EEPROM_SIZE - 1) ); +// for (uint8_t i=0; i<nuint8_ts; i++) i2cWrite(values[i]); +// i2cEndTransmission(); +// eepromWait(); +// } +//} +// +///*----------------------------------------------------------------------* +// * Read a single uint8_t from EEPROM. * +// * Address (addr) is constrained to the range (0, 127). * +// *----------------------------------------------------------------------*/ +//uint8_t MCP79412RTC::eepromRead(uint8_t addr) +//{ +// uint8_t value; +// +// eepromRead( addr & (EEPROM_SIZE - 1), &value, 1 ); +// return value; +//} +// +///*----------------------------------------------------------------------* +// * Read multiple uint8_ts from EEPROM. * +// * Address (addr) is constrained to the range (0, 127). * +// * Number of uint8_ts (nuint8_ts) must be between 1 and 32 (Wire library * +// * limitation). * +// * Invalid values for addr or nuint8_ts, or combinations of addr and * +// * nuint8_ts that would result in addressing past the last uint8_t of EEPROM * +// * result in no action. * +// *----------------------------------------------------------------------*/ +//void MCP79412RTC::eepromRead(uint8_t addr, uint8_t *values, uint8_t nuint8_ts) +//{ +//#if defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) +// if (nuint8_ts >= 1 && (addr + nuint8_ts) <= EEPROM_SIZE) { +//#else +// if (nuint8_ts >= 1 && nuint8_ts <= BUFFER_LENGTH && (addr + nuint8_ts) <= EEPROM_SIZE) { +//#endif +// i2cBeginTransmission(MCP79412_EEPROM_ADDR); +// i2cWrite( addr & (EEPROM_SIZE - 1) ); +// i2cEndTransmission(); +// i2cRequestFrom( (uint8_t)MCP79412_EEPROM_ADDR, nuint8_ts ); +// for (uint8_t i=0; i<nuint8_ts; i++) values[i] = i2cRead(); +// } +//} +// +///*----------------------------------------------------------------------* +// * Wait for EEPROM write to complete. * +// *----------------------------------------------------------------------*/ +//uint8_t MCP79412RTC::eepromWait(void) +//{ +// uint8_t waitCount = 0; +// uint8_t txStatus; +// +// do +// { +// ++waitCount; +// i2cBeginTransmission(MCP79412_EEPROM_ADDR); +// i2cWrite((uint8_t)0); +// txStatus = i2cEndTransmission(); +// +// } while (txStatus != 0); +// +// return waitCount; +//} +// +///*----------------------------------------------------------------------* +// * Read the calibration register. * +// * The calibration value is not a twos-complement number. The MSB is * +// * the sign bit, and the 7 LSBs are an unsigned number, so we convert * +// * it and return it to the caller as a regular twos-complement integer. * +// *----------------------------------------------------------------------*/ +//int MCP79412RTC::calibRead(void) +//{ +// uint8_t val = ramRead(CALIB_REG); +// +// if ( val & 0x80 ) return -(val & 0x7F); +// else return val; +//} +// +///*----------------------------------------------------------------------* +// * Write the calibration register. * +// * Calibration value must be between -127 and 127, others result * +// * in no action. See note above on the format of the calibration value. * +// *----------------------------------------------------------------------*/ +//void MCP79412RTC::calibWrite(int value) +//{ +// uint8_t calibVal; +// +// if (value >= -127 && value <= 127) { +// calibVal = abs(value); +// if (value < 0) calibVal += 128; +// ramWrite(CALIB_REG, calibVal); +// } +//} +// +///*----------------------------------------------------------------------* +// * Read the unique ID. * +// * For the MCP79411 (EUI-48), the first two uint8_ts will contain 0xFF. * +// * Caller must provide an 8-uint8_t array to contain the results. * +// *----------------------------------------------------------------------*/ +//void MCP79412RTC::idRead(uint8_t *uniqueID) +//{ +// i2cBeginTransmission(MCP79412_EEPROM_ADDR); +// i2cWrite(UNIQUE_ID_ADDR); +// i2cEndTransmission(); +// i2cRequestFrom( MCP79412_EEPROM_ADDR, UNIQUE_ID_SIZE ); +// for (uint8_t i=0; i<UNIQUE_ID_SIZE; i++) uniqueID[i] = i2cRead(); +//} +// +///*----------------------------------------------------------------------* +// * Returns an EUI-64 ID. For an MCP79411, the EUI-48 ID is converted to * +// * EUI-64. For an MCP79412, calling this function is equivalent to * +// * calling idRead(). For an MCP79412, if the RTC type is known, calling * +// * idRead() will be a bit more efficient. * +// * Caller must provide an 8-uint8_t array to contain the results. * +// *----------------------------------------------------------------------*/ +//void MCP79412RTC::getEUI64(uint8_t *uniqueID) +//{ +// uint8_t rtcID[8]; +// +// idRead(rtcID); +// if (rtcID[0] == 0xFF && rtcID[1] == 0xFF) { +// rtcID[0] = rtcID[2]; +// rtcID[1] = rtcID[3]; +// rtcID[2] = rtcID[4]; +// rtcID[3] = 0xFF; +// rtcID[4] = 0xFE; +// } +// for (uint8_t i=0; i<UNIQUE_ID_SIZE; i++) uniqueID[i] = rtcID[i]; +//} +// +///*----------------------------------------------------------------------* +// * Check to see if a power failure has occurred. If so, returns TRUE * +// * as the function value, and returns the power down and power up * +// * timestamps. After returning the time stamps, the RTC's timestamp * +// * registers are cleared and the VBAT bit which indicates a power * +// * failure is reset. * +// * * +// * Note that the power down and power up timestamp registers do not * +// * contain values for seconds or for the year. The returned time stamps * +// * will therefore contain the current year from the RTC. However, there * +// * is a chance that a power outage spans from one year to the next. * +// * If we find the power down timestamp to be later (larger) than the * +// * power up timestamp, we will assume this has happened, and well * +// * subtract one year from the power down timestamp. * +// * * +// * Still, there is an assumption that the timestamps are being read * +// * in the same year as that when the power up occurred. * +// * * +// * Finally, note that once the RTC records a power outage, it must be * +// * cleared before another will be recorded. * +// *----------------------------------------------------------------------*/ +//boolean MCP79412RTC::powerFail(time_t *powerDown, time_t *powerUp) +//{ +// uint8_t day, yr; //copies of the RTC Day and Year registers +// tmElements_t dn, up; //power down and power up times +// +// ramRead(DAY_REG, &day, 1); +// ramRead(YEAR_REG, &yr, 1); +// yr = y2kYearToTm(bcd2dec(yr)); +// if ( day & _BV(VBAT) ) { +// i2cBeginTransmission(RTC_ADDR); +// i2cWrite(PWRDWN_TS_REG); +// i2cEndTransmission(); +// +// i2cRequestFrom(RTC_ADDR, TIMESTAMP_SIZE); //read both timestamp registers, 8 uint8_ts total +// dn.Second = 0; +// dn.Minute = bcd2dec(i2cRead()); +// dn.Hour = bcd2dec(i2cRead() & ~_BV(HR1224)); //assumes 24hr clock +// dn.Day = bcd2dec(i2cRead()); +// dn.Month = bcd2dec(i2cRead() & 0x1F); //mask off the day, we don't need it +// dn.Year = yr; //assume current year +// up.Second = 0; +// up.Minute = bcd2dec(i2cRead()); +// up.Hour = bcd2dec(i2cRead() & ~_BV(HR1224)); //assumes 24hr clock +// up.Day = bcd2dec(i2cRead()); +// up.Month = bcd2dec(i2cRead() & 0x1F); //mask off the day, we don't need it +// up.Year = yr; //assume current year +// +// *powerDown = makeTime(dn); +// *powerUp = makeTime(up); +// +// //clear the VBAT bit, which causes the RTC hardware to clear the timestamps too. +// //I suppose there is a risk here that the day has changed since we read it, +// //but the Day of Week is actually redundant data and the makeTime() function +// //does not use it. This could be an issue if someone is reading the RTC +// //registers directly, but as this library is meant to be used with the Time library, +// //and also because we don't provide a method to read the RTC clock/calendar +// //registers directly, we won't lose any sleep about it at this point unless +// //some issue is actually brought to our attention ;-) +// day &= ~_BV(VBAT); +// ramWrite(DAY_REG, &day , 1); +// +// //adjust the powerDown timestamp if needed (see notes above) +// if (*powerDown > *powerUp) { +// --dn.Year; +// *powerDown = makeTime(dn); +// } +// return true; +// } +// else +// return false; +//} +// +///*----------------------------------------------------------------------* +// * Enable or disable the square wave output. * +// *----------------------------------------------------------------------*/ +//void MCP79412RTC::squareWave(uint8_t freq) +//{ +// uint8_t ctrlReg; +// +// ramRead(CTRL_REG, &ctrlReg, 1); +// if (freq > 3) { +// ctrlReg &= ~_BV(SQWE); +// } +// else { +// ctrlReg = (ctrlReg & 0xF8) | _BV(SQWE) | freq; +// } +// ramWrite(CTRL_REG, &ctrlReg, 1); +//} +// +///*----------------------------------------------------------------------* +// * Set an alarm time. Sets the alarm registers only, does not enable * +// * the alarm. See enableAlarm(). * +// *----------------------------------------------------------------------*/ +//void MCP79412RTC::setAlarm(uint8_t alarmNumber, time_t alarmTime) +//{ +// tmElements_t tm; +// uint8_t day; //need to preserve bits in the day (of week) register +// +// alarmNumber &= 0x01; //ensure a valid alarm number +// ramRead( ALM0_DAY + alarmNumber * (ALM1_REG - ALM0_REG) , &day, 1); +// breakTime(alarmTime, tm); +// i2cBeginTransmission(RTC_ADDR); +// i2cWrite( ALM0_REG + alarmNumber * (ALM1_REG - ALM0_REG) ); +// i2cWrite(dec2bcd(tm.Second)); +// i2cWrite(dec2bcd(tm.Minute)); +// i2cWrite(dec2bcd(tm.Hour)); //sets 24 hour format (Bit 6 == 0) +// i2cWrite( (day & 0xF8) + tm.Wday ); +// i2cWrite(dec2bcd(tm.Day)); +// i2cWrite(dec2bcd(tm.Month)); +// i2cEndTransmission(); +//} +// +///*----------------------------------------------------------------------* +// * Enable or disable an alarm, and set the trigger criteria, * +// * e.g. match only seconds, only minutes, entire time and date, etc. * +// *----------------------------------------------------------------------*/ +//void MCP79412RTC::enableAlarm(uint8_t alarmNumber, uint8_t alarmType) +//{ +// uint8_t day; //alarm day register has config & flag bits +// uint8_t ctrl; //control register has alarm enable bits +// +// alarmNumber &= 0x01; //ensure a valid alarm number +// ramRead(CTRL_REG, &ctrl, 1); +// if (alarmType < ALM_DISABLE) { +// ramRead(ALM0_DAY + alarmNumber * (ALM1_REG - ALM0_REG), &day, 1); +// day = ( day & 0x87 ) | alarmType << 4; //reset interrupt flag, OR in the config bits +// ramWrite(ALM0_DAY + alarmNumber * (ALM1_REG - ALM0_REG), &day, 1); +// ctrl |= _BV(ALM0 + alarmNumber); //enable the alarm +// } +// else { +// ctrl &= ~(_BV(ALM0 + alarmNumber)); //disable the alarm +// } +// ramWrite(CTRL_REG, &ctrl, 1); +//} +// +///*----------------------------------------------------------------------* +// * Returns true or false depending on whether the given alarm has been * +// * triggered, and resets the alarm "interrupt" flag. This is not a real * +// * interrupt, just a bit that's set when an alarm is triggered. * +// *----------------------------------------------------------------------*/ +//boolean MCP79412RTC::alarm(uint8_t alarmNumber) +//{ +// uint8_t day; //alarm day register has config & flag bits +// +// alarmNumber &= 0x01; //ensure a valid alarm number +// ramRead( ALM0_DAY + alarmNumber * (ALM1_REG - ALM0_REG), &day, 1); +// if (day & _BV(ALMIF)) { +// day &= ~_BV(ALMIF); //turn off the alarm "interrupt" flag +// ramWrite( ALM0_DAY + alarmNumber * (ALM1_REG - ALM0_REG), &day, 1); +// return true; +// } +// else +// return false; +//} +// +///*----------------------------------------------------------------------* +// * Sets the logic level on the MFP when it's not being used as a * +// * square wave or alarm output. The default is HIGH. * +// *----------------------------------------------------------------------*/ +//void MCP79412RTC::out(boolean level) +//{ +// uint8_t ctrlReg; +// +// ramRead(CTRL_REG, &ctrlReg, 1); +// if (level) +// ctrlReg |= _BV(OUT); +// else +// ctrlReg &= ~_BV(OUT); +// ramWrite(CTRL_REG, &ctrlReg, 1); +//} +// +///*----------------------------------------------------------------------* +// * Specifies the logic level on the Multi-Function Pin (MFP) when an * +// * alarm is triggered. The default is LOW. When both alarms are * +// * active, the two are ORed together to determine the level of the MFP. * +// * With alarm polarity set to LOW (the default), this causes the MFP * +// * to go low only when BOTH alarms are triggered. With alarm polarity * +// * set to HIGH, the MFP will go high when EITHER alarm is triggered. * +// * * +// * Note that the state of the MFP is independent of the alarm * +// * "interrupt" flags, and the alarm() function will indicate when an * +// * alarm is triggered regardless of the polarity. * +// *----------------------------------------------------------------------*/ +//void MCP79412RTC::alarmPolarity(boolean polarity) +//{ +// uint8_t alm0Day; +// +// ramRead(ALM0_DAY, &alm0Day, 1); +// if (polarity) +// alm0Day |= _BV(OUT); +// else +// alm0Day &= ~_BV(OUT); +// ramWrite(ALM0_DAY, &alm0Day, 1); +//} +// +///*----------------------------------------------------------------------* +// * Check to see if the RTC's oscillator is started (ST bit in seconds * +// * register). Returns true if started. * +// *----------------------------------------------------------------------*/ +//boolean MCP79412RTC::isRunning(void) +//{ +// i2cBeginTransmission(RTC_ADDR); +// i2cWrite((uint8_t)TIME_REG); +// i2cEndTransmission(); +// +// //request just the seconds register +// i2cRequestFrom(RTC_ADDR, 1); +// return i2cRead() & _BV(ST); +//} +// +///*----------------------------------------------------------------------* +// * Set or clear the VBATEN bit. Setting the bit powers the clock and * +// * SRAM from the backup battery when Vcc falls. Note that setting the * +// * time via set() or write() sets the VBATEN bit. * +// *----------------------------------------------------------------------*/ +//void MCP79412RTC::vbaten(boolean enable) +//{ +// uint8_t day; +// +// ramRead(DAY_REG, &day, 1); +// if (enable) +// day |= _BV(VBATEN); +// else +// day &= ~_BV(VBATEN); +// +// ramWrite(DAY_REG, &day, 1); +// return; +//} + +///*----------------------------------------------------------------------* +// * Decimal-to-BCD conversion * +// *----------------------------------------------------------------------*/ +//uint8_t MCP79412RTC::dec2bcd(uint8_t n) +//{ +// return n + 6 * (n / 10); +//} +// +///*----------------------------------------------------------------------* +// * BCD-to-Decimal conversion * +// *----------------------------------------------------------------------*/ +//uint8_t __attribute__ ((noinline)) MCP79412RTC::bcd2dec(uint8_t n) +//{ +// return n - 6 * (n >> 4); +//} + +// BCD to decimal conversion +int MCP79412::bcd2dec(int bcd) +{ + return(((bcd & 0xF0) >> 4) * 10 + (bcd & 0x0F)); +} + +// decimal to BCD conversion +int MCP79412::dec2bcd(int dec) +{ + return((dec / 10) * 16 + (dec % 10)); +} + +// Convert normal decimal numbers to binary coded decimal: +int MCP79412::decToBcd(int val) +{ + return ( (val/10*16) + (val%10) ); +} + +// Convert binary coded decimal to normal decimal numbers: +int MCP79412::bcdToDec(int val) +{ + return ( (val/16*10) + (val%16) ); +}
diff -r 000000000000 -r 04311b121ac4 MCP79412.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MCP79412.h Mon Jul 23 12:24:33 2018 +0000 @@ -0,0 +1,345 @@ +/** mbded library for driving the PMAXIM DS3231 Real Time Clock +* datasheet link : http://datasheets.maximintegrated.com/en/ds/DS3231.pdf +* breakout : MACETECH ChronoDot V2.1 High Precision RTC +* remi cormier 2012 +* WARNING : sda and sdl should be pulled up with 2.2k resistor +*/ + +/** Example code +* @code +// DS3231 Library test program +// remi cormier 2012 + +#include "mbed.h" +#include "DS3231.h" + +Serial pc(USBTX, USBRX); + +int hour; +int minute; +int second; + +int dayOfWeek; +int date; +int month; +int year; + +DS3231 RTC(p28,p27); + + +int main() + {printf("\r\n\nDS3231 Library test program\r\nremi cormier 2012\r\n\n"); + + RTC.setI2Cfrequency(400000); + + //RTC.writeRegister(DS3231_Aging_Offset,0); // uncomment to set Aging Offset 1LSB = approx. 0.1 ppm according from datasheet = 0.05 ppm @ 21 °C from my measurments + + RTC.convertTemperature(); + + int reg=RTC.readRegister(DS3231_Aging_Offset); + if (reg>127) + {reg=reg-256;} + pc.printf("Aging offset : %i\r\n",reg); + + pc.printf("OSF flag : %i",RTC.OSF()); + pc.printf("\r\n"); + + RTC.readDate(&date,&month,&year); + pc.printf("date : %02i-%02i-%02i",date,month,year); + pc.printf("\r\n"); + + //RTC.setTime(19,48,45); // uncomment to set time + + RTC.readTime(&hour,&minute,&second); + pc.printf("time : %02i:%02i:%02i",hour,minute,second); + pc.printf("\r\n"); + + //RTC.setDate(6,22,12,2012); // uncomment to set date + + RTC.readDateTime(&dayOfWeek,&date,&month,&year,&hour,&minute,&second); + pc.printf("date time : %i / %02i-%02i-%02i %02i:%02i:%02i",dayOfWeek,date,month,year,hour,minute,second); + pc.printf("\r\n"); + + pc.printf("temperature :%6.2f",RTC.readTemp()); + pc.printf("\r\n"); + } +* @endcode +*/ + +/* +http://www.cplusplus.com/reference/ctime/strftime/ +%a Abbreviated weekday name * Thu +%A Full weekday name * Thursday +%b Abbreviated month name * Aug +%B Full month name * August +%d Day of the month, zero-padded (01-31) 23 +%e Day of the month, space-padded ( 1-31) 23 +%F Short YYYY-MM-DD date, equivalent to %Y-%m-%d 2001-08-23 +%H Hour in 24h format (00-23) 14 +%j Day of the year (001-366) 235 +%m Month as a decimal number (01-12) 08 +%M Minute (00-59) 55 +%R 24-hour HH:MM time, equivalent to %H:%M 14:55 +%S Second (00-61) 02 +%T ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S 14:55:02 +%u ISO 8601 weekday as number with Monday as 1 (1-7) 4 +%V ISO 8601 week number (00-53) 34 +%w Weekday as a decimal number with Sunday as 0 (0-6) 4 +%W Week number with the first Monday as the first day of week one (00-53) 34 +%X Time representation * 14:55:02 +%y Year, last two digits (00-99) 01 +%Y Year 2001 + +http://www.cplusplus.com/reference/ctime/tm/ +Member Type Meaning Range +tm_sec int seconds after the minute 0-61* +tm_min int minutes after the hour 0-59 +tm_hour int hours since midnight 0-23 +tm_mday int day of the month 1-31 +tm_mon int months since January 0-11 +tm_year int years since 1900 +tm_wday int days since Sunday 0-6 (0 = Sunday) +tm_yday int days since January 1 0-365 +tm_isdst int Daylight Saving Time flag +The Daylight Saving Time flag (tm_isdst) is greater than zero if Daylight Saving Time is in effect, +zero if Daylight Saving Time is not in effect, and less than zero if the information is not available. +* tm_sec is generally 0-59. The extra range is to accommodate for leap seconds in certain systems. + +http://www.epochconverter.com/programming/c +Convert from epoch to human readable date + time_t now; + struct tm ts; + char buf[80]; + // Get current time + time(&now); + // Format time, "ddd yyyy-mm-dd hh:mm:ss zzz" + ts = *localtime(&now); + strftime(buf, sizeof(buf), "%a %Y-%m-%d %H:%M:%S %Z", &ts); + printf("%s\n", buf); + +Convert from human readable date to epoch + struct tm t; + time_t t_of_day; + t.tm_year = 2011-1900; + t.tm_mon = 7; // Month, 0 - jan + t.tm_mday = 8; // Day of the month + t.tm_hour = 16; + t.tm_min = 11; + t.tm_sec = 42; + t.tm_isdst = -1; // Is DST on? 1 = yes, 0 = no, -1 = unknown + t_of_day = mktime(&t); + printf("seconds since the Epoch: %ld\n", (long) t_of_day) + +https://github.com/raburton/esp8266/blob/master/drivers/ds3231.c +https://github.com/raburton/esp8266/blob/master/drivers/ds3231.h + + // https://www.unixtimestamp.com/ + +*/ +#include "mbed.h" +#include "macros.h" +#include "TableSummerTime.h" +#include "TableDayLight.h" + +#ifndef __MCP79412__H_ +#define __MCP79412__H_ + +// MCP7941x I2C Addresses +#define MCP79412_RTC_ADDR 0x6F +#define MCP79412_EEPROM_ADDR 0x57 +#define MAC_LOCATION 0xF2 // Starts at 0xF0 but we are only interested in 6 bytes. +#define RTC_LOCATION 0x00 + +//MCP7941x Register Addresses +#define TIME_REG 0x00 // 7 registers, Seconds, Minutes, Hours, DOW, Date, Month, Year +#define DAY_REG 0x03 // the RTC Day register contains the OSCON, VBAT, and VBATEN bits +#define YEAR_REG 0x06 // RTC year register +#define CTRL_REG 0x07 // control register +#define CALIB_REG 0x08 // calibration register +#define UNLOCK_ID_REG 0x09 // unlock ID register +#define ALM0_REG 0x0A // alarm 0, 6 registers, Seconds, Minutes, Hours, DOW, Date, Month +#define ALM1_REG 0x11 // alarm 1, 6 registers, Seconds, Minutes, Hours, DOW, Date, Month +#define ALM0_DAY 0x0D // DOW register has alarm config/flag bits +#define PWRDWN_TS_REG 0x18 // power-down timestamp, 4 registers, Minutes, Hours, Date, Month +#define PWRUP_TS_REG 0x1C // power-up timestamp, 4 registers, Minutes, Hours, Date, Month +#define TIMESTAMP_SIZE 8 // number of bytes in the two timestamp registers +#define SRAM_START_ADDR 0x20 // first SRAM address +#define SRAM_END_ADDR 0x5F // last SRAM address +#define SRAM_SIZE 64 // number of bytes of SRAM +#define EEPROM_SIZE 128 // number of bytes of EEPROM +#define EEPROM_PAGE_SIZE 8 // number of bytes on an EEPROM page +#define UNIQUE_ID_ADDR 0xF0 // starting address for unique ID +#define UNIQUE_ID_SIZE 8 // number of bytes in unique ID + +#define UNLOCK_ID_CODE1 0x55 // PROTECTED EEPROM UNLOCK SEQUENCE +#define UNLOCK_ID_CODE2 0xAA // PROTECTED EEPROM UNLOCK SEQUENCE + +//Control Register bits +#define OUT 7 // sets logic level on MFP when not used as square wave output +#define SQWE 6 // set to enable square wave output +#define ALM1 5 // alarm 1 is active +#define ALM0 4 // alarm 0 is active +#define EXTOSC 3 // set to drive the RTC registers from an external oscillator instead of a crystal +#define RS2 2 // RS2:0 set square wave output frequency: 0==1Hz, 1==4096Hz, 2==8192Hz, 3=32768Hz +#define RS1 1 +#define RS0 0 + +//Other Control Bits +#define ST 7 // Seconds register (TIME_REG) oscillator start/stop bit, 1==Start, 0==Stop +#define HR1224 6 // Hours register (TIME_REG+2) 12 or 24 hour mode (24 hour mode==0) +#define AMPM 5 // Hours register (TIME_REG+2) AM/PM bit for 12 hour mode +#define OSCON 5 // Day register (TIME_REG+3) oscillator running (set and cleared by hardware) +#define VBAT 4 // Day register (TIME_REG+3) set by hardware when Vcc fails and RTC runs on battery. + // VBAT is cleared by software, clearing VBAT also clears the timestamp registers +#define VBATEN 3 // Day register (TIME_REG+3) VBATEN==1 enables backup battery, VBATEN==0 disconnects the VBAT pin (e.g. to save battery) +#define LP 5 // Month register (TIME_REG+5) leap year bit + +//Alarm Control Bits +#define ALMPOL 7 // Alarm Polarity: Defines the logic level for the MFP when an alarm is triggered. +#define ALMC2 6 // Alarm configuration bits determine how alarms match. See ALM_MATCH defines below. +#define ALMC1 5 +#define ALMC0 4 +#define ALMIF 3 // Alarm Interrupt Flag: Set by hardware when an alarm was triggered, cleared by software. +// Note ALM_MATCH_DAY triggers alarm at midnight +#define ALARM_0 0 // constants for calling functions +#define ALARM_1 1 + +#define MCP79412_SET 0 +#define MCP79412_CLEAR 1 +#define MCP79412_REPLACE 2 + +#define NTP_OFFSET 2208988800ULL + +//convenience macros to convert to and from tm years +#define tmYearToCalendar(Y) ((Y) + 1970) // full four digit year +#define CalendarYrToTm(Y) ((Y) - 1970) +#define tmYearToY2k(Y) ((Y) - 30) // offset is from 2000 +#define y2kYearToTm(Y) ((Y) + 30) + +enum Sqwave { + SQWAVE_1_HZ, + SQWAVE_4096_HZ, + SQWAVE_8192_HZ, + SQWAVE_32768_HZ, + SQWAVE_NONE +}; + +enum { + ALM_MATCH_SECONDS, + ALM_MATCH_MINUTES, + ALM_MATCH_HOURS, + ALM_MATCH_DAY, + ALM_MATCH_DATE, + ALM_RESERVED_5, + ALM_RESERVED_6, + ALM_MATCH_DATETIME, + ALM_DISABLE +}; + +typedef struct DateTime { + int year; + int mon; + int mday; + int wday; + int yday; + int hour; + int min; + int sec; +}; + +class MCP79412 { +public: + DateTime datetime; + struct tm *t; + time_t secondsEpoch; + uint8_t second, minute, hour, dayOfWeek, dayOfMonth, month, year; + + MCP79412(PinName sda, PinName scl); + void setI2Cfrequency(int freq); + bool getFlag(char reg, char mask, char *flag); + void setFlag(char reg, char bits, char mode); + int readRegister(char reg); + void readRegisters(char reg, char *outbuf, char length); + void writeRegister(int reg, char byte); + void writeRegisters(int reg, char *inbuf, char length); + void getMacAddress(char *mac_address); + void writeMacAddress(char *mac_address); + void unlockUniqueID(); + void setRtcDateTime(uint8_t second, uint8_t minute, uint8_t hour, uint8_t dayOfWeek, uint8_t dayOfMonth, uint8_t month, uint8_t year); + void getRtcDateTime(uint8_t *second, uint8_t *minute, uint8_t *hour, uint8_t *dayOfWeek, uint8_t *dayOfMonth, uint8_t *month, uint8_t *year); + bool checkTimeLost(void); + void enableClock(); + void disableClock(); + void enableBattery(); + + void writeRamByte(uint8_t location, uint8_t data); + uint8_t writeRamBytes(uint8_t location, uint8_t *data, uint8_t length); + uint8_t readRamByte(uint8_t location); + uint8_t readRamBytes(uint8_t location, uint8_t *data, uint8_t length); + + void writeSramByte(uint8_t location, uint8_t data); + uint8_t writeSramBytes(uint8_t location, uint8_t *data, uint8_t length); + uint8_t readSramByte(uint8_t location); + uint8_t readSramBytes(uint8_t location, uint8_t *data, uint8_t length); + + void writeEepromByte(uint8_t location, uint8_t data); + uint8_t writeEepromBytes(uint8_t location, uint8_t *data, uint8_t length); + uint8_t readEepromByte(uint8_t location); + uint8_t readEepromBytes(uint8_t location, uint8_t *data, uint8_t length); + + int calibRead(void); + void calibWrite(int value); + void readUniqueId(char *uniqueID); + void getEUI64(char *uniqueID); + bool powerFail(time_t *powerDown, time_t *powerUp); + void squareWave(Sqwave freq); + void setAlarm(uint8_t alarmNumber, time_t alarmTime); + void enableAlarm(uint8_t alarmNumber, uint8_t alarmType); + bool alarm(uint8_t alarmNumber); + void out(bool level); + void alarmPolarity(bool polarity); + bool isRunning(void); + void vbaten(bool enable); + +// bool getSummerTime(void); +// int dayOfYearC(void); +// char * getSunRise(void); +// char * getSunSet(void); +// char * getDayLength(void); +// int getSunRiseMinute(void); +// int getSunSetMinute(void); +// bool checkSunRise(void); + + void substr(char *s, char *d, int pos, int len); + char * substr(char *s, int pos, int len); + + // Mbed dateTime + struct tm setSystemDateTime(uint8_t second, uint8_t minute, uint8_t hour, uint8_t dayOfMonth, uint8_t month, uint8_t year); + void getSystemDateTime(uint8_t *second, uint8_t *minute, uint8_t *hour, uint8_t *dayOfWeek, uint8_t *dayOfMonth, uint8_t *month, uint8_t *year); + void setRtcToSystemDateTime(void); + void setSystemToRtcDateTime(void); + void setRtcFromTm(struct tm *t); + struct tm getTmFromRtc(void); + + time_t getSecondsEpoch(void); + void setSecondsEpoch(time_t t); + + void getRtcDateTimeAsTm(void); + time_t convertDateTimeToTimestamp(uint8_t second, uint8_t minute, uint8_t hour, uint8_t dayOfMonth, uint8_t month, uint8_t year); + uint8_t getWeekdayFromDate(uint8_t dayOfMonth, uint8_t month, uint8_t year); + + int bcd2dec(int k); // bcd to decimal conversion + int dec2bcd(int k); // decimal to bcd conversion + int decToBcd(int val); + int bcdToDec(int val); + +private : + I2C _i2c; + char _address_RTC; + char buffer[32]; + bool _error; + + +}; + +#endif
diff -r 000000000000 -r 04311b121ac4 TableDayLight.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TableDayLight.h Mon Jul 23 12:24:33 2018 +0000 @@ -0,0 +1,149 @@ + const char * const SunRise[] = { +// const string SunRise[] = { + "08:50", "08:50", "08:49", "08:49", "08:49", "08:48", "08:48", "08:47", + "08:47", "08:46", "08:45", "08:44", "08:44", "08:43", "08:42", "08:41", + "08:40", "08:39", "08:38", "08:37", "08:35", "08:34", "08:33", "08:32", + "08:30", "08:29", "08:27", "08:26", "08:24", "08:23", "08:21", "08:20", + "08:18", "08:16", "08:15", "08:13", "08:11", "08:09", "08:08", "08:06", + "08:04", "08:02", "08:00", "07:58", "07:56", "07:54", "07:52", "07:50", + "07:48", "07:46", "07:44", "07:42", "07:40", "07:37", "07:35", "07:33", + "07:31", "07:29", "07:27", "07:24", "07:22", "07:20", "07:18", "07:15", + "07:13", "07:11", "07:08", "07:06", "07:04", "07:02", "06:59", "06:57", + "06:55", "06:52", "06:50", "06:48", "06:45", "06:43", "06:41", "06:38", + "06:36", "06:34", "06:31", "06:29", "06:26", "06:24", "06:22", "06:19", + "06:17", "07:15", "07:12", "07:10", "07:08", "07:05", "07:03", "07:01", + "06:59", "06:56", "06:54", "06:52", "06:49", "06:47", "06:45", "06:43", + "06:41", "06:38", "06:36", "06:34", "06:32", "06:30", "06:28", "06:25", + "06:23", "06:21", "06:19", "06:17", "06:15", "06:13", "06:11", "06:09", + "06:07", "06:05", "06:03", "06:02", "06:00", "05:58", "05:56", "05:54", + "05:53", "05:51", "05:49", "05:48", "05:46", "05:45", "05:43", "05:41", + "05:40", "05:39", "05:37", "05:36", "05:35", "05:33", "05:32", "05:31", + "05:30", "05:29", "05:28", "05:27", "05:26", "05:25", "05:24", "05:23", + "05:22", "05:22", "05:21", "05:20", "05:20", "05:19", "05:19", "05:18", + "05:18", "05:18", "05:17", "05:17", "05:17", "05:17", "05:17", "05:17", + "05:17", "05:17", "05:17", "05:18", "05:18", "05:18", "05:19", "05:19", + "05:20", "05:20", "05:21", "05:21", "05:22", "05:23", "05:23", "05:24", + "05:25", "05:26", "05:27", "05:28", "05:29", "05:30", "05:31", "05:32", + "05:33", "05:35", "05:36", "05:37", "05:38", "05:40", "05:41", "05:42", + "05:44", "05:45", "05:46", "05:48", "05:49", "05:51", "05:52", "05:54", + "05:55", "05:57", "05:58", "06:00", "06:01", "06:03", "06:05", "06:06", + "06:08", "06:09", "06:11", "06:13", "06:14", "06:16", "06:18", "06:19", + "06:21", "06:23", "06:24", "06:26", "06:27", "06:29", "06:31", "06:32", + "06:34", "06:36", "06:37", "06:39", "06:41", "06:42", "06:44", "06:46", + "06:47", "06:49", "06:51", "06:52", "06:54", "06:56", "06:57", "06:59", + "07:01", "07:02", "07:04", "07:06", "07:07", "07:09", "07:11", "07:12", + "07:14", "07:15", "07:17", "07:19", "07:20", "07:22", "07:24", "07:25", + "07:27", "07:29", "07:30", "07:32", "07:34", "07:35", "07:37", "07:39", + "07:41", "07:42", "07:44", "07:46", "07:47", "07:49", "07:51", "07:53", + "07:54", "07:56", "07:58", "07:59", "08:01", "08:03", "08:05", "08:06", + "08:08", "08:10", "08:12", "08:14", "08:15", "08:17", "08:19", "08:21", + "08:23", "08:24", "08:26", "07:28", "07:30", "07:32", "07:33", "07:35", + "07:37", "07:39", "07:41", "07:43", "07:44", "07:46", "07:48", "07:50", + "07:52", "07:54", "07:55", "07:57", "07:59", "08:01", "08:02", "08:04", + "08:06", "08:08", "08:09", "08:11", "08:13", "08:14", "08:16", "08:18", + "08:19", "08:21", "08:22", "08:24", "08:25", "08:27", "08:28", "08:30", + "08:31", "08:32", "08:34", "08:35", "08:36", "08:37", "08:38", "08:39", + "08:40", "08:41", "08:42", "08:43", "08:44", "08:45", "08:46", "08:46", + "08:47", "08:47", "08:48", "08:48", "08:49", "08:49", "08:49", "08:50", + "08:50", "08:50", "08:50", "08:50", "08:50", "08:50" + }; + + const char * const SunSet[] = { +// const string SunSet[] = { + "16:38", "16:39", "16:40", "16:41", "16:43", "16:44", "16:45", "16:47", + "16:48", "16:50", "16:51", "16:53", "16:54", "16:56", "16:57", "16:59", + "17:01", "17:02", "17:04", "17:06", "17:07", "17:09", "17:11", "17:13", + "17:15", "17:16", "17:18", "17:20", "17:22", "17:24", "17:26", "17:28", + "17:29", "17:31", "17:33", "17:35", "17:37", "17:39", "17:41", "17:43", + "17:44", "17:46", "17:48", "17:50", "17:52", "17:54", "17:56", "17:58", + "18:00", "18:01", "18:03", "18:05", "18:07", "18:09", "18:11", "18:13", + "18:14", "18:16", "18:18", "18:20", "18:22", "18:24", "18:25", "18:27", + "18:29", "18:31", "18:33", "18:34", "18:36", "18:38", "18:40", "18:42", + "18:43", "18:45", "18:47", "18:49", "18:50", "18:52", "18:54", "18:56", + "18:57", "18:59", "19:01", "19:03", "19:04", "19:06", "19:08", "19:10", + "19:11", "20:13", "20:15", "20:17", "20:18", "20:20", "20:22", "20:23", + "20:25", "20:27", "20:29", "20:30", "20:32", "20:34", "20:36", "20:37", + "20:39", "20:41", "20:43", "20:44", "20:46", "20:48", "20:49", "20:51", + "20:53", "20:55", "20:56", "20:58", "21:00", "21:02", "21:03", "21:05", + "21:07", "21:08", "21:10", "21:12", "21:13", "21:15", "21:17", "21:18", + "21:20", "21:22", "21:23", "21:25", "21:26", "21:28", "21:30", "21:31", + "21:33", "21:34", "21:36", "21:37", "21:39", "21:40", "21:41", "21:43", + "21:44", "21:45", "21:47", "21:48", "21:49", "21:50", "21:52", "21:53", + "21:54", "21:55", "21:56", "21:57", "21:58", "21:59", "22:00", "22:00", + "22:01", "22:02", "22:02", "22:03", "22:04", "22:04", "22:05", "22:05", + "22:05", "22:06", "22:06", "22:06", "22:06", "22:06", "22:06", "22:06", + "22:06", "22:06", "22:06", "22:06", "22:06", "22:05", "22:05", "22:04", + "22:04", "22:03", "22:03", "22:02", "22:01", "22:01", "22:00", "21:59", + "21:58", "21:57", "21:56", "21:55", "21:54", "21:53", "21:52", "21:50", + "21:49", "21:48", "21:46", "21:45", "21:44", "21:42", "21:41", "21:39", + "21:38", "21:36", "21:34", "21:33", "21:31", "21:29", "21:27", "21:26", + "21:24", "21:22", "21:20", "21:18", "21:16", "21:14", "21:12", "21:10", + "21:08", "21:06", "21:04", "21:02", "21:00", "20:58", "20:56", "20:54", + "20:52", "20:50", "20:47", "20:45", "20:43", "20:41", "20:38", "20:36", + "20:34", "20:32", "20:29", "20:27", "20:25", "20:23", "20:20", "20:18", + "20:16", "20:13", "20:11", "20:09", "20:06", "20:04", "20:01", "19:59", + "19:57", "19:54", "19:52", "19:50", "19:47", "19:45", "19:42", "19:40", + "19:38", "19:35", "19:33", "19:31", "19:28", "19:26", "19:24", "19:21", + "19:19", "19:17", "19:14", "19:12", "19:10", "19:07", "19:05", "19:03", + "19:00", "18:58", "18:56", "18:54", "18:51", "18:49", "18:47", "18:45", + "18:42", "18:40", "18:38", "18:36", "18:34", "18:32", "18:30", "18:28", + "18:26", "18:23", "18:21", "17:19", "17:18", "17:16", "17:14", "17:12", + "17:10", "17:08", "17:06", "17:04", "17:03", "17:01", "16:59", "16:58", + "16:56", "16:54", "16:53", "16:51", "16:50", "16:48", "16:47", "16:46", + "16:44", "16:43", "16:42", "16:40", "16:39", "16:38", "16:37", "16:36", + "16:35", "16:34", "16:33", "16:32", "16:32", "16:31", "16:30", "16:30", + "16:29", "16:29", "16:28", "16:28", "16:27", "16:27", "16:27", "16:27", + "16:27", "16:27", "16:27", "16:27", "16:27", "16:27", "16:27", "16:27", + "16:28", "16:28", "16:29", "16:29", "16:30", "16:31", "16:31", "16:32", + "16:33", "16:34", "16:35", "16:36", "16:37", "16:37" + }; + + const char * const DayLength[] = { +// const string DayLength[] = { + "07:48", "07:49", "07:51", "07:52", "07:54", "07:55", "07:57", "07:59", + "08:01", "08:03", "08:05", "08:08", "08:10", "08:13", "08:15", "08:18", + "08:20", "08:23", "08:26", "08:29", "08:32", "08:35", "08:38", "08:41", + "08:44", "08:47", "08:50", "08:54", "08:57", "09:00", "09:04", "09:07", + "09:11", "09:14", "09:18", "09:22", "09:25", "09:29", "09:33", "09:36", + "09:40", "09:44", "09:48", "09:52", "09:55", "09:59", "10:03", "10:07", + "10:11", "10:15", "10:19", "10:23", "10:27", "10:31", "10:35", "10:39", + "10:43", "10:47", "10:51", "10:55", "10:59", "11:03", "11:07", "11:11", + "11:15", "11:20", "11:24", "11:28", "11:32", "11:36", "11:40", "11:44", + "11:48", "11:52", "11:56", "12:01", "12:05", "12:09", "12:13", "12:17", + "12:21", "12:25", "12:29", "12:33", "12:37", "12:42", "12:46", "12:50", + "12:54", "12:58", "13:02", "13:06", "13:10", "13:14", "13:18", "13:22", + "13:26", "13:30", "13:34", "13:38", "13:42", "13:46", "13:50", "13:54", + "13:58", "14:02", "14:06", "14:10", "14:14", "14:18", "14:21", "14:25", + "14:29", "14:33", "14:37", "14:40", "14:44", "14:48", "14:52", "14:55", + "14:59", "15:03", "15:06", "15:10", "15:13", "15:17", "15:20", "15:23", + "15:27", "15:30", "15:33", "15:37", "15:40", "15:43", "15:46", "15:49", + "15:52", "15:55", "15:58", "16:01", "16:04", "16:06", "16:09", "16:11", + "16:14", "16:16", "16:19", "16:21", "16:23", "16:25", "16:27", "16:29", + "16:31", "16:33", "16:34", "16:36", "16:38", "16:39", "16:40", "16:41", + "16:43", "16:44", "16:45", "16:45", "16:46", "16:47", "16:47", "16:48", + "16:48", "16:48", "16:48", "16:48", "16:48", "16:48", "16:47", "16:47", + "16:46", "16:46", "16:45", "16:44", "16:43", "16:42", "16:41", "16:40", + "16:38", "16:37", "16:35", "16:34", "16:32", "16:30", "16:28", "16:26", + "16:24", "16:22", "16:20", "16:17", "16:15", "16:13", "16:10", "16:08", + "16:05", "16:02", "16:00", "15:57", "15:54", "15:51", "15:48", "15:45", + "15:42", "15:39", "15:35", "15:32", "15:29", "15:26", "15:22", "15:19", + "15:16", "15:12", "15:09", "15:05", "15:02", "14:58", "14:54", "14:51", + "14:47", "14:43", "14:40", "14:36", "14:32", "14:28", "14:25", "14:21", + "14:17", "14:13", "14:09", "14:06", "14:02", "13:58", "13:54", "13:50", + "13:46", "13:42", "13:38", "13:34", "13:30", "13:26", "13:22", "13:18", + "13:14", "13:10", "13:06", "13:02", "12:58", "12:54", "12:50", "12:46", + "12:42", "12:38", "12:34", "12:30", "12:26", "12:22", "12:18", "12:14", + "12:10", "12:06", "12:02", "11:58", "11:54", "11:50", "11:46", "11:42", + "11:38", "11:34", "11:30", "11:26", "11:22", "11:18", "11:14", "11:10", + "11:06", "11:02", "10:58", "10:54", "10:50", "10:46", "10:42", "10:38", + "10:34", "10:30", "10:26", "10:22", "10:18", "10:14", "10:10", "10:06", + "10:02", "09:59", "09:55", "09:51", "09:47", "09:43", "09:40", "09:36", + "09:32", "09:29", "09:25", "09:21", "09:18", "09:14", "09:11", "09:07", + "09:04", "09:00", "08:57", "08:54", "08:50", "08:47", "08:44", "08:41", + "08:38", "08:35", "08:32", "08:29", "08:26", "08:23", "08:21", "08:18", + "08:15", "08:13", "08:10", "08:08", "08:06", "08:04", "08:01", "07:59", + "07:58", "07:56", "07:54", "07:52", "07:51", "07:49", "07:48", "07:47", + "07:46", "07:45", "07:44", "07:43", "07:42", "07:42", "07:41", "07:41", + "07:41", "07:40", "07:40", "07:40", "07:41", "07:41", "07:41", "07:42", + "07:43", "07:43", "07:44", "07:45", "07:46", "07:46" + };
diff -r 000000000000 -r 04311b121ac4 TableSummerTime.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TableSummerTime.h Mon Jul 23 12:24:33 2018 +0000 @@ -0,0 +1,67 @@ +/* +http://hemel.waarnemen.com/aarde/zomertijd.html#2016 +De zomertijd (of zomeruur) begint in de EU op de laatste zondag van maart en eindigt op de laatste zondag van oktober. +Dit gebeurt in alle lidstaten op hetzelfde moment. +In België en Nederland is dat 's nachts om 2 uur wintertijd (of winteruur; MET). +In het voorjaar betekent dat dat de klok van 2 uur MET wordt omgezet naar 3 uur MEZT, +zodat de nacht een uur korter duurt. +In het najaar wordt de klok om 3 uur MEZT teruggezet naar 2 uur MET, +zodat we een uur langer kunnen slapen (de tijdspanne tussen 2 en 3 uur komt immers tweemaal voor). +*/ + + const char * const SummerTime[] = { + "2011", "03", "27", "10", "30", + "2012", "03", "25", "10", "28", + "2013", "03", "31", "10", "27", + "2014", "03", "30", "10", "26", + "2015", "03", "29", "10", "25", + "2016", "03", "27", "10", "30", + "2017", "03", "26", "10", "29", + "2018", "03", "25", "10", "28", + "2019", "03", "31", "10", "27", + "2020", "03", "29", "10", "25", + + "2021", "03", "28", "10", "31", + "2022", "03", "27", "10", "30", + "2023", "03", "26", "10", "29", + "2024", "03", "31", "10", "27", + "2025", "03", "30", "10", "26", + "2026", "03", "29", "10", "25", + "2027", "03", "28", "10", "31", + "2028", "03", "26", "10", "29", + "2029", "03", "25", "10", "28", + "2030", "03", "31", "10", "27", + + "2031", "03", "30", "10", "26", + "2032", "03", "28", "10", "31", + "2033", "03", "27", "10", "30", + "2034", "03", "26", "10", "29", + "2035", "03", "25", "10", "28", + "2036", "03", "30", "10", "26", + "2037", "03", "29", "10", "25", + "2038", "03", "28", "10", "31", + "2039", "03", "27", "10", "30", + "2040", "03", "25", "10", "28", + + "2041", "03", "31", "10", "27", + "2042", "03", "30", "10", "26", + "2043", "03", "29", "10", "25", + "2044", "03", "27", "10", "30", + "2045", "03", "26", "10", "29", + "2046", "03", "25", "10", "28", + "2047", "03", "31", "10", "27", + "2048", "03", "29", "10", "25", + "2049", "03", "28", "10", "31", + "2050", "03", "27", "10", "30", + + "2051", "03", "26", "10", "29", + "2052", "03", "31", "10", "27", + "2053", "03", "30", "10", "26", + "2054", "03", "29", "10", "25", + "2055", "03", "28", "10", "31", + "2056", "03", "26", "10", "29", + "2057", "03", "25", "10", "28", + "2058", "03", "31", "10", "27", + "2059", "03", "30", "10", "26", + "2060", "03", "28", "10", "31" + };