aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2016-05-29 14:38:15 +0200
committerMatthias P. Braendli <matthias.braendli@mpb.li>2016-05-29 14:38:15 +0200
commit7d91c4db01385c22d4bd01b7fe180adacb6480b5 (patch)
tree359461ebde3b4a3de2680a2b8ebae88478cd5916
parent40d7fb0493e3e5746efb86f2abf2a8caf2e34a96 (diff)
downloadglutte-o-matic-7d91c4db01385c22d4bd01b7fe180adacb6480b5.tar.gz
glutte-o-matic-7d91c4db01385c22d4bd01b7fe180adacb6480b5.tar.bz2
glutte-o-matic-7d91c4db01385c22d4bd01b7fe180adacb6480b5.zip
Implement DST calculation
-rw-r--r--src/fsm/common.c119
-rw-r--r--src/fsm/common.h24
-rw-r--r--src/fsm/gps.c44
-rw-r--r--src/fsm/gps.h21
-rw-r--r--src/fsm/main.c35
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);