#ifndef DCFTIME_H
#define DCFTIME_H

/**
 * \file dcftime.h
 * \brief Decoder for DCF-77 time signals
 * \author Ronald Schaten & Thomas Stegemann
 * \version $Id: dcftime.h,v 1.1 2007/01/02 21:30:40 rschaten Exp $
 *
 * License: See documentation.
 */

#include "boole.h"

/*
  dcf-signal samples per second
*/
#ifndef DCF_RATE
#define DCF_RATE 200 /**< number of samples per second. dcf_signal() should be called this often */
#endif
#if (DCF_RATE < 100) || (250 < DCF_RATE)
#error DCF_RATE should be between 100 and 250
#endif

typedef unsigned int dcf_second;      /**< seconds (0-59) */
typedef unsigned int dcf_minute;      /**< minutes (0-59) */
typedef unsigned int dcf_hour;        /**< hours (0-24) */
typedef unsigned int dcf_dayofmonth;  /**< day of month (1-31) */
typedef unsigned int dcf_year;        /**< year (0-99) */
typedef boolean      dcf_is_dst;      /**< daylight saving: True: MESZ, False: MEZ */

/** definition of weekdays */
enum dcf_dayofweek_enum {
    dcf_monday = 1, /**< monday = 1 */
    dcf_tuesday, /**< tuesday */
    dcf_wednesday, /**< wednesday */
    dcf_thursday, /**< thursday */
    dcf_friday, /**< friday */
    dcf_saturday, /**< saturday */
    dcf_sunday, /**< sunday = 7 */
};
/** definition of weekdays */
typedef enum dcf_dayofweek_enum dcf_dayofweek;

/** definition of months */
enum dcf_month_enum {
    dcf_january = 1, /**< january = 1 */
    dcf_february, /**< february */
    dcf_march, /**< march */
    dcf_april, /**< april */
    dcf_may, /**< may */
    dcf_june, /**< june */
    dcf_july, /**< july */
    dcf_august, /**< august */
    dcf_september, /**< september */
    dcf_october, /**< october */
    dcf_november, /**< november */
    dcf_december /**< december = 12 */
};
/** definition of months */
typedef enum dcf_month_enum dcf_month;

/** format of the dcf_time */
struct dcf_time_struct {
    dcf_second second; /**< seconds */
    dcf_minute minute; /**< minutes */
    dcf_hour hour; /**< hours */
    dcf_is_dst is_dst; /**< daylight saving time */
};
/** definition of dcf_time */
typedef struct dcf_time_struct dcf_time;

/** format of the dcf_date */
struct dcf_date_struct {
    dcf_dayofweek dayofweek; /**< day of week */
    dcf_dayofmonth dayofmonth; /**< day of month */
    dcf_month month; /**< month */
    dcf_year year; /**< year */
};
/** definition of dcf_date */
typedef struct dcf_date_struct dcf_date;

/** format of the dcf_datetime */
struct dcf_datetime_struct {
    dcf_time time; /**< the time */
    dcf_date date; /**< the time */
    boolean is_valid; /**< if is_valid is False: no complete signal received, do not use date and times */
    boolean has_signal; /**< if has_signal is True: currently receiving signal */
};
/** definition of dcf_datetime */
typedef struct dcf_datetime_struct dcf_datetime;

/**
 * Initialize the DCF-module. Call dcf_init before any other DCF function.
 */
void dcf_init(void);

/**
 * Tell the DCF-module if the signal is high or low. This function decides if
 * the received bit is a long or a short one, and if it is usable at all. It
 * should be called regularly, the number of calls per second is defined in
 * DCF_RATE.
 * \param signal: True if the input signal is high, False if it is low.
 */
void dcf_signal(boolean signal);

/**
 * Fetch the current date and time.
 * \return The current date and time in a dcf_datetime structure
 */
dcf_datetime dcf_current_datetime(void);

/**
 * Get the name of the current weekday.
 * \param dow: Day of the current week. Monday = 1, tuesday = 2...
 * \return Pointer to the name
 */
const char* dcf_dayofweek_name(dcf_dayofweek dow);

/**
 * Get the name of the current daylight saving time (summertime, wintertime).
 * \param dst: daylight saving time bit from the time signal
 * \return Pointer to the name
 */
const char* dcf_is_dst_name(dcf_is_dst dst);

#endif
