1 /*
2  * Copyright (c) 2023 Trackunit Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file gnss.h
9  * @brief Public GNSS API.
10  */
11 
12 #ifndef ZEPHYR_INCLUDE_DRIVERS_GNSS_H_
13 #define ZEPHYR_INCLUDE_DRIVERS_GNSS_H_
14 
15 /**
16  * @brief GNSS Interface
17  * @defgroup gnss_interface GNSS Interface
18  * @since 3.6
19  * @version 0.1.0
20  * @ingroup io_interfaces
21  * @{
22  */
23 
24 #include <zephyr/kernel.h>
25 #include <zephyr/types.h>
26 #include <zephyr/device.h>
27 #include <zephyr/data/navigation.h>
28 #include <errno.h>
29 
30 #ifdef __cplusplus
31 extern "C" {
32 #endif
33 
34 /** GNSS PPS modes */
35 enum gnss_pps_mode {
36 	/** PPS output disabled */
37 	GNSS_PPS_MODE_DISABLED = 0,
38 	/** PPS output always enabled */
39 	GNSS_PPS_MODE_ENABLED = 1,
40 	/** PPS output enabled from first lock */
41 	GNSS_PPS_MODE_ENABLED_AFTER_LOCK = 2,
42 	/** PPS output enabled while locked */
43 	GNSS_PPS_MODE_ENABLED_WHILE_LOCKED = 3
44 };
45 
46 /** API for setting fix rate */
47 typedef int (*gnss_set_fix_rate_t)(const struct device *dev, uint32_t fix_interval_ms);
48 
49 /** API for getting fix rate */
50 typedef int (*gnss_get_fix_rate_t)(const struct device *dev, uint32_t *fix_interval_ms);
51 
52 /** GNSS navigation modes */
53 enum gnss_navigation_mode {
54 	/** Dynamics have no impact on tracking */
55 	GNSS_NAVIGATION_MODE_ZERO_DYNAMICS = 0,
56 	/** Low dynamics have higher impact on tracking */
57 	GNSS_NAVIGATION_MODE_LOW_DYNAMICS = 1,
58 	/** Low and high dynamics have equal impact on tracking */
59 	GNSS_NAVIGATION_MODE_BALANCED_DYNAMICS = 2,
60 	/** High dynamics have higher impact on tracking */
61 	GNSS_NAVIGATION_MODE_HIGH_DYNAMICS = 3
62 };
63 
64 /** API for setting navigation mode */
65 typedef int (*gnss_set_navigation_mode_t)(const struct device *dev,
66 					  enum gnss_navigation_mode mode);
67 
68 /** API for getting navigation mode */
69 typedef int (*gnss_get_navigation_mode_t)(const struct device *dev,
70 					  enum gnss_navigation_mode *mode);
71 
72 /** Systems contained in gnss_systems_t */
73 enum gnss_system {
74 	/** Global Positioning System (GPS) */
75 	GNSS_SYSTEM_GPS = BIT(0),
76 	/** GLObal NAvigation Satellite System (GLONASS) */
77 	GNSS_SYSTEM_GLONASS = BIT(1),
78 	/** Galileo */
79 	GNSS_SYSTEM_GALILEO = BIT(2),
80 	/** BeiDou Navigation Satellite System */
81 	GNSS_SYSTEM_BEIDOU = BIT(3),
82 	/** Quasi-Zenith Satellite System (QZSS) */
83 	GNSS_SYSTEM_QZSS = BIT(4),
84 	/** Indian Regional Navigation Satellite System (IRNSS) */
85 	GNSS_SYSTEM_IRNSS = BIT(5),
86 	/** Satellite-Based Augmentation System (SBAS) */
87 	GNSS_SYSTEM_SBAS = BIT(6),
88 	/** Indoor Messaging System (IMES) */
89 	GNSS_SYSTEM_IMES = BIT(7),
90 };
91 
92 /** Type storing bitmask of GNSS systems */
93 typedef uint32_t gnss_systems_t;
94 
95 /** API for enabling systems */
96 typedef int (*gnss_set_enabled_systems_t)(const struct device *dev, gnss_systems_t systems);
97 
98 /** API for getting enabled systems */
99 typedef int (*gnss_get_enabled_systems_t)(const struct device *dev, gnss_systems_t *systems);
100 
101 /** API for getting enabled systems */
102 typedef int (*gnss_get_supported_systems_t)(const struct device *dev, gnss_systems_t *systems);
103 
104 /** API for getting timestamp of last PPS pulse */
105 typedef int (*gnss_get_latest_timepulse_t)(const struct device *dev, k_ticks_t *timestamp);
106 
107 /** GNSS fix status */
108 enum gnss_fix_status {
109 	/** No GNSS fix acquired */
110 	GNSS_FIX_STATUS_NO_FIX = 0,
111 	/** GNSS fix acquired */
112 	GNSS_FIX_STATUS_GNSS_FIX = 1,
113 	/** Differential GNSS fix acquired */
114 	GNSS_FIX_STATUS_DGNSS_FIX = 2,
115 	/** Estimated fix acquired */
116 	GNSS_FIX_STATUS_ESTIMATED_FIX = 3,
117 };
118 
119 /** GNSS fix quality */
120 enum gnss_fix_quality {
121 	/** Invalid fix */
122 	GNSS_FIX_QUALITY_INVALID = 0,
123 	/** Standard positioning service */
124 	GNSS_FIX_QUALITY_GNSS_SPS = 1,
125 	/** Differential GNSS */
126 	GNSS_FIX_QUALITY_DGNSS = 2,
127 	/** Precise positioning service */
128 	GNSS_FIX_QUALITY_GNSS_PPS = 3,
129 	/** Real-time kinematic */
130 	GNSS_FIX_QUALITY_RTK = 4,
131 	/** Floating real-time kinematic */
132 	GNSS_FIX_QUALITY_FLOAT_RTK = 5,
133 	/** Estimated fix */
134 	GNSS_FIX_QUALITY_ESTIMATED = 6,
135 };
136 
137 /** GNSS info data structure */
138 struct gnss_info {
139 	/** Number of satellites being tracked */
140 	uint16_t satellites_cnt;
141 	/** Horizontal dilution of precision in 1/1000 */
142 	uint32_t hdop;
143 	/** Geoid separation in millimeters */
144 	int32_t geoid_separation;
145 	/** The fix status */
146 	enum gnss_fix_status fix_status;
147 	/** The fix quality */
148 	enum gnss_fix_quality fix_quality;
149 };
150 
151 /** GNSS time data structure */
152 struct gnss_time {
153 	/** Hour [0, 23] */
154 	uint8_t hour;
155 	/** Minute [0, 59] */
156 	uint8_t minute;
157 	/** Millisecond [0, 60999] */
158 	uint16_t millisecond;
159 	/** Day of month [1, 31] */
160 	uint8_t month_day;
161 	/** Month [1, 12] */
162 	uint8_t month;
163 	/** Year [0, 99] */
164 	uint8_t century_year;
165 };
166 
167 /** GNSS API structure */
168 __subsystem struct gnss_driver_api {
169 	gnss_set_fix_rate_t set_fix_rate;
170 	gnss_get_fix_rate_t get_fix_rate;
171 	gnss_set_navigation_mode_t set_navigation_mode;
172 	gnss_get_navigation_mode_t get_navigation_mode;
173 	gnss_set_enabled_systems_t set_enabled_systems;
174 	gnss_get_enabled_systems_t get_enabled_systems;
175 	gnss_get_supported_systems_t get_supported_systems;
176 	gnss_get_latest_timepulse_t get_latest_timepulse;
177 };
178 
179 /** GNSS data structure */
180 struct gnss_data {
181 	/** Navigation data acquired */
182 	struct navigation_data nav_data;
183 	/** GNSS info when navigation data was acquired */
184 	struct gnss_info info;
185 	/** UTC time when data was acquired */
186 	struct gnss_time utc;
187 };
188 
189 /** Template for GNSS data callback */
190 typedef void (*gnss_data_callback_t)(const struct device *dev, const struct gnss_data *data);
191 
192 /** GNSS callback structure */
193 struct gnss_data_callback {
194 	/** Filter callback to GNSS data from this device if not NULL */
195 	const struct device *dev;
196 	/** Callback called when GNSS data is published */
197 	gnss_data_callback_t callback;
198 };
199 
200 /** GNSS satellite structure */
201 struct gnss_satellite {
202 	/** Pseudo-random noise sequence */
203 	uint8_t prn;
204 	/** Signal-to-noise ratio in dB */
205 	uint8_t snr;
206 	/** Elevation in degrees [0, 90] */
207 	uint8_t elevation;
208 	/** Azimuth relative to True North in degrees [0, 359] */
209 	uint16_t azimuth;
210 	/** System of satellite */
211 	enum gnss_system system;
212 	/** True if satellite is being tracked */
213 	uint8_t is_tracked : 1;
214 };
215 
216 /** Template for GNSS satellites callback */
217 typedef void (*gnss_satellites_callback_t)(const struct device *dev,
218 					   const struct gnss_satellite *satellites,
219 					   uint16_t size);
220 
221 /** GNSS callback structure */
222 struct gnss_satellites_callback {
223 	/** Filter callback to GNSS data from this device if not NULL */
224 	const struct device *dev;
225 	/** Callback called when GNSS satellites is published */
226 	gnss_satellites_callback_t callback;
227 };
228 
229 /**
230  * @brief Set the GNSS fix rate
231  *
232  * @param dev Device instance
233  * @param fix_interval_ms Fix interval to set in milliseconds
234  *
235  * @return 0 if successful
236  * @return -errno negative errno code on failure
237  */
238 __syscall int gnss_set_fix_rate(const struct device *dev, uint32_t fix_interval_ms);
239 
z_impl_gnss_set_fix_rate(const struct device * dev,uint32_t fix_interval_ms)240 static inline int z_impl_gnss_set_fix_rate(const struct device *dev, uint32_t fix_interval_ms)
241 {
242 	const struct gnss_driver_api *api = (const struct gnss_driver_api *)dev->api;
243 
244 	if (api->set_fix_rate == NULL) {
245 		return -ENOSYS;
246 	}
247 
248 	return api->set_fix_rate(dev, fix_interval_ms);
249 }
250 
251 /**
252  * @brief Get the GNSS fix rate
253  *
254  * @param dev Device instance
255  * @param fix_interval_ms Destination for fix interval in milliseconds
256  *
257  * @return 0 if successful
258  * @return -errno negative errno code on failure
259  */
260 __syscall int gnss_get_fix_rate(const struct device *dev, uint32_t *fix_interval_ms);
261 
z_impl_gnss_get_fix_rate(const struct device * dev,uint32_t * fix_interval_ms)262 static inline int z_impl_gnss_get_fix_rate(const struct device *dev, uint32_t *fix_interval_ms)
263 {
264 	const struct gnss_driver_api *api = (const struct gnss_driver_api *)dev->api;
265 
266 	if (api->get_fix_rate == NULL) {
267 		return -ENOSYS;
268 	}
269 
270 	return api->get_fix_rate(dev, fix_interval_ms);
271 }
272 
273 /**
274  * @brief Set the GNSS navigation mode
275  *
276  * @param dev Device instance
277  * @param mode Navigation mode to set
278  *
279  * @return 0 if successful
280  * @return -errno negative errno code on failure
281  */
282 __syscall int gnss_set_navigation_mode(const struct device *dev,
283 				       enum gnss_navigation_mode mode);
284 
z_impl_gnss_set_navigation_mode(const struct device * dev,enum gnss_navigation_mode mode)285 static inline int z_impl_gnss_set_navigation_mode(const struct device *dev,
286 						  enum gnss_navigation_mode mode)
287 {
288 	const struct gnss_driver_api *api = (const struct gnss_driver_api *)dev->api;
289 
290 	if (api->set_navigation_mode == NULL) {
291 		return -ENOSYS;
292 	}
293 
294 	return api->set_navigation_mode(dev, mode);
295 }
296 
297 /**
298  * @brief Get the GNSS navigation mode
299  *
300  * @param dev Device instance
301  * @param mode Destination for navigation mode
302  *
303  * @return 0 if successful
304  * @return -errno negative errno code on failure
305  */
306 __syscall int gnss_get_navigation_mode(const struct device *dev,
307 				       enum gnss_navigation_mode *mode);
308 
z_impl_gnss_get_navigation_mode(const struct device * dev,enum gnss_navigation_mode * mode)309 static inline int z_impl_gnss_get_navigation_mode(const struct device *dev,
310 						  enum gnss_navigation_mode *mode)
311 {
312 	const struct gnss_driver_api *api = (const struct gnss_driver_api *)dev->api;
313 
314 	if (api->get_navigation_mode == NULL) {
315 		return -ENOSYS;
316 	}
317 
318 	return api->get_navigation_mode(dev, mode);
319 }
320 
321 /**
322  * @brief Set enabled GNSS systems
323  *
324  * @param dev Device instance
325  * @param systems Systems to enable
326  *
327  * @return 0 if successful
328  * @return -errno negative errno code on failure
329  */
330 __syscall int gnss_set_enabled_systems(const struct device *dev, gnss_systems_t systems);
331 
z_impl_gnss_set_enabled_systems(const struct device * dev,gnss_systems_t systems)332 static inline int z_impl_gnss_set_enabled_systems(const struct device *dev,
333 						  gnss_systems_t systems)
334 {
335 	const struct gnss_driver_api *api = (const struct gnss_driver_api *)dev->api;
336 
337 	if (api->set_enabled_systems == NULL) {
338 		return -ENOSYS;
339 	}
340 
341 	return api->set_enabled_systems(dev, systems);
342 }
343 
344 /**
345  * @brief Get enabled GNSS systems
346  *
347  * @param dev Device instance
348  * @param systems Destination for enabled systems
349  *
350  * @return 0 if successful
351  * @return -errno negative errno code on failure
352  */
353 __syscall int gnss_get_enabled_systems(const struct device *dev, gnss_systems_t *systems);
354 
z_impl_gnss_get_enabled_systems(const struct device * dev,gnss_systems_t * systems)355 static inline int z_impl_gnss_get_enabled_systems(const struct device *dev,
356 						  gnss_systems_t *systems)
357 {
358 	const struct gnss_driver_api *api = (const struct gnss_driver_api *)dev->api;
359 
360 	if (api->get_enabled_systems == NULL) {
361 		return -ENOSYS;
362 	}
363 
364 	return api->get_enabled_systems(dev, systems);
365 }
366 
367 /**
368  * @brief Get supported GNSS systems
369  *
370  * @param dev Device instance
371  * @param systems Destination for supported systems
372  *
373  * @return 0 if successful
374  * @return -errno negative errno code on failure
375  */
376 __syscall int gnss_get_supported_systems(const struct device *dev, gnss_systems_t *systems);
377 
z_impl_gnss_get_supported_systems(const struct device * dev,gnss_systems_t * systems)378 static inline int z_impl_gnss_get_supported_systems(const struct device *dev,
379 						    gnss_systems_t *systems)
380 {
381 	const struct gnss_driver_api *api = (const struct gnss_driver_api *)dev->api;
382 
383 	if (api->get_supported_systems == NULL) {
384 		return -ENOSYS;
385 	}
386 
387 	return api->get_supported_systems(dev, systems);
388 }
389 
390 /**
391  * @brief Get the timestamp of the latest PPS timepulse
392  *
393  * @note The timestamp is considered valid when the timepulse pin is actively toggling.
394  *
395  * @param dev Device instance
396  * @param timestamp Kernel tick count at the time of the PPS pulse
397  *
398  * @retval 0 if successful
399  * @retval -ENOSYS if driver does not support API
400  * @retval -ENOTSUP if driver does not have PPS pin connected
401  * @retval -EAGAIN if PPS pulse is not considered valid
402  */
403 __syscall int gnss_get_latest_timepulse(const struct device *dev, k_ticks_t *timestamp);
404 
z_impl_gnss_get_latest_timepulse(const struct device * dev,k_ticks_t * timestamp)405 static inline int z_impl_gnss_get_latest_timepulse(const struct device *dev,
406 						    k_ticks_t *timestamp)
407 {
408 	const struct gnss_driver_api *api = (const struct gnss_driver_api *)dev->api;
409 
410 	if (api->get_latest_timepulse == NULL) {
411 		return -ENOSYS;
412 	}
413 
414 	return api->get_latest_timepulse(dev, timestamp);
415 }
416 
417 /**
418  * @brief Register a callback structure for GNSS data published
419  *
420  * @param _dev Device pointer
421  * @param _callback The callback function
422  */
423 #if CONFIG_GNSS
424 #define GNSS_DATA_CALLBACK_DEFINE(_dev, _callback)                                              \
425 	static const STRUCT_SECTION_ITERABLE(gnss_data_callback,                                \
426 					     _gnss_data_callback__##_callback) = {              \
427 		.dev = _dev,                                                                    \
428 		.callback = _callback,                                                          \
429 	}
430 #else
431 #define GNSS_DATA_CALLBACK_DEFINE(_dev, _callback)
432 #endif
433 
434 /**
435  * @brief Register a callback structure for GNSS satellites published
436  *
437  * @param _dev Device pointer
438  * @param _callback The callback function
439  */
440 #if CONFIG_GNSS_SATELLITES
441 #define GNSS_SATELLITES_CALLBACK_DEFINE(_dev, _callback)                                        \
442 	static const STRUCT_SECTION_ITERABLE(gnss_satellites_callback,                          \
443 					     _gnss_satellites_callback__##_callback) = {        \
444 		.dev = _dev,                                                                    \
445 		.callback = _callback,                                                          \
446 	}
447 #else
448 #define GNSS_SATELLITES_CALLBACK_DEFINE(_dev, _callback)
449 #endif
450 
451 /**
452  * @}
453  */
454 
455 #ifdef __cplusplus
456 }
457 #endif
458 
459 #include <zephyr/syscalls/gnss.h>
460 
461 #endif /* ZEPHYR_INCLUDE_DRIVERS_GNSS_H_ */
462