luat_lib_libgnss.c 30 KB

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