mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
363 lines
7.9 KiB
C
363 lines
7.9 KiB
C
/*
|
|
* Copyright (C) 2020 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 tests
|
|
* @{
|
|
*
|
|
* @file
|
|
* @brief Test application for the DS3231 RTC driver
|
|
*
|
|
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
|
*
|
|
* @}
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
|
|
#include "shell.h"
|
|
#include "xtimer.h"
|
|
#include "ds3231.h"
|
|
#include "ds3231_params.h"
|
|
|
|
#define ISOSTR_LEN (20U)
|
|
#define TEST_DELAY (2U)
|
|
|
|
static ds3231_t _dev;
|
|
|
|
/* 2010-09-22T15:10:42 is the author date of RIOT's initial commit */
|
|
static struct tm _riot_bday = {
|
|
.tm_sec = 42,
|
|
.tm_min = 10,
|
|
.tm_hour = 15,
|
|
.tm_wday = 3,
|
|
.tm_mday = 22,
|
|
.tm_mon = 8,
|
|
.tm_year = 110
|
|
};
|
|
|
|
/* parse ISO date string (YYYY-MM-DDTHH:mm:ss) to struct tm */
|
|
static int _tm_from_str(const char *str, struct tm *time)
|
|
{
|
|
char tmp[5];
|
|
|
|
if (strlen(str) != ISOSTR_LEN - 1) {
|
|
return -1;
|
|
}
|
|
if ((str[4] != '-') || (str[7] != '-') || (str[10] != 'T') ||
|
|
(str[13] != ':') || (str[16] != ':')) {
|
|
return -1;
|
|
}
|
|
|
|
memset(time, 0, sizeof(struct tm));
|
|
|
|
memcpy(tmp, str, 4);
|
|
tmp[4] = '\0';
|
|
str += 5;
|
|
time->tm_year = atoi(tmp) - 1900;
|
|
|
|
memcpy(tmp, str, 2);
|
|
tmp[2] = '\0';
|
|
str += 3;
|
|
time->tm_mon = atoi(tmp) - 1;
|
|
|
|
memcpy(tmp, str, 2);
|
|
str += 3;
|
|
time->tm_mday = atoi(tmp);
|
|
|
|
memcpy(tmp, str, 2);
|
|
str += 3;
|
|
time->tm_hour = atoi(tmp);
|
|
|
|
memcpy(tmp, str, 2);
|
|
str += 3;
|
|
time->tm_min = atoi(tmp);
|
|
|
|
memcpy(tmp, str, 2);
|
|
time->tm_sec = atoi(tmp);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int _cmd_get(int argc, char **argv)
|
|
{
|
|
(void)argc;
|
|
(void)argv;
|
|
char dstr[ISOSTR_LEN];
|
|
|
|
struct tm time;
|
|
int res;
|
|
res = ds3231_get_time(&_dev, &time);
|
|
if (res != 0) {
|
|
puts("error: unable to read time");
|
|
return 1;
|
|
}
|
|
|
|
size_t pos = strftime(dstr, ISOSTR_LEN, "%Y-%m-%dT%H:%M:%S", &time);
|
|
dstr[pos] = '\0';
|
|
printf("The current time is: %s\n", dstr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int _cmd_set(int argc, char **argv)
|
|
{
|
|
if (argc != 2) {
|
|
printf("usage: %s <iso-date-str YYYY-MM-DDTHH:mm:ss>\n", argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
if (strlen(argv[1]) != (ISOSTR_LEN - 1)) {
|
|
puts("error: input date string has invalid length");
|
|
return 1;
|
|
}
|
|
|
|
struct tm target_time;
|
|
int res = _tm_from_str(argv[1], &target_time);
|
|
if (res != 0) {
|
|
puts("error: unable do parse input date string");
|
|
return 1;
|
|
}
|
|
|
|
res = ds3231_set_time(&_dev, &target_time);
|
|
if (res != 0) {
|
|
puts("error: unable to set time");
|
|
return 1;
|
|
}
|
|
|
|
printf("success: time set to %s\n", argv[1]);
|
|
return 0;
|
|
}
|
|
|
|
static int _cmd_temp(int argc, char **argv)
|
|
{
|
|
(void)argc;
|
|
(void)argv;
|
|
int16_t temp;
|
|
|
|
int res = ds3231_get_temp(&_dev, &temp);
|
|
if (res != 0) {
|
|
puts("error: unable to read temperature");
|
|
return 1;
|
|
}
|
|
|
|
int t1 = temp / 100;
|
|
int t2 = temp - (t1 * 100);
|
|
printf("Current temperature: %i.%02i°C\n", t1, t2);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int _cmd_aging(int argc, char **argv)
|
|
{
|
|
int8_t val;
|
|
int res;
|
|
|
|
if (argc == 1) {
|
|
res = ds3231_get_aging_offset(&_dev, &val);
|
|
if (res != 0) {
|
|
puts("error: unable to obtain aging offset");
|
|
return 1;
|
|
}
|
|
printf("Aging offset: %i\n", (int)val);
|
|
}
|
|
else {
|
|
val = atoi(argv[1]);
|
|
res = ds3231_set_aging_offset(&_dev, val);
|
|
if (res != 0) {
|
|
puts("error: unable to set againg offset");
|
|
return 1;
|
|
}
|
|
printf("Success: set aging offset to %i\n", (int)val);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int _cmd_bat(int argc, char **argv)
|
|
{
|
|
int res;
|
|
|
|
if (argc != 2) {
|
|
printf("usage: %s <'0' or '1'>\n", argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
if (argv[1][0] == '1') {
|
|
res = ds3231_enable_bat(&_dev);
|
|
if (res == 0) {
|
|
puts("success: backup battery enabled");
|
|
}
|
|
else {
|
|
puts("error: unable to enable backup battery");
|
|
}
|
|
}
|
|
else if (argv[1][0] == '0') {
|
|
res = ds3231_disable_bat(&_dev);
|
|
if (res == 0) {
|
|
puts("success: backup battery disabled");
|
|
}
|
|
else {
|
|
puts("error: unable to disable backup battery");
|
|
}
|
|
}
|
|
else {
|
|
puts("error: unable to parse command");
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int _cmd_test(int argc, char **argv)
|
|
{
|
|
(void)argc;
|
|
(void)argv;
|
|
int res;
|
|
struct tm time;
|
|
|
|
puts("testing device now");
|
|
|
|
/* set time to RIOT birthdate */
|
|
res = ds3231_set_time(&_dev, &_riot_bday);
|
|
if (res != 0) {
|
|
puts("error: unable to set time");
|
|
return 1;
|
|
}
|
|
|
|
/* read time and compare to initial value */
|
|
res = ds3231_get_time(&_dev, &time);
|
|
if (res != 0) {
|
|
puts("error: unable to read time");
|
|
return 1;
|
|
}
|
|
|
|
if ((mktime(&time) - mktime(&_riot_bday)) > 1) {
|
|
puts("error: device time has unexpected value");
|
|
return 1;
|
|
}
|
|
|
|
/* wait a short while and check if time has progressed */
|
|
xtimer_sleep(TEST_DELAY);
|
|
res = ds3231_get_time(&_dev, &time);
|
|
if (res != 0) {
|
|
puts("error: unable to read time");
|
|
return 1;
|
|
}
|
|
|
|
if (!(mktime(&time) > mktime(&_riot_bday))) {
|
|
puts("error: time did not progress");
|
|
return 1;
|
|
}
|
|
|
|
/* clear all existing alarm flag */
|
|
res = ds3231_clear_alarm_1_flag(&_dev);
|
|
if (res != 0) {
|
|
puts("error: unable to clear alarm flag");
|
|
return 1;
|
|
}
|
|
|
|
/* get time to set up next alarm*/
|
|
res = ds3231_get_time(&_dev, &time);
|
|
if (res != 0) {
|
|
puts("error: unable to read time");
|
|
return 1;
|
|
}
|
|
|
|
time.tm_sec += TEST_DELAY;
|
|
mktime(&time);
|
|
|
|
/* set alarm */
|
|
res = ds3231_set_alarm_1(&_dev, &time, DS3231_AL1_TRIG_H_M_S);
|
|
if (res != 0) {
|
|
puts("error: unable to program alarm");
|
|
return 1;
|
|
}
|
|
|
|
#ifdef MODULE_DS3231_INT
|
|
|
|
/* wait for an alarm with GPIO interrupt */
|
|
res = ds3231_await_alarm(&_dev);
|
|
if (res < 0){
|
|
puts("error: unable to program GPIO interrupt or to clear alarm flag");
|
|
}
|
|
|
|
if (!(res & DS3231_FLAG_ALARM_1)){
|
|
puts("error: alarm was not triggered");
|
|
}
|
|
|
|
puts("OK");
|
|
return 0;
|
|
|
|
#else
|
|
|
|
/* wait for the alarm to trigger */
|
|
xtimer_sleep(TEST_DELAY);
|
|
|
|
bool alarm;
|
|
|
|
/* check if alarm flag is on */
|
|
res = ds3231_get_alarm_1_flag(&_dev, &alarm);
|
|
if (res != 0) {
|
|
puts("error: unable to get alarm flag");
|
|
return 1;
|
|
}
|
|
|
|
if (alarm != true){
|
|
puts("error: alarm was not triggered");
|
|
}
|
|
|
|
/* clear alarm flag */
|
|
res = ds3231_clear_alarm_1_flag(&_dev);
|
|
if (res != 0) {
|
|
puts("error: unable to clear alarm flag");
|
|
return 1;
|
|
}
|
|
|
|
puts("OK");
|
|
return 0;
|
|
|
|
#endif
|
|
}
|
|
|
|
static const shell_command_t shell_commands[] = {
|
|
{ "time_get", "init as output (push-pull mode)", _cmd_get },
|
|
{ "time_set", "init as input w/o pull resistor", _cmd_set },
|
|
{ "temp", "get temperature", _cmd_temp },
|
|
{ "aging", "get or set the aging offset", _cmd_aging },
|
|
{ "bat", "en/disable backup battery", _cmd_bat },
|
|
{ "test", "test if the device is working properly", _cmd_test},
|
|
{ NULL, NULL, NULL }
|
|
};
|
|
|
|
int main(void)
|
|
{
|
|
int res;
|
|
|
|
puts("DS3231 RTC test\n");
|
|
|
|
/* initialize the device */
|
|
ds3231_params_t params= ds3231_params[0];
|
|
params.opt = DS3231_OPT_BAT_ENABLE;
|
|
params.opt |= DS3231_OPT_INTER_ENABLE;
|
|
res = ds3231_init(&_dev, ¶ms);
|
|
if (res != 0) {
|
|
puts("error: unable to initialize DS3231 [I2C initialization error]");
|
|
return 1;
|
|
}
|
|
|
|
/* start the shell */
|
|
char line_buf[SHELL_DEFAULT_BUFSIZE];
|
|
shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
|
|
|
|
return 0;
|
|
}
|