Skip to content
This repository was archived by the owner on Apr 13, 2021. It is now read-only.

Commit c0c00b4

Browse files
committed
Merge pull request #330 from pmiettinen/i144-glonass-time
Add transformation of GLONASS-M current data information into gps_time_t
2 parents 29da613 + 2ed3e52 commit c0c00b4

File tree

3 files changed

+223
-3
lines changed

3 files changed

+223
-3
lines changed

include/libswiftnav/time.h

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,42 @@
1717

1818
#include <libswiftnav/common.h>
1919

20-
/** Number of seconds in a week. */
21-
#define WEEK_SECS (7*24*60*60)
20+
/** Number of days in a year. */
21+
#define YEAR_DAYS 365
22+
#define LEAP_YEAR_DAYS (YEAR_DAYS + 1)
23+
24+
/** Number of days in a week. */
25+
#define WEEK_DAYS 7
26+
27+
/** Number of months in a year. */
28+
#define YEAR_MONTHS 12
29+
30+
/** Days in (leap) year 1980 since GPS epoch Jan 6th */
31+
#define YEAR_1980_GPS_DAYS 361
32+
33+
/** Year of GPS epoch */
34+
#define GPS_EPOCH_YEAR 1980
35+
36+
/** UTC (SU) offset */
37+
#define UTC_SU_OFFSET 3
38+
39+
/** Number of seconds in a minute. */
40+
#define MINUTE_SECS 60
41+
42+
/** Number of minutes in an hour. */
43+
#define HOUR_MINUTES 60
44+
45+
/** Number of seconds in an hour. */
46+
#define HOUR_SECS (MINUTE_SECS * HOUR_MINUTES)
47+
48+
/** Number of hours in a day. */
49+
#define DAY_HOURS 24
2250

2351
/** Number of seconds in a day. */
24-
#define DAY_SECS (24*60*60)
52+
#define DAY_SECS (DAY_HOURS * HOUR_MINUTES * MINUTE_SECS)
53+
54+
/** Number of seconds in a week. */
55+
#define WEEK_SECS (WEEK_DAYS * DAY_SECS)
2556

2657
/** Number of rollovers in the 10-bit broadcast GPS week number.
2758
* Update on next rollover on April 7, 2019.
@@ -61,4 +92,11 @@ double gpsdifftime(const gps_time_t *end, const gps_time_t *beginning);
6192
void gps_time_match_weeks(gps_time_t *t, const gps_time_t *ref);
6293
u16 gps_adjust_week_cycle(u16 wn_raw, u16 wn_ref);
6394

95+
static inline bool is_leap_year(s32 year)
96+
{
97+
return ((year%4==0) && (year%100!=0)) || (year%400==0);
98+
}
99+
100+
gps_time_t glo_time2gps_time(u16 nt, u8 n4, s8 h, s8 m, s8 s);
101+
64102
#endif /* LIBSWIFTNAV_TIME_H */

src/time.c

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
1111
*/
1212

13+
#include <assert.h>
1314
#include <math.h>
15+
#include <stdio.h>
1416

1517
#include <libswiftnav/time.h>
1618
#include <libswiftnav/constants.h>
@@ -115,4 +117,72 @@ u16 gps_adjust_week_cycle(u16 wn_raw, u16 wn_ref)
115117
return wn_raw + 1024 * ((wn_ref + 1023 - wn_raw) / 1024);
116118
}
117119

