driver_ubx.c 87 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569
  1. /*
  2. * UBX driver. All capabilities are common to Antaris4 and u-blox 6.
  3. * Reference manuals are at
  4. * http://www.u-blox.com/en/download/documents-a-resources/u-blox-6-gps-modules-resources.html
  5. *
  6. * updated for u-blox 8
  7. * http://www.ublox.com/images/downloads/Product_Docs/u-bloxM8_ReceiverDescriptionProtocolSpec_%28UBX-13003221%29_Public.pdf
  8. *
  9. * Week counters are not limited to 10 bits. It's unknown what
  10. * the firmware is doing to disambiguate them, if anything; it might just
  11. * be adding a fixed offset based on a hidden epoch value, in which case
  12. * unhappy things will occur on the next rollover.
  13. *
  14. * For the Antaris 4, the default leap-second offset (before getting one from
  15. * the sats, one presumes) is 0sec; for the u-blox 6 it's 15sec.
  16. *
  17. * This file is Copyright (c) 2010-2019 by the GPSD project
  18. * SPDX-License-Identifier: BSD-2-clause
  19. *
  20. */
  21. #include "gpsd_config.h" /* must be before all includes */
  22. #include <assert.h>
  23. #include <math.h>
  24. #include <stdbool.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <unistd.h>
  29. #include "gpsd.h"
  30. #if defined(UBLOX_ENABLE) && defined(BINARY_ENABLE)
  31. #include "driver_ubx.h"
  32. #include "bits.h"
  33. #include "timespec.h"
  34. /*
  35. * A ubx packet looks like this:
  36. * leader: 0xb5 0x62
  37. * message class: 1 byte
  38. * message type: 1 byte
  39. * length of payload: 2 bytes
  40. * payload: variable length
  41. * checksum: 2 bytes
  42. *
  43. * see also the FV25 and UBX documents on reference.html
  44. */
  45. #define UBX_PREFIX_LEN 6
  46. #define UBX_CLASS_OFFSET 2
  47. #define UBX_TYPE_OFFSET 3
  48. /* because we hates magic numbers forever */
  49. #define USART1_ID 1
  50. #define USART2_ID 2
  51. #define USB_ID 3
  52. #define UBX_PROTOCOL_MASK 0x01
  53. #define NMEA_PROTOCOL_MASK 0x02
  54. #define RTCM_PROTOCOL_MASK 0x04
  55. #define UBX_CFG_LEN 20
  56. #define outProtoMask 14
  57. static gps_mask_t ubx_parse(struct gps_device_t *session, unsigned char *buf,
  58. size_t len);
  59. static gps_mask_t ubx_msg_nav_eoe(struct gps_device_t *session,
  60. unsigned char *buf, size_t data_len);
  61. static gps_mask_t ubx_msg_nav_dop(struct gps_device_t *session,
  62. unsigned char *buf, size_t data_len);
  63. static void ubx_msg_inf(struct gps_device_t *session, unsigned char *buf,
  64. size_t data_len);
  65. static gps_mask_t ubx_msg_nav_posecef(struct gps_device_t *session,
  66. unsigned char *buf, size_t data_len);
  67. static gps_mask_t ubx_msg_nav_pvt(struct gps_device_t *session,
  68. unsigned char *buf, size_t data_len);
  69. static void ubx_msg_mon_ver(struct gps_device_t *session,
  70. unsigned char *buf, size_t data_len);
  71. static gps_mask_t ubx_msg_nav_sat(struct gps_device_t *session,
  72. unsigned char *buf, size_t data_len);
  73. static gps_mask_t ubx_msg_nav_sol(struct gps_device_t *session,
  74. unsigned char *buf, size_t data_len);
  75. static gps_mask_t ubx_msg_nav_svinfo(struct gps_device_t *session,
  76. unsigned char *buf, size_t data_len);
  77. static gps_mask_t ubx_msg_nav_timegps(struct gps_device_t *session,
  78. unsigned char *buf, size_t data_len);
  79. static gps_mask_t ubx_msg_nav_velecef(struct gps_device_t *session,
  80. unsigned char *buf, size_t data_len);
  81. static void ubx_msg_sbas(struct gps_device_t *session, unsigned char *buf,
  82. size_t data_len);
  83. static gps_mask_t ubx_msg_tim_tp(struct gps_device_t *session,
  84. unsigned char *buf, size_t data_len);
  85. #ifdef RECONFIGURE_ENABLE
  86. static void ubx_mode(struct gps_device_t *session, int mode);
  87. #endif /* RECONFIGURE_ENABLE */
  88. /* make up an NMEA 4.0 (extended) PRN based on gnssId:svId,
  89. * using Appendix A from * u-blox ZED-F9P Interface Description
  90. *
  91. * Return PRN, or zero for error
  92. */
  93. static short ubx2_to_prn(int gnssId, int svId)
  94. {
  95. short nmea_PRN;
  96. if (1 > svId) {
  97. /* skip 0 svId */
  98. return 0;
  99. }
  100. switch (gnssId) {
  101. case 0:
  102. /* GPS, 1-32 maps to 1-32 */
  103. if (32 < svId) {
  104. /* skip bad svId */
  105. return 0;
  106. }
  107. nmea_PRN = svId;
  108. break;
  109. case 1:
  110. /* SBAS, 120..151, 152..158 maps to 33..64, 152..158 */
  111. if (120 > svId) {
  112. /* Huh? */
  113. return 0;
  114. } else if (151 >= svId) {
  115. nmea_PRN = svId - 87;
  116. } else if (158 >= svId) {
  117. nmea_PRN = svId;
  118. } else {
  119. /* Huh? */
  120. return 0;
  121. }
  122. break;
  123. case 2:
  124. /* Galileo, 1..36 -> 301-336 */
  125. /* Galileo, 211..246 -> 301-336 */
  126. if (36 >= svId) {
  127. nmea_PRN = svId + 300;
  128. } else if (211 > svId) {
  129. /* skip bad svId */
  130. return 0;
  131. } else if (246 >= svId) {
  132. nmea_PRN = svId + 90;
  133. } else {
  134. /* skip bad svId */
  135. return 0;
  136. }
  137. break;
  138. case 3:
  139. /* BeiDou, 1..37 -> to 401-437 */
  140. /* BeiDou, 159..163,33..64 -> to 401-437 */
  141. if (37 >= svId) {
  142. nmea_PRN = svId + 400;
  143. } else {
  144. /* skip bad svId */
  145. return 0;
  146. }
  147. break;
  148. case 4:
  149. /* IMES, 1-10 -> to 173-182, per u-blox 8/NMEA 4.0 extended */
  150. if (10 < svId) {
  151. /* skip bad svId */
  152. return 0;
  153. }
  154. nmea_PRN = svId + 172;
  155. break;
  156. case 5:
  157. /* QZSS, 1-5 maps to 193-197 */
  158. /* ZED-F9T also see 198 and 199 */
  159. if (7 < svId) {
  160. /* skip bad svId */
  161. return 0;
  162. }
  163. nmea_PRN = svId + 192;
  164. break;
  165. case 6:
  166. /* GLONASS, 1-32 maps to 65-96 */
  167. if (32 < svId) {
  168. /* skip bad svId */
  169. /* 255 == tracked, but unidentified, skip */
  170. return 0;
  171. }
  172. nmea_PRN = svId + 64;
  173. break;
  174. default:
  175. /* Huh? */
  176. return 0;
  177. }
  178. return nmea_PRN;
  179. }
  180. /* Convert a ubx PRN to an NMEA 4.0 (extended) PRN and ubx gnssid, svid
  181. *
  182. * return 0 on fail
  183. */
  184. static short ubx_to_prn(int ubx_PRN, unsigned char *gnssId,
  185. unsigned char *svId)
  186. {
  187. *gnssId = 0;
  188. *svId = 0;
  189. if (1 > ubx_PRN) {
  190. /* skip 0 PRN */
  191. return 0;
  192. } else if (32 >= ubx_PRN) {
  193. /* GPS 1..32 -> 1..32 */
  194. *gnssId = 0;
  195. *svId = ubx_PRN;
  196. } else if (64 >= ubx_PRN) {
  197. /* BeiDou, 159..163,33..64 -> 1..5,6..37 */
  198. *gnssId = 3;
  199. *svId = ubx_PRN - 27;
  200. } else if (96 >= ubx_PRN) {
  201. /* GLONASS 65..96 -> 1..32 */
  202. *gnssId = 6;
  203. *svId = ubx_PRN - 64;
  204. } else if (120 > ubx_PRN) {
  205. /* Huh? */
  206. return 0;
  207. } else if (158 >= ubx_PRN) {
  208. /* SBAS 120..158 -> 120..158 */
  209. *gnssId = 1;
  210. *svId = ubx_PRN;
  211. } else if (163 >= ubx_PRN) {
  212. /* BeiDou, 159..163 -> 1..5 */
  213. *gnssId = 3;
  214. *svId = ubx_PRN - 158;
  215. } else if (173 > ubx_PRN) {
  216. /* Huh? */
  217. return 0;
  218. } else if (182 >= ubx_PRN) {
  219. /* IMES 173..182 -> 1..5, in u-blox 8, bot u-blox 9 */
  220. *gnssId = 4;
  221. *svId = ubx_PRN - 172;
  222. } else if (193 > ubx_PRN) {
  223. /* Huh? */
  224. return 0;
  225. } else if (199 >= ubx_PRN) {
  226. /* QZSS 193..197 -> 1..5 */
  227. /* ZED-F9T also see 198 and 199 */
  228. *gnssId = 5;
  229. *svId = ubx_PRN - 192;
  230. } else if (211 > ubx_PRN) {
  231. /* Huh? */
  232. return 0;
  233. } else if (246 >= ubx_PRN) {
  234. /* Galileo 211..246 -> 1..36 */
  235. *gnssId = 2;
  236. *svId = ubx_PRN - 210;
  237. } else {
  238. /* greater than 246
  239. * GLONASS (255), unused, or other unknown */
  240. return 0;
  241. }
  242. return ubx2_to_prn(*gnssId, *svId);
  243. }
  244. /**
  245. * Receiver/Software Version
  246. * UBX-MON-VER
  247. *
  248. * sadly more info than fits in session->swtype for now.
  249. * so squish the data hard.
  250. */
  251. static void
  252. ubx_msg_mon_ver(struct gps_device_t *session, unsigned char *buf,
  253. size_t data_len)
  254. {
  255. size_t n = 0; /* extended info counter */
  256. char obuf[128]; /* temp version string buffer */
  257. char *cptr;
  258. if (40 > data_len) {
  259. GPSD_LOG(LOG_WARN, &session->context->errout,
  260. "Runt MON-VER message, payload len %zd", data_len);
  261. return;
  262. }
  263. /* save SW and HW Version as subtype */
  264. (void)snprintf(obuf, sizeof(obuf),
  265. "SW %.30s,HW %.10s",
  266. (char *)&buf[UBX_MESSAGE_DATA_OFFSET + 0],
  267. (char *)&buf[UBX_MESSAGE_DATA_OFFSET + 30]);
  268. /* save what we can */
  269. (void)strlcpy(session->subtype, obuf, sizeof(session->subtype));
  270. /* find PROTVER= */
  271. cptr = strstr(session->subtype, "PROTVER=");
  272. if (NULL != cptr) {
  273. int protver = atoi(cptr + 8);
  274. if (9 < protver) {
  275. /* protver 10, u-blox 5, is the oldest we know */
  276. session->driver.ubx.protver = protver;
  277. }
  278. }
  279. obuf[0] = '\0';
  280. /* get n number of Extended info strings. what is max n? */
  281. for ( n = 0; ; n++ ) {
  282. size_t start_of_str = UBX_MESSAGE_DATA_OFFSET + 40 + (30 * n);
  283. if ( (start_of_str + 2 ) > data_len ) {
  284. /* last one can be shorter than 30 */
  285. /* no more data */
  286. break;
  287. }
  288. (void)strlcat(obuf, ",", sizeof(obuf));
  289. (void)strlcat(obuf, (char *)&buf[start_of_str], sizeof(obuf));
  290. }
  291. /* save what we can */
  292. (void)strlcpy(session->subtype1, obuf, sizeof(session->subtype1));
  293. /* output SW and HW Version at LOG_INFO */
  294. GPSD_LOG(LOG_INF, &session->context->errout,
  295. "UBX-MON-VER: %s %s\n",
  296. session->subtype, session->subtype1);
  297. }
  298. /*
  299. * UBX-NAV-HPPOSECEF - High Precision Position Solution in ECEF
  300. */
  301. static gps_mask_t
  302. ubx_msg_nav_hpposecef(struct gps_device_t *session, unsigned char *buf,
  303. size_t data_len)
  304. {
  305. gps_mask_t mask = ECEF_SET;
  306. int version;
  307. if (28 > data_len) {
  308. GPSD_LOG(LOG_WARN, &session->context->errout,
  309. "Runt UBX-NAV-HPPOSECEF message, payload len %zd", data_len);
  310. return 0;
  311. }
  312. version = getub(buf, 0);
  313. session->driver.ubx.iTOW = getleu32(buf, 4);
  314. session->newdata.ecef.x = ((getles32(buf, 8) +
  315. (getsb(buf, 20) * 1e-2)) * 1e-2);
  316. session->newdata.ecef.y = ((getles32(buf, 12) +
  317. (getsb(buf, 21) * 1e-2)) * 1e-2);
  318. session->newdata.ecef.z = ((getles32(buf, 16) +
  319. (getsb(buf, 22) * 1e-2)) * 1e-2);
  320. session->newdata.ecef.pAcc = getleu32(buf, 24) * 1e-4;
  321. /* (long long) cast for 32-bit compat */
  322. GPSD_LOG(LOG_DATA, &session->context->errout,
  323. "UBX-NAV-HPPOSECEF: version %d iTOW=%lld ECEF x=%.4f y=%.4f z=%.4f "
  324. "pAcc=%.4f\n",
  325. version,
  326. (long long)session->driver.ubx.iTOW,
  327. session->newdata.ecef.x,
  328. session->newdata.ecef.y,
  329. session->newdata.ecef.z,
  330. session->newdata.ecef.pAcc);
  331. return mask;
  332. }
  333. /**
  334. * High Precision Geodetic Position Solution
  335. * UBX-NAV-HPPOSLLH, Class 1, ID x14
  336. *
  337. * No mode, so limited usefulness.
  338. */
  339. static gps_mask_t
  340. ubx_msg_nav_hpposllh(struct gps_device_t *session, unsigned char *buf,
  341. size_t data_len)
  342. {
  343. int version;
  344. gps_mask_t mask = 0;
  345. if (36 > data_len) {
  346. GPSD_LOG(LOG_WARN, &session->context->errout,
  347. "Runt NAV-HPPOSLLH message, payload len %zd", data_len);
  348. return mask;
  349. }
  350. mask = ONLINE_SET | HERR_SET | VERR_SET | LATLON_SET | ALTITUDE_SET;
  351. version = getub(buf, 0);
  352. session->driver.ubx.iTOW = getles32(buf, 4);
  353. session->newdata.longitude = (1e-7 * (getles32(buf, 8) +
  354. (getsb(buf, 24) * 1e-2)));
  355. session->newdata.latitude = (1e-7 * (getles32(buf, 12) + \
  356. (getsb(buf, 25) * 1e-2)));
  357. /* altitude WGS84 */
  358. session->newdata.altHAE = (1e-3 * (getles32(buf, 16) + \
  359. (getsb(buf, 26) * 1e-2)));
  360. /* altitude MSL */
  361. session->newdata.altMSL = (1e-3 * (getles32(buf, 20) + \
  362. (getsb(buf, 27) * 1e-2)));
  363. /* Let gpsd_error_model() deal with geoid_sep */
  364. /* Horizontal accuracy estimate in .1 mm, unknown est type */
  365. session->newdata.eph = getleu32(buf, 28) * 1e-4;
  366. /* Vertical accuracy estimate in .1 mm, unknown est type */
  367. session->newdata.epv = getleu32(buf, 32) * 1e-4;
  368. GPSD_LOG(LOG_DATA, &session->context->errout,
  369. "UBX-NAV-HPPOSLLH: version %d iTOW=%lld lat=%.4f lon=%.4f "
  370. "altHAE=%.4f\n",
  371. version,
  372. (long long)session->driver.ubx.iTOW,
  373. session->newdata.latitude,
  374. session->newdata.longitude,
  375. session->newdata.altHAE);
  376. return mask;
  377. }
  378. /*
  379. * Navigation Position ECEF message
  380. */
  381. static gps_mask_t
  382. ubx_msg_nav_posecef(struct gps_device_t *session, unsigned char *buf,
  383. size_t data_len)
  384. {
  385. gps_mask_t mask = ECEF_SET;
  386. if (20 > data_len) {
  387. GPSD_LOG(LOG_WARN, &session->context->errout,
  388. "Runt UBX-NAV-POSECEF message, payload len %zd", data_len);
  389. return 0;
  390. }
  391. session->driver.ubx.iTOW = getleu32(buf, 0);
  392. /* all in cm */
  393. session->newdata.ecef.x = getles32(buf, 4) * 1e-2;
  394. session->newdata.ecef.y = getles32(buf, 8) * 1e-2;
  395. session->newdata.ecef.z = getles32(buf, 12) * 1e-2;
  396. session->newdata.ecef.pAcc = getleu32(buf, 16) * 1e-2;
  397. /* (long long) cast for 32-bit compat */
  398. GPSD_LOG(LOG_DATA, &session->context->errout,
  399. "UBX-NAV-POSECEF: iTOW=%lld ECEF x=%.2f y=%.2f z=%.2f pAcc=%.2f\n",
  400. (long long)session->driver.ubx.iTOW,
  401. session->newdata.ecef.x,
  402. session->newdata.ecef.y,
  403. session->newdata.ecef.z,
  404. session->newdata.ecef.pAcc);
  405. return mask;
  406. }
  407. /**
  408. * Navigation Position Velocity Time solution message
  409. * UBX-NAV-PVT Class 1, ID 7
  410. *
  411. * Not in u-blox 5 or 6, present in u-blox 7
  412. */
  413. static gps_mask_t
  414. ubx_msg_nav_pvt(struct gps_device_t *session, unsigned char *buf,
  415. size_t data_len)
  416. {
  417. uint8_t valid;
  418. uint8_t flags;
  419. uint8_t fixType;
  420. struct tm unpacked_date;
  421. int *status = &session->gpsdata.status;
  422. int *mode = &session->newdata.mode;
  423. gps_mask_t mask = 0;
  424. char ts_buf[TIMESPEC_LEN];
  425. /* u-blox 6 and 7 are 84 bytes, u-blox 8 and 9 are 92 bytes */
  426. if (84 > data_len) {
  427. GPSD_LOG(LOG_WARN, &session->context->errout,
  428. "Runt NAV-PVT message, payload len %zd", data_len);
  429. return 0;
  430. }
  431. session->driver.ubx.iTOW = getleu32(buf, 0);
  432. valid = (unsigned int)getub(buf, 11);
  433. fixType = (unsigned char)getub(buf, 20);
  434. flags = (unsigned int)getub(buf, 21);
  435. switch (fixType) {
  436. case UBX_MODE_TMONLY:
  437. // 5 - Surveyed-in, so a precise 3D.
  438. *mode = MODE_3D;
  439. *status = STATUS_TIME;
  440. mask |= STATUS_SET | MODE_SET;
  441. break;
  442. case UBX_MODE_3D:
  443. // 3
  444. // FALLTHROUGH
  445. case UBX_MODE_GPSDR:
  446. // 4
  447. if (*mode != MODE_3D) {
  448. *mode = MODE_3D;
  449. mask |= MODE_SET;
  450. }
  451. if ((flags & UBX_NAV_PVT_FLAG_DGPS) == UBX_NAV_PVT_FLAG_DGPS) {
  452. if (*status != STATUS_DGPS_FIX) {
  453. *status = STATUS_DGPS_FIX;
  454. mask |= STATUS_SET;
  455. }
  456. } else {
  457. if (*status != STATUS_FIX) {
  458. *status = STATUS_FIX;
  459. mask |= STATUS_SET;
  460. }
  461. }
  462. mask |= LATLON_SET;
  463. break;
  464. case UBX_MODE_2D:
  465. // 2
  466. // FALLTHROUGH
  467. case UBX_MODE_DR: /* consider this too as 2D */
  468. // 1
  469. if (*mode != MODE_2D) {
  470. *mode = MODE_2D;
  471. mask |= MODE_SET;
  472. };
  473. if (*status != STATUS_FIX) {
  474. *status = STATUS_FIX;
  475. mask |= STATUS_SET;
  476. }
  477. mask |= LATLON_SET | SPEED_SET;
  478. break;
  479. case UBX_MODE_NOFIX:
  480. // 0
  481. // FALLTHROUGH
  482. default:
  483. // huh?
  484. if (*mode != MODE_NO_FIX) {
  485. *mode = MODE_NO_FIX;
  486. mask |= MODE_SET;
  487. };
  488. if (*status != STATUS_NO_FIX) {
  489. *status = STATUS_NO_FIX;
  490. mask |= STATUS_SET;
  491. }
  492. break;
  493. }
  494. if ((valid & UBX_NAV_PVT_VALID_DATE_TIME) == UBX_NAV_PVT_VALID_DATE_TIME) {
  495. unpacked_date.tm_year = (uint16_t)getleu16(buf, 4) - 1900;
  496. unpacked_date.tm_mon = (uint8_t)getub(buf, 6) - 1;
  497. unpacked_date.tm_mday = (uint8_t)getub(buf, 7);
  498. unpacked_date.tm_hour = (uint8_t)getub(buf, 8);
  499. unpacked_date.tm_min = (uint8_t)getub(buf, 9);
  500. unpacked_date.tm_sec = (uint8_t)getub(buf, 10);
  501. unpacked_date.tm_isdst = 0;
  502. unpacked_date.tm_wday = 0;
  503. unpacked_date.tm_yday = 0;
  504. session->newdata.time.tv_sec = mkgmtime(&unpacked_date);
  505. /* field 16, nano, can be negative! So normalize */
  506. session->newdata.time.tv_nsec = getles32(buf, 16);
  507. TS_NORM(&session->newdata.time);
  508. mask |= TIME_SET | NTPTIME_IS | GOODTIME_IS;
  509. }
  510. session->newdata.longitude = 1e-7 * getles32(buf, 24);
  511. session->newdata.latitude = 1e-7 * getles32(buf, 28);
  512. /* altitude WGS84 */
  513. session->newdata.altHAE = 1e-3 * getles32(buf, 32);
  514. /* altitude MSL */
  515. session->newdata.altMSL = 1e-3 * getles32(buf, 36);
  516. /* Let gpsd_error_model() deal with geoid_sep */
  517. session->newdata.speed = 1e-3 * (int32_t)getles32(buf, 60);
  518. /* u-blox calls this Heading of motion (2-D) */
  519. session->newdata.track = 1e-5 * (int32_t)getles32(buf, 64);
  520. mask |= LATLON_SET | ALTITUDE_SET | SPEED_SET | TRACK_SET;
  521. /* Height Accuracy estimate, unknown details */
  522. session->newdata.eph = (double)(getles32(buf, 40) / 1000.0);
  523. /* Velocity Accuracy estimate, unknown details */
  524. session->newdata.epv = (double)(getles32(buf, 44) / 1000.0);
  525. /* Speed Accuracy estimate, unknown details */
  526. session->newdata.eps = (double)(getles32(buf, 48) / 1000.0);
  527. /* let gpsd_error_model() do the rest */
  528. mask |= HERR_SET | SPEEDERR_SET | VERR_SET;
  529. GPSD_LOG(LOG_DATA, &session->context->errout,
  530. "NAV-PVT: flags=%02x time=%s lat=%.2f lon=%.2f altHAE=%.2f "
  531. "track=%.2f speed=%.2f climb=%.2f mode=%d status=%d used=%d\n",
  532. flags,
  533. timespec_str(&session->newdata.time, ts_buf, sizeof(ts_buf)),
  534. session->newdata.latitude,
  535. session->newdata.longitude,
  536. session->newdata.altHAE,
  537. session->newdata.track,
  538. session->newdata.speed,
  539. session->newdata.climb,
  540. session->newdata.mode,
  541. session->gpsdata.status,
  542. session->gpsdata.satellites_used);
  543. if (92 <= data_len) {
  544. /* u-blox 8 and 9 extended */
  545. double magDec = NAN;
  546. double magAcc = NAN;
  547. #ifdef __UNUSED
  548. if (flags & UBX_NAV_PVT_FLAG_HDG_OK) {
  549. /* u-blox calls this Heading of vehicle (2-D)
  550. * why is it different than earlier track? */
  551. session->newdata.track = (double)(getles32(buf, 84) * 1e-5);
  552. }
  553. #endif /* __UNUSED */
  554. if (valid & UBX_NAV_PVT_VALID_MAG) {
  555. magDec = (double)(getles16(buf, 88) * 1e-2);
  556. magAcc = (double)(getleu16(buf, 90) * 1e-2);
  557. }
  558. GPSD_LOG(LOG_DATA, &session->context->errout,
  559. " headVeh %.5f magDec %.2f magAcc %.2f\n",
  560. session->newdata.track, magDec, magAcc);
  561. }
  562. return mask;
  563. }
  564. /**
  565. * High Precision Relative Positioning Information in NED frame
  566. * UBX-NAV-RELPOSNED, Class 1, ID x3c
  567. * HP GNSS only, protver 20+
  568. */
  569. static gps_mask_t
  570. ubx_msg_nav_relposned(struct gps_device_t *session, unsigned char *buf,
  571. size_t data_len)
  572. {
  573. int version;
  574. unsigned refStationId, flags;
  575. double accN, accE, accD;
  576. gps_mask_t mask = 0;
  577. if (40 > data_len) {
  578. GPSD_LOG(LOG_WARN, &session->context->errout,
  579. "Runt NAV-RELPOSNED message, payload len %zd", data_len);
  580. return mask;
  581. }
  582. mask = NED_SET;
  583. version = getub(buf, 0);
  584. refStationId = getleu16(buf, 2);
  585. session->driver.ubx.iTOW = getles32(buf, 4);
  586. session->newdata.NED.relPosN = (1e-2 * (getles32(buf, 8) +
  587. (getsb(buf, 20) * 1e-2)));
  588. session->newdata.NED.relPosE = (1e-2 * (getles32(buf, 12) +
  589. (getsb(buf, 21) * 1e-2)));
  590. session->newdata.NED.relPosD = (1e-2 * (getles32(buf, 16) +
  591. (getsb(buf, 22) * 1e-2)));
  592. accN = 1e-4 * getles32(buf, 24);
  593. accE = 1e-4 * getles32(buf, 28);
  594. accD = 1e-4 * getles32(buf, 32);
  595. flags = getleu32(buf, 36);
  596. GPSD_LOG(LOG_DATA, &session->context->errout,
  597. "UBX-NAV-RELPOSNED: version %d iTOW=%lld refStationId %u flags x%x\n"
  598. "UBX-NAV-RELPOSNED: relPos N=%.4f E=%.4f D=%.4f\n"
  599. "UBX-NAV-RELPOSNED: acc N=%.4f E=%.4f D=%.4f\n",
  600. version,
  601. (long long)session->driver.ubx.iTOW,
  602. refStationId,
  603. flags,
  604. session->newdata.NED.relPosN,
  605. session->newdata.NED.relPosE,
  606. session->newdata.NED.relPosD,
  607. accN, accE, accD);
  608. if (5 != (flags & 5)) {
  609. /* gnssFixOK or relPosValid are false, no fix */
  610. return 0;
  611. }
  612. return mask;
  613. }
  614. /**
  615. * Navigation solution message: UBX-NAV-SOL
  616. *
  617. * UBX-NAV-SOL deprecated in u-blox 6, gone in u-blox 9.
  618. * Use UBX-NAV-PVT instead
  619. */
  620. static gps_mask_t
  621. ubx_msg_nav_sol(struct gps_device_t *session, unsigned char *buf,
  622. size_t data_len)
  623. {
  624. unsigned int flags;
  625. unsigned char navmode;
  626. gps_mask_t mask;
  627. char ts_buf[TIMESPEC_LEN];
  628. if (52 > data_len) {
  629. GPSD_LOG(LOG_WARN, &session->context->errout,
  630. "Runt NAV-SOL message, payload len %zd", data_len);
  631. return 0;
  632. }
  633. session->driver.ubx.iTOW = getleu32(buf, 0);
  634. flags = (unsigned int)getub(buf, 11);
  635. mask = 0;
  636. #define DATE_VALID (UBX_SOL_VALID_WEEK | UBX_SOL_VALID_TIME)
  637. if ((flags & DATE_VALID) == DATE_VALID) {
  638. unsigned short week;
  639. timespec_t ts_tow;
  640. MSTOTS(&ts_tow, session->driver.ubx.iTOW);
  641. ts_tow.tv_nsec += (long)getles32(buf, 4);
  642. week = (unsigned short)getles16(buf, 8);
  643. session->newdata.time = gpsd_gpstime_resolv(session, week, ts_tow);
  644. mask |= TIME_SET | NTPTIME_IS | GOODTIME_IS;
  645. }
  646. #undef DATE_VALID
  647. session->newdata.ecef.x = getles32(buf, 12) / 100.0;
  648. session->newdata.ecef.y = getles32(buf, 16) / 100.0;
  649. session->newdata.ecef.z = getles32(buf, 20) / 100.0;
  650. session->newdata.ecef.pAcc = getleu32(buf, 24) / 100.0;
  651. session->newdata.ecef.vx = getles32(buf, 28) / 100.0;
  652. session->newdata.ecef.vy = getles32(buf, 32) / 100.0;
  653. session->newdata.ecef.vz = getles32(buf, 36) / 100.0;
  654. session->newdata.ecef.vAcc = getleu32(buf, 40) / 100.0;
  655. mask |= ECEF_SET | VECEF_SET;
  656. session->newdata.eps = (double)(getles32(buf, 40) / 100.0);
  657. mask |= SPEEDERR_SET;
  658. /* Better to have a single point of truth about DOPs */
  659. //session->gpsdata.dop.pdop = (double)(getleu16(buf, 44)/100.0);
  660. session->gpsdata.satellites_used = (int)getub(buf, 47);
  661. navmode = (unsigned char)getub(buf, 10);
  662. switch (navmode) {
  663. case UBX_MODE_TMONLY:
  664. /* Surveyed-in, better not have moved */
  665. session->newdata.mode = MODE_3D;
  666. session->gpsdata.status = STATUS_TIME;
  667. break;
  668. case UBX_MODE_3D:
  669. session->newdata.mode = MODE_3D;
  670. session->gpsdata.status = STATUS_FIX;
  671. break;
  672. case UBX_MODE_2D:
  673. session->newdata.mode = MODE_2D;
  674. session->gpsdata.status = STATUS_FIX;
  675. break;
  676. case UBX_MODE_DR: /* consider this too as 2D */
  677. session->newdata.mode = MODE_2D;
  678. session->gpsdata.status = STATUS_DR;
  679. break;
  680. case UBX_MODE_GPSDR: /* DR-aided GPS is valid 3D */
  681. session->newdata.mode = MODE_3D;
  682. session->gpsdata.status = STATUS_GNSSDR;
  683. break;
  684. default:
  685. session->newdata.mode = MODE_NO_FIX;
  686. session->gpsdata.status = STATUS_NO_FIX;
  687. break;
  688. }
  689. if ((flags & UBX_SOL_FLAG_DGPS) != 0)
  690. session->gpsdata.status = STATUS_DGPS_FIX;
  691. mask |= MODE_SET | STATUS_SET;
  692. GPSD_LOG(LOG_DATA, &session->context->errout,
  693. "UBX-NAV-SOL: time=%s ecef x:%.2f y:%.2f z:%.2f track=%.2f "
  694. "speed=%.2f climb=%.2f mode=%d status=%d used=%d\n",
  695. timespec_str(&session->newdata.time, ts_buf, sizeof(ts_buf)),
  696. session->newdata.ecef.x,
  697. session->newdata.ecef.y,
  698. session->newdata.ecef.z,
  699. session->newdata.track,
  700. session->newdata.speed,
  701. session->newdata.climb,
  702. session->newdata.mode,
  703. session->gpsdata.status,
  704. session->gpsdata.satellites_used);
  705. return mask;
  706. }
  707. /**
  708. * Navigation time to leap second: UBX-NAV-TIMELS
  709. *
  710. * Sets leap_notify if leap second is < 23 hours away.
  711. * Not in u-blox 5
  712. */
  713. static void ubx_msg_nav_timels(struct gps_device_t *session,
  714. unsigned char *buf, size_t data_len)
  715. {
  716. int version;
  717. unsigned int flags;
  718. int valid_curr_ls;
  719. int valid_time_to_ls_event;
  720. #define UBX_TIMELS_VALID_CURR_LS 0x01
  721. #define UBX_TIMELS_VALID_TIME_LS_EVT 0x01
  722. if (24 > data_len) {
  723. GPSD_LOG(LOG_WARN, &session->context->errout,
  724. "UBX-NAV-TIMELS: unexpected length %zd, expecting 24\n",
  725. data_len);
  726. return;
  727. }
  728. session->driver.ubx.iTOW = getles32(buf, 0);
  729. version = getsb(buf, 4);
  730. /* Only version 0 is defined so far. */
  731. flags = (unsigned int)getub(buf, 23);
  732. GPSD_LOG(LOG_PROG, &session->context->errout,
  733. "UBX-NAV-TIMELS: flags 0x%x message version %d\n",
  734. flags, version);
  735. valid_curr_ls = flags & UBX_TIMELS_VALID_CURR_LS;
  736. valid_time_to_ls_event = flags & UBX_TIMELS_VALID_TIME_LS_EVT;
  737. if (valid_curr_ls) {
  738. unsigned int src_of_curr_ls = getub(buf,8);
  739. int curr_ls = getsb(buf,9);
  740. char *src = "Unknown";
  741. static char *srcOfCurrLs[] = {
  742. "firmware",
  743. "GPS GLONASS difference",
  744. "GPS",
  745. "SBAS",
  746. "BeiDou",
  747. "Galileo",
  748. "Aided data",
  749. "Configured"
  750. };
  751. if (src_of_curr_ls < (sizeof(srcOfCurrLs) / sizeof(srcOfCurrLs[0])))
  752. src = srcOfCurrLs[src_of_curr_ls];
  753. GPSD_LOG(LOG_DATA, &session->context->errout,
  754. "UBX-NAV-TIMELS: source_of_current_leapsecond=%u:%s "
  755. "curr_ls=%d\n",
  756. src_of_curr_ls, src,curr_ls);
  757. session->context->leap_seconds = curr_ls;
  758. session->context->valid |= LEAP_SECOND_VALID;
  759. } /* Valid current leap second */
  760. if (valid_time_to_ls_event) {
  761. char *src = "Unknown";
  762. unsigned int src_of_ls_change;
  763. unsigned short dateOfLSGpsWn, dateOfLSGpsDn;
  764. int lsChange = getsb(buf, 11);
  765. int timeToLsEvent = getles32(buf, 12);
  766. static char *srcOfLsChange[] = {
  767. "No Source",
  768. "Undefined",
  769. "GPS",
  770. "SBAS",
  771. "BeiDou",
  772. "Galileo",
  773. "GLONASS",
  774. };
  775. src_of_ls_change = getub(buf,10);
  776. if (src_of_ls_change <
  777. (sizeof(srcOfLsChange) / sizeof(srcOfLsChange[0]))) {
  778. src = srcOfLsChange[src_of_ls_change];
  779. }
  780. dateOfLSGpsWn = getles16(buf,16);
  781. dateOfLSGpsDn = getles16(buf,18);
  782. GPSD_LOG(LOG_DATA, &session->context->errout,
  783. "UBX-NAV-TIMELS: source_of_leapsecond_change %u:%s "
  784. "leapSecondChage %d timeToLsEvent %d\n",
  785. src_of_ls_change,src,lsChange,timeToLsEvent);
  786. GPSD_LOG(LOG_DATA, &session->context->errout,
  787. "UBX-NAV-TIMELS: dateOfLSGpsWn=%d dateOfLSGpsDn=%d\n",
  788. dateOfLSGpsWn,dateOfLSGpsDn);
  789. if ((0 != lsChange) && (0 < timeToLsEvent) &&
  790. ((60 * 60 * 23) > timeToLsEvent)) {
  791. if (1 == lsChange) {
  792. session->context->leap_notify = LEAP_ADDSECOND;
  793. GPSD_LOG(LOG_INF, &session->context->errout,
  794. "UBX-NAV-TIMELS: Positive leap second today\n");
  795. } else if (-1 == lsChange) {
  796. session->context->leap_notify = LEAP_DELSECOND;
  797. GPSD_LOG(LOG_INF, &session->context->errout,
  798. "UBX-NAV-TIMELS: Negative leap second today\n");
  799. }
  800. } else {
  801. session->context->leap_notify = LEAP_NOWARNING;
  802. GPSD_LOG(LOG_DATA, &session->context->errout,
  803. "UBX-NAV-TIMELS: leap_notify %d, none today\n",
  804. session->context->leap_notify);
  805. }
  806. }
  807. }
  808. /**
  809. * Geodetic position solution message
  810. * UBX-NAV-POSLLH, Class 1, ID 2
  811. *
  812. * No mode, so limited usefulness
  813. */
  814. static gps_mask_t
  815. ubx_msg_nav_posllh(struct gps_device_t *session, unsigned char *buf,
  816. size_t data_len UNUSED)
  817. {
  818. gps_mask_t mask = 0;
  819. if (28 > data_len) {
  820. GPSD_LOG(LOG_WARN, &session->context->errout,
  821. "Runt NAV-POSLLH message, payload len %zd", data_len);
  822. return 0;
  823. }
  824. mask = ONLINE_SET | HERR_SET | VERR_SET | LATLON_SET | ALTITUDE_SET;
  825. session->driver.ubx.iTOW = getles32(buf, 0);
  826. session->newdata.longitude = 1e-7 * getles32(buf, 4);
  827. session->newdata.latitude = 1e-7 * getles32(buf, 8);
  828. /* altitude WGS84 */
  829. session->newdata.altHAE = 1e-3 * getles32(buf, 12);
  830. /* altitude MSL */
  831. session->newdata.altMSL = 1e-3 * getles32(buf, 16);
  832. /* Let gpsd_error_model() deal with geoid_sep */
  833. /* Horizontal accuracy estimate in mm, unknown type */
  834. session->newdata.eph = getleu32(buf, 20) * 1e-3;
  835. /* Vertical accuracy estimate in mm, unknown type */
  836. session->newdata.epv = getleu32(buf, 24) * 1e-3;
  837. GPSD_LOG(LOG_DATA, &session->context->errout,
  838. "UBX-NAV-POSLLH: iTOW=%lld lat=%.3f lon=%.3f altHAE=%.3f "
  839. "eph %.3f epv %.3f\n",
  840. (long long)session->driver.ubx.iTOW,
  841. session->newdata.latitude,
  842. session->newdata.longitude,
  843. session->newdata.altHAE,
  844. session->newdata.eph,
  845. session->newdata.epv);
  846. return mask;
  847. }
  848. /**
  849. * Dilution of precision message
  850. */
  851. static gps_mask_t
  852. ubx_msg_nav_dop(struct gps_device_t *session, unsigned char *buf,
  853. size_t data_len)
  854. {
  855. if (18 > data_len) {
  856. GPSD_LOG(LOG_WARN, &session->context->errout,
  857. "Runt RXM-SFRB message, payload len %zd", data_len);
  858. return 0;
  859. }
  860. session->driver.ubx.iTOW = getles32(buf, 0);
  861. /*
  862. * We make a deliberate choice not to clear DOPs from the
  863. * last skyview here, but rather to treat this as a supplement
  864. * to our calculations from the visibility matrix, trusting
  865. * the firmware algorithms over ours.
  866. */
  867. session->gpsdata.dop.gdop = (double)(getleu16(buf, 4) / 100.0);
  868. session->gpsdata.dop.pdop = (double)(getleu16(buf, 6) / 100.0);
  869. session->gpsdata.dop.tdop = (double)(getleu16(buf, 8) / 100.0);
  870. session->gpsdata.dop.vdop = (double)(getleu16(buf, 10) / 100.0);
  871. session->gpsdata.dop.hdop = (double)(getleu16(buf, 12) / 100.0);
  872. GPSD_LOG(LOG_DATA, &session->context->errout,
  873. "NAVDOP: gdop=%.2f pdop=%.2f "
  874. "hdop=%.2f vdop=%.2f tdop=%.2f mask={DOP}\n",
  875. session->gpsdata.dop.gdop,
  876. session->gpsdata.dop.hdop,
  877. session->gpsdata.dop.vdop,
  878. session->gpsdata.dop.pdop, session->gpsdata.dop.tdop);
  879. return DOP_SET;
  880. }
  881. /**
  882. * End of Epoch
  883. * Not in u-blox 5, 6 or 7
  884. * Present in u-blox 8 and 9
  885. */
  886. static gps_mask_t
  887. ubx_msg_nav_eoe(struct gps_device_t *session, unsigned char *buf,
  888. size_t data_len)
  889. {
  890. if (4 > data_len) {
  891. GPSD_LOG(LOG_WARN, &session->context->errout,
  892. "Runt NAV-EOE message, payload len %zd", data_len);
  893. return 0;
  894. }
  895. if (18 > session->driver.ubx.protver) {
  896. /* this GPS is at least protver 18 */
  897. session->driver.ubx.protver = 18;
  898. }
  899. session->driver.ubx.iTOW = getles32(buf, 0);
  900. GPSD_LOG(LOG_DATA, &session->context->errout, "EOE: iTOW=%lld\n",
  901. (long long)session->driver.ubx.iTOW);
  902. /* nothing to report, but the iTOW for cycle ender is good */
  903. return 0;
  904. }
  905. /**
  906. * GPS Leap Seconds - UBX-NAV-TIMEGPS
  907. */
  908. static gps_mask_t
  909. ubx_msg_nav_timegps(struct gps_device_t *session, unsigned char *buf,
  910. size_t data_len)
  911. {
  912. uint8_t valid; /* Validity Flags */
  913. gps_mask_t mask = 0;
  914. char ts_buf[TIMESPEC_LEN];
  915. if (16 > data_len) {
  916. GPSD_LOG(LOG_WARN, &session->context->errout,
  917. "Runt NAV-TIMEGPS message, payload len %zd", data_len);
  918. return 0;
  919. }
  920. session->driver.ubx.iTOW = getles32(buf, 0);
  921. valid = getub(buf, 11);
  922. // Valid leap seconds ?
  923. if ((valid & UBX_TIMEGPS_VALID_LEAP_SECOND) ==
  924. UBX_TIMEGPS_VALID_LEAP_SECOND) {
  925. session->context->leap_seconds = (int)getub(buf, 10);
  926. session->context->valid |= LEAP_SECOND_VALID;
  927. }
  928. // Valid GPS time of week and week number
  929. #define VALID_TIME (UBX_TIMEGPS_VALID_TIME | UBX_TIMEGPS_VALID_WEEK)
  930. if ((valid & VALID_TIME) == VALID_TIME) {
  931. #undef VALID_TIME
  932. uint16_t week;
  933. double tAcc; /* Time Accuracy Estimate in ns */
  934. timespec_t ts_tow;
  935. week = getles16(buf, 8);
  936. MSTOTS(&ts_tow, session->driver.ubx.iTOW);
  937. ts_tow.tv_nsec += (long)getles32(buf, 4);
  938. session->newdata.time = gpsd_gpstime_resolv(session, week, ts_tow);
  939. tAcc = (double)getleu32(buf, 12); /* tAcc in ms */
  940. session->newdata.ept = tAcc * 1e-9;
  941. mask |= (TIME_SET | NTPTIME_IS);
  942. }
  943. GPSD_LOG(LOG_DATA, &session->context->errout,
  944. "TIMEGPS: time=%s mask={TIME}\n",
  945. timespec_str(&session->newdata.time, ts_buf, sizeof(ts_buf)));
  946. return mask;
  947. }
  948. /**
  949. * GPS Satellite Info -- new style UBX-NAV-SAT
  950. * Not in u-blox 5, protocol version 15+
  951. */
  952. static gps_mask_t
  953. ubx_msg_nav_sat(struct gps_device_t *session, unsigned char *buf,
  954. size_t data_len)
  955. {
  956. unsigned int i, nchan, nsv, st, ver;
  957. if (8 > data_len) {
  958. GPSD_LOG(LOG_PROG, &session->context->errout,
  959. "Runt NAV-SAT (datalen=%zd)\n", data_len);
  960. return 0;
  961. }
  962. session->driver.ubx.iTOW = getles32(buf, 0);
  963. ver = (unsigned int)getub(buf, 4);
  964. if (1 != ver) {
  965. GPSD_LOG(LOG_WARN, &session->context->errout,
  966. "NAV-SAT message unknown version %d", ver);
  967. return 0;
  968. }
  969. nchan = (unsigned int)getub(buf, 5);
  970. if (nchan > MAXCHANNELS) {
  971. GPSD_LOG(LOG_WARN, &session->context->errout,
  972. "Runt NAV-SAT message, >%d reported visible",
  973. MAXCHANNELS);
  974. return 0;
  975. }
  976. /* two "unused" bytes at buf[6:7] */
  977. gpsd_zero_satellites(&session->gpsdata);
  978. nsv = 0;
  979. for (i = st = 0; i < nchan; i++) {
  980. unsigned int off = 8 + 12 * i;
  981. short nmea_PRN = 0;
  982. unsigned char gnssId = getub(buf, off + 0);
  983. short svId = (short)getub(buf, off + 1);
  984. unsigned char cno = getub(buf, off + 2);
  985. /* health data in flags. */
  986. uint32_t flags = getleu32(buf, off + 8);
  987. bool used = (bool)(flags & 0x08);
  988. int tmp;
  989. /* Notice NO sigid! */
  990. nmea_PRN = ubx2_to_prn(gnssId, svId);
  991. #ifdef __UNUSED
  992. /* debug */
  993. GPSD_LOG(LOG_ERROR, &session->context->errout,
  994. "NAV-SAT gnssid %d, svid %d nmea_PRN %d\n",
  995. gnssId, svId, nmea_PRN);
  996. #endif /* __UNUSED */
  997. session->gpsdata.skyview[st].gnssid = gnssId;
  998. session->gpsdata.skyview[st].svid = svId;
  999. session->gpsdata.skyview[st].PRN = nmea_PRN;
  1000. session->gpsdata.skyview[st].ss = (double)cno;
  1001. tmp = getsb(buf, off + 3);
  1002. if (90 >= abs(tmp)) {
  1003. session->gpsdata.skyview[st].elevation = (double)tmp;
  1004. }
  1005. tmp = getles16(buf, off + 4);
  1006. if (359 > tmp && 0 <= tmp) {
  1007. session->gpsdata.skyview[st].azimuth = (double)tmp;
  1008. }
  1009. session->gpsdata.skyview[st].used = used;
  1010. /* by some coincidence, our health flags matches u-blox's */
  1011. session->gpsdata.skyview[st].health = (flags >> 4) & 3;
  1012. /* sbas_in_use is not same as used */
  1013. if (used) {
  1014. nsv++;
  1015. session->gpsdata.skyview[st].used = true;
  1016. }
  1017. st++;
  1018. }
  1019. /* UBX does not give us these, so recompute */
  1020. session->gpsdata.dop.xdop = NAN;
  1021. session->gpsdata.dop.ydop = NAN;
  1022. session->gpsdata.skyview_time.tv_sec = 0;
  1023. session->gpsdata.skyview_time.tv_nsec = 0;
  1024. session->gpsdata.satellites_visible = (int)st;
  1025. session->gpsdata.satellites_used = (int)nsv;
  1026. GPSD_LOG(LOG_DATA, &session->context->errout,
  1027. "SAT: visible=%d used=%d mask={SATELLITE|USED}\n",
  1028. session->gpsdata.satellites_visible,
  1029. session->gpsdata.satellites_used);
  1030. return SATELLITE_SET | USED_IS;
  1031. }
  1032. /**
  1033. * GPS Satellite Info -- deprecated - UBX-NAV-SVINFO
  1034. * Not in u-blox 9, use UBX-NAV-SAT instead
  1035. */
  1036. static gps_mask_t
  1037. ubx_msg_nav_svinfo(struct gps_device_t *session, unsigned char *buf,
  1038. size_t data_len)
  1039. {
  1040. unsigned int i, nchan, nsv, st;
  1041. if (8 > data_len) {
  1042. GPSD_LOG(LOG_PROG, &session->context->errout,
  1043. "Runt NAV-SVINFO (datalen=%zd)\n", data_len);
  1044. return 0;
  1045. }
  1046. session->driver.ubx.iTOW = getles32(buf, 0);
  1047. nchan = (unsigned int)getub(buf, 4);
  1048. if (nchan > MAXCHANNELS) {
  1049. GPSD_LOG(LOG_WARN, &session->context->errout,
  1050. "Runt NAV SVINFO message, >%d reported visible",
  1051. MAXCHANNELS);
  1052. return 0;
  1053. }
  1054. gpsd_zero_satellites(&session->gpsdata);
  1055. nsv = 0;
  1056. for (i = st = 0; i < nchan; i++) {
  1057. unsigned int off = 8 + 12 * i;
  1058. short nmea_PRN;
  1059. short ubx_PRN = (short)getub(buf, off + 1);
  1060. unsigned char snr = getub(buf, off + 4);
  1061. bool used = (bool)(getub(buf, off + 2) & 0x01);
  1062. unsigned char flags = getub(buf, off + 12) & 3;
  1063. int tmp;
  1064. nmea_PRN = ubx_to_prn(ubx_PRN,
  1065. &session->gpsdata.skyview[st].gnssid,
  1066. &session->gpsdata.skyview[st].svid);
  1067. #ifdef __UNUSED
  1068. /* debug */
  1069. GPSD_LOG(LOG_ERROR, &session->context->errout,
  1070. "NAV-SVINFO ubx_prn %d gnssid %d, svid %d nmea_PRN %d\n",
  1071. ubx_PRN,
  1072. session->gpsdata.skyview[st].gnssid,
  1073. session->gpsdata.skyview[st].svid, nmea_PRN);
  1074. #endif /* __UNUSED */
  1075. if (1 > nmea_PRN) {
  1076. /* skip bad PRN */
  1077. continue;
  1078. }
  1079. session->gpsdata.skyview[st].PRN = nmea_PRN;
  1080. session->gpsdata.skyview[st].ss = (double)snr;
  1081. tmp = getsb(buf, off + 5);
  1082. if (90 >= abs(tmp)) {
  1083. session->gpsdata.skyview[st].elevation = (double)tmp;
  1084. }
  1085. tmp = (double)getles16(buf, off + 6);
  1086. if (359 > tmp && 0 <= tmp) {
  1087. session->gpsdata.skyview[st].azimuth = (double)tmp;
  1088. }
  1089. session->gpsdata.skyview[st].used = used;
  1090. if (0x10 & flags) {
  1091. session->gpsdata.skyview[st].health = SAT_HEALTH_BAD;
  1092. } else {
  1093. session->gpsdata.skyview[st].health = SAT_HEALTH_OK;
  1094. }
  1095. /* sbas_in_use is not same as used */
  1096. if (used) {
  1097. /* not really 'used', just integrity data from there */
  1098. nsv++;
  1099. session->gpsdata.skyview[st].used = true;
  1100. }
  1101. st++;
  1102. }
  1103. /* UBX does not give us these, so recompute */
  1104. session->gpsdata.dop.xdop = NAN;
  1105. session->gpsdata.dop.ydop = NAN;
  1106. session->gpsdata.skyview_time.tv_sec = 0;
  1107. session->gpsdata.skyview_time.tv_nsec = 0;
  1108. session->gpsdata.satellites_visible = (int)st;
  1109. session->gpsdata.satellites_used = (int)nsv;
  1110. GPSD_LOG(LOG_DATA, &session->context->errout,
  1111. "SVINFO: visible=%d used=%d mask={SATELLITE|USED}\n",
  1112. session->gpsdata.satellites_visible,
  1113. session->gpsdata.satellites_used);
  1114. return SATELLITE_SET | USED_IS;
  1115. }
  1116. /*
  1117. * Velocity Position ECEF message, UBX-NAV-VELECEF
  1118. */
  1119. static gps_mask_t
  1120. ubx_msg_nav_velecef(struct gps_device_t *session, unsigned char *buf,
  1121. size_t data_len)
  1122. {
  1123. gps_mask_t mask = VECEF_SET;
  1124. if (20 > data_len) {
  1125. GPSD_LOG(LOG_WARN, &session->context->errout,
  1126. "Runt NAV-VELECEF message, payload len %zd", data_len);
  1127. return 0;
  1128. }
  1129. session->driver.ubx.iTOW = getles32(buf, 0);
  1130. session->newdata.ecef.vx = getles32(buf, 4) / 100.0;
  1131. session->newdata.ecef.vy = getles32(buf, 8) / 100.0;
  1132. session->newdata.ecef.vz = getles32(buf, 12) / 100.0;
  1133. session->newdata.ecef.vAcc = getleu32(buf, 16) / 100.0;
  1134. GPSD_LOG(LOG_DATA, &session->context->errout,
  1135. "UBX-NAV-VELECEF: iTOW=%lld ECEF vx=%.2f vy=%.2f vz=%.2f vAcc=%.2f\n",
  1136. (long long)session->driver.ubx.iTOW,
  1137. session->newdata.ecef.vx,
  1138. session->newdata.ecef.vy,
  1139. session->newdata.ecef.vz,
  1140. session->newdata.ecef.vAcc);
  1141. return mask;
  1142. }
  1143. /*
  1144. * Velocity NED message, UBX-NAV-VELNED
  1145. * protocol versions 15+
  1146. */
  1147. static gps_mask_t
  1148. ubx_msg_nav_velned(struct gps_device_t *session, unsigned char *buf,
  1149. size_t data_len)
  1150. {
  1151. gps_mask_t mask = VNED_SET;
  1152. if (36 > data_len) {
  1153. GPSD_LOG(LOG_WARN, &session->context->errout,
  1154. "Runt NAV-VELNED message, payload len %zd", data_len);
  1155. return 0;
  1156. }
  1157. session->driver.ubx.iTOW = getles32(buf, 0);
  1158. session->newdata.NED.velN = getles32(buf, 4) / 100.0;
  1159. session->newdata.NED.velE = getles32(buf, 8) / 100.0;
  1160. session->newdata.NED.velD = getles32(buf, 12) / 100.0;
  1161. /* ignore speed for now */
  1162. GPSD_LOG(LOG_DATA, &session->context->errout,
  1163. "UBX-NAV-VELNED: iTOW=%lld NED velN=%.2f velE=%.2f velD=%.2f\n",
  1164. (long long)session->driver.ubx.iTOW,
  1165. session->newdata.NED.velN,
  1166. session->newdata.NED.velE,
  1167. session->newdata.NED.velD);
  1168. return mask;
  1169. }
  1170. /*
  1171. * SBAS Info UBX-NAV-SBAS
  1172. * Not in u-blox 9
  1173. * FIXME: not well decoded...
  1174. */
  1175. static void ubx_msg_sbas(struct gps_device_t *session, unsigned char *buf,
  1176. size_t data_len)
  1177. {
  1178. unsigned int i, nsv;
  1179. short ubx_PRN;
  1180. short nmea_PRN;
  1181. unsigned char gnssid = 0;
  1182. unsigned char svid = 0;
  1183. if (12 > data_len) {
  1184. GPSD_LOG(LOG_WARN, &session->context->errout,
  1185. "Runt NAV-SBAS message, payload len %zd", data_len);
  1186. return;
  1187. }
  1188. session->driver.ubx.iTOW = getles32(buf, 0);
  1189. GPSD_LOG(LOG_DATA, &session->context->errout,
  1190. "SBAS: %d %d %d %d %d\n",
  1191. (int)getub(buf, 4), (int)getub(buf, 5), (int)getub(buf, 6),
  1192. (int)getub(buf, 7), (int)getub(buf, 8));
  1193. nsv = (int)getub(buf, 8);
  1194. for (i = 0; i < nsv; i++) {
  1195. int off = 12 + 12 * i;
  1196. GPSD_LOG(LOG_DATA, &session->context->errout,
  1197. "SBAS info on SV: %d\n", (int)getub(buf, off));
  1198. }
  1199. /* really 'in_use' depends on the sats info, EGNOS is still
  1200. * in test. In WAAS areas one might also check for the type of
  1201. * corrections indicated
  1202. */
  1203. ubx_PRN = getub(buf, 4);
  1204. nmea_PRN = ubx_to_prn(ubx_PRN, &gnssid, &svid);
  1205. #ifdef __UNUSED
  1206. /* debug */
  1207. GPSD_LOG(LOG_ERROR, &session->context->errout,
  1208. "NAV-SBAS ubx_prn %d gnssid %d, svid %d nmea_PRN %d\n",
  1209. ubx_PRN, gnssid, svid, nmea_PRN);
  1210. #endif /* __UNUSED */
  1211. session->driver.ubx.sbas_in_use = nmea_PRN;
  1212. }
  1213. /*
  1214. * Multi-GNSS Raw measurement Data -- UBX-RXM-RAWX
  1215. * Not in u-blox 5, 6 or 7
  1216. */
  1217. static gps_mask_t ubx_rxm_rawx(struct gps_device_t *session,
  1218. const unsigned char *buf,
  1219. size_t data_len)
  1220. {
  1221. double rcvTow;
  1222. uint16_t week;
  1223. int8_t leapS;
  1224. uint8_t numMeas;
  1225. uint8_t recStat;
  1226. int i;
  1227. const char * obs_code;
  1228. timespec_t ts_tow;
  1229. if (16 > data_len) {
  1230. GPSD_LOG(LOG_WARN, &session->context->errout,
  1231. "Runt RXM-RAWX message, payload len %zd", data_len);
  1232. return 0;
  1233. }
  1234. /* Note: this is "approximately" GPS TOW, this is not iTOW */
  1235. rcvTow = getled64((const char *)buf, 0); /* time of week in seconds */
  1236. week = getleu16(buf, 8);
  1237. leapS = getsb(buf, 10);
  1238. numMeas = getub(buf, 11);
  1239. recStat = getub(buf, 12);
  1240. GPSD_LOG(LOG_PROG, &session->context->errout,
  1241. "UBX-RXM-RAWX: rcvTow %f week %u leapS %d numMeas %u recStat %d\n",
  1242. rcvTow, week, leapS, numMeas, recStat);
  1243. if (recStat & 1) {
  1244. /* Valid leap seconds */
  1245. session->context->leap_seconds = leapS;
  1246. session->context->valid |= LEAP_SECOND_VALID;
  1247. }
  1248. /* convert GPS weeks and "approximately" GPS TOW to UTC */
  1249. DTOTS(&ts_tow, rcvTow);
  1250. // Do not set newdata.time. set gpsdata.raw.mtime
  1251. session->gpsdata.raw.mtime = gpsd_gpstime_resolv(session, week, ts_tow);
  1252. /* zero the measurement data */
  1253. /* so we can tell which meas never got set */
  1254. memset(session->gpsdata.raw.meas, 0, sizeof(session->gpsdata.raw.meas));
  1255. for (i = 0; i < numMeas; i++) {
  1256. int off = 32 * i;
  1257. /* psuedorange in meters */
  1258. double prMes = getled64((const char *)buf, off + 16);
  1259. /* carrier phase in cycles */
  1260. double cpMes = getled64((const char *)buf, off + 24);
  1261. /* doppler in Hz, positive towards sat */
  1262. double doMes = getlef32((const char *)buf, off + 32);
  1263. uint8_t gnssId = getub(buf, off + 36);
  1264. uint8_t svId = getub(buf, off + 37);
  1265. /* reserved in u-blox 8, sigId in u-blox 9 */
  1266. uint8_t sigId = getub(buf, off + 38);
  1267. /* GLONASS frequency slot */
  1268. uint8_t freqId = getub(buf, off + 39);
  1269. /* carrier phase locktime in ms, max 64500ms */
  1270. uint16_t locktime = getleu16(buf, off + 40);
  1271. /* carrier-to-noise density ratio dB-Hz */
  1272. uint8_t cno = getub(buf, off + 42);
  1273. uint8_t prStdev = getub(buf, off + 43) & 0x0f;
  1274. uint8_t cpStdev = getub(buf, off + 44) & 0x0f;
  1275. uint8_t doStdev = getub(buf, off + 45) & 0x0f;
  1276. /* tracking stat
  1277. * bit 0 - prMes valid
  1278. * bit 1 - cpMes valid
  1279. * bit 2 - halfCycle valid
  1280. * bit 3 - halfCycle subtracted from phase
  1281. */
  1282. uint8_t trkStat = getub(buf, off + 46);
  1283. GPSD_LOG(LOG_DATA, &session->context->errout,
  1284. "%u:%u:%u freqId %u prMes %f cpMes %f doMes %f locktime %u\n"
  1285. "cno %u prStdev %u cpStdev %u doStdev %u rtkStat %u\n",
  1286. gnssId, svId, sigId, freqId, prMes, cpMes, doMes, locktime,
  1287. cno, prStdev, cpStdev, doStdev, trkStat);
  1288. session->gpsdata.raw.meas[i].gnssid = gnssId;
  1289. session->gpsdata.raw.meas[i].sigid = sigId;
  1290. /* some of these are GUESSES as the u-blox codes do not
  1291. * match RINEX codes */
  1292. switch (gnssId) {
  1293. case 0: /* GPS */
  1294. switch (sigId) {
  1295. default:
  1296. /* let PPP figure it out */
  1297. /* FALLTHROUGH */
  1298. case 0: /* L1C/A */
  1299. obs_code = "L1C";
  1300. break;
  1301. case 3: /* L2 CL */
  1302. obs_code = "L2C";
  1303. break;
  1304. case 4: /* L2 CM */
  1305. obs_code = "L2X";
  1306. break;
  1307. }
  1308. break;
  1309. case 1: /* SBAS */
  1310. /* sigId added on protVer 27, and SBAS gone in protVer 27
  1311. * so must be L1C/A */
  1312. svId -= 100; /* adjust for RINEX 3 svid */
  1313. /* SBAS can do L5I, but the code? */
  1314. switch (sigId) {
  1315. default:
  1316. /* let PPP figure it out */
  1317. /* FALLTHROUGH */
  1318. case 0: /* L1C/A */
  1319. obs_code = "L1C";
  1320. break;
  1321. }
  1322. obs_code = "L1C"; /* u-blox calls this L1C/A */
  1323. break;
  1324. case 2: /* GALILEO */
  1325. switch (sigId) {
  1326. default:
  1327. /* let PPP figure it out */
  1328. /* FALLTHROUGH */
  1329. case 0: /* */
  1330. obs_code = "L1C"; /* u-blox calls this E1OS or E1C */
  1331. break;
  1332. case 1: /* */
  1333. obs_code = "L1B"; /* u-blox calls this E1B */
  1334. break;
  1335. case 5: /* */
  1336. obs_code = "L7I"; /* u-blox calls this E5bl */
  1337. break;
  1338. case 6: /* */
  1339. obs_code = "L7Q"; /* u-blox calls this E5bQ */
  1340. break;
  1341. }
  1342. break;
  1343. case 3: /* BeiDou */
  1344. switch (sigId) {
  1345. default:
  1346. /* let PPP figure it out */
  1347. /* FALLTHROUGH */
  1348. case 0: /* */
  1349. obs_code = "L2Q"; /* u-blox calls this B1I D1 */
  1350. break;
  1351. case 1: /* */
  1352. obs_code = "L2I"; /* u-blox calls this B1I D2 */
  1353. break;
  1354. case 2: /* */
  1355. obs_code = "L7Q"; /* u-blox calls this B2I D1 */
  1356. break;
  1357. case 3: /* */
  1358. obs_code = "L7I"; /* u-blox calls this B2I D2 */
  1359. break;
  1360. }
  1361. break;
  1362. default: /* huh? */
  1363. case 4: /* IMES. really? */
  1364. obs_code = ""; /* u-blox calls this L1 */
  1365. break;
  1366. case 5: /* QZSS */
  1367. switch (sigId) {
  1368. default:
  1369. /* let PPP figure it out */
  1370. /* FALLTHROUGH */
  1371. case 0: /* */
  1372. obs_code = "L1C"; /* u-blox calls this L1C/A */
  1373. break;
  1374. case 4: /* */
  1375. obs_code = "L2S"; /* u-blox calls this L2CM */
  1376. break;
  1377. case 5: /* */
  1378. obs_code = "L2L"; /* u-blox calls this L2CL*/
  1379. break;
  1380. }
  1381. break;
  1382. case 6: /* GLONASS */
  1383. switch (sigId) {
  1384. default:
  1385. /* let PPP figure it out */
  1386. /* FALLTHROUGH */
  1387. case 0: /* */
  1388. obs_code = "L1C"; /* u-blox calls this L1OF */
  1389. break;
  1390. case 2: /* */
  1391. obs_code = "L2C"; /* u-blox calls this L2OF */
  1392. break;
  1393. }
  1394. break;
  1395. }
  1396. (void)strlcpy(session->gpsdata.raw.meas[i].obs_code, obs_code,
  1397. sizeof(session->gpsdata.raw.meas[i].obs_code));
  1398. session->gpsdata.raw.meas[i].svid = svId;
  1399. session->gpsdata.raw.meas[i].freqid = freqId;
  1400. session->gpsdata.raw.meas[i].snr = cno;
  1401. session->gpsdata.raw.meas[i].satstat = trkStat;
  1402. if (trkStat & 1) {
  1403. /* prMes valid */
  1404. session->gpsdata.raw.meas[i].pseudorange = prMes;
  1405. } else {
  1406. session->gpsdata.raw.meas[i].pseudorange = NAN;
  1407. }
  1408. if ((trkStat & 2) && (5 >= cpStdev)) {
  1409. /* cpMes valid, RTKLIB uses 5 < cpStdev */
  1410. session->gpsdata.raw.meas[i].carrierphase = cpMes;
  1411. } else {
  1412. session->gpsdata.raw.meas[i].carrierphase = NAN;
  1413. }
  1414. session->gpsdata.raw.meas[i].doppler = doMes;
  1415. session->gpsdata.raw.meas[i].codephase = NAN;
  1416. session->gpsdata.raw.meas[i].deltarange = NAN;
  1417. session->gpsdata.raw.meas[i].locktime = locktime;
  1418. if (0 == locktime) {
  1419. /* possible slip */
  1420. session->gpsdata.raw.meas[i].lli = 2;
  1421. }
  1422. }
  1423. return RAW_IS;
  1424. }
  1425. /*
  1426. * Raw Subframes - UBX-RXM-SFRB
  1427. * Not in u-blox 8 or 9
  1428. */
  1429. static gps_mask_t ubx_rxm_sfrb(struct gps_device_t *session,
  1430. unsigned char *buf, size_t data_len)
  1431. {
  1432. unsigned int i, chan, svid;
  1433. uint32_t words[10];
  1434. if (42 > data_len) {
  1435. GPSD_LOG(LOG_WARN, &session->context->errout,
  1436. "Runt RXM-SFRB message, payload len %zd", data_len);
  1437. return 0;
  1438. }
  1439. chan = (unsigned int)getub(buf, 0);
  1440. svid = (unsigned int)getub(buf, 1);
  1441. GPSD_LOG(LOG_PROG, &session->context->errout,
  1442. "UBX-RXM-SFRB: %u %u\n", chan, svid);
  1443. /* UBX does all the parity checking, but still bad data gets through */
  1444. for (i = 0; i < 10; i++) {
  1445. words[i] = (uint32_t)getleu32(buf, 4 * i + 2) & 0xffffff;
  1446. }
  1447. return gpsd_interpret_subframe(session, svid, words);
  1448. }
  1449. /* UBX-INF-* */
  1450. static void ubx_msg_inf(struct gps_device_t *session, unsigned char *buf,
  1451. size_t data_len)
  1452. {
  1453. unsigned short msgid;
  1454. static char txtbuf[MAX_PACKET_LENGTH];
  1455. /* No minimum payload length */
  1456. msgid = (unsigned short)((buf[2] << 8) | buf[3]);
  1457. if (data_len > MAX_PACKET_LENGTH - 1)
  1458. data_len = MAX_PACKET_LENGTH - 1;
  1459. (void)strlcpy(txtbuf, (char *)buf + UBX_PREFIX_LEN, sizeof(txtbuf));
  1460. txtbuf[data_len] = '\0';
  1461. switch (msgid) {
  1462. case UBX_INF_DEBUG:
  1463. GPSD_LOG(LOG_PROG, &session->context->errout, "UBX-INF-DEBUG: %s\n",
  1464. txtbuf);
  1465. break;
  1466. case UBX_INF_TEST:
  1467. GPSD_LOG(LOG_PROG, &session->context->errout, "UBX-INF-TEST: %s\n",
  1468. txtbuf);
  1469. break;
  1470. case UBX_INF_NOTICE:
  1471. GPSD_LOG(LOG_INF, &session->context->errout, "UBX-INF-NOTICE: %s\n",
  1472. txtbuf);
  1473. break;
  1474. case UBX_INF_WARNING:
  1475. GPSD_LOG(LOG_WARN, &session->context->errout, "UBX-INF-WARNING: %s\n",
  1476. txtbuf);
  1477. break;
  1478. case UBX_INF_ERROR:
  1479. GPSD_LOG(LOG_WARN, &session->context->errout, "UBX-INF-ERROR: %s\n",
  1480. txtbuf);
  1481. break;
  1482. default:
  1483. break;
  1484. }
  1485. return;
  1486. }
  1487. /**
  1488. * Time Pulse Timedata - UBX-TIM-TP
  1489. */
  1490. static gps_mask_t
  1491. ubx_msg_tim_tp(struct gps_device_t *session, unsigned char *buf,
  1492. size_t data_len)
  1493. {
  1494. gps_mask_t mask = ONLINE_SET;
  1495. uint32_t towMS;
  1496. uint32_t towSubMS;
  1497. int32_t qErr;
  1498. uint16_t week;
  1499. uint8_t flags;
  1500. uint8_t refInfo;
  1501. timespec_t ts_tow;
  1502. if (16 > data_len) {
  1503. GPSD_LOG(LOG_WARN, &session->context->errout,
  1504. "Runt TIM-TP message, payload len %zd", data_len);
  1505. return 0;
  1506. }
  1507. towMS = getleu32(buf, 0);
  1508. // towSubMS always seems zero, which will match the PPS
  1509. towSubMS = getleu32(buf, 4);
  1510. qErr = getles32(buf, 8);
  1511. week = getleu16(buf, 12);
  1512. flags = buf[14];
  1513. refInfo = buf[15];
  1514. /* are we UTC, and towSubMs is zero? */
  1515. if (3 == (flags & 0x03) &&
  1516. 0 == towSubMS) {
  1517. // leap already added!?!?
  1518. int saved_leap = session->context->leap_seconds;
  1519. // remove it!
  1520. session->context->leap_seconds = 0;
  1521. /* good, save qErr and qErr_time */
  1522. session->gpsdata.qErr = qErr;
  1523. MSTOTS(&ts_tow, towMS);
  1524. session->gpsdata.qErr_time = gpsd_gpstime_resolv(session, week, ts_tow);
  1525. // restore leap
  1526. session->context->leap_seconds = saved_leap;
  1527. #ifdef __UNUSED
  1528. {
  1529. struct gps_device_t *ppsonly;
  1530. // FIXME!! should be up a layer so other drivers can use it
  1531. // FIXME!! this qErr can only apply to one PPS!
  1532. /* propagate this in-band-time to all PPS-only devices */
  1533. for (ppsonly = devices; ppsonly < devices + MAX_DEVICES; ppsonly++)
  1534. if (ppsonly->sourcetype == source_pps)
  1535. pps_thread_qErrin(&ppsonly->pps_thread, qErr,
  1536. session->gpsdata.qErr_time);
  1537. }
  1538. #endif /* __UNUSED */
  1539. }
  1540. /* cast for 32 bit compatibility */
  1541. GPSD_LOG(LOG_DATA, &session->context->errout,
  1542. "TIM-TP: towMS %lu, towSubMS %lu, qErr %ld week %u "
  1543. "flags %#x, refInfo %#x\n",
  1544. (unsigned long)towMS, (unsigned long)towSubMS, (long)qErr,
  1545. week, flags, refInfo);
  1546. return mask;
  1547. }
  1548. gps_mask_t ubx_parse(struct gps_device_t * session, unsigned char *buf,
  1549. size_t len)
  1550. {
  1551. size_t data_len;
  1552. unsigned short msgid;
  1553. gps_mask_t mask = 0;
  1554. /* the packet at least contains a head long enough for an empty message */
  1555. if (len < UBX_PREFIX_LEN)
  1556. return 0;
  1557. session->cycle_end_reliable = true;
  1558. session->driver.ubx.iTOW = -1; /* set by decoder */
  1559. /* extract message id and length */
  1560. msgid = (buf[2] << 8) | buf[3];
  1561. data_len = (size_t) getles16(buf, 4);
  1562. switch (msgid) {
  1563. case UBX_ACK_ACK:
  1564. if (2 <= data_len) {
  1565. GPSD_LOG(LOG_DATA, &session->context->errout,
  1566. "UBX-ACK-ACK, class: %02x, id: %02x\n",
  1567. buf[UBX_MESSAGE_DATA_OFFSET],
  1568. buf[UBX_MESSAGE_DATA_OFFSET + 1]);
  1569. }
  1570. break;
  1571. case UBX_ACK_NAK:
  1572. if (2 <= data_len) {
  1573. GPSD_LOG(LOG_WARN, &session->context->errout,
  1574. "UBX-ACK-NAK, class: %02x, id: %02x\n",
  1575. buf[UBX_MESSAGE_DATA_OFFSET],
  1576. buf[UBX_MESSAGE_DATA_OFFSET + 1]);
  1577. }
  1578. break;
  1579. case UBX_CFG_PRT:
  1580. if (session->driver.ubx.port_id != buf[UBX_MESSAGE_DATA_OFFSET + 0] ) {
  1581. session->driver.ubx.port_id = buf[UBX_MESSAGE_DATA_OFFSET + 0];
  1582. GPSD_LOG(LOG_INF, &session->context->errout,
  1583. "UBX-CFG-PRT: port %d\n", session->driver.ubx.port_id);
  1584. #ifdef RECONFIGURE_ENABLE
  1585. /* Need to reinitialize since port changed */
  1586. if (session->mode == O_OPTIMIZE) {
  1587. ubx_mode(session, MODE_BINARY);
  1588. } else {
  1589. ubx_mode(session, MODE_NMEA);
  1590. }
  1591. #endif /* RECONFIGURE_ENABLE */
  1592. }
  1593. break;
  1594. case UBX_INF_DEBUG:
  1595. /* FALLTHROUGH */
  1596. case UBX_INF_ERROR:
  1597. /* FALLTHROUGH */
  1598. case UBX_INF_NOTICE:
  1599. /* FALLTHROUGH */
  1600. case UBX_INF_TEST:
  1601. /* FALLTHROUGH */
  1602. case UBX_INF_USER:
  1603. /* FALLTHROUGH */
  1604. case UBX_INF_WARNING:
  1605. ubx_msg_inf(session, buf, data_len);
  1606. break;
  1607. case UBX_MON_EXCEPT:
  1608. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-MON-EXCEPT\n");
  1609. break;
  1610. case UBX_MON_GNSS:
  1611. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-MON-GNSS\n");
  1612. break;
  1613. case UBX_MON_HW:
  1614. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-MON-HW\n");
  1615. break;
  1616. case UBX_MON_HW2:
  1617. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-MON-HW2\n");
  1618. break;
  1619. case UBX_MON_IO:
  1620. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-MON-IO\n");
  1621. break;
  1622. case UBX_MON_IPC:
  1623. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-MON-IPC\n");
  1624. break;
  1625. case UBX_MON_MSGPP:
  1626. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-MON-MSGPP\n");
  1627. break;
  1628. case UBX_MON_PATCH:
  1629. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-MON-PATCH\n");
  1630. break;
  1631. case UBX_MON_RXBUF:
  1632. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-MON-RXBUF\n");
  1633. break;
  1634. case UBX_MON_RXR:
  1635. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-MON-RXR\n");
  1636. break;
  1637. case UBX_MON_SCHED:
  1638. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-MON-SCHED\n");
  1639. break;
  1640. case UBX_MON_SMGR:
  1641. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-MON-SMGR\n");
  1642. break;
  1643. case UBX_MON_TXBUF:
  1644. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-MON-TXBUF\n");
  1645. break;
  1646. case UBX_MON_USB:
  1647. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-MON-USB\n");
  1648. break;
  1649. case UBX_MON_VER:
  1650. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-MON-VER\n");
  1651. ubx_msg_mon_ver(session, buf, data_len);
  1652. break;
  1653. case UBX_NAV_AOPSTATUS:
  1654. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-NAV-AOPSTATUS\n");
  1655. break;
  1656. case UBX_NAV_ATT:
  1657. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-NAV-ATT\n");
  1658. break;
  1659. case UBX_NAV_CLOCK:
  1660. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-NAV-CLOCK\n");
  1661. break;
  1662. case UBX_NAV_DGPS:
  1663. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-NAV-DGPS\n");
  1664. break;
  1665. case UBX_NAV_DOP:
  1666. /* DOP seems to be the last NAV sent in a cycle */
  1667. GPSD_LOG(LOG_PROG, &session->context->errout, "UBX-NAV-DOP\n");
  1668. mask = ubx_msg_nav_dop(session, &buf[UBX_PREFIX_LEN], data_len);
  1669. break;
  1670. case UBX_NAV_EKFSTATUS:
  1671. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-NAV-EKFSTATUS\n");
  1672. break;
  1673. case UBX_NAV_EOE:
  1674. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-NAV-EOE\n");
  1675. mask = ubx_msg_nav_eoe(session, &buf[UBX_PREFIX_LEN], data_len);
  1676. break;
  1677. case UBX_NAV_GEOFENCE:
  1678. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-NAV-GEOFENCE\n");
  1679. break;
  1680. case UBX_NAV_HPPOSECEF:
  1681. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-NAV-HPPOSECEF\n");
  1682. mask = ubx_msg_nav_hpposecef(session, &buf[UBX_PREFIX_LEN], data_len);
  1683. break;
  1684. case UBX_NAV_HPPOSLLH:
  1685. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-NAV-HPPOSLLH\n");
  1686. mask = ubx_msg_nav_hpposllh(session, &buf[UBX_PREFIX_LEN], data_len);
  1687. break;
  1688. case UBX_NAV_ODO:
  1689. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-NAV-ODO\n");
  1690. break;
  1691. case UBX_NAV_ORB:
  1692. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-NAV-ORB\n");
  1693. break;
  1694. case UBX_NAV_POSECEF:
  1695. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-NAV-POSECEF\n");
  1696. mask = ubx_msg_nav_posecef(session, &buf[UBX_PREFIX_LEN], data_len);
  1697. break;
  1698. case UBX_NAV_POSLLH:
  1699. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-NAV-POSLLH\n");
  1700. mask = ubx_msg_nav_posllh(session, &buf[UBX_PREFIX_LEN], data_len);
  1701. break;
  1702. case UBX_NAV_POSUTM:
  1703. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-NAV-POSUTM\n");
  1704. break;
  1705. case UBX_NAV_PVT:
  1706. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-NAV-PVT\n");
  1707. mask = ubx_msg_nav_pvt(session, &buf[UBX_PREFIX_LEN], data_len);
  1708. mask |= REPORT_IS;
  1709. break;
  1710. case UBX_NAV_RELPOSNED:
  1711. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-NAV-RELPOSNED\n");
  1712. mask = ubx_msg_nav_relposned(session, &buf[UBX_PREFIX_LEN], data_len);
  1713. break;
  1714. case UBX_NAV_RESETODO:
  1715. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-NAV-RESETODO\n");
  1716. break;
  1717. case UBX_NAV_SIG:
  1718. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-NAV-SIG\n");
  1719. break;
  1720. case UBX_NAV_SAT:
  1721. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-NAV-SAT\n");
  1722. mask = ubx_msg_nav_sat(session, &buf[UBX_PREFIX_LEN], data_len);
  1723. break;
  1724. case UBX_NAV_SBAS:
  1725. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-NAV-SBAS\n");
  1726. ubx_msg_sbas(session, &buf[UBX_PREFIX_LEN], data_len);
  1727. break;
  1728. case UBX_NAV_SOL:
  1729. /* UBX-NAV-SOL deprecated in u-blox 6, gone in u-blox 9.
  1730. * Use UBX-NAV-PVT instead */
  1731. GPSD_LOG(LOG_PROG, &session->context->errout, "UBX-NAV-SOL\n");
  1732. mask = ubx_msg_nav_sol(session, &buf[UBX_PREFIX_LEN], data_len);
  1733. mask |= REPORT_IS;
  1734. break;
  1735. case UBX_NAV_STATUS:
  1736. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-NAV-STATUS\n");
  1737. break;
  1738. case UBX_NAV_SVIN:
  1739. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-NAV-SVIN\n");
  1740. break;
  1741. case UBX_NAV_SVINFO:
  1742. /* UBX-NAV-SVINFO deprecated, use UBX-NAV-SAT instead */
  1743. GPSD_LOG(LOG_PROG, &session->context->errout, "UBX-NAV-SVINFO\n");
  1744. mask = ubx_msg_nav_svinfo(session, &buf[UBX_PREFIX_LEN], data_len);
  1745. /* this is a hack to move some initialization until after we
  1746. * get some u-blox message so we know the GPS is alive */
  1747. if ('\0' == session->subtype[0]) {
  1748. /* one time only */
  1749. (void)strlcpy(session->subtype, "Unknown", 8);
  1750. /* request SW and HW Versions */
  1751. (void)ubx_write(session, UBX_CLASS_MON, 0x04, NULL, 0);
  1752. }
  1753. break;
  1754. case UBX_NAV_TIMEBDS:
  1755. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-NAV-TIMEBDS\n");
  1756. break;
  1757. case UBX_NAV_TIMEGAL:
  1758. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-NAV-TIMEGAL\n");
  1759. break;
  1760. case UBX_NAV_TIMEGLO:
  1761. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-NAV-TIMEGLO\n");
  1762. break;
  1763. case UBX_NAV_TIMEGPS:
  1764. GPSD_LOG(LOG_PROG, &session->context->errout, "UBX-NAV-TIMEGPS\n");
  1765. mask = ubx_msg_nav_timegps(session, &buf[UBX_PREFIX_LEN], data_len);
  1766. break;
  1767. case UBX_NAV_TIMELS:
  1768. ubx_msg_nav_timels(session, &buf[UBX_PREFIX_LEN], data_len);
  1769. break;
  1770. case UBX_NAV_TIMEUTC:
  1771. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-NAV-TIMEUTC\n");
  1772. break;
  1773. case UBX_NAV_VELECEF:
  1774. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-NAV-VELECEF\n");
  1775. mask = ubx_msg_nav_velecef(session, &buf[UBX_PREFIX_LEN], data_len);
  1776. break;
  1777. case UBX_NAV_VELNED:
  1778. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-NAV-VELNED\n");
  1779. mask = ubx_msg_nav_velned(session, &buf[UBX_PREFIX_LEN], data_len);
  1780. break;
  1781. case UBX_RXM_ALM:
  1782. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-RXM-ALM\n");
  1783. break;
  1784. case UBX_RXM_EPH:
  1785. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-RXM-EPH\n");
  1786. break;
  1787. case UBX_RXM_IMES:
  1788. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-RXM-IMES\n");
  1789. break;
  1790. case UBX_RXM_MEASX:
  1791. GPSD_LOG(LOG_PROG, &session->context->errout, "UBX-RXM-MEASX\n");
  1792. break;
  1793. case UBX_RXM_PMREQ:
  1794. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-RXM-PMREQ\n");
  1795. break;
  1796. case UBX_RXM_POSREQ:
  1797. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-RXM-POSREQ\n");
  1798. break;
  1799. case UBX_RXM_RAW:
  1800. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-RXM-RAW\n");
  1801. break;
  1802. case UBX_RXM_RAWX:
  1803. mask = ubx_rxm_rawx(session, &buf[UBX_PREFIX_LEN], data_len);
  1804. break;
  1805. case UBX_RXM_RLM:
  1806. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-RXM-RLM\n");
  1807. break;
  1808. case UBX_RXM_RTCM:
  1809. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-RXM-RTCM\n");
  1810. break;
  1811. case UBX_RXM_SFRB:
  1812. mask = ubx_rxm_sfrb(session, &buf[UBX_PREFIX_LEN], data_len);
  1813. break;
  1814. case UBX_RXM_SFRBX:
  1815. GPSD_LOG(LOG_PROG, &session->context->errout, "UBX-RXM-SFRBX\n");
  1816. break;
  1817. case UBX_RXM_SVSI:
  1818. GPSD_LOG(LOG_PROG, &session->context->errout, "UBX-RXM-SVSI\n");
  1819. break;
  1820. case UBX_TIM_DOSC:
  1821. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-TIM-DOSC\n");
  1822. break;
  1823. case UBX_TIM_FCHG:
  1824. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-TIM-FCHG\n");
  1825. break;
  1826. case UBX_TIM_HOC:
  1827. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-TIM-HOC\n");
  1828. break;
  1829. case UBX_TIM_SMEAS:
  1830. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-TIM-SMEAS\n");
  1831. break;
  1832. case UBX_TIM_SVIN:
  1833. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-TIM-SVIN\n");
  1834. break;
  1835. case UBX_TIM_TM:
  1836. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-TIM-TM\n");
  1837. break;
  1838. case UBX_TIM_TM2:
  1839. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-TIM-TM2\n");
  1840. break;
  1841. case UBX_TIM_TP:
  1842. mask = ubx_msg_tim_tp(session, &buf[UBX_PREFIX_LEN], data_len);
  1843. break;
  1844. case UBX_TIM_TOS:
  1845. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-TIM-TOS\n");
  1846. break;
  1847. case UBX_TIM_VCOCAL:
  1848. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-TIM-VCOCAL\n");
  1849. break;
  1850. case UBX_TIM_VRFY:
  1851. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX-TIM-VRFY\n");
  1852. break;
  1853. default:
  1854. GPSD_LOG(LOG_WARN, &session->context->errout,
  1855. "UBX: unknown packet id 0x%04hx (length %zd)\n",
  1856. msgid, len);
  1857. }
  1858. /* end of cycle ? */
  1859. if (session->driver.ubx.end_msgid == msgid) {
  1860. /* end of cycle, report it */
  1861. GPSD_LOG(LOG_PROG, &session->context->errout,
  1862. "UBX: cycle end %x\n", msgid);
  1863. mask |= REPORT_IS;
  1864. }
  1865. /* start of cycle ? */
  1866. if ( -1 < session->driver.ubx.iTOW) {
  1867. /* this sentence has a good time */
  1868. /* debug
  1869. GPSD_LOG(LOG_ERROR, &session->context->errout,
  1870. "UBX: time %.2f msgid %x\n",
  1871. session->newdata.time, msgid);
  1872. GPSD_LOG(LOG_ERROR, &session->context->errout,
  1873. " last_time %s last_msgid %x\n",
  1874. timespec_str(&session->driver.ubx.last_time, ts_buf,
  1875. sizeof(ts_buf)),
  1876. session->driver.ubx.last_msgid);
  1877. */
  1878. /* iTOW is to ms, can go forward or backwards */
  1879. if ((session->driver.ubx.last_iTOW != session->driver.ubx.iTOW) &&
  1880. (session->driver.ubx.end_msgid !=
  1881. session->driver.ubx.last_msgid)) {
  1882. /* time changed, new cycle ender */
  1883. session->driver.ubx.end_msgid = session->driver.ubx.last_msgid;
  1884. session->driver.ubx.last_iTOW = session->driver.ubx.iTOW;
  1885. /* debug
  1886. GPSD_LOG(LOG_ERROR, &session->context->errout,
  1887. "UBX: new ender %x, iTOW %.2f\n",
  1888. session->driver.ubx.end_msgid, iTOW);
  1889. */
  1890. }
  1891. session->driver.ubx.last_msgid = msgid;
  1892. /* FIXME: last_time never used... */
  1893. session->driver.ubx.last_time = session->newdata.time;
  1894. } else {
  1895. /* no time */
  1896. /* debug
  1897. GPSD_LOG(LOG_ERROR, &session->context->errout,
  1898. "UBX: No time, msgid %x\n", msgid);
  1899. */
  1900. }
  1901. return mask | ONLINE_SET;
  1902. }
  1903. static gps_mask_t parse_input(struct gps_device_t *session)
  1904. {
  1905. if (session->lexer.type == UBX_PACKET) {
  1906. return ubx_parse(session, session->lexer.outbuffer,
  1907. session->lexer.outbuflen);
  1908. } else
  1909. return generic_parse_input(session);
  1910. }
  1911. bool ubx_write(struct gps_device_t * session,
  1912. unsigned int msg_class, unsigned int msg_id,
  1913. unsigned char *msg, size_t data_len)
  1914. {
  1915. unsigned char CK_A, CK_B;
  1916. ssize_t count;
  1917. size_t i;
  1918. bool ok;
  1919. /* do not write if -b (readonly) option set */
  1920. if (session->context->readonly)
  1921. return true;
  1922. session->msgbuf[0] = 0xb5;
  1923. session->msgbuf[1] = 0x62;
  1924. CK_A = CK_B = 0;
  1925. session->msgbuf[2] = msg_class;
  1926. session->msgbuf[3] = msg_id;
  1927. session->msgbuf[4] = data_len & 0xff;
  1928. session->msgbuf[5] = (data_len >> 8) & 0xff;
  1929. assert(msg != NULL || data_len == 0);
  1930. if (msg != NULL)
  1931. (void)memcpy(&session->msgbuf[6], msg, data_len);
  1932. /* calculate CRC */
  1933. for (i = 2; i < 6; i++) {
  1934. CK_A += session->msgbuf[i];
  1935. CK_B += CK_A;
  1936. }
  1937. if (msg != NULL)
  1938. for (i = 0; i < data_len; i++) {
  1939. CK_A += msg[i];
  1940. CK_B += CK_A;
  1941. }
  1942. session->msgbuf[6 + data_len] = CK_A;
  1943. session->msgbuf[7 + data_len] = CK_B;
  1944. session->msgbuflen = data_len + 8;
  1945. GPSD_LOG(LOG_PROG, &session->context->errout,
  1946. "=> GPS: UBX class: %02x, id: %02x, len: %zd, crc: %02x%02x\n",
  1947. msg_class, msg_id, data_len,
  1948. CK_A, CK_B);
  1949. count = gpsd_write(session, session->msgbuf, session->msgbuflen);
  1950. ok = (count == (ssize_t) session->msgbuflen);
  1951. return (ok);
  1952. }
  1953. #ifdef CONTROLSEND_ENABLE
  1954. static ssize_t ubx_control_send(struct gps_device_t *session, char *msg,
  1955. size_t data_len)
  1956. /* not used by gpsd, it's for gpsctl and friends */
  1957. {
  1958. return ubx_write(session, (unsigned int)msg[0], (unsigned int)msg[1],
  1959. (unsigned char *)msg + 2,
  1960. (size_t)(data_len - 2)) ? ((ssize_t) (data_len + 7)) : -1;
  1961. }
  1962. #endif /* CONTROLSEND_ENABLE */
  1963. static void ubx_init_query(struct gps_device_t *session)
  1964. {
  1965. /* UBX-MON-VER: query for version information */
  1966. (void)ubx_write(session, UBX_CLASS_MON, 0x04, NULL, 0);
  1967. }
  1968. static void ubx_event_hook(struct gps_device_t *session, event_t event)
  1969. {
  1970. if (session->context->readonly)
  1971. return;
  1972. else if (event == event_identified) {
  1973. GPSD_LOG(LOG_DATA, &session->context->errout, "UBX identified\n");
  1974. /* no longer set UBX-CFG-SBAS here, u-blox 9 does not have it */
  1975. #ifdef RECONFIGURE_ENABLE
  1976. /*
  1977. * Turn off NMEA output, turn on UBX on this port.
  1978. */
  1979. if (session->mode == O_OPTIMIZE) {
  1980. ubx_mode(session, MODE_BINARY);
  1981. } else {
  1982. ubx_mode(session, MODE_NMEA);
  1983. }
  1984. #endif /* RECONFIGURE_ENABLE */
  1985. } else if (event == event_deactivate) {
  1986. /* There used to be a hotstart/reset here.
  1987. * That caused u-blox USB to re-enumerate.
  1988. * Sometimes to a new device name.
  1989. * Bad. Don't do that anymore...
  1990. */
  1991. }
  1992. }
  1993. #ifdef RECONFIGURE_ENABLE
  1994. static void ubx_cfg_prt(struct gps_device_t *session,
  1995. speed_t speed, const char parity, const int stopbits,
  1996. const int mode)
  1997. /* generate and send a configuration block */
  1998. {
  1999. unsigned long usart_mode = 0;
  2000. unsigned char buf[UBX_CFG_LEN];
  2001. memset(buf, '\0', UBX_CFG_LEN);
  2002. /*
  2003. * When this is called from gpsd, the initial probe for UBX should
  2004. * have picked up the device's port number from the CFG_PRT response.
  2005. */
  2006. /* FIXME! Bad test, port_id == 0 is valid too. DDC (I2X) = port 0 */
  2007. if (session->driver.ubx.port_id != 0) {
  2008. buf[0] = session->driver.ubx.port_id;
  2009. }
  2010. /*
  2011. * This default can be hit if we haven't sent a CFG_PRT query yet,
  2012. * which can happen in gpsmon because it doesn't autoprobe.
  2013. *
  2014. * What we'd like to do here is dispatch to USART1_ID or
  2015. * USB_ID intelligently based on whether this is a USB or RS232
  2016. * source. Unfortunately the GR601-W screws that up by being
  2017. * a USB device with port_id 1. So we bite the bullet and
  2018. * default to port 1.
  2019. *
  2020. * Without further logic, this means gpsmon wouldn't be able to
  2021. * change the speed on the EVK 6H's USB port. But! To pick off
  2022. * the EVK 6H on Linux as a special case, we notice that its
  2023. * USB device name is /dev/ACMx - it presents as a USB modem.
  2024. *
  2025. * This logic will fail on any USB u-blox device that presents
  2026. * as an ordinary USB serial device (/dev/USB*) and actually
  2027. * has port ID 3 the way it "ought" to.
  2028. */
  2029. else if (strstr(session->gpsdata.dev.path, "/ACM") != NULL) {
  2030. /* using the built in USB port */
  2031. session->driver.ubx.port_id = buf[0] = USB_ID;
  2032. } else {
  2033. /* A guess. Could be UART2, or SPI, or DDC port */
  2034. session->driver.ubx.port_id = buf[0] = USART1_ID;
  2035. }
  2036. putle32(buf, 8, speed);
  2037. /*
  2038. * u-blox tech support explains the default contents of the mode
  2039. * field as follows:
  2040. *
  2041. * D0 08 00 00 mode (LSB first)
  2042. *
  2043. * re-ordering bytes: 000008D0
  2044. * dividing into fields: 000000000000000000 00 100 0 11 0 1 0000
  2045. * nStopbits = 00 = 1
  2046. * parity = 100 = none
  2047. * charLen = 11 = 8-bit
  2048. * reserved1 = 1
  2049. *
  2050. * The protocol reference further gives the following subfield values:
  2051. * 01 = 1.5 stop bits (?)
  2052. * 10 = 2 stopbits
  2053. * 000 = even parity
  2054. * 001 = odd parity
  2055. * 10x = no parity
  2056. * 10 = 7 bits
  2057. *
  2058. * Some UBX reference code amplifies this with:
  2059. *
  2060. * prtcfg.mode = (1<<4) | // compatibility with ANTARIS 4
  2061. * (1<<7) | // charLen = 11 = 8 bit
  2062. * (1<<6) | // charLen = 11 = 8 bit
  2063. * (1<<11); // parity = 10x = none
  2064. */
  2065. usart_mode |= (1<<4); /* reserved1 Antaris 4 compatibility bit */
  2066. usart_mode |= (1<<7); /* high bit of charLen */
  2067. /* u-blox 5+ binary only supports 8N1 */
  2068. switch (parity) {
  2069. case (int)'E':
  2070. case 2:
  2071. usart_mode |= (1<<7); /* 7E */
  2072. break;
  2073. case (int)'O':
  2074. case 1:
  2075. usart_mode |= (1<<9) | (1<<7); /* 7O */
  2076. break;
  2077. case (int)'N':
  2078. case 0:
  2079. default:
  2080. usart_mode |= (1<<11) | (3<<6); /* 8N */
  2081. break;
  2082. }
  2083. if (stopbits == 2)
  2084. usart_mode |= (1<<13);
  2085. putle32(buf, 4, usart_mode);
  2086. /* enable all input protocols by default */
  2087. /* FIXME! RTCM3 needs to be set too */
  2088. buf[12] = NMEA_PROTOCOL_MASK | UBX_PROTOCOL_MASK | RTCM_PROTOCOL_MASK;
  2089. /* FIXME? RTCM/RTCM3 needs to be set too? */
  2090. buf[outProtoMask] = (mode == MODE_NMEA
  2091. ? NMEA_PROTOCOL_MASK : UBX_PROTOCOL_MASK);
  2092. (void)ubx_write(session, 0x06u, 0x00, buf, sizeof(buf));
  2093. GPSD_LOG(LOG_DATA, &session->context->errout,
  2094. "UBX ubx_cfg_prt mode:%d, port:%d\n", mode, buf[0]);
  2095. /* selectively enable output protocols */
  2096. if (mode == MODE_NMEA) {
  2097. /*
  2098. * We have to club the GR601-W over the head to make it stop emitting
  2099. * UBX after we've told it to start. Turning off the UBX protocol
  2100. * mask, by itself, seems to be ineffective.
  2101. */
  2102. unsigned char msg[3];
  2103. msg[0] = 0x01; /* class */
  2104. msg[1] = 0x04; /* msg id = UBX-NAV-DOP */
  2105. msg[2] = 0x00; /* rate */
  2106. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2107. /* UBX-NAV-SOL deprecated in u-blox 6, gone in u-blox 9.
  2108. * UBX-NAV-PVT for later models. Turn both off */
  2109. msg[0] = 0x01; /* class */
  2110. msg[1] = 0x06; /* msg id = NAV-SOL */
  2111. msg[2] = 0x00; /* rate */
  2112. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2113. msg[0] = 0x01; /* class */
  2114. msg[1] = 0x07; /* msg id = NAV-PVT */
  2115. msg[2] = 0x00; /* rate */
  2116. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2117. msg[0] = 0x01; /* class */
  2118. msg[1] = 0x20; /* msg id = UBX-NAV-TIMEGPS */
  2119. msg[2] = 0x00; /* rate */
  2120. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2121. /* NAV-SVINFO became NAV-SAT */
  2122. msg[0] = 0x01; /* class */
  2123. msg[1] = 0x30; /* msg id = NAV-SVINFO */
  2124. msg[2] = 0x00; /* rate */
  2125. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2126. msg[0] = 0x01; /* class */
  2127. msg[1] = 0x35; /* msg id = NAV-SAT */
  2128. msg[2] = 0x00; /* rate */
  2129. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2130. msg[0] = 0x01; /* class */
  2131. msg[1] = 0x32; /* msg id = NAV-SBAS */
  2132. msg[2] = 0x00; /* rate */
  2133. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2134. /* UBX-NAV-EOE */
  2135. msg[0] = 0x01; /* class */
  2136. msg[1] = 0x61; /* msg id = NAV-EOE */
  2137. msg[2] = 0x00; /* rate */
  2138. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2139. /* try to improve the sentence mix. in particular by enabling ZDA */
  2140. msg[0] = 0xf0; /* class */
  2141. msg[1] = 0x09; /* msg id = GBS */
  2142. msg[2] = 0x01; /* rate */
  2143. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2144. msg[0] = 0xf0; /* class */
  2145. msg[1] = 0x00; /* msg id = GGA */
  2146. msg[2] = 0x01; /* rate */
  2147. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2148. msg[0] = 0xf0; /* class */
  2149. msg[1] = 0x02; /* msg id = GSA */
  2150. msg[2] = 0x01; /* rate */
  2151. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2152. msg[0] = 0xf0; /* class */
  2153. msg[1] = 0x07; /* msg id = GST */
  2154. msg[2] = 0x01; /* rate */
  2155. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2156. msg[0] = 0xf0; /* class */
  2157. msg[1] = 0x03; /* msg id = GSV */
  2158. msg[2] = 0x01; /* rate */
  2159. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2160. msg[0] = 0xf0; /* class */
  2161. msg[1] = 0x04; /* msg id = RMC */
  2162. msg[2] = 0x01; /* rate */
  2163. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2164. msg[0] = 0xf0; /* class */
  2165. msg[1] = 0x05; /* msg id = VTG */
  2166. msg[2] = 0x01; /* rate */
  2167. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2168. msg[0] = 0xf0; /* class */
  2169. msg[1] = 0x08; /* msg id = ZDA */
  2170. msg[2] = 0x01; /* rate */
  2171. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2172. } else { /* MODE_BINARY */
  2173. /*
  2174. * Just enabling the UBX protocol for output is not enough to
  2175. * actually get UBX output; the sentence mix is initially empty.
  2176. * Fix that...
  2177. */
  2178. /* FIXME: possibly sending too many messages without waiting
  2179. * for u-blox ACK, over running its input buffer.
  2180. *
  2181. * for example, the UBX-MON-VER fails here, but works in other
  2182. * contexts
  2183. */
  2184. unsigned char msg[3] = {0, 0, 0};
  2185. /* request SW and HW Versions */
  2186. (void)ubx_write(session, UBX_CLASS_MON, 0x04, msg, 0);
  2187. msg[0] = 0x01; /* class */
  2188. msg[1] = 0x04; /* msg id = UBX-NAV-DOP */
  2189. msg[2] = 0x01; /* rate */
  2190. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2191. /* UBX-NAV-SOL deprecated in u-blox 6, gone in u-blox 9.
  2192. * Use UBX-NAV-PVT after u-blox 7 */
  2193. if (10 > session->driver.ubx.protver) {
  2194. /* unknown version, enable both */
  2195. msg[0] = 0x01; /* class */
  2196. msg[1] = 0x06; /* msg id = NAV-SOL */
  2197. msg[2] = 0x01; /* rate */
  2198. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2199. msg[0] = 0x01; /* class */
  2200. msg[1] = 0x07; /* msg id = NAV-PVT */
  2201. msg[2] = 0x01; /* rate */
  2202. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2203. } else if (15 > session->driver.ubx.protver) {
  2204. /* before u-blox 8, just NAV-SOL */
  2205. /* do not do both to avoid NACKs */
  2206. msg[0] = 0x01; /* class */
  2207. msg[1] = 0x06; /* msg id = NAV-SOL */
  2208. msg[2] = 0x01; /* rate */
  2209. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2210. } else {
  2211. /* u-blox 8 or later */
  2212. msg[0] = 0x01; /* class */
  2213. msg[1] = 0x07; /* msg id = NAV-PVT */
  2214. msg[2] = 0x01; /* rate */
  2215. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2216. }
  2217. /* UBX-NAV-TIMEGPS is a great cycle ender */
  2218. msg[0] = 0x01; /* class */
  2219. msg[1] = 0x20; /* msg id = UBX-NAV-TIMEGPS */
  2220. msg[2] = 0x01; /* rate */
  2221. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2222. /* UBX-NAV-SVINFO deprecated in u-blox 8, gone in u-blox 9.
  2223. * Use UBX-NAV-SAT after u-blox 7 */
  2224. if (10 > session->driver.ubx.protver) {
  2225. /* unknown version, enable both */
  2226. msg[0] = 0x01; /* class */
  2227. msg[1] = 0x30; /* msg id = NAV-SVINFO */
  2228. msg[2] = 0x0a; /* rate */
  2229. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2230. msg[0] = 0x01; /* class */
  2231. msg[1] = 0x35; /* msg id = NAV-SAT */
  2232. msg[2] = 0x0a; /* rate */
  2233. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2234. } else if (15 > session->driver.ubx.protver) {
  2235. /* before u-blox 8, just NAV-SVINFO */
  2236. /* do not do both to avoid NACKs */
  2237. msg[0] = 0x01; /* class */
  2238. msg[1] = 0x30; /* msg id = NAV-SVINFO */
  2239. msg[2] = 0x0a; /* rate */
  2240. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2241. } else {
  2242. /* u-blox 8 or later */
  2243. msg[0] = 0x01; /* class */
  2244. msg[1] = 0x35; /* msg id = NAV-SAT */
  2245. msg[2] = 0x0a; /* rate */
  2246. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2247. }
  2248. if (24 > session->driver.ubx.protver) {
  2249. /* Gone after u-blox 8 */
  2250. msg[0] = 0x01; /* class */
  2251. msg[1] = 0x32; /* msg id = NAV-SBAS */
  2252. msg[2] = 0x0a; /* rate */
  2253. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2254. }
  2255. msg[0] = 0x01; /* class */
  2256. msg[1] = 0x01; /* msg id = UBX-NAV-POSECEF */
  2257. msg[2] = 0x01; /* rate */
  2258. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2259. msg[0] = 0x01; /* class */
  2260. msg[1] = 0x11; /* msg id = UBX-NAV-VELECEF */
  2261. msg[2] = 0x01; /* rate */
  2262. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2263. msg[0] = 0x01; /* class */
  2264. msg[1] = 0x26; /* msg id = UBX-NAV-TIMELS */
  2265. msg[2] = 0xff; /* about every 4 minutes if nav rate is 1Hz */
  2266. (void)ubx_write(session, 0x06, 0x01, msg, 3);
  2267. if (18 <= session->driver.ubx.protver) {
  2268. /* first in u-blox 8 */
  2269. /* UBX-NAV-EOE makes a good cycle ender */
  2270. msg[0] = 0x01; /* class */
  2271. msg[1] = 0x61; /* msg id = NAV-EOE */
  2272. msg[2] = 0x00; /* rate */
  2273. (void)ubx_write(session, 0x06u, 0x01, msg, 3);
  2274. }
  2275. }
  2276. }
  2277. static void ubx_mode(struct gps_device_t *session, int mode)
  2278. {
  2279. ubx_cfg_prt(session,
  2280. gpsd_get_speed(session),
  2281. gpsd_get_parity(session),
  2282. gpsd_get_stopbits(session),
  2283. mode);
  2284. }
  2285. static bool ubx_speed(struct gps_device_t *session,
  2286. speed_t speed, char parity, int stopbits)
  2287. {
  2288. ubx_cfg_prt(session,
  2289. speed,
  2290. parity,
  2291. stopbits,
  2292. (session->lexer.type == UBX_PACKET) ? MODE_BINARY : MODE_NMEA);
  2293. return true;
  2294. }
  2295. static bool ubx_rate(struct gps_device_t *session, double cycletime)
  2296. /* change the sample rate of the GPS */
  2297. {
  2298. unsigned short s;
  2299. unsigned char msg[6] = {
  2300. 0x00, 0x00, /* U2: Measurement rate (ms) */
  2301. 0x00, 0x01, /* U2: Navigation rate (cycles) */
  2302. 0x00, 0x00, /* U2: Alignment to reference time: 0 = UTC, !0 = GPS */
  2303. };
  2304. /* clamp to cycle times that i know work on my receiver */
  2305. if (cycletime > 1000.0)
  2306. cycletime = 1000.0;
  2307. if (cycletime < 200.0)
  2308. cycletime = 200.0;
  2309. GPSD_LOG(LOG_DATA, &session->context->errout,
  2310. "UBX rate change, report every %f secs\n", cycletime);
  2311. s = (unsigned short)cycletime;
  2312. msg[0] = (unsigned char)(s >> 8);
  2313. msg[1] = (unsigned char)(s & 0xff);
  2314. return ubx_write(session, 0x06, 0x08, msg, 6); /* CFG-RATE */
  2315. }
  2316. #endif /* RECONFIGURE_ENABLE */
  2317. /* This is everything we export */
  2318. /* *INDENT-OFF* */
  2319. const struct gps_type_t driver_ubx = {
  2320. .type_name = "u-blox", /* Full name of type */
  2321. .packet_type = UBX_PACKET, /* associated lexer packet type */
  2322. .flags = DRIVER_STICKY, /* remember this */
  2323. .trigger = NULL,
  2324. /* Number of satellite channels supported by the device */
  2325. .channels = 50,
  2326. .probe_detect = NULL, /* Startup-time device detector */
  2327. /* Packet getter (using default routine) */
  2328. .get_packet = generic_get,
  2329. .parse_packet = parse_input, /* Parse message packets */
  2330. /* RTCM handler (using default routine) */
  2331. .rtcm_writer = gpsd_write,
  2332. .init_query = ubx_init_query, /* non-perturbing initial query */
  2333. .event_hook = ubx_event_hook, /* Fire on various lifetime events */
  2334. #ifdef RECONFIGURE_ENABLE
  2335. .speed_switcher = ubx_speed, /* Speed (baudrate) switch */
  2336. .mode_switcher = ubx_mode, /* Mode switcher */
  2337. .rate_switcher = ubx_rate, /* Message delivery rate switcher */
  2338. .min_cycle.tv_sec = 0, /* not relevant, no rate switch */
  2339. .min_cycle.tv_nsec = 250000000, /* Maximum 4Hz sample rate */
  2340. #endif /* RECONFIGURE_ENABLE */
  2341. #ifdef CONTROLSEND_ENABLE
  2342. .control_send = ubx_control_send,/* how to send a control string */
  2343. #endif /* CONTROLSEND_ENABLE */
  2344. .time_offset = NULL, /* no method for NTP fudge factor */
  2345. };
  2346. /* *INDENT-ON* */
  2347. #endif /* defined(UBLOX_ENABLE) && defined(BINARY_ENABLE) */