1+ /***************************************************************************/ /**
2+ * @file no_os_gnss.c
3+ * @brief Implementation of GNSS Interface
4+ * @author Radu Etz ([email protected] ) 5+ ********************************************************************************
6+ * Copyright 2025(c) Analog Devices, Inc.
7+ *
8+ * Redistribution and use in source and binary forms, with or without
9+ * modification, are permitted provided that the following conditions are met:
10+ *
11+ * 1. Redistributions of source code must retain the above copyright notice,
12+ * this list of conditions and the following disclaimer.
13+ *
14+ * 2. Redistributions in binary form must reproduce the above copyright notice,
15+ * this list of conditions and the following disclaimer in the documentation
16+ * and/or other materials provided with the distribution.
17+ *
18+ * 3. Neither the name of Analog Devices, Inc. nor the names of its
19+ * contributors may be used to endorse or promote products derived from this
20+ * software without specific prior written permission.
21+ *
22+ * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. "AS IS" AND ANY EXPRESS OR
23+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
25+ * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
26+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
28+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
31+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32+ *******************************************************************************/
33+
34+ #include <stdlib.h>
35+ #include <errno.h>
36+ #include "no_os_gnss.h"
37+ #include "no_os_alloc.h"
38+ #include "no_os_mutex.h"
39+
40+ /* Forward declarations of ublox platform operations */
41+ static int32_t ublox_gnss_platform_init (struct no_os_gnss_desc * * desc ,
42+ const struct no_os_gnss_init_param * param );
43+ static int32_t ublox_gnss_platform_refresh_timing_data (
44+ struct no_os_gnss_desc * desc );
45+ static int32_t ublox_gnss_platform_is_timing_valid (struct no_os_gnss_desc * desc ,
46+ bool * valid );
47+ static int32_t ublox_gnss_platform_get_unified_timing (
48+ struct no_os_gnss_desc * desc ,
49+ struct gnss_precise_time * timing );
50+ static uint32_t ublox_gnss_platform_get_unix_epoch_unified (
51+ struct no_os_gnss_desc * desc ,
52+ uint32_t * fractional_seconds );
53+ static int32_t ublox_gnss_platform_get_position_data (
54+ struct no_os_gnss_desc * desc ,
55+ struct gnss_nmea_position * position_data );
56+ static int32_t ublox_gnss_platform_remove (struct no_os_gnss_desc * desc );
57+
58+ /**
59+ * @brief Platform operations structure for ublox GNSS devices
60+ */
61+ const struct no_os_gnss_platform_ops ublox_gnss_ops = {
62+ .init = ublox_gnss_platform_init ,
63+ .refresh_timing_data = ublox_gnss_platform_refresh_timing_data ,
64+ .is_timing_valid = ublox_gnss_platform_is_timing_valid ,
65+ .get_unified_timing = ublox_gnss_platform_get_unified_timing ,
66+ .get_unix_epoch_unified = ublox_gnss_platform_get_unix_epoch_unified ,
67+ .get_position_data = ublox_gnss_platform_get_position_data ,
68+ .remove = ublox_gnss_platform_remove
69+ };
70+
71+ /**
72+ * @brief Initialize ublox GNSS platform device
73+ */
74+ static int32_t ublox_gnss_platform_init (struct no_os_gnss_desc * * desc ,
75+ const struct no_os_gnss_init_param * param )
76+ {
77+ struct no_os_gnss_desc * gnss_desc ;
78+ struct gnss_dev * gnss_dev ;
79+ struct gnss_init_param gnss_init_param ;
80+ int32_t ret ;
81+
82+ if (!desc || !param )
83+ return - EINVAL ;
84+
85+ gnss_desc = (struct no_os_gnss_desc * )no_os_calloc (1 , sizeof (* gnss_desc ));
86+ if (!gnss_desc )
87+ return - ENOMEM ;
88+
89+ /* Copy and modify the gnss_init_param with PPS settings */
90+ gnss_init_param = param -> gnss_init_param ;
91+ gnss_init_param .pps_enable = param -> pps_config .pps_enable ;
92+ gnss_init_param .pps_frequency = param -> pps_config .frequency ;
93+ gnss_init_param .pps_pulse_length = param -> pps_config .pulse_length ;
94+
95+ /* Initialize underlying ublox_gnss driver */
96+ ret = gnss_init (& gnss_dev , gnss_init_param );
97+ if (ret ) {
98+ no_os_free (gnss_desc );
99+ return ret ;
100+ }
101+
102+ /* Set up the descriptor */
103+ gnss_desc -> device_id = param -> device_id ;
104+ gnss_desc -> gnss_device = gnss_dev ;
105+ gnss_desc -> platform_ops = param -> platform_ops ;
106+ gnss_desc -> extra = param -> extra ;
107+
108+ /* Initialize the PPS output */
109+ ret = gnss_init_pps (gnss_desc -> gnss_device , true);
110+ if (ret ) {
111+ no_os_free (gnss_desc );
112+ return ret ;
113+ }
114+
115+ /* Initialize mutex if needed */
116+ no_os_mutex_init (& gnss_desc -> mutex );
117+
118+ * desc = gnss_desc ;
119+
120+ return 0 ;
121+ }
122+
123+ /**
124+ * @brief Refresh timing data from ublox GNSS device
125+ */
126+ static int32_t ublox_gnss_platform_refresh_timing_data (
127+ struct no_os_gnss_desc * desc )
128+ {
129+ if (!desc || !desc -> gnss_device )
130+ return - EINVAL ;
131+
132+ return gnss_refresh_timing_data (desc -> gnss_device );
133+ }
134+
135+ /**
136+ * @brief Check if timing data is valid for ublox GNSS device
137+ */
138+ static int32_t ublox_gnss_platform_is_timing_valid (struct no_os_gnss_desc * desc ,
139+ bool * valid )
140+ {
141+ if (!desc || !desc -> gnss_device || !valid )
142+ return - EINVAL ;
143+
144+ * valid = gnss_is_timing_valid (desc -> gnss_device );
145+ return 0 ;
146+ }
147+
148+ /**
149+ * @brief Get unified timing from ublox GNSS device
150+ */
151+ static int32_t ublox_gnss_platform_get_unified_timing (
152+ struct no_os_gnss_desc * desc ,
153+ struct gnss_precise_time * timing )
154+ {
155+ if (!desc || !desc -> gnss_device || !timing )
156+ return - EINVAL ;
157+
158+ return gnss_get_unified_timing (desc -> gnss_device , timing );
159+ }
160+
161+ /**
162+ * @brief Get Unix epoch with unified precision from ublox GNSS device
163+ */
164+ static uint32_t ublox_gnss_platform_get_unix_epoch_unified (
165+ struct no_os_gnss_desc * desc ,
166+ uint32_t * fractional_seconds )
167+ {
168+ if (!desc || !desc -> gnss_device || !fractional_seconds )
169+ return 0 ;
170+
171+ return gnss_get_unix_epoch_unified (desc -> gnss_device , fractional_seconds );
172+ }
173+
174+ /**
175+ * @brief Remove ublox GNSS platform device
176+ */
177+ static int32_t ublox_gnss_platform_remove (struct no_os_gnss_desc * desc )
178+ {
179+ if (!desc )
180+ return - EINVAL ;
181+
182+ /* Remove underlying ublox_gnss device */
183+ if (desc -> gnss_device )
184+ gnss_remove (desc -> gnss_device );
185+
186+ /* Remove mutex */
187+ if (desc -> mutex )
188+ no_os_mutex_remove (desc -> mutex );
189+
190+ no_os_free (desc );
191+
192+ return 0 ;
193+ }
194+
195+ /* Public API Functions */
196+
197+ /**
198+ * @brief Initialize the GNSS communication peripheral.
199+ */
200+ int32_t no_os_gnss_init (struct no_os_gnss_desc * * desc ,
201+ const struct no_os_gnss_init_param * param )
202+ {
203+ if (!desc || !param || !param -> platform_ops )
204+ return - EINVAL ;
205+
206+ return param -> platform_ops -> init (desc , param );
207+ }
208+
209+ /**
210+ * @brief Free the resources allocated by no_os_gnss_init().
211+ */
212+ int32_t no_os_gnss_remove (struct no_os_gnss_desc * desc )
213+ {
214+ if (!desc || !desc -> platform_ops )
215+ return - EINVAL ;
216+
217+ return desc -> platform_ops -> remove (desc );
218+ }
219+
220+ /**
221+ * @brief Refresh timing data from GNSS device.
222+ */
223+ int32_t no_os_gnss_refresh_timing_data (struct no_os_gnss_desc * desc )
224+ {
225+ if (!desc || !desc -> platform_ops )
226+ return - EINVAL ;
227+
228+ return desc -> platform_ops -> refresh_timing_data (desc );
229+ }
230+
231+ /**
232+ * @brief Check if timing data is valid.
233+ */
234+ int32_t no_os_gnss_is_timing_valid (struct no_os_gnss_desc * desc , bool * valid )
235+ {
236+ if (!desc || !desc -> platform_ops || !valid )
237+ return - EINVAL ;
238+
239+ return desc -> platform_ops -> is_timing_valid (desc , valid );
240+ }
241+
242+ /**
243+ * @brief Get unified timing information with best available precision.
244+ */
245+ int32_t no_os_gnss_get_unified_timing (struct no_os_gnss_desc * desc ,
246+ struct gnss_precise_time * timing )
247+ {
248+ if (!desc || !desc -> platform_ops || !timing )
249+ return - EINVAL ;
250+
251+ return desc -> platform_ops -> get_unified_timing (desc , timing );
252+ }
253+
254+ /**
255+ * @brief Get Unix epoch timestamp with unified precision.
256+ */
257+ uint32_t no_os_gnss_get_unix_epoch_unified (struct no_os_gnss_desc * desc ,
258+ uint32_t * fractional_seconds )
259+ {
260+ if (!desc || !desc -> platform_ops || !fractional_seconds )
261+ return 0 ;
262+
263+ return desc -> platform_ops -> get_unix_epoch_unified (desc , fractional_seconds );
264+ }
265+
266+ /**
267+ * @brief Get position data from ublox GNSS device
268+ */
269+ static int32_t ublox_gnss_platform_get_position_data (
270+ struct no_os_gnss_desc * desc ,
271+ struct gnss_nmea_position * position_data )
272+ {
273+ if (!desc || !desc -> gnss_device || !position_data )
274+ return - EINVAL ;
275+
276+ return gnss_get_nmea_position_data (desc -> gnss_device , position_data );
277+ }
278+
279+ /**
280+ * @brief Get GPS position and fix quality data (NMEA-only devices).
281+ */
282+ int32_t no_os_gnss_get_position_data (struct no_os_gnss_desc * desc ,
283+ struct gnss_nmea_position * position_data )
284+ {
285+ if (!desc || !desc -> platform_ops || !position_data )
286+ return - EINVAL ;
287+
288+ return desc -> platform_ops -> get_position_data (desc , position_data );
289+ }
0 commit comments