luat_lib_libgnss.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119
  1. /*
  2. @module libgnss
  3. @summary NMEA数据处理
  4. @version 1.0
  5. @date 2020.07.03
  6. @demo libgnss
  7. @tag LUAT_USE_LIBGNSS
  8. @usage
  9. -- 提醒: 本库输出的坐标,均为 WGS84 坐标系
  10. -- 如需要在国内地图使用, 要转换成对应地图的坐标系, 例如 GCJ02 BD09
  11. -- 相关链接: https://lbsyun.baidu.com/index.php?title=coordinate
  12. -- 相关链接: https://www.openluat.com/GPS-Offset.html
  13. -- 方案1, 经lua层进行数据中转
  14. uart.setup(2, 115200)
  15. uart.on(2, "recv", function(id, len)
  16. while 1 do
  17. local data = uart.read(id, 1024)
  18. if data and #data > 1 then
  19. libgnss.parse(data)
  20. else
  21. break
  22. end
  23. end
  24. end)
  25. -- 方案2, 适合2022.12.26之后编译固件,效率更高一些
  26. uart.setup(2, 115200)
  27. libgnss.bind(2)
  28. -- 可选调试模式
  29. -- libgnss.debug(true)
  30. sys.subscribe("GNSS_STATE", function(event, ticks)
  31. -- event取值有
  32. -- FIXED 定位成功
  33. -- LOSE 定位丢失
  34. -- ticks是事件发生的时间,一般可以忽略
  35. log.info("gnss", "state", event, ticks)
  36. end)
  37. */
  38. #include "luat_base.h"
  39. #include "luat_msgbus.h"
  40. #include "luat_mem.h"
  41. #include "luat_uart.h"
  42. #include "luat_mcu.h"
  43. #include "luat_rtc.h"
  44. #define LUAT_LOG_TAG "gnss"
  45. #include "luat_log.h"
  46. #include "minmea.h"
  47. extern luat_libgnss_t *libgnss_gnss;
  48. // extern luat_libgnss_t *libgnss_gnsstmp;
  49. extern char* libgnss_recvbuff;
  50. extern int libgnss_route_uart_id;
  51. extern int gnss_debug;
  52. void luat_uart_set_app_recv(int id, luat_uart_recv_callback_t cb);
  53. static inline void push_gnss_value(lua_State *L, struct minmea_float *f, int mode) {
  54. if (f->value == 0) {
  55. lua_pushinteger(L, 0);
  56. return;
  57. }
  58. switch (mode)
  59. {
  60. case 0:
  61. lua_pushnumber(L, minmea_tofloat(f));
  62. break;
  63. case 1:
  64. lua_pushinteger(L, minmea_tocoord2(f));
  65. break;
  66. case 2:
  67. lua_pushnumber(L, minmea_tocoord(f));
  68. break;
  69. default:
  70. lua_pushnumber(L, minmea_tocoord(f));
  71. break;
  72. }
  73. }
  74. static int luat_libgnss_state_handler(lua_State *L, void* ptr) {
  75. (void)ptr;
  76. rtos_msg_t* msg = (rtos_msg_t*)lua_topointer(L, -1);
  77. lua_getglobal(L, "sys_pub");
  78. if (!lua_isfunction(L, -1)) {
  79. return 0;
  80. }
  81. /*
  82. @sys_pub libgnss
  83. GNSS状态变化
  84. GNSS_STATE
  85. @usage
  86. sys.subscribe("GNSS_STATE", function(event, ticks)
  87. -- event取值有
  88. -- FIXED 定位成功
  89. -- LOSE 定位丢失
  90. -- ticks是事件发生的时间,一般可以忽略
  91. log.info("gnss", "state", event, ticks)
  92. end)
  93. */
  94. lua_pushliteral(L, "GNSS_STATE");
  95. switch (msg->arg1)
  96. {
  97. case GNSS_STATE_FIXED:
  98. lua_pushliteral(L, "FIXED");
  99. break;
  100. case GNSS_STATE_LOSE:
  101. lua_pushliteral(L, "LOSE");
  102. break;
  103. case GNSS_STATE_OPEN:
  104. lua_pushliteral(L, "OPEN");
  105. break;
  106. case GNSS_STATE_CLOSE:
  107. lua_pushliteral(L, "CLOSE");
  108. break;
  109. default:
  110. return 0;
  111. }
  112. lua_pushinteger(L, msg->arg2);
  113. lua_call(L, 3, 0);
  114. return 0;
  115. }
  116. int luat_libgnss_state_onchanged(int state) {
  117. rtos_msg_t msg = {0};
  118. msg.handler = luat_libgnss_state_handler;
  119. msg.arg1 = state;
  120. #ifdef LUAT_USE_MCU
  121. msg.arg2 = luat_mcu_ticks();
  122. #endif
  123. luat_msgbus_put(&msg, 0);
  124. return 0;
  125. }
  126. static void put_datetime(lua_State*L, struct tm* rtime) {
  127. lua_pushliteral(L, "year");
  128. lua_pushinteger(L, rtime->tm_year);
  129. lua_settable(L, -3);
  130. lua_pushliteral(L, "month");
  131. lua_pushinteger(L, rtime->tm_mon + 1); // 比较纠结, 要不要兼容老的呢?
  132. lua_settable(L, -3);
  133. lua_pushliteral(L, "day");
  134. lua_pushinteger(L, rtime->tm_mday);
  135. lua_settable(L, -3);
  136. lua_pushliteral(L, "hour");
  137. lua_pushinteger(L, rtime->tm_hour);
  138. lua_settable(L, -3);
  139. lua_pushliteral(L, "min");
  140. lua_pushinteger(L, rtime->tm_min);
  141. lua_settable(L, -3);
  142. lua_pushliteral(L, "sec");
  143. lua_pushinteger(L, rtime->tm_sec);
  144. lua_settable(L, -3);
  145. }
  146. static int l_gnss_callback(lua_State *L, void* ptr){
  147. (void)ptr;
  148. rtos_msg_t* msg = (rtos_msg_t*)lua_topointer(L, -1);
  149. luat_libgnss_uart_recv_cb(msg->arg1, msg->arg2);
  150. return 0;
  151. }
  152. static void l_libgnss_uart_recv_cb(int uart_id, uint32_t data_len)
  153. {
  154. rtos_msg_t msg = {0};
  155. msg.handler = l_gnss_callback;
  156. msg.arg1 = uart_id;
  157. msg.arg2 = data_len;
  158. luat_msgbus_put(&msg, 0);
  159. }
  160. /**
  161. 处理nmea数据
  162. @api libgnss.parse(str)
  163. @string 原始nmea数据
  164. @usage
  165. -- 解析nmea数据
  166. libgnss.parse(indata)
  167. log.info("nmea", json.encode(libgnss.getRmc(), "11g"))
  168. */
  169. static int l_libgnss_parse(lua_State *L) {
  170. size_t len = 0;
  171. const char* str = luaL_checklstring(L, 1, &len);
  172. if (len > 0) {
  173. luat_libgnss_parse_data(str, len);
  174. }
  175. return 0;
  176. }
  177. /**
  178. 当前是否已经定位成功
  179. @api libgnss.isFix()
  180. @return boolean 定位成功与否
  181. @usage
  182. log.info("nmea", "isFix", libgnss.isFix())
  183. */
  184. static int l_libgnss_is_fix(lua_State *L) {
  185. if (libgnss_gnss == NULL) {
  186. lua_pushboolean(L, 0);
  187. }
  188. else
  189. lua_pushboolean(L, libgnss_gnss->frame_rmc.valid != 0 ? 1 : 0);
  190. return 1;
  191. }
  192. /**
  193. 获取位置信息
  194. @api libgnss.getIntLocation(speed_type)
  195. @int 速度单位,默认是m/h
  196. @return int lat数据, 格式为 ddddddddd
  197. @return int lng数据, 格式为 ddddddddd
  198. @return int speed数据, 单位米. 于2023.9.26修正
  199. @usage
  200. -- 建议用libgnss.getRmc(1)
  201. log.info("nmea", "loc", libgnss.getIntLocation())
  202. -- 2023.12.11 新增speed_type参数
  203. --[[
  204. 速度单位可选值
  205. 0 - m/h 米/小时, 默认值, 整型
  206. 1 - m/s 米/秒, 浮点数
  207. 2 - km/h 千米/小时, 浮点数
  208. 3 - kn/h 英里/小时, 浮点数
  209. ]]
  210. -- 默认 米/小时
  211. log.info("nmea", "loc", libgnss.getIntLocation())
  212. -- 米/秒
  213. log.info("nmea", "loc", libgnss.getIntLocation(1))
  214. -- 千米/小时
  215. log.info("nmea", "loc", libgnss.getIntLocation(2))
  216. -- 英里/小时
  217. log.info("nmea", "loc", libgnss.getIntLocation(3))
  218. */
  219. static int l_libgnss_get_int_location(lua_State *L) {
  220. if (libgnss_gnss != NULL && libgnss_gnss->frame_rmc.valid) {
  221. lua_pushinteger(L, libgnss_gnss->frame_rmc.latitude.value);
  222. lua_pushinteger(L, libgnss_gnss->frame_rmc.longitude.value);
  223. int speed_type = luaL_optinteger(L, 1, 0);
  224. switch (speed_type)
  225. {
  226. case 1: // 米/秒
  227. lua_pushnumber(L, (minmea_tofloat(&(libgnss_gnss->frame_rmc.speed)) * 1852 / 3600));
  228. break;
  229. case 2: // 千米/小时
  230. lua_pushnumber(L, (minmea_tofloat(&(libgnss_gnss->frame_rmc.speed)) * 1.852));
  231. break;
  232. case 3: // 英里/小时
  233. lua_pushnumber(L, minmea_tofloat(&(libgnss_gnss->frame_rmc.speed)));
  234. break;
  235. default: // 米/小时
  236. lua_pushinteger(L, (int32_t)(minmea_tofloat(&(libgnss_gnss->frame_rmc.speed)) * 1852));
  237. break;
  238. }
  239. } else {
  240. lua_pushinteger(L, 0);
  241. lua_pushinteger(L, 0);
  242. lua_pushinteger(L, 0);
  243. }
  244. return 3;
  245. }
  246. /**
  247. 获取原始RMC位置信息
  248. @api libgnss.getRmc(data_mode)
  249. @int 坐标类数据的格式, 0-DDMM.MMM格式, 1-DDDDDDD格式, 2-DD.DDDDD格式
  250. @return table 原始rmc数据
  251. @usage
  252. -- 解析nmea
  253. log.info("nmea", "rmc", json.encode(libgnss.getRmc(2)))
  254. -- 实例输出
  255. --[[
  256. {
  257. "course":0,
  258. "valid":true, // true定位成功,false定位丢失
  259. "lat":23.4067, // 纬度, 正数为北纬, 负数为南纬
  260. "lng":113.231, // 经度, 正数为东经, 负数为西经
  261. "variation":0, // 地面航向,单位为度,从北向起顺时针计算
  262. "speed":0 // 地面速度, 单位为"节"
  263. "year":2023, // 年份
  264. "month":1, // 月份, 1-12
  265. "day":5, // 月份天, 1-31
  266. "hour":7, // 小时,0-23
  267. "min":23, // 分钟,0-59
  268. "sec":20, // 秒,0-59
  269. }
  270. ]]
  271. */
  272. static int l_libgnss_get_rmc(lua_State *L) {
  273. int mode = luaL_optinteger(L, 1, 0);
  274. lua_settop(L, 0);
  275. lua_createtable(L, 0, 12);
  276. struct tm rtime = {0};
  277. if (libgnss_gnss != NULL) {
  278. lua_pushboolean(L, libgnss_gnss->frame_rmc.valid);
  279. lua_setfield(L, -2, "valid");
  280. if (libgnss_gnss->frame_rmc.valid) {
  281. push_gnss_value(L, &(libgnss_gnss->frame_rmc.latitude), mode);
  282. }
  283. else
  284. lua_pushinteger(L, 0);
  285. lua_setfield(L, -2, "lat");
  286. if (libgnss_gnss->frame_rmc.valid) {
  287. push_gnss_value(L, &(libgnss_gnss->frame_rmc.longitude), mode);
  288. }
  289. else
  290. lua_pushinteger(L, 0);
  291. lua_setfield(L, -2, "lng");
  292. if (libgnss_gnss->frame_rmc.valid) {
  293. push_gnss_value(L, &(libgnss_gnss->frame_rmc.speed), 0);
  294. }
  295. else
  296. lua_pushinteger(L, 0);
  297. lua_setfield(L, -2, "speed");
  298. if (libgnss_gnss->frame_rmc.valid) {
  299. push_gnss_value(L, &(libgnss_gnss->frame_rmc.course), 0);
  300. }
  301. else
  302. lua_pushinteger(L, 0);
  303. lua_setfield(L, -2, "course");
  304. if (libgnss_gnss->frame_rmc.valid) {
  305. push_gnss_value(L, &(libgnss_gnss->frame_rmc.variation), 0);
  306. }
  307. else
  308. lua_pushinteger(L, 0);
  309. lua_setfield(L, -2, "variation");
  310. // 时间类
  311. minmea_getdatetime(&rtime, &libgnss_gnss->frame_rmc.date, &libgnss_gnss->frame_rmc.time);
  312. put_datetime(L, &rtime);
  313. }
  314. return 1;
  315. }
  316. static void add_gsv(lua_State*L, struct minmea_sentence_gsv* gsvs, size_t *count, int tp) {
  317. for (size_t i = 0; i < FRAME_GSV_MAX; i++)
  318. {
  319. for (size_t j = 0; j < 4; j++)
  320. {
  321. //LLOGD("nr %d snr %d", gnss->frame_gsv[i].sats[j].nr, gnss->frame_gsv[i].sats[j].snr);
  322. if (gsvs[i].sats[j].nr) {
  323. lua_pushinteger(L, *count);
  324. lua_createtable(L, 0, 4);
  325. lua_pushliteral(L, "nr");
  326. lua_pushinteger(L, gsvs[i].sats[j].nr);
  327. lua_settable(L, -3);
  328. lua_pushliteral(L, "snr");
  329. lua_pushinteger(L, gsvs[i].sats[j].snr);
  330. lua_settable(L, -3);
  331. lua_pushliteral(L, "elevation");
  332. lua_pushinteger(L, gsvs[i].sats[j].elevation);
  333. lua_settable(L, -3);
  334. lua_pushliteral(L, "azimuth");
  335. lua_pushinteger(L, gsvs[i].sats[j].azimuth);
  336. lua_settable(L, -3);
  337. lua_pushliteral(L, "tp");
  338. lua_pushinteger(L, tp);
  339. lua_settable(L, -3);
  340. lua_settable(L, -3);
  341. *count = *count + 1;
  342. }
  343. }
  344. }
  345. }
  346. /**
  347. 获取原始GSV信息
  348. @api libgnss.getGsv()
  349. @return table 原始GSV数据
  350. @usage
  351. -- 解析nmea
  352. log.info("nmea", "gsv", json.encode(libgnss.getGsv()))
  353. --[[实例输出
  354. {
  355. "total_sats":24, // 总可见卫星数量
  356. "sats":[
  357. {
  358. "snr":27, // 信噪比
  359. "azimuth":278, // 方向角
  360. "elevation":59, // 仰角
  361. "tp":0, // 0 - GPS/SASS/QSZZ, 1 - BD
  362. "nr":4 // 卫星编号
  363. },
  364. // 这里忽略了22个卫星的信息
  365. {
  366. "snr":0,
  367. "azimuth":107,
  368. "elevation":19,
  369. "tp":1,
  370. "nr":31
  371. }
  372. ]
  373. }
  374. ]]
  375. */
  376. static int l_libgnss_get_gsv(lua_State *L) {
  377. lua_createtable(L, 0, 2);
  378. if (libgnss_gnss == NULL)
  379. return 1;
  380. size_t count = 1;
  381. lua_createtable(L, 12, 0);
  382. if (libgnss_gnss->frame_gsv_gp->total_sats > 0) {
  383. add_gsv(L, libgnss_gnss->frame_gsv_gp, &count, 0);
  384. }
  385. if (libgnss_gnss->frame_gsv_gb->total_sats > 0) {
  386. add_gsv(L, libgnss_gnss->frame_gsv_gb, &count, 1);
  387. }
  388. // if (libgnss_gnss->frame_gsv_gl->total_sats > 0) {
  389. // add_gsv(L, libgnss_gnss->frame_gsv_gl, &count);
  390. // }
  391. // if (libgnss_gnss->frame_gsv_ga->total_sats > 0) {
  392. // add_gsv(L, libgnss_gnss->frame_gsv_ga, &count);
  393. // }
  394. lua_setfield(L, -2, "sats");
  395. lua_pushliteral(L, "total_sats");
  396. lua_pushinteger(L, count - 1);
  397. lua_settable(L, -3);
  398. return 1;
  399. }
  400. /**
  401. 获取原始GSA信息
  402. @api libgnss.getGsa(data_mode)
  403. @int 坐标类数据的格式, 0-DDMM.MMM格式, 1-DDDDDDD格式, 2-DD.DDDDD格式
  404. @return table 原始GSA数据
  405. @usage
  406. -- 获取
  407. log.info("nmea", "gsa", json.encode(libgnss.getGsa(), "11g"))
  408. -- 示例数据
  409. --[[
  410. {
  411. "sats":[ // 正在使用的卫星编号
  412. 9,
  413. 6,
  414. 16,
  415. 16,
  416. 26,
  417. 21,
  418. 27,
  419. 27,
  420. 4,
  421. 36,
  422. 3,
  423. 7,
  424. 8,
  425. 194
  426. ],
  427. "vdop":0.03083333, // 垂直精度因子,0.00 - 99.99,不定位时值为 99.99
  428. "pdop":0.0455, // 水平精度因子,0.00 - 99.99,不定位时值为 99.99
  429. "fix_type":3, // 定位模式, 1-未定位, 2-2D定位, 3-3D定位
  430. "hdop":0.0335 // 位置精度因子,0.00 - 99.99,不定位时值为 99.99
  431. }
  432. ]]
  433. */
  434. static int l_libgnss_get_gsa(lua_State *L) {
  435. // int mode = luaL_optinteger(L, 1, 0);
  436. lua_settop(L, 0);
  437. if (libgnss_gnss == NULL)
  438. return 0;
  439. lua_createtable(L, 0, 10);
  440. //lua_pushliteral(L, "mode");
  441. //lua_pushlstring(L, gnss ? &(gnss->frame_gsa.mode) : "N", 1);
  442. //lua_settable(L, -3);
  443. lua_pushliteral(L, "fix_type");
  444. lua_pushinteger(L, libgnss_gnss->frame_gsa[0].fix_type);
  445. lua_settable(L, -3);
  446. lua_pushliteral(L, "pdop");
  447. push_gnss_value(L, &(libgnss_gnss->frame_gsa[0].pdop), 0);
  448. lua_settable(L, -3);
  449. lua_pushliteral(L, "hdop");
  450. push_gnss_value(L, &(libgnss_gnss->frame_gsa[0].hdop), 0);
  451. lua_settable(L, -3);
  452. lua_pushliteral(L, "vdop");
  453. push_gnss_value(L, &(libgnss_gnss->frame_gsa[0].vdop), 0);
  454. lua_settable(L, -3);
  455. lua_pushliteral(L, "sats");
  456. lua_createtable(L, 12, 0);
  457. size_t pos = 1;
  458. for (size_t i = 0; i < 12; i++) {
  459. for (size_t j = 0; j < 3; j++)
  460. {
  461. if (libgnss_gnss->frame_gsa[j].sats[i] == 0)
  462. continue;
  463. lua_pushinteger(L, libgnss_gnss->frame_gsa[j].sats[i]);
  464. lua_seti(L, -2, pos);
  465. pos ++;
  466. }
  467. }
  468. lua_settable(L, -3);
  469. return 1;
  470. }
  471. /**
  472. 获取VTA速度信息
  473. @api libgnss.getVtg(data_mode)
  474. @int 可选, 3-原始字符串, 不传或者传其他值, 则返回浮点值
  475. @return table 原始VTA数据
  476. @usage
  477. -- 解析nmea
  478. log.info("nmea", "vtg", json.encode(libgnss.getVtg()))
  479. -- 示例
  480. --[[
  481. {
  482. "speed_knots":0, // 速度, 英里/小时
  483. "true_track_degrees":0, // 真北方向角
  484. "magnetic_track_degrees":0, // 磁北方向角
  485. "speed_kph":0 // 速度, 千米/小时
  486. }
  487. ]]
  488. */
  489. static int l_libgnss_get_vtg(lua_State *L) {
  490. int mode = luaL_optinteger(L, 1, 0);
  491. lua_settop(L, 0);
  492. if (libgnss_gnss == NULL)
  493. return 0;
  494. if (mode == 3) {
  495. lua_pushstring(L, libgnss_gnss->vtg);
  496. return 1;
  497. }
  498. lua_createtable(L, 0, 10);
  499. struct minmea_sentence_vtg frame_vtg = {0};
  500. minmea_parse_vtg(&frame_vtg, libgnss_gnss->vtg);
  501. // lua_pushliteral(L, "faa_mode");
  502. // lua_pushlstring(L, libgnss_gnss->frame_vtg.faa_mode, 1);
  503. // lua_settable(L, -3);
  504. lua_pushliteral(L, "true_track_degrees");
  505. push_gnss_value(L, &(frame_vtg.true_track_degrees), 0);
  506. lua_settable(L, -3);
  507. lua_pushliteral(L, "magnetic_track_degrees");
  508. push_gnss_value(L, &(frame_vtg.magnetic_track_degrees), 0);
  509. lua_settable(L, -3);
  510. lua_pushliteral(L, "speed_knots");
  511. push_gnss_value(L, &(frame_vtg.speed_knots), 0);
  512. lua_settable(L, -3);
  513. lua_pushliteral(L, "speed_kph");
  514. push_gnss_value(L, &(frame_vtg.speed_kph), 0);
  515. lua_settable(L, -3);
  516. return 1;
  517. }
  518. /**
  519. 获取原始ZDA时间和日期信息
  520. @api libgnss.getZda()
  521. @return table 原始zda数据
  522. @usage
  523. log.info("nmea", "zda", json.encode(libgnss.getZda()))
  524. -- 实例输出
  525. --[[
  526. {
  527. "minute_offset":0, // 本地时区的分钟, 一般固定输出0
  528. "hour_offset":0, // 本地时区的小时, 一般固定输出0
  529. "year":2023 // UTC 年,四位数字
  530. "month":1, // UTC 月,两位,01 ~ 12
  531. "day":5, // UTC 日,两位数字,01 ~ 31
  532. "hour":7, // 小时
  533. "min":50, // 分
  534. "sec":14, // 秒
  535. }
  536. ]]
  537. */
  538. static int l_libgnss_get_zda(lua_State *L) {
  539. lua_createtable(L, 0, 9);
  540. struct tm rtime = {0};
  541. if (libgnss_gnss != NULL) {
  542. struct minmea_sentence_zda frame_zda = {0};
  543. minmea_parse_zda(&frame_zda, libgnss_gnss->zda);
  544. lua_pushliteral(L, "hour_offset");
  545. lua_pushinteger(L, frame_zda.hour_offset);
  546. lua_settable(L, -3);
  547. lua_pushliteral(L, "minute_offset");
  548. lua_pushinteger(L, frame_zda.minute_offset);
  549. lua_settable(L, -3);
  550. // 时间相关
  551. minmea_getdatetime(&rtime, &frame_zda.date, &frame_zda.time);
  552. put_datetime(L, &rtime);
  553. }
  554. return 1;
  555. }
  556. /**
  557. 设置调试模式
  558. @api libgnss.debug(mode)
  559. @bool true开启调试,false关闭调试,默认为false
  560. @usage
  561. -- 开启调试, 会输出GNSS原始数据到日志中
  562. libgnss.debug(true)
  563. -- 关闭调试
  564. libgnss.debug(false)
  565. */
  566. static int l_libgnss_debug(lua_State *L) {
  567. if (libgnss_gnss == NULL && luat_libgnss_init(0)) {
  568. return 0;
  569. }
  570. if (lua_isboolean(L, 1) && lua_toboolean(L, 1)) {
  571. LLOGD("Debug ON");
  572. gnss_debug = 1;
  573. }
  574. else
  575. {
  576. LLOGD("Debug OFF");
  577. gnss_debug = 0;
  578. }
  579. return 0;
  580. }
  581. /*
  582. 获取GGA数据
  583. @api libgnss.getGga(data_mode)
  584. @int 坐标类数据的格式, 0-DDMM.MMM格式, 1-DDDDDDD格式, 2-DD.DDDDD格式, 3-原始字符串
  585. @return table GGA数据, 若如不存在会返回nil
  586. @usage
  587. local gga = libgnss.getGga(2)
  588. if gga then
  589. log.info("GGA", json.encode(gga, "11g"))
  590. end
  591. --实例输出
  592. --[[
  593. {
  594. "dgps_age":0, // 差分校正时延,单位为秒
  595. "fix_quality":1, // 定位状态标识 0 - 无效,1 - 单点定位,2 - 差分定位
  596. "satellites_tracked":14, // 参与定位的卫星数量
  597. "altitude":0.255, // 海平面分离度, 或者成为海拔, 单位是米,
  598. "hdop":0.0335, // 水平精度因子,0.00 - 99.99,不定位时值为 99.99
  599. "longitude":113.231, // 经度, 正数为东经, 负数为西经
  600. "latitude":23.4067, // 纬度, 正数为北纬, 负数为南纬
  601. "height":0 // 椭球高,固定输出 1 位小数
  602. }
  603. ]]
  604. */
  605. static int l_libgnss_get_gga(lua_State* L) {
  606. int mode = luaL_optinteger(L, 1, 0);
  607. lua_settop(L, 0);
  608. if (libgnss_gnss == NULL)
  609. return 0;
  610. if (mode == 3) {
  611. lua_pushstring(L, libgnss_gnss->gga);
  612. return 1;
  613. }
  614. lua_newtable(L);
  615. struct minmea_sentence_gga frame_gga = {0};
  616. minmea_parse_gga(&frame_gga, libgnss_gnss->gga);
  617. lua_pushstring(L, "altitude");
  618. push_gnss_value(L, &(frame_gga.altitude), 0);
  619. lua_settable(L, -3);
  620. lua_pushstring(L, "latitude");
  621. push_gnss_value(L, &(frame_gga.latitude), mode);
  622. lua_settable(L, -3);
  623. lua_pushstring(L, "longitude");
  624. push_gnss_value(L, &(frame_gga.longitude), mode);
  625. lua_settable(L, -3);
  626. lua_pushstring(L, "fix_quality");
  627. lua_pushinteger(L, frame_gga.fix_quality);
  628. lua_settable(L, -3);
  629. lua_pushstring(L, "satellites_tracked");
  630. lua_pushinteger(L, frame_gga.satellites_tracked);
  631. lua_settable(L, -3);
  632. lua_pushstring(L, "hdop");
  633. push_gnss_value(L, &(frame_gga.hdop), 0);
  634. lua_settable(L, -3);
  635. lua_pushstring(L, "height");
  636. push_gnss_value(L, &(frame_gga.height), 0);
  637. lua_settable(L, -3);
  638. lua_pushstring(L, "dgps_age");
  639. push_gnss_value(L, &(frame_gga.dgps_age), 0);
  640. lua_settable(L, -3);
  641. return 1;
  642. }
  643. /*
  644. 获取GLL数据
  645. @api libgnss.getGll(data_mode)
  646. @int 坐标类数据的格式, 0-DDMM.MMM格式, 1-DDDDDDD格式, 2-DD.DDDDD格式
  647. @return table GLL数据, 若如不存在会返回nil
  648. @usage
  649. local gll = libgnss.getGll(2)
  650. if gll then
  651. log.info("GLL", json.encode(gll, "11g"))
  652. end
  653. -- 实例数据
  654. --[[
  655. {
  656. "status":"A", // 定位状态, A有效, B无效
  657. "mode":"A", // 定位模式, V无效, A单点解, D差分解
  658. "sec":20, // 秒, UTC时间为准
  659. "min":23, // 分钟, UTC时间为准
  660. "hour":7, // 小时, UTC时间为准
  661. "longitude":113.231, // 经度, 正数为东经, 负数为西经
  662. "latitude":23.4067, // 纬度, 正数为北纬, 负数为南纬
  663. "us":0 // 微妙数, 通常为0
  664. }
  665. ]]
  666. */
  667. static int l_libgnss_get_gll(lua_State* L) {
  668. int mode = luaL_optinteger(L, 1, 0);
  669. lua_settop(L, 0);
  670. if (libgnss_gnss == NULL)
  671. return 0;
  672. if (mode == 3) {
  673. lua_pushstring(L, libgnss_gnss->vtg);
  674. return 1;
  675. }
  676. lua_newtable(L);
  677. struct minmea_sentence_gll frame_gll = {0};
  678. minmea_parse_gll(&frame_gll, libgnss_gnss->gll);
  679. lua_pushstring(L, "latitude");
  680. push_gnss_value(L, &(frame_gll.latitude), mode);
  681. lua_settable(L, -3);
  682. lua_pushstring(L, "longitude");
  683. push_gnss_value(L, &(frame_gll.longitude), mode);
  684. lua_settable(L, -3);
  685. lua_pushstring(L, "mode");
  686. lua_pushfstring(L, "%c", frame_gll.mode);
  687. lua_settable(L, -3);
  688. lua_pushstring(L, "status");
  689. lua_pushfstring(L, "%c", frame_gll.status);
  690. lua_settable(L, -3);
  691. lua_pushstring(L, "hour");
  692. lua_pushinteger(L, frame_gll.time.hours);
  693. lua_settable(L, -3);
  694. lua_pushstring(L, "us");
  695. lua_pushinteger(L, frame_gll.time.microseconds);
  696. lua_settable(L, -3);
  697. lua_pushstring(L, "min");
  698. lua_pushinteger(L, frame_gll.time.minutes);
  699. lua_settable(L, -3);
  700. lua_pushstring(L, "sec");
  701. lua_pushinteger(L, frame_gll.time.seconds);
  702. lua_settable(L, -3);
  703. return 1;
  704. }
  705. /**
  706. 清除历史定位数据
  707. @api libgnss.clear()
  708. @return nil 无返回值
  709. @usage
  710. -- 该操作会清除所有定位数据
  711. */
  712. static int l_libgnss_clear(lua_State*L) {
  713. (void)L;
  714. if (libgnss_gnss == NULL && luat_libgnss_init(1))
  715. return 0;
  716. memset(libgnss_gnss, 0, sizeof(luat_libgnss_t));
  717. return 0;
  718. }
  719. /*
  720. 绑定uart端口进行GNSS数据读取
  721. @api libgnss.bind(id, next_id)
  722. @int uart端口号
  723. @int 转发到uart的id, 例如虚拟uart.VUART_0
  724. @usage
  725. -- 配置串口信息, 通常为 115200 8N1
  726. uart.setup(2, 115200)
  727. -- 绑定uart, 马上开始解析GNSS数据
  728. libgnss.bind(2)
  729. -- 无需再调用uart.on然后调用libgnss.parse
  730. -- 开发期可打开调试日志
  731. libgnss.debug(true)
  732. -- 2023-01-02之后编译的固件有效
  733. -- 从uart2读取并解析, 同时转发到虚拟串口0
  734. libgnss.bind(2, uart.VUART_0)
  735. */
  736. static int l_libgnss_bind(lua_State* L) {
  737. int uart_id = luaL_checkinteger(L, 1);
  738. l_libgnss_clear(L);
  739. if (libgnss_recvbuff == NULL) {
  740. libgnss_recvbuff = luat_heap_malloc(RECV_BUFF_SIZE);
  741. }
  742. if (luat_uart_exist(uart_id)) {
  743. //uart_app_recvs[uart_id] = nmea_uart_recv_cb;
  744. luat_uart_set_app_recv(uart_id, l_libgnss_uart_recv_cb);
  745. }
  746. if (lua_isinteger(L, 2)) {
  747. libgnss_route_uart_id = luaL_checkinteger(L, 2);
  748. }
  749. return 0;
  750. }
  751. /**
  752. 获取位置字符串
  753. @api libgnss.locStr(mode)
  754. @int 字符串模式. 0- Air780EG所需的格式
  755. @return 指定模式的字符串
  756. @usage
  757. -- 仅推荐在定位成功后调用
  758. */
  759. static int l_libgnss_locStr(lua_State *L) {
  760. int mode = luaL_optinteger(L, 1, 0);
  761. char buff[64] = {0};
  762. float lat_f = minmea_tofloat(&libgnss_gnss->frame_rmc.latitude);
  763. float lng_f = minmea_tofloat(&libgnss_gnss->frame_rmc.longitude);
  764. switch (mode)
  765. {
  766. case 0:
  767. snprintf_(buff, 63, "%.7g,%c,%.7g,%c,1.0",
  768. fabs(lat_f), lat_f > 0 ? 'N' : 'S',
  769. fabs(lng_f), lng_f > 0 ? 'E' : 'W');
  770. break;
  771. case 1:
  772. snprintf_(buff, 63, "%d,%d", libgnss_gnss->frame_rmc.latitude.value, libgnss_gnss->frame_rmc.longitude.value);
  773. break;
  774. default:
  775. break;
  776. }
  777. lua_pushstring(L, buff);
  778. return 1;
  779. }
  780. /**
  781. 定位成功后自动设置RTC
  782. @api libgnss.rtcAuto(enable)
  783. @bool 开启与否, 默认是false关闭
  784. @usage
  785. -- 开启自动设置RTC
  786. libgnss.rtcAuto(true)
  787. */
  788. static int l_libgnss_rtc_auto(lua_State *L) {
  789. if (libgnss_gnss == NULL)
  790. return 0;
  791. if (lua_isboolean(L, 1) && lua_toboolean(L, 1)) {
  792. libgnss_gnss->rtc_auto = 1;
  793. LLOGD("GNSS->RTC Auto-Set now is ON");
  794. }
  795. else {
  796. libgnss_gnss->rtc_auto = 0;
  797. LLOGD("GNSS->RTC Auto-Set now is OFF");
  798. }
  799. return 0;
  800. }
  801. //临时处理, 当前GNSS处理均在lua线程
  802. // static lua_State *gnss_L;
  803. static int gnss_raw_cb = 0;
  804. int luat_libgnss_rawdata_cb(lua_State *L, void* ptr) {
  805. rtos_msg_t* msg = (rtos_msg_t*)lua_topointer(L, -1);
  806. // lua_getglobal(L, "sys_pub");
  807. lua_geti(L, LUA_REGISTRYINDEX, gnss_raw_cb);
  808. if (lua_isfunction(L, -1)) {
  809. // lua_pushliteral(gnss_L, "GNSS_RAW_DATA");
  810. lua_pushlstring(L, ptr, msg->arg1);
  811. luat_heap_free(ptr);
  812. ptr = NULL;
  813. lua_call(L, 1, 0);
  814. }
  815. else {
  816. luat_heap_free(ptr);
  817. }
  818. return 0;
  819. }
  820. int luat_libgnss_on_rawdata(const char* data, size_t len) {
  821. if (gnss_raw_cb == 0)
  822. return 0;
  823. char* ptr = luat_heap_malloc(len);
  824. if (ptr == NULL)
  825. return 0;
  826. memcpy(ptr, data, len);
  827. rtos_msg_t msg = {
  828. .handler = luat_libgnss_rawdata_cb,
  829. .arg1 = len,
  830. .ptr = ptr
  831. };
  832. luat_msgbus_put(&msg, 0);
  833. return 0;
  834. }
  835. /**
  836. 底层事件回调
  837. @api libgnss.on(tp, fn)
  838. @string 事件类型,当前支持"raw"
  839. @usage
  840. -- 本函数一般用于调试, 用于获取底层实际收到的数据
  841. libgnss.on("raw", function(data)
  842. log.info("GNSS", data)
  843. end)
  844. */
  845. static int l_libgnss_on(lua_State *L) {
  846. size_t len = 0;
  847. const char* tp = luaL_checklstring(L, 1, &len);
  848. if (!strcmp("raw", tp)) {
  849. if (gnss_raw_cb != 0) {
  850. luaL_unref(L, LUA_REGISTRYINDEX, gnss_raw_cb);
  851. gnss_raw_cb = 0;
  852. }
  853. if (lua_isfunction(L, 2)) {
  854. lua_pushvalue(L, 2);
  855. gnss_raw_cb = luaL_ref(L, LUA_REGISTRYINDEX);
  856. }
  857. }
  858. return 0;
  859. }
  860. /**
  861. 获取非标的GPTXT数据
  862. @api libgnss.getTxt()
  863. @return GPTXT所携带的字符串
  864. @usage
  865. -- 本函数于2023.6.6 添加
  866. log.info("gnss", "txt", libgnss.getTxt())
  867. -- 测试语句
  868. libgnss.parse("$GPTXT,01,01,01,ANTENNA SHORT*63\r\n")
  869. log.info("GNSS", libgnss.getTxt())
  870. libgnss.parse("$GPTXT,01,01,01,ANTENNA OPEN*25\r\n")
  871. log.info("GNSS", libgnss.getTxt())
  872. libgnss.parse("$GPTXT,01,01,01,ANTENNA OK*35\r\n")
  873. log.info("GNSS", libgnss.getTxt())
  874. */
  875. static int l_libgnss_get_txt(lua_State *L) {
  876. if (libgnss_gnss == NULL) {
  877. lua_pushliteral(L, "");
  878. return 1;
  879. }
  880. libgnss_gnss->txt.txt[FRAME_TXT_MAX_LEN] = 0x00;
  881. lua_pushstring(L, libgnss_gnss->txt.txt);
  882. return 1;
  883. }
  884. /*
  885. 合成Air530Z所需要的辅助定位数据
  886. @api libgnss.casic_aid(dt, loc)
  887. @table 时间信息
  888. @table 经纬度及海拔
  889. @return string 辅助定位数据
  890. @usage
  891. -- 本函数适合CASIC系列GNSS模块的辅助定位信息的合成
  892. -- 本函数 2023.11.14 新增
  893. -- 首先是时间信息,注意是UTC时间
  894. -- 时间来源很多, 一般建议socket.sntp()时间同步后的系统时间
  895. local dt = os.date("!*t")
  896. -- 然后是辅助定位坐标
  897. -- 来源有很多方式:
  898. -- 1. 从历史定位数据得到, 例如之前定位成功后保存到本地文件系统了
  899. -- 2. 通过基站定位或者wifi定位获取到
  900. -- 3. 通过IP定位获取到大概坐标
  901. -- 坐标系是WGS84, 但鉴于是辅助定位,精度不是关键因素
  902. local lla = {
  903. lat = 23.12,
  904. lng = 114.12
  905. }
  906. local aid = libgnss.casic_aid(dt, lla)
  907. */
  908. #include "luat_casic_gnss.h"
  909. double strtod(const char *s,char **ptr);
  910. static int l_libgnss_casic_aid(lua_State* L) {
  911. DATETIME_STR dt = {0};
  912. POS_LLA_STR lla = {0};
  913. const char* data = "";
  914. if (lua_istable(L, 1)) {
  915. if (LUA_TNUMBER == lua_getfield(L, 1, "day")) {
  916. dt.day = lua_tointeger(L, -1);
  917. };
  918. lua_pop(L, 1);
  919. // 这里兼容month和mon两种, os.date 和 rtc.get
  920. if (LUA_TNUMBER == lua_getfield(L, 1, "month")) {
  921. dt.month = lua_tointeger(L, -1);
  922. };
  923. lua_pop(L, 1);
  924. if (LUA_TNUMBER == lua_getfield(L, 1, "mon")) {
  925. dt.month = lua_tointeger(L, -1);
  926. };
  927. lua_pop(L, 1);
  928. if (LUA_TNUMBER == lua_getfield(L, 1, "year")) {
  929. dt.year = lua_tointeger(L, -1);
  930. if (dt.year > 2022)
  931. dt.valid = 1;
  932. };
  933. lua_pop(L, 1);
  934. if (LUA_TNUMBER == lua_getfield(L, 1, "hour")) {
  935. dt.hour = lua_tointeger(L, -1);
  936. };
  937. lua_pop(L, 1);
  938. if (LUA_TNUMBER == lua_getfield(L, 1, "min")) {
  939. dt.minute = lua_tointeger(L, -1);
  940. };
  941. lua_pop(L, 1);
  942. if (LUA_TNUMBER == lua_getfield(L, 1, "sec")) {
  943. dt.second = lua_tointeger(L, -1);
  944. };
  945. lua_pop(L, 1);
  946. }
  947. if (lua_istable(L, 2)) {
  948. lua_getfield(L, 2, "lat");
  949. if (LUA_TNUMBER == lua_type(L, -1)) {
  950. lla.lat = lua_tonumber(L, -1);
  951. }
  952. else if (LUA_TSTRING == lua_type(L, -1)) {
  953. data = luaL_checkstring(L, -1);
  954. lla.lat = strtod(data, NULL);
  955. }
  956. lua_pop(L, 1);
  957. lua_getfield(L, 2, "lng");
  958. if (LUA_TNUMBER == lua_type(L, -1)) {
  959. lla.lon = lua_tonumber(L, -1);
  960. }
  961. else if (LUA_TSTRING == lua_type(L, -1)) {
  962. data = luaL_checkstring(L, -1);
  963. lla.lon = strtod(data, NULL);
  964. }
  965. lua_pop(L, 1);
  966. if (LUA_TNUMBER == lua_getfield(L, 2, "alt")) {
  967. lla.alt = lua_tonumber(L, -1);
  968. };
  969. if (lla.lat > 0.001 || lla.lat < -0.01)
  970. if (lla.lon > 0.001 || lla.lon < -0.01)
  971. lla.valid = 1;
  972. }
  973. char tmp[66] = {0};
  974. casicAgnssAidIni(&dt, &lla, tmp);
  975. lua_pushlstring(L, tmp, 66);
  976. return 1;
  977. };
  978. #include "rotable2.h"
  979. static const rotable_Reg_t reg_libgnss[] =
  980. {
  981. { "parse", ROREG_FUNC(l_libgnss_parse)},
  982. { "isFix", ROREG_FUNC(l_libgnss_is_fix)},
  983. { "getIntLocation", ROREG_FUNC(l_libgnss_get_int_location)},
  984. { "getRmc", ROREG_FUNC(l_libgnss_get_rmc)},
  985. { "getGsv", ROREG_FUNC(l_libgnss_get_gsv)},
  986. { "getGsa", ROREG_FUNC(l_libgnss_get_gsa)},
  987. { "getVtg", ROREG_FUNC(l_libgnss_get_vtg)},
  988. { "getGga", ROREG_FUNC(l_libgnss_get_gga)},
  989. { "getGll", ROREG_FUNC(l_libgnss_get_gll)},
  990. { "getZda", ROREG_FUNC(l_libgnss_get_zda)},
  991. { "locStr", ROREG_FUNC(l_libgnss_locStr)},
  992. { "rtcAuto",ROREG_FUNC(l_libgnss_rtc_auto)},
  993. { "on", ROREG_FUNC(l_libgnss_on)},
  994. { "debug", ROREG_FUNC(l_libgnss_debug)},
  995. { "clear", ROREG_FUNC(l_libgnss_clear)},
  996. { "bind", ROREG_FUNC(l_libgnss_bind)},
  997. { "getTxt", ROREG_FUNC(l_libgnss_get_txt)},
  998. { "casic_aid", ROREG_FUNC(l_libgnss_casic_aid)},
  999. { NULL, ROREG_INT(0)}
  1000. };
  1001. LUAMOD_API int luaopen_libgnss( lua_State *L ) {
  1002. luat_newlib2(L, reg_libgnss);
  1003. return 1;
  1004. }