120+
#define GLO_NT_0_FLOOR 1
121+
#define GLO_NT_0_CEILING LEAP_YEAR_DAYS /* 366 */
122+
#define GLO_NT_1_CEILING (GLO_NT_0_CEILING + YEAR_DAYS) /* 731 */
123+
#define GLO_NT_2_CEILING (GLO_NT_1_CEILING + YEAR_DAYS) /* 1096 */
124+
#define GLO_NT_3_CEILING (GLO_NT_2_CEILING + YEAR_DAYS) /* 1461 */
125+
126+
#define N4_MIN 1
127+
#define N4_MAX 31
128+
129+
/** Transformation of GLONASS-M current data information into gps_time_t.
130+
*
131+
* Reference: GLONASS ICD Edition 5.1 2008
132+
*
133+
* \param nt current date, calendar number of day within four-year interval
134+
* starting from the 1-st of January in a leap year
135+
* \param n4 four-year interval number starting from 1996
136+
* \param h hours part of tk field
137+
* \param m minutes part of tk field
138+
* \param s seconds part of tk field
139+
* |return converted gps time
140+
*/
141+
142+
gps_time_t glo_time2gps_time(u16 nt, u8 n4, s8 h, s8 m, s8 s)
143+
{
144+
u8 j = 0;
145+
u16 day_of_year = 0;
146+
u32 glo_year = 0;
147+
gps_time_t gps_t = {0, 0};
148+
149+
assert(n4 >= N4_MIN && n4 <= N4_MAX);
150+
151+
if (nt >= GLO_NT_0_FLOOR && nt <= GLO_NT_0_CEILING) {
152+
j = 1;
153+
day_of_year = nt;
154+
}
155+
else if (nt <= GLO_NT_1_CEILING) {
156+
j = 2;
157+
day_of_year = nt - LEAP_YEAR_DAYS;
158+
}
159+
else if (nt <= GLO_NT_2_CEILING) {
160+
j = 3;
161+
day_of_year = nt - LEAP_YEAR_DAYS - YEAR_DAYS;
162+
}
163+
else if (nt <= GLO_NT_3_CEILING) {
164+
j = 4;
165+
day_of_year = nt - LEAP_YEAR_DAYS - YEAR_DAYS * 2;
166+
}
167+
else
168+
assert(0 && "invalid nt");
169+
170+
glo_year = 1996 + 4 * (n4 - 1) + (j - 1);
171+
172+
/* Calculate days since GPS epoch */
173+
s64 days_gps_epoch = YEAR_1980_GPS_DAYS + day_of_year - 1;
174+
u32 y = GPS_EPOCH_YEAR;
175+
while (++y < glo_year) {
176+
days_gps_epoch += is_leap_year(y) ? LEAP_YEAR_DAYS : YEAR_DAYS;
177+
}
178+
179+
gps_t.wn = days_gps_epoch / WEEK_DAYS;
180+
gps_t.tow = GPS_MINUS_UTC_SECS + (days_gps_epoch % WEEK_DAYS) * DAY_SECS +
181+
(h - UTC_SU_OFFSET) * HOUR_SECS + m * MINUTE_SECS + s;
182+
183+
normalize_gps_time(&gps_t);
184+
185+
return gps_t;
186+
}
187+
118188
/** \} */

tests/check_time.c

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,116 @@ START_TEST(test_gps_adjust_week_cycle)
105105
}
106106
END_TEST
107107

