mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
210 lines
6.5 KiB
C
210 lines
6.5 KiB
C
/*
|
|
* Copyright (C) 2017 Freie Universität Berlin
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU Lesser
|
|
* General Public License v2.1. See the file LICENSE in the top level
|
|
* directory for more details.
|
|
*/
|
|
|
|
/**
|
|
* @ingroup drivers_ds1307
|
|
* @{
|
|
*
|
|
* @file
|
|
* @author Martine Lenders <m.lenders@fu-berlin.de>
|
|
*/
|
|
|
|
#include <string.h>
|
|
|
|
#include "bcd.h"
|
|
|
|
#include "ds1307.h"
|
|
#include "ds1307_internal.h"
|
|
|
|
#define ENABLE_DEBUG 0
|
|
#include "debug.h"
|
|
|
|
static int _nvram_read(struct nvram *dev, uint8_t *dst, uint32_t src,
|
|
size_t size);
|
|
static int _nvram_write(struct nvram *dev, const uint8_t *src, uint32_t dst,
|
|
size_t size);
|
|
|
|
static uint8_t _convert_12_to_24(uint8_t hour)
|
|
{
|
|
if (hour & DS1307_REG_HOUR_12H) {
|
|
uint8_t tmp = bcd_to_byte(hour & DS1307_REG_HOUR_12H_MASK);
|
|
if (hour & DS1307_REG_HOUR_PM) {
|
|
if (tmp < 12) {
|
|
tmp += 12;
|
|
}
|
|
}
|
|
else {
|
|
if (tmp == 12) {
|
|
tmp = 0;
|
|
}
|
|
}
|
|
hour = (bcd_from_byte(tmp) & DS1307_REG_HOUR_24H_MASK);
|
|
}
|
|
return hour;
|
|
}
|
|
|
|
int ds1307_init(ds1307_t *dev, const ds1307_params_t *params)
|
|
{
|
|
int res;
|
|
uint8_t hour;
|
|
|
|
dev->i2c = params->i2c;
|
|
|
|
i2c_acquire(dev->i2c);
|
|
/* normalize hour format */
|
|
res = i2c_read_reg(dev->i2c, DS1307_I2C_ADDRESS, DS1307_REG_HOUR, &hour, 0);
|
|
if (res != 0) { /* should be 0 if device is connected */
|
|
i2c_release(dev->i2c);
|
|
DEBUG("ds1307: Error reading HOUR register on init: %i\n", res);
|
|
return -1;
|
|
}
|
|
res = i2c_write_reg(dev->i2c, DS1307_I2C_ADDRESS, DS1307_REG_HOUR,
|
|
_convert_12_to_24(hour), 0);
|
|
i2c_release(dev->i2c);
|
|
|
|
if (res != 0) {
|
|
DEBUG("ds1307: Error writing HOUR register on init: %i\n", res);
|
|
return -1;
|
|
}
|
|
dev->nvram.read = _nvram_read;
|
|
dev->nvram.write = _nvram_write;
|
|
dev->nvram.size = (DS1307_REG_RAM_LAST - DS1307_REG_RAM_FIRST) + 1;
|
|
dev->nvram.extra = dev;
|
|
return 0;
|
|
}
|
|
|
|
int ds1307_set_time(const ds1307_t *dev, const struct tm *time)
|
|
{
|
|
uint8_t regs[DS1307_REG_YEAR - DS1307_REG_SEC + 1];
|
|
int res;
|
|
|
|
regs[DS1307_REG_SEC] = (bcd_from_byte(time->tm_sec) & DS1307_REG_SEC_MASK);
|
|
regs[DS1307_REG_MIN] = (bcd_from_byte(time->tm_min) & DS1307_REG_MIN_MASK);
|
|
regs[DS1307_REG_HOUR] = (bcd_from_byte(time->tm_hour) &
|
|
DS1307_REG_HOUR_24H_MASK);
|
|
regs[DS1307_REG_DOW] = (bcd_from_byte(time->tm_wday + DS1307_DOW_OFFSET) &
|
|
DS1307_REG_DOW_MASK);
|
|
regs[DS1307_REG_DOM] = (bcd_from_byte(time->tm_mday) & DS1307_REG_DOM_MASK);
|
|
regs[DS1307_REG_MON] = (bcd_from_byte(time->tm_mon + DS1307_MON_OFFSET) &
|
|
DS1307_REG_MON_MASK);
|
|
regs[DS1307_REG_YEAR] = bcd_from_byte(time->tm_year + DS1307_YEAR_OFFSET);
|
|
i2c_acquire(dev->i2c);
|
|
res = i2c_write_regs(dev->i2c, DS1307_I2C_ADDRESS, DS1307_REG_SEC, regs,
|
|
sizeof(regs), 0);
|
|
DEBUG("ds1307: wrote bytes %02x %02x %02x %02x %02x %02x %02x to device (result: %i)\n",
|
|
regs[DS1307_REG_SEC], regs[DS1307_REG_MIN], regs[DS1307_REG_HOUR],
|
|
regs[DS1307_REG_DOW], regs[DS1307_REG_DOM], regs[DS1307_REG_MON],
|
|
regs[DS1307_REG_YEAR], res);
|
|
i2c_release(dev->i2c);
|
|
return (res != 0) ? -1 : 0;
|
|
}
|
|
|
|
int ds1307_get_time(const ds1307_t *dev, struct tm *time)
|
|
{
|
|
uint8_t regs[DS1307_REG_YEAR - DS1307_REG_SEC + 1];
|
|
int res;
|
|
|
|
i2c_acquire(dev->i2c);
|
|
res = i2c_read_regs(dev->i2c, DS1307_I2C_ADDRESS, DS1307_REG_SEC, regs,
|
|
sizeof(regs), 0);
|
|
DEBUG("ds1307: read bytes %02x %02x %02x %02x %02x %02x %02x from device (result: %i)\n",
|
|
regs[DS1307_REG_SEC], regs[DS1307_REG_MIN], regs[DS1307_REG_HOUR],
|
|
regs[DS1307_REG_DOW], regs[DS1307_REG_DOM], regs[DS1307_REG_MON],
|
|
regs[DS1307_REG_YEAR], res);
|
|
i2c_release(dev->i2c);
|
|
if (res != 0) {
|
|
return -1;
|
|
}
|
|
time->tm_sec = bcd_to_byte(regs[DS1307_REG_SEC] & DS1307_REG_SEC_MASK);
|
|
time->tm_min = bcd_to_byte(regs[DS1307_REG_MIN] & DS1307_REG_MIN_MASK);
|
|
time->tm_hour = bcd_to_byte(regs[DS1307_REG_HOUR] &
|
|
DS1307_REG_HOUR_24H_MASK);
|
|
time->tm_wday = (bcd_to_byte(regs[DS1307_REG_DOW] & DS1307_REG_DOW_MASK) -
|
|
DS1307_DOW_OFFSET);
|
|
time->tm_mday = bcd_to_byte(regs[DS1307_REG_DOM] & DS1307_REG_DOM_MASK);
|
|
time->tm_mon = bcd_to_byte(regs[DS1307_REG_MON] & DS1307_REG_MON_MASK) -
|
|
DS1307_MON_OFFSET;
|
|
time->tm_year = (bcd_to_byte(regs[DS1307_REG_YEAR]) - DS1307_YEAR_OFFSET);
|
|
return 0;
|
|
}
|
|
|
|
int ds1307_halt(const ds1307_t *dev)
|
|
{
|
|
int res;
|
|
uint8_t sec;
|
|
|
|
i2c_acquire(dev->i2c);
|
|
res = i2c_read_reg(dev->i2c, DS1307_I2C_ADDRESS, DS1307_REG_SEC, &sec, 0);
|
|
if (res != 0) {
|
|
i2c_release(dev->i2c);
|
|
DEBUG("ds1307: Error reading SEC register on halt: %i\n", res);
|
|
return -1;
|
|
}
|
|
sec |= DS1307_REG_SEC_CH;
|
|
res = i2c_write_reg(dev->i2c, DS1307_I2C_ADDRESS, DS1307_REG_SEC, sec, 0);
|
|
i2c_release(dev->i2c);
|
|
return (res != 0) ? -1 : 0;
|
|
}
|
|
|
|
int ds1307_set_sqw_mode(const ds1307_t *dev, ds1307_sqw_mode_t mode)
|
|
{
|
|
int res;
|
|
|
|
i2c_acquire(dev->i2c);
|
|
res = i2c_write_reg(dev->i2c, DS1307_I2C_ADDRESS, DS1307_REG_SQW_CTL,
|
|
(uint8_t)mode, 0);
|
|
i2c_release(dev->i2c);
|
|
return res;
|
|
}
|
|
|
|
int ds1307_get_sqw_mode(const ds1307_t *dev)
|
|
{
|
|
uint8_t mode;
|
|
int res;
|
|
|
|
i2c_acquire(dev->i2c);
|
|
res = i2c_read_reg(dev->i2c, DS1307_I2C_ADDRESS, DS1307_REG_SQW_CTL,
|
|
&mode, 0);
|
|
i2c_release(dev->i2c);
|
|
return (res < 0) ? res : (int)mode;
|
|
}
|
|
|
|
static int _nvram_read(struct nvram *nvram, uint8_t *dst, uint32_t src,
|
|
size_t size)
|
|
{
|
|
const ds1307_t *dev = nvram->extra;
|
|
int res;
|
|
|
|
if ((src + size) > nvram->size) {
|
|
return -3;
|
|
}
|
|
i2c_acquire(dev->i2c);
|
|
res = i2c_read_regs(dev->i2c, DS1307_I2C_ADDRESS,
|
|
DS1307_REG_RAM_FIRST + src, dst, size, 0);
|
|
i2c_release(dev->i2c);
|
|
return (res == 0) ? (int)size : -1;
|
|
}
|
|
|
|
static int _nvram_write(struct nvram *nvram, const uint8_t *src, uint32_t dst,
|
|
size_t size)
|
|
{
|
|
const ds1307_t *dev = nvram->extra;
|
|
int res;
|
|
|
|
if ((dst + size) > nvram->size) {
|
|
return -3;
|
|
}
|
|
i2c_acquire(dev->i2c);
|
|
res = i2c_write_regs(dev->i2c, DS1307_I2C_ADDRESS,
|
|
DS1307_REG_RAM_FIRST + dst, src, size, 0);
|
|
i2c_release(dev->i2c);
|
|
return (res == 0) ? (int)size : -1;
|
|
}
|
|
|
|
/** @} */
|