diff options
-rw-r--r-- | src/fsm/common.c | 119 | ||||
-rw-r--r-- | src/fsm/common.h | 24 | ||||
-rw-r--r-- | src/fsm/gps.c | 44 | ||||
-rw-r--r-- | src/fsm/gps.h | 21 | ||||
-rw-r--r-- | src/fsm/main.c | 35 |
5 files changed, 161 insertions, 82 deletions
diff --git a/src/fsm/common.c b/src/fsm/common.c index 953a015..27c792f 100644 --- a/src/fsm/common.c +++ b/src/fsm/common.c @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2015 Matthias P. Braendli + * Copyright (c) 2016 Matthias P. Braendli * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,6 +26,7 @@ #include "usart.h" #include "FreeRTOS.h" #include "timers.h" +#include "gps.h" #include <stm32f4xx.h> #include <time.h> @@ -38,6 +39,107 @@ static uint16_t lfsr; static void common_increase_timestamp(TimerHandle_t t); +int find_last_sunday(const struct tm* time) +{ + struct tm t = *time; + + // the last sunday can never be before the 20th + t.tm_mday = 20; + + int last_sunday = 1; + + while (t.tm_mon == time->tm_mon) { + t.tm_mday++; + if (mktime(&t) == (time_t)-1) { + // TODO error + return -1; + } + + const int sunday = 0; + if (t.tm_wday == sunday) { + last_sunday = t.tm_mday; + } + } + + return last_sunday; +} + +/* Calculate if we are in daylight saving time. + * return 0 if false + * 1 if true + * -1 in case of error + */ +static int is_dst(const struct tm *time) +{ + /* DST from 01:00 UTC on last Sunday in March + * to 01:00 UTC on last Sunday in October + */ + const int march = 2; + const int october = 9; + if (time->tm_mon < march) { + return 0; + } + else if (time->tm_mon == march) { + int last_sunday = find_last_sunday(time); + if (last_sunday == -1) return -1; + + if (time->tm_mday < last_sunday) { + return 0; + } + else if (time->tm_mday == last_sunday) { + return (time->tm_hour < 1) ? 0 : 1; + } + else { + return 1; + } + } + else if (time->tm_mon > march && time->tm_mon < october) { + return 1; + } + else if (time->tm_mon == october) { + int last_sunday = find_last_sunday(time); + if (last_sunday == -1) return -1; + + if (time->tm_mday < last_sunday) { + return 1; + } + else if (time->tm_mday == last_sunday) { + return (time->tm_hour < 1) ? 1 : 0; + } + else { + return 0; + } + } + else { + return 0; + } +} + +int local_time(struct tm *time) +{ + const int local_time_offset=1; // hours + + int valid = gps_utctime(time); + + if (valid) { + time->tm_hour += local_time_offset; + + if (is_dst(time)) { + time->tm_hour++; + time->tm_isdst = 1; + } + + // Let mktime fix the struct tm *time + if (mktime(time) == (time_t)-1) { + // TODO inform about failure + valid = 0; + } + } + + return valid; +} + + void common_init(void) { common_timer = xTimerCreate("Timer", @@ -62,21 +164,6 @@ uint64_t timestamp_now(void) return common_timestamp; } -int dayofweek(uint8_t day, uint8_t month, uint16_t year) -{ - /* Zeller's congruence for the Gregorian calendar. - * With 0=Monday, ... 5=Saturday, 6=Sunday - */ - if (month < 3) { - month += 12; - year--; - } - int k = year % 100; - int j = year / 100; - int h = day + 13*(month+1)/5 + k + k/4 + j/4 + 5*j; - return (h + 5) % 7 + 1; -} - // Return either 0 or 1, somewhat randomly int random_bool(void) diff --git a/src/fsm/common.h b/src/fsm/common.h index b283f03..80739cf 100644 --- a/src/fsm/common.h +++ b/src/fsm/common.h @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2015 Matthias P. Braendli + * Copyright (c) 2016 Matthias P. Braendli * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,31 +26,27 @@ * a random number */ -#include <stdint.h> +#pragma once -#ifndef _COMMON_H_ -#define _COMMON_H_ +#include <stdint.h> +#include <time.h> /* Feature defines */ #define ENABLE_PSK31 0 #define FLOAT_PI 3.1415926535897932384f - void common_init(void); // Return the current timestamp in milliseconds. Timestamps are monotonic, and not // wall clock time. uint64_t timestamp_now(void); -/* Convert date to day of week. - * day: 1-31 - * month: 1-12 - * year: 1900 to 3000 - * - * Returns 1=Monday, ... 6=Saturday, 7=Sunday - */ -int dayofweek(uint8_t day, uint8_t month, uint16_t year); +// Calculate local time from GPS time, including daylight saving time +// Return 1 on success, 0 on failure +// A call to this function will invalidate the information inside 'time' +// regardless of return value. +int local_time(struct tm *time); // Return either 0 or 1, somewhat randomly int random_bool(void); @@ -62,5 +58,3 @@ int random_bool(void); #define FAULT_SOURCE_USART 4 void trigger_fault(int source); -#endif // _COMMON_H_ - diff --git a/src/fsm/gps.c b/src/fsm/gps.c index 7b86f1c..ea3e597 100644 --- a/src/fsm/gps.c +++ b/src/fsm/gps.c @@ -35,7 +35,8 @@ TickType_t gps_timeutc_last_updated = 0; -static struct gps_time_s gps_timeutc; +static struct tm gps_timeutc; +static int gps_timeutc_valid; const TickType_t gps_data_validity_timeout = 10000ul / portTICK_PERIOD_MS; @@ -44,22 +45,23 @@ static void gps_task(void *pvParameters); SemaphoreHandle_t timeutc_semaphore; // Get current time from GPS -void gps_utctime(struct gps_time_s *timeutc) +int gps_utctime(struct tm *timeutc) { + int valid = 0; + xSemaphoreTake(timeutc_semaphore, portMAX_DELAY); if (xTaskGetTickCount() - gps_timeutc_last_updated < gps_data_validity_timeout) { - timeutc->year = gps_timeutc.year; - timeutc->month = gps_timeutc.month; - timeutc->day = gps_timeutc.day; - timeutc->hour = gps_timeutc.hour; - timeutc->min = gps_timeutc.min; - timeutc->sec = gps_timeutc.sec; - timeutc->valid = gps_timeutc.valid; - } - else { - timeutc->valid = 0; + timeutc->tm_year = gps_timeutc.tm_year; + timeutc->tm_mon = gps_timeutc.tm_mon; + timeutc->tm_mday = gps_timeutc.tm_mday; + timeutc->tm_hour = gps_timeutc.tm_hour; + timeutc->tm_min = gps_timeutc.tm_min; + timeutc->tm_sec = gps_timeutc.tm_sec; + valid = gps_timeutc_valid; } xSemaphoreGive(timeutc_semaphore); + + return valid; } #define RXBUF_LEN MAX_NMEA_SENTENCE_LEN @@ -81,14 +83,14 @@ static void gps_task(void *pvParameters) struct minmea_sentence_rmc frame; if (minmea_parse_rmc(&frame, rxbuf)) { xSemaphoreTake(timeutc_semaphore, portMAX_DELAY); + gps_timeutc.tm_year = 2000 + frame.date.year; + gps_timeutc.tm_mon = frame.date.month; + gps_timeutc.tm_mday = frame.date.day; + gps_timeutc.tm_hour = frame.time.hours; + gps_timeutc.tm_min = frame.time.minutes; + gps_timeutc.tm_sec = frame.time.seconds; + gps_timeutc_valid = frame.valid; gps_timeutc_last_updated = xTaskGetTickCount(); - gps_timeutc.year = 2000 + frame.date.year; - gps_timeutc.month = frame.date.month; - gps_timeutc.day = frame.date.day; - gps_timeutc.hour = frame.time.hours; - gps_timeutc.min = frame.time.minutes; - gps_timeutc.sec = frame.time.seconds; - gps_timeutc.valid = frame.valid; xSemaphoreGive(timeutc_semaphore); } } break; @@ -101,7 +103,7 @@ static void gps_task(void *pvParameters) void gps_init() { - gps_timeutc.valid = 0; + gps_timeutc_valid = 0; usart_gps_init(); @@ -127,7 +129,7 @@ void gps_init() int gps_locked() { if (xTaskGetTickCount() - gps_timeutc_last_updated < gps_data_validity_timeout) { - return gps_timeutc.valid; + return gps_timeutc_valid; } else { return 0; diff --git a/src/fsm/gps.h b/src/fsm/gps.h index b1f023a..3472237 100644 --- a/src/fsm/gps.h +++ b/src/fsm/gps.h @@ -22,10 +22,10 @@ * SOFTWARE. */ -#include <stdint.h> +#pragma once -#ifndef __GPS_H_ -#define __GPS_H_ +#include <stdint.h> +#include <time.h> /* Setup GPS receiver over USART and parse time */ @@ -34,16 +34,6 @@ * board RX to GPS TX on PD9 */ -struct gps_time_s { - uint16_t year; // Year, range 1999..2099 (UTC) - uint8_t month; // Month, range 1..12 (UTC) - uint8_t day; // Day of Month, range 1..31 (UTC) - uint8_t hour; // Hour of Day, range 0..23 (UTC) - uint8_t min; // Minute of Hour, range 0..59 (UTC) - uint8_t sec; // Seconds of Minute, range 0..59 (UTC) - uint8_t valid; // validity flag -}; - // Setup communication and GPS receiver void gps_init(); @@ -51,7 +41,6 @@ void gps_init(); int gps_locked(); // Get current time from GPS -void gps_utctime(struct gps_time_s *timeutc); - -#endif // __GPS_H_ +// Returns 1 if time is valid, 0 otherwise +int gps_utctime(struct tm *timeutc); diff --git a/src/fsm/main.c b/src/fsm/main.c index 94c15e0..1376b4b 100644 --- a/src/fsm/main.c +++ b/src/fsm/main.c @@ -266,7 +266,7 @@ static void audio_callback(void* context, int select_buffer) ProvideAudioBufferWithoutBlocking(samples, samples_len); } -static struct gps_time_s gps_time; +static struct tm gps_time; static void gps_monit_task(void *pvParameters) { GPIO_SetBits(GPIOD, GPIOD_BOARD_LED_BLUE); @@ -274,27 +274,34 @@ static void gps_monit_task(void *pvParameters) int t_gps_print_latch = 0; while (1) { - if (gps_locked()) { + struct tm time; + int time_valid = local_time(&time); - gps_utctime(&gps_time); - - if (gps_time.sec % 4 >= 2) { + if (time_valid) { + if (time.tm_sec % 4 >= 2) { GPIO_SetBits(GPIOD, GPIOD_BOARD_LED_BLUE); } else { GPIO_ResetBits(GPIOD, GPIOD_BOARD_LED_BLUE); } - if (gps_time.sec % 30 == 0 && t_gps_print_latch == 0) { - usart_debug("T_GPS %04d-%02d-%02d %02d:%02d:%02d\r\n", - gps_time.year, gps_time.month, gps_time.day, - gps_time.hour, gps_time.min, gps_time.sec); + } - t_gps_print_latch = 1; - } - if (gps_time.sec % 30 > 0) { - t_gps_print_latch = 0; - } + gps_utctime(&gps_time); + + if (gps_time.tm_sec % 30 == 0 && t_gps_print_latch == 0) { + usart_debug("T_GPS %04d-%02d-%02d %02d:%02d:%02d\r\n", + gps_time.tm_year, gps_time.tm_mon, gps_time.tm_mday, + gps_time.tm_hour, gps_time.tm_min, gps_time.tm_sec); + + usart_debug("TIME %04d-%02d-%02d %02d:%02d:%02d\r\n", + time.tm_year, time.tm_mon, time.tm_mday, + time.tm_hour, time.tm_min, time.tm_sec); + + t_gps_print_latch = 1; + } + if (gps_time.tm_sec % 30 > 0) { + t_gps_print_latch = 0; } vTaskDelay(100 / portTICK_RATE_MS); |