108+
START_TEST(test_is_leap_year)
109+
{
110+
struct is_leap_year_testcase {
111+
u16 year;
112+
bool ret;
113+
} testcases[] = {
114+
{.year = 1900, .ret = false},
115+
{.year = 1901, .ret = false},
116+
{.year = 1904, .ret = true},
117+
{.year = 1980, .ret = true},
118+
{.year = 1981, .ret = false},
119+
{.year = 1982, .ret = false},
120+
{.year = 1983, .ret = false},
121+
{.year = 1984, .ret = true},
122+
{.year = 1985, .ret = false},
123+
{.year = 1986, .ret = false},
124+
{.year = 1987, .ret = false},
125+
{.year = 1988, .ret = true},
126+
{.year = 1989, .ret = false},
127+
{.year = 1990, .ret = false},
128+
{.year = 1991, .ret = false},
129+
{.year = 1992, .ret = true},
130+
{.year = 1993, .ret = false},
131+
{.year = 1994, .ret = false},
132+
{.year = 1995, .ret = false},
133+
{.year = 1996, .ret = true},
134+
{.year = 1997, .ret = false},
135+
{.year = 1998, .ret = false},
136+
{.year = 1999, .ret = false},
137+
{.year = 2000, .ret = true},
138+
{.year = 2001, .ret = false},
139+
{.year = 2002, .ret = false},
140+
{.year = 2003, .ret = false},
141+
{.year = 2004, .ret = true},
142+
{.year = 2005, .ret = false},
143+
{.year = 2006, .ret = false},
144+
{.year = 2007, .ret = false},
145+
{.year = 2008, .ret = true},
146+
{.year = 2009, .ret = false},
147+
{.year = 2010, .ret = false},
148+
{.year = 2011, .ret = false},
149+
{.year = 2012, .ret = true},
150+
{.year = 2013, .ret = false},
151+
{.year = 2014, .ret = false},
152+
{.year = 2015, .ret = false},
153+
{.year = 2016, .ret = true},
154+
{.year = 2017, .ret = false},
155+
{.year = 2018, .ret = false},
156+
{.year = 2019, .ret = false},
157+
{.year = 2020, .ret = true},
158+
};
159+
160+
for (size_t i = 0;
161+
i < sizeof(testcases) / sizeof(struct is_leap_year_testcase);
162+
i++) {
163+
fail_unless(is_leap_year(testcases[i].year) == testcases[i].ret,
164+
"is_leap_year test case %d failed, year = %d",
165+
testcases[i].year);
166+
}
167+
}
168+
END_TEST
169+
170+
START_TEST(test_glo_time2gps_time)
171+
{
172+
struct glo_time2gps_time_testcase {
173+
u16 nt;
174+
u8 n4;
175+
s8 h;
176+
s8 m;
177+
s8 s;
178+
gps_time_t ret;
179+
} testcases[] = {
180+
/* GLO time 29th Dec 2000 01:00:00 */
181+
{.nt = 364, .n4 = 2, .h = 1, .m = 0, .s = 0,
182+
.ret = {.wn = 1094, .tow = 424817}},
183+
/* GLO time 30th Dec 2000 01:00:00 */
184+
{.nt = 365, .n4 = 2, .h = 1, .m = 0, .s = 0,
185+
.ret = {.wn = 1094, .tow = 511217}},
186+
/* GLO time 31st Dec 2000 02:00:00 */
187+
{.nt = 366, .n4 = 2, .h = 2, .m = 0, .s = 0,
188+
.ret = {.wn = 1094, .tow = 601217}},
189+
/* GLO time 1st Jan 2001 02:00:00 */
190+
{.nt = 367, .n4 = 2, .h = 2, .m = 0, .s = 0,
191+
.ret = {.wn = 1095, .tow = 82817}},
192+
/* GLO time 2nd Jan 2001 02:00:00 */
193+
{.nt = 368, .n4 = 2, .h = 2, .m = 0, .s = 0,
194+
.ret = {.wn = 1095, .tow = 169217}},
195+
/* GLO time 31st Dec 2009 12:12:12 */
196+
{.nt = 731, .n4 = 4, .h = 12, .m = 12, .s = 12,
197+
.ret = {.wn = 1564, .tow = 378749}},
198+
/* GLO time 31st Dec 2010 12:12:12 */
199+
{.nt = 1096, .n4 = 4, .h = 12, .m = 12, .s = 12,
200+
.ret = {.wn = 1616, .tow = 465149}},
201+
/* GLO time 31st Dec 2011 12:12:12 */
202+
{.nt = 1461, .n4 = 4, .h = 12, .m = 12, .s = 12,
203+
.ret = {.wn = 1668, .tow = 551549}},
204+
};
205+
for (size_t i = 0;
206+
i < sizeof(testcases) / sizeof(struct glo_time2gps_time_testcase);
207+
i++) {
208+
gps_time_t ret = glo_time2gps_time(testcases[i].nt, testcases[i].n4,
209+
testcases[i].h, testcases[i].m,
210+
testcases[i].s);
211+
fail_unless(ret.wn == testcases[i].ret.wn &&
212+
ret.tow == testcases[i].ret.tow,
213+
"glo_time2gps_time test case %d failed, %d, %f", i, ret.wn, ret.tow);
214+
}
215+
}
216+
END_TEST
217+
108218
Suite* time_test_suite(void)
109219
{
110220
Suite *s = suite_create("Time handling");
@@ -114,6 +224,8 @@ Suite* time_test_suite(void)
114224
tcase_add_test(tc_core, test_normalize_gps_time);
115225
tcase_add_test(tc_core, test_gps_time_match_weeks);
116226
tcase_add_test(tc_core, test_gps_adjust_week_cycle);
227+
tcase_add_test(tc_core, test_is_leap_year);
228+
tcase_add_test(tc_core, test_glo_time2gps_time);
117229
suite_add_tcase(s, tc_core);
118230

119231
return s;

0 commit comments

Comments
 (0)