10 -- 提醒: 本库输出的坐标,均为 WGS84 坐标系
11 -- 如需要在国内地图使用, 要转换成对应地图的坐标系, 例如 GCJ02 BD09
12 -- 相关链接: https://lbsyun.baidu.com/index.php?title=coordinate
13 -- 相关链接: https://www.openluat.com/GPS-Offset.html
15 -- 提醒: GPS功能, GNSS功能, NMEA解析功能,均为当前库的子功能
16 -- 本库的主要功能就是解析NMEA协议, 支持内置GNSS也支持外置GNSS
21 uart.on(2, "recv", function(id, len)
23 local data = uart.read(id, 1024)
24 if data and #data > 1 then
31 -- 方案2, 适合2022.12.26之后编译固件,效率更高一些
36 -- libgnss.debug(true)
38 sys.subscribe("GNSS_STATE", function(event, ticks)
42 -- ticks是事件发生的时间,一般可以忽略
43 log.info("gnss", "state", event, ticks)
46 #include "luat_base.h"
47 #include "luat_msgbus.h"
49 #include "luat_uart.h"
52 #include "luat_zbuff.h"
54 #define LUAT_LOG_TAG "gnss"
59 extern luat_libgnss_t gnssctx
;
60 // extern luat_libgnss_t *libgnss_gnsstmp;
61 extern char* libgnss_recvbuff
;
62 extern int libgnss_route_uart_id
;
63 extern int gnss_debug
;
65 static int gnss_raw_cb
= 0;
66 static int gnss_txt_cb
= 0;
67 // static int gnss_rmc_cb = 0;
68 static int gnss_other_cb
= 0;
70 void luat_uart_set_app_recv(int id
, luat_uart_recv_callback_t cb
);
72 static inline void push_gnss_value(lua_State
*L
, struct minmea_float
*f
, int mode
) {
74 lua_pushinteger(L
, 0);
80 lua_pushnumber(L
, minmea_tofloat(f
));
83 lua_pushinteger(L
, minmea_tocoord2(f
));
86 lua_pushnumber(L
, minmea_tocoord(f
));
89 lua_pushnumber(L
, minmea_tocoord(f
));
94 static int luat_libgnss_state_handler(lua_State
*L
, void* ptr
) {
96 rtos_msg_t
* msg
= (rtos_msg_t
*)lua_topointer(L
, -1);
97 lua_getglobal(L
, "sys_pub");
98 if (!lua_isfunction(L
, -1)) {
106 sys.subscribe("GNSS_STATE", function(event, ticks)
110 -- ticks是事件发生的时间,一般可以忽略
111 log.info("gnss", "state", event, ticks)
114 lua_pushliteral(L
, "GNSS_STATE");
117 case GNSS_STATE_FIXED
:
118 lua_pushliteral(L
, "FIXED");
120 case GNSS_STATE_LOSE
:
121 lua_pushliteral(L
, "LOSE");
123 case GNSS_STATE_OPEN
:
124 lua_pushliteral(L
, "OPEN");
126 case GNSS_STATE_CLOSE
:
127 lua_pushliteral(L
, "CLOSE");
132 lua_pushinteger(L
, msg
->arg2
);
137 int luat_libgnss_state_onchanged(int state
) {
138 rtos_msg_t msg
= {0};
139 msg
.handler
= luat_libgnss_state_handler
;
142 msg
.arg2
= luat_mcu_ticks();
144 luat_msgbus_put(&msg
, 0);
148 static void put_datetime(lua_State
*L
, struct tm
* rtime
) {
149 lua_pushliteral(L
, "year");
150 lua_pushinteger(L
, rtime
->tm_year
);
153 lua_pushliteral(L
, "month");
154 lua_pushinteger(L
, rtime
->tm_mon
+ 1); // 比较纠结, 要不要兼容老的呢?
157 lua_pushliteral(L
, "day");
158 lua_pushinteger(L
, rtime
->tm_mday
);
161 lua_pushliteral(L
, "hour");
162 lua_pushinteger(L
, rtime
->tm_hour
);
165 lua_pushliteral(L
, "min");
166 lua_pushinteger(L
, rtime
->tm_min
);
169 lua_pushliteral(L
, "sec");
170 lua_pushinteger(L
, rtime
->tm_sec
);
174 static int l_gnss_callback(lua_State
*L
, void* ptr
){
176 rtos_msg_t
* msg
= (rtos_msg_t
*)lua_topointer(L
, -1);
177 luat_libgnss_uart_recv_cb(msg
->arg1
, msg
->arg2
);
181 static void l_libgnss_uart_recv_cb(int uart_id
, uint32_t data_len
)
183 rtos_msg_t msg
= {0};
184 msg
.handler
= l_gnss_callback
;
187 luat_msgbus_put(&msg
, 0);
192 @api libgnss.parse(str)
196 libgnss.parse(indata)
197 log.info("nmea", json.encode(libgnss.getRmc(), "11g"))
199 static int l_libgnss_parse(lua_State
*L
) {
201 const char* str
= NULL
;
202 luat_zbuff_t
* zbuff
= NULL
;
203 if (lua_type(L
, 1) == LUA_TSTRING
) {
204 str
= luaL_checklstring(L
, 1, &len
);
206 else if (lua_isuserdata(L
, 1)) {
208 str
= (const char*)zbuff
->addr
;
216 luat_libgnss_parse_data(str
, len
);
224 @return boolean 定位成功与否
226 log.info("nmea", "isFix", libgnss.isFix())
228 static int l_libgnss_is_fix(lua_State
*L
) {
229 lua_pushboolean(L
, gnssctx
.frame_rmc
.valid
!= 0 ? 1 : 0);
235 @api libgnss.getIntLocation(speed_type)
237 @return int lat数据, 格式为 ddddddddd
238 @return int lng数据, 格式为 ddddddddd
239 @return int speed数据, 单位米. 于2023.9.26修正
241 -- 建议用libgnss.getRmc(1)
242 log.info("nmea", "loc", libgnss.getIntLocation())
244 -- 2023.12.11 新增speed_type参数
247 0 - m/h 米/小时, 默认值, 整型
253 log.info("nmea", "loc", libgnss.getIntLocation())
255 log.info("nmea", "loc", libgnss.getIntLocation(1))
257 log.info("nmea", "loc", libgnss.getIntLocation(2))
259 log.info("nmea", "loc", libgnss.getIntLocation(3))
261 static int l_libgnss_get_int_location(lua_State
*L
) {
262 if (gnssctx
.frame_rmc
.valid
) {
263 lua_pushinteger(L
, gnssctx
.frame_rmc
.latitude
.value
);
264 lua_pushinteger(L
, gnssctx
.frame_rmc
.longitude
.value
);
265 int speed_type
= luaL_optinteger(L
, 1, 0);
269 lua_pushnumber(L
, (minmea_tofloat(&(gnssctx
.frame_rmc
.speed
)) * 1852 / 3600));
272 lua_pushnumber(L
, (minmea_tofloat(&(gnssctx
.frame_rmc
.speed
)) * 1.852));
275 lua_pushnumber(L
, minmea_tofloat(&(gnssctx
.frame_rmc
.speed
)));
278 lua_pushinteger(L
, (int32_t)(minmea_tofloat(&(gnssctx
.frame_rmc
.speed
)) * 1852));
283 lua_pushinteger(L
, 0);
284 lua_pushinteger(L
, 0);
285 lua_pushinteger(L
, 0);
292 @api libgnss.getRmc(data_mode)
293 @int 坐标类数据的格式, 0-DDMM.MMM格式, 1-DDDDDDD格式, 2-DD.DDDDD格式, 3-原始RMC字符串
294 @return table 原始rmc数据
297 log.info("nmea", "rmc", json.encode(libgnss.getRmc(2)))
302 "valid":true, // true定位成功,false定位丢失
303 "lat":23.4067, // 纬度, 正数为北纬, 负数为南纬
304 "lng":113.231, // 经度, 正数为东经, 负数为西经
305 "variation":0, // 地面航向,单位为度,从北向起顺时针计算
306 "speed":0 // 地面速度, 单位为"节"
308 "month":1, // 月份, 1-12
309 "day":5, // 月份天, 1-31
316 static int l_libgnss_get_rmc(lua_State
*L
) {
317 int mode
= luaL_optinteger(L
, 1, 0);
319 lua_createtable(L
, 0, 12);
321 struct tm rtime
= {0};
324 if (gnssctx
.rmc
== NULL
)
326 lua_pushstring(L
, gnssctx
.rmc
->data
);
331 lua_pushboolean(L
, gnssctx
.frame_rmc
.valid
);
332 lua_setfield(L
, -2, "valid");
334 if (gnssctx
.frame_rmc
.valid
) {
335 push_gnss_value(L
, &(gnssctx
.frame_rmc
.latitude
), mode
);
338 lua_pushinteger(L
, 0);
339 lua_setfield(L
, -2, "lat");
341 if (gnssctx
.frame_rmc
.valid
) {
342 push_gnss_value(L
, &(gnssctx
.frame_rmc
.longitude
), mode
);
345 lua_pushinteger(L
, 0);
346 lua_setfield(L
, -2, "lng");
348 if (gnssctx
.frame_rmc
.valid
) {
349 push_gnss_value(L
, &(gnssctx
.frame_rmc
.speed
), 0);
352 lua_pushinteger(L
, 0);
353 lua_setfield(L
, -2, "speed");
355 if (gnssctx
.frame_rmc
.valid
) {
356 push_gnss_value(L
, &(gnssctx
.frame_rmc
.course
), 0);
359 lua_pushinteger(L
, 0);
360 lua_setfield(L
, -2, "course");
362 if (gnssctx
.frame_rmc
.valid
) {
363 push_gnss_value(L
, &(gnssctx
.frame_rmc
.variation
), 0);
366 lua_pushinteger(L
, 0);
367 lua_setfield(L
, -2, "variation");
370 minmea_getdatetime(&rtime
, &gnssctx
.frame_rmc
.date
, &gnssctx
.frame_rmc
.time
);
371 put_datetime(L
, &rtime
);
379 @api libgnss.getGsv()
380 @return table 原始GSV数据
383 log.info("nmea", "gsv", json.encode(libgnss.getGsv()))
386 "total_sats":24, // 总可见卫星数量
390 "azimuth":278, // 方向角
391 "elevation":59, // 仰角
392 "tp":0, // 0 - GPS, 1 - BD
407 static int l_libgnss_get_gsv(lua_State
*L
) {
408 lua_createtable(L
, 0, 2);
410 uint64_t tnow
= luat_mcu_tick64_ms();
411 struct minmea_sentence_gsv frame_gsv
= {0};
412 lua_createtable(L
, FRAME_GSV_MAX
, 0);
413 for (size_t i
= 0; i
< FRAME_GSV_MAX
; i
++)
415 if (!luat_libgnss_data_check(gnssctx
.gsv
[i
], 3500, tnow
) || !minmea_parse_gsv(&frame_gsv
, gnssctx
.gsv
[i
]->data
)) {
419 for (size_t j
= 0; j
< 4; j
++)
421 if (!frame_gsv
.sats
[j
].nr
) {
424 lua_pushinteger(L
, count
);
425 lua_createtable(L
, 0, 4);
427 lua_pushliteral(L
, "nr");
428 lua_pushinteger(L
, frame_gsv
.sats
[j
].nr
);
431 lua_pushliteral(L
, "snr");
432 lua_pushinteger(L
, frame_gsv
.sats
[j
].snr
);
435 lua_pushliteral(L
, "elevation");
436 lua_pushinteger(L
, frame_gsv
.sats
[j
].elevation
);
439 lua_pushliteral(L
, "azimuth");
440 lua_pushinteger(L
, frame_gsv
.sats
[j
].azimuth
);
444 // https://receiverhelp.trimble.com/alloy-gnss/en-us/NMEA-0183messages_GSA.html
445 lua_pushliteral(L
, "tp");
446 if (memcmp(gnssctx
.gsv
[i
], "$GP", 3) == 0) {
447 lua_pushinteger(L
, 0);
449 else if (memcmp(gnssctx
.gsv
[i
], "$GL", 3) == 0) {
450 lua_pushinteger(L
, 2);
452 else if (memcmp(gnssctx
.gsv
[i
], "$GA", 3) == 0) {
453 lua_pushinteger(L
, 3);
455 else if (memcmp(gnssctx
.gsv
[i
], "$BD", 3) == 0 || memcmp(gnssctx
.gsv
[i
], "$GB", 3) == 0) {
456 lua_pushinteger(L
, 1);
458 else if (memcmp(gnssctx
.gsv
[i
], "$QZ", 3) == 0) {
459 lua_pushinteger(L
, 4);
462 lua_pushinteger(L
, 0);
466 // 新增一个类型, 字符串的, 实在是各种变化无法应对
467 lua_pushliteral(L
, "tpstr");
468 lua_pushlstring(L
, gnssctx
.gsv
[i
]->data
+ 1, 2);
475 lua_setfield(L
, -2, "sats");
477 lua_pushliteral(L
, "total_sats");
478 lua_pushinteger(L
, count
- 1);
487 @api libgnss.getGsa(data_mode)
489 @return table 原始GSA数据
492 log.info("nmea", "gsa", json.encode(libgnss.getGsa(), "11g"))
493 -- 示例数据(模式0, 也就是默认模式)
496 "sats":[ // 正在使用的卫星编号
512 "vdop":0.03083333, // 垂直精度因子,0.00 - 99.99,不定位时值为 99.99
513 "pdop":0.0455, // 水平精度因子,0.00 - 99.99,不定位时值为 99.99
514 "fix_type":3, // 定位模式, 1-未定位, 2-2D定位, 3-3D定位
515 "hdop":0.0335 // 位置精度因子,0.00 - 99.99,不定位时值为 99.99
519 -- 示例数据(模式1), 2024.5.26新增
521 {"pdop":7.8299999,"sats":[13,15,18,23],"vdop":3.2400000,"hdop":7.1300001,"fix_type":3},
522 {"pdop":7.8299999,"sats":[20,35,8,13],"vdop":3.2400000,"hdop":7.1300001,"fix_type":3}
526 static int l_libgnss_get_gsa_mode0(lua_State
*L
) {
527 struct minmea_sentence_gsa frame_gsa
= {0};
528 uint64_t tnow
= luat_mcu_tick64_ms();
529 lua_createtable(L
, 0, 12);
531 for (size_t i
= 0; i
< FRAME_GSA_MAX
; i
++)
533 if (!luat_libgnss_data_check(gnssctx
.gsa
[i
], 1500, tnow
) || minmea_parse_gsa(&frame_gsa
, gnssctx
.gsa
[i
]->data
) != 1)
537 lua_pushliteral(L
, "fix_type");
538 lua_pushinteger(L
, frame_gsa
.fix_type
);
541 lua_pushliteral(L
, "pdop");
542 push_gnss_value(L
, &(frame_gsa
.pdop
), 0);
545 lua_pushliteral(L
, "hdop");
546 push_gnss_value(L
, &(frame_gsa
.hdop
), 0);
549 lua_pushliteral(L
, "vdop");
550 push_gnss_value(L
, &(frame_gsa
.vdop
), 0);
553 lua_pushliteral(L
, "sysid");
554 lua_pushinteger(L
, frame_gsa
.sysid
);
559 lua_pushliteral(L
, "sats");
560 lua_createtable(L
, FRAME_GSA_MAX
, 0);
562 for (size_t i
= 0; i
< FRAME_GSA_MAX
; i
++) {
563 if (gnssctx
.gsa
[i
] == NULL
|| minmea_parse_gsa(&frame_gsa
, gnssctx
.gsa
[i
]->data
) != 1)
567 if (tnow
- gnssctx
.gsa
[i
]->tm
> 1000) {
570 // LLOGD("GSA: %s", gnssctx.gsa[i]->data);
571 for (size_t j
= 0; j
< 12; j
++)
573 if (frame_gsa
.sats
[j
] == 0)
576 lua_pushinteger(L
, frame_gsa
.sats
[j
]);
577 lua_seti(L
, -2, pos
);
585 static int l_libgnss_get_gsa_mode1(lua_State
*L
) {
586 struct minmea_sentence_gsa frame_gsa
= {0};
587 uint64_t tnow
= luat_mcu_tick64_ms();
589 lua_createtable(L
, FRAME_GSA_MAX
, 0);
591 for (size_t i
= 0; i
< FRAME_GSA_MAX
; i
++) {
592 if (gnssctx
.gsa
[i
] == NULL
|| minmea_parse_gsa(&frame_gsa
, gnssctx
.gsa
[i
]->data
) != 1)
596 if (tnow
- gnssctx
.gsa
[i
]->tm
> 1000) {
600 lua_createtable(L
, 0, 12);
601 lua_pushliteral(L
, "fix_type");
602 lua_pushinteger(L
, frame_gsa
.fix_type
);
605 lua_pushliteral(L
, "pdop");
606 push_gnss_value(L
, &(frame_gsa
.pdop
), 0);
609 lua_pushliteral(L
, "hdop");
610 push_gnss_value(L
, &(frame_gsa
.hdop
), 0);
613 lua_pushliteral(L
, "vdop");
614 push_gnss_value(L
, &(frame_gsa
.vdop
), 0);
617 lua_pushliteral(L
, "sysid");
618 lua_pushinteger(L
, frame_gsa
.sysid
);
621 lua_pushliteral(L
, "sats");
622 lua_createtable(L
, 12, 0);
624 for (size_t j
= 0; j
< 12; j
++)
626 if (frame_gsa
.sats
[j
] == 0)
629 lua_pushinteger(L
, frame_gsa
.sats
[j
]);
630 lua_seti(L
, -2, pos
);
634 lua_seti(L
, -2, count
);
638 static int l_libgnss_get_gsa(lua_State
*L
) {
639 int mode
= luaL_optinteger(L
, 1, 0);
642 return l_libgnss_get_gsa_mode1(L
);
645 return l_libgnss_get_gsa_mode0(L
);
652 @api libgnss.getVtg(data_mode)
653 @int 可选, 3-原始字符串, 不传或者传其他值, 则返回浮点值
654 @return table 原始VTA数据
657 log.info("nmea", "vtg", json.encode(libgnss.getVtg()))
661 "speed_knots":0, // 速度, 英里/小时
662 "true_track_degrees":0, // 真北方向角
663 "magnetic_track_degrees":0, // 磁北方向角
664 "speed_kph":0 // 速度, 千米/小时
666 -- 提醒: Air780EG和Air510U,在速度<5km/h时, 不会返回方向角
669 static int l_libgnss_get_vtg(lua_State
*L
) {
670 int mode
= luaL_optinteger(L
, 1, 0);
672 if (gnssctx
.vtg
== NULL
)
675 lua_pushstring(L
, gnssctx
.vtg
->data
);
678 lua_createtable(L
, 0, 10);
679 struct minmea_sentence_vtg frame_vtg
= {0};
680 minmea_parse_vtg(&frame_vtg
, gnssctx
.vtg
->data
);
682 // lua_pushliteral(L, "faa_mode");
683 // lua_pushlstring(L, gnssctx.frame_vtg.faa_mode, 1);
684 // lua_settable(L, -3);
686 lua_pushliteral(L
, "true_track_degrees");
687 push_gnss_value(L
, &(frame_vtg
.true_track_degrees
), 0);
690 lua_pushliteral(L
, "magnetic_track_degrees");
691 push_gnss_value(L
, &(frame_vtg
.magnetic_track_degrees
), 0);
694 lua_pushliteral(L
, "speed_knots");
695 push_gnss_value(L
, &(frame_vtg
.speed_knots
), 0);
698 lua_pushliteral(L
, "speed_kph");
699 push_gnss_value(L
, &(frame_vtg
.speed_kph
), 0);
707 @api libgnss.getZda()
708 @return table 原始zda数据
710 log.info("nmea", "zda", json.encode(libgnss.getZda()))
714 "minute_offset":0, // 本地时区的分钟, 一般固定输出0
715 "hour_offset":0, // 本地时区的小时, 一般固定输出0
716 "year":2023 // UTC 年,四位数字
717 "month":1, // UTC 月,两位,01 ~ 12
718 "day":5, // UTC 日,两位数字,01 ~ 31
725 static int l_libgnss_get_zda(lua_State
*L
) {
726 lua_createtable(L
, 0, 9);
727 struct tm rtime
= {0};
728 if (gnssctx
.zda
!= NULL
) {
729 struct minmea_sentence_zda frame_zda
= {0};
730 minmea_parse_zda(&frame_zda
, gnssctx
.zda
->data
);
732 lua_pushliteral(L
, "hour_offset");
733 lua_pushinteger(L
, frame_zda
.hour_offset
);
736 lua_pushliteral(L
, "minute_offset");
737 lua_pushinteger(L
, frame_zda
.minute_offset
);
741 minmea_getdatetime(&rtime
, &frame_zda
.date
, &frame_zda
.time
);
742 put_datetime(L
, &rtime
);
750 @api libgnss.debug(mode)
751 @bool true开启调试,false关闭调试,默认为false
753 -- 开启调试, 会输出GNSS原始数据到日志中
758 static int l_libgnss_debug(lua_State
*L
) {
759 if (lua_isboolean(L
, 1) && lua_toboolean(L
, 1)) {
773 @api libgnss.getGga(data_mode)
774 @int 坐标类数据的格式, 0-DDMM.MMM格式, 1-DDDDDDD格式, 2-DD.DDDDD格式, 3-原始字符串
775 @return table GGA数据, 若如不存在会返回nil
777 local gga = libgnss.getGga(2)
779 log.info("GGA", json.encode(gga, "11g"))
784 "dgps_age":0, // 差分校正时延,单位为秒
785 "fix_quality":1, // 定位状态标识 0 - 无效,1 - 单点定位,2 - 差分定位
786 "satellites_tracked":14, // 参与定位的卫星数量
787 "altitude":0.255, // 海平面分离度, 或者成为海拔, 单位是米,
788 "hdop":0.0335, // 水平精度因子,0.00 - 99.99,不定位时值为 99.99
789 "longitude":113.231, // 经度, 正数为东经, 负数为西经
790 "latitude":23.4067, // 纬度, 正数为北纬, 负数为南纬
791 "height":0 // 椭球高,固定输出 1 位小数
795 static int l_libgnss_get_gga(lua_State
* L
) {
796 int mode
= luaL_optinteger(L
, 1, 0);
798 if (gnssctx
.gga
== NULL
)
801 lua_pushstring(L
, gnssctx
.gga
->data
);
805 struct minmea_sentence_gga frame_gga
= {0};
806 minmea_parse_gga(&frame_gga
, gnssctx
.gga
->data
);
808 lua_pushstring(L
, "altitude");
809 push_gnss_value(L
, &(frame_gga
.altitude
), 0);
812 lua_pushstring(L
, "latitude");
813 push_gnss_value(L
, &(frame_gga
.latitude
), mode
);
816 lua_pushstring(L
, "longitude");
817 push_gnss_value(L
, &(frame_gga
.longitude
), mode
);
820 lua_pushstring(L
, "fix_quality");
821 lua_pushinteger(L
, frame_gga
.fix_quality
);
824 lua_pushstring(L
, "satellites_tracked");
825 lua_pushinteger(L
, frame_gga
.satellites_tracked
);
828 lua_pushstring(L
, "hdop");
829 push_gnss_value(L
, &(frame_gga
.hdop
), 0);
832 lua_pushstring(L
, "height");
833 push_gnss_value(L
, &(frame_gga
.height
), 0);
836 lua_pushstring(L
, "dgps_age");
837 push_gnss_value(L
, &(frame_gga
.dgps_age
), 0);
845 @api libgnss.getGll(data_mode)
846 @int 坐标类数据的格式, 0-DDMM.MMM格式, 1-DDDDDDD格式, 2-DD.DDDDD格式
847 @return table GLL数据, 若如不存在会返回nil
849 local gll = libgnss.getGll(2)
851 log.info("GLL", json.encode(gll, "11g"))
856 "status":"A", // 定位状态, A有效, B无效
857 "mode":"A", // 定位模式, V无效, A单点解, D差分解
858 "sec":20, // 秒, UTC时间为准
859 "min":23, // 分钟, UTC时间为准
860 "hour":7, // 小时, UTC时间为准
861 "longitude":113.231, // 经度, 正数为东经, 负数为西经
862 "latitude":23.4067, // 纬度, 正数为北纬, 负数为南纬
867 static int l_libgnss_get_gll(lua_State
* L
) {
868 int mode
= luaL_optinteger(L
, 1, 0);
870 if (gnssctx
.gll
== NULL
)
873 lua_pushstring(L
, gnssctx
.vtg
->data
);
877 struct minmea_sentence_gll frame_gll
= {0};
878 minmea_parse_gll(&frame_gll
, gnssctx
.gll
->data
);
880 lua_pushstring(L
, "latitude");
881 push_gnss_value(L
, &(frame_gll
.latitude
), mode
);
884 lua_pushstring(L
, "longitude");
885 push_gnss_value(L
, &(frame_gll
.longitude
), mode
);
888 lua_pushstring(L
, "mode");
889 lua_pushfstring(L
, "%c", frame_gll
.mode
);
892 lua_pushstring(L
, "status");
893 lua_pushfstring(L
, "%c", frame_gll
.status
);
896 lua_pushstring(L
, "hour");
897 lua_pushinteger(L
, frame_gll
.time
.hours
);
899 lua_pushstring(L
, "us");
900 lua_pushinteger(L
, frame_gll
.time
.microseconds
);
902 lua_pushstring(L
, "min");
903 lua_pushinteger(L
, frame_gll
.time
.minutes
);
905 lua_pushstring(L
, "sec");
906 lua_pushinteger(L
, frame_gll
.time
.seconds
);
919 static int l_libgnss_clear(lua_State
*L
) {
921 luat_libgnss_init(true);
927 @api libgnss.bind(id, next_id)
929 @int 转发到uart的id, 例如虚拟uart.VUART_0
931 -- 配置串口信息, 通常为 115200 8N1
932 uart.setup(2, 115200)
933 -- 绑定uart, 马上开始解析GNSS数据
935 -- 无需再调用uart.on然后调用libgnss.parse
939 -- 2023-01-02之后编译的固件有效
940 -- 从uart2读取并解析, 同时转发到虚拟串口0
941 libgnss.bind(2, uart.VUART_0)
943 static int l_libgnss_bind(lua_State
* L
) {
944 int uart_id
= luaL_checkinteger(L
, 1);
946 if (libgnss_recvbuff
== NULL
) {
947 libgnss_recvbuff
= luat_heap_malloc(RECV_BUFF_SIZE
);
949 if (luat_uart_exist(uart_id
)) {
950 //uart_app_recvs[uart_id] = nmea_uart_recv_cb;
951 luat_uart_set_app_recv(uart_id
, l_libgnss_uart_recv_cb
);
953 if (lua_isinteger(L
, 2)) {
954 libgnss_route_uart_id
= luaL_checkinteger(L
, 2);
962 @api libgnss.locStr(mode)
963 @int 字符串模式. 0- Air780EG所需的格式
968 static int l_libgnss_locStr(lua_State
*L
) {
969 int mode
= luaL_optinteger(L
, 1, 0);
971 float lat_f
= minmea_tofloat(&gnssctx
.frame_rmc
.latitude
);
972 float lng_f
= minmea_tofloat(&gnssctx
.frame_rmc
.longitude
);
976 snprintf_(buff
, 63, "%.7g,%c,%.7g,%c,1.0",
977 fabs(lat_f
), lat_f
> 0 ? 'N' : 'S',
978 fabs(lng_f
), lng_f
> 0 ? 'E' : 'W');
981 snprintf_(buff
, 63, "%d,%d", gnssctx
.frame_rmc
.latitude
.value
, gnssctx
.frame_rmc
.longitude
.value
);
986 lua_pushstring(L
, buff
);
992 @api libgnss.rtcAuto(enable)
993 @bool 开启与否, 默认是false关闭
996 libgnss.rtcAuto(true)
998 static int l_libgnss_rtc_auto(lua_State
*L
) {
999 if (lua_isboolean(L
, 1) && lua_toboolean(L
, 1)) {
1000 gnssctx
.rtc_auto
= 1;
1001 LLOGD("GNSS->RTC Auto-Set now is ON");
1004 gnssctx
.rtc_auto
= 0;
1005 LLOGD("GNSS->RTC Auto-Set now is OFF");
1010 static int l_libgnss_data_cb(lua_State
*L
, void* ptr
) {
1011 rtos_msg_t
* msg
= (rtos_msg_t
*)lua_topointer(L
, -1);
1012 // lua_getglobal(L, "sys_pub");
1013 lua_geti(L
, LUA_REGISTRYINDEX
, msg
->arg2
);
1014 if (lua_isfunction(L
, -1)) {
1015 // lua_pushliteral(gnss_L, "GNSS_RAW_DATA");
1016 lua_pushlstring(L
, ptr
, msg
->arg1
);
1017 luat_heap_free(ptr
);
1022 luat_heap_free(ptr
);
1027 int luat_libgnss_on_rawdata(const char* data
, size_t len
, int type
) {
1030 if (gnss_raw_cb
== 0)
1034 else if (type
== 1) {
1035 if (gnss_txt_cb
== 0)
1039 else if (type
== 2) {
1040 if (gnss_other_cb
== 0)
1047 char* ptr
= luat_heap_malloc(len
);
1050 memcpy(ptr
, data
, len
);
1052 .handler
= l_libgnss_data_cb
,
1057 luat_msgbus_put(&msg
, 0);
1063 @api libgnss.on(tp, fn)
1064 @string 事件类型,当前支持"raw"
1066 -- 本函数一般用于调试, 用于获取底层实际收到的数据
1067 libgnss.on("raw", function(data)
1068 log.info("GNSS", data)
1071 static int l_libgnss_on(lua_State
*L
) {
1073 const char* tp
= luaL_checklstring(L
, 1, &len
);
1074 if (!strcmp("raw", tp
)) {
1075 if (gnss_raw_cb
!= 0) {
1076 luaL_unref(L
, LUA_REGISTRYINDEX
, gnss_raw_cb
);
1079 if (lua_isfunction(L
, 2)) {
1080 lua_pushvalue(L
, 2);
1081 gnss_raw_cb
= luaL_ref(L
, LUA_REGISTRYINDEX
);
1084 else if (!strcmp("txt", tp
)) {
1085 if (gnss_txt_cb
!= 0) {
1086 luaL_unref(L
, LUA_REGISTRYINDEX
, gnss_txt_cb
);
1089 if (lua_isfunction(L
, 2)) {
1090 lua_pushvalue(L
, 2);
1091 gnss_txt_cb
= luaL_ref(L
, LUA_REGISTRYINDEX
);
1094 else if (!strcmp("other", tp
)) {
1095 if (gnss_other_cb
!= 0) {
1096 luaL_unref(L
, LUA_REGISTRYINDEX
, gnss_other_cb
);
1099 if (lua_isfunction(L
, 2)) {
1100 lua_pushvalue(L
, 2);
1101 gnss_other_cb
= luaL_ref(L
, LUA_REGISTRYINDEX
);
1109 @api libgnss.getTxt()
1110 @return GPTXT所携带的字符串
1113 log.info("gnss", "txt", libgnss.getTxt())
1116 libgnss.parse("$GPTXT,01,01,01,ANTENNA SHORT*63\r\n")
1117 log.info("GNSS", libgnss.getTxt())
1118 libgnss.parse("$GPTXT,01,01,01,ANTENNA OPEN*25\r\n")
1119 log.info("GNSS", libgnss.getTxt())
1120 libgnss.parse("$GPTXT,01,01,01,ANTENNA OK*35\r\n")
1121 log.info("GNSS", libgnss.getTxt())
1123 static int l_libgnss_get_txt(lua_State
*L
) {
1124 if (gnssctx
.txt
== NULL
) {
1125 lua_pushliteral(L
, "");
1128 struct minmea_sentence_txt txt
= {0};
1129 minmea_parse_txt(&txt
, gnssctx
.txt
->data
);
1130 txt
.txt
[FRAME_TXT_MAX_LEN
] = 0x00;
1131 lua_pushstring(L
, txt
.txt
);
1137 @api libgnss.casic_aid(dt, loc)
1140 @return string 辅助定位数据
1142 -- 本函数适合CASIC系列GNSS模块的辅助定位信息的合成
1143 -- 本函数 2023.11.14 新增
1146 -- 时间来源很多, 一般建议socket.sntp()时间同步后的系统时间
1147 local dt = os.date("!*t")
1151 -- 1. 从历史定位数据得到, 例如之前定位成功后保存到本地文件系统了
1152 -- 2. 通过基站定位或者wifi定位获取到
1154 -- 坐标系是WGS84, 但鉴于是辅助定位,精度不是关键因素
1160 local aid = libgnss.casic_aid(dt, lla)
1162 #include "luat_casic_gnss.h"
1163 double strtod(const char *s
,char **ptr
);
1164 static int l_libgnss_casic_aid(lua_State
* L
) {
1165 DATETIME_STR dt
= {0};
1166 POS_LLA_STR lla
= {0};
1167 const char* data
= "";
1169 if (lua_istable(L
, 1)) {
1170 if (LUA_TNUMBER
== lua_getfield(L
, 1, "day")) {
1171 dt
.day
= lua_tointeger(L
, -1);
1174 // 这里兼容month和mon两种, os.date 和 rtc.get
1175 if (LUA_TNUMBER
== lua_getfield(L
, 1, "month")) {
1176 dt
.month
= lua_tointeger(L
, -1);
1179 if (LUA_TNUMBER
== lua_getfield(L
, 1, "mon")) {
1180 dt
.month
= lua_tointeger(L
, -1);
1184 if (LUA_TNUMBER
== lua_getfield(L
, 1, "year")) {
1185 dt
.year
= lua_tointeger(L
, -1);
1190 if (LUA_TNUMBER
== lua_getfield(L
, 1, "hour")) {
1191 dt
.hour
= lua_tointeger(L
, -1);
1194 if (LUA_TNUMBER
== lua_getfield(L
, 1, "min")) {
1195 dt
.minute
= lua_tointeger(L
, -1);
1198 if (LUA_TNUMBER
== lua_getfield(L
, 1, "sec")) {
1199 dt
.second
= lua_tointeger(L
, -1);
1203 if (lua_istable(L
, 2)) {
1204 lua_getfield(L
, 2, "lat");
1205 if (LUA_TNUMBER
== lua_type(L
, -1)) {
1206 lla
.lat
= lua_tonumber(L
, -1);
1208 else if (LUA_TSTRING
== lua_type(L
, -1)) {
1209 data
= luaL_checkstring(L
, -1);
1210 lla
.lat
= strtod(data
, NULL
);
1214 lua_getfield(L
, 2, "lng");
1215 if (LUA_TNUMBER
== lua_type(L
, -1)) {
1216 lla
.lon
= lua_tonumber(L
, -1);
1218 else if (LUA_TSTRING
== lua_type(L
, -1)) {
1219 data
= luaL_checkstring(L
, -1);
1220 lla
.lon
= strtod(data
, NULL
);
1223 if (LUA_TNUMBER
== lua_getfield(L
, 2, "alt")) {
1224 lla
.alt
= lua_tonumber(L
, -1);
1227 if (lla
.lat
> 0.001 || lla
.lat
< -0.01)
1228 if (lla
.lon
> 0.001 || lla
.lon
< -0.01)
1232 casicAgnssAidIni(&dt
, &lla
, tmp
);
1233 lua_pushlstring(L
, tmp
, 66);
1237 #include "rotable2.h"
1238 static const rotable_Reg_t reg_libgnss
[] =
1240 { "parse", ROREG_FUNC(l_libgnss_parse
)},
1241 { "isFix", ROREG_FUNC(l_libgnss_is_fix
)},
1242 { "getIntLocation", ROREG_FUNC(l_libgnss_get_int_location
)},
1243 { "getRmc", ROREG_FUNC(l_libgnss_get_rmc
)},
1244 { "getGsv", ROREG_FUNC(l_libgnss_get_gsv
)},
1245 { "getGsa", ROREG_FUNC(l_libgnss_get_gsa
)},
1246 { "getVtg", ROREG_FUNC(l_libgnss_get_vtg
)},
1247 { "getGga", ROREG_FUNC(l_libgnss_get_gga
)},
1248 { "getGll", ROREG_FUNC(l_libgnss_get_gll
)},
1249 { "getZda", ROREG_FUNC(l_libgnss_get_zda
)},
1250 { "locStr", ROREG_FUNC(l_libgnss_locStr
)},
1251 { "rtcAuto",ROREG_FUNC(l_libgnss_rtc_auto
)},
1252 { "on", ROREG_FUNC(l_libgnss_on
)},
1254 { "debug", ROREG_FUNC(l_libgnss_debug
)},
1255 { "clear", ROREG_FUNC(l_libgnss_clear
)},
1256 { "bind", ROREG_FUNC(l_libgnss_bind
)},
1258 { "getTxt", ROREG_FUNC(l_libgnss_get_txt
)},
1259 { "casic_aid", ROREG_FUNC(l_libgnss_casic_aid
)},
1261 { NULL
, ROREG_INT(0)}
1264 LUAMOD_API
int luaopen_libgnss( lua_State
*L
) {
1265 luat_newlib2(L
, reg_libgnss
);