1 /*
2  *
3  * NMEA library
4  * URL: http://nmea.sourceforge.net
5  * Author: Tim (xtimor@gmail.com)
6  * Licence: http://www.gnu.org/licenses/lgpl.html
7  * $Id: generator.c 17 2008-03-11 11:56:11Z xtimor $
8  *
9  */
10 
11 #include "nmea/gmath.h"
12 #include "nmea/generate.h"
13 #include "nmea/generator.h"
14 #include "nmea/context.h"
15 
16 #include <string.h>
17 #include <stdlib.h>
18 
19 #if defined(NMEA_WIN) && defined(_MSC_VER)
20 # pragma warning(disable: 4100) /* unreferenced formal parameter */
21 #endif
22 
nmea_random(double min,double max)23 double nmea_random(double min, double max)
24 {
25     static double rand_max = RAND_MAX;
26     double rand_val = rand();
27     double bounds = max - min;
28     return min + (rand_val * bounds) / rand_max;
29 }
30 
31 /*
32  * low level
33  */
34 
nmea_gen_init(nmeaGENERATOR * gen,nmeaINFO * info)35 int nmea_gen_init(nmeaGENERATOR *gen, nmeaINFO *info)
36 {
37     int RetVal = 1; int smask = info->smask;
38     nmeaGENERATOR *igen = gen;
39 
40     nmea_zero_INFO(info);
41     info->smask = smask;
42 
43     info->lat = NMEA_DEF_LAT;
44     info->lon = NMEA_DEF_LON;
45 
46     while(RetVal && igen)
47     {
48         if(igen->init_call)
49             RetVal = (*igen->init_call)(igen, info);
50         igen = igen->next;
51     }
52 
53     return RetVal;
54 }
55 
nmea_gen_loop(nmeaGENERATOR * gen,nmeaINFO * info)56 int nmea_gen_loop(nmeaGENERATOR *gen, nmeaINFO *info)
57 {
58     int RetVal = 1;
59 
60     if(gen->loop_call)
61         RetVal = (*gen->loop_call)(gen, info);
62 
63     if(RetVal && gen->next)
64         RetVal = nmea_gen_loop(gen->next, info);
65 
66     return RetVal;
67 }
68 
nmea_gen_reset(nmeaGENERATOR * gen,nmeaINFO * info)69 int nmea_gen_reset(nmeaGENERATOR *gen, nmeaINFO *info)
70 {
71     int RetVal = 1;
72 
73     if(gen->reset_call)
74         RetVal = (*gen->reset_call)(gen, info);
75 
76     return RetVal;
77 }
78 
nmea_gen_destroy(nmeaGENERATOR * gen)79 void nmea_gen_destroy(nmeaGENERATOR *gen)
80 {
81     if(gen->next)
82     {
83         nmea_gen_destroy(gen->next);
84         gen->next = 0;
85     }
86 
87     if(gen->destroy_call)
88         (*gen->destroy_call)(gen);
89 
90     free(gen);
91 }
92 
nmea_gen_add(nmeaGENERATOR * to,nmeaGENERATOR * gen)93 void nmea_gen_add(nmeaGENERATOR *to, nmeaGENERATOR *gen)
94 {
95     if(to->next)
96         nmea_gen_add(to->next, gen);
97     else
98         to->next = gen;
99 }
100 
nmea_generate_from(char * buff,int buff_sz,nmeaINFO * info,nmeaGENERATOR * gen,int generate_mask)101 int nmea_generate_from(
102     char *buff, int buff_sz,
103     nmeaINFO *info,
104     nmeaGENERATOR *gen,
105     int generate_mask
106     )
107 {
108     int retval;
109 
110     if(0 != (retval = nmea_gen_loop(gen, info)))
111         retval = nmea_generate(buff, buff_sz, info, generate_mask);
112 
113     return retval;
114 }
115 
116 /*
117  * NOISE generator
118  */
119 
nmea_igen_noise_init(nmeaGENERATOR * gen,nmeaINFO * info)120 int nmea_igen_noise_init(nmeaGENERATOR *gen, nmeaINFO *info)
121 {
122     return 1;
123 }
124 
nmea_igen_noise_loop(nmeaGENERATOR * gen,nmeaINFO * info)125 int nmea_igen_noise_loop(nmeaGENERATOR *gen, nmeaINFO *info)
126 {
127     int it;
128     int in_use;
129 
130     info->sig = (int)nmea_random(1, 3);
131     info->PDOP = nmea_random(0, 9);
132     info->HDOP = nmea_random(0, 9);
133     info->VDOP = nmea_random(0, 9);
134     info->fix = (int)nmea_random(2, 3);
135     info->lat = nmea_random(0, 100);
136     info->lon = nmea_random(0, 100);
137     info->speed = nmea_random(0, 100);
138     info->direction = nmea_random(0, 360);
139     info->declination = nmea_random(0, 360);
140     info->elv = (int)nmea_random(-100, 100);
141 
142     info->satinfo.inuse = 0;
143     info->satinfo.inview = 0;
144 
145     for(it = 0; it < 12; ++it)
146     {
147         info->satinfo.sat[it].id = it;
148         info->satinfo.sat[it].in_use = in_use = (int)nmea_random(0, 3);
149         info->satinfo.sat[it].elv = (int)nmea_random(0, 90);
150         info->satinfo.sat[it].azimuth = (int)nmea_random(0, 359);
151         info->satinfo.sat[it].sig = (int)(in_use?nmea_random(40, 99):nmea_random(0, 40));
152 
153         if(in_use)
154             info->satinfo.inuse++;
155         if(info->satinfo.sat[it].sig > 0)
156             info->satinfo.inview++;
157     }
158 
159     return 1;
160 }
161 
nmea_igen_noise_reset(nmeaGENERATOR * gen,nmeaINFO * info)162 int nmea_igen_noise_reset(nmeaGENERATOR *gen, nmeaINFO *info)
163 {
164     return 1;
165 }
166 
167 /*
168  * STATIC generator
169  */
170 
nmea_igen_static_loop(nmeaGENERATOR * gen,nmeaINFO * info)171 int nmea_igen_static_loop(nmeaGENERATOR *gen, nmeaINFO *info)
172 {
173     nmea_time_now(&info->utc);
174     return 1;
175 };
176 
nmea_igen_static_reset(nmeaGENERATOR * gen,nmeaINFO * info)177 int nmea_igen_static_reset(nmeaGENERATOR *gen, nmeaINFO *info)
178 {
179     info->satinfo.inuse = 4;
180     info->satinfo.inview = 4;
181 
182     info->satinfo.sat[0].id = 1;
183     info->satinfo.sat[0].in_use = 1;
184     info->satinfo.sat[0].elv = 50;
185     info->satinfo.sat[0].azimuth = 0;
186     info->satinfo.sat[0].sig = 99;
187 
188     info->satinfo.sat[1].id = 2;
189     info->satinfo.sat[1].in_use = 1;
190     info->satinfo.sat[1].elv = 50;
191     info->satinfo.sat[1].azimuth = 90;
192     info->satinfo.sat[1].sig = 99;
193 
194     info->satinfo.sat[2].id = 3;
195     info->satinfo.sat[2].in_use = 1;
196     info->satinfo.sat[2].elv = 50;
197     info->satinfo.sat[2].azimuth = 180;
198     info->satinfo.sat[2].sig = 99;
199 
200     info->satinfo.sat[3].id = 4;
201     info->satinfo.sat[3].in_use = 1;
202     info->satinfo.sat[3].elv = 50;
203     info->satinfo.sat[3].azimuth = 270;
204     info->satinfo.sat[3].sig = 99;
205 
206     return 1;
207 }
208 
nmea_igen_static_init(nmeaGENERATOR * gen,nmeaINFO * info)209 int nmea_igen_static_init(nmeaGENERATOR *gen, nmeaINFO *info)
210 {
211     info->sig = 3;
212     info->fix = 3;
213 
214     nmea_igen_static_reset(gen, info);
215 
216     return 1;
217 }
218 
219 /*
220  * SAT_ROTATE generator
221  */
222 
nmea_igen_rotate_loop(nmeaGENERATOR * gen,nmeaINFO * info)223 int nmea_igen_rotate_loop(nmeaGENERATOR *gen, nmeaINFO *info)
224 {
225     int it;
226     int count = info->satinfo.inview;
227     double deg = 360 / (count?count:1);
228     double srt = (count?(info->satinfo.sat[0].azimuth):0) + 5;
229 
230     nmea_time_now(&info->utc);
231 
232     for(it = 0; it < count; ++it)
233     {
234         info->satinfo.sat[it].azimuth =
235             (int)((srt >= 360)?srt - 360:srt);
236         srt += deg;
237     }
238 
239     return 1;
240 };
241 
nmea_igen_rotate_reset(nmeaGENERATOR * gen,nmeaINFO * info)242 int nmea_igen_rotate_reset(nmeaGENERATOR *gen, nmeaINFO *info)
243 {
244     int it;
245     double deg = 360 / 8;
246     double srt = 0;
247 
248     info->satinfo.inuse = 8;
249     info->satinfo.inview = 8;
250 
251     for(it = 0; it < info->satinfo.inview; ++it)
252     {
253         info->satinfo.sat[it].id = it + 1;
254         info->satinfo.sat[it].in_use = 1;
255         info->satinfo.sat[it].elv = 5;
256         info->satinfo.sat[it].azimuth = (int)srt;
257         info->satinfo.sat[it].sig = 80;
258         srt += deg;
259     }
260 
261     return 1;
262 }
263 
nmea_igen_rotate_init(nmeaGENERATOR * gen,nmeaINFO * info)264 int nmea_igen_rotate_init(nmeaGENERATOR *gen, nmeaINFO *info)
265 {
266     info->sig = 3;
267     info->fix = 3;
268 
269     nmea_igen_rotate_reset(gen, info);
270 
271     return 1;
272 }
273 
274 /*
275  * POS_RANDMOVE generator
276  */
277 
nmea_igen_pos_rmove_init(nmeaGENERATOR * gen,nmeaINFO * info)278 int nmea_igen_pos_rmove_init(nmeaGENERATOR *gen, nmeaINFO *info)
279 {
280     info->sig = 3;
281     info->fix = 3;
282     info->direction = info->declination = 0;
283     info->speed = 20;
284     return 1;
285 }
286 
nmea_igen_pos_rmove_loop(nmeaGENERATOR * gen,nmeaINFO * info)287 int nmea_igen_pos_rmove_loop(nmeaGENERATOR *gen, nmeaINFO *info)
288 {
289     nmeaPOS crd;
290 
291     info->direction += nmea_random(-10, 10);
292     info->speed += nmea_random(-2, 3);
293 
294     if(info->direction < 0)
295         info->direction = 359 + info->direction;
296     if(info->direction > 359)
297         info->direction -= 359;
298 
299     if(info->speed > 40)
300         info->speed = 40;
301     if(info->speed < 1)
302         info->speed = 1;
303 
304     nmea_info2pos(info, &crd);
305     nmea_move_horz(&crd, &crd, info->direction, info->speed / 3600);
306     nmea_pos2info(&crd, info);
307 
308     info->declination = info->direction;
309 
310     return 1;
311 };
312 
nmea_igen_pos_rmove_destroy(nmeaGENERATOR * gen)313 int nmea_igen_pos_rmove_destroy(nmeaGENERATOR *gen)
314 {
315     return 1;
316 };
317 
318 /*
319  * generator create
320  */
321 
__nmea_create_generator(int type,nmeaINFO * info)322 nmeaGENERATOR * __nmea_create_generator(int type, nmeaINFO *info)
323 {
324     nmeaGENERATOR *gen = 0;
325 
326     switch(type)
327     {
328     case NMEA_GEN_NOISE:
329         if(0 == (gen = malloc(sizeof(nmeaGENERATOR))))
330             nmea_error("Insufficient memory!");
331         else
332         {
333             memset(gen, 0, sizeof(nmeaGENERATOR));
334             gen->init_call = &nmea_igen_noise_init;
335             gen->loop_call = &nmea_igen_noise_loop;
336             gen->reset_call = &nmea_igen_noise_reset;
337         }
338         break;
339     case NMEA_GEN_STATIC:
340     case NMEA_GEN_SAT_STATIC:
341         if(0 == (gen = malloc(sizeof(nmeaGENERATOR))))
342             nmea_error("Insufficient memory!");
343         else
344         {
345             memset(gen, 0, sizeof(nmeaGENERATOR));
346             gen->init_call = &nmea_igen_static_init;
347             gen->loop_call = &nmea_igen_static_loop;
348             gen->reset_call = &nmea_igen_static_reset;
349         }
350         break;
351     case NMEA_GEN_SAT_ROTATE:
352         if(0 == (gen = malloc(sizeof(nmeaGENERATOR))))
353             nmea_error("Insufficient memory!");
354         else
355         {
356             memset(gen, 0, sizeof(nmeaGENERATOR));
357             gen->init_call = &nmea_igen_rotate_init;
358             gen->loop_call = &nmea_igen_rotate_loop;
359             gen->reset_call = &nmea_igen_rotate_reset;
360         }
361         break;
362     case NMEA_GEN_POS_RANDMOVE:
363         if(0 == (gen = malloc(sizeof(nmeaGENERATOR))))
364             nmea_error("Insufficient memory!");
365         else
366         {
367             memset(gen, 0, sizeof(nmeaGENERATOR));
368             gen->init_call = &nmea_igen_pos_rmove_init;
369             gen->loop_call = &nmea_igen_pos_rmove_loop;
370             gen->destroy_call = &nmea_igen_pos_rmove_destroy;
371         }
372         break;
373     case NMEA_GEN_ROTATE:
374         gen = __nmea_create_generator(NMEA_GEN_SAT_ROTATE, info);
375         nmea_gen_add(gen, __nmea_create_generator(NMEA_GEN_POS_RANDMOVE, info));
376         break;
377     };
378 
379     return gen;
380 }
381 
nmea_create_generator(int type,nmeaINFO * info)382 nmeaGENERATOR * nmea_create_generator(int type, nmeaINFO *info)
383 {
384     nmeaGENERATOR *gen = __nmea_create_generator(type, info);
385 
386     if(gen)
387         nmea_gen_init(gen, info);
388 
389     return gen;
390 }
391 
nmea_destroy_generator(nmeaGENERATOR * gen)392 void nmea_destroy_generator(nmeaGENERATOR *gen)
393 {
394     nmea_gen_destroy(gen);
395 }
396 
397 #if defined(NMEA_WIN) && defined(_MSC_VER)
398 # pragma warning(default: 4100)
399 #endif
400