1 /*
2  * Copyright (c) 2024 Trackunit Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #undef _POSIX_C_SOURCE
8 #define _POSIX_C_SOURCE 200809L /* Required for gmtime_r */
9 
10 #include <zephyr/drivers/gnss.h>
11 #include <zephyr/drivers/gnss/gnss_publish.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/pm/device.h>
14 #include <zephyr/pm/device_runtime.h>
15 
16 #include <string.h>
17 #include <time.h>
18 
19 #include <zephyr/logging/log.h>
20 LOG_MODULE_REGISTER(gnss_emul, CONFIG_GNSS_LOG_LEVEL);
21 
22 #define DT_DRV_COMPAT zephyr_gnss_emul
23 
24 #define GNSS_EMUL_DEFAULT_FIX_INTERVAL_MS      1000
25 #define GNSS_EMUL_MIN_FIX_INTERVAL_MS          100
26 #define GNSS_EMUL_FIX_ACQUIRE_TIME_MS          5000
27 #define GNSS_EMUL_DEFAULT_NAV_MODE             GNSS_NAVIGATION_MODE_BALANCED_DYNAMICS
28 #define GNSS_EMUL_SUPPORTED_SYSTEMS_MASK       0xFF
29 #define GNSS_EMUL_SUPPORTED_SYSTEMS_COUNT      8
30 #define GNSS_EMUL_DEFAULT_ENABLED_SYSTEMS_MASK GNSS_EMUL_SUPPORTED_SYSTEMS_MASK
31 
32 struct gnss_emul_data {
33 	const struct device *dev;
34 	struct k_work_delayable data_dwork;
35 	struct k_sem lock;
36 	int64_t resume_timestamp_ms;
37 	int64_t fix_timestamp_ms;
38 	uint32_t fix_interval_ms;
39 	enum gnss_navigation_mode nav_mode;
40 	gnss_systems_t enabled_systems;
41 	struct gnss_data data;
42 
43 #ifdef CONFIG_GNSS_SATELLITES
44 	struct gnss_satellite satellites[GNSS_EMUL_SUPPORTED_SYSTEMS_COUNT];
45 	uint8_t satellites_len;
46 #endif
47 };
48 
gnss_emul_lock_sem(const struct device * dev)49 static void gnss_emul_lock_sem(const struct device *dev)
50 {
51 	struct gnss_emul_data *data = dev->data;
52 
53 	(void)k_sem_take(&data->lock, K_FOREVER);
54 }
55 
gnss_emul_unlock_sem(const struct device * dev)56 static void gnss_emul_unlock_sem(const struct device *dev)
57 {
58 	struct gnss_emul_data *data = dev->data;
59 
60 	k_sem_give(&data->lock);
61 }
62 
gnss_emul_update_fix_timestamp(const struct device * dev,bool resuming)63 static void gnss_emul_update_fix_timestamp(const struct device *dev, bool resuming)
64 {
65 	struct gnss_emul_data *data = dev->data;
66 	int64_t uptime_ms;
67 
68 	uptime_ms = k_uptime_get();
69 	data->fix_timestamp_ms = ((uptime_ms / data->fix_interval_ms) + 1) * data->fix_interval_ms;
70 
71 	if (resuming) {
72 		data->resume_timestamp_ms = data->fix_timestamp_ms;
73 	}
74 }
75 
gnss_emul_fix_is_acquired(const struct device * dev)76 static bool gnss_emul_fix_is_acquired(const struct device *dev)
77 {
78 	struct gnss_emul_data *data = dev->data;
79 	int64_t time_since_resume;
80 
81 	time_since_resume = data->fix_timestamp_ms - data->resume_timestamp_ms;
82 	return time_since_resume >= GNSS_EMUL_FIX_ACQUIRE_TIME_MS;
83 }
84 
85 #ifdef CONFIG_PM_DEVICE
gnss_emul_clear_fix_timestamp(const struct device * dev)86 static void gnss_emul_clear_fix_timestamp(const struct device *dev)
87 {
88 	struct gnss_emul_data *data = dev->data;
89 
90 	data->fix_timestamp_ms = 0;
91 }
92 #endif
93 
gnss_emul_schedule_work(const struct device * dev)94 static void gnss_emul_schedule_work(const struct device *dev)
95 {
96 	struct gnss_emul_data *data = dev->data;
97 
98 	k_work_schedule(&data->data_dwork, K_TIMEOUT_ABS_MS(data->fix_timestamp_ms));
99 }
100 
gnss_emul_cancel_work(const struct device * dev)101 static bool gnss_emul_cancel_work(const struct device *dev)
102 {
103 	struct gnss_emul_data *data = dev->data;
104 	struct k_work_sync sync;
105 
106 	return k_work_cancel_delayable_sync(&data->data_dwork, &sync);
107 }
108 
gnss_emul_is_resumed(const struct device * dev)109 static bool gnss_emul_is_resumed(const struct device *dev)
110 {
111 	struct gnss_emul_data *data = dev->data;
112 
113 	return data->fix_timestamp_ms > 0;
114 }
115 
gnss_emul_lock(const struct device * dev)116 static void gnss_emul_lock(const struct device *dev)
117 {
118 	gnss_emul_lock_sem(dev);
119 	gnss_emul_cancel_work(dev);
120 }
121 
gnss_emul_unlock(const struct device * dev)122 static void gnss_emul_unlock(const struct device *dev)
123 {
124 	if (gnss_emul_is_resumed(dev)) {
125 		gnss_emul_schedule_work(dev);
126 	}
127 
128 	gnss_emul_unlock_sem(dev);
129 }
130 
gnss_emul_set_fix_rate(const struct device * dev,uint32_t fix_interval_ms)131 static int gnss_emul_set_fix_rate(const struct device *dev, uint32_t fix_interval_ms)
132 {
133 	struct gnss_emul_data *data = dev->data;
134 
135 	if (fix_interval_ms < GNSS_EMUL_MIN_FIX_INTERVAL_MS) {
136 		return -EINVAL;
137 	}
138 
139 	data->fix_interval_ms = fix_interval_ms;
140 	return 0;
141 }
142 
gnss_emul_get_fix_rate(const struct device * dev,uint32_t * fix_interval_ms)143 static int gnss_emul_get_fix_rate(const struct device *dev, uint32_t *fix_interval_ms)
144 {
145 	struct gnss_emul_data *data = dev->data;
146 
147 	*fix_interval_ms = data->fix_interval_ms;
148 	return 0;
149 }
150 
gnss_emul_set_navigation_mode(const struct device * dev,enum gnss_navigation_mode mode)151 static int gnss_emul_set_navigation_mode(const struct device *dev,
152 					 enum gnss_navigation_mode mode)
153 {
154 	struct gnss_emul_data *data = dev->data;
155 
156 	if (mode > GNSS_NAVIGATION_MODE_HIGH_DYNAMICS) {
157 		return -EINVAL;
158 	}
159 
160 	data->nav_mode = mode;
161 	return 0;
162 }
163 
gnss_emul_get_navigation_mode(const struct device * dev,enum gnss_navigation_mode * mode)164 static int gnss_emul_get_navigation_mode(const struct device *dev,
165 					 enum gnss_navigation_mode *mode)
166 {
167 	struct gnss_emul_data *data = dev->data;
168 
169 	*mode = data->nav_mode;
170 	return 0;
171 }
172 
gnss_emul_set_enabled_systems(const struct device * dev,gnss_systems_t systems)173 static int gnss_emul_set_enabled_systems(const struct device *dev, gnss_systems_t systems)
174 {
175 	struct gnss_emul_data *data = dev->data;
176 
177 	if (systems > GNSS_EMUL_SUPPORTED_SYSTEMS_MASK) {
178 		return -EINVAL;
179 	}
180 
181 	data->enabled_systems = systems;
182 	return 0;
183 }
184 
gnss_emul_get_enabled_systems(const struct device * dev,gnss_systems_t * systems)185 static int gnss_emul_get_enabled_systems(const struct device *dev, gnss_systems_t *systems)
186 {
187 	struct gnss_emul_data *data = dev->data;
188 
189 	*systems = data->enabled_systems;
190 	return 0;
191 }
192 
193 #ifdef CONFIG_PM_DEVICE
gnss_emul_resume(const struct device * dev)194 static void gnss_emul_resume(const struct device *dev)
195 {
196 	gnss_emul_update_fix_timestamp(dev, true);
197 }
198 
gnss_emul_suspend(const struct device * dev)199 static void gnss_emul_suspend(const struct device *dev)
200 {
201 	gnss_emul_clear_fix_timestamp(dev);
202 }
203 
gnss_emul_pm_action(const struct device * dev,enum pm_device_action action)204 static int gnss_emul_pm_action(const struct device *dev, enum pm_device_action action)
205 {
206 	int ret = 0;
207 
208 	gnss_emul_lock(dev);
209 
210 	switch (action) {
211 	case PM_DEVICE_ACTION_SUSPEND:
212 		gnss_emul_suspend(dev);
213 		break;
214 
215 	case PM_DEVICE_ACTION_RESUME:
216 		gnss_emul_resume(dev);
217 		break;
218 
219 	default:
220 		ret = -ENOTSUP;
221 		break;
222 	}
223 
224 	gnss_emul_unlock(dev);
225 	return ret;
226 }
227 #endif
228 
gnss_emul_api_set_fix_rate(const struct device * dev,uint32_t fix_interval_ms)229 static int gnss_emul_api_set_fix_rate(const struct device *dev, uint32_t fix_interval_ms)
230 {
231 	int ret = -ENODEV;
232 
233 	gnss_emul_lock(dev);
234 
235 	if (!gnss_emul_is_resumed(dev)) {
236 		goto unlock_return;
237 	}
238 
239 	ret = gnss_emul_set_fix_rate(dev, fix_interval_ms);
240 
241 unlock_return:
242 	gnss_emul_unlock(dev);
243 	return ret;
244 }
245 
gnss_emul_api_get_fix_rate(const struct device * dev,uint32_t * fix_interval_ms)246 static int gnss_emul_api_get_fix_rate(const struct device *dev, uint32_t *fix_interval_ms)
247 {
248 	int ret = -ENODEV;
249 
250 	gnss_emul_lock(dev);
251 
252 	if (!gnss_emul_is_resumed(dev)) {
253 		goto unlock_return;
254 	}
255 
256 	ret = gnss_emul_get_fix_rate(dev, fix_interval_ms);
257 
258 unlock_return:
259 	gnss_emul_unlock(dev);
260 	return ret;
261 }
262 
gnss_emul_api_set_navigation_mode(const struct device * dev,enum gnss_navigation_mode mode)263 static int gnss_emul_api_set_navigation_mode(const struct device *dev,
264 					     enum gnss_navigation_mode mode)
265 {
266 	int ret = -ENODEV;
267 
268 	gnss_emul_lock(dev);
269 
270 	if (!gnss_emul_is_resumed(dev)) {
271 		goto unlock_return;
272 	}
273 
274 	ret = gnss_emul_set_navigation_mode(dev, mode);
275 
276 unlock_return:
277 	gnss_emul_unlock(dev);
278 	return ret;
279 }
280 
gnss_emul_api_get_navigation_mode(const struct device * dev,enum gnss_navigation_mode * mode)281 static int gnss_emul_api_get_navigation_mode(const struct device *dev,
282 					 enum gnss_navigation_mode *mode)
283 {
284 	int ret = -ENODEV;
285 
286 	gnss_emul_lock(dev);
287 
288 	if (!gnss_emul_is_resumed(dev)) {
289 		goto unlock_return;
290 	}
291 
292 	ret = gnss_emul_get_navigation_mode(dev, mode);
293 
294 unlock_return:
295 	gnss_emul_unlock(dev);
296 	return ret;
297 }
298 
gnss_emul_api_set_enabled_systems(const struct device * dev,gnss_systems_t systems)299 static int gnss_emul_api_set_enabled_systems(const struct device *dev, gnss_systems_t systems)
300 {
301 	int ret = -ENODEV;
302 
303 	gnss_emul_lock(dev);
304 
305 	if (!gnss_emul_is_resumed(dev)) {
306 		goto unlock_return;
307 	}
308 
309 	ret = gnss_emul_set_enabled_systems(dev, systems);
310 
311 unlock_return:
312 	gnss_emul_unlock(dev);
313 	return ret;
314 }
315 
gnss_emul_api_get_enabled_systems(const struct device * dev,gnss_systems_t * systems)316 static int gnss_emul_api_get_enabled_systems(const struct device *dev, gnss_systems_t *systems)
317 {
318 	int ret = -ENODEV;
319 
320 	gnss_emul_lock(dev);
321 
322 	if (!gnss_emul_is_resumed(dev)) {
323 		goto unlock_return;
324 	}
325 
326 	ret = gnss_emul_get_enabled_systems(dev, systems);
327 
328 unlock_return:
329 	gnss_emul_unlock(dev);
330 	return ret;
331 }
332 
gnss_emul_api_get_supported_systems(const struct device * dev,gnss_systems_t * systems)333 static int gnss_emul_api_get_supported_systems(const struct device *dev, gnss_systems_t *systems)
334 {
335 	*systems = GNSS_EMUL_SUPPORTED_SYSTEMS_MASK;
336 	return 0;
337 }
338 
339 static DEVICE_API(gnss, api) = {
340 	.set_fix_rate = gnss_emul_api_set_fix_rate,
341 	.get_fix_rate = gnss_emul_api_get_fix_rate,
342 	.set_navigation_mode = gnss_emul_api_set_navigation_mode,
343 	.get_navigation_mode = gnss_emul_api_get_navigation_mode,
344 	.set_enabled_systems = gnss_emul_api_set_enabled_systems,
345 	.get_enabled_systems = gnss_emul_api_get_enabled_systems,
346 	.get_supported_systems = gnss_emul_api_get_supported_systems,
347 };
348 
gnss_emul_clear_data(const struct device * dev)349 static void gnss_emul_clear_data(const struct device *dev)
350 {
351 	struct gnss_emul_data *data = dev->data;
352 
353 	memset(&data->data, 0, sizeof(data->data));
354 }
355 
gnss_emul_set_fix(const struct device * dev)356 static void gnss_emul_set_fix(const struct device *dev)
357 {
358 	struct gnss_emul_data *data = dev->data;
359 
360 	data->data.info.satellites_cnt = 8;
361 	data->data.info.hdop = 100;
362 	data->data.info.fix_status = GNSS_FIX_STATUS_GNSS_FIX;
363 	data->data.info.fix_quality = GNSS_FIX_QUALITY_GNSS_SPS;
364 }
365 
gnss_emul_set_utc(const struct device * dev)366 static void gnss_emul_set_utc(const struct device *dev)
367 {
368 	struct gnss_emul_data *data = dev->data;
369 	time_t timestamp;
370 	struct tm datetime;
371 	uint16_t millisecond;
372 
373 	timestamp = (time_t)(data->fix_timestamp_ms / 1000);
374 	gmtime_r(&timestamp, &datetime);
375 
376 	millisecond = (uint16_t)(data->fix_timestamp_ms % 1000)
377 		    + (uint16_t)(datetime.tm_sec * 1000);
378 
379 	data->data.utc.hour = datetime.tm_hour;
380 	data->data.utc.millisecond = millisecond;
381 	data->data.utc.minute = datetime.tm_min;
382 	data->data.utc.month = datetime.tm_mon + 1;
383 	data->data.utc.century_year = datetime.tm_year % 100;
384 }
385 
gnss_emul_set_nav_data(const struct device * dev)386 static void gnss_emul_set_nav_data(const struct device *dev)
387 {
388 	struct gnss_emul_data *data = dev->data;
389 
390 	data->data.nav_data.latitude = 10000000000;
391 	data->data.nav_data.longitude = -10000000000;
392 	data->data.nav_data.bearing = 3000;
393 	data->data.nav_data.speed = 0;
394 	data->data.nav_data.altitude = 20000;
395 }
396 
397 #ifdef CONFIG_GNSS_SATELLITES
gnss_emul_clear_satellites(const struct device * dev)398 static void gnss_emul_clear_satellites(const struct device *dev)
399 {
400 	struct gnss_emul_data *data = dev->data;
401 
402 	data->satellites_len = 0;
403 }
404 
gnss_emul_system_enabled(const struct device * dev,uint8_t system_bit)405 static bool gnss_emul_system_enabled(const struct device *dev, uint8_t system_bit)
406 {
407 	struct gnss_emul_data *data = dev->data;
408 
409 	return BIT(system_bit) & data->enabled_systems;
410 }
411 
gnss_emul_add_satellite(const struct device * dev,uint8_t system_bit)412 static void gnss_emul_add_satellite(const struct device *dev, uint8_t system_bit)
413 {
414 	struct gnss_emul_data *data = dev->data;
415 
416 	/* Unique values synthesized from GNSS system */
417 	data->satellites[data->satellites_len].prn = system_bit;
418 	data->satellites[data->satellites_len].snr = system_bit + 20;
419 	data->satellites[data->satellites_len].elevation = system_bit + 40;
420 	data->satellites[data->satellites_len].azimuth = system_bit + 60;
421 	data->satellites[data->satellites_len].system = BIT(system_bit);
422 	data->satellites[data->satellites_len].is_tracked = true;
423 	data->satellites_len++;
424 }
425 
gnss_emul_set_satellites(const struct device * dev)426 static void gnss_emul_set_satellites(const struct device *dev)
427 {
428 	gnss_emul_clear_satellites(dev);
429 
430 	for (uint8_t i = 0; i < GNSS_EMUL_SUPPORTED_SYSTEMS_COUNT; i++) {
431 		if (!gnss_emul_system_enabled(dev, i)) {
432 			continue;
433 		}
434 
435 		gnss_emul_add_satellite(dev, i);
436 	}
437 }
438 #endif
439 
gnss_emul_work_handler(struct k_work * work)440 static void gnss_emul_work_handler(struct k_work *work)
441 {
442 	struct k_work_delayable *dwork = k_work_delayable_from_work(work);
443 	struct gnss_emul_data *data = CONTAINER_OF(dwork, struct gnss_emul_data, data_dwork);
444 	const struct device *dev = data->dev;
445 
446 	if (!gnss_emul_fix_is_acquired(dev)) {
447 		gnss_emul_clear_data(dev);
448 	} else {
449 		gnss_emul_set_fix(dev);
450 		gnss_emul_set_utc(dev);
451 		gnss_emul_set_nav_data(dev);
452 	}
453 
454 	gnss_publish_data(dev, &data->data);
455 
456 #ifdef CONFIG_GNSS_SATELLITES
457 	gnss_emul_set_satellites(dev);
458 	gnss_publish_satellites(dev, data->satellites, data->satellites_len);
459 #endif
460 
461 	gnss_emul_update_fix_timestamp(dev, false);
462 	gnss_emul_schedule_work(dev);
463 }
464 
gnss_emul_init_data(const struct device * dev)465 static void gnss_emul_init_data(const struct device *dev)
466 {
467 	struct gnss_emul_data *data = dev->data;
468 
469 	data->dev = dev;
470 	k_sem_init(&data->lock, 1, 1);
471 	k_work_init_delayable(&data->data_dwork, gnss_emul_work_handler);
472 }
473 
gnss_emul_init(const struct device * dev)474 static int gnss_emul_init(const struct device *dev)
475 {
476 	gnss_emul_init_data(dev);
477 
478 	if (pm_device_is_powered(dev)) {
479 		gnss_emul_update_fix_timestamp(dev, true);
480 		gnss_emul_schedule_work(dev);
481 	} else {
482 		pm_device_init_off(dev);
483 	}
484 
485 	return pm_device_runtime_enable(dev);
486 }
487 
488 #define GNSS_EMUL_NAME(inst, name) _CONCAT(name, inst)
489 
490 #define GNSS_EMUL_DEVICE(inst)								\
491 	static struct gnss_emul_data GNSS_EMUL_NAME(inst, data) = {			\
492 		.fix_interval_ms = GNSS_EMUL_DEFAULT_FIX_INTERVAL_MS,			\
493 		.nav_mode = GNSS_EMUL_DEFAULT_NAV_MODE,					\
494 		.enabled_systems = GNSS_EMUL_DEFAULT_ENABLED_SYSTEMS_MASK,		\
495 	};										\
496 											\
497 	PM_DEVICE_DT_INST_DEFINE(inst, gnss_emul_pm_action);				\
498 											\
499 	DEVICE_DT_INST_DEFINE(								\
500 		inst,									\
501 		gnss_emul_init,								\
502 		PM_DEVICE_DT_INST_GET(inst),						\
503 		&GNSS_EMUL_NAME(inst, data),						\
504 		NULL,									\
505 		POST_KERNEL,								\
506 		CONFIG_GNSS_INIT_PRIORITY,						\
507 		&api									\
508 	);
509 
510 DT_INST_FOREACH_STATUS_OKAY(GNSS_EMUL_DEVICE)
511