Data Structures | Defines | Functions

clock.c File Reference

wall clock More...

#include "config.h"
#include <stdio.h>
#include <avr/pgmspace.h>
#include <clock.h>
#include <rtc.h>

Data Structures

struct  adjbuf_s
 adjustment buffer

Defines

#define ADJ_BUFFER_SIZE   (1)
 number of entries in adjustment buffer

Functions

void clock_adjust (uint16_t ticks, uint8_t t2_val, clock_adj_source_t src, const clock_time_t *time)
 post adjustment to clock
clock_status_t clock_get_time (clock_time_t *time)
 get current time (UTC)

Detailed Description

wall clock

For a short explanation, see Time Handling.


Function Documentation

void clock_adjust ( uint16_t  ticks,
uint8_t  t2_val,
clock_adj_source_t  src,
const clock_time_t time 
)

post adjustment to clock

The current implementation records only the last adjustment values.

{
  if (ADJ_BUFFER_SIZE >= 1) {
    hl_time_t curr_time = hl_get_current_time ();
    if (curr_time.ticks < ticks)
      /* there was a wrap-around, computation is too complicated
       * here at the moment */
      return;

    /* just store it away */
    adjust_buffer[0].uptime.seconds = curr_time.seconds;
    adjust_buffer[0].uptime.ticks = ticks;
    adjust_buffer[0].uptime.t2_val = t2_val;
    adjust_buffer[0].walltime.time = *time;
    adjust_buffer[0].source = src;
  }
}

clock_status_t clock_get_time ( clock_time_t time  ) 

get current time (UTC)

Todo:
sub-second resolution

{
  clock_status_t retval = {
    .is_set = 0,
    .valid_time = 0, .valid_date = 0, .valid_century = 0,
  };
  if (ADJ_BUFFER_SIZE >= 1) {
#ifdef DEBUG
    printf_P (PSTR("last seconds=%ld tick=%d\r\n"),
              adjust_buffer[0].uptime.seconds,
              adjust_buffer[0].uptime.ticks);
#endif

    if (adjust_buffer[0].uptime.ticks || adjust_buffer[0].uptime.seconds) {
      /* clock_adjust() has already been called, so we can return data */
      struct adjbuf_s * buf = &adjust_buffer[0];

      retval.is_set = 1;
      retval.valid_time = 1;
      retval.valid_date = buf->walltime.time.day && buf->walltime.time.month;
      retval.valid_century = buf->walltime.time.year >= 100;

      if (time) {
        /* The caller has requested to get the data and not just the status */
        hl_time_t curr_time = hl_get_current_time ();
        /* time elapsed since last call to clock_adjust(),
         * will be (very) near 0 when GPS reception is OK. */
        int32_t offset = curr_time.seconds - buf->uptime.seconds;
        ldiv_t d;

#ifdef DEBUG
        printf_P (PSTR("time offset=%ld\r\n"), offset);
#endif

        /* if we did not reach the saved tick value, the real second
         * tick did not occur yet */
        if (curr_time.ticks < buf->uptime.ticks) {
          offset--;
        }

        *time = buf->walltime.time;
        if (offset == 0) goto out;

        /* do corrections */
        /* seconds */
        d = ldiv(offset + buf->walltime.time.sec, 60L);
        time->sec = d.rem;
        offset = d.quot;
        if (offset == 0) goto out;

        /* minutes */
        d = ldiv(offset + buf->walltime.time.min, 60L);
        time->min = d.rem;
        offset = d.quot;
        if (offset == 0) goto out;
        
        /* hours */
        d = ldiv(offset + buf->walltime.time.hour, 24L);
        time->hour = d.rem;
        offset = d.quot;

        /* now offset is in days
         * --- we don't expect a very long time between adjustments */
        while (offset) {
          uint8_t mdays = month_days (time->year, time->month);
          if (offset > (int8_t)(mdays - time->day)) {
            /* advance to first day of next month */
            offset -= mdays - time->day + 1;
            time->day = 1;
            if (++time->month > 12) {
              time->month = 1;
              time->year++;
            }
          } else {
            time->day += offset;
            offset = 0;
          }
        }

      out:;
        /* now offset is 0, so *time contains the current time */

#ifdef DEBUG
        printf_P (PSTR("%04u-%02u-%02u %02u:%02u:%02u\r\n"),
                  time->year, time->month, time->day,
                  time->hour, time->min, time->sec);
#endif

      }
    }
  }
  return retval;
}