Rev 1649 | Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1648 | giacomo | 1 | /* |
2 | * Project: S.Ha.R.K. |
||
3 | * G P S D E M O : this program receives and displays data from a gps |
||
4 | * transmitter connected to COM1 port. This is also a graphic demo that |
||
5 | * uses a software emulation of MESA libraries to display actual latitude |
||
6 | * and longitude on the earth globe. You can also use the program without |
||
7 | * having a gps transmitter because it can run in a demo mode (to do that |
||
8 | * press d key when the program starts). |
||
9 | * |
||
10 | * In the main function graphics and com1 port are initialized, respectively |
||
11 | * with a call to the functions gl_init and open_com. Then all the tasks |
||
12 | * used in the program are created and activated, these are : |
||
13 | * |
||
14 | * TASK refresh : copies the gl buffer to video memory |
||
15 | * TASK draw : draws all the graphics |
||
16 | * TASK gps : receives data from gps transmitter |
||
17 | * |
||
18 | */ |
||
19 | |||
20 | #include <kernel/log.h> |
||
21 | #include <kernel/kern.h> |
||
22 | #include <math.h> |
||
23 | #include <stdlib.h> |
||
24 | |||
25 | #include <drivers/shark_fb26.h> |
||
26 | #include <drivers/shark_keyb26.h> |
||
27 | |||
28 | #include <GL/osmesa.h> //MESA header |
||
29 | #include <GL/glut.h> //MESA header |
||
30 | #include "texture.h" //contains three arrayes that define the R, G, B data of the first texture (phisical earth) |
||
31 | #include "texture2.h" //contains three arrayes that define the R, G, B data of the second texture (political earth) |
||
32 | #include "comport.h" //contains constants used by COM1 functions |
||
33 | |||
34 | #ifndef M_PI |
||
35 | #define M_PI 3.14159265 |
||
36 | #endif |
||
37 | |||
38 | //Graphic variables and constants |
||
39 | |||
40 | #define WIDTH 800 //Width of the screen in pixel |
||
41 | #define HEIGHT 600 //Height of the screen in pixel |
||
42 | #define BYTES_PP 2 //BytesPerPixel |
||
43 | |||
44 | OSMesaContext ctx; |
||
45 | |||
46 | extern void *video_memory; |
||
47 | |||
48 | unsigned char *rgb_565_buf = NULL; //RGB 16 bpp Buffer |
||
49 | unsigned char *video_buf = NULL; //Video Buffer |
||
50 | unsigned long int VMEMLONG = WIDTH*HEIGHT*BYTES_PP / 4; //Used by copy_videomem_16to16 |
||
51 | unsigned long int RGB565MEM = WIDTH*HEIGHT*BYTES_PP; //Total video mem |
||
52 | |||
53 | //Graphic Objects variables and constants |
||
54 | |||
55 | GLdouble radius, twist; //radius and twist of the sphere |
||
56 | float zoom = 0; //zoom factor |
||
57 | int sel_texture = 1; //index of the actually selected texture |
||
58 | GLubyte tex[256][256][3]; //stores the R, G, B data of the first texture |
||
59 | GLubyte tex2[256][256][3]; //stores the R, G, B data of the second texture |
||
60 | GLint sphere; //index of the shpere list (see mesa functions for details) |
||
61 | |||
62 | //Tasks variables and constants |
||
63 | |||
64 | unsigned long int PERIOD_REFRESH = 100000; //period of the refresh task in ns |
||
65 | unsigned long int PERIOD_DRAW = 100000; //period of the draw task |
||
66 | unsigned long int PERIOD_GPS = 1000; //period of the gps task |
||
67 | unsigned long int WCET_REFRESH, WCET_DRAW, WCET_GPS; //deadlines of the tasks |
||
68 | PID refresh_PID, draw_PID, gps_PID; //indexes of the tasks |
||
69 | |||
70 | //Gps receiver task variables and constants |
||
71 | |||
72 | char word[30]; //contains every word received from the gps transmitter |
||
73 | int ind = 0; //contains the index of the next character to be written in the variable word |
||
74 | int ind_gpgga = 0; //index of the next gpgga word to be read from gps |
||
75 | int ind_gpgsv = 0; //index of the next gpgsv word to be read from gps |
||
76 | int ind_gprmc = 0; //index of the next gprmc word to be read from gps |
||
77 | int nlist; //used to index satellites in gps_sat_data structure |
||
78 | |||
79 | //Demo mode variables and functions |
||
80 | |||
81 | int demo_mode = 0; //indicates if demo mode is active(=1) or not (=0) |
||
82 | int ndemo = 0; //a counter used while running in demo mode |
||
83 | int lat, lon; //auxiliary variables used for integer division |
||
84 | int kmov; //used to change the moving direction |
||
85 | float demolat = 0; //stores latitude |
||
86 | float demolon = 0; //stores longitude |
||
87 | |||
88 | //Gps data structures |
||
89 | |||
90 | typedef struct { |
||
91 | float id, elevation, azimuth, signal_level; |
||
92 | } gps_sat_data; |
||
93 | |||
94 | struct { |
||
95 | float latitude, longitude, altitude, nsat, speed, dir_mov, date, var_mov; |
||
96 | char dirlat, dirlon, time[12], dir_var_mov; |
||
97 | gps_sat_data sat_data[4]; //data of the satellites in view (4 maximum) |
||
98 | } gps_data; |
||
99 | |||
100 | TASK refesh(void); |
||
101 | TASK draw(void); |
||
102 | TASK gps(void); |
||
103 | |||
104 | //converts a string to a floating point |
||
105 | float strtof(char *s) |
||
106 | { |
||
107 | int d, n; |
||
108 | float f = 0, pot; |
||
109 | |||
110 | //if the string is null ends returning 0 |
||
111 | if(s[0] == '\0') |
||
112 | return 0; |
||
113 | |||
114 | //finds the dot character until the end of the string |
||
115 | for(d = 0; (s[d] != '.') && (s[d] != '\0') ; d++); |
||
116 | |||
117 | //converts non decimal numbers |
||
118 | pot = 1; |
||
119 | for(n = d - 1; n >= 0; n--) { |
||
120 | f = f + pot * (s[n] - 48); |
||
121 | pot = pot * 10; |
||
122 | } |
||
123 | |||
124 | //ends if there are not decimal numbers |
||
125 | if( s[d] == '\0') |
||
126 | return f; |
||
127 | |||
128 | //converts decimal numbers |
||
129 | pot = 0.1; |
||
130 | for(n = d + 1; s[n] != '\0'; n++) { |
||
131 | f = f + pot * (s[n] - 48); |
||
132 | pot = pot / 10; |
||
133 | if(n >= 30) |
||
134 | break; |
||
135 | |||
136 | } |
||
137 | return f; |
||
138 | } |
||
139 | |||
140 | //compares two strings returning 1 if they are equal otherwise 0 |
||
141 | int streq(char *s1, char *s2) |
||
142 | { |
||
143 | int n = 0; |
||
144 | while(1) |
||
145 | if( s1[n] == s2[n] ) |
||
146 | if( s1[n] == '\0' ) { |
||
147 | return 1; |
||
148 | } |
||
149 | else { |
||
150 | n++; |
||
151 | //ends if the string is larger than the word variable |
||
152 | if(n >= 30) |
||
153 | return 0; |
||
154 | } |
||
155 | else |
||
156 | return 0; |
||
157 | } |
||
158 | |||
159 | //copies s2 string in s1 string |
||
160 | void strcp(char *s1, char *s2) |
||
161 | { |
||
162 | int n = 0; |
||
163 | while( s2[n] != '\0' ) { |
||
164 | s1[n] = s2[n]; |
||
165 | n++; |
||
166 | //ends if the string is larger than the word variable |
||
167 | if(n >= 30) |
||
168 | break; |
||
169 | } |
||
170 | s1[n] = '\0'; |
||
171 | } |
||
172 | |||
173 | //writes data on the COM1 port (used only by open_com function) |
||
174 | void com_write(unsigned int port,unsigned int reg,unsigned int value) |
||
175 | { |
||
176 | if (port > 3 || reg > 7) return; |
||
177 | ll_out(com_base[port]+reg,value); |
||
178 | } |
||
179 | |||
180 | //reads data from the COM1 port without waiting |
||
181 | unsigned int com_read(unsigned int port,unsigned int reg) |
||
182 | { |
||
183 | unsigned int b; |
||
184 | if (port > 3 || reg > 7) return(0); |
||
185 | b = ll_in(com_base[port]+reg); |
||
186 | return(b); |
||
187 | } |
||
188 | |||
189 | //activates the COM1 port and makes it ready for reading/writing |
||
190 | int open_com(unsigned int port, DWORD speed, BYTE parity, BYTE len, BYTE stop) |
||
191 | { |
||
192 | unsigned long div,b_mask; |
||
193 | |||
194 | /* Now set up the serial link */ |
||
195 | b_mask = (parity & 3) * 8 + (stop & 1) * 4 + ((len - 5) & 3); |
||
196 | div = 115200L / speed; |
||
197 | /* Clear serial interrupt enable register */ |
||
198 | com_write(port,IER,0); |
||
199 | /* Empty input buffer */ |
||
200 | com_read(port,RBR); |
||
201 | /* Activate DLAB bit for speed setting */ |
||
202 | com_write(port,LCR,0x80); |
||
203 | /* Load baud divisor */ |
||
204 | com_write(port,0,div & 0x00FF); |
||
205 | div >>= 8; |
||
206 | com_write(port,1,div & 0x00FF); |
||
207 | /* Load control word (parity,stop bit,bit len) */ |
||
208 | com_write(port,LCR,b_mask); |
||
209 | /* Activate OUT1 & OUT2 */ |
||
210 | com_write(port,MCR,0x0C); |
||
211 | |||
212 | return 0; |
||
213 | |||
214 | } |
||
215 | |||
216 | /*rotates the axes of the mesa graphic objects and also of the sphere |
||
217 | using the latitude and longitude data contained in the gps_data structure */ |
||
218 | void polarView() |
||
219 | { |
||
220 | float signlat, signlon; //contains directions of rotation |
||
221 | |||
222 | //translates the axes far or near from the observer point to make zoom effect |
||
223 | glTranslated(0.0, 0.0, radius + zoom); |
||
224 | glRotated(-twist, 0.0, 0.0, 1.0); |
||
225 | |||
226 | //direction of rotation in latitude may be Nord 'N' or Suoth 'S' |
||
227 | if(gps_data.dirlat == 'N') |
||
228 | signlat = -1; |
||
229 | else |
||
230 | signlat = 1; |
||
231 | |||
232 | //direction of rotation in longitude may be East 'E' or West 'W' |
||
233 | if(gps_data.dirlon == 'E') |
||
234 | signlon = -1; |
||
235 | else |
||
236 | signlon = 1; |
||
237 | |||
238 | /*there are some graphic errors in the two textures that result in a |
||
239 | wrong placing of latitude and longitude on the image displayed. |
||
240 | To compensate these errors some correction factors that depend |
||
241 | on what texture you are using are added to latitude and longitude.*/ |
||
242 | |||
243 | switch(sel_texture) { |
||
244 | case 1 : glRotated(signlat*gps_data.latitude + 3 , 1.0, 0.0, 0.0); |
||
245 | glRotated(signlon*gps_data.longitude, 0.0, 1.0, 0.0); |
||
246 | break; |
||
247 | case 2 : glRotated(signlat*gps_data.latitude + 7 , 1.0, 0.0, 0.0); |
||
248 | glRotated(signlon*gps_data.longitude + 15, 0.0, 1.0, 0.0); |
||
249 | } |
||
250 | } |
||
251 | |||
252 | //initializes the mesa memory and prepares the textures |
||
253 | void gl_init() |
||
254 | { |
||
255 | GLfloat h = (GLfloat) HEIGHT / (GLfloat) WIDTH; |
||
256 | int r, c; |
||
257 | |||
258 | //Create the OSMesa Context |
||
259 | ctx = OSMesaCreateContext(OSMESA_RGB_565, NULL); |
||
260 | |||
261 | //Set the memory pointed by rgb_565_buf to be the mesa buffer |
||
262 | OSMesaMakeCurrent(ctx, rgb_565_buf, GL_UNSIGNED_SHORT_5_6_5, WIDTH, HEIGHT); |
||
263 | |||
264 | glEnable(GL_DEPTH_TEST); |
||
265 | glDisable( GL_DITHER ); |
||
266 | |||
267 | //Set up texturing |
||
268 | glEnable( GL_TEXTURE_2D ); |
||
269 | glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL ); |
||
270 | glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST ); |
||
271 | |||
272 | /*puts all data contained in the headers in the tex and tex2 structures |
||
273 | using the right order*/ |
||
274 | for(r = 0; r < 256; r++) |
||
275 | for(c = 0; c < 256; c++) |
||
276 | { |
||
277 | tex[r][c][0] = textureR[256*(256-r)+c]; |
||
278 | tex[r][c][1] = textureG[256*(256-r)+c]; |
||
279 | tex[r][c][2] = textureB[256*(256-r)+c]; |
||
280 | tex2[r][c][0] = texture2R[256*(256-r)+c]; |
||
281 | tex2[r][c][1] = texture2G[256*(256-r)+c]; |
||
282 | tex2[r][c][2] = texture2B[256*(256-r)+c]; |
||
283 | |||
284 | } |
||
285 | |||
286 | glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); |
||
287 | glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); |
||
288 | glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); |
||
289 | glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); |
||
290 | |||
291 | //creates the list that define the sphere object |
||
292 | sphere = 1; |
||
293 | glNewList(sphere, GL_COMPILE); |
||
294 | glEnable(GL_TEXTURE_2D); |
||
295 | GLUquadricObj *quadObj = gluNewQuadric (); |
||
296 | gluQuadricTexture(quadObj, GL_TRUE); |
||
297 | gluQuadricDrawStyle(quadObj, GLU_FILL); |
||
298 | gluQuadricNormals(quadObj, GLU_SMOOTH); |
||
299 | glRotated(-90, 1.0, 0.0, 0.0); |
||
300 | gluSphere (quadObj, 3, 30, 30); |
||
301 | glEndList(); |
||
302 | |||
303 | glEnable(GL_NORMALIZE); |
||
304 | |||
305 | //sets mesa(gl) viewport |
||
306 | glViewport(0, 0, (GLint) WIDTH, (GLint) HEIGHT); |
||
307 | glMatrixMode(GL_PROJECTION); |
||
308 | glLoadIdentity(); |
||
309 | //sets the 3d visual volume and the observer point |
||
310 | glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0); |
||
311 | glMatrixMode(GL_MODELVIEW); |
||
312 | glLoadIdentity(); |
||
313 | //places the origin of the axes of the 3d view |
||
314 | glTranslated(0, -1, -40); |
||
315 | |||
316 | radius = 0; |
||
317 | twist = 0; |
||
318 | |||
319 | } |
||
320 | |||
321 | /*Because mesa functions write graphic data on a dedicated buffer (gl buffer) |
||
322 | this buffer once drawn has to be copied on video memory using this task*/ |
||
323 | TASK refresh(void) |
||
324 | { |
||
325 | |||
326 | /* The gl buffer is used only by mesa functions, other graphic |
||
327 | * functions write directly on video memory (es. grx_text, grx_rect,...) |
||
328 | * so the refresh task can not overwrite the first 90 lines of video memory |
||
329 | * used by non mesa functions. |
||
330 | */ |
||
331 | |||
332 | while(1) { |
||
333 | task_testcancel(); |
||
334 | memcpy((video_buf+90*WIDTH*2), rgb_565_buf, RGB565MEM-90*WIDTH*2); |
||
335 | task_endcycle(); |
||
336 | } |
||
337 | |||
338 | sys_end(); |
||
339 | |||
340 | } |
||
341 | |||
342 | /*generates gps-like values to simulate the gps transmitter when it is not connected, |
||
343 | this function is called every time before drawing the image on mesa buffer |
||
344 | if demo mode is on*/ |
||
345 | void demo_val() |
||
346 | { |
||
347 | int ns; |
||
348 | int signal_max[4] = {25, 30, 10, 70}; |
||
349 | int azimuth_max[4] = {170, 10, 60, 100}; |
||
350 | int elevation_max[4] = {10, 60, 30, 79}; |
||
351 | ndemo += 1; |
||
352 | |||
353 | //generates speed |
||
354 | gps_data.speed = 25; |
||
355 | |||
356 | //generates next direction increasing or decreasing the last one using kmov |
||
357 | if(gps_data.dir_mov == 135) |
||
358 | kmov = -1; |
||
359 | if(gps_data.dir_mov == 45) |
||
360 | kmov = 1; |
||
361 | |||
362 | gps_data.dir_mov += kmov; |
||
363 | |||
364 | //generates next latitude and longitude data using direction and speed |
||
365 | demolat += cos(gps_data.dir_mov / (360/(2*M_PI)) ) * (gps_data.speed / 20); |
||
366 | demolon += sin(gps_data.dir_mov / (360/(2*M_PI)) ) * (gps_data.speed / 20); |
||
367 | |||
368 | lat = (int) demolat; |
||
369 | lon = (int) demolon; |
||
370 | |||
371 | /*demolat and demonlon count latitude and longitude from -infinite to |
||
372 | +infinite, but latitude is actually displayed from -90 to +90 |
||
373 | (respectively nord or south) and longitude from -180 to +180 (respectively |
||
374 | east or west) and so you have to convert demolat and demolon data into real |
||
375 | latitude and longitude data before putting them in gps_data structure*/ |
||
376 | |||
377 | if(lon < 0) |
||
378 | lon = 360 - (-lon) % 360; |
||
379 | |||
380 | if(lon % 360 > 180) { |
||
381 | gps_data.longitude = 180 - (lon % 360 - 180); |
||
382 | gps_data.dirlon = 'W'; |
||
383 | } |
||
384 | else { |
||
385 | gps_data.longitude = lon % 360; |
||
386 | gps_data.dirlon = 'E'; |
||
387 | } |
||
388 | |||
389 | if(lat < 0) |
||
390 | lat = 360 - (-lat) % 360; |
||
391 | |||
392 | if(lat % 360 >= 180) { |
||
393 | gps_data.dirlat = 'S'; |
||
394 | if(lat % 360 > 270) |
||
395 | gps_data.latitude = 90 - (lat % 360 - 270); |
||
396 | else { |
||
397 | gps_data.latitude = lat % 360 - 180; |
||
398 | |||
399 | gps_data.longitude = 180 - gps_data.longitude; |
||
400 | if(gps_data.dirlon == 'E') |
||
401 | gps_data.dirlon = 'W'; |
||
402 | else |
||
403 | gps_data.dirlon = 'E'; |
||
404 | } |
||
405 | } |
||
406 | |||
407 | if(lat % 360 < 180) { |
||
408 | gps_data.dirlat = 'N'; |
||
409 | if(lat % 360 > 90) { |
||
410 | gps_data.latitude = 90 - (lat % 360 - 90); |
||
411 | |||
412 | gps_data.longitude = 180 - gps_data.longitude; |
||
413 | if(gps_data.dirlon == 'E') |
||
414 | gps_data.dirlon = 'W'; |
||
415 | else |
||
416 | gps_data.dirlon = 'E'; |
||
417 | } |
||
418 | else |
||
419 | gps_data.latitude = lat % 360; |
||
420 | } |
||
421 | |||
422 | //generates altitude and time |
||
423 | gps_data.altitude = 79; |
||
424 | strcp(gps_data.time, "113024.00"); |
||
425 | |||
426 | //generates the data of the satellites |
||
427 | gps_data.nsat = 4; |
||
428 | |||
429 | for(ns = 0; ns < 4; ns++) { |
||
430 | gps_data.sat_data[ns].id = ns + 20; |
||
431 | gps_data.sat_data[ns].azimuth = ndemo % azimuth_max[ns]; |
||
432 | gps_data.sat_data[ns].elevation = ndemo % elevation_max[ns]; |
||
433 | gps_data.sat_data[ns].signal_level = ndemo % signal_max[ns]; |
||
434 | } |
||
435 | |||
436 | } |
||
437 | |||
438 | //this task draws the whole graphic on video memory and on mesa buffer |
||
439 | TASK draw(void) |
||
440 | { |
||
441 | char text[100]; |
||
442 | TIME draw_TIME, refresh_TIME, gps_TIME; |
||
443 | |||
444 | while(1) { |
||
445 | |||
446 | task_testcancel(); |
||
447 | |||
448 | //if demo mode is on it calls demo_val function to generate gps-like values |
||
449 | if(demo_mode == 1) |
||
450 | demo_val(); |
||
451 | |||
452 | //gets time of execution of all the tasks |
||
453 | jet_gettable(refresh_PID, &refresh_TIME, 1); |
||
454 | jet_gettable(draw_PID, &draw_TIME, 1); |
||
455 | jet_gettable(gps_PID, &gps_TIME, 1); |
||
456 | |||
457 | //displays text informations and graphics using standard functions (grx functions) |
||
458 | |||
459 | //displays the data of the execution times of the tasks |
||
460 | sprintf(text,"Hard Task Refresh PER:%6d us EX:%6d us",(int)PERIOD_REFRESH,(int)refresh_TIME); |
||
461 | grx_text(text,10,55,rgb16(100,100,100),0); |
||
462 | sprintf(text,"Hard Task Draw PER:%6d us EX:%6d us",(int)PERIOD_DRAW,(int)draw_TIME); |
||
463 | |||
464 | //if there is a risk of system crash warns displaying the text in red color |
||
465 | if(draw_TIME > PERIOD_DRAW * 0.65) |
||
466 | grx_text(text,10,65,rgb16(255,0,0),0); |
||
467 | else |
||
468 | grx_text(text,10,65,rgb16(100,100,100),0); |
||
469 | |||
470 | sprintf(text,"Hard Task Gps PER:%6d us EX:%6d us",(int)PERIOD_GPS,(int)gps_TIME); |
||
471 | grx_text(text,10,75,rgb16(100,100,100),0); |
||
472 | |||
473 | //displays data contained in gps_data structure |
||
474 | grx_rect(0, 0, 799, 89, rgb16(0, 0, 250)); |
||
475 | grx_rect(1, 52, 380, 88, rgb16(100, 100, 100)); |
||
476 | |||
477 | grx_text("Current position :",390,5,rgb16(0,255,255),0); |
||
478 | sprintf(text,"Latitude %f dir %c ", gps_data.latitude, gps_data.dirlat); |
||
479 | grx_text(text,390,25,rgb16(0,255,255),0); |
||
480 | sprintf(text,"Longitude %f dir %c ", gps_data.longitude, gps_data.dirlon); |
||
481 | grx_text(text,390,35,rgb16(0,255,255),0); |
||
482 | sprintf(text,"Altitude %f ", gps_data.altitude); |
||
483 | grx_text(text,390,45,rgb16(0,255,255),0); |
||
484 | sprintf(text,"Time %c%c:%c%c:%c%c ", gps_data.time[0], gps_data.time[1], gps_data.time[2], gps_data.time[3], gps_data.time[4], gps_data.time[5]); |
||
485 | grx_text(text,390,55,rgb16(0,255,255),0); |
||
486 | sprintf(text,"Speed %f ", gps_data.speed); |
||
487 | grx_text(text,390,65,rgb16(0,0,255),0); |
||
488 | sprintf(text,"Direction %f ", gps_data.dir_mov); |
||
489 | grx_text(text,390,75,rgb16(0,0,255),0); |
||
490 | |||
491 | //displays satellites data contained in the gps_data structure |
||
492 | grx_text("Satellites in view : ",600,5,rgb16(255,0,0),0); |
||
493 | sprintf(text,"Number of satellites %f ", gps_data.nsat); |
||
494 | grx_text(text,600, 25,rgb16(255,0,0),0); |
||
495 | grx_text("Signal level ", 600, 35,rgb16(255,0,0),0); |
||
496 | |||
497 | for(nlist = 0; nlist < 4; nlist++) |
||
498 | if( gps_data.sat_data[nlist].signal_level > 99) |
||
499 | gps_data.sat_data[nlist].signal_level = 99; |
||
500 | |||
501 | grx_box(600, 45, 700, 80, rgb16(0, 0, 0)); |
||
502 | grx_box(600, 45, 600+gps_data.sat_data[0].signal_level, 50, rgb16(100, 0, 0)); |
||
503 | grx_box(600, 55, 600+gps_data.sat_data[1].signal_level, 60, rgb16(150, 0, 0)); |
||
504 | grx_box(600, 65, 600+gps_data.sat_data[2].signal_level, 70, rgb16(200, 0, 0)); |
||
505 | grx_box(600, 75, 600+gps_data.sat_data[3].signal_level, 80, rgb16(250, 0, 0)); |
||
506 | |||
507 | //displays program title and other informations |
||
508 | grx_text("G P S D E M O", 10, 5, rgb16(0, 255, 0), 0); |
||
509 | grx_text("Esc : end program...",170,5,rgb16(0,255,0),0); |
||
510 | grx_text("t : change texture" ,170,15,rgb16(0,255,0),0); |
||
511 | grx_text("d : demo/gps mode " ,170,25,rgb16(0,255,0),0); |
||
512 | grx_text("a z : zoom near/far " ,170,35,rgb16(0,255,0),0); |
||
513 | if(demo_mode == 1) |
||
514 | grx_text("Demo mode " ,10,25,rgb16(255,255,0),0); |
||
515 | else |
||
516 | grx_text("Gps mode " ,10,25,rgb16(0,255,0),0); |
||
517 | |||
518 | |||
519 | //displays mesa graphic |
||
520 | int nmax; |
||
521 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
||
522 | |||
523 | //selects and activates the correct texture |
||
524 | if(sel_texture == 1) |
||
525 | glTexImage2D( GL_TEXTURE_2D, 0, 3, 256, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, tex ); |
||
526 | else |
||
527 | glTexImage2D( GL_TEXTURE_2D, 0, 3, 256, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, tex2 ); |
||
528 | |||
529 | //draws the sphere calling the appropriate list defined in gl_init function |
||
530 | glPushMatrix(); |
||
531 | polarView(); |
||
532 | glCallList(sphere); |
||
533 | glPopMatrix(); |
||
534 | |||
535 | //draws the arrow and the cross on the sphere |
||
536 | glPushMatrix(); |
||
537 | glTranslated (0, 0, zoom); |
||
538 | glDisable(GL_TEXTURE_2D); |
||
539 | glColor3f (0, 1, 1); |
||
540 | glTranslated (0, 0, 6); |
||
541 | glRotated(180 + gps_data.dir_mov, 0.0, 0.0, 1.0); |
||
542 | glLineWidth (2.0); |
||
543 | glBegin(GL_LINES); |
||
544 | glVertex2f(-0.2, 0.2); |
||
545 | glVertex2f(0.2, -0.2); |
||
546 | glVertex2f(0.2, 0.2); |
||
547 | glVertex2f(-0.2, -0.2); |
||
548 | glColor3f (0, 0, 1); |
||
549 | glVertex2f(0, 0); |
||
550 | glVertex2f(0, gps_data.speed/30); |
||
551 | glVertex2f(0, gps_data.speed/30); |
||
552 | glVertex2f(0.2, gps_data.speed/30-0.2); |
||
553 | glVertex2f(0, gps_data.speed/30); |
||
554 | glVertex2f(-0.2, gps_data.speed/30-0.2); |
||
555 | glEnd(); |
||
556 | glColor3f (0, 0, 0.3); |
||
557 | glTranslated (0.05, 0.05, 0); |
||
558 | glBegin(GL_LINES); |
||
559 | glVertex2f(-0.2, 0.2); |
||
560 | glVertex2f(0.2, -0.2); |
||
561 | glVertex2f(0.2, 0.2); |
||
562 | glVertex2f(-0.2, -0.2); |
||
563 | glVertex2f(0, 0); |
||
564 | glVertex2f(0, gps_data.speed/30); |
||
565 | glVertex2f(0, gps_data.speed/30); |
||
566 | glVertex2f(0.2, gps_data.speed/30-0.2); |
||
567 | glVertex2f(0, gps_data.speed/30); |
||
568 | glVertex2f(-0.2, gps_data.speed/30-0.2); |
||
569 | glEnd(); |
||
570 | glPopMatrix(); |
||
571 | |||
572 | //draws sattellites in view using azimuth and elevation data |
||
573 | if(gps_data.nsat < 4) //this function can draw four satellites at maximum |
||
574 | nmax = gps_data.nsat; |
||
575 | else |
||
576 | nmax = 4; |
||
577 | |||
578 | for(nlist = 0; nlist < nmax; nlist++) { |
||
579 | glPushMatrix(); |
||
580 | glDisable(GL_TEXTURE_2D); |
||
581 | glColor3f (0.4+0.2*nlist, 0, 0); |
||
582 | glLineWidth (2.0); |
||
583 | glRotated(gps_data.sat_data[nlist].azimuth, 0.0, 0.0, 1.0); |
||
584 | glTranslated (0, 0, 3 + zoom); |
||
585 | glRotated(90 - gps_data.sat_data[nlist].elevation, 1.0, 0.0, 0.0); |
||
586 | glTranslated (0, 0, 4); |
||
587 | glBegin(GL_LINES); |
||
588 | glVertex2f(-0.1, -0.1); |
||
589 | glVertex2f(0.1, 0.1); |
||
590 | glVertex2f(-0.1, 0.1); |
||
591 | glVertex2f(0.1, -0.1); |
||
592 | glEnd(); |
||
593 | glPopMatrix(); |
||
594 | } |
||
595 | |||
596 | glFinish(); |
||
597 | |||
598 | task_endcycle(); |
||
599 | |||
600 | } |
||
601 | |||
602 | sys_end(); |
||
603 | } |
||
604 | |||
605 | /*This task reads the data from the gps transmitter using the polling system. |
||
606 | Gps sends data with a rate of 4800 bit/s this means 1 byte every 1.6 ms. |
||
607 | If you want to be sure to get all the bytes transmitted by the gps you have |
||
608 | to choose a period <1.6 ms for this gps task, in this program the period is |
||
609 | 1000ns or 1ms.*/ |
||
610 | |||
611 | TASK gps(void) |
||
612 | { |
||
613 | char c; |
||
614 | while(1) { |
||
615 | task_testcancel(); |
||
616 | //if a character is present on COM1 |
||
617 | if((com_read(COM1,LSR) & 1) == 1) { |
||
618 | //reads and stores it in c |
||
619 | c = com_read(COM1,RBR); |
||
620 | |||
621 | //if c is a word delimiter |
||
622 | if( (c == ',') || (c == '\n') || (c == '*') || (c == '\0') ) { |
||
623 | |||
624 | //ends the current word and resets the word index |
||
625 | word[ind] = '\0'; |
||
626 | ind = 0; |
||
627 | |||
628 | //decodes the word variable |
||
629 | |||
630 | //if word is a label that identifies the beginning of a gpgga string |
||
631 | if( streq(word, "$GPGGA") == 1 ) |
||
632 | ind_gpgga = 0; //resets the gpgga index |
||
633 | |||
634 | /*decodes the word depending on the gpgga index that identifies |
||
635 | the position of the word just read in the gpgga string. |
||
636 | then the word decoded is stored in the gps_data structure.*/ |
||
637 | switch(ind_gpgga) { |
||
638 | case 1 : strcp(gps_data.time, word); |
||
639 | break; |
||
640 | case 2 : gps_data.latitude = strtof(word) * 0.01; |
||
641 | break; |
||
642 | case 3 : gps_data.dirlat = word[0]; |
||
643 | break; |
||
644 | case 4 : gps_data.longitude = strtof(word) * 0.1; |
||
645 | break; |
||
646 | case 5 : gps_data.dirlon = word[0]; |
||
647 | break; |
||
648 | case 9 : gps_data.altitude = strtof(word); |
||
649 | } |
||
650 | |||
651 | //if the string is not ended increases the gpgga word counter |
||
652 | if(ind_gpgga <= 14) |
||
653 | ind_gpgga++; |
||
654 | |||
655 | //the same for gpgsv string |
||
656 | if( streq(word, "$GPGSV") == 1 ) |
||
657 | ind_gpgsv = 0; |
||
658 | |||
659 | switch(ind_gpgsv) { |
||
660 | case 3 : gps_data.nsat = strtof(word); |
||
661 | break; |
||
662 | case 4 : gps_data.sat_data[0].id = strtof(word); |
||
663 | break; |
||
664 | case 5 : gps_data.sat_data[0].elevation = strtof(word); |
||
665 | break; |
||
666 | case 6 : gps_data.sat_data[0].azimuth = strtof(word); |
||
667 | break; |
||
668 | case 7 : gps_data.sat_data[0].signal_level = strtof(word); |
||
669 | break; |
||
670 | case 8 : gps_data.sat_data[1].id = strtof(word); |
||
671 | break; |
||
672 | case 9 : gps_data.sat_data[1].elevation = strtof(word); |
||
673 | break; |
||
674 | case 10 : gps_data.sat_data[1].azimuth = strtof(word); |
||
675 | break; |
||
676 | case 11 : gps_data.sat_data[1].signal_level = strtof(word); |
||
677 | break; |
||
678 | case 12 : gps_data.sat_data[2].id = strtof(word); |
||
679 | break; |
||
680 | case 13 : gps_data.sat_data[2].elevation = strtof(word); |
||
681 | break; |
||
682 | case 14 : gps_data.sat_data[2].azimuth = strtof(word); |
||
683 | break; |
||
684 | case 15 : gps_data.sat_data[2].signal_level = strtof(word); |
||
685 | break; |
||
686 | case 16 : gps_data.sat_data[3].id = strtof(word); |
||
687 | break; |
||
688 | case 17 : gps_data.sat_data[3].elevation = strtof(word); |
||
689 | break; |
||
690 | case 18 : gps_data.sat_data[3].azimuth = strtof(word); |
||
691 | break; |
||
692 | case 19 : gps_data.sat_data[3].signal_level = strtof(word); |
||
693 | } |
||
694 | |||
695 | if(ind_gpgsv <= 20) |
||
696 | ind_gpgsv++; |
||
697 | |||
698 | //the same for gprmc string |
||
699 | if( streq(word, "$GPRMC") == 1 ) |
||
700 | ind_gprmc = 0; |
||
701 | |||
702 | switch(ind_gprmc) { |
||
703 | case 1 : strcp(gps_data.time, word); |
||
704 | break; |
||
705 | case 3 : gps_data.latitude = strtof(word) * 0.01; |
||
706 | break; |
||
707 | case 4 : gps_data.dirlat = word[0]; |
||
708 | break; |
||
709 | case 5 : gps_data.longitude = strtof(word) * 0.1; |
||
710 | break; |
||
711 | case 6 : gps_data.dirlon = word[0]; |
||
712 | break; |
||
713 | case 7 : gps_data.speed = strtof(word); |
||
714 | break; |
||
715 | case 8 : gps_data.dir_mov = strtof(word); |
||
716 | break; |
||
717 | case 9 : gps_data.date = strtof(word); |
||
718 | break; |
||
719 | case 10 : gps_data.var_mov = strtof(word); |
||
720 | break; |
||
721 | case 11 : gps_data.dir_var_mov = word[0]; |
||
722 | } |
||
723 | |||
724 | if(ind_gprmc <= 11) |
||
725 | ind_gprmc++; |
||
726 | |||
727 | } |
||
728 | //if c is not a word delimiter |
||
729 | else { |
||
730 | //store it in word at ind position and increase the index ind |
||
731 | word[ind] = c; |
||
732 | ind++; |
||
733 | } |
||
734 | } |
||
735 | task_endcycle(); |
||
736 | } |
||
737 | |||
738 | sys_end(); |
||
739 | |||
740 | } |
||
741 | |||
742 | //is called just before program ends |
||
743 | void program_key_end(KEY_EVT *k) |
||
744 | { |
||
745 | free(rgb_565_buf); //free the mesa buffer |
||
746 | sys_end(); |
||
747 | } |
||
748 | |||
749 | //is called when t key is pressed and changes the texture to be displayed on the sphere |
||
750 | void program_key_texture(KEY_EVT *k2) |
||
751 | { |
||
752 | if(sel_texture == 1) |
||
753 | sel_texture = 2; |
||
754 | else |
||
755 | sel_texture = 1; |
||
756 | } |
||
757 | |||
758 | //is called when d key is pressed and changes from demo to gps mode and vice versa |
||
759 | void program_key_demo(KEY_EVT *k3) |
||
760 | { |
||
761 | if(demo_mode == 0) |
||
762 | demo_mode = 1; |
||
763 | else |
||
764 | demo_mode = 0; |
||
765 | ndemo = 0; |
||
766 | kmov = -1; |
||
767 | lat = 0; |
||
768 | lon = 0; |
||
769 | demolat = 0; |
||
770 | demolon = 0; |
||
771 | gps_data.dirlat = 'N'; |
||
772 | gps_data.dirlon = 'E'; |
||
773 | gps_data.latitude = 0; |
||
774 | gps_data.longitude = 0; |
||
775 | gps_data.dir_mov = 90; |
||
776 | } |
||
777 | |||
778 | //is called when a key is pressed and increases the zoom factor |
||
779 | void program_key_near(KEY_EVT *k4) |
||
780 | { |
||
781 | zoom += 0.7; |
||
782 | } |
||
783 | |||
784 | //is called when a key is pressed and decreases the zoom factor |
||
785 | void program_key_far(KEY_EVT *k5) |
||
786 | { |
||
787 | zoom -= 0.7; |
||
788 | } |
||
789 | |||
790 | int main (int argc, char *argv[]) |
||
791 | { |
||
792 | |||
793 | HARD_TASK_MODEL ht_refresh, ht_draw, ht_gps; |
||
794 | |||
795 | //sets deadline for the tasks |
||
796 | WCET_REFRESH =(int)((float) PERIOD_REFRESH * (0.22)); |
||
797 | WCET_DRAW =(int)((float) PERIOD_DRAW * (0.70)); |
||
798 | WCET_GPS =(int)((float) PERIOD_GPS * (0.05)); |
||
799 | |||
800 | //prepares refresh task for activation |
||
801 | hard_task_default_model(ht_refresh); |
||
802 | hard_task_def_wcet(ht_refresh,WCET_REFRESH); |
||
803 | hard_task_def_mit(ht_refresh,PERIOD_REFRESH); |
||
804 | hard_task_def_usemath(ht_refresh); |
||
805 | hard_task_def_group(ht_refresh,1); |
||
806 | hard_task_def_ctrl_jet(ht_refresh); |
||
807 | |||
808 | refresh_PID = task_create("refresh", refresh, &ht_refresh, NULL); |
||
809 | if (refresh_PID == -1) { |
||
810 | sys_end(); |
||
811 | return 0; |
||
812 | } |
||
813 | |||
814 | //prepares draw task for activation |
||
815 | hard_task_default_model(ht_draw); |
||
816 | hard_task_def_mit(ht_draw,PERIOD_DRAW); |
||
817 | hard_task_def_wcet(ht_draw,WCET_DRAW); |
||
818 | hard_task_def_group(ht_draw,1); |
||
819 | hard_task_def_ctrl_jet(ht_draw); |
||
820 | hard_task_def_usemath(ht_draw); |
||
821 | hard_task_def_stack(ht_draw,35000); //VERY IMPORTANT FOR glCallList !! |
||
822 | |||
823 | draw_PID = task_create("draw", draw, &ht_draw, NULL); |
||
824 | if (draw_PID == -1) { |
||
825 | sys_end(); |
||
826 | return 0; |
||
827 | } |
||
828 | |||
829 | //prepares gps task for activation |
||
830 | hard_task_default_model(ht_gps); |
||
831 | hard_task_def_wcet(ht_gps,WCET_GPS); |
||
832 | hard_task_def_mit(ht_gps,PERIOD_GPS); |
||
833 | hard_task_def_usemath(ht_gps); |
||
834 | hard_task_def_group(ht_gps,1); |
||
835 | hard_task_def_ctrl_jet(ht_gps); |
||
836 | |||
837 | gps_PID = task_create("gps", gps, &ht_gps, NULL); |
||
838 | if (gps_PID == -1) { |
||
839 | sys_end(); |
||
840 | return 0; |
||
841 | } |
||
842 | |||
843 | //defines and activates all the keyboard events used in the program |
||
844 | { |
||
845 | KEY_EVT k; |
||
846 | k.scan = KEY_ESC; |
||
847 | k.ascii = 27; |
||
848 | k.status = KEY_PRESSED; |
||
849 | keyb_hook(k,program_key_end,FALSE); |
||
850 | } |
||
851 | |||
852 | { |
||
853 | KEY_EVT k2; |
||
854 | k2.scan = KEY_T; |
||
855 | k2.ascii = 't'; |
||
856 | k2.status = KEY_PRESSED; |
||
857 | keyb_hook(k2,program_key_texture,FALSE); |
||
858 | } |
||
859 | |||
860 | { |
||
861 | KEY_EVT k3; |
||
862 | k3.scan = KEY_D; |
||
863 | k3.ascii = 'd'; |
||
864 | k3.status = KEY_PRESSED; |
||
865 | keyb_hook(k3,program_key_demo,FALSE); |
||
866 | } |
||
867 | |||
868 | { |
||
869 | KEY_EVT k4; |
||
870 | k4.scan = KEY_A; |
||
871 | k4.ascii = 'a'; |
||
872 | k4.status = KEY_PRESSED; |
||
873 | keyb_hook(k4,program_key_near,FALSE); |
||
874 | } |
||
875 | |||
876 | { |
||
877 | KEY_EVT k5; |
||
878 | k5.scan = KEY_Z; |
||
879 | k5.ascii = 'z'; |
||
880 | k5.status = KEY_PRESSED; |
||
881 | keyb_hook(k5,program_key_far,FALSE); |
||
882 | } |
||
883 | |||
884 | //allocates memory for mesa functions (mesa buffer) |
||
885 | rgb_565_buf = malloc(RGB565MEM); |
||
886 | |||
887 | //puts in a pointer the address of video memory |
||
888 | video_buf = (unsigned char *)video_memory; |
||
889 | |||
890 | //initializes mesa functions and prepares textures |
||
891 | gl_init(); |
||
892 | |||
893 | //clears mesa buffer |
||
894 | memset(rgb_565_buf, 0, RGB565MEM); |
||
895 | |||
896 | //clears screen (video memory) |
||
897 | grx_box(0, 0, 1023, 89, rgb16(0, 0, 0)); |
||
898 | |||
899 | //resets the word variable |
||
900 | word[0] = '\0'; |
||
901 | |||
902 | //activates COM1 port to receive data from a gps transmitter |
||
903 | open_com(COM1,4800,NONE,8,0); |
||
904 | |||
905 | //activates the tasks previously created and prepared (draw, refresh, gps) |
||
906 | group_activate(1); |
||
907 | |||
908 | return 0; |
||
909 | |||
910 | } |