2 * This file is part of nmealib.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include <nmea/generator.h>
20 #include <nmea/context.h>
21 #include <nmea/gmath.h>
22 #include <nmea/generate.h>
31 * Initialise the generator
33 * @param gen a pointer to the generator
34 * @param info a pointer to an nmeaINFO structure to use during generation
35 * (present and smask are preserved, other fields are reset before generation starts)
36 * @return 1 (true) on success, 0 (false) otherwise
38 int nmea_gen_init(nmeaGENERATOR *gen, nmeaINFO *info) {
40 int present = info->present;
41 int smask = info->smask;
42 nmeaGENERATOR *igen = gen;
47 info->present = present;
49 nmea_INFO_set_present(&info->present, SMASK);
51 info->lat = NMEA_DEF_LAT;
52 info->lon = NMEA_DEF_LON;
53 nmea_INFO_set_present(&info->present, LAT);
54 nmea_INFO_set_present(&info->present, LON);
56 while (retval && igen) {
58 retval = (*igen->init_call)(igen, info);
68 * @param gen a pointer to the generator
69 * @param info a pointer to an nmeaINFO structure to use during generation
70 * @return 1 (true) on success, 0 (false) otherwise
72 int nmea_gen_loop(nmeaGENERATOR *gen, nmeaINFO *info) {
76 retVal = (*gen->loop_call)(gen, info);
78 if (retVal && gen->next)
79 retVal = nmea_gen_loop(gen->next, info);
85 * Reset the generator.
87 * @param gen a pointer to the generator
88 * @param info a pointer to an nmeaINFO structure to use during generation
89 * @return 1 (true) on success, 0 (false) otherwise
91 int nmea_gen_reset(nmeaGENERATOR *gen, nmeaINFO *info) {
95 RetVal = (*gen->reset_call)(gen, info);
101 * Destroy the generator.
103 * @param gen a pointer to the generator
105 void nmea_gen_destroy(nmeaGENERATOR *gen) {
107 nmea_gen_destroy(gen->next);
111 if (gen->destroy_call)
112 (*gen->destroy_call)(gen);
118 * Add a generator to the existing ones.
120 * @param to the generators to add to
121 * @param gen the generator to add
123 void nmea_gen_add(nmeaGENERATOR *to, nmeaGENERATOR *gen) {
124 nmeaGENERATOR * next = to;
132 * Run a new generation loop on the generator
134 * @param s a pointer to the string buffer in which to generate
135 * @param len the size of the buffer
136 * @param info a pointer to an nmeaINFO structure to use during generation
137 * @param gen a pointer to the generator
138 * @param generate_mask the smask of sentences to generate
139 * @return the total length of the generated sentences
141 int nmea_generate_from(char *s, int len, nmeaINFO *info, nmeaGENERATOR *gen, int generate_mask) {
144 if ((retval = nmea_gen_loop(gen, info)))
145 retval = nmea_generate(s, len, info, generate_mask);
155 * NOISE Generator loop function.
156 * Does not touch smask and utc in info.
158 * @param gen a pointer to the generator
159 * @param info a pointer to an nmeaINFO structure to use during generation
160 * @return 1 (true) on success, 0 (false) otherwise
162 static int nmea_igen_noise_loop(nmeaGENERATOR *gen __attribute__ ((unused)), nmeaINFO *info) {
166 info->sig = lrint(nmea_random(1, 3));
167 info->fix = lrint(nmea_random(2, 3));
168 info->PDOP = nmea_random(0, 9);
169 info->HDOP = nmea_random(0, 9);
170 info->VDOP = nmea_random(0, 9);
171 info->lat = nmea_random(0, 100);
172 info->lon = nmea_random(0, 100);
173 info->elv = lrint(nmea_random(-100, 100));
174 info->speed = nmea_random(0, 100);
175 info->track = nmea_random(0, 360);
176 info->mtrack = nmea_random(0, 360);
177 info->magvar = nmea_random(0, 360);
179 nmea_INFO_set_present(&info->present, SIG);
180 nmea_INFO_set_present(&info->present, FIX);
181 nmea_INFO_set_present(&info->present, PDOP);
182 nmea_INFO_set_present(&info->present, HDOP);
183 nmea_INFO_set_present(&info->present, VDOP);
184 nmea_INFO_set_present(&info->present, LAT);
185 nmea_INFO_set_present(&info->present, LON);
186 nmea_INFO_set_present(&info->present, ELV);
187 nmea_INFO_set_present(&info->present, SPEED);
188 nmea_INFO_set_present(&info->present, TRACK);
189 nmea_INFO_set_present(&info->present, MTRACK);
190 nmea_INFO_set_present(&info->present, MAGVAR);
192 info->satinfo.inuse = 0;
193 info->satinfo.inview = 0;
195 for (it = 0; it < NMEA_MAXSAT; it++) {
196 in_use = lrint(nmea_random(0, 3));
197 info->satinfo.in_use[it] = in_use ? it : 0;
198 info->satinfo.sat[it].id = it;
199 info->satinfo.sat[it].elv = lrint(nmea_random(0, 90));
200 info->satinfo.sat[it].azimuth = lrint(nmea_random(0, 359));
201 info->satinfo.sat[it].sig = (int) (in_use ? nmea_random(40, 99) : nmea_random(0, 40));
204 info->satinfo.inuse++;
205 if (info->satinfo.sat[it].sig > 0)
206 info->satinfo.inview++;
209 nmea_INFO_set_present(&info->present, SATINUSECOUNT);
210 nmea_INFO_set_present(&info->present, SATINUSE);
211 nmea_INFO_set_present(&info->present, SATINVIEW);
221 * STATIC Generator loop function.
222 * Only touches utc in info.
224 * @param gen a pointer to the generator
225 * @param info a pointer to an nmeaINFO structure to use during generation
226 * @return 1 (true) on success, 0 (false) otherwise
228 static int nmea_igen_static_loop(nmeaGENERATOR *gen __attribute__ ((unused)), nmeaINFO *info) {
229 nmea_time_now(&info->utc, &info->present);
234 * STATIC Generator reset function.
235 * Resets only the satinfo to 4 sats in use and in view.
237 * @param gen a pointer to the generator
238 * @param info a pointer to an nmeaINFO structure to use during generation
239 * @return 1 (true) on success, 0 (false) otherwise
241 static int nmea_igen_static_reset(nmeaGENERATOR *gen __attribute__ ((unused)), nmeaINFO *info) {
242 info->satinfo.inuse = 4;
243 info->satinfo.inview = 4;
245 info->satinfo.in_use[0] = 1;
246 info->satinfo.sat[0].id = 1;
247 info->satinfo.sat[0].elv = 50;
248 info->satinfo.sat[0].azimuth = 0;
249 info->satinfo.sat[0].sig = 99;
251 info->satinfo.in_use[1] = 2;
252 info->satinfo.sat[1].id = 2;
253 info->satinfo.sat[1].elv = 50;
254 info->satinfo.sat[1].azimuth = 90;
255 info->satinfo.sat[1].sig = 99;
257 info->satinfo.in_use[2] = 3;
258 info->satinfo.sat[2].id = 3;
259 info->satinfo.sat[2].elv = 50;
260 info->satinfo.sat[2].azimuth = 180;
261 info->satinfo.sat[2].sig = 99;
263 info->satinfo.in_use[3] = 4;
264 info->satinfo.sat[3].id = 4;
265 info->satinfo.sat[3].elv = 50;
266 info->satinfo.sat[3].azimuth = 270;
267 info->satinfo.sat[3].sig = 99;
269 nmea_INFO_set_present(&info->present, SATINUSECOUNT);
270 nmea_INFO_set_present(&info->present, SATINUSE);
271 nmea_INFO_set_present(&info->present, SATINVIEW);
277 * STATIC Generator initialiser function.
278 * Only touches sig, fix and satinfo in info.
280 * @param gen a pointer to the generator
281 * @param info a pointer to an nmeaINFO structure to use during generation
282 * @return 1 (true) on success, 0 (false) otherwise
284 static int nmea_igen_static_init(nmeaGENERATOR *gen, nmeaINFO *info) {
288 nmea_INFO_set_present(&info->present, SIG);
289 nmea_INFO_set_present(&info->present, FIX);
291 nmea_igen_static_reset(gen, info);
297 * SAT_ROTATE generator
301 * SAT_ROTATE Generator loop function.
303 * @param gen a pointer to the generator
304 * @param info a pointer to an nmeaINFO structure to use during generation
305 * @return 1 (true) on success, 0 (false) otherwise
307 static int nmea_igen_rotate_loop(nmeaGENERATOR *gen __attribute__ ((unused)), nmeaINFO *info) {
309 int count = info->satinfo.inview;
310 double deg = 360.0 / (count ? count : 1);
311 double srt = (count ? (info->satinfo.sat[0].azimuth) : 0) + 5;
313 nmea_time_now(&info->utc, &info->present);
315 for (it = 0; it < count; it++) {
316 info->satinfo.sat[it].azimuth = (int) ((srt >= 360) ? srt - 360 : srt);
320 nmea_INFO_set_present(&info->present, SATINVIEW);
326 * SAT_ROTATE Generator reset function.
328 * @param gen a pointer to the generator
329 * @param info a pointer to an nmeaINFO structure to use during generation
330 * @return 1 (true) on success, 0 (false) otherwise
332 static int nmea_igen_rotate_reset(nmeaGENERATOR *gen __attribute__ ((unused)), nmeaINFO *info) {
334 double deg = 360 / 8;
337 info->satinfo.inuse = 8;
338 info->satinfo.inview = 8;
340 for (it = 0; it < info->satinfo.inview; it++) {
341 info->satinfo.in_use[it] = it + 1;
342 info->satinfo.sat[it].id = it + 1;
343 info->satinfo.sat[it].elv = 5;
344 info->satinfo.sat[it].azimuth = (int) srt;
345 info->satinfo.sat[it].sig = 80;
349 nmea_INFO_set_present(&info->present, SATINUSECOUNT);
350 nmea_INFO_set_present(&info->present, SATINUSE);
351 nmea_INFO_set_present(&info->present, SATINVIEW);
357 * SAT_ROTATE Generator initialiser function.
358 * Only touches sig, fix and satinfo in info.
360 * @param gen a pointer to the generator
361 * @param info a pointer to an nmeaINFO structure to use during generation
362 * @return 1 (true) on success, 0 (false) otherwise
364 static int nmea_igen_rotate_init(nmeaGENERATOR *gen, nmeaINFO *info) {
368 nmea_INFO_set_present(&info->present, SIG);
369 nmea_INFO_set_present(&info->present, FIX);
371 nmea_igen_rotate_reset(gen, info);
377 * POS_RANDMOVE generator
381 * POS_RANDMOVE Generator initialiser function.
382 * Only touches sig, fix, track, mtrack, magvar and speed in info.
384 * @param gen a pointer to the generator
385 * @param info a pointer to an nmeaINFO structure to use during generation
386 * @return 1 (true) on success, 0 (false) otherwise
388 static int nmea_igen_pos_rmove_init(nmeaGENERATOR *gen __attribute__ ((unused)), nmeaINFO *info) {
396 nmea_INFO_set_present(&info->present, SIG);
397 nmea_INFO_set_present(&info->present, FIX);
398 nmea_INFO_set_present(&info->present, SPEED);
399 nmea_INFO_set_present(&info->present, TRACK);
400 nmea_INFO_set_present(&info->present, MTRACK);
401 nmea_INFO_set_present(&info->present, MAGVAR);
407 * POS_RANDMOVE Generator loop function.
409 * @param gen a pointer to the generator
410 * @param info a pointer to an nmeaINFO structure to use during generation
411 * @return 1 (true) on success, 0 (false) otherwise
413 static int nmea_igen_pos_rmove_loop(nmeaGENERATOR *gen __attribute__ ((unused)), nmeaINFO *info) {
416 info->track += nmea_random(-10, 10);
417 info->mtrack += nmea_random(-10, 10);
418 info->speed += nmea_random(-2, 3);
420 if (info->track < 0) {
421 info->track = 359 + info->track;
423 if (info->track > 359) {
426 if (info->mtrack < 0) {
427 info->mtrack = 359 + info->mtrack;
429 if (info->mtrack > 359) {
433 if (info->speed > 40)
438 nmea_info2pos(info, &crd);
439 nmea_move_horz(&crd, &crd, info->track, info->speed / 3600);
440 nmea_pos2info(&crd, info);
442 info->magvar = info->track;
444 nmea_INFO_set_present(&info->present, LAT);
445 nmea_INFO_set_present(&info->present, LON);
446 nmea_INFO_set_present(&info->present, SPEED);
447 nmea_INFO_set_present(&info->present, TRACK);
448 nmea_INFO_set_present(&info->present, MTRACK);
449 nmea_INFO_set_present(&info->present, MAGVAR);
455 * Create the generator.
457 * @param type the type of the generator to create (see nmeaGENTYPE)
458 * @param info a pointer to an nmeaINFO structure to use during generation
459 * @return the generator
461 static nmeaGENERATOR * __nmea_create_generator(const int type, nmeaINFO *info) {
462 nmeaGENERATOR *gen = 0;
466 if (!(gen = malloc(sizeof(nmeaGENERATOR))))
467 nmea_error("__nmea_create_generator: insufficient memory!");
469 memset(gen, 0, sizeof(nmeaGENERATOR));
470 gen->loop_call = &nmea_igen_noise_loop;
473 case NMEA_GEN_STATIC:
474 case NMEA_GEN_SAT_STATIC:
475 if (!(gen = malloc(sizeof(nmeaGENERATOR))))
476 nmea_error("__nmea_create_generator: insufficient memory!");
478 memset(gen, 0, sizeof(nmeaGENERATOR));
479 gen->init_call = &nmea_igen_static_init;
480 gen->loop_call = &nmea_igen_static_loop;
481 gen->reset_call = &nmea_igen_static_reset;
484 case NMEA_GEN_SAT_ROTATE:
485 if (!(gen = malloc(sizeof(nmeaGENERATOR))))
486 nmea_error("__nmea_create_generator: insufficient memory!");
488 memset(gen, 0, sizeof(nmeaGENERATOR));
489 gen->init_call = &nmea_igen_rotate_init;
490 gen->loop_call = &nmea_igen_rotate_loop;
491 gen->reset_call = &nmea_igen_rotate_reset;
494 case NMEA_GEN_POS_RANDMOVE:
495 if (!(gen = malloc(sizeof(nmeaGENERATOR))))
496 nmea_error("__nmea_create_generator: insufficient memory!");
498 memset(gen, 0, sizeof(nmeaGENERATOR));
499 gen->init_call = &nmea_igen_pos_rmove_init;
500 gen->loop_call = &nmea_igen_pos_rmove_loop;
504 /* case NMEA_GEN_ROTATE: */
505 gen = __nmea_create_generator(NMEA_GEN_SAT_ROTATE, info);
506 nmea_gen_add(gen, __nmea_create_generator(NMEA_GEN_POS_RANDMOVE, info));
514 * Create the generator and initialise it.
516 * @param type the type of the generator to create (see nmeaGENTYPE)
517 * @param info a pointer to an nmeaINFO structure to use during generation
518 * @return the generator
520 nmeaGENERATOR * nmea_create_generator(const int type, nmeaINFO *info) {
521 nmeaGENERATOR *gen = __nmea_create_generator(type, info);
524 nmea_gen_init(gen, info);