mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
194 lines
5.4 KiB
C
194 lines
5.4 KiB
C
/*
|
|
* Copyright (C) 2019 HAW Hamburg
|
|
*
|
|
* 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_dcf77
|
|
* @{
|
|
*
|
|
* @file
|
|
* @brief Device driver implementation for the dcf 77
|
|
* longwave time signal and standard-frequency radio station
|
|
*
|
|
* @author Michel Gerlach <michel.gerlach@haw-hamburg.de>
|
|
*
|
|
* @}
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#include "log.h"
|
|
#include "assert.h"
|
|
#include "xtimer.h"
|
|
#include "periph/gpio.h"
|
|
|
|
#include "dcf77.h"
|
|
#include "dcf77_params.h"
|
|
|
|
#define ENABLE_DEBUG 0
|
|
#include "debug.h"
|
|
|
|
/* Persistent level longer than 1200ms starts a new cycle */
|
|
#define DCF77_PULSE_START_HIGH_THRESHOLD_US (1200000U) /*~1200ms*/
|
|
/* Every pulse send by the DCF longer than 130ms is interpreted as 1 */
|
|
#define DCF77_PULSE_WIDTH_THRESHOLD_US (140000U) /*~140ms*/
|
|
/* Number of bits in a cycle*/
|
|
#define DCF77_READING_CYCLE (59)
|
|
|
|
#define DCF77_MINUTE_MASK (0xFE00000ULL)
|
|
#define DCF77_HOUR_MASK (0x7E0000000ULL)
|
|
#define DCF77_DATE_MASK (0x1FFFFFC00000000ULL)
|
|
|
|
#define DCF77_MINUTE_SHIFT (21)
|
|
#define DCF77_HOUR_SHIFT (29)
|
|
#define DCF77_DATE_SHIFT (36)
|
|
|
|
static void _level_cb_high(dcf77_t *dev)
|
|
{
|
|
switch (dev->internal_state) {
|
|
case DCF77_STATE_START:
|
|
DEBUG("[dcf77] EVENT START 1 !\n");
|
|
if ((xtimer_now_usec() - dev->startTime) >
|
|
DCF77_PULSE_START_HIGH_THRESHOLD_US) {
|
|
memset(&dev->bitseq.bits, 0, sizeof(dev->bitseq.bits));
|
|
dev->internal_state = DCF77_STATE_RX;
|
|
}
|
|
else {
|
|
dev->internal_state = DCF77_STATE_IDLE;
|
|
}
|
|
break;
|
|
case DCF77_STATE_RX:
|
|
DEBUG("[dcf77] EVENT RX 1 !\n");
|
|
dev->startTime = xtimer_now_usec();
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void _level_cb_low(dcf77_t *dev)
|
|
{
|
|
switch (dev->internal_state) {
|
|
case DCF77_STATE_IDLE:
|
|
DEBUG("[dcf77] EVENT IDLE 0 !\n");
|
|
dev->startTime = xtimer_now_usec();
|
|
dev->internal_state = DCF77_STATE_START;
|
|
break;
|
|
case DCF77_STATE_RX:
|
|
DEBUG("[dcf77] EVENT RX 0 !\n");
|
|
if ((xtimer_now_usec() - dev->startTime) >
|
|
DCF77_PULSE_WIDTH_THRESHOLD_US) {
|
|
dev->bitseq.bits |= 1ULL << dev->bitCounter;
|
|
}
|
|
|
|
dev->bitCounter++;
|
|
|
|
if (dev->bitCounter >= DCF77_READING_CYCLE) {
|
|
dev->bitCounter = 0;
|
|
dev->startTime = xtimer_now_usec();
|
|
dev->last_bitseq.bits = dev->bitseq.bits;
|
|
dev->internal_state = DCF77_STATE_START;
|
|
|
|
if (dev->tick_cb) {
|
|
dev->tick_cb(dev, dev->tick_cb_args);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void _level_cb(void *arg)
|
|
{
|
|
dcf77_t *dev = (dcf77_t *)arg;
|
|
|
|
if (gpio_read(dev->params.pin)) {
|
|
_level_cb_high(dev);
|
|
}
|
|
else {
|
|
_level_cb_low(dev);
|
|
}
|
|
}
|
|
|
|
int dcf77_init(dcf77_t *dev, const dcf77_params_t *params)
|
|
{
|
|
DEBUG("dcf77_init\n");
|
|
|
|
/* check parameters and configuration */
|
|
assert(dev && params);
|
|
dev->tick_cb = NULL;
|
|
dev->params = *params;
|
|
dev->internal_state = DCF77_STATE_IDLE;
|
|
dev->bitCounter = 0;
|
|
if (!gpio_init_int(dev->params.pin, dev->params.in_mode, GPIO_BOTH,
|
|
_level_cb, dev)) {
|
|
return DCF77_OK;
|
|
}
|
|
else {
|
|
return DCF77_INIT_ERROR;
|
|
}
|
|
}
|
|
|
|
int dcf77_get_time(dcf77_t *dev, struct tm *time)
|
|
{
|
|
assert(dev);
|
|
|
|
if (dev->last_bitseq.val.mesz == 2) {
|
|
time->tm_isdst = 1;
|
|
}
|
|
else {
|
|
time->tm_isdst = 0;
|
|
}
|
|
|
|
uint8_t minute = 10 * dev->last_bitseq.val.minute_h +
|
|
dev->last_bitseq.val.minute_l;
|
|
if (__builtin_parity((dev->last_bitseq.bits >> DCF77_MINUTE_SHIFT) &
|
|
(DCF77_MINUTE_MASK >> DCF77_MINUTE_SHIFT)) !=
|
|
dev->last_bitseq.val.minute_par) {
|
|
return DCF77_NOCSUM;
|
|
}
|
|
|
|
uint8_t hour = 10 * dev->last_bitseq.val.hour_h +
|
|
dev->last_bitseq.val.hour_l;
|
|
if (__builtin_parity((dev->last_bitseq.bits >> DCF77_HOUR_SHIFT) &
|
|
(DCF77_HOUR_MASK >> DCF77_HOUR_SHIFT)) !=
|
|
dev->last_bitseq.val.hour_par) {
|
|
return DCF77_NOCSUM;
|
|
}
|
|
|
|
uint8_t mday = 10 * dev->last_bitseq.val.day_h + dev->last_bitseq.val.day_l;
|
|
|
|
uint8_t wday = dev->last_bitseq.val.wday;
|
|
|
|
uint8_t month = 10 * dev->last_bitseq.val.month_h +
|
|
dev->last_bitseq.val.month_l;
|
|
|
|
uint8_t year = 10 * dev->last_bitseq.val.year_h +
|
|
dev->last_bitseq.val.year_l;
|
|
if (__builtin_parity((dev->last_bitseq.bits >> DCF77_DATE_SHIFT) &
|
|
(DCF77_DATE_MASK >> DCF77_DATE_SHIFT)) !=
|
|
dev->last_bitseq.val.date_par) {
|
|
return DCF77_NOCSUM;
|
|
}
|
|
|
|
time->tm_sec = 0;
|
|
time->tm_min = minute;
|
|
time->tm_hour = hour;
|
|
time->tm_mday = mday;
|
|
time->tm_wday = wday;
|
|
time->tm_mon = month - 1;
|
|
time->tm_year = 100 + year;
|
|
|
|
return DCF77_OK;
|
|
}
|
|
|
|
void dcf77_set_tick_cb(dcf77_t *dev, dcf77_tick_cb_t cb, void *arg)
|
|
{
|
|
assert(dev);
|
|
|
|
dev->tick_cb_args = arg;
|
|
dev->tick_cb = cb;
|
|
}
|