PageRenderTime 28ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/evadeo-statnav.c

https://github.com/jedisct1/evadeo-tools
C | 956 lines | 880 code | 75 blank | 1 comment | 86 complexity | 04e1211b7724532b4b05c355945694ae MD5 | raw file
Possible License(s): 0BSD
  1. #define COBJMACROS 1
  2. #include <windows.h>
  3. #include <winable.h>
  4. #include <ntdef.h>
  5. #include <winreg.h>
  6. #include <shellapi.h>
  7. #include <commctrl.h>
  8. #include <unistd.h>
  9. #include <stdlib.h>
  10. #include <stdio.h>
  11. #include <time.h>
  12. #include <winuser.h>
  13. #define STATNAV 1
  14. #define EPHEMERIS_NUMBER 32
  15. #define POWER_MASK 20
  16. #define FRAME_RATE (1000 / 2)
  17. extern VOID ForcePageout(void);
  18. static HWND h_test;
  19. static UINT timer = 0;
  20. static HANDLE global_hcom;
  21. typedef struct MinDecCoord_ {
  22. int deg;
  23. int min;
  24. int dec;
  25. } MinDecCoord;
  26. static MinDecCoord coord_dec_to_mindec(const double a)
  27. {
  28. MinDecCoord mindec;
  29. double min_f;
  30. mindec.deg = (int) a;
  31. min_f = (a - mindec.deg) * 60.0;
  32. mindec.min = (int) min_f;
  33. mindec.dec = ((min_f - mindec.min + 0.0005) * 1000);
  34. return mindec;
  35. }
  36. static MinDecCoord coord_nmea_to_mindec(const double a)
  37. {
  38. MinDecCoord mindec;
  39. double min_f;
  40. mindec.deg = (int) a / 100;
  41. mindec.min = (int) a % 100;
  42. min_f = a - (int) a;
  43. mindec.dec = ((min_f + 0.0005) * 1000);
  44. return mindec;
  45. }
  46. static size_t strlcpy(char *dst, const char *src, size_t siz)
  47. {
  48. char *d = dst;
  49. const char *s = src;
  50. size_t n = siz;
  51. if (n != 0) {
  52. while (--n != 0) {
  53. if ((*d++ = *s++) == '\0')
  54. break;
  55. }
  56. }
  57. if (n == 0) {
  58. if (siz != 0) {
  59. *d = 0;
  60. }
  61. while (*s++);
  62. }
  63. return s - src - 1;
  64. }
  65. static char *tokenize(char *str, int chr_)
  66. {
  67. static char *part;
  68. static int chr;
  69. char *oldpart;
  70. char *sep;
  71. if (str == NULL) {
  72. return NULL;
  73. }
  74. if (chr_ != 0) {
  75. chr = chr_;
  76. part = str;
  77. }
  78. if (*part == 0) {
  79. return "";
  80. }
  81. oldpart = part;
  82. if ((sep = strchr(part, chr)) != NULL) {
  83. *sep = 0;
  84. part = sep + 1;
  85. } else {
  86. part = "";
  87. }
  88. return oldpart;
  89. }
  90. static double tokenize_double(char *str)
  91. {
  92. return atof(tokenize(str, 0));
  93. }
  94. static WCHAR *tokenize_string(char *str)
  95. {
  96. char *tokenized;
  97. static WCHAR wstr[2000];
  98. tokenized = tokenize(str, 0);
  99. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, tokenized, -1, wstr, sizeof wstr);
  100. return wstr;
  101. }
  102. static int tokenize_int(char *str)
  103. {
  104. return (int) strtol(tokenize(str, 0), NULL, 0);
  105. }
  106. typedef double Coord;
  107. typedef enum FixQuality_ {
  108. FQ_INVALID = 0,
  109. FQ_GPS = 1,
  110. FQ_DGPS = 2,
  111. FQ_PPS = 3,
  112. FQ_RTK = 4,
  113. FQ_FLOAT = 5,
  114. FQ_ESTIMATED = 6,
  115. FQ_MANUAL = 7,
  116. FQ_SIMULATION = 8
  117. } FixQuality;
  118. typedef enum TridiFix_ {
  119. TDFX_NOFIX = 1,
  120. TDFX_2D = 2,
  121. TDFX_3D = 3
  122. } TridiFix;
  123. typedef struct GPStatus_ {
  124. BOOL initialized;
  125. Coord lat;
  126. WCHAR lat_dir[4];
  127. Coord lon;
  128. WCHAR lon_dir[4];
  129. FixQuality fix_quality;
  130. int tracked_sat_count;
  131. double hdop;
  132. double vdop;
  133. int altitude;
  134. time_t dgps_since;
  135. int dgps_station_id;
  136. TridiFix tridifix;
  137. int useful_sat_count;
  138. int time_valid_flag;
  139. int tow;
  140. int found_ephemeris;
  141. unsigned int decibels;
  142. unsigned int masked_decibels;
  143. Coord avg_total_lat;
  144. Coord avg_total_lon;
  145. long avg_lonlat_counts;
  146. long int avg_total_altitude;
  147. long avg_altitude_counts;
  148. } GPStatus;
  149. static GPStatus gpstatus;
  150. int nmea_cb_gpgga(char *sentence)
  151. {
  152. char *str;
  153. WCHAR *wstr;
  154. tokenize_int(sentence); /* fix_date */
  155. str = tokenize(sentence, 0);
  156. if (*str != 0) {
  157. gpstatus.lat = atof(str);
  158. }
  159. wstr = tokenize_string(sentence);
  160. if (wcslen(wstr) > 0) {
  161. _snwprintf(gpstatus.lat_dir, sizeof gpstatus.lat_dir, L"%s", wstr);
  162. }
  163. str = tokenize(sentence, 0);
  164. if (*str != 0) {
  165. gpstatus.lon = atof(str);
  166. }
  167. wstr = tokenize_string(sentence);
  168. if (wcslen(wstr) > 0) {
  169. _snwprintf(gpstatus.lon_dir, sizeof gpstatus.lon_dir, L"%s", wstr);
  170. }
  171. gpstatus.fix_quality = tokenize_int(sentence);
  172. gpstatus.tracked_sat_count = tokenize_int(sentence);
  173. gpstatus.hdop = tokenize_double(sentence);
  174. gpstatus.altitude = (int) (tokenize_double(sentence) + 0.5);
  175. tokenize_string(sentence); /* unité */
  176. tokenize_double(sentence); /* geoid separation */
  177. tokenize_string(sentence); /* unité */
  178. gpstatus.dgps_since = tokenize_int(sentence);
  179. gpstatus.dgps_station_id = tokenize_int(sentence);
  180. return 0;
  181. }
  182. int nmea_cb_gpgsa(char *sentence)
  183. {
  184. int sats = 0;
  185. int sat_count = 12;
  186. tokenize_string(sentence); /* auto-selection */
  187. gpstatus.tridifix = tokenize_int(sentence);
  188. do {
  189. if (*(tokenize(sentence, 0)) != 0) {
  190. sats++;
  191. }
  192. } while (--sat_count != 0);
  193. gpstatus.useful_sat_count = sats;
  194. tokenize_double(sentence); /* pdop */
  195. tokenize_double(sentence); /* hdop */
  196. gpstatus.vdop = tokenize_double(sentence);
  197. return 0;
  198. }
  199. int nmea_cb_psrf151(char *sentence)
  200. {
  201. unsigned int ephemeris;
  202. int missing_ephemeris = 0;
  203. int bits = 32;
  204. gpstatus.time_valid_flag = tokenize_int(sentence);
  205. tokenize_int(sentence); /* week number */
  206. gpstatus.tow = tokenize_int(sentence);
  207. ephemeris = (unsigned int) tokenize_int(sentence);
  208. do {
  209. if ((ephemeris & 31) != 0) {
  210. missing_ephemeris++;
  211. }
  212. ephemeris <<= 1;
  213. } while (--bits != 0);
  214. if (missing_ephemeris > EPHEMERIS_NUMBER) {
  215. missing_ephemeris = EPHEMERIS_NUMBER;
  216. }
  217. gpstatus.found_ephemeris = EPHEMERIS_NUMBER - missing_ephemeris;
  218. return 0;
  219. }
  220. int nmea_cb_gpgsv(char *sentence)
  221. {
  222. static unsigned int decibels = 0U;
  223. static unsigned int masked_decibels = 0U;
  224. int nb;
  225. int total_nb;
  226. int sats_per_sentence = 4;
  227. unsigned int snr;
  228. total_nb = tokenize_int(sentence); /* number of sentences */
  229. nb = tokenize_int(sentence);
  230. tokenize_int(sentence); /* number of stats in view */
  231. if (nb < 2) {
  232. decibels = 0U;
  233. masked_decibels = 0U;
  234. }
  235. do {
  236. tokenize_int(sentence); /* PRN */
  237. tokenize_int(sentence); /* elevation */
  238. tokenize_int(sentence); /* azimuth */
  239. snr = (unsigned int) tokenize_int(sentence);
  240. if (snr > 100) {
  241. snr = 100;
  242. }
  243. decibels += snr;
  244. if (snr > POWER_MASK) {
  245. masked_decibels += snr;
  246. }
  247. } while (--sats_per_sentence != 0);
  248. if (total_nb == nb) {
  249. gpstatus.decibels = decibels;
  250. gpstatus.masked_decibels = masked_decibels;
  251. }
  252. return 0;
  253. }
  254. typedef int (*NmeaCallback)(char *str);
  255. typedef struct NmeaSentence_ {
  256. const char *keyword;
  257. NmeaCallback callback;
  258. } NmeaSentence;
  259. NmeaSentence nmea_sentences[] = {
  260. { "$GPGGA", nmea_cb_gpgga },
  261. { "$GPGSA", nmea_cb_gpgsa },
  262. { "$PSRF151", nmea_cb_psrf151 },
  263. { "$GPGSV", nmea_cb_gpgsv },
  264. { NULL, (NmeaCallback) NULL }
  265. };
  266. static BOOL wait_any_data(HANDLE hcom)
  267. {
  268. CHAR k[8192];
  269. DWORD readen;
  270. ReadFile(hcom, k, sizeof k - 1, &readen, NULL);
  271. PurgeComm(hcom, PURGE_RXCLEAR);
  272. /* PSRF154 */
  273. return TRUE;
  274. }
  275. static BOOL send_nmea_command(HANDLE hcom, const char *cmd)
  276. {
  277. char strbuf[1000];
  278. DWORD written;
  279. DWORD length;
  280. unsigned char cksum = 0U;
  281. unsigned char c;
  282. const char *pnt = cmd;
  283. while ((c = (unsigned char) *pnt++) != 0) {
  284. cksum ^= c;
  285. }
  286. _snprintf(strbuf, sizeof strbuf, "$%s*%02X\r\n", cmd, cksum);
  287. length = strlen(strbuf);
  288. WriteFile(hcom, strbuf, length, &written, NULL);
  289. for (;;) {
  290. if (written != length) {
  291. Sleep(1000);
  292. wait_any_data(hcom);
  293. continue;
  294. }
  295. break;
  296. }
  297. FlushFileBuffers(hcom);
  298. return TRUE;
  299. }
  300. static BOOL send_sirf_command(HANDLE hcom, const unsigned char *cmd,
  301. const size_t length)
  302. {
  303. unsigned char strbuf[1000];
  304. unsigned char *pnts = strbuf;
  305. WORD cksum = 0U;
  306. size_t t = 0U;
  307. unsigned char c;
  308. DWORD written;
  309. DWORD size;
  310. if (length > sizeof strbuf - 8U) {
  311. return FALSE;
  312. }
  313. *pnts++ = 0xa0;
  314. *pnts++ = 0xa2;
  315. *pnts++ = length >> 8;
  316. *pnts++ = length & 0xff;
  317. do {
  318. c = *cmd++;
  319. cksum += (WORD) c;
  320. *pnts++ = c;
  321. } while (++t != length);
  322. cksum &= 0x7fff;
  323. *pnts++ = cksum >> 8;
  324. *pnts++ = cksum & 0xff;
  325. *pnts++ = 0xb0;
  326. *pnts++ = 0xb3;
  327. size = pnts - strbuf;
  328. for (;;) {
  329. WriteFile(hcom, strbuf, size, &written, NULL);
  330. if (written != size) {
  331. Sleep(1000);
  332. wait_any_data(hcom);
  333. continue;
  334. }
  335. break;
  336. }
  337. FlushFileBuffers(hcom);
  338. return TRUE;
  339. }
  340. static HANDLE open_port(const WCHAR **ports_list)
  341. {
  342. const WCHAR **port = ports_list;
  343. HANDLE hcom;
  344. DCB dcb;
  345. do {
  346. hcom = CreateFile(*port, GENERIC_READ | GENERIC_WRITE,
  347. 0, NULL, OPEN_EXISTING, 0, NULL);
  348. if (hcom == INVALID_HANDLE_VALUE) {
  349. continue;
  350. }
  351. if (!GetCommState(hcom, &dcb)) {
  352. CloseHandle(hcom);
  353. hcom = INVALID_HANDLE_VALUE;
  354. continue;
  355. }
  356. dcb.DCBlength = sizeof dcb;
  357. dcb.BaudRate = 57600;
  358. dcb.fBinary = TRUE;
  359. dcb.fParity = TRUE;
  360. dcb.fOutxCtsFlow = FALSE;
  361. dcb.fOutxDsrFlow = FALSE;
  362. dcb.fDtrControl = DTR_CONTROL_ENABLE;
  363. dcb.fTXContinueOnXoff = TRUE;
  364. dcb.fOutX = FALSE;
  365. dcb.fInX = FALSE;
  366. dcb.fErrorChar = FALSE;
  367. dcb.fNull = FALSE;
  368. dcb.fRtsControl = RTS_CONTROL_DISABLE;
  369. dcb.fAbortOnError = TRUE;
  370. dcb.ByteSize = 8;
  371. dcb.Parity = NOPARITY;
  372. dcb.StopBits = ONESTOPBIT;
  373. if (!SetCommState(hcom, &dcb)) {
  374. CloseHandle(hcom);
  375. hcom = INVALID_HANDLE_VALUE;
  376. continue;
  377. }
  378. PurgeComm(hcom, PURGE_RXCLEAR);
  379. PurgeComm(hcom, PURGE_TXCLEAR);
  380. break;
  381. } while (*++port != NULL);
  382. return hcom;
  383. }
  384. static BOOL setup_sirf(const WCHAR **ports_list, BOOL statnav)
  385. {
  386. WCHAR strbuf[1000];
  387. MSG msg;
  388. HANDLE hcom;
  389. hcom = open_port(ports_list);
  390. if (hcom == INVALID_HANDLE_VALUE) {
  391. MessageBox(NULL, L"Impossible d'acceder a la puce SiRF",
  392. TEXT("Evadeo StatNav"), MB_OK);
  393. return FALSE;
  394. }
  395. #if 1
  396. _snwprintf(strbuf, sizeof strbuf, L"Configuration de la Puce SiRF");
  397. SendMessage(h_test, WM_SETTEXT, 0, (LPARAM) strbuf);
  398. if (GetMessageW(&msg, NULL, 0, 0)) {
  399. TranslateMessage(&msg);
  400. DispatchMessageW(&msg);
  401. }
  402. #endif
  403. #if 0
  404. {
  405. CHAR k[1000];
  406. WCHAR wk[1000];
  407. DWORD readen;
  408. ReadFile(hcom, k, sizeof k - 1, &readen, NULL);
  409. k[readen] = 0;
  410. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, k, -1, wk, sizeof wk);
  411. }
  412. #endif
  413. wait_any_data(hcom);
  414. #if 1
  415. send_nmea_command(hcom, "PSRF151,01");
  416. send_nmea_command(hcom, "PSRF108,01");
  417. #endif
  418. send_nmea_command(hcom, "PSRF100,0,57600,8,1,0");
  419. Sleep(100);
  420. send_nmea_command(hcom, "PSRF100,0,57600,8,1,0");
  421. Sleep(100);
  422. send_nmea_command(hcom, "PSRF100,0,57600,8,1,0");
  423. Sleep(100);
  424. {
  425. const unsigned char sc_nop[] = {
  426. 0x00
  427. };
  428. send_sirf_command(hcom, sc_nop, sizeof sc_nop);
  429. }
  430. {
  431. const unsigned char sc_enable_sbas[] = {
  432. 0x85,
  433. 0x01,
  434. 0x00, 0x00, 0x00, 0x00,
  435. 0x00 };
  436. send_sirf_command(hcom, sc_enable_sbas, sizeof sc_enable_sbas);
  437. }
  438. {
  439. const unsigned char sc_enable_static_mode[] = {
  440. 0x8F, 0x01
  441. };
  442. const unsigned char sc_disable_static_mode[] = {
  443. 0x8F, 0x00
  444. };
  445. if (statnav == TRUE) {
  446. send_sirf_command(hcom, sc_enable_static_mode, sizeof sc_enable_static_mode);
  447. } else {
  448. send_sirf_command(hcom, sc_disable_static_mode, sizeof sc_disable_static_mode);
  449. }
  450. }
  451. #if 1
  452. {
  453. const unsigned char sc_back_to_nmea[] = {
  454. 0x81, 0x02, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
  455. 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01,
  456. 0xE1, 0x00 /* 57600 */
  457. };
  458. send_sirf_command(hcom, sc_back_to_nmea, sizeof sc_back_to_nmea);
  459. send_sirf_command(hcom, sc_back_to_nmea, sizeof sc_back_to_nmea);
  460. send_sirf_command(hcom, sc_back_to_nmea, sizeof sc_back_to_nmea);
  461. }
  462. #endif
  463. send_nmea_command(hcom, "PSRF103,0,0,0,1");
  464. send_nmea_command(hcom, "PSRF103,4,0,1,1");
  465. send_nmea_command(hcom, "PSRF103,0,0,1,1");
  466. send_nmea_command(hcom, "PSRF103,2,0,1,1");
  467. send_nmea_command(hcom, "PSRF103,3,0,1,1");
  468. wait_any_data(hcom);
  469. CloseHandle(hcom);
  470. #if 1
  471. _snwprintf(strbuf, sizeof strbuf, L"Puce SiRF configurée");
  472. SendMessage(h_test, WM_SETTEXT, 0, (LPARAM) strbuf);
  473. if (GetMessageW(&msg, NULL, 0, 0)) {
  474. TranslateMessage(&msg);
  475. DispatchMessageW(&msg);
  476. }
  477. #endif
  478. return TRUE;
  479. }
  480. static BOOL parse_nmea_messages(HANDLE hcom)
  481. {
  482. char serbuf[8192];
  483. DWORD readen;
  484. char *serbuf_p = serbuf;
  485. char sentence[4096];
  486. char *tok;
  487. size_t sentence_len;
  488. NmeaSentence *scanned_nmea_sentence;
  489. char *keyword;
  490. char *sep;
  491. if (ReadFile(hcom, serbuf, sizeof serbuf - 1U, &readen, NULL) == FALSE) {
  492. return FALSE;
  493. }
  494. serbuf[readen] = 0;
  495. gpstatus.initialized = TRUE;
  496. while (*serbuf_p != 0) {
  497. tok = strchr(serbuf_p, '\r');
  498. if (tok == NULL) {
  499. sentence_len = strlen(serbuf_p);
  500. } else {
  501. sentence_len = (size_t) (tok - serbuf);
  502. }
  503. if (sentence_len > sizeof sentence) {
  504. goto next;
  505. }
  506. if (tok != NULL) {
  507. *tok = 0;
  508. }
  509. memcpy(sentence, serbuf_p, sentence_len + 1);
  510. scanned_nmea_sentence = nmea_sentences;
  511. if ((sep = strrchr(sentence, '*')) != NULL) {
  512. *sep = 0;
  513. }
  514. #if 0
  515. {
  516. FILE *fp = fopen("\\Evadeo\\position.log", "a");
  517. fprintf(fp, "[%s]\n", sentence);
  518. fclose(fp);
  519. }
  520. #endif
  521. keyword = tokenize(sentence, ',');
  522. do {
  523. if (strcasecmp(scanned_nmea_sentence->keyword, keyword) == 0) {
  524. scanned_nmea_sentence->callback(sentence);
  525. break;
  526. }
  527. scanned_nmea_sentence++;
  528. } while (scanned_nmea_sentence->keyword != NULL);
  529. next:
  530. if (tok == NULL) {
  531. break;
  532. }
  533. if (tok[1] == '\n') {
  534. tok++;
  535. }
  536. serbuf_p = tok + 1;
  537. }
  538. return TRUE;
  539. }
  540. LRESULT wnd_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  541. {
  542. static HDC hdc = NULL;
  543. static HDC bmap_dc = NULL;
  544. static HBITMAP hbmap = NULL;
  545. static WORD width, height;
  546. static RECT rect;
  547. PAINTSTRUCT ps;
  548. static LOGFONT lf;
  549. static HFONT font;
  550. static HFONT location_font;
  551. static HFONT oldfont = NULL;
  552. const COLORREF bg_color = 0x000000;
  553. const COLORREF font_color = 0x6633aa;
  554. const COLORREF font_location_color = 0xff88cc;
  555. WCHAR strbuf[4000];
  556. Coord xlon = 0, xlat = 0;
  557. Coord xlon_diff, xlat_diff;
  558. int xaltitude = 0;
  559. int xaltitude_diff;
  560. MinDecCoord lon, lat;
  561. static const WCHAR *turner[] = {
  562. L" ... |",
  563. L" ... /",
  564. L" ... -",
  565. L" ... \\",
  566. NULL
  567. };
  568. static const WCHAR **turnerpnt = turner;
  569. switch(msg){
  570. case WM_CREATE:
  571. hdc = GetDC(hWnd);
  572. bmap_dc = CreateCompatibleDC(hdc);
  573. GetClientRect(hWnd, &rect);
  574. width = rect.right;
  575. height = rect.bottom;
  576. hbmap = CreateCompatibleBitmap(hdc, width, height);
  577. SelectObject(bmap_dc, hbmap);
  578. ZeroMemory(&lf, sizeof lf);
  579. lf.lfQuality = ANTIALIASED_QUALITY;
  580. lf.lfWidth = 16;
  581. lf.lfHeight = 24;
  582. font = CreateFontIndirect(&lf);
  583. oldfont = SelectObject(bmap_dc, font);
  584. lf.lfWidth = 20;
  585. lf.lfHeight = 96;
  586. location_font = CreateFontIndirect(&lf);
  587. ReleaseDC(hWnd, hdc);
  588. return 0;
  589. case WM_CLOSE:
  590. DestroyWindow(hWnd);
  591. break;
  592. case WM_DESTROY:
  593. #if 0
  594. if (oldfont != NULL) {
  595. SelectObject(bmap_dc, oldfont);
  596. oldfont = NULL;
  597. }
  598. DeleteObject(font);
  599. DeleteObject(hbmap);
  600. DeleteDC(bmap_dc);
  601. #endif
  602. PostQuitMessage(0);
  603. break;
  604. case WM_ERASEBKGND:
  605. return 1;
  606. case WM_PAINT:
  607. hdc = BeginPaint(hWnd, &ps);
  608. #if STATNAV
  609. PatBlt(hdc, 0, 0, width, height, WHITENESS);
  610. EndPaint(hWnd, &ps);
  611. return 1;
  612. #endif
  613. PatBlt(bmap_dc, 0, 0, width, height, BLACKNESS);
  614. SetBkColor(bmap_dc, bg_color);
  615. SetTextColor(bmap_dc, font_color);
  616. SelectObject(bmap_dc, font);
  617. {
  618. const WCHAR *fix_quality_s;
  619. const WCHAR *tridifix_s;
  620. const WCHAR *tow_s;
  621. WCHAR dgps_details[1000];
  622. if (gpstatus.useful_sat_count > gpstatus.tracked_sat_count) {
  623. gpstatus.tracked_sat_count = gpstatus.useful_sat_count;
  624. }
  625. switch (gpstatus.fix_quality) {
  626. case FQ_INVALID:
  627. fix_quality_s = *turnerpnt++;
  628. if (*turnerpnt == NULL) {
  629. turnerpnt = turner;
  630. }
  631. break;
  632. case FQ_GPS:
  633. fix_quality_s = L"- GPS"; break;
  634. case FQ_DGPS:
  635. if (gpstatus.dgps_station_id > 0) {
  636. _snwprintf(dgps_details, sizeof dgps_details, L"+ EGNOS n°%d", gpstatus.dgps_station_id);
  637. } else {
  638. _snwprintf(dgps_details, sizeof dgps_details, L"+ EGNOS");
  639. }
  640. fix_quality_s = dgps_details;
  641. break;
  642. case FQ_PPS:
  643. fix_quality_s = L"- PPS"; break;
  644. case FQ_RTK:
  645. fix_quality_s = L"- RTK"; break;
  646. case FQ_FLOAT:
  647. fix_quality_s = L"- flottant"; break;
  648. case FQ_ESTIMATED:
  649. fix_quality_s = L"- estimation"; break;
  650. case FQ_MANUAL:
  651. fix_quality_s = L"- manuel"; break;
  652. case FQ_SIMULATION:
  653. fix_quality_s = L"- simulation"; break;
  654. default:
  655. fix_quality_s = L"";
  656. }
  657. switch (gpstatus.tridifix) {
  658. case TDFX_NOFIX:
  659. if (gpstatus.fix_quality == FQ_INVALID) {
  660. if (gpstatus.useful_sat_count > 0) {
  661. tridifix_s = L"instable";
  662. } else if (gpstatus.tracked_sat_count > 0) {
  663. tridifix_s = L"signal brouillé";
  664. } else {
  665. tridifix_s = L"pas de fix";
  666. }
  667. } else {
  668. tridifix_s = L"approximatif";
  669. }
  670. break;
  671. case TDFX_2D:
  672. tridifix_s = L"2D"; break;
  673. case TDFX_3D:
  674. tridifix_s = L"3D"; break;
  675. default:
  676. tridifix_s = L"initialisation";
  677. }
  678. switch (gpstatus.time_valid_flag) {
  679. case 0:
  680. tow_s = L"Date inconnue"; break;
  681. case 1:
  682. tow_s = L"Heure inconnue"; break;
  683. case 2:
  684. tow_s = L"Heure OK"; break;
  685. case 3:
  686. tow_s = L"Heure et date OK"; break;
  687. default:
  688. tow_s = L"OK"; break;
  689. }
  690. if (gpstatus.useful_sat_count <= 0 || gpstatus.tracked_sat_count <= 0) {
  691. gpstatus.lon = gpstatus.lat = 0;
  692. }
  693. if ((gpstatus.tridifix != TDFX_NOFIX || gpstatus.fix_quality != FQ_INVALID) &&
  694. (gpstatus.lat != 0 || gpstatus.lon != 0)) {
  695. gpstatus.avg_total_altitude += gpstatus.altitude;
  696. gpstatus.avg_altitude_counts++;
  697. xaltitude = gpstatus.avg_total_altitude / gpstatus.avg_altitude_counts;
  698. gpstatus.avg_total_lat += gpstatus.lat;
  699. gpstatus.avg_total_lon += gpstatus.lon;
  700. gpstatus.avg_lonlat_counts++;
  701. xlat = gpstatus.avg_total_lat / gpstatus.avg_lonlat_counts;
  702. xlon = gpstatus.avg_total_lon / gpstatus.avg_lonlat_counts;
  703. } else if (gpstatus.avg_lonlat_counts > 0) {
  704. xaltitude = gpstatus.avg_total_altitude / gpstatus.avg_altitude_counts;
  705. xlat = gpstatus.avg_total_lat / gpstatus.avg_lonlat_counts;
  706. xlon = gpstatus.avg_total_lon / gpstatus.avg_lonlat_counts;
  707. } else {
  708. xaltitude = gpstatus.altitude;
  709. if (gpstatus.lat == 0 && gpstatus.lon == 0 && gpstatus.avg_lonlat_counts > 0) {
  710. xlat = gpstatus.avg_total_lat / gpstatus.avg_lonlat_counts;
  711. xlon = gpstatus.avg_total_lon / gpstatus.avg_lonlat_counts;
  712. } else {
  713. xlat = gpstatus.lat;
  714. xlon = gpstatus.lon;
  715. }
  716. }
  717. if (gpstatus.lat == 0 && gpstatus.lon == 0 && gpstatus.avg_lonlat_counts > 0) {
  718. xlat = gpstatus.avg_total_lat / gpstatus.avg_lonlat_counts;
  719. xlon = gpstatus.avg_total_lon / gpstatus.avg_lonlat_counts;
  720. } else if (gpstatus.lat != 0 || gpstatus.lon != 0) {
  721. xlon_diff = xlon - gpstatus.lon;
  722. xlat_diff = xlat - gpstatus.lat;
  723. if (xlon_diff < -0.050 || xlon_diff > 0.050 ||
  724. xlat_diff < -0.050 || xlat_diff > 0.050) {
  725. gpstatus.avg_total_lon = 0;
  726. gpstatus.avg_total_lat = 0;
  727. gpstatus.avg_lonlat_counts = 0;
  728. xlat = gpstatus.lat;
  729. xlon = gpstatus.lon;
  730. }
  731. }
  732. xaltitude_diff = xaltitude - gpstatus.altitude;
  733. if (xaltitude_diff < -50 || xaltitude_diff > 50) {
  734. gpstatus.avg_total_altitude = 0;
  735. gpstatus.avg_altitude_counts = 0;
  736. xaltitude = gpstatus.altitude;
  737. }
  738. _snwprintf(strbuf, sizeof strbuf,
  739. L"Type de fix : %s %s\r\n"
  740. L"Satellites suivis : %d - utilisés : %d\r\n"
  741. #if 0
  742. L"Altitude GPS : %d m (vdop = %.2f)\r\n"
  743. #endif
  744. L"Dilution horizontale : %.2f\r\n"
  745. L"Instant fix : %d %% - %s\r\n"
  746. L"Signal : %u dB",
  747. tridifix_s, fix_quality_s,
  748. gpstatus.tracked_sat_count,
  749. gpstatus.useful_sat_count,
  750. #if 0
  751. gpstatus.altitude, gpstatus.vdop,
  752. #endif
  753. gpstatus.hdop,
  754. gpstatus.found_ephemeris * 100 / EPHEMERIS_NUMBER, tow_s,
  755. gpstatus.decibels);
  756. DrawText(bmap_dc, strbuf, -1, &rect, DT_LEFT | DT_TOP /* | DT_VCENTER | DT_SINGLELINE */);
  757. }
  758. SetTextColor(bmap_dc, font_location_color);
  759. SelectObject(bmap_dc, location_font);
  760. lat = coord_nmea_to_mindec(xlat);
  761. lon = coord_nmea_to_mindec(xlon);
  762. _snwprintf(strbuf, sizeof strbuf, L"%d°%02d.%03d %s %d°%02d.%03d %s",
  763. lat.deg, lat.min, lat.dec, gpstatus.lat_dir, lon.deg, lon.min, lon.dec, gpstatus.lon_dir);
  764. DrawText(bmap_dc, strbuf, -1, &rect, DT_CENTER | DT_BOTTOM /* | DT_VCENTER | DT_SINGLELINE */);
  765. BitBlt(hdc, 0, 0, width, height, bmap_dc, 0, 0, SRCCOPY);
  766. EndPaint(hWnd, &ps);
  767. return 1;
  768. case WM_TIMER:
  769. parse_nmea_messages(global_hcom);
  770. timer = SetTimer(hWnd, 1, FRAME_RATE, NULL);
  771. InvalidateRect(hWnd, NULL, FALSE);
  772. return 1;
  773. default:
  774. return DefWindowProc(hWnd,msg,wParam,lParam);
  775. }
  776. return 0;
  777. }
  778. int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine,
  779. int nCmdShow)
  780. {
  781. WNDCLASS wnd_cls;
  782. HWND h_wnd;
  783. MSG msg;
  784. HANDLE hcom;
  785. const WCHAR *sirf_ports[] = { L"COM8:", L"COM7:", L"COM1:", NULL };
  786. const WCHAR *comid_ports[] = { L"COM1:", L"COM8:", L"COM7:", NULL };
  787. #if STATNAV
  788. BOOL statnav = FALSE;
  789. int choice;
  790. #endif
  791. (void) hInstance;
  792. (void) hPrevInstance;
  793. (void) lpCmdLine;
  794. (void) nCmdShow;
  795. ZeroMemory(&gpstatus, sizeof gpstatus);
  796. gpstatus.avg_total_lat = gpstatus.avg_total_lon = 0;
  797. gpstatus.avg_lonlat_counts = 0;
  798. gpstatus.avg_total_altitude = 0;
  799. gpstatus.avg_altitude_counts = 0;
  800. gpstatus.initialized = FALSE;
  801. ZeroMemory(&wnd_cls, sizeof wnd_cls);
  802. wnd_cls.style = CS_HREDRAW | CS_VREDRAW;
  803. wnd_cls.hInstance = hInstance;
  804. wnd_cls.hCursor = LoadCursor(NULL, IDC_ARROW);
  805. wnd_cls.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
  806. wnd_cls.lpszClassName = L"Evadeo StatNav";
  807. wnd_cls.lpfnWndProc = (WNDPROC) wnd_proc;
  808. RegisterClass(&wnd_cls);
  809. h_wnd = FindWindow(L"Evadeo StatNav", L"Evadeo StatNav pour www.evadeiste.fr");
  810. if (h_wnd) {
  811. SetForegroundWindow((HWND) ((ULONG) h_wnd | 0x0001));
  812. return 0;
  813. }
  814. h_wnd = CreateWindowEx(WS_EX_NODRAG, L"Evadeo StatNav", L"Evadeo StatNav v1.0 pour www.evadeiste.fr",
  815. WS_CAPTION | WS_SYSMENU | WS_MAXIMIZEBOX,
  816. CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
  817. if (!h_wnd) {
  818. MessageBox(NULL, L"Impossible de creer la fenetre",
  819. TEXT("Evadeo StatNav"), MB_OK);
  820. return 1;
  821. }
  822. #if 1
  823. h_test = CreateWindow(WC_STATIC, L"Evadeo StatNav",
  824. WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_EX_CONTROLPARENT,
  825. 0, 100, 480, 20, h_wnd, NULL, hInstance, NULL);
  826. #endif
  827. ShowWindow(h_wnd, SW_SHOW);
  828. UpdateWindow(h_wnd);
  829. ForcePageout();
  830. #if 1
  831. SendMessage(h_test, WM_SETTEXT, 0, (LPARAM) L"Configuration de la static navigation...");
  832. if (GetMessageW(&msg, NULL, 0, 0)) {
  833. TranslateMessage(&msg);
  834. DispatchMessage(&msg);
  835. }
  836. #endif
  837. #if STATNAV
  838. choice = MessageBox(h_wnd,
  839. L"Activer la \"static navigation\" (latence augmentée, mais mais position fixe à l'arrêt) ?",
  840. L"Evadeo StatNav", MB_YESNO | MB_ICONQUESTION);
  841. if (choice == IDYES) {
  842. statnav = TRUE;
  843. }
  844. #endif
  845. if (setup_sirf(sirf_ports, statnav) == FALSE) {
  846. DestroyWindow(h_wnd);
  847. UnregisterClass(wnd_cls.lpszClassName, NULL);
  848. return 1;
  849. }
  850. #if STATNAV == 0
  851. Sleep(1000);
  852. #endif
  853. #if 1
  854. DestroyWindow(h_test);
  855. #endif
  856. DestroyWindow(h_wnd);
  857. UnregisterClass(wnd_cls.lpszClassName, NULL);
  858. return 0;
  859. }