niujiuru 1 год назад
Родитель
Сommit
1c173be8bd
100 измененных файлов с 13930 добавлено и 0 удалено
  1. 92 0
      Makefile
  2. 52 0
      air530z/Makefile
  3. 199 0
      air530z/air530z.c
  4. 40 0
      air530z/air530z.go
  5. 31 0
      air530z/air530z.h
  6. 45 0
      air530z/air530z_test.c
  7. 41 0
      air530z/bridge.go
  8. 27 0
      air530z/nmealib/CHANGELOG.TXT
  9. 506 0
      air530z/nmealib/LICENSE.TXT
  10. 26 0
      air530z/nmealib/README.TXT
  11. 51 0
      air530z/nmealib/include/nmea/config.h
  12. 44 0
      air530z/nmealib/include/nmea/context.h
  13. 44 0
      air530z/nmealib/include/nmea/generate.h
  14. 79 0
      air530z/nmealib/include/nmea/generator.h
  15. 92 0
      air530z/nmealib/include/nmea/gmath.h
  16. 119 0
      air530z/nmealib/include/nmea/info.h
  17. 25 0
      air530z/nmealib/include/nmea/nmea.h
  18. 49 0
      air530z/nmealib/include/nmea/parse.h
  19. 59 0
      air530z/nmealib/include/nmea/parser.h
  20. 133 0
      air530z/nmealib/include/nmea/sentence.h
  21. 47 0
      air530z/nmealib/include/nmea/time.h
  22. 30 0
      air530z/nmealib/include/nmea/tok.h
  23. 30 0
      air530z/nmealib/include/nmea/units.h
  24. 67 0
      air530z/nmealib/src/context.c
  25. 229 0
      air530z/nmealib/src/generate.c
  26. 399 0
      air530z/nmealib/src/generator.c
  27. 377 0
      air530z/nmealib/src/gmath.c
  28. 24 0
      air530z/nmealib/src/info.c
  29. 739 0
      air530z/nmealib/src/parse.c
  30. 462 0
      air530z/nmealib/src/parser.c
  31. 54 0
      air530z/nmealib/src/sentence.c
  32. 63 0
      air530z/nmealib/src/time.c
  33. 250 0
      air530z/nmealib/src/tok.c
  34. 42 0
      air720u/Makefile
  35. 393 0
      air720u/air720u.c
  36. 233 0
      air720u/air720u.go
  37. 42 0
      air720u/air720u.h
  38. 60 0
      air720u/air720u_test.c
  39. 88 0
      air720u/bridge.go
  40. 218 0
      air720u/eth2net.go
  41. 72 0
      baseapp/app.go
  42. 99 0
      baseapp/args.go
  43. 207 0
      baseapp/log.go
  44. 71 0
      baseapp/path.go
  45. 55 0
      baseapp/ver.go
  46. 13 0
      docs/4G网络可访问白名单网址20250707.txt
  47. BIN
      docs/Air530Z定位模块使用手册V1.4.pdf
  48. BIN
      docs/Luat4G模块AT命令手册V4.3.3.pdf
  49. 19 0
      go.mod
  50. 37 0
      go.sum
  51. 70 0
      main.go
  52. 50 0
      mvs_usb_takephoto/Makefile
  53. 67 0
      mvs_usb_takephoto/bridge.go
  54. 69 0
      mvs_usb_takephoto/hkcam_reset.c
  55. 1330 0
      mvs_usb_takephoto/include/CameraParams.h
  56. 2722 0
      mvs_usb_takephoto/include/MvCameraControl.h
  57. 119 0
      mvs_usb_takephoto/include/MvErrorDefine.h
  58. 98 0
      mvs_usb_takephoto/include/MvISPErrorDefine.h
  59. 2133 0
      mvs_usb_takephoto/include/MvObsoleteInterfaces.h
  60. 655 0
      mvs_usb_takephoto/include/ObsoleteCamParams.h
  61. 198 0
      mvs_usb_takephoto/include/PixelType.h
  62. 79 0
      mvs_usb_takephoto/lib/armv7hf/CommonParameters.ini
  63. BIN
      mvs_usb_takephoto/lib/armv7hf/MvProducerGEV.cti
  64. BIN
      mvs_usb_takephoto/lib/armv7hf/MvProducerU3V.cti
  65. BIN
      mvs_usb_takephoto/lib/armv7hf/libFormatConversion.so
  66. 1 0
      mvs_usb_takephoto/lib/armv7hf/libMVGigEVisionSDK.so
  67. BIN
      mvs_usb_takephoto/lib/armv7hf/libMVGigEVisionSDK.so.4.5.0.3
  68. BIN
      mvs_usb_takephoto/lib/armv7hf/libMVRender.so
  69. BIN
      mvs_usb_takephoto/lib/armv7hf/libMediaProcess.so
  70. 1 0
      mvs_usb_takephoto/lib/armv7hf/libMvCameraControl.so
  71. BIN
      mvs_usb_takephoto/lib/armv7hf/libMvCameraControl.so.4.5.0.3
  72. 1 0
      mvs_usb_takephoto/lib/armv7hf/libMvCameraControlWrapper.so
  73. BIN
      mvs_usb_takephoto/lib/armv7hf/libMvCameraControlWrapper.so.4.5.0.1
  74. BIN
      mvs_usb_takephoto/lib/armv7hf/libMvSDKVersion.so
  75. 1 0
      mvs_usb_takephoto/lib/armv7hf/libMvUsb3vTL.so
  76. BIN
      mvs_usb_takephoto/lib/armv7hf/libMvUsb3vTL.so.4.5.0.3
  77. BIN
      mvs_usb_takephoto/lib/armv7hf/libavutil.so
  78. BIN
      mvs_usb_takephoto/lib/armv7hf/libswscale.so
  79. BIN
      mvs_usb_takephoto/lib/armv7hf/libusb-1.0.so.0
  80. 79 0
      mvs_usb_takephoto/lib/x86_64/32/CommonParameters.ini
  81. BIN
      mvs_usb_takephoto/lib/x86_64/32/MvProducerGEV.cti
  82. BIN
      mvs_usb_takephoto/lib/x86_64/32/MvProducerU3V.cti
  83. BIN
      mvs_usb_takephoto/lib/x86_64/32/libFormatConversion.so
  84. 1 0
      mvs_usb_takephoto/lib/x86_64/32/libMVGigEVisionSDK.so
  85. BIN
      mvs_usb_takephoto/lib/x86_64/32/libMVGigEVisionSDK.so.4.5.0.3
  86. BIN
      mvs_usb_takephoto/lib/x86_64/32/libMVRender.so
  87. BIN
      mvs_usb_takephoto/lib/x86_64/32/libMediaProcess.so
  88. 1 0
      mvs_usb_takephoto/lib/x86_64/32/libMvCameraControl.so
  89. BIN
      mvs_usb_takephoto/lib/x86_64/32/libMvCameraControl.so.4.5.0.3
  90. 1 0
      mvs_usb_takephoto/lib/x86_64/32/libMvCameraControlWrapper.so
  91. BIN
      mvs_usb_takephoto/lib/x86_64/32/libMvCameraControlWrapper.so.4.5.0.1
  92. BIN
      mvs_usb_takephoto/lib/x86_64/32/libMvSDKVersion.so
  93. 1 0
      mvs_usb_takephoto/lib/x86_64/32/libMvUsb3vTL.so
  94. BIN
      mvs_usb_takephoto/lib/x86_64/32/libMvUsb3vTL.so.4.5.0.3
  95. BIN
      mvs_usb_takephoto/lib/x86_64/32/libavutil.so
  96. BIN
      mvs_usb_takephoto/lib/x86_64/32/libswscale.so
  97. BIN
      mvs_usb_takephoto/lib/x86_64/32/libusb-1.0.so.0
  98. 79 0
      mvs_usb_takephoto/lib/x86_64/64/CommonParameters.ini
  99. BIN
      mvs_usb_takephoto/lib/x86_64/64/MvFGProducerCML.cti
  100. 0 0
      mvs_usb_takephoto/lib/x86_64/64/MvFGProducerCXP.cti

+ 92 - 0
Makefile

@@ -0,0 +1,92 @@
+.PHONY: all clean
+
+# C&GO编译器
+CC = gcc
+AR = ar
+DEFINS = -D_GNU_SOURCE
+
+GO := go
+GO_BUILD := $(GO) build
+GO_FLAGS := -ldflags "-s -w -X hnyfkj.com.cn/rtu/linux/baseapp.Version=1.0.0.1 -X hnyfkj.com.cn/rtu/linux/baseapp.BuildTime=$(shell date +%Y-%m-%dT%H:%M:%S)"
+
+target ?= x86_64
+ifeq ($(target),armv7hf)
+  GOOS := linux
+  GOARCH := arm
+  GOARM := 7
+  CC := arm-linux-gnueabihf-gcc
+  AR := arm-linux-gnueabihf-ar
+endif
+
+# GO编译环境
+SETGO_ENV = \
+	$(if $(GOOS),GOOS=$(GOOS)) \
+	$(if $(GOARCH),GOARCH=$(GOARCH)) \
+	$(if $(GOARM),GOARM=$(GOARM)) \
+	CC=$(CC) CGO_ENABLED=1 \
+
+# 日期和时间
+DATE := $(shell date +%Y%m%d_%H%M%S)
+
+# 编译的目标
+all : mvs_usb_takephoto.out air720u_4g.out rtu_linux_modules.out
+
+# 通用基础库
+libswapi.a :
+	$(MAKE) -C swapi target=$(target) $@
+
+# 海康机器人
+libmvs_usb_takephoto.a :
+	$(MAKE) -C mvs_usb_takephoto target=$(target) $@
+
+# "Air720U"
+libair720u.a :
+	$(MAKE) -C air720u target=$(target) $@
+
+# "Air530Z"
+libair530z.a :
+	$(MAKE) -C air530z target=$(target) $@
+
+# 海康相机拍照测试
+LIB1 := -Wl,-Bstatic -L./swapi -lswapi -L./mvs_usb_takephoto -lmvs_usb_takephoto
+ifeq ($(target),armv7hf)
+  LIB1 += -Wl,-Bdynamic -lc -lm -ldl -lpthread -L$(PWD)/mvs_usb_takephoto/lib/armv7hf/. -lMvCameraControl
+else
+  LIB1 += -Wl,-Bdynamic -lc -lm -ldl -lpthread -L$(PWD)/mvs_usb_takephoto/lib/x86_64/64 -lMvCameraControl
+endif
+mvs_usb_takephoto.out : libswapi.a libmvs_usb_takephoto.a ./tests/mvs_usb_takephoto/main.go
+	mkdir -p ./build/takephoto_test
+	$(GO) mod tidy
+	$(SETGO_ENV) CGO_LDFLAGS="$(LIB1)" $(GO_BUILD) $(GO_FLAGS) -o $@ ./tests/mvs_usb_takephoto/main.go
+	@cp $@ ./build/takephoto_test/$(basename $@)_$(DATE)$(suffix $@)
+	rm -rf $@
+
+# 测4G模块Air720U
+LIB2 := -Wl,-Bstatic -L./swapi -lswapi -L./air720u -lair720u -Wl,-Bdynamic -lc -lm -ldl -lpthread
+air720u_4g.out : libswapi.a libair720u.a ./tests/air720u/main.go
+	mkdir -p ./build/air720u_test
+	$(GO) mod tidy
+	$(SETGO_ENV) CGO_LDFLAGS="$(LIB2)" $(GO_BUILD) $(GO_FLAGS) -o $@ ./tests/air720u/main.go
+	@cp $@ ./build/air720u_test/$(basename $@)_$(DATE)$(suffix $@)
+	rm -rf $@
+
+# 主测试程序
+LIB3 := -Wl,-Bstatic -L./swapi -lswapi -L./mvs_usb_takephoto -lmvs_usb_takephoto -L./air720u -lair720u -L./air530z -lair530z
+ifeq ($(target),armv7hf)
+  LIB3 += -Wl,-Bdynamic -lc -lm -ldl -lpthread -L$(PWD)/mvs_usb_takephoto/lib/armv7hf/. -lMvCameraControl
+else
+  LIB3 += -Wl,-Bdynamic -lc -lm -ldl -lpthread -L$(PWD)/mvs_usb_takephoto/lib/x86_64/64 -lMvCameraControl
+endif
+rtu_linux_modules.out : libswapi.a libmvs_usb_takephoto.a libair720u.a libair530z.a ./main.go
+	mkdir -p ./build
+	$(GO) mod tidy
+	$(SETGO_ENV) CGO_LDFLAGS="$(LIB3)" $(GO_BUILD) $(GO_FLAGS) -o $@ ./main.go
+	@cp $@ ./build/$(basename $@)_$(DATE)$(suffix $@)
+
+# 编译的清理
+clean :
+	make -C ./swapi clean
+	make -C ./mvs_usb_takephoto clean
+	make -C ./air720u clean
+	make -C ./air530z clean
+	rm -rf ./*.a ./*.out ./build

+ 52 - 0
air530z/Makefile

@@ -0,0 +1,52 @@
+.PHONY: build clean
+
+# 头文件
+INCS += -I.
+INCS += -I../swapi
+INCS += -I./include
+INCS += -I./nmealib/include
+
+# 源文件
+NMEA_SRCS := $(wildcard ./nmealib/src/*.c)
+SRCS += $(filter-out ../swapi/testLib.c, $(wildcard ../swapi/*.c))
+SRCS += ../swapi/subjects/serial/serial.c air530z.c
+SRCS += $(NMEA_SRCS)
+
+# .o文件
+OBJS = $(SRCS:.c=.o)
+
+# 编译器
+CC = gcc
+CFLAGS = -Wall -fPIC -O2 -g
+CFLAGS_NMEA = $(CFLAGS) -Wno-unused-but-set-variable
+DEFINS = -D_GNU_SOURCE
+
+# 单元测试时使用用, 开启调试模式, 正式编译时需要注释掉
+# DEFINS += -D_DEBUG
+
+target ?= x86_64
+ifeq ($(target),armv7hf)
+  CC := arm-linux-gnueabihf-gcc
+	AR := arm-linux-gnueabihf-ar
+endif
+
+# 库文件
+LIBS += -Wl,-Bdynamic -lc -lm -ldl -lpthread
+
+# 编译和清理
+build : libair530z.a air530z_test.out
+
+%.o : %.c
+	$(CC) $(DEFINS) $(CFLAGS) -c $< $(INCS) -o $@
+
+nmealib/src/%.o: nmealib/src/%.c
+	$(CC) $(DEFINS) $(CFLAGS_NMEA) -c $< $(INCS) -o $@
+
+libair530z.a : $(OBJS)
+	$(AR) -cr $@ $(OBJS)
+
+air530z_test.out : $(OBJS)
+	$(CC) $(DEFINS) $(CFLAGS) $(OBJS) air530z_test.c $(INCS) $(LIBS) -o $@
+
+clean :
+	rm -rf $(OBJS) *.out *.a config/ log/ status/ var/

+ 199 - 0
air530z/air530z.c

@@ -0,0 +1,199 @@
+#include "air530z.h"
+#include "../swapi/subjects/serial/serial.h"
+#include "./nmealib/include/nmea/nmea.h"
+
+// 模块名称
+static const char MODULE_NAME[] = "Air530Z";
+
+// 设置输出频率
+static const char *PCAS02 = "$PCAS02,1000*2E\r\n";
+// 设置输出格式
+static const char *PCAS03 = "$PCAS03,1,0,0,1,1,0,0,0,0,0,,,0,0*03\r\n";
+// 设置卫星组合
+static const char *PCAS04 = "$PCAS04,13,13,11*29\r\n";
+// 设置接收模式: "静态模式"
+static const char *PCAS11 = "$PCAS11,1*1C\r\n";
+
+// 定义关键控制符号
+#define LF '\n' // 换行
+
+// 输出控制精度阈值
+#define HDOP_MAX               2.0 // 水平精度判定阈值
+#define MIN_SATELLITES         5   // 最小可见卫星(个)
+#define STATIONARY_RADIUS      3.0 // 静止判定半径(米)
+#define CONT_STATIONARY_FRAMES 4   // 累计连续静止帧数
+#define POS_SMOOTHING_NORMAL   0.6 // 正常定位滑动系数
+#define POS_SMOOTHING_WEAK     0.2 // 弱定位时滑动系数
+#define CONT_WEAK_FRAMES       8   // 连续弱定位的帧数
+
+// 定义无效的坐标值
+#define COORD_NAN NAN
+#define IS_COORD_NAN(x) isnan(x)
+
+// 与模块的串口通讯
+typedef struct
+{
+  void *h; // 打开的串口句柄
+
+  nmeaINFO info;     // decoded NMEA data
+  nmeaPARSER parser; // NMEA decoder解码器
+  struct
+  { // 存储经过平滑处理的经纬度坐标(滤波轨迹)
+    double lat;
+    double lon;
+    int stationary_cnt; // 连续静止帧数统计
+    int weak_cnt; // 连续弱定位帧数统计
+  } filter;
+
+  struct
+  {
+    bool bOK; // 定位是否成功
+    char lat[MAX_LINE_CHARS]; // 纬度字符串
+    char lon[MAX_LINE_CHARS]; // 经度字符串
+  } outPos2d;
+  void *out_rwlock;
+} SAir530ZCom;
+
+static SAir530ZCom s_myCom;
+
+// 接收、处理来自Air530Z模块的数据报文帧, 串口-线程回调
+static int comio_data_recv_proc(unsigned long wParam/*传递打开的串口句柄*/, unsigned long lParam/*保留暂未使用*/)
+{
+  SAir530ZCom *pComIO = &s_myCom; void *pSerial = pComIO->h;
+  const unsigned char *pRecvBuf = serial_get_recv_buffer(pSerial); int nRecvBytes = serial_get_recv_buffer_bytes(pSerial);
+  const char *log_prefix = serial_get_log_prefix(pSerial); int ret; bool bWeakPos;
+
+  if (nRecvBytes <= 0 || pRecvBuf[nRecvBytes - 1] != LF) goto ret_p;
+
+  sw_log_trace("[%s] %s received a frame(%d bytes): %s", MODULE_NAME, log_prefix, nRecvBytes, pRecvBuf);
+
+  ret = nmea_parse(&pComIO->parser, (const char *)pRecvBuf, nRecvBytes, &pComIO->info);
+  serial_clear_recv_buffer(pSerial); // 当前数据帧已解析, 清空接收缓存区, 等待下一数据帧到来
+  if(ret <= 0) { /*sw_log_error("[%s] failed to parse a NMEA frame!!", MODULE_NAME);*/ goto ret_p; }
+
+  if(pComIO->info.sig > 0)
+  {
+    if(pComIO->info.HDOP <= HDOP_MAX && pComIO->info.satinfo.inview >= MIN_SATELLITES) { bWeakPos = false; pComIO->filter.weak_cnt = 0; }
+    else { bWeakPos = true; pComIO->filter.weak_cnt++; }
+
+    double lat = pComIO->info.lat, lon = pComIO->info.lon;
+
+    if(IS_COORD_NAN(pComIO->filter.lat) || IS_COORD_NAN(pComIO->filter.lon))
+    {
+      pComIO->filter.lat = lat;
+      pComIO->filter.lon = lon;
+    }
+
+    nmeaPOS pos1, pos2;
+    nmea_info2pos(&pComIO->info, &pos1);
+    pos2.lat = nmea_ndeg2radian(pComIO->filter.lat);
+    pos2.lon = nmea_ndeg2radian(pComIO->filter.lon);
+
+    double dist = nmea_distance(&pos2, &pos1);
+    if(dist < STATIONARY_RADIUS) { pComIO->filter.stationary_cnt++; }
+    else
+    {
+      pComIO->filter.stationary_cnt = 0;
+      if(bWeakPos) pComIO->filter.lat = pComIO->filter.lon = COORD_NAN;
+      else { pComIO->filter.lat = lat; pComIO->filter.lon = lon; }
+    }
+
+    if(pComIO->filter.stationary_cnt >= CONT_STATIONARY_FRAMES)
+    { /////静止状态处理
+      // 1-应用滑动平均
+      double smoothing = bWeakPos ? POS_SMOOTHING_WEAK : POS_SMOOTHING_NORMAL;
+      pComIO->filter.lat = smoothing * lat + (1 - smoothing) * pComIO->filter.lat;
+      pComIO->filter.lon = smoothing * lon + (1 - smoothing) * pComIO->filter.lon;
+
+      // 2-输出成字符串
+      double out_lat = nmea_ndeg2degree(pComIO->filter.lat); double out_lon = nmea_ndeg2degree(pComIO->filter.lon);
+
+      sw_rwlock_wrlock(pComIO->out_rwlock, WAIT_FOREVER);
+      sprintf(pComIO->outPos2d.lat, "%.6f", out_lat);
+      sprintf(pComIO->outPos2d.lon, "%.6f", out_lon);
+      pComIO->outPos2d.bOK = true;
+      sw_rwlock_unlock(pComIO->out_rwlock);
+
+      // 3-打印定位结果
+      sw_log_trace("[%s] 已定位: lat=%.6f, lon=%.6f, HDOP=%.1f, Sats=%d/%d, DeltaMeters=%.1fm, IsWeakPos=%d", MODULE_NAME, \
+                   out_lat, out_lon, pComIO->info.HDOP, \
+                   pComIO->info.satinfo.inuse, pComIO->info.satinfo.inview, dist, bWeakPos);
+    }
+
+    if(pComIO->filter.weak_cnt >= CONT_WEAK_FRAMES)
+    {
+      pComIO->filter.weak_cnt = pComIO->filter.stationary_cnt = 0;
+      pComIO->filter.lat = pComIO->filter.lon = COORD_NAN;
+    }
+  }
+
+ret_p: return 1; // 持续累加的接收新数据
+}
+
+// 打开与模块的通讯, 返回: 0成功, <0时失败
+int Air530Z_ComInit()
+{
+  nmea_zero_INFO(&s_myCom.info);
+  s_myCom.filter.lat = s_myCom.filter.lon = COORD_NAN;
+  nmea_parser_init(&s_myCom.parser);
+
+  s_myCom.out_rwlock = sw_rwlock_create();
+  if(!s_myCom.out_rwlock)
+  {
+    sw_log_error("[%s] failed to create the \"outPos2d\" rwlock!!", MODULE_NAME);
+    Air530Z_ComExit(); return -1;
+  }
+
+#ifdef _DEBUG // 上位机单元测试时使用
+  const char *serialName = "/dev/ttyS0";   int baudrate = 9600;
+#else
+  const char *serialName = "/dev/ttymxc6"; int baudrate = 9600;
+#endif
+  const char *parityCheck = "none"; // 无校检
+  s_myCom.h = serial_open(serialName, baudrate, parityCheck, \
+                          comio_data_recv_proc, comio_data_recv_proc, NULL);
+  if(!s_myCom.h)
+  {
+    sw_log_error("[%s] failed to open the \"%s:%d(%s parity)\" device!!", \
+                 MODULE_NAME, serialName, baudrate, parityCheck);
+    Air530Z_ComExit(); return -2;
+  }
+
+  serial_send_data(s_myCom.h, (unsigned char *)PCAS02, strlen(PCAS02));
+  serial_send_data(s_myCom.h, (unsigned char *)PCAS03, strlen(PCAS03));
+  serial_send_data(s_myCom.h, (unsigned char *)PCAS04, strlen(PCAS04));
+  serial_send_data(s_myCom.h, (unsigned char *)PCAS11, strlen(PCAS11));
+
+  return 0;
+}
+
+// 关闭与模块的通讯, 返回: 0成功, <0时失败
+int Air530Z_ComExit()
+{
+  if(s_myCom.h) serial_close(s_myCom.h, WAITTHRD_SAFEEXIT_TIMEOUT);
+  if(s_myCom.out_rwlock) sw_rwlock_destroy(s_myCom.out_rwlock);
+  if(s_myCom.parser.buffer) nmea_parser_destroy(&s_myCom.parser);
+  memset(&s_myCom, 0, sizeof(s_myCom));
+  return 0;
+}
+
+// 获取当前的2D位置, 返回: 0成功, -1未定位
+int Air530Z_GetPos2D(char lat[MAX_LINE_CHARS], char lon[MAX_LINE_CHARS])
+{
+  bool bOK = false;
+  sw_rwlock_rdlock(s_myCom.out_rwlock, WAIT_FOREVER);
+  bOK = s_myCom.outPos2d.bOK;
+  if(bOK) {
+    strcpy(lat, s_myCom.outPos2d.lat);
+    strcpy(lon, s_myCom.outPos2d.lon);
+  }
+  sw_rwlock_unlock(s_myCom.out_rwlock);
+  return bOK ? 0 : -1;
+}
+
+#ifdef _DEBUG
+void *Air530Z_GetSerialHandle()
+{
+  return s_myCom.h;
+}
+#endif

+ 40 - 0
air530z/air530z.go

@@ -0,0 +1,40 @@
+// Author: NiuJiuRu
+// Email: niujiuru@qq.com
+
+package air530z
+
+import (
+	"time"
+
+	"hnyfkj.com.cn/rtu/linux/baseapp"
+)
+
+const MODULE_NAME = "Air530Z"
+
+func ModuleInit() {
+	var err error
+	var ret int
+	for range 5 {
+		if baseapp.IsExit1() {
+			return
+		}
+		ret, err = air530Z_ComInit()
+		if ret == -1 {
+			time.Sleep(1 * time.Second)
+			continue
+		} else {
+			break
+		}
+	}
+	if err != nil {
+		baseapp.Logger.Errorf("[%s] 错误: %v!!", MODULE_NAME, err)
+	}
+}
+
+func ModuleExit() {
+	air530Z_ComExit()
+}
+
+func Get2DPosition() (lat string, lon string, err error) {
+	return air530Z_Get2DPosition()
+}

+ 31 - 0
air530z/air530z.h

@@ -0,0 +1,31 @@
+// Author: NiuJiuRu
+// Email: niujiuru@qq.com
+// Date: 2025-08-15
+#ifndef __AIR530Z_H__
+#define __AIR530Z_H__
+
+#include "../swapi/include_swapiLib.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+// 打开与模块的通讯, 返回: 0成功, <0时失败
+int Air530Z_ComInit();
+
+// 关闭与模块的通讯, 返回: 0成功, <0时失败
+int Air530Z_ComExit();
+
+// 获取当前的2D位置, 返回: 0成功, -1未定位
+int Air530Z_GetPos2D(char lat[MAX_LINE_CHARS], char lon[MAX_LINE_CHARS]);
+
+#ifdef _DEBUG
+void *Air530Z_GetSerialHandle(); // 仿真串口输入, 模拟单元测试时使用
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __AIR530Z_H__ */

+ 45 - 0
air530z/air530z_test.c

@@ -0,0 +1,45 @@
+// +build ignore
+
+#include "air530z.h"
+#include "../swapi/subjects/serial/serial.h"
+
+// 主函数入口, 测试联网
+int main(int argc,char *argv[])
+{
+  int ret = Air530Z_ComInit();
+  if(ret < 0)
+  {
+    sw_log_error("an error occurred while calling the Air530Z_ComInit() function(%d)!!", ret);
+    goto end_p;
+  }
+
+  char *pos[] = {
+    // 第一组网上获取测试数据样例
+    /*"$GPGGA,111609.14,5001.27,N,3613.06,E,3,08,0.0,10.2,M,0.0,M,0.0,0000*70\r\n",
+    "$GPGSV,2,1,08,01,05,005,80,02,05,050,80,03,05,095,80,04,05,140,80*7f\r\n",
+    "$GPGSV,2,2,08,05,05,185,80,06,05,230,80,07,05,275,80,08,05,320,80*71\r\n",
+    "$GPGSA,A,3,01,02,03,04,05,06,07,08,00,00,00,00,0.0,0.0,0.0*3a\r\n"*/
+    // 第二组实际采集测试数据样例
+    "$GNGGA,084215.000,3448.59738,N,11339.70987,E,1,08,1.1,195.9,M,-18.9,M,,*6A\r\n",
+    "$GNRMC,084215.000,A,3448.59738,N,11339.70987,E,0.00,0.00,260925,,,A,V*09\r\n",
+    "$GPGSV,2,1,08,03,32,290,29,26,,,27,28,50,052,47,29,24,067,46,0*58\r\n",
+    "$BDGSV,1,1,04,01,,,35,29,07,065,31,40,22,162,34,45,25,053,39,0*46\r\n"
+  };
+
+  for(int i = 0; i < 4; i++) for(int j = 0; j < 4; j++) serial_write_recv_buffer(Air530Z_GetSerialHandle(), (unsigned char*)pos[j], strlen(pos[j]));
+
+  char lat[MAX_LINE_CHARS] = {0}, lon[MAX_LINE_CHARS] = {0};
+pos_p:
+  ret = Air530Z_GetPos2D(lat, lon);
+  if(ret == -1)
+  {
+    sw_log_warn("未定位!");
+    sw_thrd_delay(1000);
+    goto pos_p;
+  }
+  sw_log_info("已定位: lat=%s, lon=%s", lat, lon);
+
+end_p:
+  Air530Z_ComExit();
+  return ret;
+}

+ 41 - 0
air530z/bridge.go

@@ -0,0 +1,41 @@
+// Author: NiuJiuRu
+// Email: niujiuru@qq.com
+
+package air530z
+
+/*
+#include "air530z.h"
+*/
+import "C"
+import (
+	"fmt"
+	"unsafe"
+)
+
+// 打开与模块的通讯
+func air530Z_ComInit() (int, error) {
+	ret := int(C.Air530Z_ComInit())
+	if ret != 0 {
+		return ret, fmt.Errorf("an error occurred while calling the C.Air530Z_ComInit function(%d)", ret)
+	}
+	return 0, nil
+}
+
+// 关闭与模块的通讯
+func air530Z_ComExit() error {
+	ret := int(C.Air530Z_ComExit())
+	if ret != 0 {
+		return fmt.Errorf("an error occurred while calling the C.Air530Z_ComExit function(%d)", ret)
+	}
+	return nil
+}
+
+// 获取当前的2D位置
+func air530Z_Get2DPosition() (lat string, lon string, err error) {
+	var bufLat, bufLon [64]byte
+	ret := int(C.Air530Z_GetPos2D((*C.char)(unsafe.Pointer(&bufLat[0])), (*C.char)(unsafe.Pointer(&bufLon[0]))))
+	if ret == -1 {
+		return "", "", fmt.Errorf("未定位, 请稍后")
+	}
+	return C.GoString((*C.char)(unsafe.Pointer(&bufLat[0]))), C.GoString((*C.char)(unsafe.Pointer(&bufLon[0]))), nil
+}

+ 27 - 0
air530z/nmealib/CHANGELOG.TXT

@@ -0,0 +1,27 @@
+CHANGE LOG
+
+version 0.5.3
+- fixed time parse error (bug #1889477)
+- renamed math.h to gmath.h
+- excluded malloc.h header
+- fixed sleep in samples for UNIX
+- added "remake" target in Makefile
+
+version 0.5.2
+- fixed CRC error (bug #1833200)
+
+version 0.5.1
+- fixed elevation value type (bug #1832486)
+- fixed parsing of GPRMC - nmea_GPRMC2info
+
+version 0.5.0
+- added nmea_distance_ellipsoid, nmea_move_horz_ellipsoid in math.h and sample (Thanks Thomas1970)
+- fixed makefiles (Thanks for Sereg@ and Thomas1970)
+- fixed inline functions in math.h
+
+version 0.4.4
+- fixed makefiles (Thanks for Sereg@ and Thomas1970)
+
+version 0.4.3
+- fixed bugs #1805550, #1780086, #1778485
+- fixed parse VTG packet

+ 506 - 0
air530z/nmealib/LICENSE.TXT

@@ -0,0 +1,506 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
+
+

Разница между файлами не показана из-за своего большого размера
+ 26 - 0
air530z/nmealib/README.TXT


+ 51 - 0
air530z/nmealib/include/nmea/config.h

@@ -0,0 +1,51 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: config.h 17 2008-03-11 11:56:11Z xtimor $
+ *
+ */
+
+#ifndef __NMEA_CONFIG_H__
+#define __NMEA_CONFIG_H__
+
+#define NMEA_VERSION        ("0.5.3")
+#define NMEA_VERSION_MAJOR  (0)
+#define NMEA_VERSION_MINOR  (5)
+#define NMEA_VERSION_PATCH  (3)
+
+#define NMEA_CONVSTR_BUF    (256)
+#define NMEA_TIMEPARSE_BUF  (256)
+
+#if defined(WINCE) || defined(UNDER_CE)
+#   define  NMEA_CE
+#endif
+
+#if defined(WIN32) || defined(NMEA_CE)
+#   define  NMEA_WIN
+#else
+#   define  NMEA_UNI
+#endif
+
+#if defined(NMEA_WIN) && (_MSC_VER >= 1400)
+# pragma warning(disable: 4996) /* declared deprecated */
+#endif
+
+#if defined(_MSC_VER)
+# define NMEA_POSIX(x)  _##x
+# define NMEA_INLINE    __inline
+#else
+# define NMEA_POSIX(x)  x
+# define NMEA_INLINE    inline
+#endif
+
+#if !defined(NDEBUG) && !defined(NMEA_CE)
+#   include <assert.h>
+#   define NMEA_ASSERT(x)   assert(x)
+#else
+#   define NMEA_ASSERT(x)
+#endif
+
+#endif /* __NMEA_CONFIG_H__ */

+ 44 - 0
air530z/nmealib/include/nmea/context.h

@@ -0,0 +1,44 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: context.h 4 2007-08-27 13:11:03Z xtimor $
+ *
+ */
+
+#ifndef __NMEA_CONTEXT_H__
+#define __NMEA_CONTEXT_H__
+
+#include "config.h"
+
+#define NMEA_DEF_PARSEBUFF  (1024)
+#define NMEA_MIN_PARSEBUFF  (256)
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+typedef void (*nmeaTraceFunc)(const char *str, int str_size);
+typedef void (*nmeaErrorFunc)(const char *str, int str_size);
+
+typedef struct _nmeaPROPERTY
+{
+    nmeaTraceFunc   trace_func;
+    nmeaErrorFunc   error_func;
+    int             parse_buff_size;
+
+} nmeaPROPERTY;
+
+nmeaPROPERTY * nmea_property();
+
+void nmea_trace(const char *str, ...);
+void nmea_trace_buff(const char *buff, int buff_size);
+void nmea_error(const char *str, ...);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* __NMEA_CONTEXT_H__ */

+ 44 - 0
air530z/nmealib/include/nmea/generate.h

@@ -0,0 +1,44 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: generate.h 4 2007-08-27 13:11:03Z xtimor $
+ *
+ */
+
+#ifndef __NMEA_GENERATE_H__
+#define __NMEA_GENERATE_H__
+
+#include "sentence.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+int     nmea_generate(
+        char *buff, int buff_sz,    /* buffer */
+        const nmeaINFO *info,       /* source info */
+        int generate_mask           /* mask of sentence`s (e.g. GPGGA | GPGSA) */
+        );
+
+int     nmea_gen_GPGGA(char *buff, int buff_sz, nmeaGPGGA *pack);
+int     nmea_gen_GPGSA(char *buff, int buff_sz, nmeaGPGSA *pack);
+int     nmea_gen_GPGSV(char *buff, int buff_sz, nmeaGPGSV *pack);
+int     nmea_gen_GPRMC(char *buff, int buff_sz, nmeaGPRMC *pack);
+int     nmea_gen_GPVTG(char *buff, int buff_sz, nmeaGPVTG *pack);
+
+void    nmea_info2GPGGA(const nmeaINFO *info, nmeaGPGGA *pack);
+void    nmea_info2GPGSA(const nmeaINFO *info, nmeaGPGSA *pack);
+void    nmea_info2GPRMC(const nmeaINFO *info, nmeaGPRMC *pack);
+void    nmea_info2GPVTG(const nmeaINFO *info, nmeaGPVTG *pack);
+
+int     nmea_gsv_npack(int sat_count);
+void    nmea_info2GPGSV(const nmeaINFO *info, nmeaGPGSV *pack, int pack_idx);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* __NMEA_GENERATE_H__ */

+ 79 - 0
air530z/nmealib/include/nmea/generator.h

@@ -0,0 +1,79 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: generator.h 4 2007-08-27 13:11:03Z xtimor $
+ *
+ */
+
+#ifndef __NMEA_GENERATOR_H__
+#define __NMEA_GENERATOR_H__
+
+#include "info.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/*
+ * high level
+ */
+
+struct _nmeaGENERATOR;
+
+enum nmeaGENTYPE
+{
+    NMEA_GEN_NOISE = 0,
+    NMEA_GEN_STATIC,
+    NMEA_GEN_ROTATE,
+
+    NMEA_GEN_SAT_STATIC,
+    NMEA_GEN_SAT_ROTATE,
+    NMEA_GEN_POS_RANDMOVE,
+
+    NMEA_GEN_LAST
+};
+
+struct _nmeaGENERATOR * nmea_create_generator(int type, nmeaINFO *info);
+void    nmea_destroy_generator(struct _nmeaGENERATOR *gen);
+
+int     nmea_generate_from(
+        char *buff, int buff_sz,    /* buffer */
+        nmeaINFO *info,             /* source info */
+        struct _nmeaGENERATOR *gen, /* generator */
+        int generate_mask           /* mask of sentence`s (e.g. GPGGA | GPGSA) */
+        );
+
+/*
+ * low level
+ */
+
+typedef int (*nmeaNMEA_GEN_INIT)(struct _nmeaGENERATOR *gen, nmeaINFO *info);
+typedef int (*nmeaNMEA_GEN_LOOP)(struct _nmeaGENERATOR *gen, nmeaINFO *info);
+typedef int (*nmeaNMEA_GEN_RESET)(struct _nmeaGENERATOR *gen, nmeaINFO *info);
+typedef int (*nmeaNMEA_GEN_DESTROY)(struct _nmeaGENERATOR *gen);
+
+typedef struct _nmeaGENERATOR
+{
+    void                *gen_data;
+    nmeaNMEA_GEN_INIT    init_call;
+    nmeaNMEA_GEN_LOOP    loop_call;
+    nmeaNMEA_GEN_RESET   reset_call;
+    nmeaNMEA_GEN_DESTROY destroy_call;
+    struct _nmeaGENERATOR *next;
+
+} nmeaGENERATOR;
+
+int     nmea_gen_init(nmeaGENERATOR *gen, nmeaINFO *info);
+int     nmea_gen_loop(nmeaGENERATOR *gen, nmeaINFO *info);
+int     nmea_gen_reset(nmeaGENERATOR *gen, nmeaINFO *info);
+void    nmea_gen_destroy(nmeaGENERATOR *gen);
+void    nmea_gen_add(nmeaGENERATOR *to, nmeaGENERATOR *gen);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* __NMEA_GENERATOR_H__ */

+ 92 - 0
air530z/nmealib/include/nmea/gmath.h

@@ -0,0 +1,92 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: gmath.h 17 2008-03-11 11:56:11Z xtimor $
+ *
+ */
+
+#ifndef __NMEA_GMATH_H__
+#define __NMEA_GMATH_H__
+
+#include "info.h"
+
+#define NMEA_PI                     (3.141592653589793)             /**< PI value */
+#define NMEA_PI180                  (NMEA_PI / 180)                 /**< PI division by 180 */
+#define NMEA_EARTHRADIUS_KM         (6378)                          /**< Earth's mean radius in km */
+#define NMEA_EARTHRADIUS_M          (NMEA_EARTHRADIUS_KM * 1000)    /**< Earth's mean radius in m */
+#define NMEA_EARTH_SEMIMAJORAXIS_M  (6378137.0)                     /**< Earth's semi-major axis in m according WGS84 */
+#define NMEA_EARTH_SEMIMAJORAXIS_KM (NMEA_EARTHMAJORAXIS_KM / 1000) /**< Earth's semi-major axis in km according WGS 84 */
+#define NMEA_EARTH_FLATTENING       (1 / 298.257223563)             /**< Earth's flattening according WGS 84 */
+#define NMEA_DOP_FACTOR             (5)                             /**< Factor for translating DOP to meters */
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/*
+ * degree VS radian
+ */
+
+double nmea_degree2radian(double val);
+double nmea_radian2degree(double val);
+
+/*
+ * NDEG (NMEA degree)
+ */
+
+double nmea_ndeg2degree(double val);
+double nmea_degree2ndeg(double val);
+
+double nmea_ndeg2radian(double val);
+double nmea_radian2ndeg(double val);
+
+/*
+ * DOP
+ */
+
+double nmea_calc_pdop(double hdop, double vdop);
+double nmea_dop2meters(double dop);
+double nmea_meters2dop(double meters);
+
+/*
+ * positions work
+ */
+
+void nmea_info2pos(const nmeaINFO *info, nmeaPOS *pos);
+void nmea_pos2info(const nmeaPOS *pos, nmeaINFO *info);
+
+double  nmea_distance(
+        const nmeaPOS *from_pos,
+        const nmeaPOS *to_pos
+        );
+
+double  nmea_distance_ellipsoid(
+        const nmeaPOS *from_pos,
+        const nmeaPOS *to_pos,
+        double *from_azimuth,
+        double *to_azimuth
+        );
+
+int     nmea_move_horz(
+        const nmeaPOS *start_pos,
+        nmeaPOS *end_pos,
+        double azimuth,
+        double distance
+        );
+
+int     nmea_move_horz_ellipsoid(
+        const nmeaPOS *start_pos,
+        nmeaPOS *end_pos,
+        double azimuth,
+        double distance,
+        double *end_azimuth
+        );
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* __NMEA_GMATH_H__ */

+ 119 - 0
air530z/nmealib/include/nmea/info.h

@@ -0,0 +1,119 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: info.h 10 2007-11-15 14:50:15Z xtimor $
+ *
+ */
+
+/*! \file */
+
+#ifndef __NMEA_INFO_H__
+#define __NMEA_INFO_H__
+
+#include "time.h"
+
+#define NMEA_SIG_BAD        (0)
+#define NMEA_SIG_LOW        (1)
+#define NMEA_SIG_MID        (2)
+#define NMEA_SIG_HIGH       (3)
+
+#define NMEA_FIX_BAD        (1)
+#define NMEA_FIX_2D         (2)
+#define NMEA_FIX_3D         (3)
+
+#define NMEA_MAXSAT         (12)
+#define NMEA_SATINPACK      (4)
+#define NMEA_NSATPACKS      (NMEA_MAXSAT / NMEA_SATINPACK)
+
+#define NMEA_DEF_LAT        (5001.2621)
+#define NMEA_DEF_LON        (3613.0595)
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+
+extern int bd_count;
+extern int gps_count;
+
+/**
+ * Position data in fractional degrees or radians
+ */
+typedef struct _nmeaPOS
+{
+    double lat;         /**< Latitude */
+    double lon;         /**< Longitude */
+
+} nmeaPOS;
+
+/**
+ * Information about satellite
+ * @see nmeaSATINFO
+ * @see nmeaGPGSV
+ */
+typedef struct _nmeaSATELLITE
+{
+    int     id;         /**< Satellite PRN number */
+    int     in_use;     /**< Used in position fix */
+    int     elv;        /**< Elevation in degrees, 90 maximum */
+    int     azimuth;    /**< Azimuth, degrees from true north, 000 to 359 */
+    int     sig;        /**< Signal, 00-99 dB */
+
+} nmeaSATELLITE;
+
+/**
+ * Information about all satellites in view
+ * @see nmeaINFO
+ * @see nmeaGPGSV
+ */
+typedef struct _nmeaSATINFO
+{
+    int     inuse;      /**< Number of satellites in use (not those in view) */
+    int     inview;     /**< Total number of satellites in view */
+    int     inview_gps;
+    int     inview_bd;
+    char    state;      /*G:GPS,B:BD*/
+    nmeaSATELLITE sat[NMEA_MAXSAT]; /**< Satellites information */
+
+} nmeaSATINFO;
+
+/**
+ * Summary GPS information from all parsed packets,
+ * used also for generating NMEA stream
+ * @see nmea_parse
+ * @see nmea_GPGGA2info,  nmea_...2info
+ */
+typedef struct _nmeaINFO
+{
+    int     smask;      /**< Mask specifying types of packages from which data have been obtained */
+
+    nmeaTIME utc;       /**< UTC of position */
+
+    int     sig;        /**< GPS quality indicator (0 = Invalid; 1 = Fix; 2 = Differential, 3 = Sensitive) */
+    int     fix;        /**< Operating mode, used for navigation (1 = Fix not available; 2 = 2D; 3 = 3D) */
+
+    double  PDOP;       /**< Position Dilution Of Precision */
+    double  HDOP;       /**< Horizontal Dilution Of Precision */
+    double  VDOP;       /**< Vertical Dilution Of Precision */
+
+    double  lat;        /**< Latitude in NDEG - +/-[degree][min].[sec/60] */
+    double  lon;        /**< Longitude in NDEG - +/-[degree][min].[sec/60] */
+    double  elv;        /**< Antenna altitude above/below mean sea level (geoid) in meters */
+    double  speed;      /**< Speed over the ground in kilometers/hour */
+    double  direction;  /**< Track angle in degrees True */
+    double  declination; /**< Magnetic variation degrees (Easterly var. subtracts from true course) */
+
+    nmeaSATINFO satinfo; /**< Satellites information */
+
+} nmeaINFO;
+
+void nmea_zero_INFO(nmeaINFO *info);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* __NMEA_INFO_H__ */

+ 25 - 0
air530z/nmealib/include/nmea/nmea.h

@@ -0,0 +1,25 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: nmea.h 17 2008-03-11 11:56:11Z xtimor $
+ *
+ */
+
+#ifndef __NMEA_H__
+#define __NMEA_H__
+
+#include "./config.h"
+#include "./units.h"
+#include "./gmath.h"
+#include "./info.h"
+#include "./sentence.h"
+#include "./generate.h"
+#include "./generator.h"
+#include "./parse.h"
+#include "./parser.h"
+#include "./context.h"
+
+#endif /* __NMEA_H__ */

+ 49 - 0
air530z/nmealib/include/nmea/parse.h

@@ -0,0 +1,49 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: parse.h 4 2007-08-27 13:11:03Z xtimor $
+ *
+ */
+
+#ifndef __NMEA_PARSE_H__
+#define __NMEA_PARSE_H__
+
+#include "sentence.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+int nmea_pack_type(const char *buff, int buff_sz);
+int nmea_find_tail(const char *buff, int buff_sz, int *res_crc);
+
+int nmea_parse_GPGGA(const char *buff, int buff_sz, nmeaGPGGA *pack);
+int nmea_parse_GPGSA(const char *buff, int buff_sz, nmeaGPGSA *pack);
+int nmea_parse_GPGSV(const char *buff, int buff_sz, nmeaGPGSV *pack);
+int nmea_parse_GPRMC(const char *buff, int buff_sz, nmeaGPRMC *pack);
+int nmea_parse_GPVTG(const char *buff, int buff_sz, nmeaGPVTG *pack);
+
+int nmea_parse_GNGGA(const char *buff, int buff_sz, nmeaGPGGA *pack);
+
+void nmea_GPGGA2info(nmeaGPGGA *pack, nmeaINFO *info);
+void nmea_GPGSA2info(nmeaGPGSA *pack, nmeaINFO *info);
+void nmea_GPGSV2info(nmeaGPGSV *pack, nmeaINFO *info);
+void nmea_GPRMC2info(nmeaGPRMC *pack, nmeaINFO *info);
+void nmea_GPVTG2info(nmeaGPVTG *pack, nmeaINFO *info);
+void nmea_BDGSV2info(nmeaGPGSV *pack, nmeaINFO *info);
+void nmea_GNGGA2info(nmeaGPGGA *pack, nmeaINFO *info);
+void nmea_GNGSA2info(nmeaGPGSA *pack, nmeaINFO *info);
+
+void nmea_GNRMC2info(nmeaGPRMC *pack, nmeaINFO *info);
+int nmea_parse_GNGSA(const char *buff, int buff_sz, nmeaGPGSA *pack);
+int nmea_parse_BDGSV(const char *buff, int buff_sz, nmeaGPGSV *pack);
+int nmea_parse_GNRMC(const char *buff, int buff_sz, nmeaGPRMC *pack);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* __NMEA_PARSE_H__ */

+ 59 - 0
air530z/nmealib/include/nmea/parser.h

@@ -0,0 +1,59 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: parser.h 4 2007-08-27 13:11:03Z xtimor $
+ *
+ */
+
+#ifndef __NMEA_PARSER_H__
+#define __NMEA_PARSER_H__
+
+#include "info.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/*
+ * high level
+ */
+
+typedef struct _nmeaPARSER
+{
+    void *top_node;
+    void *end_node;
+    unsigned char *buffer;
+    int buff_size;
+    int buff_use;
+
+} nmeaPARSER;
+
+int     nmea_parser_init(nmeaPARSER *parser);
+void    nmea_parser_destroy(nmeaPARSER *parser);
+
+int     nmea_parse(
+        nmeaPARSER *parser,
+        const char *buff, int buff_sz,
+        nmeaINFO *info
+        );
+
+/*
+ * low level
+ */
+
+int     nmea_parser_push(nmeaPARSER *parser, const char *buff, int buff_sz);
+int     nmea_parser_top(nmeaPARSER *parser);
+int     nmea_parser_pop(nmeaPARSER *parser, void **pack_ptr);
+int     nmea_parser_peek(nmeaPARSER *parser, void **pack_ptr);
+int     nmea_parser_drop(nmeaPARSER *parser);
+int     nmea_parser_buff_clear(nmeaPARSER *parser);
+int     nmea_parser_queue_clear(nmeaPARSER *parser);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* __NMEA_PARSER_H__ */

+ 133 - 0
air530z/nmealib/include/nmea/sentence.h

@@ -0,0 +1,133 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: sentence.h 17 2008-03-11 11:56:11Z xtimor $
+ *
+ */
+
+/*! \file */
+
+#ifndef __NMEA_SENTENCE_H__
+#define __NMEA_SENTENCE_H__
+
+#include "info.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/**
+ * NMEA packets type which parsed and generated by library
+ */
+enum nmeaPACKTYPE
+{
+    GPNON   = 0x0000,   /**< Unknown packet type. */
+    GPGGA   = 0x0001,   /**< GGA - Essential fix data which provide 3D location and accuracy data. */
+    GPGSA   = 0x0002,   /**< GSA - GPS receiver operating mode, SVs used for navigation, and DOP values. */
+    GPGSV   = 0x0004,   /**< GSV - Number of SVs in view, PRN numbers, elevation, azimuth & SNR values. */
+    GPRMC   = 0x0008,   /**< RMC - Recommended Minimum Specific GPS/TRANSIT Data. */
+    GPVTG   = 0x0010,    /**< VTG - Actual track made good and speed over ground. */
+    GNGGA   = 0x0011,   
+    GNGSA   = 0x0020,
+    GNRMC   = 0x0080,
+    BDGSV   = 0x0044   /**< GSV - Number of SVs in view, PRN numbers, elevation, azimuth & SNR values. */
+};
+
+/**
+ * GGA packet information structure (Global Positioning System Fix Data)
+ */
+typedef struct _nmeaGPGGA
+{
+    nmeaTIME utc;       /**< UTC of position (just time) */
+	double  lat;        /**< Latitude in NDEG - [degree][min].[sec/60] */
+    char    ns;         /**< [N]orth or [S]outh */
+	double  lon;        /**< Longitude in NDEG - [degree][min].[sec/60] */
+    char    ew;         /**< [E]ast or [W]est */
+    int     sig;        /**< GPS quality indicator (0 = Invalid; 1 = Fix; 2 = Differential, 3 = Sensitive) */
+	int     satinuse;   /**< Number of satellites in use (not those in view) */
+    double  HDOP;       /**< Horizontal dilution of precision */
+    double  elv;        /**< Antenna altitude above/below mean sea level (geoid) */
+    char    elv_units;  /**< [M]eters (Antenna height unit) */
+    double  diff;       /**< Geoidal separation (Diff. between WGS-84 earth ellipsoid and mean sea level. '-' = geoid is below WGS-84 ellipsoid) */
+    char    diff_units; /**< [M]eters (Units of geoidal separation) */
+    double  dgps_age;   /**< Time in seconds since last DGPS update */
+    int     dgps_sid;   /**< DGPS station ID number */
+
+} nmeaGPGGA;
+
+/**
+ * GSA packet information structure (Satellite status)
+ */
+typedef struct _nmeaGPGSA
+{
+    char    fix_mode;   /**< Mode (M = Manual, forced to operate in 2D or 3D; A = Automatic, 3D/2D) */
+    int     fix_type;   /**< Type, used for navigation (1 = Fix not available; 2 = 2D; 3 = 3D) */
+    int     sat_prn[NMEA_MAXSAT]; /**< PRNs of satellites used in position fix (null for unused fields) */
+    double  PDOP;       /**< Dilution of precision */
+    double  HDOP;       /**< Horizontal dilution of precision */
+    double  VDOP;       /**< Vertical dilution of precision */
+    int selectedSatellites;
+} nmeaGPGSA;
+
+/**
+ * GSV packet information structure (Satellites in view)
+ */
+typedef struct _nmeaGPGSV
+{
+    int     pack_count; /**< Total number of messages of this type in this cycle */
+    int     pack_index; /**< Message number */
+    int     sat_count;  /**< Total number of satellites in view */
+    nmeaSATELLITE sat_data[NMEA_SATINPACK];
+
+} nmeaGPGSV;
+
+
+/**
+ * RMC packet information structure (Recommended Minimum sentence C)
+ */
+typedef struct _nmeaGPRMC
+{
+    nmeaTIME utc;       /**< UTC of position */
+    char    status;     /**< Status (A = active or V = void) */
+	double  lat;        /**< Latitude in NDEG - [degree][min].[sec/60] */
+    char    ns;         /**< [N]orth or [S]outh */
+	double  lon;        /**< Longitude in NDEG - [degree][min].[sec/60] */
+    char    ew;         /**< [E]ast or [W]est */
+    double  speed;      /**< Speed over the ground in knots */
+    double  direction;  /**< Track angle in degrees True */
+    double  declination; /**< Magnetic variation degrees (Easterly var. subtracts from true course) */
+    char    declin_ew;  /**< [E]ast or [W]est */
+    char    mode;       /**< Mode indicator of fix type (A = autonomous, D = differential, E = estimated, N = not valid, S = simulator) */
+
+} nmeaGPRMC;
+
+/**
+ * VTG packet information structure (Track made good and ground speed)
+ */
+typedef struct _nmeaGPVTG
+{
+    double  dir;        /**< True track made good (degrees) */
+    char    dir_t;      /**< Fixed text 'T' indicates that track made good is relative to true north */
+    double  dec;        /**< Magnetic track made good */
+    char    dec_m;      /**< Fixed text 'M' */
+    double  spn;        /**< Ground speed, knots */
+    char    spn_n;      /**< Fixed text 'N' indicates that speed over ground is in knots */
+    double  spk;        /**< Ground speed, kilometers per hour */
+    char    spk_k;      /**< Fixed text 'K' indicates that speed over ground is in kilometers/hour */
+
+} nmeaGPVTG;
+
+void nmea_zero_GPGGA(nmeaGPGGA *pack);
+void nmea_zero_GPGSA(nmeaGPGSA *pack);
+void nmea_zero_GPGSV(nmeaGPGSV *pack);
+void nmea_zero_GPRMC(nmeaGPRMC *pack);
+void nmea_zero_GPVTG(nmeaGPVTG *pack);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* __NMEA_SENTENCE_H__ */

+ 47 - 0
air530z/nmealib/include/nmea/time.h

@@ -0,0 +1,47 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: time.h 4 2007-08-27 13:11:03Z xtimor $
+ *
+ */
+
+/*! \file */
+
+#ifndef __NMEA_TIME_H__
+#define __NMEA_TIME_H__
+
+#include "config.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Date and time data
+ * @see nmea_time_now
+ */
+typedef struct _nmeaTIME
+{
+    int     year;       /**< Years since 1900 */
+    int     mon;        /**< Months since January - [0,11] */
+    int     day;        /**< Day of the month - [1,31] */
+    int     hour;       /**< Hours since midnight - [0,23] */
+    int     min;        /**< Minutes after the hour - [0,59] */
+    int     sec;        /**< Seconds after the minute - [0,59] */
+    int     hsec;       /**< Hundredth part of second - [0,99] */
+
+} nmeaTIME;
+
+/**
+ * \brief Get time now to nmeaTIME structure
+ */
+void nmea_time_now(nmeaTIME *t);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* __NMEA_TIME_H__ */

+ 30 - 0
air530z/nmealib/include/nmea/tok.h

@@ -0,0 +1,30 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: tok.h 4 2007-08-27 13:11:03Z xtimor $
+ *
+ */
+
+#ifndef __NMEA_TOK_H__
+#define __NMEA_TOK_H__
+
+#include "config.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+int     nmea_calc_crc(const char *buff, int buff_sz);
+int     nmea_atoi(const char *str, int str_sz, int radix);
+double  nmea_atof(const char *str, int str_sz);
+int     nmea_printf(char *buff, int buff_sz, const char *format, ...);
+int     nmea_scanf(const char *buff, int buff_sz, const char *format, ...);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* __NMEA_TOK_H__ */

+ 30 - 0
air530z/nmealib/include/nmea/units.h

@@ -0,0 +1,30 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: units.h 4 2007-08-27 13:11:03Z xtimor $
+ *
+ */
+
+#ifndef __NMEA_UNITS_H__
+#define __NMEA_UNITS_H__
+
+#include "config.h"
+
+/*
+ * Distance units
+ */
+
+#define NMEA_TUD_YARDS      (1.0936)        /**< Yeards, meter * NMEA_TUD_YARDS = yard */
+#define NMEA_TUD_KNOTS      (1.852)         /**< Knots, kilometer / NMEA_TUD_KNOTS = knot */
+#define NMEA_TUD_MILES      (1.609)         /**< Miles, kilometer / NMEA_TUD_MILES = mile */
+
+/*
+ * Speed units
+ */
+
+#define NMEA_TUS_MS         (3.6)           /**< Meters per seconds, (k/h) / NMEA_TUS_MS= (m/s) */
+
+#endif /* __NMEA_UNITS_H__ */

+ 67 - 0
air530z/nmealib/src/context.c

@@ -0,0 +1,67 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: context.c 17 2008-03-11 11:56:11Z xtimor $
+ *
+ */
+
+#include "nmea/context.h"
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+nmeaPROPERTY * nmea_property()
+{
+    static nmeaPROPERTY prop = {
+        0, 0, NMEA_DEF_PARSEBUFF
+        };
+
+    return &prop;
+}
+
+void nmea_trace(const char *str, ...)
+{
+    int size;
+    va_list arg_list;
+    char buff[NMEA_DEF_PARSEBUFF];
+    nmeaTraceFunc func = nmea_property()->trace_func;
+
+    if(func)
+    {
+        va_start(arg_list, str);
+        size = NMEA_POSIX(vsnprintf)(&buff[0], NMEA_DEF_PARSEBUFF - 1, str, arg_list);
+        va_end(arg_list);
+
+        if(size > 0)
+            (*func)(&buff[0], size);
+    }
+}
+
+void nmea_trace_buff(const char *buff, int buff_size)
+{
+    nmeaTraceFunc func = nmea_property()->trace_func;
+    if(func && buff_size)
+        (*func)(buff, buff_size);
+}
+
+void nmea_error(const char *str, ...)
+{
+    int size;
+    va_list arg_list;
+    char buff[NMEA_DEF_PARSEBUFF];
+    nmeaErrorFunc func = nmea_property()->error_func;
+
+    if(func)
+    {
+        va_start(arg_list, str);
+        size = NMEA_POSIX(vsnprintf)(&buff[0], NMEA_DEF_PARSEBUFF - 1, str, arg_list);
+        va_end(arg_list);
+
+        if(size > 0)
+            (*func)(&buff[0], size);
+    }
+}

+ 229 - 0
air530z/nmealib/src/generate.c

@@ -0,0 +1,229 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: generate.c 17 2008-03-11 11:56:11Z xtimor $
+ *
+ */
+
+#include "nmea/tok.h"
+#include "nmea/sentence.h"
+#include "nmea/generate.h"
+#include "nmea/units.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+int nmea_gen_GPGGA(char *buff, int buff_sz, nmeaGPGGA *pack)
+{
+    return nmea_printf(buff, buff_sz,
+        "$GPGGA,%02d%02d%02d.%02d,%07.4f,%C,%07.4f,%C,%1d,%02d,%03.1f,%03.1f,%C,%03.1f,%C,%03.1f,%04d",
+        pack->utc.hour, pack->utc.min, pack->utc.sec, pack->utc.hsec,
+        pack->lat, pack->ns, pack->lon, pack->ew,
+        pack->sig, pack->satinuse, pack->HDOP, pack->elv, pack->elv_units,
+        pack->diff, pack->diff_units, pack->dgps_age, pack->dgps_sid);
+}
+
+int nmea_gen_GPGSA(char *buff, int buff_sz, nmeaGPGSA *pack)
+{
+    return nmea_printf(buff, buff_sz,
+        "$GPGSA,%C,%1d,%02d,%02d,%02d,%02d,%02d,%02d,%02d,%02d,%02d,%02d,%02d,%02d,%03.1f,%03.1f,%03.1f",
+        pack->fix_mode, pack->fix_type,
+        pack->sat_prn[0], pack->sat_prn[1], pack->sat_prn[2], pack->sat_prn[3], pack->sat_prn[4], pack->sat_prn[5],
+        pack->sat_prn[6], pack->sat_prn[7], pack->sat_prn[8], pack->sat_prn[9], pack->sat_prn[10], pack->sat_prn[11],
+        pack->PDOP, pack->HDOP, pack->VDOP);
+}
+
+int nmea_gen_GPGSV(char *buff, int buff_sz, nmeaGPGSV *pack)
+{
+    return nmea_printf(buff, buff_sz,
+        "$GPGSV,%1d,%1d,%02d,"
+        "%02d,%02d,%03d,%02d,"
+        "%02d,%02d,%03d,%02d,"
+        "%02d,%02d,%03d,%02d,"
+        "%02d,%02d,%03d,%02d",
+        pack->pack_count, pack->pack_index + 1, pack->sat_count,
+        pack->sat_data[0].id, pack->sat_data[0].elv, pack->sat_data[0].azimuth, pack->sat_data[0].sig,
+        pack->sat_data[1].id, pack->sat_data[1].elv, pack->sat_data[1].azimuth, pack->sat_data[1].sig,
+        pack->sat_data[2].id, pack->sat_data[2].elv, pack->sat_data[2].azimuth, pack->sat_data[2].sig,
+        pack->sat_data[3].id, pack->sat_data[3].elv, pack->sat_data[3].azimuth, pack->sat_data[3].sig);
+}
+
+int nmea_gen_GPRMC(char *buff, int buff_sz, nmeaGPRMC *pack)
+{
+    return nmea_printf(buff, buff_sz,
+        "$GPRMC,%02d%02d%02d.%02d,%C,%07.4f,%C,%07.4f,%C,%03.1f,%03.1f,%02d%02d%02d,%03.1f,%C,%C",
+        pack->utc.hour, pack->utc.min, pack->utc.sec, pack->utc.hsec,
+        pack->status, pack->lat, pack->ns, pack->lon, pack->ew,
+        pack->speed, pack->direction,
+        pack->utc.day, pack->utc.mon + 1, pack->utc.year - 100,
+        pack->declination, pack->declin_ew, pack->mode);
+}
+
+int nmea_gen_GPVTG(char *buff, int buff_sz, nmeaGPVTG *pack)
+{
+    return nmea_printf(buff, buff_sz,
+        "$GPVTG,%.1f,%C,%.1f,%C,%.1f,%C,%.1f,%C",
+        pack->dir, pack->dir_t,
+        pack->dec, pack->dec_m,
+        pack->spn, pack->spn_n,
+        pack->spk, pack->spk_k);
+}
+
+void nmea_info2GPGGA(const nmeaINFO *info, nmeaGPGGA *pack)
+{
+    nmea_zero_GPGGA(pack);
+
+    pack->utc = info->utc;
+    pack->lat = fabs(info->lat);
+    pack->ns = ((info->lat > 0)?'N':'S');
+    pack->lon = fabs(info->lon);
+    pack->ew = ((info->lon > 0)?'E':'W');
+    pack->sig = info->sig;
+    pack->satinuse = info->satinfo.inuse;
+    pack->HDOP = info->HDOP;
+    pack->elv = info->elv;
+}
+
+void nmea_info2GPGSA(const nmeaINFO *info, nmeaGPGSA *pack)
+{
+    int it;
+
+    nmea_zero_GPGSA(pack);
+
+    pack->fix_type = info->fix;
+    pack->PDOP = info->PDOP;
+    pack->HDOP = info->HDOP;
+    pack->VDOP = info->VDOP;
+
+    for(it = 0; it < NMEA_MAXSAT; ++it)
+    {
+        pack->sat_prn[it] =
+            ((info->satinfo.sat[it].in_use)?info->satinfo.sat[it].id:0);
+    }
+}
+
+int nmea_gsv_npack(int sat_count)
+{
+    int pack_count = (int)ceil(((double)sat_count) / NMEA_SATINPACK);
+
+    if(0 == pack_count)
+        pack_count = 1;
+
+    return pack_count;
+}
+
+void nmea_info2GPGSV(const nmeaINFO *info, nmeaGPGSV *pack, int pack_idx)
+{
+    int sit, pit;
+
+    nmea_zero_GPGSV(pack);
+
+    pack->sat_count = (info->satinfo.inview <= NMEA_MAXSAT)?info->satinfo.inview:NMEA_MAXSAT;
+    pack->pack_count = nmea_gsv_npack(pack->sat_count);
+
+    if(pack->pack_count == 0)
+        pack->pack_count = 1;
+
+    if(pack_idx >= pack->pack_count)
+        pack->pack_index = pack_idx % pack->pack_count;
+    else
+        pack->pack_index = pack_idx;
+
+    for(pit = 0, sit = pack->pack_index * NMEA_SATINPACK; pit < NMEA_SATINPACK; ++pit, ++sit)
+        pack->sat_data[pit] = info->satinfo.sat[sit];
+}
+
+void nmea_info2GPRMC(const nmeaINFO *info, nmeaGPRMC *pack)
+{
+    nmea_zero_GPRMC(pack);
+
+    pack->utc = info->utc;
+    pack->status = ((info->sig > 0)?'A':'V');
+    pack->lat = fabs(info->lat);
+    pack->ns = ((info->lat > 0)?'N':'S');
+    pack->lon = fabs(info->lon);
+    pack->ew = ((info->lon > 0)?'E':'W');
+    pack->speed = info->speed / NMEA_TUD_KNOTS;
+    pack->direction = info->direction;
+    pack->declination = info->declination;
+    pack->declin_ew = 'E';
+    pack->mode = ((info->sig > 0)?'A':'N');
+}
+
+void nmea_info2GPVTG(const nmeaINFO *info, nmeaGPVTG *pack)
+{
+    nmea_zero_GPVTG(pack);
+
+    pack->dir = info->direction;
+    pack->dec = info->declination;
+    pack->spn = info->speed / NMEA_TUD_KNOTS;
+    pack->spk = info->speed;
+}
+
+int nmea_generate(
+    char *buff, int buff_sz,
+    const nmeaINFO *info,
+    int generate_mask
+    )
+{
+    int gen_count = 0, gsv_it, gsv_count;
+    int pack_mask = generate_mask;
+
+    nmeaGPGGA gga;
+    nmeaGPGSA gsa;
+    nmeaGPGSV gsv;
+    nmeaGPRMC rmc;
+    nmeaGPVTG vtg;
+
+    if(!buff)
+        return 0;
+
+    while(pack_mask)
+    {
+        if(pack_mask & GPGGA)
+        {
+            nmea_info2GPGGA(info, &gga);
+            gen_count += nmea_gen_GPGGA(buff + gen_count, buff_sz - gen_count, &gga);
+            pack_mask &= ~GPGGA;
+        }
+        else if(pack_mask & GPGSA)
+        {
+            nmea_info2GPGSA(info, &gsa);
+            gen_count += nmea_gen_GPGSA(buff + gen_count, buff_sz - gen_count, &gsa);
+            pack_mask &= ~GPGSA;
+        }
+        else if(pack_mask & GPGSV)
+        {
+            gsv_count = nmea_gsv_npack(info->satinfo.inview);
+            for(gsv_it = 0; gsv_it < gsv_count && buff_sz - gen_count > 0; ++gsv_it)
+            {
+                nmea_info2GPGSV(info, &gsv, gsv_it);
+                gen_count += nmea_gen_GPGSV(buff + gen_count, buff_sz - gen_count, &gsv);
+            }
+            pack_mask &= ~GPGSV;
+        }
+        else if(pack_mask & GPRMC)
+        {
+            nmea_info2GPRMC(info, &rmc);
+            gen_count += nmea_gen_GPRMC(buff + gen_count, buff_sz - gen_count, &rmc);
+            pack_mask &= ~GPRMC;
+        }
+        else if(pack_mask & GPVTG)
+        {
+            nmea_info2GPVTG(info, &vtg);
+            gen_count += nmea_gen_GPVTG(buff + gen_count, buff_sz - gen_count, &vtg);
+            pack_mask &= ~GPVTG;
+        }
+        else
+            break;
+
+        if(buff_sz - gen_count <= 0)
+            break;
+    }
+
+    return gen_count;
+}

+ 399 - 0
air530z/nmealib/src/generator.c

@@ -0,0 +1,399 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: generator.c 17 2008-03-11 11:56:11Z xtimor $
+ *
+ */
+
+#include "nmea/gmath.h"
+#include "nmea/generate.h"
+#include "nmea/generator.h"
+#include "nmea/context.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#if defined(NMEA_WIN) && defined(_MSC_VER)
+# pragma warning(disable: 4100) /* unreferenced formal parameter */
+#endif
+
+double nmea_random(double min, double max)
+{
+    static double rand_max = RAND_MAX;
+    double rand_val = rand();
+    double bounds = max - min;
+    return min + (rand_val * bounds) / rand_max;
+}
+
+/*
+ * low level
+ */
+
+int nmea_gen_init(nmeaGENERATOR *gen, nmeaINFO *info)
+{
+    int RetVal = 1; int smask = info->smask;
+    nmeaGENERATOR *igen = gen;
+
+    nmea_zero_INFO(info);
+    info->smask = smask;
+
+    info->lat = NMEA_DEF_LAT;
+    info->lon = NMEA_DEF_LON;
+
+    while(RetVal && igen)
+    {
+        if(igen->init_call)
+            RetVal = (*igen->init_call)(igen, info);
+        igen = igen->next;
+    }
+
+    return RetVal;
+}
+
+int nmea_gen_loop(nmeaGENERATOR *gen, nmeaINFO *info)
+{
+    int RetVal = 1;
+
+    if(gen->loop_call)
+        RetVal = (*gen->loop_call)(gen, info);
+
+    if(RetVal && gen->next)
+        RetVal = nmea_gen_loop(gen->next, info);
+
+    return RetVal;
+}
+
+int nmea_gen_reset(nmeaGENERATOR *gen, nmeaINFO *info)
+{
+    int RetVal = 1;
+
+    if(gen->reset_call)
+        RetVal = (*gen->reset_call)(gen, info);
+
+    return RetVal;
+}
+
+void nmea_gen_destroy(nmeaGENERATOR *gen)
+{
+    if(gen->next)
+    {
+        nmea_gen_destroy(gen->next);
+        gen->next = 0;
+    }
+
+    if(gen->destroy_call)
+        (*gen->destroy_call)(gen);
+
+    free(gen);
+}
+
+void nmea_gen_add(nmeaGENERATOR *to, nmeaGENERATOR *gen)
+{
+    if(to->next)
+        nmea_gen_add(to->next, gen);
+    else
+        to->next = gen;
+}
+
+int nmea_generate_from(
+    char *buff, int buff_sz,
+    nmeaINFO *info,
+    nmeaGENERATOR *gen,
+    int generate_mask
+    )
+{
+    int retval;
+
+    if(0 != (retval = nmea_gen_loop(gen, info)))
+        retval = nmea_generate(buff, buff_sz, info, generate_mask);
+
+    return retval;
+}
+
+/*
+ * NOISE generator
+ */
+
+int nmea_igen_noise_init(nmeaGENERATOR *gen, nmeaINFO *info)
+{
+    return 1;
+}
+
+int nmea_igen_noise_loop(nmeaGENERATOR *gen, nmeaINFO *info)
+{
+    int it;
+    int in_use;
+
+    info->sig = (int)nmea_random(1, 3);
+    info->PDOP = nmea_random(0, 9);
+    info->HDOP = nmea_random(0, 9);
+    info->VDOP = nmea_random(0, 9);
+    info->fix = (int)nmea_random(2, 3);
+    info->lat = nmea_random(0, 100);
+    info->lon = nmea_random(0, 100);
+    info->speed = nmea_random(0, 100);
+    info->direction = nmea_random(0, 360);
+    info->declination = nmea_random(0, 360);
+    info->elv = (int)nmea_random(-100, 100);
+
+    info->satinfo.inuse = 0;
+    info->satinfo.inview = 0;
+
+    for(it = 0; it < 12; ++it)
+    {
+        info->satinfo.sat[it].id = it;
+        info->satinfo.sat[it].in_use = in_use = (int)nmea_random(0, 3);
+        info->satinfo.sat[it].elv = (int)nmea_random(0, 90);
+        info->satinfo.sat[it].azimuth = (int)nmea_random(0, 359);
+        info->satinfo.sat[it].sig = (int)(in_use?nmea_random(40, 99):nmea_random(0, 40));
+
+        if(in_use)
+            info->satinfo.inuse++;
+        if(info->satinfo.sat[it].sig > 0)
+            info->satinfo.inview++;
+    }
+
+    return 1;
+}
+
+int nmea_igen_noise_reset(nmeaGENERATOR *gen, nmeaINFO *info)
+{
+    return 1;
+}
+
+/*
+ * STATIC generator
+ */
+
+int nmea_igen_static_loop(nmeaGENERATOR *gen, nmeaINFO *info)
+{
+    nmea_time_now(&info->utc);
+    return 1;
+};
+
+int nmea_igen_static_reset(nmeaGENERATOR *gen, nmeaINFO *info)
+{
+    info->satinfo.inuse = 4;
+    info->satinfo.inview = 4;
+
+    info->satinfo.sat[0].id = 1;
+    info->satinfo.sat[0].in_use = 1;
+    info->satinfo.sat[0].elv = 50;
+    info->satinfo.sat[0].azimuth = 0;
+    info->satinfo.sat[0].sig = 99;
+
+    info->satinfo.sat[1].id = 2;
+    info->satinfo.sat[1].in_use = 1;
+    info->satinfo.sat[1].elv = 50;
+    info->satinfo.sat[1].azimuth = 90;
+    info->satinfo.sat[1].sig = 99;
+
+    info->satinfo.sat[2].id = 3;
+    info->satinfo.sat[2].in_use = 1;
+    info->satinfo.sat[2].elv = 50;
+    info->satinfo.sat[2].azimuth = 180;
+    info->satinfo.sat[2].sig = 99;
+
+    info->satinfo.sat[3].id = 4;
+    info->satinfo.sat[3].in_use = 1;
+    info->satinfo.sat[3].elv = 50;
+    info->satinfo.sat[3].azimuth = 270;
+    info->satinfo.sat[3].sig = 99;
+
+    return 1;
+}
+
+int nmea_igen_static_init(nmeaGENERATOR *gen, nmeaINFO *info)
+{
+    info->sig = 3;
+    info->fix = 3;
+
+    nmea_igen_static_reset(gen, info);
+
+    return 1;
+}
+
+/*
+ * SAT_ROTATE generator
+ */
+
+int nmea_igen_rotate_loop(nmeaGENERATOR *gen, nmeaINFO *info)
+{
+    int it;
+    int count = info->satinfo.inview;
+    double deg = 360 / (count?count:1);
+    double srt = (count?(info->satinfo.sat[0].azimuth):0) + 5;
+
+    nmea_time_now(&info->utc);
+
+    for(it = 0; it < count; ++it)
+    {
+        info->satinfo.sat[it].azimuth =
+            (int)((srt >= 360)?srt - 360:srt);
+        srt += deg;
+    }
+
+    return 1;
+};
+
+int nmea_igen_rotate_reset(nmeaGENERATOR *gen, nmeaINFO *info)
+{
+    int it;
+    double deg = 360 / 8;
+    double srt = 0;
+
+    info->satinfo.inuse = 8;
+    info->satinfo.inview = 8;
+
+    for(it = 0; it < info->satinfo.inview; ++it)
+    {
+        info->satinfo.sat[it].id = it + 1;
+        info->satinfo.sat[it].in_use = 1;
+        info->satinfo.sat[it].elv = 5;
+        info->satinfo.sat[it].azimuth = (int)srt;
+        info->satinfo.sat[it].sig = 80;
+        srt += deg;
+    }
+
+    return 1;
+}
+
+int nmea_igen_rotate_init(nmeaGENERATOR *gen, nmeaINFO *info)
+{
+    info->sig = 3;
+    info->fix = 3;
+
+    nmea_igen_rotate_reset(gen, info);
+
+    return 1;
+}
+
+/*
+ * POS_RANDMOVE generator
+ */
+
+int nmea_igen_pos_rmove_init(nmeaGENERATOR *gen, nmeaINFO *info)
+{    
+    info->sig = 3;
+    info->fix = 3;
+    info->direction = info->declination = 0;
+    info->speed = 20;
+    return 1;
+}
+
+int nmea_igen_pos_rmove_loop(nmeaGENERATOR *gen, nmeaINFO *info)
+{
+    nmeaPOS crd;
+
+    info->direction += nmea_random(-10, 10);
+    info->speed += nmea_random(-2, 3);
+
+    if(info->direction < 0)
+        info->direction = 359 + info->direction;
+    if(info->direction > 359)
+        info->direction -= 359;
+
+    if(info->speed > 40)
+        info->speed = 40;
+    if(info->speed < 1)
+        info->speed = 1;
+
+    nmea_info2pos(info, &crd);
+    nmea_move_horz(&crd, &crd, info->direction, info->speed / 3600);
+    nmea_pos2info(&crd, info);
+
+    info->declination = info->direction;
+
+    return 1;
+};
+
+int nmea_igen_pos_rmove_destroy(nmeaGENERATOR *gen)
+{
+    return 1;
+};
+
+/*
+ * generator create
+ */
+
+nmeaGENERATOR * __nmea_create_generator(int type, nmeaINFO *info)
+{
+    nmeaGENERATOR *gen = 0;
+
+    switch(type)
+    {
+    case NMEA_GEN_NOISE:
+        if(0 == (gen = malloc(sizeof(nmeaGENERATOR))))
+            nmea_error("Insufficient memory!");
+        else
+        {
+            memset(gen, 0, sizeof(nmeaGENERATOR));
+            gen->init_call = &nmea_igen_noise_init;
+            gen->loop_call = &nmea_igen_noise_loop;
+            gen->reset_call = &nmea_igen_noise_reset;
+        }
+        break;
+    case NMEA_GEN_STATIC:
+    case NMEA_GEN_SAT_STATIC:
+        if(0 == (gen = malloc(sizeof(nmeaGENERATOR))))
+            nmea_error("Insufficient memory!");
+        else
+        {
+            memset(gen, 0, sizeof(nmeaGENERATOR));
+            gen->init_call = &nmea_igen_static_init;
+            gen->loop_call = &nmea_igen_static_loop;
+            gen->reset_call = &nmea_igen_static_reset;
+        }
+        break;
+    case NMEA_GEN_SAT_ROTATE:
+        if(0 == (gen = malloc(sizeof(nmeaGENERATOR))))
+            nmea_error("Insufficient memory!");
+        else
+        {
+            memset(gen, 0, sizeof(nmeaGENERATOR));
+            gen->init_call = &nmea_igen_rotate_init;
+            gen->loop_call = &nmea_igen_rotate_loop;
+            gen->reset_call = &nmea_igen_rotate_reset;
+        }
+        break;
+    case NMEA_GEN_POS_RANDMOVE:
+        if(0 == (gen = malloc(sizeof(nmeaGENERATOR))))
+            nmea_error("Insufficient memory!");
+        else
+        {
+            memset(gen, 0, sizeof(nmeaGENERATOR));
+            gen->init_call = &nmea_igen_pos_rmove_init;
+            gen->loop_call = &nmea_igen_pos_rmove_loop;
+            gen->destroy_call = &nmea_igen_pos_rmove_destroy;
+        }
+        break;
+    case NMEA_GEN_ROTATE:
+        gen = __nmea_create_generator(NMEA_GEN_SAT_ROTATE, info);
+        nmea_gen_add(gen, __nmea_create_generator(NMEA_GEN_POS_RANDMOVE, info));
+        break;
+    };
+
+    return gen;
+}
+
+nmeaGENERATOR * nmea_create_generator(int type, nmeaINFO *info)
+{
+    nmeaGENERATOR *gen = __nmea_create_generator(type, info);
+
+    if(gen)
+        nmea_gen_init(gen, info);
+
+    return gen;
+}
+
+void nmea_destroy_generator(nmeaGENERATOR *gen)
+{
+    nmea_gen_destroy(gen);
+}
+
+#if defined(NMEA_WIN) && defined(_MSC_VER)
+# pragma warning(default: 4100)
+#endif

+ 377 - 0
air530z/nmealib/src/gmath.c

@@ -0,0 +1,377 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: gmath.c 17 2008-03-11 11:56:11Z xtimor $
+ *
+ */
+
+/*! \file gmath.h */
+
+#include "nmea/gmath.h"
+
+#include <math.h>
+#include <float.h>
+
+/**
+ * \fn nmea_degree2radian
+ * \brief Convert degree to radian
+ */
+double nmea_degree2radian(double val)
+{ return (val * NMEA_PI180); }
+
+/**
+ * \fn nmea_radian2degree
+ * \brief Convert radian to degree
+ */
+double nmea_radian2degree(double val)
+{ return (val / NMEA_PI180); }
+
+/**
+ * \brief Convert NDEG (NMEA degree) to fractional degree
+ */
+double nmea_ndeg2degree(double val)
+{
+    double deg = ((int)(val / 100));
+    val = deg + (val - deg * 100) / 60;
+    return val;
+}
+
+/**
+ * \brief Convert fractional degree to NDEG (NMEA degree)
+ */
+double nmea_degree2ndeg(double val)
+{
+    double int_part;
+    double fra_part;
+    fra_part = modf(val, &int_part);
+    val = int_part * 100 + fra_part * 60;
+    return val;
+}
+
+/**
+ * \fn nmea_ndeg2radian
+ * \brief Convert NDEG (NMEA degree) to radian
+ */
+double nmea_ndeg2radian(double val)
+{ return nmea_degree2radian(nmea_ndeg2degree(val)); }
+
+/**
+ * \fn nmea_radian2ndeg
+ * \brief Convert radian to NDEG (NMEA degree)
+ */
+double nmea_radian2ndeg(double val)
+{ return nmea_degree2ndeg(nmea_radian2degree(val)); }
+
+/**
+ * \brief Calculate PDOP (Position Dilution Of Precision) factor
+ */
+double nmea_calc_pdop(double hdop, double vdop)
+{
+    return sqrt(pow(hdop, 2) + pow(vdop, 2));
+}
+
+double nmea_dop2meters(double dop)
+{ return (dop * NMEA_DOP_FACTOR); }
+
+double nmea_meters2dop(double meters)
+{ return (meters / NMEA_DOP_FACTOR); }
+
+/**
+ * \brief Calculate distance between two points
+ * \return Distance in meters
+ */
+double nmea_distance(
+        const nmeaPOS *from_pos,    /**< From position in radians */
+        const nmeaPOS *to_pos       /**< To position in radians */
+        )
+{
+    double dist = ((double)NMEA_EARTHRADIUS_M) * acos(
+        sin(to_pos->lat) * sin(from_pos->lat) +
+        cos(to_pos->lat) * cos(from_pos->lat) * cos(to_pos->lon - from_pos->lon)
+        );
+    return dist;
+}
+
+/**
+ * \brief Calculate distance between two points
+ * This function uses an algorithm for an oblate spheroid earth model.
+ * The algorithm is described here: 
+ * http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
+ * \return Distance in meters
+ */
+double nmea_distance_ellipsoid(
+        const nmeaPOS *from_pos,    /**< From position in radians */
+        const nmeaPOS *to_pos,      /**< To position in radians */
+        double *from_azimuth,       /**< (O) azimuth at "from" position in radians */
+        double *to_azimuth          /**< (O) azimuth at "to" position in radians */
+        )
+{
+    /* All variables */
+    double f, a, b, sqr_a, sqr_b;
+    double L, phi1, phi2, U1, U2, sin_U1, sin_U2, cos_U1, cos_U2;
+    double sigma, sin_sigma, cos_sigma, cos_2_sigmam, sqr_cos_2_sigmam, sqr_cos_alpha, lambda, sin_lambda, cos_lambda, delta_lambda;
+    int remaining_steps; 
+    double sqr_u, A, B, delta_sigma;
+
+    /* Check input */
+    NMEA_ASSERT(from_pos != 0);
+    NMEA_ASSERT(to_pos != 0);
+
+    if ((from_pos->lat == to_pos->lat) && (from_pos->lon == to_pos->lon))
+    { /* Identical points */
+        if ( from_azimuth != 0 )
+            *from_azimuth = 0;
+        if ( to_azimuth != 0 )
+            *to_azimuth = 0;
+        return 0;    
+    } /* Identical points */
+
+    /* Earth geometry */
+    f = NMEA_EARTH_FLATTENING;
+    a = NMEA_EARTH_SEMIMAJORAXIS_M;
+    b = (1 - f) * a;
+    sqr_a = a * a;
+    sqr_b = b * b;
+
+    /* Calculation */
+    L = to_pos->lon - from_pos->lon;
+    phi1 = from_pos->lat;
+    phi2 = to_pos->lat;
+    U1 = atan((1 - f) * tan(phi1));
+    U2 = atan((1 - f) * tan(phi2));
+    sin_U1 = sin(U1);
+    sin_U2 = sin(U2);
+    cos_U1 = cos(U1);
+    cos_U2 = cos(U2);
+
+    /* Initialize iteration */
+    sigma = 0;
+    sin_sigma = sin(sigma);
+    cos_sigma = cos(sigma);
+    cos_2_sigmam = 0;
+    sqr_cos_2_sigmam = cos_2_sigmam * cos_2_sigmam;
+    sqr_cos_alpha = 0;
+    lambda = L;
+    sin_lambda = sin(lambda);                            
+    cos_lambda = cos(lambda);                       
+    delta_lambda = lambda;
+    remaining_steps = 20; 
+
+    while ((delta_lambda > 1e-12) && (remaining_steps > 0)) 
+    { /* Iterate */
+        /* Variables */
+        double tmp1, tmp2, tan_sigma, sin_alpha, cos_alpha, C, lambda_prev; 
+
+        /* Calculation */
+        tmp1 = cos_U2 * sin_lambda;
+        tmp2 = cos_U1 * sin_U2 - sin_U1 * cos_U2 * cos_lambda;  
+        sin_sigma = sqrt(tmp1 * tmp1 + tmp2 * tmp2);                
+        cos_sigma = sin_U1 * sin_U2 + cos_U1 * cos_U2 * cos_lambda;   
+        tan_sigma = sin_sigma / cos_sigma;                  
+        sin_alpha = cos_U1 * cos_U2 * sin_lambda / sin_sigma;  
+        cos_alpha = cos(asin(sin_alpha));                 
+        sqr_cos_alpha = cos_alpha * cos_alpha;                     
+        cos_2_sigmam = cos_sigma - 2 * sin_U1 * sin_U2 / sqr_cos_alpha;
+        sqr_cos_2_sigmam = cos_2_sigmam * cos_2_sigmam; 
+        C = f / 16 * sqr_cos_alpha * (4 + f * (4 - 3 * sqr_cos_alpha));
+        lambda_prev = lambda; 
+        sigma = asin(sin_sigma); 
+        lambda = L + 
+            (1 - C) * f * sin_alpha
+            * (sigma + C * sin_sigma * (cos_2_sigmam + C * cos_sigma * (-1 + 2 * sqr_cos_2_sigmam)));                                                
+        delta_lambda = lambda_prev - lambda; 
+        if ( delta_lambda < 0 ) delta_lambda = -delta_lambda; 
+        sin_lambda = sin(lambda);
+        cos_lambda = cos(lambda);
+        remaining_steps--; 
+    }  /* Iterate */
+
+    /* More calculation  */
+    sqr_u = sqr_cos_alpha * (sqr_a - sqr_b) / sqr_b; 
+    A = 1 + sqr_u / 16384 * (4096 + sqr_u * (-768 + sqr_u * (320 - 175 * sqr_u)));
+    B = sqr_u / 1024 * (256 + sqr_u * (-128 + sqr_u * (74 - 47 * sqr_u)));
+    delta_sigma = B * sin_sigma * ( 
+        cos_2_sigmam + B / 4 * ( 
+        cos_sigma * (-1 + 2 * sqr_cos_2_sigmam) -
+        B / 6 * cos_2_sigmam * (-3 + 4 * sin_sigma * sin_sigma) * (-3 + 4 * sqr_cos_2_sigmam)
+        ));
+
+    /* Calculate result */
+    if ( from_azimuth != 0 )
+    {
+        double tan_alpha_1 = cos_U2 * sin_lambda / (cos_U1 * sin_U2 - sin_U1 * cos_U2 * cos_lambda);
+        *from_azimuth = atan(tan_alpha_1);
+    }
+    if ( to_azimuth != 0 )
+    {
+        double tan_alpha_2 = cos_U1 * sin_lambda / (-sin_U1 * cos_U2 + cos_U1 * sin_U2 * cos_lambda);
+        *to_azimuth = atan(tan_alpha_2);
+    }
+
+    return b * A * (sigma - delta_sigma);
+}
+
+/**
+ * \brief Horizontal move of point position
+ */
+int nmea_move_horz(
+    const nmeaPOS *start_pos,   /**< Start position in radians */
+    nmeaPOS *end_pos,           /**< Result position in radians */
+    double azimuth,             /**< Azimuth (degree) [0, 359] */
+    double distance             /**< Distance (km) */
+    )
+{
+    nmeaPOS p1 = *start_pos;
+    int RetVal = 1;
+
+    distance /= NMEA_EARTHRADIUS_KM; /* Angular distance covered on earth's surface */
+    azimuth = nmea_degree2radian(azimuth);
+
+    end_pos->lat = asin(
+        sin(p1.lat) * cos(distance) + cos(p1.lat) * sin(distance) * cos(azimuth));
+    end_pos->lon = p1.lon + atan2(
+        sin(azimuth) * sin(distance) * cos(p1.lat), cos(distance) - sin(p1.lat) * sin(end_pos->lat));
+
+    if(NMEA_POSIX(isnan)(end_pos->lat) || NMEA_POSIX(isnan)(end_pos->lon))
+    {
+        end_pos->lat = 0; end_pos->lon = 0;
+        RetVal = 0;
+    }
+
+    return RetVal;
+}
+
+/**
+ * \brief Horizontal move of point position
+ * This function uses an algorithm for an oblate spheroid earth model.
+ * The algorithm is described here: 
+ * http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
+ */
+int nmea_move_horz_ellipsoid(
+    const nmeaPOS *start_pos,   /**< Start position in radians */
+    nmeaPOS *end_pos,           /**< (O) Result position in radians */
+    double azimuth,             /**< Azimuth in radians */
+    double distance,            /**< Distance (km) */
+    double *end_azimuth         /**< (O) Azimuth at end position in radians */
+    )
+{
+    /* Variables */
+    double f, a, b, sqr_a, sqr_b;
+    double phi1, tan_U1, sin_U1, cos_U1, s, alpha1, sin_alpha1, cos_alpha1;
+    double tan_sigma1, sigma1, sin_alpha, cos_alpha, sqr_cos_alpha, sqr_u, A, B;
+    double sigma_initial, sigma, sigma_prev, sin_sigma, cos_sigma, cos_2_sigmam, sqr_cos_2_sigmam, delta_sigma;
+    int remaining_steps;
+    double tmp1, phi2, lambda, C, L;
+    
+    /* Check input */
+    NMEA_ASSERT(start_pos != 0);
+    NMEA_ASSERT(end_pos != 0);
+    
+    if (fabs(distance) < 1e-12)
+    { /* No move */
+        *end_pos = *start_pos;
+        if ( end_azimuth != 0 ) *end_azimuth = azimuth;
+        return ! (NMEA_POSIX(isnan)(end_pos->lat) || NMEA_POSIX(isnan)(end_pos->lon));
+    } /* No move */
+
+    /* Earth geometry */
+    f = NMEA_EARTH_FLATTENING;
+    a = NMEA_EARTH_SEMIMAJORAXIS_M;
+    b = (1 - f) * a;
+    sqr_a = a * a;
+    sqr_b = b * b;
+    
+    /* Calculation */
+    phi1 = start_pos->lat;
+    tan_U1 = (1 - f) * tan(phi1);
+    cos_U1 = 1 / sqrt(1 + tan_U1 * tan_U1);
+    sin_U1 = tan_U1 * cos_U1;
+    s = distance;
+    alpha1 = azimuth;
+    sin_alpha1 = sin(alpha1);
+    cos_alpha1 = cos(alpha1);
+    tan_sigma1 = tan_U1 / cos_alpha1;
+    sigma1 = atan2(tan_U1, cos_alpha1);
+    sin_alpha = cos_U1 * sin_alpha1;
+    sqr_cos_alpha = 1 - sin_alpha * sin_alpha;
+    cos_alpha = sqrt(sqr_cos_alpha);
+    sqr_u = sqr_cos_alpha * (sqr_a - sqr_b) / sqr_b; 
+    A = 1 + sqr_u / 16384 * (4096 + sqr_u * (-768 + sqr_u * (320 - 175 * sqr_u)));
+    B = sqr_u / 1024 * (256 + sqr_u * (-128 + sqr_u * (74 - 47 * sqr_u)));
+    
+    /* Initialize iteration */
+    sigma_initial = s / (b * A);
+    sigma = sigma_initial;
+    sin_sigma = sin(sigma);
+    cos_sigma = cos(sigma);
+    cos_2_sigmam = cos(2 * sigma1 + sigma);
+    sqr_cos_2_sigmam = cos_2_sigmam * cos_2_sigmam;
+    delta_sigma = 0;
+    sigma_prev = 2 * NMEA_PI;
+    remaining_steps = 20;
+
+    while ((fabs(sigma - sigma_prev) > 1e-12) && (remaining_steps > 0))
+    { /* Iterate */
+        cos_2_sigmam = cos(2 * sigma1 + sigma);
+        sqr_cos_2_sigmam = cos_2_sigmam * cos_2_sigmam;
+        sin_sigma = sin(sigma);
+        cos_sigma = cos(sigma);
+        delta_sigma = B * sin_sigma * ( 
+             cos_2_sigmam + B / 4 * ( 
+             cos_sigma * (-1 + 2 * sqr_cos_2_sigmam) - 
+             B / 6 * cos_2_sigmam * (-3 + 4 * sin_sigma * sin_sigma) * (-3 + 4 * sqr_cos_2_sigmam)
+             ));
+        sigma_prev = sigma;
+        sigma = sigma_initial + delta_sigma;
+        remaining_steps --;
+    } /* Iterate */
+    
+    /* Calculate result */
+    tmp1 = (sin_U1 * sin_sigma - cos_U1 * cos_sigma * cos_alpha1);
+    phi2 = atan2(
+            sin_U1 * cos_sigma + cos_U1 * sin_sigma * cos_alpha1,
+            (1 - f) * sqrt(sin_alpha * sin_alpha + tmp1 * tmp1)
+            );
+    lambda = atan2(
+            sin_sigma * sin_alpha1,
+            cos_U1 * cos_sigma - sin_U1 * sin_sigma * cos_alpha1
+            );
+    C = f / 16 * sqr_cos_alpha * (4 + f * (4 - 3 * sqr_cos_alpha));
+    L = lambda -
+        (1 - C) * f * sin_alpha * (
+        sigma + C * sin_sigma *
+        (cos_2_sigmam + C * cos_sigma * (-1 + 2 * sqr_cos_2_sigmam))
+        );
+    
+    /* Result */
+    end_pos->lon = start_pos->lon + L;
+    end_pos->lat = phi2;
+    if ( end_azimuth != 0 )
+    {
+        *end_azimuth = atan2(
+            sin_alpha, -sin_U1 * sin_sigma + cos_U1 * cos_sigma * cos_alpha1
+            );
+    }
+    return ! (NMEA_POSIX(isnan)(end_pos->lat) || NMEA_POSIX(isnan)(end_pos->lon));
+}
+
+/**
+ * \brief Convert position from INFO to radians position
+ */
+void nmea_info2pos(const nmeaINFO *info, nmeaPOS *pos)
+{
+    pos->lat = nmea_ndeg2radian(info->lat);
+    pos->lon = nmea_ndeg2radian(info->lon);
+}
+
+/**
+ * \brief Convert radians position to INFOs position
+ */
+void nmea_pos2info(const nmeaPOS *pos, nmeaINFO *info)
+{
+    info->lat = nmea_radian2ndeg(pos->lat);
+    info->lon = nmea_radian2ndeg(pos->lon);
+}

+ 24 - 0
air530z/nmealib/src/info.c

@@ -0,0 +1,24 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: info.c 17 2008-03-11 11:56:11Z xtimor $
+ *
+ */
+
+#include <string.h>
+
+#include "nmea/info.h"
+
+int bd_count;
+int gps_count;
+
+void nmea_zero_INFO(nmeaINFO *info)
+{
+    memset(info, 0, sizeof(nmeaINFO));
+    nmea_time_now(&info->utc);
+    info->sig = NMEA_SIG_BAD;
+    info->fix = NMEA_FIX_BAD;
+}

+ 739 - 0
air530z/nmealib/src/parse.c

@@ -0,0 +1,739 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: parse.c 17 2008-03-11 11:56:11Z xtimor $
+ *
+ */
+
+/**
+ * \file parse.h
+ * \brief Functions of a low level for analysis of
+ * packages of NMEA stream.
+ *
+ * \code
+ * ...
+ * ptype = nmea_pack_type(
+ *     (const char *)parser->buffer + nparsed + 1,
+ *     parser->buff_use - nparsed - 1);
+ * 
+ * if(0 == (node = malloc(sizeof(nmeaParserNODE))))
+ *     goto mem_fail;
+ * 
+ * node->pack = 0;
+ * 
+ * switch(ptype)
+ * {
+ * case GPGGA:
+ *     if(0 == (node->pack = malloc(sizeof(nmeaGPGGA))))
+ *         goto mem_fail;
+ *     node->packType = GPGGA;
+ *     if(!nmea_parse_GPGGA(
+ *         (const char *)parser->buffer + nparsed,
+ *         sen_sz, (nmeaGPGGA *)node->pack))
+ *     {
+ *         free(node);
+ *         node = 0;
+ *     }
+ *     break;
+ * case GPGSA:
+ *     if(0 == (node->pack = malloc(sizeof(nmeaGPGSA))))
+ *         goto mem_fail;
+ *     node->packType = GPGSA;
+ *     if(!nmea_parse_GPGSA(
+ *         (const char *)parser->buffer + nparsed,
+ *         sen_sz, (nmeaGPGSA *)node->pack))
+ *     {
+ *         free(node);
+ *         node = 0;
+ *     }
+ *     break;
+ * ...
+ * \endcode
+ */
+
+#include "nmea/tok.h"
+#include "nmea/parse.h"
+#include "nmea/context.h"
+#include "nmea/gmath.h"
+#include "nmea/units.h"
+
+#include <string.h>
+#include <stdio.h>
+
+int _nmea_parse_time(const char *buff, int buff_sz, nmeaTIME *res)
+{
+    int success = 0;
+
+    switch(buff_sz)
+    {
+    case sizeof("hhmmss") - 1:
+        success = (3 == nmea_scanf(buff, buff_sz,
+            "%2d%2d%2d", &(res->hour), &(res->min), &(res->sec)
+            ));
+        break;
+    case sizeof("hhmmss.s") - 1:
+    case sizeof("hhmmss.ss") - 1:
+    case sizeof("hhmmss.sss") - 1:
+        success = (4 == nmea_scanf(buff, buff_sz,
+            "%2d%2d%2d.%d", &(res->hour), &(res->min), &(res->sec), &(res->hsec)
+            ));
+        break;
+    default:
+        nmea_error("Parse of time error (format error)!");
+        success = 0;
+        break;
+    }
+
+    return (success?0:-1);        
+}
+
+/**
+ * \brief Define packet type by header (nmeaPACKTYPE).
+ * @param buff a constant character pointer of packet buffer.
+ * @param buff_sz buffer size.
+ * @return The defined packet type
+ * @see nmeaPACKTYPE
+ */
+int nmea_pack_type(const char *buff, int buff_sz)
+{
+    static const char *pheads[] = {
+        "GPGGA",
+        "GPGSA",
+        "GPGSV",
+        "GPRMC",
+        "GPVTG",
+        "GNGGA",
+        "GNGSA",
+        "BDGSV",
+        "GNRMC"
+    };
+
+    NMEA_ASSERT(buff);
+
+    if(buff_sz < 5)
+        return GPNON;
+    else if(0 == memcmp(buff, pheads[0], 5))
+        return GPGGA;
+    else if(0 == memcmp(buff, pheads[1], 5))
+        return GPGSA;
+    else if(0 == memcmp(buff, pheads[2], 5))
+        return GPGSV;
+    else if(0 == memcmp(buff, pheads[3], 5))
+        return GPRMC;
+    else if(0 == memcmp(buff, pheads[4], 5))
+        return GPVTG;
+    else if(0 == memcmp(buff, pheads[5], 5))
+        return GNGGA;
+    else if(0 == memcmp(buff, pheads[6], 5))
+        return GNGSA;
+    else if(0 == memcmp(buff, pheads[7], 5))
+        return BDGSV;
+    else if(0 == memcmp(buff, pheads[8], 5))
+        return GNRMC;
+    return GPNON;
+}
+
+/**
+ * \brief Find tail of packet ("\r\n") in buffer and check control sum (CRC).
+ * @param buff a constant character pointer of packets buffer.
+ * @param buff_sz buffer size.
+ * @param res_crc a integer pointer for return CRC of packet (must be defined).
+ * @return Number of bytes to packet tail.
+ */
+int nmea_find_tail(const char *buff, int buff_sz, int *res_crc)
+{
+    static const int tail_sz = 3 /* *[CRC] */ + 1 /* \n */;
+
+    const char *end_buff = buff + buff_sz;
+    int nread = 0;
+    int crc = 0;
+
+    NMEA_ASSERT(buff && res_crc);
+
+    *res_crc = -1;
+
+    for(;buff < end_buff; ++buff, ++nread)
+    {
+        if(('$' == *buff) && nread)
+        {
+            buff = 0;
+            break;
+        }
+        else if('*' == *buff)
+        {
+            if(buff + tail_sz <= end_buff && ('\n' == buff[3] || ('\r' == buff[3] && '\n' == buff[4])))
+            {
+                *res_crc = nmea_atoi(buff + 1, 2, 16);
+                nread = buff_sz - (int)(end_buff - (buff + tail_sz));
+                if(*res_crc != crc)
+                {
+                    *res_crc = -1;
+                    buff = 0;
+                }
+            }
+
+            break;
+        }
+        else if(nread)
+            crc ^= (int)*buff;
+    }
+
+    if(*res_crc < 0 && buff)
+        nread = 0;
+
+    return nread;
+}
+
+/**
+ * \brief Parse GGA packet from buffer.
+ * @param buff a constant character pointer of packet buffer.
+ * @param buff_sz buffer size.
+ * @param pack a pointer of packet which will filled by function.
+ * @return 1 (true) - if parsed successfully or 0 (false) - if fail.
+ */
+int nmea_parse_GPGGA(const char *buff, int buff_sz, nmeaGPGGA *pack)
+{
+    char time_buff[NMEA_TIMEPARSE_BUF];
+
+    NMEA_ASSERT(buff && pack);
+
+    memset(pack, 0, sizeof(nmeaGPGGA));
+
+    nmea_trace_buff(buff, buff_sz);
+
+    if(14 != nmea_scanf(buff, buff_sz,
+        "$GPGGA,%s,%f,%C,%f,%C,%d,%d,%f,%f,%C,%f,%C,%f,%d*",
+        &(time_buff[0]),
+        &(pack->lat), &(pack->ns), &(pack->lon), &(pack->ew),
+        &(pack->sig), &(pack->satinuse), &(pack->HDOP), &(pack->elv), &(pack->elv_units),
+        &(pack->diff), &(pack->diff_units), &(pack->dgps_age), &(pack->dgps_sid)))
+    {
+        nmea_error("GPGGA parse error!");
+        return 0;
+    }
+
+    if(0 != _nmea_parse_time(&time_buff[0], (int)strlen(&time_buff[0]), &(pack->utc)))
+    {
+        nmea_error("GPGGA time parse error!");
+        return 0;
+    }
+
+    return 1;
+}
+int nmea_parse_GNGGA(const char *buff, int buff_sz, nmeaGPGGA *pack)
+{
+    char time_buff[NMEA_TIMEPARSE_BUF];
+
+    NMEA_ASSERT(buff && pack);
+
+    memset(pack, 0, sizeof(nmeaGPGGA));
+
+    nmea_trace_buff(buff, buff_sz);
+
+    if(14 != nmea_scanf(buff, buff_sz,
+        "$GNGGA,%s,%f,%C,%f,%C,%d,%d,%f,%f,%C,%f,%C,%f,%d*",
+        &(time_buff[0]),
+        &(pack->lat), &(pack->ns), &(pack->lon), &(pack->ew),
+        &(pack->sig), &(pack->satinuse), &(pack->HDOP), &(pack->elv), &(pack->elv_units),
+        &(pack->diff), &(pack->diff_units), &(pack->dgps_age), &(pack->dgps_sid)))
+    {
+        nmea_error("GNGGA parse error!");
+        return 0;
+    }
+
+    if(0 != _nmea_parse_time(&time_buff[0], (int)strlen(&time_buff[0]), &(pack->utc)))
+    {
+        nmea_error("GNGGA time parse error!");
+        return 0;
+    }
+
+    return 1;
+}
+/**
+ * \brief Parse GSA packet from buffer.
+ * @param buff a constant character pointer of packet buffer.
+ * @param buff_sz buffer size.
+ * @param pack a pointer of packet which will filled by function.
+ * @return 1 (true) - if parsed successfully or 0 (false) - if fail.
+ */
+int nmea_parse_GPGSA(const char *buff, int buff_sz, nmeaGPGSA *pack)
+{
+    NMEA_ASSERT(buff && pack);
+
+    memset(pack, 0, sizeof(nmeaGPGSA));
+
+    nmea_trace_buff(buff, buff_sz);
+
+    if(17 != nmea_scanf(buff, buff_sz,
+        "$GPGSA,%C,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%f,%f,%f*",
+        &(pack->fix_mode), &(pack->fix_type),
+        &(pack->sat_prn[0]), &(pack->sat_prn[1]), &(pack->sat_prn[2]), &(pack->sat_prn[3]), &(pack->sat_prn[4]), &(pack->sat_prn[5]),
+        &(pack->sat_prn[6]), &(pack->sat_prn[7]), &(pack->sat_prn[8]), &(pack->sat_prn[9]), &(pack->sat_prn[10]), &(pack->sat_prn[11]),
+        &(pack->PDOP), &(pack->HDOP), &(pack->VDOP)))
+    {
+        nmea_error("GPGSA parse error!");
+        return 0;
+    }
+
+    return 1;
+}
+int nmea_parse_GNGSA(const char *buff, int buff_sz, nmeaGPGSA *pack)
+{
+    
+    NMEA_ASSERT(buff && pack);
+
+    memset(pack, 0, sizeof(nmeaGPGSA));
+
+    nmea_trace_buff(buff, buff_sz);
+    int scanf_res = nmea_scanf(buff, buff_sz,
+        "$GNGSA,%C,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%f,%f,%f,%d*%*X",
+        &(pack->fix_mode), &(pack->fix_type),
+        &(pack->sat_prn[0]), &(pack->sat_prn[1]), &(pack->sat_prn[2]), &(pack->sat_prn[3]), &(pack->sat_prn[4]), &(pack->sat_prn[5]),
+        &(pack->sat_prn[6]), &(pack->sat_prn[7]), &(pack->sat_prn[8]), &(pack->sat_prn[9]), &(pack->sat_prn[10]), &(pack->sat_prn[11]),
+        &(pack->PDOP), &(pack->HDOP), &(pack->VDOP),
+        &(pack->selectedSatellites));
+    //printf("\n解析到:nmea_parse_GNGSA:%d-%d\n",scanf_res,buff_sz);
+    //printf("\n解析到:nmea_parse_GNGSA:%C\n",pack->fix_mode);
+    if(19 != scanf_res)
+    {
+        //printf("\nGNGSA parse error\n");
+        nmea_error("GPGSA parse error!");
+        return 0;
+    }
+
+    return 1;
+}
+/**
+ * \brief Parse GSV packet from buffer.
+ * @param buff a constant character pointer of packet buffer.
+ * @param buff_sz buffer size.
+ * @param pack a pointer of packet which will filled by function.
+ * @return 1 (true) - if parsed successfully or 0 (false) - if fail.
+ */
+//$GPGSV,3,1,09,10,46,320,39,12,20,121,26,15,28,069,22,18,39,201,26,0*64
+//$GPGSV,3,2,09,23,80,028,,24,56,053,,25,10,161,,32,25,274,28,0*60
+//$GPGSV,3,3,09,194,24,133,,0*67
+int nmea_parse_GPGSV(const char *buff, int buff_sz, nmeaGPGSV *pack)
+{
+    int nsen, nsat;
+
+    NMEA_ASSERT(buff && pack);
+
+    memset(pack, 0, sizeof(nmeaGPGSV));
+
+    nmea_trace_buff(buff, buff_sz);
+
+    nsen = nmea_scanf(buff, buff_sz,
+        "$GPGSV,%d,%d,%d,"
+        "%d,%d,%d,%d,"
+        "%d,%d,%d,%d,"
+        "%d,%d,%d,%d,"
+        "%d,%d,%d,%d*",
+        &(pack->pack_count), &(pack->pack_index), &(pack->sat_count),
+        &(pack->sat_data[0].id), &(pack->sat_data[0].elv), &(pack->sat_data[0].azimuth), &(pack->sat_data[0].sig),
+        &(pack->sat_data[1].id), &(pack->sat_data[1].elv), &(pack->sat_data[1].azimuth), &(pack->sat_data[1].sig),
+        &(pack->sat_data[2].id), &(pack->sat_data[2].elv), &(pack->sat_data[2].azimuth), &(pack->sat_data[2].sig),
+        &(pack->sat_data[3].id), &(pack->sat_data[3].elv), &(pack->sat_data[3].azimuth), &(pack->sat_data[3].sig));
+
+    nsat = (pack->pack_index - 1) * NMEA_SATINPACK;
+    nsat = (nsat + NMEA_SATINPACK > pack->sat_count)?pack->sat_count - nsat:NMEA_SATINPACK;
+    nsat = nsat * 4 + 3 /* first three sentence`s */;
+    //printf("nmea_parse_GPGSV:%d-%d",nsen,nsat);
+    if(nsen < nsat || nsen > (NMEA_SATINPACK * 4 + 3))
+    {
+        //printf("nmea_parse_GPGSV ERR:%d-%d",nsen,nsat);
+        nmea_error("GPGSV parse error!");
+        return 0;
+    }
+
+    return 1;
+}
+//$BDGSV,3,1,12,06,67,235,24,09,54,229,27,16,75,242,17,20,17,298,33,0*74
+//$BDGSV,3,2,12,25,30,052,21,27,09,205,23,29,09,306,31,30,19,253,23,0*77
+//$BDGSV,3,3,12,32,62,345,22,37,28,182,15,39,81,277,30,41,41,083,26,0*7C
+int nmea_parse_BDGSV(const char *buff, int buff_sz, nmeaGPGSV *pack)
+{
+    int nsen, nsat;
+
+    NMEA_ASSERT(buff && pack);
+
+    memset(pack, 0, sizeof(nmeaGPGSV));
+
+    nmea_trace_buff(buff, buff_sz);
+
+    nsen = nmea_scanf(buff, buff_sz,
+        "$BDGSV,%d,%d,%d,"
+        "%d,%d,%d,%d,"
+        "%d,%d,%d,%d,"
+        "%d,%d,%d,%d,"
+        "%d,%d,%d,%d*",
+        &(pack->pack_count), &(pack->pack_index), &(pack->sat_count),
+        &(pack->sat_data[0].id), &(pack->sat_data[0].elv), &(pack->sat_data[0].azimuth), &(pack->sat_data[0].sig),
+        &(pack->sat_data[1].id), &(pack->sat_data[1].elv), &(pack->sat_data[1].azimuth), &(pack->sat_data[1].sig),
+        &(pack->sat_data[2].id), &(pack->sat_data[2].elv), &(pack->sat_data[2].azimuth), &(pack->sat_data[2].sig),
+        &(pack->sat_data[3].id), &(pack->sat_data[3].elv), &(pack->sat_data[3].azimuth), &(pack->sat_data[3].sig));
+
+    nsat = (pack->pack_index - 1) * NMEA_SATINPACK;
+    nsat = (nsat + NMEA_SATINPACK > pack->sat_count)?pack->sat_count - nsat:NMEA_SATINPACK;
+    nsat = nsat * 4 + 3 /* first three sentence`s */;
+    if(nsen < nsat || nsen > (NMEA_SATINPACK * 4 + 3))
+    {
+        //printf("BDGSV parse error!\n");
+        nmea_error("GPGSV parse error!");
+        return 0;
+    }
+    
+    return 1;
+}
+/**
+ * \brief Parse RMC packet from buffer.
+ * @param buff a constant character pointer of packet buffer.
+ * @param buff_sz buffer size.
+ * @param pack a pointer of packet which will filled by function.
+ * @return 1 (true) - if parsed successfully or 0 (false) - if fail.
+ */
+int nmea_parse_GPRMC(const char *buff, int buff_sz, nmeaGPRMC *pack)
+{
+    int nsen;
+    char time_buff[NMEA_TIMEPARSE_BUF];
+
+    NMEA_ASSERT(buff && pack);
+
+    memset(pack, 0, sizeof(nmeaGPRMC));
+
+    nmea_trace_buff(buff, buff_sz);
+
+    nsen = nmea_scanf(buff, buff_sz,
+        "$GPRMC,%s,%C,%f,%C,%f,%C,%f,%f,%2d%2d%2d,%f,%C,%C*",
+        &(time_buff[0]),
+        &(pack->status), &(pack->lat), &(pack->ns), &(pack->lon), &(pack->ew),
+        &(pack->speed), &(pack->direction),
+        &(pack->utc.day), &(pack->utc.mon), &(pack->utc.year),
+        &(pack->declination), &(pack->declin_ew), &(pack->mode));
+
+    if(nsen != 13 && nsen != 14)
+    {
+        nmea_error("GPRMC parse error!");
+        return 0;
+    }
+
+    if(0 != _nmea_parse_time(&time_buff[0], (int)strlen(&time_buff[0]), &(pack->utc)))
+    {
+        nmea_error("GPRMC time parse error!");
+        return 0;
+    }
+
+    if(pack->utc.year < 90)
+        pack->utc.year += 100;
+    pack->utc.mon -= 1;
+
+    return 1;
+}
+//$GPRMC,014600.00,A,2237.496474,N,11356.089515,E,0.0,225.5,310518,2.3,W,A*23
+//$GNRMC,032950.000,A,3448.60391,N,11339.61318,E,0.00,165.77,050923,,A,V*0A
+//
+int nmea_parse_GNRMC(const char *buff, int buff_sz, nmeaGPRMC *pack)
+{
+    int nsen;
+    char time_buff[NMEA_TIMEPARSE_BUF];
+
+    NMEA_ASSERT(buff && pack);
+
+    memset(pack, 0, sizeof(nmeaGPRMC));
+
+    nmea_trace_buff(buff, buff_sz);
+
+    nsen = nmea_scanf(buff, buff_sz,
+        "$GNRMC,%s,%C,%f,%C,%f,%C,%f,%f,%2d%2d%2d,%f,%C,%C",
+        &(time_buff[0]),
+        &(pack->status), &(pack->lat), &(pack->ns), &(pack->lon), &(pack->ew),
+        &(pack->speed), &(pack->direction),
+        &(pack->utc.day), &(pack->utc.mon), &(pack->utc.year),
+        &(pack->declination), &(pack->declin_ew), &(pack->mode));
+
+    if(nsen != 13 && nsen != 14)
+    {
+        //printf("GnRMC parse error!%d-%d",nsen,buff_sz);
+        nmea_error("GPRMC parse error!");
+        return 0;
+    }
+
+    if(0 != _nmea_parse_time(&time_buff[0], (int)strlen(&time_buff[0]), &(pack->utc)))
+    {
+        nmea_error("GPRMC time parse error!");
+        return 0;
+    }
+
+    if(pack->utc.year < 90)
+        pack->utc.year += 100;
+    pack->utc.mon -= 1;
+
+    return 1;
+}
+/**
+ * \brief Parse VTG packet from buffer.
+ * @param buff a constant character pointer of packet buffer.
+ * @param buff_sz buffer size.
+ * @param pack a pointer of packet which will filled by function.
+ * @return 1 (true) - if parsed successfully or 0 (false) - if fail.
+ */
+int nmea_parse_GPVTG(const char *buff, int buff_sz, nmeaGPVTG *pack)
+{
+    NMEA_ASSERT(buff && pack);
+
+    memset(pack, 0, sizeof(nmeaGPVTG));
+
+    nmea_trace_buff(buff, buff_sz);
+
+    if(8 != nmea_scanf(buff, buff_sz,
+        "$GPVTG,%f,%C,%f,%C,%f,%C,%f,%C*",
+        &(pack->dir), &(pack->dir_t),
+        &(pack->dec), &(pack->dec_m),
+        &(pack->spn), &(pack->spn_n),
+        &(pack->spk), &(pack->spk_k)))
+    {
+        nmea_error("GPVTG parse error!");
+        return 0;
+    }
+
+    if( pack->dir_t != 'T' ||
+        pack->dec_m != 'M' ||
+        pack->spn_n != 'N' ||
+        pack->spk_k != 'K')
+    {
+        nmea_error("GPVTG parse error (format error)!");
+        return 0;
+    }
+
+    return 1;
+}
+
+/**
+ * \brief Fill nmeaINFO structure by GGA packet data.
+ * @param pack a pointer of packet structure.
+ * @param info a pointer of summary information structure.
+ */
+void nmea_GPGGA2info(nmeaGPGGA *pack, nmeaINFO *info)
+{
+    NMEA_ASSERT(pack && info);
+
+    info->utc.hour = pack->utc.hour;
+    info->utc.min = pack->utc.min;
+    info->utc.sec = pack->utc.sec;
+    info->utc.hsec = pack->utc.hsec;
+    info->sig = pack->sig;
+    info->satinfo.inuse = pack->satinuse;
+    info->HDOP = pack->HDOP;
+    info->elv = pack->elv;
+    info->lat = ((pack->ns == 'N')?pack->lat:-(pack->lat));
+    info->lon = ((pack->ew == 'E')?pack->lon:-(pack->lon));
+    info->smask |= GPGGA;
+}
+//$GNGGA,020209.000,3448.60499,N,11339.61056,E,1,20,0.7,134.7,M,-18.9,M,,*66
+void nmea_GNGGA2info(nmeaGPGGA *pack, nmeaINFO *info)
+{
+    NMEA_ASSERT(pack && info);
+
+    info->utc.hour = pack->utc.hour;
+    info->utc.min = pack->utc.min;
+    info->utc.sec = pack->utc.sec;
+    info->utc.hsec = pack->utc.hsec;
+    info->sig = pack->sig;
+    info->satinfo.inuse = pack->satinuse;
+    info->HDOP = pack->HDOP;
+    info->elv = pack->elv;
+    info->lat = ((pack->ns == 'N')?pack->lat:-(pack->lat));
+    info->lon = ((pack->ew == 'E')?pack->lon:-(pack->lon));
+    info->smask |= GNGGA;
+}
+/**
+ * \brief Fill nmeaINFO structure by GSA packet data.
+ * @param pack a pointer of packet structure.
+ * @param info a pointer of summary information structure.
+ */
+void nmea_GPGSA2info(nmeaGPGSA *pack, nmeaINFO *info)
+{
+    int i, j, nuse = 0;
+
+    NMEA_ASSERT(pack && info);
+
+    info->fix = pack->fix_type;
+    info->PDOP = pack->PDOP;
+    info->HDOP = pack->HDOP;
+    info->VDOP = pack->VDOP;
+
+    for(i = 0; i < NMEA_MAXSAT; ++i)
+    {
+        for(j = 0; j < info->satinfo.inview; ++j)
+        {
+            if(pack->sat_prn[i] && pack->sat_prn[i] == info->satinfo.sat[j].id)
+            {
+                info->satinfo.sat[j].in_use = 1;
+                nuse++;
+            }
+        }
+    }
+
+    info->satinfo.inuse = nuse;
+    info->smask |= GPGSA;
+}
+
+void nmea_GNGSA2info(nmeaGPGSA *pack, nmeaINFO *info)
+{
+    int i, j, nuse = 0;
+
+    NMEA_ASSERT(pack && info);
+
+    info->fix = pack->fix_type;
+    info->PDOP = pack->PDOP;
+    info->HDOP = pack->HDOP;
+    info->VDOP = pack->VDOP;
+
+    for(i = 0; i < NMEA_MAXSAT; ++i)
+    {
+        for(j = 0; j < info->satinfo.inview; ++j)
+        {
+            if(pack->sat_prn[i] && pack->sat_prn[i] == info->satinfo.sat[j].id)
+            {
+                info->satinfo.sat[j].in_use = 1;
+                nuse++;
+            }
+        }
+    }
+
+    info->satinfo.inuse = nuse;
+    info->smask |= GNGSA;
+}
+/**
+ * \brief Fill nmeaINFO structure by GSV packet data.
+ * @param pack a pointer of packet structure.
+ * @param info a pointer of summary information structure.
+ */
+void nmea_GPGSV2info(nmeaGPGSV *pack, nmeaINFO *info)
+{
+    int isat, isi, nsat;
+
+    NMEA_ASSERT(pack && info);
+
+    if(pack->pack_index > pack->pack_count ||
+        pack->pack_index * NMEA_SATINPACK > NMEA_MAXSAT)
+        return;
+
+    if(pack->pack_index < 1)
+        pack->pack_index = 1;
+    gps_count = pack->sat_count;
+    info->satinfo.inview = gps_count  + bd_count ;
+    //printf("GPS卫星数量:%d\n",pack->sat_count);
+    nsat = (pack->pack_index - 1) * NMEA_SATINPACK;
+    nsat = (nsat + NMEA_SATINPACK > pack->sat_count)?pack->sat_count - nsat:NMEA_SATINPACK;
+
+    for(isat = 0; isat < nsat; ++isat)
+    {
+        isi = (pack->pack_index - 1) * NMEA_SATINPACK + isat;
+        info->satinfo.sat[isi].id = pack->sat_data[isat].id;
+        info->satinfo.sat[isi].elv = pack->sat_data[isat].elv;
+        info->satinfo.sat[isi].azimuth = pack->sat_data[isat].azimuth;
+        info->satinfo.sat[isi].sig = pack->sat_data[isat].sig;
+    }
+    info->smask |= GPGSV;
+}
+void nmea_BDGSV2info(nmeaGPGSV *pack, nmeaINFO *info)
+{
+    int isat, isi, nsat;
+
+    NMEA_ASSERT(pack && info);
+    bd_count = pack->sat_count;
+    info->satinfo.inview = gps_count  + bd_count ;
+    //printf("北斗卫星数量:%d\n",pack->sat_count);
+    if(pack->pack_index > pack->pack_count ||
+        pack->pack_index * NMEA_SATINPACK > NMEA_MAXSAT)
+        return;
+
+    if(pack->pack_index < 1)
+        pack->pack_index = 1;
+
+
+    nsat = (pack->pack_index - 1) * NMEA_SATINPACK;
+    nsat = (nsat + NMEA_SATINPACK > pack->sat_count)?pack->sat_count - nsat:NMEA_SATINPACK;
+
+    for(isat = 0; isat < nsat; ++isat)
+    {
+        isi = (pack->pack_index - 1) * NMEA_SATINPACK + isat;
+        info->satinfo.sat[isi].id = pack->sat_data[isat].id;
+        info->satinfo.sat[isi].elv = pack->sat_data[isat].elv;
+        info->satinfo.sat[isi].azimuth = pack->sat_data[isat].azimuth;
+        info->satinfo.sat[isi].sig = pack->sat_data[isat].sig;
+    }
+    info->satinfo.state = 'B';
+    info->smask |= GPGSV;
+}
+/**
+ * \brief Fill nmeaINFO structure by RMC packet data.
+ * @param pack a pointer of packet structure.
+ * @param info a pointer of summary information structure.
+ */
+void nmea_GPRMC2info(nmeaGPRMC *pack, nmeaINFO *info)
+{
+    NMEA_ASSERT(pack && info);
+
+    if('A' == pack->status)
+    {
+        if(NMEA_SIG_BAD == info->sig)
+            info->sig = NMEA_SIG_MID;
+        if(NMEA_FIX_BAD == info->fix)
+            info->fix = NMEA_FIX_2D;
+    }
+    else if('V' == pack->status)
+    {
+        info->sig = NMEA_SIG_BAD;
+        info->fix = NMEA_FIX_BAD;
+    }
+
+    info->utc = pack->utc;
+    info->lat = ((pack->ns == 'N')?pack->lat:-(pack->lat));
+    info->lon = ((pack->ew == 'E')?pack->lon:-(pack->lon));
+    info->speed = pack->speed * NMEA_TUD_KNOTS;
+    info->direction = pack->direction;
+    info->smask |= GPRMC;
+}
+void nmea_GNRMC2info(nmeaGPRMC *pack, nmeaINFO *info)
+{
+    NMEA_ASSERT(pack && info);
+
+    if('A' == pack->status)
+    {
+        if(NMEA_SIG_BAD == info->sig)
+            info->sig = NMEA_SIG_MID;
+        if(NMEA_FIX_BAD == info->fix)
+            info->fix = NMEA_FIX_2D;
+    }
+    else if('V' == pack->status)
+    {
+        info->sig = NMEA_SIG_BAD;
+        info->fix = NMEA_FIX_BAD;
+    }
+
+    info->utc = pack->utc;
+    info->lat = ((pack->ns == 'N')?pack->lat:-(pack->lat));
+    info->lon = ((pack->ew == 'E')?pack->lon:-(pack->lon));
+    info->speed = pack->speed * NMEA_TUD_KNOTS;
+    info->direction = pack->direction;
+    info->smask |= GPRMC;
+}
+/**
+ * \brief Fill nmeaINFO structure by VTG packet data.
+ * @param pack a pointer of packet structure.
+ * @param info a pointer of summary information structure.
+ */
+void nmea_GPVTG2info(nmeaGPVTG *pack, nmeaINFO *info)
+{
+    NMEA_ASSERT(pack && info);
+
+    info->direction = pack->dir;
+    info->declination = pack->dec;
+    info->speed = pack->spk;
+    info->smask |= GPVTG;
+}

+ 462 - 0
air530z/nmealib/src/parser.c

@@ -0,0 +1,462 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: parser.c 17 2008-03-11 11:56:11Z xtimor $
+ *
+ */
+
+/**
+ * \file parser.h
+ */
+
+#include "nmea/tok.h"
+#include "nmea/parse.h"
+#include "nmea/parser.h"
+#include "nmea/context.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+typedef struct _nmeaParserNODE
+{
+    int packType;
+    void *pack;
+    struct _nmeaParserNODE *next_node;
+
+} nmeaParserNODE;
+
+/*
+ * high level
+ */
+
+/**
+ * \brief Initialization of parser object
+ * @return true (1) - success or false (0) - fail
+ */
+int nmea_parser_init(nmeaPARSER *parser)
+{
+    int resv = 0;
+    int buff_size = nmea_property()->parse_buff_size;
+
+    NMEA_ASSERT(parser);
+
+    if(buff_size < NMEA_MIN_PARSEBUFF)
+        buff_size = NMEA_MIN_PARSEBUFF;
+
+    memset(parser, 0, sizeof(nmeaPARSER));
+
+    if(0 == (parser->buffer = malloc(buff_size)))
+        nmea_error("Insufficient memory!");
+    else
+    {
+        parser->buff_size = buff_size;
+        resv = 1;
+    }    
+
+    return resv;
+}
+
+/**
+ * \brief Destroy parser object
+ */
+void nmea_parser_destroy(nmeaPARSER *parser)
+{
+    NMEA_ASSERT(parser && parser->buffer);
+    free(parser->buffer);
+    nmea_parser_queue_clear(parser);
+    memset(parser, 0, sizeof(nmeaPARSER));
+}
+
+/**
+ * \brief Analysis of buffer and put results to information structure
+ * @return Number of packets wos parsed
+ */
+int nmea_parse(    
+    nmeaPARSER *parser,
+    const char *buff, int buff_sz,
+    nmeaINFO *info
+    )
+{
+    int ptype, nread = 0;
+    void *pack = 0;
+
+    NMEA_ASSERT(parser && parser->buffer);
+    
+    nmea_parser_push(parser, buff, buff_sz);
+
+    while(GPNON != (ptype = nmea_parser_pop(parser, &pack)))
+    {
+        nread++;
+
+        switch(ptype)
+        {
+        case GPGGA:
+            nmea_GPGGA2info((nmeaGPGGA *)pack, info);
+            break;
+        case GPGSA:
+            nmea_GPGSA2info((nmeaGPGSA *)pack, info);
+            break;
+        case GPGSV:
+            nmea_GPGSV2info((nmeaGPGSV *)pack, info);
+            break;
+        case GPRMC:
+            nmea_GPRMC2info((nmeaGPRMC *)pack, info);
+            break;
+        case GNRMC:
+            nmea_GNRMC2info((nmeaGPRMC *)pack, info);
+            break;
+        case GPVTG:
+            nmea_GPVTG2info((nmeaGPVTG *)pack, info);
+            break;
+        case GNGGA:
+            //printf("nmea解析GNGGA成功:%s\n",info);
+            nmea_GNGGA2info((nmeaGPGGA *)pack, info);
+            break;
+        case BDGSV:
+            //printf("nmea解析BDGSV成功:%s\n",info);
+            nmea_BDGSV2info((nmeaGPGSV *)pack, info);
+            break;
+        case GNGSA:
+            nmea_GNGSA2info((nmeaGPGSA *)pack, info);
+            break;
+        };
+        free(pack);
+    }
+    return nread;
+}
+
+/*
+ * low level
+ */
+
+int nmea_parser_real_push(nmeaPARSER *parser, const char *buff, int buff_sz)
+{
+    
+    int nparsed = 0, crc, sen_sz, ptype;
+    nmeaParserNODE *node = 0;
+
+    NMEA_ASSERT(parser && parser->buffer);
+
+    /* clear unuse buffer (for debug) */
+    /*
+    memset(
+        parser->buffer + parser->buff_use, 0,
+        parser->buff_size - parser->buff_use
+        );
+        */
+
+    /* add */
+    if(parser->buff_use + buff_sz >= parser->buff_size)
+        nmea_parser_buff_clear(parser);
+
+    memcpy(parser->buffer + parser->buff_use, buff, buff_sz);
+    parser->buff_use += buff_sz;
+
+    /* parse */
+    for(;;node = 0)
+    {
+        sen_sz = nmea_find_tail(
+            (const char *)parser->buffer + nparsed,
+            (int)parser->buff_use - nparsed, &crc);
+        
+        if(!sen_sz)
+        {
+            if(nparsed)
+                memcpy(
+                parser->buffer,
+                parser->buffer + nparsed,
+                parser->buff_use -= nparsed);
+            break;
+        }
+        else if(crc >= 0)
+        {
+            ptype = nmea_pack_type(
+                (const char *)parser->buffer + nparsed + 1,
+                parser->buff_use - nparsed - 1);
+            //printf("\n解析到nmea_parser_real_push:%d\n",ptype);
+            if(0 == (node = malloc(sizeof(nmeaParserNODE))))
+                goto mem_fail;
+
+            node->pack = 0;
+
+            switch(ptype)
+            {
+            case GPGGA:
+                if(0 == (node->pack = malloc(sizeof(nmeaGPGGA))))
+                    goto mem_fail;
+                node->packType = GPGGA;
+                if(!nmea_parse_GPGGA(
+                    (const char *)parser->buffer + nparsed,
+                    sen_sz, (nmeaGPGGA *)node->pack))
+                {
+                    free(node);
+                    node = 0;
+                }
+                break;
+            case GNGGA:
+                if(0 == (node->pack = malloc(sizeof(nmeaGPGGA))))
+                    goto mem_fail;
+                node->packType = GPGGA;
+                if(!nmea_parse_GNGGA(
+                    (const char *)parser->buffer + nparsed,
+                    sen_sz, (nmeaGPGGA *)node->pack))
+                {
+                    free(node);
+                    node = 0;
+                }
+                break;                
+            case GPGSA:
+                if(0 == (node->pack = malloc(sizeof(nmeaGPGSA))))
+                    goto mem_fail;
+                node->packType = GPGSA;
+                if(!nmea_parse_GPGSA(
+                    (const char *)parser->buffer + nparsed,
+                    sen_sz, (nmeaGPGSA *)node->pack))
+                {
+                    free(node);
+                    node = 0;
+                }
+                break;
+            case GNGSA:
+                if(0 == (node->pack = malloc(sizeof(nmeaGPGSA))))
+                    goto mem_fail;
+                node->packType = GPGSA;
+                if(!nmea_parse_GNGSA(
+                    (const char *)parser->buffer + nparsed,
+                    sen_sz, (nmeaGPGSA *)node->pack))
+                {
+                    free(node);
+                    node = 0;
+                }
+                break;
+            case GPGSV:
+                if(0 == (node->pack = malloc(sizeof(nmeaGPGSV))))
+                    goto mem_fail;
+                node->packType = GPGSV;
+                if(!nmea_parse_GPGSV(
+                    (const char *)parser->buffer + nparsed,
+                    sen_sz, (nmeaGPGSV *)node->pack))
+                {
+                    free(node);
+                    node = 0;
+                }
+                break;
+            case BDGSV:
+                if(0 == (node->pack = malloc(sizeof(nmeaGPGSV))))
+                    goto mem_fail;
+                node->packType = BDGSV;
+                if(!nmea_parse_BDGSV(
+                    (const char *)parser->buffer + nparsed,
+                    sen_sz, (nmeaGPGSV *)node->pack))
+                {
+                    free(node);
+                    node = 0;
+                }
+                break;
+            case GPRMC:
+                if(0 == (node->pack = malloc(sizeof(nmeaGPRMC))))
+                    goto mem_fail;
+                node->packType = GPRMC;
+                if(!nmea_parse_GPRMC(
+                    (const char *)parser->buffer + nparsed,
+                    sen_sz, (nmeaGPRMC *)node->pack))
+                {
+                    free(node);
+                    node = 0;
+                }
+                break;
+            case GNRMC:
+                if(0 == (node->pack = malloc(sizeof(nmeaGPRMC))))
+                    goto mem_fail;
+                node->packType = GPRMC;
+                if(!nmea_parse_GNRMC(
+                    (const char *)parser->buffer + nparsed,
+                    sen_sz, (nmeaGPRMC *)node->pack))
+                {
+                    free(node);
+                    node = 0;
+                }
+                break;
+            case GPVTG:
+                if(0 == (node->pack = malloc(sizeof(nmeaGPVTG))))
+                    goto mem_fail;
+                node->packType = GPVTG;
+                if(!nmea_parse_GPVTG(
+                    (const char *)parser->buffer + nparsed,
+                    sen_sz, (nmeaGPVTG *)node->pack))
+                {
+                    free(node);
+                    node = 0;
+                }
+                break;
+            default:
+                free(node);
+                node = 0;
+                break;
+            };
+
+            if(node)
+            {
+                if(parser->end_node)
+                    ((nmeaParserNODE *)parser->end_node)->next_node = node;
+                parser->end_node = node;
+                if(!parser->top_node)
+                    parser->top_node = node;
+                node->next_node = 0;
+            }
+        }
+
+        nparsed += sen_sz;
+    }
+
+    return nparsed;
+
+mem_fail:
+    if(node)
+        free(node);
+ 
+    nmea_error("Insufficient memory!");
+
+    return -1;
+}
+
+/**
+ * \brief Analysis of buffer and keep results into parser
+ * @return Number of bytes wos parsed from buffer
+ */
+int nmea_parser_push(nmeaPARSER *parser, const char *buff, int buff_sz)
+{
+    int nparse, nparsed = 0;
+
+    do
+    {
+        if(buff_sz > parser->buff_size)
+            nparse = parser->buff_size;
+        else
+            nparse = buff_sz;
+
+        nparsed += nmea_parser_real_push(
+            parser, buff, nparse);
+
+        buff_sz -= nparse;
+
+    } while(buff_sz);
+
+    return nparsed;
+}
+
+/**
+ * \brief Get type of top packet keeped into parser
+ * @return Type of packet
+ * @see nmeaPACKTYPE
+ */
+int nmea_parser_top(nmeaPARSER *parser)
+{
+    int retval = GPNON;
+    nmeaParserNODE *node = (nmeaParserNODE *)parser->top_node;
+
+    NMEA_ASSERT(parser && parser->buffer);
+
+    if(node)
+        retval = node->packType;
+
+    return retval;
+}
+
+/**
+ * \brief Withdraw top packet from parser
+ * @return Received packet type
+ * @see nmeaPACKTYPE
+ */
+int nmea_parser_pop(nmeaPARSER *parser, void **pack_ptr)
+{
+    int retval = GPNON;
+    nmeaParserNODE *node = (nmeaParserNODE *)parser->top_node;
+
+    NMEA_ASSERT(parser && parser->buffer);
+
+    if(node)
+    {
+        *pack_ptr = node->pack;
+        retval = node->packType;
+        parser->top_node = node->next_node;
+        if(!parser->top_node)
+            parser->end_node = 0;
+        free(node);
+    }
+
+    return retval;
+}
+
+/**
+ * \brief Get top packet from parser without withdraw
+ * @return Received packet type
+ * @see nmeaPACKTYPE
+ */
+int nmea_parser_peek(nmeaPARSER *parser, void **pack_ptr)
+{
+    int retval = GPNON;
+    nmeaParserNODE *node = (nmeaParserNODE *)parser->top_node;
+
+    NMEA_ASSERT(parser && parser->buffer);
+
+    if(node)
+    {
+        *pack_ptr = node->pack;
+        retval = node->packType;
+    }
+
+    return retval;
+}
+
+/**
+ * \brief Delete top packet from parser
+ * @return Deleted packet type
+ * @see nmeaPACKTYPE
+ */
+int nmea_parser_drop(nmeaPARSER *parser)
+{
+    int retval = GPNON;
+    nmeaParserNODE *node = (nmeaParserNODE *)parser->top_node;
+
+    NMEA_ASSERT(parser && parser->buffer);
+
+    if(node)
+    {
+        if(node->pack)
+            free(node->pack);
+        retval = node->packType;
+        parser->top_node = node->next_node;
+        if(!parser->top_node)
+            parser->end_node = 0;
+        free(node);
+    }
+
+    return retval;
+}
+
+/**
+ * \brief Clear cache of parser
+ * @return true (1) - success
+ */
+int nmea_parser_buff_clear(nmeaPARSER *parser)
+{
+    NMEA_ASSERT(parser && parser->buffer);
+    parser->buff_use = 0;
+    return 1;
+}
+
+/**
+ * \brief Clear packets queue into parser
+ * @return true (1) - success
+ */
+int nmea_parser_queue_clear(nmeaPARSER *parser)
+{
+    NMEA_ASSERT(parser);
+    while(parser->top_node)
+        nmea_parser_drop(parser);
+    return 1;
+}

+ 54 - 0
air530z/nmealib/src/sentence.c

@@ -0,0 +1,54 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: sentence.c 17 2008-03-11 11:56:11Z xtimor $
+ *
+ */
+
+#include "nmea/sentence.h"
+
+#include <string.h>
+
+void nmea_zero_GPGGA(nmeaGPGGA *pack)
+{
+    memset(pack, 0, sizeof(nmeaGPGGA));
+    nmea_time_now(&pack->utc);
+    pack->ns = 'N';
+    pack->ew = 'E';
+    pack->elv_units = 'M';
+    pack->diff_units = 'M';
+}
+
+void nmea_zero_GPGSA(nmeaGPGSA *pack)
+{
+    memset(pack, 0, sizeof(nmeaGPGSA));
+    pack->fix_mode = 'A';
+    pack->fix_type = NMEA_FIX_BAD;
+}
+
+void nmea_zero_GPGSV(nmeaGPGSV *pack)
+{
+    memset(pack, 0, sizeof(nmeaGPGSV));
+}
+
+void nmea_zero_GPRMC(nmeaGPRMC *pack)
+{
+    memset(pack, 0, sizeof(nmeaGPRMC));
+    nmea_time_now(&pack->utc);
+    pack->status = 'V';
+    pack->ns = 'N';
+    pack->ew = 'E';
+    pack->declin_ew = 'E';
+}
+
+void nmea_zero_GPVTG(nmeaGPVTG *pack)
+{
+    memset(pack, 0, sizeof(nmeaGPVTG));
+    pack->dir_t = 'T';
+    pack->dec_m = 'M';
+    pack->spn_n = 'N';
+    pack->spk_k = 'K';
+}

+ 63 - 0
air530z/nmealib/src/time.c

@@ -0,0 +1,63 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: time.c 4 2007-08-27 13:11:03Z xtimor $
+ *
+ */
+
+/*! \file time.h */
+
+#include "nmea/time.h"
+
+#ifdef NMEA_WIN
+#   pragma warning(disable: 4201)
+#   pragma warning(disable: 4214)
+#   pragma warning(disable: 4115)
+#   include <windows.h>
+#   pragma warning(default: 4201)
+#   pragma warning(default: 4214)
+#   pragma warning(default: 4115)
+#else
+#   include <time.h>
+#endif
+
+#ifdef NMEA_WIN
+
+void nmea_time_now(nmeaTIME *stm)
+{
+    SYSTEMTIME st;
+
+    GetSystemTime(&st);
+
+    stm->year = st.wYear - 1900;
+    stm->mon = st.wMonth - 1;
+    stm->day = st.wDay;
+    stm->hour = st.wHour;
+    stm->min = st.wMinute;
+    stm->sec = st.wSecond;
+    stm->hsec = st.wMilliseconds / 10;
+}
+
+#else /* NMEA_WIN */
+
+void nmea_time_now(nmeaTIME *stm)
+{
+    time_t lt;
+    struct tm *tt;
+
+    time(&lt);
+    tt = gmtime(&lt);
+
+    stm->year = tt->tm_year;
+    stm->mon = tt->tm_mon;
+    stm->day = tt->tm_mday;
+    stm->hour = tt->tm_hour;
+    stm->min = tt->tm_min;
+    stm->sec = tt->tm_sec;
+    stm->hsec = 0;
+}
+
+#endif

+ 250 - 0
air530z/nmealib/src/tok.c

@@ -0,0 +1,250 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: tok.c 17 2008-03-11 11:56:11Z xtimor $
+ *
+ */
+
+/*! \file tok.h */
+
+#include "nmea/tok.h"
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <limits.h>
+
+#define NMEA_TOKS_COMPARE   (1)
+#define NMEA_TOKS_PERCENT   (2)
+#define NMEA_TOKS_WIDTH     (3)
+#define NMEA_TOKS_TYPE      (4)
+
+/**
+ * \brief Calculate control sum of binary buffer
+ */
+int nmea_calc_crc(const char *buff, int buff_sz)
+{
+    int chsum = 0,
+        it;
+
+    for(it = 0; it < buff_sz; ++it)
+        chsum ^= (int)buff[it];
+
+    return chsum;
+}
+
+/**
+ * \brief Convert string to number
+ */
+int nmea_atoi(const char *str, int str_sz, int radix)
+{
+    char *tmp_ptr;
+    char buff[NMEA_CONVSTR_BUF];
+    int res = 0;
+
+    if(str_sz < NMEA_CONVSTR_BUF)
+    {
+        memcpy(&buff[0], str, str_sz);
+        buff[str_sz] = '\0';
+        res = strtol(&buff[0], &tmp_ptr, radix);
+    }
+
+    return res;
+}
+
+/**
+ * \brief Convert string to fraction number
+ */
+double nmea_atof(const char *str, int str_sz)
+{
+    char *tmp_ptr;
+    char buff[NMEA_CONVSTR_BUF];
+    double res = 0;
+
+    if(str_sz < NMEA_CONVSTR_BUF)
+    {
+        memcpy(&buff[0], str, str_sz);
+        buff[str_sz] = '\0';
+        res = strtod(&buff[0], &tmp_ptr);
+    }
+
+    return res;
+}
+
+/**
+ * \brief Formating string (like standart printf) with CRC tail (*CRC)
+ */
+int nmea_printf(char *buff, int buff_sz, const char *format, ...)
+{
+    int retval, add = 0;
+    va_list arg_ptr;
+
+    if(buff_sz <= 0)
+        return 0;
+
+    va_start(arg_ptr, format);
+
+    retval = NMEA_POSIX(vsnprintf)(buff, buff_sz, format, arg_ptr);
+
+    if(retval > 0)
+    {
+        add = NMEA_POSIX(snprintf)(
+            buff + retval, buff_sz - retval, "*%02x\r\n",
+            nmea_calc_crc(buff + 1, retval - 1));
+    }
+
+    retval += add;
+
+    if(retval < 0 || retval > buff_sz)
+    {
+        memset(buff, ' ', buff_sz);
+        retval = buff_sz;
+    }
+
+    va_end(arg_ptr);
+
+    return retval;
+}
+
+/**
+ * \brief Analyse string (specificate for NMEA sentences)
+ */
+int nmea_scanf(const char *buff, int buff_sz, const char *format, ...)
+{
+    const char *beg_tok;
+    const char *end_buf = buff + buff_sz;
+
+    va_list arg_ptr;
+    int tok_type = NMEA_TOKS_COMPARE;
+    int width = 0;
+    const char *beg_fmt = 0;
+    int snum = 0, unum = 0;
+
+    int tok_count = 0;
+    void *parg_target;
+
+    va_start(arg_ptr, format);
+    
+    for(; *format && buff < end_buf; ++format)
+    {
+        switch(tok_type)
+        {
+        case NMEA_TOKS_COMPARE:
+            if('%' == *format)
+                tok_type = NMEA_TOKS_PERCENT;
+            else if(*buff++ != *format)
+                goto fail;
+            break;
+        case NMEA_TOKS_PERCENT:
+            width = 0;
+            beg_fmt = format;
+            tok_type = NMEA_TOKS_WIDTH;
+        case NMEA_TOKS_WIDTH:
+            if(isdigit(*format))
+                break;
+            {
+                tok_type = NMEA_TOKS_TYPE;
+                if(format > beg_fmt)
+                    width = nmea_atoi(beg_fmt, (int)(format - beg_fmt), 10);
+            }
+        case NMEA_TOKS_TYPE:
+            beg_tok = buff;
+
+            if(!width && ('c' == *format || 'C' == *format) && *buff != format[1])
+                width = 1;
+
+            if(width)
+            {
+                if(buff + width <= end_buf)
+                    buff += width;
+                else
+                    goto fail;
+            }
+            else
+            {
+                if(!format[1] || (0 == (buff = (char *)memchr(buff, format[1], end_buf - buff))))
+                    buff = end_buf;
+            }
+
+            if(buff > end_buf)
+                goto fail;
+
+            tok_type = NMEA_TOKS_COMPARE;
+            tok_count++;
+
+            parg_target = 0; width = (int)(buff - beg_tok);
+
+            switch(*format)
+            {
+            case 'c':
+            case 'C':
+                parg_target = (void *)va_arg(arg_ptr, char *);
+                if(width && 0 != (parg_target))
+                    *((char *)parg_target) = *beg_tok;
+                break;
+            case 's':
+            case 'S':
+                parg_target = (void *)va_arg(arg_ptr, char *);
+                if(width && 0 != (parg_target))
+                {
+                    memcpy(parg_target, beg_tok, width);
+                    ((char *)parg_target)[width] = '\0';
+                }
+                break;
+            case 'f':
+            case 'g':
+            case 'G':
+            case 'e':
+            case 'E':
+                parg_target = (void *)va_arg(arg_ptr, double *);
+                if(width && 0 != (parg_target))
+                    *((double *)parg_target) = nmea_atof(beg_tok, width);
+                break;
+            };
+
+            if(parg_target)
+                break;
+            if(0 == (parg_target = (void *)va_arg(arg_ptr, int *)))
+                break;
+            if(!width)
+                break;
+
+            switch(*format)
+            {
+            case 'd':
+            case 'i':
+                snum = nmea_atoi(beg_tok, width, 10);
+                memcpy(parg_target, &snum, sizeof(int));
+                break;
+            case 'u':
+                unum = nmea_atoi(beg_tok, width, 10);
+                memcpy(parg_target, &unum, sizeof(unsigned int));
+                break;
+            case 'x':
+            case 'X':
+                unum = nmea_atoi(beg_tok, width, 16);
+                memcpy(parg_target, &unum, sizeof(unsigned int));
+                break;
+            case 'o':
+                unum = nmea_atoi(beg_tok, width, 8);
+                memcpy(parg_target, &unum, sizeof(unsigned int));
+                break;
+            default:
+                goto fail;
+            };
+
+            break;
+        };
+    }
+
+fail:
+
+    va_end(arg_ptr);
+
+    return tok_count;
+}

+ 42 - 0
air720u/Makefile

@@ -0,0 +1,42 @@
+.PHONY: build clean
+
+# 头文件
+INCS += -I.
+INCS += -I../swapi
+INCS += -I./include
+
+# 源文件
+SRCS += $(filter-out ../swapi/testLib.c, $(wildcard ../swapi/*.c))
+SRCS += ../swapi/subjects/serial/serial.c air720u.c
+
+# .o文件
+OBJS = $(SRCS:.c=.o)
+
+# 编译器
+CC = gcc
+CFLAGS = -Wall -fPIC -O2 -g
+DEFINS = -D_GNU_SOURCE
+
+target ?= x86_64
+ifeq ($(target),armv7hf)
+  CC := arm-linux-gnueabihf-gcc
+	AR := arm-linux-gnueabihf-ar
+endif
+
+# 库文件
+LIBS += -Wl,-Bdynamic -lc -lm -ldl -lpthread
+
+# 编译和清理
+build : libair720u.a air720u_test.out
+
+%.o : %.c
+	$(CC) $(DEFINS) $(CFLAGS) -c $< $(INCS) -o $@
+
+libair720u.a : $(OBJS)
+	$(AR) -cr $@ $(OBJS)
+
+air720u_test.out : $(OBJS)
+	$(CC) $(DEFINS) $(CFLAGS) $(OBJS) air720u_test.c $(INCS) $(LIBS) -o $@
+
+clean :
+	rm -rf $(OBJS) *.out *.a config/ log/ status/ var/

+ 393 - 0
air720u/air720u.c

@@ -0,0 +1,393 @@
+#include "air720u.h"
+#include "../swapi/subjects/serial/serial.h"
+
+// 模块名称
+static const char MODULE_NAME[] = "Air720U";
+
+#define MAX_CMD_CHARS    65535 // 单条指令最大字符数
+#define MAX_ACK_CHARS    65535 // 指令应答最大字符数
+#define WAIT_ACK_TIMEOUT 9000  // 等待应答超时时间ms
+#define R_SILENT_TIMEOUT 50    // 应答静默超时时间ms
+
+// 关闭命令回显模式
+static const char *AT_USE_ECHO   = "ATE0"    ;
+// 获取模块的IMEI号
+static const char *AT_GET_IMEI   = "AT+CGSN" ;
+// 查看网络注册状态
+static const char *AT_GET_CREG   = "AT+CREG?";
+// 获取当前信号强度
+static const char *AT_GET_CSQ    = "AT+CSQ"  ;
+// 获取SIM-PIN状态
+static const char *AT_GET_PINSTA = "AT+CPIN?";
+// 获取SIM-ICCID号
+static const char *AT_GET_ICCID  = "AT+ICCID";
+
+// AT指令请求和应答
+typedef struct
+{
+  // 指令
+  struct
+  {
+    char data[MAX_CMD_CHARS+1]; // 指令数据(字符串)
+    int len; // 指令长度
+  } cmd;
+  // 等待执行结束的超时ms
+  int timeout;
+  // 等待执行结束的信号量
+  void *hEndSgl;
+  // 应答
+  struct
+  {
+    int ret; // 返回值: >0时执行成功, 表明应答数据的长度; <0时出错(-1超时)
+    char data[MAX_ACK_CHARS+1]; // 应答数据(字符串)
+  } ack;
+} SATCmdTrans;
+
+// 与模块的串口通讯
+typedef struct
+{
+  void *h;             // 打开的串口句柄
+  void *do_cmd_mutex;  // 指令执行互斥量, 同一时刻正在执行的指令只能有一条
+  SATCmdTrans *pTrans; // 执行的指令及其应答结果: 空闲时为空, 工作时不为空
+} SAir720UCom;
+
+static SAir720UCom s_myCom;
+
+// 定义AT指令格式符
+#define CR   '\r'      // 回车
+#define LF   '\n'      // 换行
+#define CRLF "\r\n"    // 回车换行
+#define ATOK "\r\nOK\r\n" // 应答成功
+#define ATER "ERROR"   // 应答失败
+
+// 执行一条指令, 返回: 大于0成功; 小于0失败(-1命令超时)
+static int comio_doCmd(SATCmdTrans *pTrans/*要执行的指令(IN&OUT)*/, int timeout/*等待应答的超时时间, 单位是毫秒*/)
+{
+  SAir720UCom *pComIO = &s_myCom; const char *log_prefix = serial_get_log_prefix(pComIO->h);
+  unsigned long stime, wtime, etime; char *pAtCmdStr; int atCmdLen, ret;
+
+  xgettickcount(&stime);
+  ret = sw_mutex_lock(pComIO->do_cmd_mutex, timeout);
+  if(ret != 0) { pTrans->ack.ret = -1; goto end_p; } // 互斥量上锁超时
+  xgettickcount(&etime); wtime = etime - stime;
+
+  pTrans->hEndSgl = sw_signal_create();
+  if(!pTrans->hEndSgl) { pTrans->ack.ret = -2; goto end_p; }
+
+  pAtCmdStr = (char *)sw_heap_malloc(pTrans->cmd.len+2);
+  if(!pAtCmdStr) { pTrans->ack.ret = -3; goto end_p; }
+  memcpy(pAtCmdStr, pTrans->cmd.data, pTrans->cmd.len);
+  pAtCmdStr[pTrans->cmd.len] = CR; pAtCmdStr[pTrans->cmd.len+1] = '\0';
+  atCmdLen = strlen((const char *)pAtCmdStr);
+
+  serial_recvThrd_pause(pComIO->h); sw_thrd_delay(THRDWAIT_DELAY); // "pComIO->pTrans"的控制权转移前, 先暂停串口数据的接收
+  ret = serial_send_data(pComIO->h, (unsigned char *)pAtCmdStr, atCmdLen); // 发送一条指令
+  sw_heap_free(pAtCmdStr); // 释放AT指令字符串内存
+  if(ret == atCmdLen)
+  {
+    sw_log_debug("[%s] %s send a cmd(%d bytes): %s", MODULE_NAME, log_prefix, pTrans->cmd.len, pTrans->cmd.data);
+  }
+  else
+  {
+    sw_log_error("[%s] %s failed to send a cmd(%d bytes, ret=%d): %s!!", MODULE_NAME, log_prefix, pTrans->cmd.len, ret, pTrans->cmd.data);
+    serial_recvThrd_resume(pComIO->h); pTrans->ack.ret = -4; goto end_p;
+  }
+
+  pTrans->timeout = (wtime > timeout ? 0 : (timeout - wtime));
+  pComIO->pTrans = pTrans;  serial_recvThrd_resume(pComIO->h); // 恢复串口数据接收, "pComIO->pTrans"的控制权转移给接收线程.
+  sw_signal_wait(pTrans->hEndSgl, WAIT_FOREVER); // 等待指令执行结束, "pComIO->pTrans"的控制权收回
+
+end_p:
+  if(pTrans->hEndSgl) sw_signal_destroy(pTrans->hEndSgl);
+  pComIO->pTrans = NULL;
+  sw_mutex_unlock(pComIO->do_cmd_mutex);
+  return pTrans->ack.ret;
+}
+
+// 接收、处理来自Air720U模块的数据报文帧, 串口-线程回调
+static int comio_data_recv_proc(unsigned long wParam/*传递打开的串口句柄*/, unsigned long lParam/*保留暂未使用*/)
+{
+  SAir720UCom *pComIO = &s_myCom; void *pSerial = pComIO->h; SATCmdTrans *pTrans = pComIO->pTrans;
+  const unsigned char *pRecvBuf = serial_get_recv_buffer(pSerial); int nRecvBytes = serial_get_recv_buffer_bytes(pSerial);
+  const char *log_prefix = serial_get_log_prefix(pSerial); bool bPrintRecvBuf = true;
+  static unsigned long enteredWaitAckTime = 0, now; static unsigned long enteredSilentTime = 0; static int nSilentRecvBytes = 0;
+
+  if(!pTrans) { goto ret_p2; } // 无主动指令时
+
+  // 1, 计算命令应答超时
+  if(enteredWaitAckTime == 0) xgettickcount(&enteredWaitAckTime);
+  xgettickcount(&now);
+
+  // 2, 分析应答回复内容
+  if(strstr((const char *)pRecvBuf, ATOK) != NULL || strstr((const char *)pRecvBuf, ATER) != NULL)
+  { // 已应答
+    if(nRecvBytes > nSilentRecvBytes) { enteredSilentTime = now; nSilentRecvBytes = nRecvBytes; }
+    if((now-enteredSilentTime) < R_SILENT_TIMEOUT) { goto ret_p3; } // 等待静默期结束(延期多接收一会数据, 避免"内容"在"ATOK"或"ATER"之后)
+    memcpy(pTrans->ack.data, pRecvBuf, nRecvBytes);
+    pTrans->ack.ret = nRecvBytes; pTrans->ack.data[pTrans->ack.ret] = '\0'; bPrintRecvBuf = false;
+    sw_log_debug("[%s] %s received a cmd ack(%d bytes): %s", MODULE_NAME, log_prefix, pTrans->ack.ret, pTrans->ack.data);
+    goto ret_p1;
+  }
+  else if((now-enteredWaitAckTime) >= pTrans->timeout)
+  { // 已超时
+    sw_log_error("[%s] %s timeout occurred while waiting for the \"%s\" command's ack!!", MODULE_NAME, log_prefix, pTrans->cmd.data);
+    pTrans->ack.ret = -1; pTrans->ack.data[0] = '\0';
+    goto ret_p1;
+  }
+  else
+  { // 继续收
+    goto ret_p3;
+  }
+
+  // 3, 缓存数据接收控制
+ret_p1: // 点亮信号量, 表明本指令执行结束
+  sw_signal_give(pComIO->pTrans->hEndSgl); enteredWaitAckTime = 0; enteredSilentTime = 0; nSilentRecvBytes = 0;
+  goto ret_p2;
+
+ret_p2: // 清接收缓存, 重新开始一轮新指令
+  if(nRecvBytes > 0 && bPrintRecvBuf)
+  {
+    serial_printf_recv_buffer(pSerial, LEVEL_TRACE); // 十六进制打印当前串口接收数据缓存
+    sw_log_warn("[%s] %s discarded %d bytes of meaningless data!", MODULE_NAME, log_prefix, nRecvBytes);
+  }
+  if(nRecvBytes > 0) serial_clear_recv_buffer(pSerial);
+  goto ret_p3;
+
+ret_p3: return 1; // 持续累加的接收新数据
+}
+
+// 打开与模块的通讯, 返回: 0成功, <0时失败
+int Air720U_ComInit()
+{
+  s_myCom.do_cmd_mutex = sw_mutex_create();
+  if(!s_myCom.do_cmd_mutex) { sw_log_error("[%s] error to create a mutex!!", MODULE_NAME); return -1; }
+  s_myCom.pTrans = NULL;
+
+  const char *serialName = "/dev/ttyUSB0"; int baudrate = 115200;
+  const char *parityCheck = "none"; // 无校检
+  s_myCom.h = serial_open(serialName, baudrate, parityCheck, \
+                          comio_data_recv_proc, comio_data_recv_proc, NULL);
+  if(!s_myCom.h)
+  {
+    sw_log_error("[%s] failed to open the \"%s:%d(%s parity)\" device!!", \
+                 MODULE_NAME, serialName, baudrate, parityCheck);
+    sw_mutex_destroy(s_myCom.do_cmd_mutex); return -1;
+  }
+
+  SATCmdTrans trans; memset(&trans, 0, sizeof(SATCmdTrans));
+  strcpy(trans.cmd.data, AT_USE_ECHO); trans.cmd.len = strlen(trans.cmd.data);
+  int ret = comio_doCmd(&trans, WAIT_ACK_TIMEOUT);
+  if(!(ret > 0 && strstr(trans.ack.data, ATOK)))
+  {
+    sw_log_error("[%s] failed to close echo mode!!", MODULE_NAME);
+    Air720U_ComExit(); return -2+ret;
+  }
+
+  return 0;
+}
+
+// 关闭与模块的通讯, 返回: 0成功, <0时失败
+int Air720U_ComExit()
+{
+  if(s_myCom.h) serial_close(s_myCom.h, WAITTHRD_SAFEEXIT_TIMEOUT);
+  if(s_myCom.do_cmd_mutex) sw_mutex_destroy(s_myCom.do_cmd_mutex);
+  memset(&s_myCom, 0, sizeof(s_myCom));
+  return 0;
+}
+
+// 改写sysfs虚拟文件, 返回: 0成功, <0失败
+static int sysfs_write(const char *path, const char *value)
+{
+  int fd = open(path, O_WRONLY);
+  if (fd < 0) return -1;
+  ssize_t len = write(fd, value, strlen(value));
+  if(len != strlen(value)) { close(fd); return -2; }
+  close(fd); return 0;
+}
+
+// 控制模块断电重启, 返回: 0成功, <0时失败
+// 138脚 -- gpio4.IO[20] (4-1)*32+20 = 116 -- 4G_POWER
+int Air720U_Repower()
+{
+  sysfs_write("/sys/class/gpio/unexport",             "116");                // 撤销原导出
+  if(sysfs_write("/sys/class/gpio/export",            "116") < 0) return -2; // 重设新导出
+  if(sysfs_write("/sys/class/gpio/gpio116/direction", "out") < 0) return -3; // 设置为输出
+  if(sysfs_write("/sys/class/gpio/gpio116/value",       "1") < 0) return -4; // 输出高电平-断电
+  sw_thrd_delay(5000);                                                       // 等一段时间-毫秒
+  if(sysfs_write("/sys/class/gpio/gpio116/value",       "0") < 0) return -5; // 输出低电平-上电
+  return 0;
+}
+
+// 获取模块的标识号, 返回: =15成功, <0失败(-1命令超时)
+int Air720U_GetIMEI(char buf[16]/*固定长15个十进制数字组成*/)
+{
+  SATCmdTrans trans; memset(&trans, 0, sizeof(SATCmdTrans));
+  strcpy(trans.cmd.data, AT_GET_IMEI);
+  trans.cmd.len = strlen(trans.cmd.data);
+  int ret = comio_doCmd(&trans, WAIT_ACK_TIMEOUT);
+  if(ret < 0) return ret; // 执行超时或出错
+  else if(strstr(trans.ack.data, ATOK) == NULL) goto end_p; // 未收到成功应答
+
+  const char *p = trans.ack.data, *pLineS, *pLineE; int lineLen, crlfLen = strlen(CRLF);
+lsa_p: // 行扫描, 逐行分析应答结果
+  if((*p) == '\0') goto end_p;
+  pLineS = strstr(p, CRLF); pLineE = NULL; lineLen = 0;
+  if(pLineS) { pLineS += crlfLen; pLineE = strstr(pLineS, CRLF); }
+  if(pLineE) { lineLen = pLineE - pLineS; }
+  if(lineLen == 0)
+  { // 连续两个CRLF, 上面的逻辑保证了"lineLen"只可能大于或等于0, 不会是小于0
+    if(pLineE) { p = pLineE; goto lsa_p; } // 跳第一个CRLF, 继续分析下一行
+    else goto end_p;
+  }
+  //// 示例: "359759002514931"
+  if(lineLen == 15)
+  {
+    bool isHex = true;
+    for(int i = 0; i < lineLen; i++) if(!xisxdigit(pLineS[i])) { isHex = false; break; }
+    if(isHex) { memcpy(buf, pLineS, lineLen); buf[lineLen] = '\0'; return lineLen; } // 成功读到模块的IMEI号
+  }
+  p = pLineE + crlfLen;
+  goto lsa_p; // 继续分析下一行
+
+end_p:
+  return -5;
+}
+
+// 获取网络注册状态, 返回: >=0成功, <0失败(-1命令超时)
+int Air720U_GetCregState()
+{
+  SATCmdTrans trans; memset(&trans, 0, sizeof(SATCmdTrans));
+  strcpy(trans.cmd.data, AT_GET_CREG);
+  trans.cmd.len = strlen(trans.cmd.data);
+  int ret = comio_doCmd(&trans, WAIT_ACK_TIMEOUT);
+  if(ret < 0) return ret; // 执行超时或出错
+  else if(strstr(trans.ack.data, ATOK) == NULL) goto end_p; // 未收到成功应答
+
+  const char *p = trans.ack.data, *pLineS, *pLineE; int lineLen, crlfLen = strlen(CRLF);
+  const char *p1, *p2; char statBuf[3]; int statLen;
+lsa_p: // 行扫描, 逐行分析应答结果
+  if((*p) == '\0') goto end_p;
+  pLineS = strstr(p, CRLF); pLineE = NULL; lineLen = 0;
+  if(pLineS) { pLineS += crlfLen; pLineE = strstr(pLineS, CRLF); }
+  if(pLineE) { lineLen = pLineE - pLineS; }
+  if(lineLen == 0)
+  { // 连续两个CRLF, 上面的逻辑保证了"lineLen"只可能大于或等于0, 不会是小于0
+    if(pLineE) { p = pLineE; goto lsa_p; } // 跳第一个CRLF, 继续分析下一行
+    else goto end_p;
+  }
+  //// 示例: "+CREG: <n>,<stat>"
+  //// 说明: <n>注册状态报告模式, <stat>当前网络注册状态
+  p1 = strstr(pLineS, "+CREG:"); p2 = NULL;
+  if(p1 && p1 < pLineE) { p1 += 6; p2 = strchr(p1, ','); }
+  if(p2 && p2 < pLineE)
+  {
+    p2++; while(*p2 == 0x20 && p2 < pLineE) { p2++; } // 跳过空格
+    statLen = (pLineE - p2); if(statLen != 1 && statLen != 2) return -5; // 状态值范围: 1或2个数字
+    memcpy(statBuf, p2, statLen); statBuf[statLen] = '\0';
+    bool isDigit = true;
+    for(int i = 0; i < strlen(statBuf); i++) if(!xisdigit(statBuf[i])) { isDigit = false; break; }
+    if(isDigit) return atoi(statBuf); // 成功读到模块的网络注册状态值
+    else return -6;
+  }
+  p = pLineE + crlfLen;
+  goto lsa_p; // 继续分析下一行
+
+end_p:
+  return -7;
+}
+
+// 获取当前信号强度, 返回: >=0成功, <0失败(-1命令超时)
+int Air720U_GetRSSIFromCSQ()
+{
+  SATCmdTrans trans; memset(&trans, 0, sizeof(SATCmdTrans));
+  strcpy(trans.cmd.data, AT_GET_CSQ);
+  trans.cmd.len = strlen(trans.cmd.data);
+  int ret = comio_doCmd(&trans, WAIT_ACK_TIMEOUT);
+  if(ret < 0) return ret; // 执行超时或出错
+  else if(strstr(trans.ack.data, ATOK) == NULL) goto end_p; // 未收到成功应答
+
+  const char *p = trans.ack.data, *pLineS, *pLineE; int lineLen, crlfLen = strlen(CRLF);
+  const char *p1, *p2; char rssiBuf[3]; int rssiLen;
+lsa_p: // 行扫描, 逐行分析应答结果
+  if((*p) == '\0') goto end_p;
+  pLineS = strstr(p, CRLF); pLineE = NULL; lineLen = 0;
+  if(pLineS) { pLineS += crlfLen; pLineE = strstr(pLineS, CRLF); }
+  if(pLineE) { lineLen = pLineE - pLineS; }
+  if(lineLen == 0)
+  { // 连续两个CRLF, 上面的逻辑保证了"lineLen"只可能大于或等于0, 不会是小于0
+    if(pLineE) { p = pLineE; goto lsa_p; } // 跳第一个CRLF, 继续分析下一行
+    else goto end_p;
+  }
+  //// 示例: "+CSQ: 15,99"
+  //// 说明: 逗号前第一个数值是RSSI的值
+  p1 = strstr(pLineS, "+CSQ:"); p2 = NULL;
+  if(p1 && p1 < pLineE) { p1 += 5; p2 = strchr(p1, ','); }
+  if(p2 && p2 < pLineE)
+  {
+    while(*p1 == 0x20 && p1 < p2) { p1++; } // 跳过空格
+    rssiLen = (p2 - p1); if(rssiLen != 1 && rssiLen != 2) return -5; // 强度值范围: 0-99, 1或2个数字
+    memcpy(rssiBuf, p1, rssiLen); rssiBuf[rssiLen] = '\0';
+    bool isDigit = true;
+    for(int i = 0; i < strlen(rssiBuf); i++) if(!xisdigit(rssiBuf[i])) { isDigit = false; break; }
+    if(isDigit) return atoi(rssiBuf); // 成功读到模块的接收信号强度值
+    else return -6;
+  }
+  p = pLineE + crlfLen;
+  goto lsa_p; // 继续分析下一行
+
+end_p:
+  return -7;
+}
+
+// 返回电话卡的状态, 返回: 1已可用, <0失败(-1命令超时)
+int Air720U_IsSimCardReady()
+{
+  SATCmdTrans trans; memset(&trans, 0, sizeof(SATCmdTrans));
+  strcpy(trans.cmd.data, AT_GET_PINSTA);
+  trans.cmd.len = strlen(trans.cmd.data);
+  int ret = comio_doCmd(&trans, WAIT_ACK_TIMEOUT);
+  if(ret < 0) return ret; // 执行超时或出错
+  else if(strstr(trans.ack.data, ATOK) && strstr(trans.ack.data, "+CPIN: READY")) return 1;
+  else return -5;
+}
+
+// 获取电话卡标识号, 返回: =20成功, <0失败(-1命令超时)
+int Air720U_GetSimICCID(char buf[21]/*一般由20个十进制数字组成*/)
+{
+  SATCmdTrans trans; memset(&trans, 0, sizeof(SATCmdTrans));
+  strcpy(trans.cmd.data, AT_GET_ICCID);
+  trans.cmd.len = strlen(trans.cmd.data);
+  int ret = comio_doCmd(&trans, WAIT_ACK_TIMEOUT);
+  if(ret < 0) return ret; // 执行超时或出错
+  else if(strstr(trans.ack.data, ATOK) == NULL) goto end_p; // 未收到成功应答
+
+  const char *p = trans.ack.data, *pLineS, *pLineE; int lineLen, crlfLen = strlen(CRLF);
+  const char *p1, *p2; int iccidLen;
+lsa_p: // 行扫描, 逐行分析应答结果
+  if((*p) == '\0') goto end_p;
+  pLineS = strstr(p, CRLF); pLineE = NULL; lineLen = 0;
+  if(pLineS) { pLineS += crlfLen; pLineE = strstr(pLineS, CRLF); }
+  if(pLineE) { lineLen = pLineE - pLineS; }
+  if(lineLen == 0)
+  { // 连续两个CRLF, 上面的逻辑保证了"lineLen"只可能大于或等于0, 不会是小于0
+    if(pLineE) { p = pLineE; goto lsa_p; } // 跳第一个CRLF, 继续分析下一行
+    else goto end_p;
+  }
+  //// 示例: "+ICCID: 89860117831003134201"
+  p1 = strstr(pLineS, "+ICCID:"); p2 = NULL;
+  if(p1 && p1 < pLineE) { p1 += 7; p2 = pLineE; }
+  if(p2)
+  {
+    while(*p1 == 0x20 && p1 < p2) { p1++; } // 跳过空格
+    iccidLen = (p2 - p1); if(iccidLen != 20) return -5; // 长度不对
+    bool isHex = true;
+    for(int i = 0; i < iccidLen; i++) if(!xisxdigit(p1[i])) { isHex = false; break; }
+    if(isHex) { memcpy(buf, p1, iccidLen); buf[iccidLen] = '\0'; return iccidLen; } // 成功读到SIM卡的ICCID号
+    else return -6;
+  }
+  p = pLineE + crlfLen;
+  goto lsa_p; // 继续分析下一行
+
+end_p:
+  return -7;
+}

+ 233 - 0
air720u/air720u.go

@@ -0,0 +1,233 @@
+// Author: NiuJiuRu
+// Email: niujiuru@qq.com
+
+package air720u
+
+import (
+	"os"
+	"sync"
+	"time"
+
+	"hnyfkj.com.cn/rtu/linux/baseapp"
+)
+
+const MODULE_NAME = "Air720U"
+
+var (
+	imei  string // Air720U模块的IMEI号, 唯一标识
+	rssi  string // Air720U模块当前信号强度(RSSI)
+	iccid string // Air720U模块插入SIM卡的ICCID号
+
+	mu                sync.Mutex
+	isRunning         bool
+	healthCheckExitCh chan struct{}
+	wg                sync.WaitGroup
+)
+
+// 初始化4G网络模块
+func ModuleInit(bForceRepower bool /*是否强制重启*/) bool {
+	mu.Lock()
+	defer mu.Unlock()
+
+	if isRunning {
+		return true
+	}
+
+	var err error
+	var ret int
+	var bExists bool
+
+	killAllUdhcpc()
+	err = disableEthBut2()
+	if err != nil {
+		baseapp.Logger.Errorf("[%s] 错误: %v!!", MODULE_NAME, err)
+		return false
+	}
+
+	bExists, _ = udhcpcEth2Exists()
+	if bExists {
+		killEth2Udhcpc()
+	}
+
+	_, statErr := os.Stat("/dev/ttyUSB0")
+	bExists = (statErr == nil)
+
+	if bExists && !bForceRepower {
+		ret, err = air720U_ComInit()
+		if err == nil {
+			goto initOK
+		}
+		switch ret {
+		case -1: // 串口被占用(或不存在, 这里只能是被占用的情况)
+			freeTTYUSB0()
+		case -3: // 设备无应答(初始化时会发送一条关闭回显的指令)
+			air720U_Repower() // 重新上电
+			bExists = false   // 等待复位, 标记设备已不存在
+		}
+	} else { // 设备不存在或函数调用明确要求强制模块重新启动时
+		air720U_Repower() //// 重新上电
+		bExists = false   //// 等待复位, 标记设备已不存在
+	}
+
+	for range 6 {
+		if baseapp.IsExit1() {
+			air720U_ComExit()
+			return false
+		}
+		if !bExists {
+			time.Sleep(5 * time.Second) // 等待设备文件再次出现
+		}
+		ret, err = air720U_ComInit()
+		if err != nil && ret == -1 && !bExists { // 继续等待
+			continue
+		}
+		break
+	}
+
+	if err != nil {
+		air720U_ComExit()
+		baseapp.Logger.Errorf("[%s] 错误: %v!!", MODULE_NAME, err)
+		return false
+	}
+
+initOK:
+	imei, err = air720U_GetIMEI()
+	if err != nil {
+		air720U_ComExit()
+		baseapp.Logger.Errorf("[%s] 错误: %v!!", MODULE_NAME, err)
+		return false
+	}
+	baseapp.Logger.Infof("[%s] 模块IMEI: %s", MODULE_NAME, imei)
+
+	for range 30 { // 等待模块完成蜂窝网络注册, 否则RSSI读取不到, 网也不可能不去
+		if baseapp.IsExit1() {
+			air720U_ComExit()
+			return false
+		}
+		cs, err := air720U_GetCregState()
+		if err != nil || cs == 1 /*已注册本地网*/ || cs == 5 /*已注册漫游网*/ {
+			break
+		}
+		time.Sleep(1 * time.Second)
+	}
+
+	rssi, err = air720U_GetRSSIFromCSQ()
+	if err != nil {
+		air720U_ComExit()
+		baseapp.Logger.Errorf("[%s] 错误: %v!!", MODULE_NAME, err)
+		return false
+	}
+	baseapp.Logger.Infof("[%s] 模块RSSI: %s", MODULE_NAME, rssi)
+
+	bOK, err := air720U_IsSimCardReady()
+	if err != nil {
+		air720U_ComExit()
+		baseapp.Logger.Errorf("[%s] 错误: %v!!", MODULE_NAME, err)
+		return false
+	}
+	baseapp.Logger.Infof("[%s] SIM卡状态: %v", MODULE_NAME, bOK)
+
+	if !bOK {
+		return false
+	}
+
+	iccid, err = air720U_GetSimICCID()
+	if err != nil {
+		air720U_ComExit()
+		baseapp.Logger.Errorf("[%s] 错误: %v!!", MODULE_NAME, err)
+		return false
+	}
+	baseapp.Logger.Infof("[%s] SIM卡ICCID: %s", MODULE_NAME, iccid)
+
+	err = dialupEth2()
+	if err != nil {
+		baseapp.Logger.Errorf("[%s] 拨号连接\"eth2\"时发生错误: %v!!", MODULE_NAME, err)
+		return false
+	}
+	ipv4, mask, err := getEth2Addr()
+	if err != nil {
+		baseapp.Logger.Errorf("[%s] 读取\"eth2\"地址时发生错误: %v!!", MODULE_NAME, err)
+		return false
+	}
+	baseapp.Logger.Infof("[%s] \"eth2\"分配的地址: %s/%s", MODULE_NAME, ipv4, mask)
+
+	healthCheckExitCh = make(chan struct{})
+	wg.Add(1)
+	go func() { // 启动携程守护"eth2"网卡上的"udhcpc"后台服务进程
+		defer wg.Done()
+		monitorEth2Udhcpc(healthCheckExitCh)
+	}()
+	wg.Add(1)
+	go func() { // 启动携程循环读取4G模块的信号强度和ICCID号等信息
+		defer wg.Done()
+		monitorAir720UInfo(healthCheckExitCh)
+	}()
+
+	isRunning = true
+	return isRunning
+}
+
+// 4G调制解调器退出
+func ModuleExit() {
+	mu.Lock()
+	defer mu.Unlock()
+
+	if !isRunning {
+		return
+	}
+
+	close(healthCheckExitCh)
+	wg.Wait() // 等待守护"udhcpc"的携程退出
+
+	bExists, _ := udhcpcEth2Exists()
+	if bExists {
+		killEth2Udhcpc()
+	}
+
+	air720U_ComExit()
+	imei, rssi, iccid = "", "", ""
+	isRunning = false
+}
+
+// 获取模块的标识号
+func GetIMEI() string {
+	mu.Lock()
+	defer mu.Unlock()
+	return imei
+}
+
+// 获取当前信号强度
+func GetRSSI() string {
+	mu.Lock()
+	defer mu.Unlock()
+	return rssi
+}
+
+// 获取电话卡标识号
+func GetSimICCID() string {
+	mu.Lock()
+	defer mu.Unlock()
+	return iccid
+}
+
+// 间隔读取刷新信息
+func monitorAir720UInfo(exitCh <-chan struct{}) {
+	t := time.NewTicker(time.Duration(5) * time.Second)
+	defer t.Stop()
+
+	for {
+		select {
+		case <-t.C:
+			mu.Lock()
+			rssi, _ = air720U_GetRSSIFromCSQ()
+			if bOK, _ := air720U_IsSimCardReady(); bOK {
+				iccid, _ = air720U_GetSimICCID()
+			} else {
+				iccid = ""
+			}
+			mu.Unlock()
+		case <-exitCh:
+			return
+		} // select end
+	} // for end
+}

+ 42 - 0
air720u/air720u.h

@@ -0,0 +1,42 @@
+// Author: NiuJiuRu
+// Email: niujiuru@qq.com
+// Date: 2025-07-31
+#ifndef __AIR720U_H__
+#define __AIR720U_H__
+
+#include "../swapi/include_swapiLib.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+// 打开与模块的通讯, 返回: 0成功, <0时失败
+int Air720U_ComInit();
+
+// 关闭与模块的通讯, 返回: 0成功, <0时失败
+int Air720U_ComExit();
+
+// 控制模块断电重启, 返回: 0成功, <0时失败
+int Air720U_Repower();
+
+// 获取模块的标识号, 返回: =15成功, <0失败(-1命令超时)
+int Air720U_GetIMEI(char buf[16]/*固定长15个十进制数字组成*/);
+
+// 获取网络注册状态, 返回: >=0成功, <0失败(-1命令超时)
+int Air720U_GetCregState();
+
+// 获取当前信号强度, 返回: >=0成功, <0失败(-1命令超时)
+int Air720U_GetRSSIFromCSQ();
+
+// 返回电话卡的状态, 返回: 1已可用, <0失败(-1命令超时)
+int Air720U_IsSimCardReady();
+
+// 获取电话卡标识号, 返回: =20成功, <0失败(-1命令超时)
+int Air720U_GetSimICCID(char buf[21]/*一般由20个十进制数字组成*/);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __AIR720U_H__ */

+ 60 - 0
air720u/air720u_test.c

@@ -0,0 +1,60 @@
+// +build ignore
+
+#include "air720u.h"
+
+// 主函数入口, 测试联网
+int main(int argc,char *argv[])
+{
+  int ret = Air720U_ComInit();
+  if(ret < 0)
+  {
+    sw_log_error("an error occurred while calling the Air720U_ComInit() function(%d)!!", ret);
+    goto end_p;
+  }
+
+  char MMEI[16] = { 0 };
+  ret = Air720U_GetIMEI(MMEI);
+  if(ret < 0)
+  {
+    sw_log_error("an error occurred while calling the Air720U_GetIMEI() function(%d)!!", ret);
+    goto end_p;
+  }
+  sw_log_info("IMEI: %s", MMEI);
+
+  ret = Air720U_GetCregState();
+  if(ret < 0)
+  {
+    sw_log_error("an error occurred while calling the Air720U_GetCregState() function(%d)!!", ret);
+    goto end_p;
+  }
+  sw_log_info("Creg State: %d", ret);
+
+  ret = Air720U_GetRSSIFromCSQ();
+  if(ret < 0)
+  {
+    sw_log_error("an error occurred while calling the Air720U_GetRSSIFromCSQ() function(%d)!!", ret);
+    goto end_p;
+  }
+  sw_log_info("RSSI: %d", ret);
+
+  ret = Air720U_IsSimCardReady();
+  if(ret < 0)
+  {
+    sw_log_error("an error occurred while calling the Air720U_IsSimCardReady() function(%d)!!", ret);
+    goto end_p;
+  }
+  sw_log_info("SIM card status: %d", ret);
+
+  char ICCID[21] = { 0 };
+  ret = Air720U_GetSimICCID(ICCID);
+  if(ret < 0)
+  {
+    sw_log_error("an error occurred while calling the Air720U_GetSimICCID() function(%d)!!", ret);
+    goto end_p;
+  }
+  sw_log_info("ICCID: %s", ICCID);
+
+end_p:
+  Air720U_ComExit();
+  return ret;
+}

+ 88 - 0
air720u/bridge.go

@@ -0,0 +1,88 @@
+// Author: NiuJiuRu
+// Email: niujiuru@qq.com
+
+package air720u
+
+/*
+#include "air720u.h"
+*/
+import "C"
+
+import (
+	"fmt"
+	"strconv"
+	"unsafe"
+)
+
+// 打开与模块的通讯
+func air720U_ComInit() (int, error) {
+	ret := int(C.Air720U_ComInit())
+	if ret != 0 {
+		return ret, fmt.Errorf("an error occurred while calling the C.Air720U_ComInit() function(%d)", ret)
+	}
+	return 0, nil
+}
+
+// 关闭与模块的通讯
+func air720U_ComExit() error {
+	ret := int(C.Air720U_ComExit())
+	if ret != 0 {
+		return fmt.Errorf("an error occurred while calling the C.Air720U_ComExit() function(%d)", ret)
+	}
+	return nil
+}
+
+func air720U_Repower() error {
+	ret := int(C.Air720U_Repower())
+	if ret != 0 {
+		return fmt.Errorf("an error occurred while calling the C.Air720U_Repower() function(%d)", ret)
+	}
+	return nil
+}
+
+// 获取模块的标识号
+func air720U_GetIMEI() (string, error) {
+	var buf [16]byte
+	ret := int(C.Air720U_GetIMEI((*C.char)(unsafe.Pointer(&buf[0]))))
+	if ret != 15 {
+		return "", fmt.Errorf("an error occurred while calling the C.Air720U_GetIMEI() function(%d)", ret)
+	}
+	return C.GoString((*C.char)(unsafe.Pointer(&buf[0]))), nil
+}
+
+// 获取网络注册状态
+func air720U_GetCregState() (int, error) {
+	ret := int(C.Air720U_GetCregState())
+	if ret < 0 {
+		return -1, fmt.Errorf("an error occurred while calling the C.Air720U_GetCregState() function(%d)", ret)
+	}
+	return ret, nil
+}
+
+// 获取当前信号强度
+func air720U_GetRSSIFromCSQ() (string, error) {
+	ret := int(C.Air720U_GetRSSIFromCSQ())
+	if ret < 0 {
+		return "", fmt.Errorf("an error occurred while calling the C.Air720U_GetRSSIFromCSQ() function(%d)", ret)
+	}
+	return strconv.Itoa(ret), nil
+}
+
+// 返回电话卡的状态
+func air720U_IsSimCardReady() (bool, error) {
+	ret := int(C.Air720U_IsSimCardReady())
+	if ret < 0 {
+		return false, fmt.Errorf("an error occurred while calling the C.Air720U_IsSimCardReady() function(%d)", ret)
+	}
+	return ret == 1, nil
+}
+
+// 获取电话卡标识号
+func air720U_GetSimICCID() (string, error) {
+	var buf [21]byte
+	ret := int(C.Air720U_GetSimICCID((*C.char)(unsafe.Pointer(&buf[0]))))
+	if ret != 20 {
+		return "", fmt.Errorf("an error occurred while calling the C.Air720U_GetSimICCID() function(%d)", ret)
+	}
+	return C.GoString((*C.char)(unsafe.Pointer(&buf[0]))), nil
+}

+ 218 - 0
air720u/eth2net.go

@@ -0,0 +1,218 @@
+// Author: NiuJiuRu
+// Email: niujiuru@qq.com
+// 以下函数需"root"权限运行
+
+package air720u
+
+import (
+	"fmt"
+	"io/fs"
+	"net"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"strconv"
+	"strings"
+	"syscall"
+	"time"
+
+	"github.com/sirupsen/logrus"
+	"hnyfkj.com.cn/rtu/linux/baseapp"
+)
+
+// 只保留需要使用的"eth2"网卡, 其它"eth*"网卡都被禁用掉(状态-离线)
+func disableEthBut2() error {
+	ifaces, err := net.Interfaces()
+	if err != nil {
+		return fmt.Errorf("获取网络接口列表失败: %w", err)
+	}
+
+	for _, iface := range ifaces {
+		if !strings.HasPrefix(iface.Name, "eth") || iface.Name == "eth2" {
+			continue
+		}
+
+		cmd := exec.Command("ip", "link", "set", "dev", iface.Name, "down")
+		cmd.Stdout = baseapp.Logger.WriterLevel(logrus.DebugLevel)
+		cmd.Stderr = baseapp.Logger.WriterLevel(logrus.ErrorLevel)
+		if err := cmd.Run(); err != nil {
+			return fmt.Errorf("关闭网口\"%s\"失败: %w", iface.Name, err)
+		}
+	}
+
+	return nil
+}
+
+// 分配上网地址, 成功后"udhcpc"会保持后台运行并占用"/dev/ttyUSB0"
+func dialupEth2() error {
+	cmd1 := exec.Command("ip", "link", "set", "dev", "eth2", "up")
+	cmd1.Stdout = baseapp.Logger.WriterLevel(logrus.DebugLevel)
+	cmd1.Stderr = baseapp.Logger.WriterLevel(logrus.ErrorLevel)
+	if err := cmd1.Run(); err != nil {
+		return fmt.Errorf("启动网口\"eth2\"失败: %w", err)
+	}
+
+	eth2pid := baseapp.RUN_DIR + "/udhcpc.eth2.pid"
+	cmd2 := exec.Command("udhcpc", "-b", "-i", "eth2", "-p", eth2pid)
+	cmd2.Stdout = baseapp.Logger.WriterLevel(logrus.DebugLevel)
+	cmd2.Stderr = baseapp.Logger.WriterLevel(logrus.ErrorLevel)
+	if err := cmd2.Run(); err != nil {
+		return fmt.Errorf("\"eth2\"请求地址失败: %w", err)
+	}
+
+	return nil
+}
+
+// 检测"eth2"网口上的"udhcpc"后台进程是否正在运行, 只保持一个实例
+func udhcpcEth2Exists() (bool, error) {
+	eth2pid := baseapp.RUN_DIR + "/udhcpc.eth2.pid"
+	data, err := os.ReadFile(eth2pid)
+	if err != nil {
+		return false, err
+	}
+	pid, err := strconv.Atoi(strings.TrimSpace(string(data)))
+	if err != nil {
+		return false, err
+	}
+	err = syscall.Kill(pid, 0)
+	if err == nil { // 存在
+		return true, nil
+	}
+	if err == syscall.ESRCH { // 不存在
+		return false, nil
+	}
+	return false, err
+}
+
+// 杀死"eth2"网口上的"udhcpc"进程(根据上次运行时它的PID-文件记录)
+func killEth2Udhcpc() error {
+	eth2pid := baseapp.RUN_DIR + "/udhcpc.eth2.pid"
+	data, err := os.ReadFile(eth2pid)
+	if err != nil {
+		return err
+	}
+	pid, err := strconv.Atoi(strings.TrimSpace(string(data)))
+	if err != nil {
+		return err
+	}
+	if err := syscall.Kill(pid, syscall.SIGTERM); err != nil && err != syscall.ESRCH {
+		syscall.Kill(pid, syscall.SIGKILL)
+	}
+	return nil
+}
+
+// 强制杀死所有运行中的"udhcpc"进程,包括驻留在后台运行的(SIGKILL)
+func killAllUdhcpc() {
+	cmd := exec.Command("sh", "-c", `ps | grep '[u]dhcpc' | awk '{print $1}'`)
+	output, err := cmd.Output()
+	if err != nil {
+		return // 没找到也不是错误
+	}
+
+	pids := strings.FieldsSeq(string(output))
+	for pidStr := range pids {
+		pid, err := strconv.Atoi(pidStr)
+		if err != nil {
+			continue
+		}
+		if err := syscall.Kill(pid, syscall.SIGTERM); err != nil && err != syscall.ESRCH {
+			syscall.Kill(pid, syscall.SIGKILL)
+		}
+	}
+}
+
+// 运行"udhcpc"后, 获取"eth2"网口分配到的IPv4地址, 并校检其合法性
+func getEth2Addr() (ip, mask string, err error) {
+	iface, err := net.InterfaceByName("eth2")
+	if err != nil {
+		return "", "", fmt.Errorf("找不到网络接口\"eth2\": %w", err)
+	}
+
+	addrs, err := iface.Addrs()
+	if err != nil {
+		return "", "", fmt.Errorf("获取\"eth2\"的地址失败: %w", err)
+	}
+
+	for _, addr := range addrs {
+		ipNet, ok := addr.(*net.IPNet)
+		if !ok {
+			continue
+		}
+
+		ip4 := ipNet.IP.To4()
+		if ip4 == nil {
+			continue
+		}
+
+		if ip4.IsPrivate() { // 判断得到IP地址是否合法
+			return ip4.String(), net.IP(ipNet.Mask).String(), nil
+		} else {
+			return "", "", fmt.Errorf("分配给\"eth2\"的地址\"%s\"无效", ip4.String())
+		}
+	}
+
+	return "", "", fmt.Errorf("在\"eth2\"上未找到有效的IPv4 地址")
+}
+
+// 查找并杀死所有占用"/dev/ttyUSB0"设备的进程,返回被杀死进程的PID
+func freeTTYUSB0() ([]int, error) {
+	var pids []int
+	seen := make(map[int]struct{})
+
+	err := filepath.WalkDir("/proc", func(path string, d fs.DirEntry, walkErr error) error {
+		if walkErr != nil {
+			return nil
+		}
+		if filepath.Base(filepath.Dir(path)) != "fd" {
+			return nil
+		}
+		link, err := os.Readlink(path)
+		if err != nil || link != "/dev/ttyUSB0" {
+			return nil
+		}
+		parts := strings.Split(path, "/")
+		if len(parts) < 3 {
+			return nil
+		}
+		pid, err := strconv.Atoi(parts[2])
+		if err != nil {
+			return nil
+		}
+		if _, exists := seen[pid]; exists {
+			return nil // 已处理过这个PID, 跳过
+		}
+		seen[pid] = struct{}{}
+
+		if err := syscall.Kill(pid, syscall.SIGTERM); err != nil && err != syscall.ESRCH {
+			syscall.Kill(pid, syscall.SIGKILL)
+		}
+
+		pids = append(pids, pid)
+		return nil
+	})
+
+	return pids, err
+}
+
+// 定时检测"eth2"网卡上的"udhcpc"后台服务进程, 发现退出时自动拉起
+func monitorEth2Udhcpc(exitCh <-chan struct{}) {
+	t := time.NewTicker(time.Duration(5) * time.Second)
+	defer t.Stop()
+
+	for {
+		select {
+		case <-t.C:
+			bExists, _ := udhcpcEth2Exists()
+			if !bExists { // 清场一次
+				killAllUdhcpc()
+				disableEthBut2()
+			}
+			if !bExists && dialupEth2() == nil { // 重新进场
+				ip, mask, _ := getEth2Addr()
+				baseapp.Logger.Warnf("[%s] \"eth2\"重新分配的地址: %s/%s!", MODULE_NAME, ip, mask)
+			}
+		case <-exitCh:
+			return
+		} // select end
+	} // for end
+}

+ 72 - 0
baseapp/app.go

@@ -0,0 +1,72 @@
+// Author: NiuJiuRu
+// Email: niujiuru@qq.com
+
+package baseapp
+
+import (
+	"fmt"
+	"os"
+	"os/signal"
+	"path/filepath"
+	"sync/atomic"
+	"syscall"
+
+	"github.com/alexflint/go-filemutex"
+)
+
+var Version, BuildTime string // 由Makefile传入
+
+var isExit atomic.Bool
+var exitCh = make(chan struct{})
+
+func ModuleInit() {
+	InitPath()
+	InitLogger()
+}
+
+func SingleInstanceRun() { // 非阻塞单实例运行
+	lockFile := filepath.Join(RUN_DIR, EXEC_FILENAME+".lock")
+	mux, err := filemutex.New(lockFile)
+	if err != nil {
+		Logger.Fatalf("An error occurred while calling the filemutex.New() function: %v", err)
+	}
+
+	if err = mux.TryLock(); err != nil {
+		Logger.Warnf("Another instance is already running!")
+		mux.Close()
+		Logger.Infof("Exited")
+		os.Exit(0)
+	}
+
+	pid := os.Getpid()
+	err = os.WriteFile(lockFile, fmt.Appendf(nil, "%d", pid), 0644)
+	if err != nil {
+		Logger.Warnf("Can't to write PID to the \"%s\" file: %v!", lockFile, err)
+	}
+
+	ch := make(chan os.Signal, 1)
+	signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
+	go func() {
+		for s := range ch {
+			switch s {
+			case syscall.SIGINT, syscall.SIGTERM:
+				Logger.Infof("Received signal: %v", s)
+				mux.Close()
+				os.RemoveAll(lockFile)
+				isExit.Store(true)
+				close(exitCh)
+				return
+			default:
+				Logger.Warnf("Received unexpected signal: %v!", s)
+			}
+		}
+	}()
+}
+
+func IsExit1() bool {
+	return isExit.Load()
+}
+
+func IsExit2() <-chan struct{} {
+	return exitCh
+}

+ 99 - 0
baseapp/args.go

@@ -0,0 +1,99 @@
+// Author: NiuJiuRu
+// Email: niujiuru@qq.com
+
+package baseapp
+
+import (
+	"os"
+	"strconv"
+	"strings"
+)
+
+// 解析命令行参数os.Args参数到map, 以'-'开头的视为key, 后面跟着的为value
+var os_args_param map[string]string = make(map[string]string)
+
+func init() {
+	procArgsParam(os.Args)
+}
+
+func GetArgsParamStr(p string, def string) string {
+	s, ok := os_args_param[p]
+	if ok {
+		return s
+	} else {
+		return def
+	}
+}
+
+func GetArgsParamBool(p string, def bool) bool {
+	s, ok := os_args_param[p]
+	if ok {
+		return strings.EqualFold(s, "y") || strings.EqualFold(s, "yes") || strings.EqualFold(s, "true")
+	} else {
+		return def
+	}
+}
+
+func GetArgsParamInt64(p string, def int64) int64 {
+	s, ok := os_args_param[p]
+	if ok {
+		i, e := strconv.ParseInt(s, 10, 64)
+		if e != nil {
+			return def
+		}
+		return i
+	} else {
+		return def
+	}
+}
+
+func GetArgsParamInt(p string, def int) int {
+	s, ok := os_args_param[p]
+	if ok {
+		i, e := strconv.Atoi(s)
+		if e != nil {
+			return def
+		}
+		return i
+	} else {
+		return def
+	}
+}
+
+func procArgsParam(p []string) {
+	if len(p) < 1 {
+		return
+	}
+
+	var k, v string
+	for i := 1; i < len(p); i++ {
+		if len(p[i]) < 1 {
+			continue
+		}
+
+		if p[i][0] == '-' {
+			if k != "" {
+				os_args_param[k] = v
+			}
+			k, v = p[i], ""
+		} else {
+			if k == "" {
+				continue
+			}
+			if v != "" {
+				v += " " + p[i]
+			} else {
+				v = p[i]
+			}
+		}
+	}
+
+	if k != "" {
+		os_args_param[k] = v
+	}
+}
+
+func IsArgsParam(k string) bool {
+	_, ok := os_args_param[k]
+	return ok
+}

+ 207 - 0
baseapp/log.go

@@ -0,0 +1,207 @@
+// Author: NiuJiuRu
+// Email: niujiuru@qq.com
+
+package baseapp
+
+import "C"
+
+import (
+	"fmt"
+	"io"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"github.com/sirupsen/logrus"
+	"gopkg.in/ini.v1"
+	"gopkg.in/natefinch/lumberjack.v2"
+)
+
+// 日志级别
+type level uint32
+
+const (
+	LEVEL_TRACE level = level(logrus.TraceLevel) // trace
+	LEVEL_DEBUG       = level(logrus.DebugLevel) // debug
+	LEVEL_INFO        = level(logrus.InfoLevel)  // info
+	LEVEL_WARN        = level(logrus.WarnLevel)  // warning
+	LEVEL_ERROR       = level(logrus.ErrorLevel) // error
+	LEVEL_FATAL       = level(logrus.FatalLevel) // fatal, 会结束程序运行, 会自动调用os.Exit(1)
+	LEVEL_PANIC       = level(logrus.PanicLevel) // panic, 会触发程序崩溃, 不处理的话, 程序退出
+)
+
+func (l *level) fromString(s string) {
+	switch strings.ToLower(s) {
+	case "trace":
+		*l = LEVEL_TRACE
+	case "debug":
+		*l = LEVEL_DEBUG
+	case "warn":
+		*l = LEVEL_WARN
+	case "error":
+		*l = LEVEL_ERROR
+	case "fatal":
+		*l = LEVEL_FATAL
+	case "panic":
+		*l = LEVEL_PANIC
+	default:
+		*l = LEVEL_INFO
+	}
+}
+
+// 输出目标
+type target uint32
+
+const (
+	TARGET_NONE    target = iota      // 不输出日志
+	TARGET_CONSOLE target = 1 << iota // 控制台输出
+	TARGET_FILE                       // 输出到文件
+)
+
+func (t *target) fromString(s string) {
+	switch strings.ToLower(s) {
+	case "console":
+		*t = TARGET_CONSOLE
+	case "file":
+		*t = TARGET_FILE
+	case "all":
+		*t = (TARGET_CONSOLE | TARGET_FILE)
+	default:
+		*t = TARGET_NONE
+	}
+}
+
+// 输出格式
+type formatter struct{}
+
+func (f *formatter) Format(entry *logrus.Entry) ([]byte, error) {
+	msg := ""
+	pid := os.Getpid()
+
+	if entry.Caller != nil {
+		file := filepath.Base(entry.Caller.File)
+		line := entry.Caller.Line
+		msg = fmt.Sprintf("[%s, PID: %d] [%s] (%s:%d): %s\n", entry.Time.Format("2006-01-02 15:04:05"), pid, entry.Level.String(), file, line, entry.Message)
+	} else {
+		msg = fmt.Sprintf("[%s, PID: %d] [%s]: %s\n", entry.Time.Format("2006-01-02 15:04:05"), pid, entry.Level.String(), entry.Message)
+	}
+
+	return []byte(msg), nil
+}
+
+// 日志配置
+type config struct {
+	// 日志输出级别
+	Level level
+
+	// 日志输出目标
+	Target target
+
+	// 每个日志文件的最大大下, 以"MB"为单位
+	MaxSize int `ini:"MaxFileSize"`
+
+	// 保留日志文件的最大天数, 以"天"为单位
+	MaxAge int `ini:"MaxReserveDays"`
+
+	// 保留的最大备份文件数量, 以"个"为单位
+	MaxBackups int `ini:"MaxBackupFileCnts"`
+
+	// 轮转文件是否压缩(gzip)减少占用的空间
+	Compress bool `ini:"IsCompress"`
+}
+
+var (
+	Logger        *logrus.Logger
+	logFileWriter *lumberjack.Logger
+	cfgLog        = &config{
+		Level:      LEVEL_TRACE,
+		Target:     TARGET_CONSOLE,
+		MaxSize:    0,
+		MaxAge:     0,
+		MaxBackups: 0,
+		Compress:   true,
+	}
+)
+
+func InitLogger() {
+	cfgFile := filepath.Join(CFG_DIR, "config.ini")
+	cfgIni, err := ini.Load(cfgFile) // 从配置文件中加载相关配置项覆盖默认值
+	if err == nil && cfgIni.HasSection("Log") {
+		tmpCfgLog := *cfgLog
+		err = cfgIni.Section("Log").MapTo(&tmpCfgLog)
+		if err != nil {
+			fmt.Printf("Failed to load the \"[Log]\" section data from the \"%s\" file: %v\n", cfgFile, err)
+		} else {
+			*cfgLog = tmpCfgLog
+		}
+		if cfgIni.Section("Log").HasKey("Level") {
+			cfgLog.Level.fromString(cfgIni.Section("Log").Key("Level").String())
+		}
+		if cfgIni.Section("Log").HasKey("Target") {
+			cfgLog.Target.fromString(cfgIni.Section("Log").Key("Target").String())
+		}
+	}
+
+	Logger = logrus.New()
+	Logger.SetLevel(logrus.Level(cfgLog.Level))
+	if cfgLog.Level == LEVEL_TRACE || cfgLog.Level == LEVEL_DEBUG {
+		Logger.SetReportCaller(true) // 使得输出日志时能够获取到文件名和行号
+	}
+	Logger.SetFormatter(new(formatter))
+
+	writers := make([]io.Writer, 0)
+	if (cfgLog.Target & TARGET_CONSOLE) != 0 {
+		writers = append(writers, os.Stdout)
+	}
+	if (cfgLog.Target & TARGET_FILE) != 0 {
+		logFile := filepath.Join(LOG_DIR, EXEC_FILENAME+".log")
+		logFileWriter = &lumberjack.Logger{Filename: logFile, MaxSize: cfgLog.MaxSize, MaxAge: cfgLog.MaxAge,
+			MaxBackups: cfgLog.MaxBackups, Compress: cfgLog.Compress}
+		writers = append(writers, logFileWriter)
+	}
+
+	if len(writers) > 0 {
+		multiWriter := io.MultiWriter(writers...)
+		Logger.SetOutput(multiWriter)
+	} else {
+		Logger.SetOutput(io.Discard) // 不输出
+	}
+}
+
+func ExitLogger() {
+	if Logger != nil {
+		Logger.Out = io.Discard
+	}
+	if logFileWriter != nil {
+		logFileWriter.Close() // 关闭日志文件, 只是将日志提交到内核缓存区, 如果要强制落盘, 避免日志丢失,
+		// 需要修改开源库代码, 在关闭函数中调用"l.file.Sync()"方法并等待一会儿, 20251021 by niujiuru.
+		logFileWriter = nil
+	}
+}
+
+//export LogFromGo
+func LogFromGo(level *C.char, file *C.char, line C.int, message *C.char) {
+	goLevel := C.GoString(level)
+	goMessage := C.GoString(message)
+
+	if (cfgLog.Level == LEVEL_TRACE || cfgLog.Level == LEVEL_DEBUG) && line > 0 {
+		gofile := filepath.Base(C.GoString(file))
+		goline := int(line)
+		goMessage = fmt.Sprintf("(from %s:%d): %s", gofile, goline, goMessage)
+	}
+
+	switch goLevel {
+	case "trace":
+		Logger.Tracef("%s", goMessage)
+	case "debug":
+		Logger.Debugf("%s", goMessage)
+	case "info":
+		Logger.Infof("%s", goMessage)
+	case "warn":
+		Logger.Warnf("%s", goMessage)
+	case "error":
+		Logger.Errorf("%s", goMessage)
+	case "fatal":
+		Logger.Fatalf("%s", goMessage)
+	}
+}

+ 71 - 0
baseapp/path.go

@@ -0,0 +1,71 @@
+// Author: NiuJiuRu
+// Email: niujiuru@qq.com
+
+package baseapp
+
+import (
+	"fmt"
+	"os"
+	"os/exec"
+	"path/filepath"
+)
+
+// 当前可执行文件的路径
+var EXEC_DIR string
+
+// 当前可执行文件的名字
+var EXEC_FILENAME string
+
+// 配置文件路径
+var CFG_DIR string
+
+// 程序日志目录
+var LOG_DIR string
+
+// 记录运行状态
+var RUN_DIR string
+
+// 变动缓存文件
+var VAR_DIR string
+
+// 相机图片目录
+var IMG_DIR string
+
+func InitPath() {
+	file, err := exec.LookPath(os.Args[0])
+	if err != nil {
+		fmt.Printf("An error occurred while calling the exec.LookPath() function: %v\n", err)
+		os.Exit(1)
+	}
+
+	path, err := filepath.Abs(file)
+	if err != nil {
+		fmt.Printf("An error occurred while calling the filepath.Abs() function: %v\n", err)
+		os.Exit(1)
+	}
+
+	EXEC_DIR = filepath.Dir(path)
+	EXEC_FILENAME = filepath.Base(path)
+
+	CFG_DIR = filepath.Join(EXEC_DIR, "config")
+	LOG_DIR = filepath.Join(EXEC_DIR, "log")
+	RUN_DIR = filepath.Join(EXEC_DIR, "status")
+	VAR_DIR = filepath.Join(EXEC_DIR, "var")
+	IMG_DIR = filepath.Join(EXEC_DIR, "cam_img")
+
+	for _, dir := range []string{CFG_DIR, LOG_DIR, RUN_DIR, VAR_DIR, IMG_DIR} {
+		if err := ExistsDir(dir, true); err != nil {
+			fmt.Printf("Failed to create the %s directory: %v\n", dir, err)
+			os.Exit(1)
+		}
+	}
+}
+
+func ExistsDir(dir string, create bool) error {
+	var err error
+	_, err = os.Stat(dir)
+	if os.IsNotExist(err) && create {
+		err = os.MkdirAll(dir, os.ModePerm)
+	}
+	return err
+}

+ 55 - 0
baseapp/ver.go

@@ -0,0 +1,55 @@
+// Author: NiuJiuRu
+// Email: niujiuru@qq.com
+
+package baseapp
+
+import (
+	"fmt"
+	"strconv"
+	"strings"
+)
+
+// 用32位无符号整数表示版本号, 组成格式:
+// [major(8bit)][minor(8bit)][patch(8bit)][build(8bit)]
+// 对应的字符串组成格式必须为: "x.y.z.w"
+type VersionCode uint32
+
+func NewVersionCode(major, minor, patch, build uint32) VersionCode {
+	return VersionCode(major<<24 | minor<<16 | patch<<8 | build)
+}
+
+func (v *VersionCode) FromString(s string) error {
+	parts := strings.Split(s, ".")
+	if len(parts) != 4 {
+		return fmt.Errorf("invalid version string: %s", s)
+	}
+
+	var u uint32
+	for i, p := range parts {
+		n, err := strconv.Atoi(p)
+		if err != nil || n < 0 || n > 255 {
+			return fmt.Errorf("invalid version part: %s", p)
+		}
+		u |= uint32(n) << uint((3-i)*8)
+	}
+	*v = VersionCode(u)
+	return nil
+}
+
+func (v VersionCode) String() string {
+	return fmt.Sprintf("%d.%d.%d.%d", v.Major(), v.Minor(), v.Patch(), v.Build())
+}
+
+func (v VersionCode) Parts() [4]uint32 {
+	shifts := [4]uint{24, 16, 8, 0}
+	var parts [4]uint32
+	for i, s := range shifts {
+		parts[i] = uint32(v>>s) & 0xFF
+	}
+	return parts
+}
+
+func (v VersionCode) Major() uint32 { return v.Parts()[0] }
+func (v VersionCode) Minor() uint32 { return v.Parts()[1] }
+func (v VersionCode) Patch() uint32 { return v.Parts()[2] }
+func (v VersionCode) Build() uint32 { return v.Parts()[3] }

+ 13 - 0
docs/4G网络可访问白名单网址20250707.txt

@@ -0,0 +1,13 @@
+www.hnyfwlw.com   // 大数据平台域
+www.yfzhwlw.com   // 四情平台域名
+lyq.yfznscd.com   // 路由器设备管理平台
+210.72.145.44     // ntp对时服务器1
+ntp.aliyun.com    // ntp对时服务器2
+ntp.ntsc.ac.cn    // ntp对时服务器3
+*.ntp.org.cn      // ntp对时服务器3		
+*.rt-thread.org   // 网络状态检测
+www.aliyun.com    // 网络状态检测
+223.5.5.5         // 网络状态检测
+117.190.40.178    // 易丰平台地址
+8.136.98.49       // 大数据平台地址
+120.27.222.26     // 四情平台地址

BIN
docs/Air530Z定位模块使用手册V1.4.pdf


BIN
docs/Luat4G模块AT命令手册V4.3.3.pdf


+ 19 - 0
go.mod

@@ -0,0 +1,19 @@
+module hnyfkj.com.cn/rtu/linux
+
+go 1.24.2
+
+require (
+	github.com/alexflint/go-filemutex v1.3.0
+	github.com/beevik/ntp v1.5.0
+	github.com/jlaffaye/ftp v0.2.0
+	github.com/sirupsen/logrus v1.9.3
+	gopkg.in/ini.v1 v1.67.0
+	gopkg.in/natefinch/lumberjack.v2 v2.2.1
+)
+
+require (
+	github.com/hashicorp/errwrap v1.0.0 // indirect
+	github.com/hashicorp/go-multierror v1.1.1 // indirect
+	golang.org/x/net v0.44.0 // indirect
+	golang.org/x/sys v0.36.0 // indirect
+)

+ 37 - 0
go.sum

@@ -0,0 +1,37 @@
+github.com/alexflint/go-filemutex v1.3.0 h1:LgE+nTUWnQCyRKbpoceKZsPQbs84LivvgwUymZXdOcM=
+github.com/alexflint/go-filemutex v1.3.0/go.mod h1:U0+VA/i30mGBlLCrFPGtTe9y6wGQfNAWPBTekHQ+c8A=
+github.com/beevik/ntp v1.5.0 h1:y+uj/JjNwlY2JahivxYvtmv4ehfi3h74fAuABB9ZSM4=
+github.com/beevik/ntp v1.5.0/go.mod h1:mJEhBrwT76w9D+IfOEGvuzyuudiW9E52U2BaTrMOYow=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
+github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
+github.com/jlaffaye/ftp v0.2.0 h1:lXNvW7cBu7R/68bknOX3MrRIIqZ61zELs1P2RAiA3lg=
+github.com/jlaffaye/ftp v0.2.0/go.mod h1:is2Ds5qkhceAPy2xD6RLI6hmp/qysSoymZ+Z2uTnspI=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
+github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
+github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
+golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
+golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
+golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
+gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
+gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

+ 70 - 0
main.go

@@ -0,0 +1,70 @@
+package main
+
+import (
+	"fmt"
+	"time"
+
+	gps "hnyfkj.com.cn/rtu/linux/air530z"
+	modem "hnyfkj.com.cn/rtu/linux/air720u"
+	baseapp "hnyfkj.com.cn/rtu/linux/baseapp"
+	camera1 "hnyfkj.com.cn/rtu/linux/mvs_usb_takephoto" // 海康USB相机
+	netmgrd "hnyfkj.com.cn/rtu/linux/netmgrd"
+)
+
+func main() {
+	if baseapp.IsArgsParam("-h") {
+		help()
+		return
+	}
+
+	if baseapp.IsArgsParam("-v") {
+		fmt.Println("程序版本:", baseapp.Version, "\n构建时间:", baseapp.BuildTime)
+		return
+	}
+
+	baseapp.ModuleInit()
+	baseapp.SingleInstanceRun() // 异步非阻塞
+	baseapp.Logger.Infof("程序版本: %s 构建时间: %s\n程序开始运行...",
+		baseapp.Version, baseapp.BuildTime)
+
+	// 01, 初始化卫星定位模块
+	gps.ModuleInit()
+
+	// 02, 初始化4G调制解调器
+	if !modem.ModuleInit(false) {
+		goto end_p
+	}
+
+	// 03, 初始化网络管理模块
+	netmgrd.ModuleInit()
+	netmgrd.WaitAllOK(time.Duration(10) * time.Second) // 等待联网成功和NTP时间同步成功
+
+	// 04, 初始化相机拍照模块
+	if !camera1.ModuleInit() {
+		goto end_p
+	}
+
+	// 05, 初始化单片机控制板, Todo: 根据项目不同, 使用的控制版硬件和协议都不同, 具体看情况
+
+	// 06, 后台服务器业务交互, Todo: 根据项目不同, 实现具体的业务逻辑协议都不同, 具体看情况
+
+	// 07, 阻塞等待退出信号量
+	baseapp.IsExit2()
+
+	// 08, 退出程序并释放资源
+end_p:
+	modem.ModuleExit()
+	gps.ModuleExit()
+
+	baseapp.Logger.Info("程序退出")
+	baseapp.ExitLogger() // 安全的关闭日志模块
+}
+
+func help() {
+	h := `
+-h 显示帮助提示
+-v 当前程序版本
+`
+
+	fmt.Println(h)
+}

+ 50 - 0
mvs_usb_takephoto/Makefile

@@ -0,0 +1,50 @@
+.PHONY: build clean
+
+# 头文件
+INCS += -I.
+INCS += -I../swapi
+INCS += -I./include
+
+# 源文件
+SRCS += $(filter-out ../swapi/testLib.c, $(wildcard ../swapi/*.c))
+SRCS += takephoto.c
+
+# .o文件
+OBJS = $(SRCS:.c=.o)
+
+# 编译器
+CC = gcc
+CFLAGS = -Wall -fPIC -O2 -g
+DEFINS = -D_GNU_SOURCE
+
+target ?= x86_64
+ifeq ($(target),armv7hf)
+  CC := arm-linux-gnueabihf-gcc
+	AR := arm-linux-gnueabihf-ar
+endif
+
+# 库文件
+LIBS += -Wl,-Bdynamic -lc -lm -ldl -lpthread
+ifeq ($(target),armv7hf)
+  LIBS += ./lib/armv7hf/./libMvCameraControl.so.4.5.0.3
+else
+  LIBS += ./lib/x86_64/64/libMvCameraControl.so.4.5.0.3
+endif
+
+# 编译和清理
+build : libmvs_usb_takephoto.a takephoto_test.out hkcam_reset.out
+
+%.o : %.c
+	$(CC) $(DEFINS) $(CFLAGS) -c $< $(INCS) -o $@
+
+libmvs_usb_takephoto.a : $(OBJS)
+	$(AR) -cr $@ $(OBJS)
+
+hkcam_reset.out : $(OBJS)
+	$(CC) $(DEFINS) $(CFLAGS) $(OBJS) hkcam_reset.c $(INCS) $(LIBS) -o $@
+
+takephoto_test.out : $(OBJS)
+	$(CC) $(DEFINS) $(CFLAGS) $(OBJS) takephoto_test.c $(INCS) $(LIBS) -o $@
+
+clean :
+	rm -rf $(OBJS) *.out *.a *.jpg *.bmp *.png *.tif config/ log/ status/ var/ MvSdkLog/

+ 67 - 0
mvs_usb_takephoto/bridge.go

@@ -0,0 +1,67 @@
+// Author: NiuJiuRu
+// Email: niujiuru@qq.com
+
+package mvs_usb_takephoto
+
+/*
+#include "takephoto.h"
+*/
+import "C"
+
+import (
+	"fmt"
+	"unsafe"
+)
+
+// 图像类型
+const (
+	IMG_TYPE_BMP = 1 // 拍照输出"bmp"图像
+	IMG_TYPE_JPG = 2 // 拍照输出"jpg"图像
+)
+
+// 图像水印
+type SImgMark struct {
+	CamModelName    string  // 相机型号名
+	CamSerialNum    string  // 相机序列号
+	ImgExposureTime float32 // 曝光时间值
+}
+
+// 获取系统当前USBFS内存大小(MB), 成功返回: >=0, 失败返回: -1值
+func getSysUsbfsMemCurrentSize() int {
+	ret := int(C.GetSysUsbfsMemCurrentSize())
+	return ret
+}
+
+// 设置系统新的USBFS内存大小(MB), 成功返回: 0值, 失败返回: -1值
+func setSysUsbfsMemSize(val int) int {
+	setNewV := C.int(val)
+	ret := int(C.SetSysUsbfsMemSize(setNewV))
+	return ret
+}
+
+// 单次执行相机拍照, 并保存到文件, 成功返回: 本次拍照图像的水印信息, 失败返回: 错误原因和空的水印信息
+// 参数说明:
+// "imgType"         - 图像保存类型: 1-".bmp", 2-".jpg"
+// "saveImgFilename" - 保存的文件名: 根据所选保存图像的类型, 程序会自动校检和处理文件的扩展名(智能)
+// "timeout"         - 等待超时时间, 单位:秒: < 0 表示无超时; 无论超时怎么设置, 首次尝试拍照一定会
+// 执行, 但时间不确定; 拍照成功、超时(相机持续无数据的时间)或发生错误时会自动结束任务.
+func TakePhoto(imgType int, saveImgFilename string, timeout int) (SImgMark, error) {
+	if (imgType != IMG_TYPE_BMP && imgType != IMG_TYPE_JPG) || len(saveImgFilename) == 0 {
+		return SImgMark{}, fmt.Errorf("invalid arguments")
+	}
+
+	filename := C.CString(saveImgFilename)
+	defer C.free(unsafe.Pointer(filename))
+
+	var imgMark C.SImgMark
+	ret := int(C.TakePhoto(C.EImgType(imgType), filename, C.int(timeout), &imgMark))
+	if ret != 0 {
+		return SImgMark{}, fmt.Errorf("an error occurred while calling the C.TakePhoto() function(%d)", ret)
+	}
+
+	return SImgMark{
+		CamModelName:    C.GoString((*C.char)(unsafe.Pointer(&imgMark.camModelName[0]))),
+		CamSerialNum:    C.GoString((*C.char)(unsafe.Pointer(&imgMark.camSerialNum[0]))),
+		ImgExposureTime: float32(imgMark.imgExposureTime),
+	}, nil
+}

+ 69 - 0
mvs_usb_takephoto/hkcam_reset.c

@@ -0,0 +1,69 @@
+// +build ignore
+
+#include "./include/MvCameraControl.h"
+#include "../swapi/include_swapiLib.h"
+
+const char *MODULE_NAME = "HKCamReset";
+
+int main(int argc,char *argv[])
+{
+  HANDLE hCam = NULL; MV_CC_DEVICE_INFO_LIST devList = { 0 };
+  MV_CC_DEVICE_INFO *pDevInfo; int ret;
+
+  // 1, 查找相机
+  ret = MV_CC_Initialize();
+  if(MV_OK != ret)
+  {
+    sw_log_error("[%s] 相机SDK初始化失败, errCode=0x%x!!", MODULE_NAME, ret);
+    goto end_p;
+  }
+
+  ret = MV_CC_EnumDevices(MV_USB_DEVICE, &devList); // 目前只枚举USB连接的相机
+  if(MV_OK != ret)
+  {
+    sw_log_error("[%s] USB口枚举相机失败, errCode=0x%x!!", MODULE_NAME, ret);
+    goto end_p;
+  }
+  if(devList.nDeviceNum != 1)
+  {
+    ret = -1;
+    sw_log_error("[%s] USB口相机数量错误, deviceNum=%u!!", MODULE_NAME, devList.nDeviceNum);
+    goto end_p;
+  }
+
+  pDevInfo = devList.pDeviceInfo[0];
+  if(!pDevInfo)
+  {
+    ret = -2;
+    sw_log_error("[%s] unexpected internal error, unable to obtain detailed information about the industrial camera!!", MODULE_NAME);
+    goto end_p;
+  }
+
+  // 2, 打开相机
+  ret = MV_CC_CreateHandleWithoutLog(&hCam, pDevInfo);
+  if(MV_OK == ret) ret = MV_CC_OpenDevice(hCam, MV_ACCESS_Exclusive, 0);
+  if(MV_OK != ret)
+  {
+    sw_log_error("[%s] USB口相机打开失败, errCode=0x%x!!", MODULE_NAME, ret);
+    goto end_p;
+  }
+
+  // 3, 重置相机
+  ret = MV_CC_SetCommandValue(hCam, "DeviceReset");
+  if(MV_OK != ret)
+  {
+    sw_log_error("[%s] USB口相机重置失败, errCode=0x%x!!", MODULE_NAME, ret);
+    goto end_p;
+  }
+
+  // 4, 关闭相机
+end_p:
+  if(hCam)
+  {
+    MV_CC_CloseDevice(hCam);
+    MV_CC_DestroyHandle(hCam);
+  }
+  MV_CC_Finalize();
+
+  return ret;
+}

Разница между файлами не показана из-за своего большого размера
+ 1330 - 0
mvs_usb_takephoto/include/CameraParams.h


Разница между файлами не показана из-за своего большого размера
+ 2722 - 0
mvs_usb_takephoto/include/MvCameraControl.h


+ 119 - 0
mvs_usb_takephoto/include/MvErrorDefine.h

@@ -0,0 +1,119 @@
+
+#ifndef _MV_ERROR_DEFINE_H_
+#define _MV_ERROR_DEFINE_H_
+
+#include "MvISPErrorDefine.h"
+
+/********************************************************************/
+///  \~chinese
+///  \name 正确码定义
+///  @{
+///  \~english
+///  \name Definition of correct code
+///  @{
+#define MV_OK                       0x00000000  ///< \~chinese 成功,无错误             \~english Successed, no error
+/// @}
+
+/********************************************************************/
+///  \~chinese
+///  \name 通用错误码定义:范围0x80000000-0x800000FF
+///  @{
+///  \~english
+///  \name Definition of General error code
+///  @{
+#define MV_E_HANDLE                 0x80000000  ///< \~chinese 错误或无效的句柄         \~english Error or invalid handle
+#define MV_E_SUPPORT                0x80000001  ///< \~chinese 不支持的功能             \~english Not supported function
+#define MV_E_BUFOVER                0x80000002  ///< \~chinese 缓存已满                 \~english Buffer overflow
+#define MV_E_CALLORDER              0x80000003  ///< \~chinese 函数调用顺序错误         \~english Function calling order error
+#define MV_E_PARAMETER              0x80000004  ///< \~chinese 错误的参数               \~english Incorrect parameter
+#define MV_E_RESOURCE               0x80000006  ///< \~chinese 资源申请失败             \~english Applying resource failed
+#define MV_E_NODATA                 0x80000007  ///< \~chinese 无数据                   \~english No data
+#define MV_E_PRECONDITION           0x80000008  ///< \~chinese 前置条件有误,或运行环境已发生变化   \~english Precondition error, or running environment changed
+#define MV_E_VERSION                0x80000009  ///< \~chinese 版本不匹配               \~english Version mismatches
+#define MV_E_NOENOUGH_BUF           0x8000000A  ///< \~chinese 传入的内存空间不足       \~english Insufficient memory
+#define MV_E_ABNORMAL_IMAGE         0x8000000B  ///< \~chinese 异常图像,可能是丢包导致图像不完整   \~english Abnormal image, maybe incomplete image because of lost packet
+#define MV_E_LOAD_LIBRARY           0x8000000C  ///< \~chinese 动态导入DLL失败          \~english Load library failed
+#define MV_E_NOOUTBUF               0x8000000D  ///< \~chinese 没有可输出的缓存         \~english No Avaliable Buffer
+#define MV_E_ENCRYPT                0x8000000E  ///< \~chinese 加密错误                 \~english Encryption error
+#define MV_E_OPENFILE               0x8000000F  ///< \~chinese 打开文件出现错误         \~english open file error
+#define MV_E_BUF_IN_USE             0x80000010  ///< \~chinese 缓存地址已使用           \~english Buffer already in use
+#define MV_E_BUF_INVALID            0x80000011  ///< \~chinese 无效的缓存地址           \~english Buffer address invalid
+#define MV_E_NOALIGN_BUF            0x80000012  ///< \~chinese 缓存对齐异常             \~english Buffer alignmenterror error
+#define MV_E_NOENOUGH_BUF_NUM       0x80000013  ///< \~chinese 缓存个数不足             \~english Insufficient cache count
+#define MV_E_PORT_IN_USE            0x80000014  ///< \~chinese 串口被占用               \~english Port is in use
+#define MV_E_IMAGE_DECODEC          0x80000015  ///< \~chinese 解码错误(SDK校验图像异常)\~english Decoding error (SDK verification image exception)
+#define MV_E_UINT32_LIMIT           0x80000016  ///  \~chinese 图像大小超过unsigned int返回,接口不支持   
+#define MV_E_IMAGE_HEIGHT           0x80000017  ///  \~chinese 图像高度异常(残帧丢弃) \~english image height anomaly (discard incomplete images)
+
+#define MV_E_UNKNOW                 0x800000FF  ///< \~chinese 未知的错误               \~english Unknown error
+/// @}
+
+/********************************************************************/
+///  \~chinese
+///  \name GenICam系列错误:范围0x80000100-0x800001FF
+///  @{
+///  \~english
+///  \name GenICam Series Error Codes: Range from 0x80000100 to 0x800001FF
+///  @{
+#define MV_E_GC_GENERIC             0x80000100  ///< \~chinese 通用错误                 \~english General error
+#define MV_E_GC_ARGUMENT            0x80000101  ///< \~chinese 参数非法                 \~english Illegal parameters
+#define MV_E_GC_RANGE               0x80000102  ///< \~chinese 值超出范围               \~english The value is out of range
+#define MV_E_GC_PROPERTY            0x80000103  ///< \~chinese 属性                     \~english Property
+#define MV_E_GC_RUNTIME             0x80000104  ///< \~chinese 运行环境有问题           \~english Running environment error
+#define MV_E_GC_LOGICAL             0x80000105  ///< \~chinese 逻辑错误                 \~english Logical error
+#define MV_E_GC_ACCESS              0x80000106  ///< \~chinese 节点访问条件有误         \~english Node accessing condition error
+#define MV_E_GC_TIMEOUT             0x80000107  ///< \~chinese 超时                     \~english Timeout
+#define MV_E_GC_DYNAMICCAST         0x80000108  ///< \~chinese 转换异常                 \~english Transformation exception
+#define MV_E_GC_UNKNOW              0x800001FF  ///< \~chinese GenICam未知错误          \~english GenICam unknown error
+/// @}
+
+/********************************************************************/
+///  \~chinese
+///  \name GigE_STATUS对应的错误码:范围0x80000200-0x800002FF
+///  @{
+///  \~english
+///  \name GigE_STATUS Error Codes: Range from 0x80000200 to 0x800002FF
+///  @{
+#define MV_E_NOT_IMPLEMENTED        0x80000200  ///< \~chinese 命令不被设备支持         \~english The command is not supported by device
+#define MV_E_INVALID_ADDRESS        0x80000201  ///< \~chinese 访问的目标地址不存在     \~english The target address being accessed does not exist
+#define MV_E_WRITE_PROTECT          0x80000202  ///< \~chinese 目标地址不可写           \~english The target address is not writable
+#define MV_E_ACCESS_DENIED          0x80000203  ///< \~chinese 设备无访问权限           \~english No permission
+#define MV_E_BUSY                   0x80000204  ///< \~chinese 设备忙,或网络断开       \~english Device is busy, or network disconnected
+#define MV_E_PACKET                 0x80000205  ///< \~chinese 网络包数据错误           \~english Network data packet error
+#define MV_E_NETER                  0x80000206  ///< \~chinese 网络相关错误             \~english Network error
+#define MV_E_SUPPORT_MODIFY_DEVICE_IP   0x8000020E ///< 在固定IP模式下不支持修改设备IP模式  \~english Current Mode Not Support Modify Ip
+#define MV_E_KEY_VERIFICATION       0x8000020F  ///< \~chinese 秘钥校验错误              \~english SwitchKey error
+#define MV_E_IP_CONFLICT            0x80000221  ///< \~chinese 设备IP冲突               \~english Device IP conflict
+/// @}
+
+/********************************************************************/
+///  \~chinese
+///  \name USB_STATUS对应的错误码:范围0x80000300-0x800003FF
+///  @{
+///  \~english
+///  \name USB_STATUS Error Codes: Range from 0x80000300 to 0x800003FF
+///  @{
+#define MV_E_USB_READ               0x80000300  ///< \~chinese 读usb出错                \~english Reading USB error
+#define MV_E_USB_WRITE              0x80000301  ///< \~chinese 写usb出错                \~english Writing USB error
+#define MV_E_USB_DEVICE             0x80000302  ///< \~chinese 设备异常                 \~english Device exception
+#define MV_E_USB_GENICAM            0x80000303  ///< \~chinese GenICam相关错误          \~english GenICam error
+#define MV_E_USB_BANDWIDTH          0x80000304  ///< \~chinese 带宽不足                 \~english Insufficient bandwidth
+#define MV_E_USB_DRIVER             0x80000305  ///< \~chinese 驱动不匹配或者未装驱动   \~english Driver mismatch or unmounted drive
+#define MV_E_USB_UNKNOW             0x800003FF  ///< \~chinese USB未知的错误            \~english USB unknown error
+/// @}
+
+/********************************************************************/
+///  \~chinese
+///  \name 升级时对应的错误码:范围0x80000400-0x800004FF
+///  @{
+///  \~english
+///  \name Upgrade Error Codes: Range from 0x80000400 to 0x800004FF
+///  @{
+#define MV_E_UPG_FILE_MISMATCH      0x80000400  ///< \~chinese 升级固件不匹配           \~english Firmware mismatches
+#define MV_E_UPG_LANGUSGE_MISMATCH  0x80000401  ///< \~chinese 升级固件语言不匹配       \~english Firmware language mismatches
+#define MV_E_UPG_CONFLICT           0x80000402  ///< \~chinese 升级冲突(设备已经在升级了再次请求升级即返回此错误) \~english Upgrading conflicted (repeated upgrading requests during device upgrade)
+#define MV_E_UPG_INNER_ERR          0x80000403  ///< \~chinese 升级时设备内部出现错误   \~english Camera internal error during upgrade
+#define MV_E_UPG_UNKNOW             0x800004FF  ///< \~chinese 升级时未知错误           \~english Unknown error during upgrade
+/// @}
+
+#endif //_MV_ERROR_DEFINE_H_

+ 98 - 0
mvs_usb_takephoto/include/MvISPErrorDefine.h

@@ -0,0 +1,98 @@
+
+#ifndef _MV_ISP_ERROR_DEFINE_H_
+#define _MV_ISP_ERROR_DEFINE_H_
+
+/************************************************************************
+* 来自ISP算法库的错误码
+************************************************************************/
+// 通用类型
+#define MV_ALG_OK                   0x00000000  //处理正确
+#define MV_ALG_ERR                  0x10000000  //不确定类型错误
+
+// 能力检查
+#define MV_ALG_E_ABILITY_ARG        0x10000001  //能力集中存在无效参数
+
+// 内存检查
+#define MV_ALG_E_MEM_NULL           0x10000002  //内存地址为空
+#define MV_ALG_E_MEM_ALIGN          0x10000003  //内存对齐不满足要求
+#define MV_ALG_E_MEM_LACK           0x10000004  //内存空间大小不够
+#define MV_ALG_E_MEM_SIZE_ALIGN     0x10000005  //内存空间大小不满足对齐要求
+#define MV_ALG_E_MEM_ADDR_ALIGN     0x10000006  //内存地址不满足对齐要求
+
+// 图像检查
+#define MV_ALG_E_IMG_FORMAT         0x10000007  //图像格式不正确或者不支持
+#define MV_ALG_E_IMG_SIZE           0x10000008  //图像宽高不正确或者超出范围
+#define MV_ALG_E_IMG_STEP           0x10000009  //图像宽高与step参数不匹配
+#define MV_ALG_E_IMG_DATA_NULL      0x1000000A  //图像数据存储地址为空
+
+// 输入输出参数检查
+#define MV_ALG_E_CFG_TYPE           0x1000000B  //设置或者获取参数类型不正确
+#define MV_ALG_E_CFG_SIZE           0x1000000C  //设置或者获取参数的输入、输出结构体大小不正确
+#define MV_ALG_E_PRC_TYPE           0x1000000D  //处理类型不正确
+#define MV_ALG_E_PRC_SIZE           0x1000000E  //处理时输入、输出参数大小不正确
+#define MV_ALG_E_FUNC_TYPE          0x1000000F  //子处理类型不正确
+#define MV_ALG_E_FUNC_SIZE          0x10000010  //子处理时输入、输出参数大小不正确
+
+// 运行参数检查
+#define MV_ALG_E_PARAM_INDEX        0x10000011  //index参数不正确
+#define MV_ALG_E_PARAM_VALUE        0x10000012  //value参数不正确或者超出范围
+#define MV_ALG_E_PARAM_NUM          0x10000013  //param_num参数不正确
+
+// 接口调用检查
+#define MV_ALG_E_NULL_PTR           0x10000014  //函数参数指针为空
+#define MV_ALG_E_OVER_MAX_MEM       0x10000015  //超过限定的最大内存
+#define MV_ALG_E_CALL_BACK          0x10000016  //回调函数出错
+
+// 算法库加密相关检查
+#define MV_ALG_E_ENCRYPT            0x10000017  //加密错误
+#define MV_ALG_E_EXPIRE             0x10000018  //算法库使用期限错误
+
+// 内部模块返回的基本错误类型
+#define MV_ALG_E_BAD_ARG            0x10000019  //参数范围不正确
+#define MV_ALG_E_DATA_SIZE          0x1000001A  //数据大小不正确
+#define MV_ALG_E_STEP               0x1000001B  //数据step不正确
+
+// cpu指令集支持错误码
+#define MV_ALG_E_CPUID              0x1000001C  //cpu不支持优化代码中的指令集
+
+#define MV_ALG_WARNING              0x1000001D  //警告
+
+#define MV_ALG_E_TIME_OUT           0x1000001E  //算法库超时
+#define MV_ALG_E_LIB_VERSION        0x1000001F  //算法版本号出错
+#define MV_ALG_E_MODEL_VERSION      0x10000020  //模型版本号出错
+#define MV_ALG_E_GPU_MEM_ALLOC      0x10000021  //GPU内存分配错误
+#define MV_ALG_E_FILE_NON_EXIST     0x10000022  //文件不存在
+#define MV_ALG_E_NONE_STRING        0x10000023  //字符串为空
+#define MV_ALG_E_IMAGE_CODEC        0x10000024  //图像解码器错误
+#define MV_ALG_E_FILE_OPEN          0x10000025  //打开文件错误
+#define MV_ALG_E_FILE_READ          0x10000026  //文件读取错误
+#define MV_ALG_E_FILE_WRITE         0x10000027  //文件写错误
+#define MV_ALG_E_FILE_READ_SIZE     0x10000028  //文件读取大小错误
+#define MV_ALG_E_FILE_TYPE          0x10000029  //文件类型错误
+#define MV_ALG_E_MODEL_TYPE         0x1000002A  //模型类型错误
+#define MV_ALG_E_MALLOC_MEM         0x1000002B  //分配内存错误
+#define MV_ALG_E_BIND_CORE_FAILED   0x1000002C  //线程绑核失败
+
+// 降噪特有错误码
+#define MV_ALG_E_DENOISE_NE_IMG_FORMAT       0x10402001  //噪声特性图像格式错误
+#define MV_ALG_E_DENOISE_NE_FEATURE_TYPE     0x10402002  //噪声特性类型错误
+#define MV_ALG_E_DENOISE_NE_PROFILE_NUM      0x10402003  //噪声特性个数错误
+#define MV_ALG_E_DENOISE_NE_GAIN_NUM         0x10402004  //噪声特性增益个数错误
+#define MV_ALG_E_DENOISE_NE_GAIN_VAL         0x10402005  //噪声曲线增益值输入错误
+#define MV_ALG_E_DENOISE_NE_BIN_NUM          0x10402006  //噪声曲线柱数错误
+#define MV_ALG_E_DENOISE_NE_INIT_GAIN        0x10402007  //噪声估计初始化增益设置错误
+#define MV_ALG_E_DENOISE_NE_NOT_INIT         0x10402008  //噪声估计未初始化
+#define MV_ALG_E_DENOISE_COLOR_MODE          0x10402009  //颜色空间模式错误
+#define MV_ALG_E_DENOISE_ROI_NUM             0x1040200a  //图像ROI个数错误
+#define MV_ALG_E_DENOISE_ROI_ORI_PT          0x1040200b  //图像ROI原点错误
+#define MV_ALG_E_DENOISE_ROI_SIZE            0x1040200c  //图像ROI大小错误
+#define MV_ALG_E_DENOISE_GAIN_NOT_EXIST      0x1040200d  //输入的相机增益不存在(增益个数已达上限)
+#define MV_ALG_E_DENOISE_GAIN_BEYOND_RANGE   0x1040200e  //输入的相机增益不在范围内
+#define MV_ALG_E_DENOISE_NP_BUF_SIZE         0x1040200f  //输入的噪声特性内存大小错误
+
+// 去紫边特有错误码
+#define MV_ALG_E_PFC_ROI_PT                 0x10405000  //去紫边算法ROI原点错误
+#define MV_ALG_E_PFC_ROI_SIZE               0x10405001  //去紫边算法ROI大小错误
+#define MV_ALG_E_PFC_KERNEL_SIZE            0x10405002  //去紫边算法滤波核尺寸错误
+
+#endif //_MV_ISP_ERROR_DEFINE_H_

Разница между файлами не показана из-за своего большого размера
+ 2133 - 0
mvs_usb_takephoto/include/MvObsoleteInterfaces.h


+ 655 - 0
mvs_usb_takephoto/include/ObsoleteCamParams.h

@@ -0,0 +1,655 @@
+
+#ifndef _MV_OBSOLETE_CAM_PARAMS_H_
+#define _MV_OBSOLETE_CAM_PARAMS_H_
+
+#include "PixelType.h"
+
+/// \~chinese 输出帧的信息             \~english Output Frame Information
+typedef struct _MV_FRAME_OUT_INFO_
+{
+    unsigned short      nWidth;             ///< [OUT]  \~chinese 图像宽            \~english Image Width
+    unsigned short      nHeight;            ///< [OUT]  \~chinese 图像高            \~english Image Height
+    enum MvGvspPixelType    enPixelType;    ///< [OUT]  \~chinese 像素格式          \~english Pixel Type
+
+    unsigned int        nFrameNum;          ///< [OUT]  \~chinese 帧号              \~english Frame Number
+    unsigned int        nDevTimeStampHigh;  ///< [OUT]  \~chinese 时间戳高32位      \~english Timestamp high 32 bits
+    unsigned int        nDevTimeStampLow;   ///< [OUT]  \~chinese 时间戳低32位      \~english Timestamp low 32 bits
+    unsigned int        nReserved0;         ///< [OUT]  \~chinese 保留,8字节对齐   \~english Reserved, 8-byte aligned
+    int64_t             nHostTimeStamp;     ///< [OUT]  \~chinese 主机生成的时间戳  \~english Host-generated timestamp
+
+    unsigned int        nFrameLen;
+
+    unsigned int        nLostPacket;  // 本帧丢包数
+    unsigned int        nReserved[2];
+}MV_FRAME_OUT_INFO;
+
+/// \~chinese 保存图片参数            \~english Save image type
+typedef struct _MV_SAVE_IMAGE_PARAM_T_
+{
+    unsigned char*      pData;              ///< [IN]   \~chinese 输入数据缓存      \~english Input Data Buffer
+    unsigned int        nDataLen;           ///< [IN]   \~chinese 输入数据大小      \~english Input Data Size
+    enum MvGvspPixelType    enPixelType;    ///< [IN]   \~chinese 输入像素格式      \~english Input Data Pixel Format
+    unsigned short      nWidth;             ///< [IN]   \~chinese 图像宽            \~english Image Width
+    unsigned short      nHeight;            ///< [IN]   \~chinese 图像高            \~english Image Height
+
+    unsigned char*      pImageBuffer;       ///< [OUT]  \~chinese 输出图片缓存      \~english Output Image Buffer
+    unsigned int        nImageLen;          ///< [OUT]  \~chinese 输出图片大小      \~english Output Image Size
+    unsigned int        nBufferSize;        ///< [IN]   \~chinese 提供的输出缓冲区大小  \~english Output buffer size provided
+    enum MV_SAVE_IAMGE_TYPE enImageType;    ///< [IN]   \~chinese 输出图片格式      \~english Output Image Format
+
+}MV_SAVE_IMAGE_PARAM;
+
+typedef struct _MV_IMAGE_BASIC_INFO_
+{
+    unsigned short      nWidthValue;
+    unsigned short      nWidthMin;
+    unsigned int        nWidthMax;
+    unsigned int        nWidthInc;
+
+    unsigned int        nHeightValue;
+    unsigned int        nHeightMin;
+    unsigned int        nHeightMax;
+    unsigned int        nHeightInc;
+
+    float               fFrameRateValue;
+    float               fFrameRateMin;
+    float               fFrameRateMax;
+
+    unsigned int        enPixelType;        ///< [OUT]  \~chinese 当前的像素格式    \~english Current pixel format
+    unsigned int        nSupportedPixelFmtNum;  ///< [OUT]  \~chinese 支持的像素格式种类    \~english Support pixel format
+    unsigned int        enPixelList[MV_MAX_XML_SYMBOLIC_NUM];
+    unsigned int        nReserved[8];
+
+}MV_IMAGE_BASIC_INFO;
+
+
+/// \~chinese 噪声特性类型    \~english Noise feature type
+typedef enum _MV_CC_BAYER_NOISE_FEATURE_TYPE
+{
+    MV_CC_BAYER_NOISE_FEATURE_TYPE_INVALID = 0, ///<        \~chinese 无效值                        \~english Invalid
+    MV_CC_BAYER_NOISE_FEATURE_TYPE_PROFILE = 1, ///<        \~chinese 噪声曲线                      \~english Noise curve
+    MV_CC_BAYER_NOISE_FEATURE_TYPE_LEVEL   = 2, ///<        \~chinese 噪声水平                      \~english Noise level
+    MV_CC_BAYER_NOISE_FEATURE_TYPE_DEFAULT = 1, ///<        \~chinese 默认值                        \~english Default
+
+}MV_CC_BAYER_NOISE_FEATURE_TYPE;
+
+/// \~chinese Bayer格式降噪特性信息    \~english Denoise profile info
+typedef struct _MV_CC_BAYER_NOISE_PROFILE_INFO_T_
+{
+    unsigned int        nVersion;           ///<  \~chinese 版本                           \~english version
+    MV_CC_BAYER_NOISE_FEATURE_TYPE enNoiseFeatureType;  ///<  \~chinese 噪声特性类型       \~english noise feature type
+    enum MvGvspPixelType    enPixelType;    ///<  \~chinese 图像格式                       \~english image format
+    int                 nNoiseLevel;        ///<  \~chinese 平均噪声水平                   \~english noise level
+    unsigned int        nCurvePointNum;     ///<  \~chinese 曲线点数                       \~english curve point number
+    int*                nNoiseCurve;        ///<  \~chinese 噪声曲线                       \~english noise curve
+    int*                nLumCurve;          ///<  \~chinese 亮度曲线                       \~english luminance curve
+
+    unsigned int        nRes[8];            ///<       \~chinese 预留                           \~english Reserved
+
+}MV_CC_BAYER_NOISE_PROFILE_INFO;
+
+/// \~chinese Bayer格式噪声估计参数    \~english Bayer noise estimate param
+typedef struct _MV_CC_BAYER_NOISE_ESTIMATE_PARAM_T_
+{
+    unsigned int        nWidth;             ///< [IN]  \~chinese 图像宽(大于等于8)              \~english Width
+    unsigned int        nHeight;            ///< [IN]  \~chinese 图像高(大于等于8)              \~english Height
+    enum MvGvspPixelType    enPixelType;    ///< [IN]  \~chinese 像素格式                       \~english Pixel format
+
+    unsigned char*      pSrcData;           ///< [IN]  \~chinese 输入数据缓存                   \~english Input data buffer
+    unsigned int        nSrcDataLen;        ///< [IN]  \~chinese 输入数据大小                   \~english Input data size
+
+    unsigned int        nNoiseThreshold;    ///< [IN]  \~chinese 噪声阈值(0-4095)               \~english Noise Threshold
+
+    unsigned char*      pCurveBuf;          ///< [IN]  \~chinese 用于存储噪声曲线和亮度曲线(需要外部分配,缓存大小:4096 * sizeof(int) * 2)     \~english Buffer used to store noise and brightness curves, size:4096 * sizeof(int) * 2)
+    MV_CC_BAYER_NOISE_PROFILE_INFO stNoiseProfile; ///< [OUT]  \~chinese 降噪特性信息               \~english Denoise profile
+
+    unsigned int        nThreadNum;         ///< [IN]  \~chinese 线程数量,0表示算法库根据硬件自适应;1表示单线程(默认);大于1表示线程数目      \~english Thread number, 0 means that the library is adaptive to the hardware, 1 means single thread(Default value), Greater than 1 indicates the number of threads
+
+    unsigned int        nRes[8];            ///<       \~chinese 预留                           \~english Reserved
+
+}MV_CC_BAYER_NOISE_ESTIMATE_PARAM;
+
+/// \~chinese Bayer格式空域降噪参数    \~english Bayer spatial Denoise param
+typedef struct _MV_CC_BAYER_SPATIAL_DENOISE_PARAM_T_
+{
+    unsigned int        nWidth;             ///< [IN]  \~chinese 图像宽(大于等于8)              \~english Width
+    unsigned int        nHeight;            ///< [IN]  \~chinese 图像高(大于等于8)              \~english Height
+    enum MvGvspPixelType    enPixelType;        ///< [IN]  \~chinese 像素格式                       \~english Pixel format
+
+    unsigned char*      pSrcData;           ///< [IN]  \~chinese 输入数据缓存                   \~english Input data buffer
+    unsigned int        nSrcDataLen;        ///< [IN]  \~chinese 输入数据大小                   \~english Input data size
+
+    unsigned char*      pDstBuf;            ///< [OUT] \~chinese 输出降噪后的数据               \~english Output data buffer
+    unsigned int        nDstBufSize;        ///< [IN]  \~chinese 提供的输出缓冲区大小           \~english Provided output buffer size
+    unsigned int        nDstBufLen;         ///< [OUT] \~chinese 输出降噪后的数据长度           \~english Output data length
+
+    MV_CC_BAYER_NOISE_PROFILE_INFO stNoiseProfile; ///< [IN]  \~chinese 降噪特性信息(来源于噪声估计)   \~english Denoise profile
+    unsigned int        nDenoiseStrength;   ///< [IN]  \~chinese 降噪强度(0-100)                \~english nDenoise Strength   
+    unsigned int        nSharpenStrength;   ///< [IN]  \~chinese 锐化强度(0-32)                 \~english Sharpen Strength
+    unsigned int        nNoiseCorrect;      ///< [IN]  \~chinese 噪声校正系数(0-1280)           \~english Noise Correct  
+
+    unsigned int        nThreadNum;         ///< [IN]  \~chinese 线程数量,0表示算法库根据硬件自适应;1表示单线程(默认);大于1表示线程数目         \~english Thread number, 0 means that the library is adaptive to the hardware, 1 means single thread(Default value), Greater than 1 indicates the number of threads
+
+    unsigned int        nRes[8];            ///<       \~chinese 预留                           \~english Reserved
+
+}MV_CC_BAYER_SPATIAL_DENOISE_PARAM;
+
+/// \~chinese CLUT参数                  \~english CLUT param
+typedef struct _MV_CC_CLUT_PARAM_T_
+{
+    bool                bCLUTEnable;                                ///< [IN]  \~chinese 是否启用CLUT           \~english CLUT enable
+    unsigned int        nCLUTScale;                                 ///< [IN]  \~chinese 量化系数(2的整数幂,最大65536)  \~english Quantitative scale(Integer power of 2, <= 65536)
+    unsigned int        nCLUTSize;                                  ///< [IN]  \~chinese CLUT大小,目前仅支持17     \~english CLUT size, currently only supports 17
+    unsigned char*      pCLUTBuf;                                   ///< [IN]  \~chinese 量化CLUT表             \~english CLUT buffer
+    unsigned int        nCLUTBufLen;                                ///< [IN]  \~chinese 量化CLUT缓存大小(nCLUTSize*nCLUTSize*nCLUTSize*sizeof(int)*3)  \~english CLUT buffer length(nCLUTSize*nCLUTSize*nCLUTSize*sizeof(int)*3)
+
+    unsigned int        nRes[8];                                    ///<       \~chinese 预留                   \~english Reserved
+
+}MV_CC_CLUT_PARAM;
+
+/// \~chinese 锐化结构体                \~english Sharpen structure
+typedef struct _MV_CC_SHARPEN_PARAM_T_
+{
+    unsigned int            nWidth;                                 ///< [IN]  \~chinese 图像宽度(最小8)        \~english Image Width
+    unsigned int            nHeight;                                ///< [IN]  \~chinese 图像高度(最小8)        \~english Image Height
+    unsigned char*          pSrcBuf;                                ///< [IN]  \~chinese 输入数据缓存           \~english Input data buffer
+    unsigned int            nSrcBufLen;                             ///< [IN]  \~chinese 输入数据大小           \~english Input data length
+    enum MvGvspPixelType    enPixelType;                            ///< [IN]  \~chinese 像素格式               \~english Pixel format
+
+    unsigned char*          pDstBuf;                                ///< [OUT] \~chinese 输出数据缓存           \~english Output data buffer
+    unsigned int            nDstBufSize;                            ///< [IN]  \~chinese 提供的输出缓冲区大小   \~english Provided output buffer size
+    unsigned int            nDstBufLen;                             ///< [OUT] \~chinese 输出数据长度           \~english Output data length
+
+    unsigned int            nSharpenAmount;                         ///< [IN]  \~chinese 锐度调节强度,[0,500]  \~english Sharpen amount,[0,500]  //   [nSharpenAmount 作废, 使用 nSharpenPosAmount & nSharpenNegAmount 替代 ]
+    unsigned int            nSharpenRadius;                         ///< [IN]  \~chinese 锐度调节半径(半径越大,耗时越长),[1,21]   \~english Sharpen radius(The larger the radius, the longer it takes),[1,21]
+    unsigned int            nSharpenThreshold;                      ///< [IN]  \~chinese 锐度调节阈值,[0,255]  \~english Sharpen threshold,[0,255]
+
+
+    unsigned int        nSharpenPosAmount;     // [IN]     锐度调节正向强度,范围:[0, 500]  
+    unsigned int        nSharpenNegAmount;     // [IN]     锐度调节负向强度,范围:[0, 500]    
+
+    unsigned int            nRes[6];                                ///<       \~chinese 预留                   \~english Reserved
+
+}MV_CC_SHARPEN_PARAM;
+
+/// \~chinese 色彩校正结构体            \~english Color correct structure
+typedef struct _MV_CC_COLOR_CORRECT_PARAM_T_
+{
+    unsigned int            nWidth;                                 ///< [IN]  \~chinese 图像宽度               \~english Image Width
+    unsigned int            nHeight;                                ///< [IN]  \~chinese 图像高度               \~english Image Height
+    unsigned char*          pSrcBuf;                                ///< [IN]  \~chinese 输入数据缓存           \~english Input data buffer
+    unsigned int            nSrcBufLen;                             ///< [IN]  \~chinese 输入数据大小           \~english Input data length
+    enum MvGvspPixelType    enPixelType;                            ///< [IN]  \~chinese 像素格式               \~english Pixel format
+
+    unsigned char*          pDstBuf;                                ///< [OUT] \~chinese 输出数据缓存           \~english Output data buffer
+    unsigned int            nDstBufSize;                            ///< [IN]  \~chinese 提供的输出缓冲区大小   \~english Provided output buffer size
+    unsigned int            nDstBufLen;                             ///< [OUT] \~chinese 输出数据长度           \~english Output data length
+
+    unsigned int            nImageBit;                              ///< [IN]  \~chinese 有效图像位数(8,10,12,16)   \~english Image bit(8 or 10 or 12 or 16)
+    MV_CC_GAMMA_PARAM       stGammaParam;                           ///< [IN]  \~chinese Gamma信息              \~english Gamma info
+    MV_CC_CCM_PARAM_EX      stCCMParam;                             ///< [IN]  \~chinese CCM信息                \~english CCM info
+    MV_CC_CLUT_PARAM        stCLUTParam;                            ///< [IN]  \~chinese CLUT信息               \~english CLUT info
+
+    unsigned int            nRes[8];                                ///<       \~chinese 预留                   \~english Reserved
+
+}MV_CC_COLOR_CORRECT_PARAM;
+
+/// \~chinese 矩形ROI结构体             \~english Rect ROI structure
+typedef struct _MV_CC_RECT_I_
+{
+    unsigned int nX;                                                ///< \~chinese 矩形左上角X轴坐标            \~english X Position
+    unsigned int nY;                                                ///< \~chinese 矩形左上角Y轴坐标            \~english Y Position
+    unsigned int nWidth;                                            ///< \~chinese 矩形宽度                     \~english Rect Width
+    unsigned int nHeight;                                           ///< \~chinese 矩形高度                     \~english Rect Height
+
+}MV_CC_RECT_I;
+
+/// \~chinese 噪声估计结构体            \~english Noise estimate structure
+typedef struct _MV_CC_NOISE_ESTIMATE_PARAM_T_
+{
+    unsigned int            nWidth;                                 ///< [IN]  \~chinese 图像宽度(最小8)        \~english Image Width
+    unsigned int            nHeight;                                ///< [IN]  \~chinese 图像高度(最小8)        \~english Image Height
+    enum MvGvspPixelType    enPixelType;                            ///< [IN]  \~chinese 像素格式               \~english Pixel format
+    unsigned char*          pSrcBuf;                                ///< [IN]  \~chinese 输入数据缓存           \~english Input data buffer
+    unsigned int            nSrcBufLen;                             ///< [IN]  \~chinese 输入数据大小           \~english Input data length
+
+    MV_CC_RECT_I*           pstROIRect;                             ///< [IN]  \~chinese 图像ROI                \~english Image ROI
+    unsigned int            nROINum;                                ///< [IN]  \~chinese ROI个数                \~english ROI number
+
+    ///< \~chinese Bayer域噪声估计参数,Mono8/RGB域无效     \~english Bayer Noise estimate param,Mono8/RGB formats are invalid
+    unsigned int            nNoiseThreshold;                        ///< [IN]  \~chinese 噪声阈值[0,4095]       \~english Noise threshold[0,4095]
+    ///< \~chinese 建议值:8bit,0xE0;10bit,0x380;12bit,0xE00     \~english Suggestive value:8bit,0xE0;10bit,0x380;12bit,0xE00
+
+    unsigned char*          pNoiseProfile;                          ///< [OUT] \~chinese 输出噪声特性           \~english Output Noise Profile
+    unsigned int            nNoiseProfileSize;                      ///< [IN]  \~chinese 提供的输出缓冲区大小   \~english Provided output buffer size
+    unsigned int            nNoiseProfileLen;                       ///< [OUT] \~chinese 输出噪声特性长度       \~english Output Noise Profile length
+
+    unsigned int            nRes[8];                                ///<       \~chinese 预留                   \~english Reserved
+
+}MV_CC_NOISE_ESTIMATE_PARAM;
+
+/// \~chinese 空域降噪结构体            \~english Spatial denoise structure
+typedef struct _MV_CC_SPATIAL_DENOISE_PARAM_T_
+{
+    unsigned int            nWidth;                                 ///< [IN]  \~chinese 图像宽度(最小8)        \~english Image Width
+    unsigned int            nHeight;                                ///< [IN]  \~chinese 图像高度(最小8)        \~english Image Height
+    enum MvGvspPixelType    enPixelType;                            ///< [IN]  \~chinese 像素格式               \~english Pixel format
+    unsigned char*          pSrcBuf;                                ///< [IN]  \~chinese 输入数据缓存           \~english Input data buffer
+    unsigned int            nSrcBufLen;                             ///< [IN]  \~chinese 输入数据大小           \~english Input data length
+
+    unsigned char*          pDstBuf;                                ///< [OUT] \~chinese 输出降噪后的数据       \~english Output data buffer
+    unsigned int            nDstBufSize;                            ///< [IN]  \~chinese 提供的输出缓冲区大小   \~english Provided output buffer size
+    unsigned int            nDstBufLen;                             ///< [OUT] \~chinese 输出降噪后的数据长度   \~english Output data length
+
+    unsigned char*          pNoiseProfile;                          ///< [IN]  \~chinese 输入噪声特性           \~english Input Noise Profile
+    unsigned int            nNoiseProfileLen;                       ///< [IN]  \~chinese 输入噪声特性长度       \~english Input Noise Profile length
+
+    ///< \~chinese Bayer域空域降噪参数,Mono8/RGB域无效     \~english Bayer Spatial denoise param,Mono8/RGB formats are invalid
+    unsigned int            nBayerDenoiseStrength;                  ///< [IN]  \~chinese 降噪强度[0,100]        \~english Denoise Strength[0,100]
+    unsigned int            nBayerSharpenStrength;                  ///< [IN]  \~chinese 锐化强度[0,32]         \~english Sharpen Strength[0,32]
+    unsigned int            nBayerNoiseCorrect;                     ///< [IN]  \~chinese 噪声校正系数[0,1280]   \~english Noise Correct[0,1280]
+
+    ///< \~chinese Mono8/RGB域空域降噪参数,Bayer域无效     \~english Mono8/RGB Spatial denoise param,Bayer formats are invalid
+    unsigned int            nNoiseCorrectLum;                       ///< [IN]  \~chinese 亮度校正系数[1,2000]   \~english Noise Correct Lum[1,2000]
+    unsigned int            nNoiseCorrectChrom;                     ///< [IN]  \~chinese 色调校正系数[1,2000]   \~english Noise Correct Chrom[1,2000]
+    unsigned int            nStrengthLum;                           ///< [IN]  \~chinese 亮度降噪强度[0,100]    \~english Strength Lum[0,100]
+    unsigned int            nStrengthChrom;                         ///< [IN]  \~chinese 色调降噪强度[0,100]    \~english Strength Chrom[0,100]
+    unsigned int            nStrengthSharpen;                       ///< [IN]  \~chinese 锐化强度[1,1000]       \~english Strength Sharpen[1,1000]
+
+    unsigned int            nRes[8];                                ///<       \~chinese 预留                   \~english Reserved
+
+}MV_CC_SPATIAL_DENOISE_PARAM;
+
+/// \~chinese LSC标定结构体             \~english LSC calib structure
+typedef struct _MV_CC_LSC_CALIB_PARAM_T_
+{
+    unsigned int            nWidth;                                 ///< [IN]  \~chinese 图像宽度[16,65535]     \~english Image Width
+    unsigned int            nHeight;                                ///< [IN]  \~chinese 图像高度[16-65535]     \~english Image Height
+    enum MvGvspPixelType    enPixelType;                            ///< [IN]  \~chinese 像素格式               \~english Pixel format
+    unsigned char*          pSrcBuf;                                ///< [IN]  \~chinese 输入数据缓存           \~english Input data buffer
+    unsigned int            nSrcBufLen;                             ///< [IN]  \~chinese 输入数据长度           \~english Input data length
+
+    unsigned char*          pCalibBuf;                              ///< [OUT] \~chinese 输出标定表缓存         \~english Output calib buffer
+    unsigned int            nCalibBufSize;                          ///< [IN]  \~chinese 提供的标定表缓冲大小(nWidth*nHeight*sizeof(unsigned short))    \~english Provided output buffer size
+    unsigned int            nCalibBufLen;                           ///< [OUT] \~chinese 输出标定表缓存长度     \~english Output calib buffer length
+
+    unsigned int            nSecNumW;                               ///< [IN]  \~chinese 宽度分块数             \~english Width Sec num
+    unsigned int            nSecNumH;                               ///< [IN]  \~chinese 高度分块数             \~english Height Sec num
+    unsigned int            nPadCoef;                               ///< [IN]  \~chinese 边缘填充系数[1,5]      \~english Pad Coef[1,5]
+    unsigned int            nCalibMethod;                           ///< [IN]  \~chinese 标定方式(0-中心为基准;1-最亮区域为基准;2-目标亮度为基准) \~english Calib method
+    unsigned int            nTargetGray;                            ///< [IN]  \~chinese 目标亮度(标定方式为2时有效)    \~english Target Gray
+    ///< \~chinese 8位,范围:[0,255]            \~english 8bit,range:[0,255]
+    ///< \~chinese 10位,范围:[0,1023]          \~english 10bit,range:[0,1023]
+    ///< \~chinese 12位,范围:[0,4095]          \~english 12bit,range:[0,4095]
+
+    unsigned int            nRes[8];                                ///<       \~chinese 预留                   \~english Reserved
+
+}MV_CC_LSC_CALIB_PARAM;
+
+/// \~chinese LSC校正结构体             \~english LSC correct structure
+typedef struct _MV_CC_LSC_CORRECT_PARAM_T_
+{
+    unsigned int            nWidth;                                 ///< [IN]  \~chinese 图像宽度[16,65535]     \~english Image Width
+    unsigned int            nHeight;                                ///< [IN]  \~chinese 图像高度[16,65535]     \~english Image Height
+    enum MvGvspPixelType    enPixelType;                            ///< [IN]  \~chinese 像素格式               \~english Pixel format
+    unsigned char*          pSrcBuf;                                ///< [IN]  \~chinese 输入数据缓存           \~english Input data buffer
+    unsigned int            nSrcBufLen;                             ///< [IN]  \~chinese 输入数据长度           \~english Input data length
+
+    unsigned char*          pDstBuf;                                ///< [OUT] \~chinese 输出数据缓存           \~english Output data buffer
+    unsigned int            nDstBufSize;                            ///< [IN]  \~chinese 提供的输出缓冲区大小   \~english Provided output buffer size
+    unsigned int            nDstBufLen;                             ///< [OUT] \~chinese 输出数据长度           \~english Output data length
+
+    unsigned char*          pCalibBuf;                              ///< [IN]  \~chinese 输入标定表缓存         \~english Input calib buffer
+    unsigned int            nCalibBufLen;                           ///< [IN]  \~chinese 输入标定表缓存长度     \~english Input calib buffer length
+
+    unsigned int            nRes[8];                                ///<       \~chinese 预留                   \~english Reserved
+
+}MV_CC_LSC_CORRECT_PARAM;
+
+/// \~chinese 某个节点对应的子节点个数最大值    \~english The maximum number of child nodes corresponding to a node
+#define MV_MAX_XML_NODE_NUM_C       128
+
+/// \~chinese 节点名称字符串最大长度            \~english The maximum length of node name string
+#define MV_MAX_XML_NODE_STRLEN_C    64
+
+/// \~chinese 节点String值最大长度              \~english The maximum length of Node String
+#define MV_MAX_XML_STRVALUE_STRLEN_C 64
+
+/// \~chinese 节点描述字段最大长度              \~english The maximum length of the node description field
+#define MV_MAX_XML_DISC_STRLEN_C    512
+
+/// \~chinese 最多的单元数                      \~english The maximum number of units
+#define MV_MAX_XML_ENTRY_NUM        10
+
+/// \~chinese 父节点个数上限                    \~english The maximum number of parent nodes
+#define MV_MAX_XML_PARENTS_NUM      8
+
+/// \~chinese 每个已经实现单元的名称长度        \~english The length of the name of each unit that has been implemented
+#define MV_MAX_XML_SYMBOLIC_STRLEN_C 64
+
+enum MV_XML_Visibility
+{
+    V_Beginner      = 0,    ///< Always visible
+    V_Expert        = 1,    ///< Visible for experts or Gurus
+    V_Guru          = 2,    ///< Visible for Gurus
+    V_Invisible     = 3,    ///< Not Visible
+    V_Undefined     = 99    ///< Object is not yet initialized
+};
+
+/// \~chinese 单个节点基本属性 | en:Single Node Basic Attributes
+typedef struct _MV_XML_NODE_FEATURE_
+{
+    enum MV_XML_InterfaceType   enType;                             ///< \~chinese 节点类型         \~english Node Type
+    enum MV_XML_Visibility  enVisivility;                           ///< \~chinese 是否可见         \~english Is visibility
+    char                strDescription[MV_MAX_XML_DISC_STRLEN_C];   ///< \~chinese 节点描述,目前暂不支持   \~english Node Description, NOT SUPPORT NOW
+    char                strDisplayName[MV_MAX_XML_NODE_STRLEN_C];   ///< \~chinese 显示名称         \~english Display Name
+    char                strName[MV_MAX_XML_NODE_STRLEN_C];          ///< \~chinese 节点名           \~english Node Name
+    char                strToolTip[MV_MAX_XML_DISC_STRLEN_C];       ///< \~chinese 提示             \~english Notice
+
+    unsigned int        nReserved[4];
+}MV_XML_NODE_FEATURE;
+
+/// \~chinese 节点列表 | en:Node List
+typedef struct _MV_XML_NODES_LIST_
+{
+    unsigned int        nNodeNum;       ///< \~chinese 节点个数             \~english Node Number
+    MV_XML_NODE_FEATURE stNodes[MV_MAX_XML_NODE_NUM_C];
+}MV_XML_NODES_LIST;
+
+typedef struct _MV_XML_FEATURE_Value_
+{
+    enum MV_XML_InterfaceType   enType;                             ///< \~chinese 节点类型         \~english Node Type
+    char                strDescription[MV_MAX_XML_DISC_STRLEN_C];   ///< \~chinese 节点描述,目前暂不支持   \~english Node Description, NOT SUPPORT NOW
+    char                strDisplayName[MV_MAX_XML_NODE_STRLEN_C];   ///< \~chinese 显示名称         \~english Display Name
+    char                strName[MV_MAX_XML_NODE_STRLEN_C];          ///< \~chinese 节点名           \~english Node Name
+    char                strToolTip[MV_MAX_XML_DISC_STRLEN_C];       ///< \~chinese 提示             \~english Notice
+    unsigned int        nReserved[4];
+}MV_XML_FEATURE_Value;
+
+typedef struct _MV_XML_FEATURE_Base_
+{
+    enum MV_XML_AccessMode enAccessMode;                           ///< \~chinese 访问模式         \~english Access Mode
+}MV_XML_FEATURE_Base;
+
+typedef struct _MV_XML_FEATURE_Integer_
+{
+    char                strName[MV_MAX_XML_NODE_STRLEN_C];
+    char                strDisplayName[MV_MAX_XML_NODE_STRLEN_C];
+    char                strDescription[MV_MAX_XML_DISC_STRLEN_C];   ///< \~chinese 目前暂不支持     \~english NOT SUPPORT NOW
+    char                strToolTip[MV_MAX_XML_DISC_STRLEN_C];
+
+    enum MV_XML_Visibility  enVisivility;                           ///< \~chinese 是否可见         \~english Visible
+    enum MV_XML_AccessMode  enAccessMode;                           ///< \~chinese 访问模式         \~english Access Mode
+    int                 bIsLocked;                                  ///< \~chinese 是否锁定。0-否;1-是,目前暂不支持    \~english Locked. 0-NO; 1-YES, NOT SUPPORT NOW
+    int64_t             nValue;                                     ///< \~chinese 当前值           \~english Current Value
+    int64_t             nMinValue;                                  ///< \~chinese 最小值           \~english Min Value
+    int64_t             nMaxValue;                                  ///< \~chinese 最大值           \~english Max Value
+    int64_t             nIncrement;                                 ///< \~chinese 增量             \~english Increment
+
+    unsigned int        nReserved[4];
+
+}MV_XML_FEATURE_Integer;
+
+typedef struct _MV_XML_FEATURE_Boolean_
+{
+    char                strName[MV_MAX_XML_NODE_STRLEN_C];
+    char                strDisplayName[MV_MAX_XML_NODE_STRLEN_C];
+    char                strDescription[MV_MAX_XML_DISC_STRLEN_C];   ///< \~chinese 目前暂不支持     \~english NOT SUPPORT NOW
+    char                strToolTip[MV_MAX_XML_DISC_STRLEN_C];
+
+    enum MV_XML_Visibility  enVisivility;                           ///< \~chinese 是否可见         \~english Visible
+    enum MV_XML_AccessMode  enAccessMode;                           ///< \~chinese 访问模式         \~english Access Mode
+    int                 bIsLocked;                                  ///< \~chinese 是否锁定。0-否;1-是,目前暂不支持    \~english Locked. 0-NO; 1-YES, NOT SUPPORT NOW
+    bool                bValue;                                     ///< \~chinese 当前值           \~english Current Value
+
+    unsigned int        nReserved[4];
+}MV_XML_FEATURE_Boolean;
+
+typedef struct _MV_XML_FEATURE_Command_
+{
+    char                strName[MV_MAX_XML_NODE_STRLEN_C];
+    char                strDisplayName[MV_MAX_XML_NODE_STRLEN_C];
+    char                strDescription[MV_MAX_XML_DISC_STRLEN_C];   ///< \~chinese 目前暂不支持     \~english NOT SUPPORT NOW
+    char                strToolTip[MV_MAX_XML_DISC_STRLEN_C];
+
+    enum MV_XML_Visibility  enVisivility;                           ///< \~chinese 是否可见         \~english Visible
+    enum MV_XML_AccessMode  enAccessMode;                           ///< \~chinese 访问模式         \~english Access Mode
+    int                 bIsLocked;                                  ///< \~chinese 是否锁定。0-否;1-是,目前暂不支持    \~english Locked. 0-NO; 1-YES, NOT SUPPORT NOW
+
+    unsigned int        nReserved[4];
+}MV_XML_FEATURE_Command;
+
+typedef struct _MV_XML_FEATURE_Float_
+{
+    char                strName[MV_MAX_XML_NODE_STRLEN_C];
+    char                strDisplayName[MV_MAX_XML_NODE_STRLEN_C];
+    char                strDescription[MV_MAX_XML_DISC_STRLEN_C];   ///< \~chinese 目前暂不支持     \~english NOT SUPPORT NOW
+    char                strToolTip[MV_MAX_XML_DISC_STRLEN_C];
+
+    enum MV_XML_Visibility  enVisivility;                           ///< \~chinese 是否可见         \~english Visible
+    enum MV_XML_AccessMode  enAccessMode;                           ///< \~chinese 访问模式         \~english Access Mode
+    int                 bIsLocked;                                  ///< \~chinese 是否锁定。0-否;1-是,目前暂不支持    \~english Locked. 0-NO; 1-YES, NOT SUPPORT NOW
+    double              dfValue;                                    ///< \~chinese 当前值           \~english Current Value
+    double              dfMinValue;                                 ///< \~chinese 最小值           \~english Min Value
+    double              dfMaxValue;                                 ///< \~chinese 最大值           \~english Max Value
+    double              dfIncrement;                                ///< \~chinese 增量             \~english Increment
+
+    unsigned int        nReserved[4];
+}MV_XML_FEATURE_Float;
+
+typedef struct _MV_XML_FEATURE_String_
+{
+    char                strName[MV_MAX_XML_NODE_STRLEN_C];
+    char                strDisplayName[MV_MAX_XML_NODE_STRLEN_C];
+    char                strDescription[MV_MAX_XML_DISC_STRLEN_C];   ///< \~chinese 目前暂不支持     \~english NOT SUPPORT NOW
+    char                strToolTip[MV_MAX_XML_DISC_STRLEN_C];
+
+    enum MV_XML_Visibility  enVisivility;                           ///< \~chinese 是否可见         \~english Visible
+    enum MV_XML_AccessMode  enAccessMode;                           ///< \~chinese 访问模式         \~english Access Mode
+    int                 bIsLocked;                                  ///< \~chinese 是否锁定。0-否;1-是,目前暂不支持    \~english Locked. 0-NO; 1-YES, NOT SUPPORT NOW
+    char                strValue[MV_MAX_XML_STRVALUE_STRLEN_C];     ///< \~chinese 当前值           \~english Current Value
+
+    unsigned int        nReserved[4];
+}MV_XML_FEATURE_String;
+
+typedef struct _MV_XML_FEATURE_Register_
+{
+    char                strName[MV_MAX_XML_NODE_STRLEN_C];
+    char                strDisplayName[MV_MAX_XML_NODE_STRLEN_C];
+    char                strDescription[MV_MAX_XML_DISC_STRLEN_C];   ///< \~chinese 目前暂不支持     \~english NOT SUPPORT NOW
+    char                strToolTip[MV_MAX_XML_DISC_STRLEN_C];
+
+    enum MV_XML_Visibility  enVisivility;                           ///< \~chinese 是否可见         \~english Visible
+    enum MV_XML_AccessMode  enAccessMode;                           ///< \~chinese 访问模式         \~english Access Mode
+    int                 bIsLocked;                                  ///< \~chinese 是否锁定。0-否;1-是,目前暂不支持    \~english Locked. 0-NO; 1-YES, NOT SUPPORT NOW
+    int64_t             nAddrValue;                                 ///< \~chinese 当前值           \~english Current Value
+
+    unsigned int        nReserved[4];
+}MV_XML_FEATURE_Register;
+
+typedef struct _MV_XML_FEATURE_Category_
+{
+    char                strDescription[MV_MAX_XML_DISC_STRLEN_C];   ///< \~chinese 节点描述 目前暂不支持    \~english Node Description, NOT SUPPORT NOW
+    char                strDisplayName[MV_MAX_XML_NODE_STRLEN_C];   ///< \~chinese 显示名称         \~english Display Name
+    char                strName[MV_MAX_XML_NODE_STRLEN_C];          ///< \~chinese 节点名           \~english Node Name
+    char                strToolTip[MV_MAX_XML_DISC_STRLEN_C];       ///< \~chinese 提示             \~english Notice
+
+    enum MV_XML_Visibility  enVisivility;                           ///< \~chinese 是否可见         \~english Visible
+
+    unsigned int        nReserved[4];
+}MV_XML_FEATURE_Category;
+
+typedef struct _MV_XML_FEATURE_EnumEntry_
+{
+    char                strName[MV_MAX_XML_NODE_STRLEN_C];
+    char                strDisplayName[MV_MAX_XML_NODE_STRLEN_C];
+    char                strDescription[MV_MAX_XML_DISC_STRLEN_C];   ///< \~chinese 目前暂不支持     \~english NOT SUPPORT NOW
+    char                strToolTip[MV_MAX_XML_DISC_STRLEN_C];
+    int                 bIsImplemented;
+    int                 nParentsNum;
+    MV_XML_NODE_FEATURE stParentsList[MV_MAX_XML_PARENTS_NUM];
+
+    enum MV_XML_Visibility  enVisivility;                           ///< \~chinese 是否可见         \~english Visible
+    int64_t             nValue;                                     ///< \~chinese 当前值           \~english Current Value
+    enum MV_XML_AccessMode  enAccessMode;                           ///< \~chinese 访问模式         \~english Access Mode
+    int                 bIsLocked;                                  ///< \~chinese 是否锁定。0-否;1-是,目前暂不支持    \~english Locked. 0-NO; 1-YES, NOT SUPPORT NOW
+    int                 nReserved[8];
+
+}MV_XML_FEATURE_EnumEntry;
+
+typedef struct _MV_XML_FEATURE_Enumeration_
+{
+    enum MV_XML_Visibility  enVisivility;                           ///< \~chinese 是否可见         \~english Visible
+    char                strDescription[MV_MAX_XML_DISC_STRLEN_C];   ///< \~chinese 节点描述 目前暂不支持    \~english Node Description, NOT SUPPORT NOW
+    char                strDisplayName[MV_MAX_XML_NODE_STRLEN_C];   ///< \~chinese 显示名称         \~english Display Name
+    char                strName[MV_MAX_XML_NODE_STRLEN_C];          ///< \~chinese 节点名           \~english Node Name
+    char                strToolTip[MV_MAX_XML_DISC_STRLEN_C];       ///< \~chinese 提示             \~english Notice
+
+    int                 nSymbolicNum;                               ///< \~chinese ymbolic数        \~english Symbolic Number
+    char                strCurrentSymbolic[MV_MAX_XML_SYMBOLIC_STRLEN_C];///< \~chinese 当前Symbolic索引    \~english Current Symbolic Index
+    char                strSymbolic[MV_MAX_XML_SYMBOLIC_NUM][MV_MAX_XML_SYMBOLIC_STRLEN_C];
+    enum MV_XML_AccessMode   enAccessMode;                          ////< \~chinese 访问模式        \~english Access Mode
+    int                 bIsLocked;                                  ///< \~chinese 是否锁定。0-否;1-是,目前暂不支持    \~english Locked. 0-NO; 1-YES, NOT SUPPORT NOW
+    int64_t             nValue;                                     ///< \~chinese 当前值           \~english Current Value
+
+    unsigned int        nReserved[4];
+}MV_XML_FEATURE_Enumeration;
+
+typedef struct _MV_XML_FEATURE_Port_
+{
+    enum MV_XML_Visibility  enVisivility;                           ///< \~chinese 是否可见         \~english Visible
+    char                strDescription[MV_MAX_XML_DISC_STRLEN_C];   ///< \~chinese 节点描述,目前暂不支持    \~english Node Description, NOT SUPPORT NOW
+    char                strDisplayName[MV_MAX_XML_NODE_STRLEN_C];   ///< \~chinese 显示名称         \~english Display Name
+    char                strName[MV_MAX_XML_NODE_STRLEN_C];          ///< \~chinese 节点名           \~english Node Name
+    char                strToolTip[MV_MAX_XML_DISC_STRLEN_C];       ///< \~chinese 提示             \~english Notice
+
+    enum MV_XML_AccessMode  enAccessMode;                           ///< \~chinese 访问模式         \~english Access Mode
+    int                 bIsLocked;                                  ///< \~chinese 是否锁定。0-否;1-是,目前暂不支持    \~english Locked. 0-NO; 1-YES, NOT SUPPORT NOW
+
+    unsigned int        nReserved[4];
+}MV_XML_FEATURE_Port;
+
+typedef struct _MV_XML_CAMERA_FEATURE_
+{
+    enum MV_XML_InterfaceType    enType;
+    union
+    {
+        MV_XML_FEATURE_Integer      stIntegerFeature;
+        MV_XML_FEATURE_Float        stFloatFeature;
+        MV_XML_FEATURE_Enumeration  stEnumerationFeature;
+        MV_XML_FEATURE_String       stStringFeature;
+    }SpecialFeature;
+
+}MV_XML_CAMERA_FEATURE;
+
+
+
+/// \~chinese 图片保存参数              \~english Save Image Parameters
+typedef struct _MV_SAVE_IMAGE_PARAM_T_EX_
+{
+    unsigned char*          pData;                                  ///< [IN]  \~chinese 输入数据缓存           \~english Input Data Buffer
+    unsigned int            nDataLen;                               ///< [IN]  \~chinese 输入数据长度           \~english Input Data length
+    enum MvGvspPixelType    enPixelType;                            ///< [IN]  \~chinese 输入数据的像素格式     \~english Input Data Pixel Format
+    unsigned short          nWidth;                                 ///< [IN]  \~chinese 图像宽                 \~english Image Width
+    unsigned short          nHeight;                                ///< [IN]  \~chinese 图像高                 \~english Image Height
+
+    unsigned char*          pImageBuffer;                           ///< [OUT] \~chinese 输出图片缓存           \~english Output Image Buffer
+    unsigned int            nImageLen;                              ///< [OUT] \~chinese 输出图片长度           \~english Output Image length
+    unsigned int            nBufferSize;                            ///< [IN]  \~chinese 提供的输出缓冲区大小   \~english Output buffer size provided
+    enum MV_SAVE_IAMGE_TYPE enImageType;                            ///< [IN]  \~chinese 输出图片格式           \~english Output Image Format
+    unsigned int            nJpgQuality;                            ///< [IN]  \~chinese JPG编码质量(50-99],其它格式无效   \~english Encoding quality(50-99],Other formats are invalid
+
+    unsigned int            iMethodValue;                           ///< [IN]  \~chinese 插值方法 0-快速 1-均衡(其它值默认为均衡) 2-最优 3-最优+  \~english Bayer interpolation method  0-Fast 1-Equilibrium 2-Optimal 3-Optimal+
+
+    unsigned int            nReserved[3];                           ///<       \~chinese 预留                   \~english Reserved
+
+}MV_SAVE_IMAGE_PARAM_EX;
+
+
+
+/// \~chinese 图片保存参数              \~english Save Image Parameters
+typedef struct _MV_SAVE_IMG_TO_FILE_PARAM_
+{
+    enum MvGvspPixelType    enPixelType;                            ///< [IN]  \~chinese输入数据的像素格式      \~english The pixel format of the input data
+    unsigned char*          pData;                                  ///< [IN]  \~chinese 输入数据缓存           \~english Input Data Buffer
+    unsigned int            nDataLen;                               ///< [IN]  \~chinese 输入数据长度           \~english Input Data length
+    unsigned short          nWidth;                                 ///< [IN]  \~chinese 图像宽                 \~english Image Width
+    unsigned short          nHeight;                                ///< [IN]  \~chinese 图像高                 \~english Image Height
+    enum MV_SAVE_IAMGE_TYPE enImageType;                            ///< [IN]  \~chinese 输入图片格式           \~english Input Image Format
+    unsigned int            nQuality;                               ///< [IN]  \~chinese JPG编码质量(50-99],其它格式无效 \~english JPG Encoding quality(50-99],Other formats are invalid
+    char                    pImagePath[256];                        ///< [IN]  \~chinese 输入文件路径           \~english Input file path
+
+    int                     iMethodValue;                           ///< [IN]  \~chinese 插值方法 0-快速 1-均衡(其它值默认为均衡) 2-最优 3-最优+ \~english Bayer interpolation method  0-Fast 1-Equilibrium 2-Optimal 3-Optimal+
+
+    unsigned int            nReserved[8];                           ///<       \~chinese 预留                   \~english Reserved
+
+}MV_SAVE_IMG_TO_FILE_PARAM;
+
+
+// \~chinese 像素转换结构体            \~english Pixel convert structure
+typedef struct _MV_CC_PIXEL_CONVERT_PARAM_
+{
+    unsigned short          nWidth;                                 ///< [IN]  \~chinese 图像宽                 \~english Width
+    unsigned short          nHeight;                                ///< [IN]  \~chinese 图像高                 \~english Height
+
+    enum MvGvspPixelType    enSrcPixelType;                         ///< [IN]  \~chinese 源像素格式             \~english Source pixel format
+    unsigned char*          pSrcData;                               ///< [IN]  \~chinese 输入数据缓存           \~english Input data buffer
+    unsigned int            nSrcDataLen;                            ///< [IN]  \~chinese 输入数据长度           \~english Input data length
+
+    enum MvGvspPixelType    enDstPixelType;                         ///< [IN]  \~chinese 目标像素格式           \~english Destination pixel format
+    unsigned char*          pDstBuffer;                             ///< [OUT] \~chinese 输出数据缓存           \~english Output data buffer
+    unsigned int            nDstLen;                                ///< [OUT] \~chinese 输出数据长度           \~english Output data length
+    unsigned int            nDstBufferSize;                         ///< [IN]  \~chinese 提供的输出缓冲区大小   \~english Provided output buffer size
+
+    unsigned int            nRes[4];                                ///<       \~chinese 预留                   \~english Reserved
+
+}MV_CC_PIXEL_CONVERT_PARAM;
+
+/// \~chinese 保存的3D数据格式          \~english The saved format for 3D data
+enum MV_SAVE_POINT_CLOUD_FILE_TYPE
+{
+    MV_PointCloudFile_Undefined         = 0,                        ///< \~chinese 未定义的点云格式             \~english Undefined point cloud format
+    MV_PointCloudFile_PLY               = 1,                        ///< \~chinese PLY点云格式                  \~english The point cloud format named PLY
+    MV_PointCloudFile_CSV               = 2,                        ///< \~chinese CSV点云格式                  \~english The point cloud format named CSV
+    MV_PointCloudFile_OBJ               = 3,                        ///< \~chinese OBJ点云格式                  \~english The point cloud format named OBJ
+
+};
+
+/// \~chinese 保存3D数据到缓存          \~english Save 3D data to buffer
+typedef struct _MV_SAVE_POINT_CLOUD_PARAM_
+{
+    unsigned int                    nLinePntNum;                    ///< [IN]  \~chinese 行点数,即图像宽       \~english The number of points in each row,which is the width of the image
+    unsigned int                    nLineNum;                       ///< [IN]  \~chinese 行数,即图像高         \~english The number of rows,which is the height of the image
+
+    enum MvGvspPixelType            enSrcPixelType;                 ///< [IN]  \~chinese 输入数据的像素格式     \~english The pixel format of the input data
+    unsigned char*                  pSrcData;                       ///< [IN]  \~chinese 输入数据缓存           \~english Input data buffer
+    unsigned int                    nSrcDataLen;                    ///< [IN]  \~chinese 输入数据长度           \~english Input data length
+
+    unsigned char*                  pDstBuf;                        ///< [OUT] \~chinese 输出像素数据缓存       \~english Output pixel data buffer
+    unsigned int                    nDstBufSize;                    ///< [IN]  \~chinese 提供的输出缓冲区大小(nLinePntNum * nLineNum * (16*3 + 4) + 2048)   \~english Output buffer size provided(nLinePntNum * nLineNum * (16*3 + 4) + 2048) 
+    unsigned int                    nDstBufLen;                     ///< [OUT] \~chinese 输出像素数据缓存长度   \~english Output pixel data buffer size
+    enum MV_SAVE_POINT_CLOUD_FILE_TYPE   enPointCloudFileType;      ///< [IN]  \~chinese 提供输出的点云文件类型 \~english Output point data file type provided
+
+    unsigned int        nReserved[8];                               ///<       \~chinese 保留字段               \~english Reserved
+
+}MV_SAVE_POINT_CLOUD_PARAM;
+
+/// \~chinese 显示帧信息                \~english Display frame information
+typedef struct _MV_DISPLAY_FRAME_INFO_
+{
+	void*                   hWnd;                                   ///< [IN] \~chinese 窗口句柄                \~english HWND
+	unsigned char*          pData;                                  ///< [IN] \~chinese 显示的数据              \~english Data Buffer
+	unsigned int            nDataLen;                               ///< [IN] \~chinese 数据长度                \~english Data Size
+	unsigned short          nWidth;                                 ///< [IN] \~chinese 图像宽                  \~english Width
+	unsigned short          nHeight;                                ///< [IN] \~chinese 图像高                  \~english Height
+	enum MvGvspPixelType    enPixelType;                            ///< [IN] \~chinese 像素格式                \~english Pixel format
+
+	unsigned int            enRenderMode;                             ///  [IN] \~chinese 图像渲染方式  Windows:0-GDI(默认), 1-D3D, 2-OPENGL Linux: 0-OPENGL(默认)   \~english Windows:0-GDI(default), 1-D3D, 2-OPENGL Linux: 0-OPENGL(default)
+	unsigned int            nRes[3];                                ///<      \~chinese 保留                    \~english Reserved
+
+}MV_DISPLAY_FRAME_INFO;
+
+
+
+
+#endif /* _MV_OBSOLETE_CAM_PARAMS_H_ */

+ 198 - 0
mvs_usb_takephoto/include/PixelType.h

@@ -0,0 +1,198 @@
+
+#ifndef _MV_PIXEL_TYPE_H_
+#define _MV_PIXEL_TYPE_H_
+
+/************************************************************************/
+/*     GigE Vision (2.0.03) PIXEL FORMATS                               */
+/************************************************************************/
+
+// Indicate if pixel is monochrome or RGB
+#define MV_GVSP_PIX_MONO                                0x01000000 
+#define MV_GVSP_PIX_RGB                                 0x02000000 // deprecated in version 1.1
+#define MV_GVSP_PIX_COLOR                               0x02000000
+#define MV_GVSP_PIX_CUSTOM                              0x80000000
+#define MV_GVSP_PIX_COLOR_MASK                          0xFF000000
+
+// Indicate effective number of bits occupied by the pixel (including padding).
+// This can be used to compute amount of memory required to store an image.
+#define MV_PIXEL_BIT_COUNT(n)                           ((n) << 16)
+
+#define MV_GVSP_PIX_EFFECTIVE_PIXEL_SIZE_MASK           0x00FF0000
+#define MV_GVSP_PIX_EFFECTIVE_PIXEL_SIZE_SHIFT          16
+
+// Pixel ID: lower 16-bit of the pixel formats
+#define MV_GVSP_PIX_ID_MASK                             0x0000FFFF
+#define MV_GVSP_PIX_COUNT                               0x46 // next Pixel ID available
+
+enum MvGvspPixelType
+{
+    // Undefined pixel type
+#ifdef WIN32
+	PixelType_Gvsp_Undefined                =   0xFFFFFFFF, 
+
+#else
+	PixelType_Gvsp_Undefined                =   -1, 
+
+#endif
+    // Mono buffer format defines
+    PixelType_Gvsp_Mono1p                   =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(1) | 0x0037),
+    PixelType_Gvsp_Mono2p                   =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(2) | 0x0038),
+    PixelType_Gvsp_Mono4p                   =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(4) | 0x0039),
+    PixelType_Gvsp_Mono8                    =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(8) | 0x0001),
+    PixelType_Gvsp_Mono8_Signed             =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(8)  | 0x0002),    
+    PixelType_Gvsp_Mono10                   =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0003),
+    PixelType_Gvsp_Mono10_Packed            =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x0004),
+    PixelType_Gvsp_Mono12                   =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0005),
+    PixelType_Gvsp_Mono12_Packed            =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x0006),
+    PixelType_Gvsp_Mono14                   =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0025),
+    PixelType_Gvsp_Mono16                   =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0007),
+
+    // Bayer buffer format defines 
+    PixelType_Gvsp_BayerGR8                 =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(8) | 0x0008),
+    PixelType_Gvsp_BayerRG8                 =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(8) | 0x0009),
+    PixelType_Gvsp_BayerGB8                 =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(8) | 0x000A),
+    PixelType_Gvsp_BayerBG8                 =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(8) | 0x000B),
+    PixelType_Gvsp_BayerRBGG8               =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(8) | 0x0046),
+    PixelType_Gvsp_BayerGR10                =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x000C),
+    PixelType_Gvsp_BayerRG10                =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x000D),
+    PixelType_Gvsp_BayerGB10                =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x000E),
+    PixelType_Gvsp_BayerBG10                =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x000F),
+    PixelType_Gvsp_BayerGR12                =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0010),
+    PixelType_Gvsp_BayerRG12                =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0011),
+    PixelType_Gvsp_BayerGB12                =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0012),
+    PixelType_Gvsp_BayerBG12                =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0013),
+    PixelType_Gvsp_BayerGR10_Packed         =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x0026),
+    PixelType_Gvsp_BayerRG10_Packed         =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x0027),
+    PixelType_Gvsp_BayerGB10_Packed         =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x0028),
+    PixelType_Gvsp_BayerBG10_Packed         =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x0029),
+    PixelType_Gvsp_BayerGR12_Packed         =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x002A),
+    PixelType_Gvsp_BayerRG12_Packed         =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x002B),
+    PixelType_Gvsp_BayerGB12_Packed         =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x002C),
+    PixelType_Gvsp_BayerBG12_Packed         =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x002D),
+    PixelType_Gvsp_BayerGR16                =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x002E),
+    PixelType_Gvsp_BayerRG16                =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x002F),
+    PixelType_Gvsp_BayerGB16                =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0030),
+    PixelType_Gvsp_BayerBG16                =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0031),
+
+    // RGB Packed buffer format defines 
+    PixelType_Gvsp_RGB8_Packed              =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(24) | 0x0014),
+    PixelType_Gvsp_BGR8_Packed              =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(24) | 0x0015),
+    PixelType_Gvsp_RGBA8_Packed             =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(32) | 0x0016),
+    PixelType_Gvsp_BGRA8_Packed             =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(32) | 0x0017),
+    PixelType_Gvsp_RGB10_Packed             =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(48) | 0x0018),
+    PixelType_Gvsp_BGR10_Packed             =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(48) | 0x0019),
+    PixelType_Gvsp_RGB12_Packed             =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(48) | 0x001A),
+    PixelType_Gvsp_BGR12_Packed             =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(48) | 0x001B),
+    PixelType_Gvsp_RGB16_Packed             =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(48) | 0x0033),
+    PixelType_Gvsp_BGR16_Packed             =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(48) | 0x004B),
+    PixelType_Gvsp_RGBA16_Packed            =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(64) | 0x0064),
+    PixelType_Gvsp_BGRA16_Packed            =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(64) | 0x0051),
+    PixelType_Gvsp_RGB10V1_Packed           =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(32) | 0x001C),
+    PixelType_Gvsp_RGB10V2_Packed           =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(32) | 0x001D),
+    PixelType_Gvsp_RGB12V1_Packed           =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(36) | 0X0034),
+    PixelType_Gvsp_RGB565_Packed            =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(16) | 0x0035),
+    PixelType_Gvsp_BGR565_Packed            =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(16) | 0X0036),
+
+    // YUV Packed buffer format defines 
+    PixelType_Gvsp_YUV411_Packed            =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(12) | 0x001E),
+    PixelType_Gvsp_YUV422_Packed            =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(16) | 0x001F),
+    PixelType_Gvsp_YUV422_YUYV_Packed       =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(16) | 0x0032),
+    PixelType_Gvsp_YUV444_Packed            =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(24) | 0x0020),
+    PixelType_Gvsp_YCBCR8_CBYCR             =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(24) | 0x003A),
+    PixelType_Gvsp_YCBCR422_8               =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(16) | 0x003B),
+    PixelType_Gvsp_YCBCR422_8_CBYCRY        =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(16) | 0x0043),
+    PixelType_Gvsp_YCBCR411_8_CBYYCRYY      =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(12) | 0x003C),
+    PixelType_Gvsp_YCBCR601_8_CBYCR         =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(24) | 0x003D),
+    PixelType_Gvsp_YCBCR601_422_8           =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(16) | 0x003E),
+    PixelType_Gvsp_YCBCR601_422_8_CBYCRY    =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(16) | 0x0044),
+    PixelType_Gvsp_YCBCR601_411_8_CBYYCRYY  =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(12) | 0x003F),
+    PixelType_Gvsp_YCBCR709_8_CBYCR         =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(24) | 0x0040),
+    PixelType_Gvsp_YCBCR709_422_8           =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(16) | 0x0041),
+    PixelType_Gvsp_YCBCR709_422_8_CBYCRY    =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(16) | 0x0045),
+    PixelType_Gvsp_YCBCR709_411_8_CBYYCRYY  =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(12) | 0x0042),
+
+    // YUV420
+    PixelType_Gvsp_YUV420SP_NV12            =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(12) | 0x8001),
+    PixelType_Gvsp_YUV420SP_NV21            =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(12) | 0x8002),
+
+    // RGB Planar buffer format defines 
+    PixelType_Gvsp_RGB8_Planar              =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(24) | 0x0021),
+    PixelType_Gvsp_RGB10_Planar             =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(48) | 0x0022),
+    PixelType_Gvsp_RGB12_Planar             =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(48) | 0x0023),
+    PixelType_Gvsp_RGB16_Planar             =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(48) | 0x0024),
+
+    // 自定义的图片格式
+    PixelType_Gvsp_Jpeg                     =   (MV_GVSP_PIX_CUSTOM | MV_PIXEL_BIT_COUNT(24) | 0x0001),
+
+    PixelType_Gvsp_Coord3D_ABC32f           =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(96) | 0x00C0),//0x026000C0
+    PixelType_Gvsp_Coord3D_ABC32f_Planar    =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(96) | 0x00C1),//0x026000C1
+
+    // 该值被废弃,请参考PixelType_Gvsp_Coord3D_AC32f_64; the value is discarded
+    PixelType_Gvsp_Coord3D_AC32f            =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(40) | 0x00C2),
+    // 该值被废弃; the value is discarded    (已放入Chunkdata)
+    PixelType_Gvsp_COORD3D_DEPTH_PLUS_MASK  =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(28) | 0x0001),
+
+    PixelType_Gvsp_Coord3D_ABC32            =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(96) | 0x3001),//0x82603001
+    PixelType_Gvsp_Coord3D_AB32f            =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(64) | 0x3002),//0x82403002
+    PixelType_Gvsp_Coord3D_AB32             =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(64) | 0x3003),//0x82403003
+    PixelType_Gvsp_Coord3D_AC32f_64         =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(64) | 0x00C2),//0x024000C2
+    PixelType_Gvsp_Coord3D_AC32f_Planar     =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(64) | 0x00C3),//0x024000C3
+    PixelType_Gvsp_Coord3D_AC32             =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(64) | 0x3004),//0x82403004
+    PixelType_Gvsp_Coord3D_A32f             =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(32) | 0x00BD),//0x012000BD
+    PixelType_Gvsp_Coord3D_A32              =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(32) | 0x3005),//0x81203005
+    PixelType_Gvsp_Coord3D_C32f             =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(32) | 0x00BF),//0x012000BF
+    PixelType_Gvsp_Coord3D_C32              =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(32) | 0x3006),//0x81203006
+    PixelType_Gvsp_Coord3D_ABC16            =   (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(48) | 0x00B9),//0x023000B9
+    PixelType_Gvsp_Coord3D_C16              =   (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x00B8),//0x011000B8
+
+    PixelType_Gvsp_Float32                  =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(32) | 0x0001),//0x81200001
+
+    //无损压缩像素格式定义
+    PixelType_Gvsp_HB_Mono8                    =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(8) | 0x0001),
+    PixelType_Gvsp_HB_Mono10                   =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0003),
+    PixelType_Gvsp_HB_Mono10_Packed            =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x0004),
+    PixelType_Gvsp_HB_Mono12                   =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0005),
+    PixelType_Gvsp_HB_Mono12_Packed            =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x0006),
+    PixelType_Gvsp_HB_Mono16                   =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0007),
+    PixelType_Gvsp_HB_BayerGR8                 =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(8) | 0x0008),
+    PixelType_Gvsp_HB_BayerRG8                 =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(8) | 0x0009),
+    PixelType_Gvsp_HB_BayerGB8                 =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(8) | 0x000A),
+    PixelType_Gvsp_HB_BayerBG8                 =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(8) | 0x000B),
+    PixelType_Gvsp_HB_BayerRBGG8               =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(8) | 0x0046),
+    PixelType_Gvsp_HB_BayerGR10                =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x000C),
+    PixelType_Gvsp_HB_BayerRG10                =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x000D),
+    PixelType_Gvsp_HB_BayerGB10                =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x000E),
+    PixelType_Gvsp_HB_BayerBG10                =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x000F),
+    PixelType_Gvsp_HB_BayerGR12                =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0010),
+    PixelType_Gvsp_HB_BayerRG12                =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0011),
+    PixelType_Gvsp_HB_BayerGB12                =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0012),
+    PixelType_Gvsp_HB_BayerBG12                =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0013),
+    PixelType_Gvsp_HB_BayerGR10_Packed         =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x0026),
+    PixelType_Gvsp_HB_BayerRG10_Packed         =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x0027),
+    PixelType_Gvsp_HB_BayerGB10_Packed         =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x0028),
+    PixelType_Gvsp_HB_BayerBG10_Packed         =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x0029),
+    PixelType_Gvsp_HB_BayerGR12_Packed         =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x002A),
+    PixelType_Gvsp_HB_BayerRG12_Packed         =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x002B),
+    PixelType_Gvsp_HB_BayerGB12_Packed         =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x002C),
+    PixelType_Gvsp_HB_BayerBG12_Packed         =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x002D),
+    PixelType_Gvsp_HB_YUV422_Packed            =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(16) | 0x001F),
+    PixelType_Gvsp_HB_YUV422_YUYV_Packed       =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(16) | 0x0032),
+    PixelType_Gvsp_HB_RGB8_Packed              =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(24) | 0x0014),
+    PixelType_Gvsp_HB_BGR8_Packed              =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(24) | 0x0015),
+    PixelType_Gvsp_HB_RGBA8_Packed             =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(32) | 0x0016),
+    PixelType_Gvsp_HB_BGRA8_Packed             =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(32) | 0x0017),
+    PixelType_Gvsp_HB_RGB16_Packed             =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(48) | 0x0033),
+    PixelType_Gvsp_HB_BGR16_Packed             =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(48) | 0x004B),
+    PixelType_Gvsp_HB_RGBA16_Packed            =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(64) | 0x0064),
+    PixelType_Gvsp_HB_BGRA16_Packed            =   (MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(64) | 0x0051),
+
+};
+
+#ifdef WIN32
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#else
+#include <stdint.h>
+#endif
+
+#endif /* _MV_PIXEL_TYPE_H_ */

+ 79 - 0
mvs_usb_takephoto/lib/armv7hf/CommonParameters.ini

@@ -0,0 +1,79 @@
+;@~chinese
+;该配置文件列出了部分可配置的参数,其他可配置参数请参考软件安装路径下 /opt/(软件名)/doc/工业相机SDK可配置化参数表.xlsx
+;修改配置后上层应用程序要重新启动
+;不分设备类型的通用参数
+;@~english
+;The configuration file lists some configurable parameters, other configurable parameters please refer to the software installation path /opt/(Software)/doc/Camera SDK configurable parameter table.xlsx
+;When modifying the configuration, the upper application need restarted
+;Generic parameters that do not distinguish device types
+[COMMON]
+;@~chinese
+;设置SDK内部图像缓存节点个数,若调用接口(MV_CC_SetImageNodeNum)主动设置,则此参数无效;若是外部分配缓存模式(即调用MV_CC_RegisterBuffer)此参数也无效;不支持MV_CAMERALINK_DEVICE 类型的设备
+;SDK实际分配的节点个数 = SDK内部预分配的个数 + ImageNodeNum;
+;不同相机因为取流方式不同,SDK内部预分配的个数不同:比如 双U内部分配默认3个节点
+;@~english
+;Set the number of image cache nodes within the SDK, and if you call the interface (MV_CC_SetImageNodeNum or MV_CC_RegisterBuffer), the parameter is invalid; not support MV_CAMERALINK_DEVICE device
+;The actual number of image cache nodes allocated by the SDK = the number of pre allocated nodes within the SDK + ImageNodeNum;
+;Different cameras default to different pre allocated nodes. For example, for dual USB camera, the default number is 3
+ImageNodeNum=1  
+
+;@~chinese
+;网口相机相关参数
+;@~english
+;The parameters of Gige camera
+[GIGE]
+;@~chinese
+;设置GVCP命令超时时间,默认500ms,范围:0-10000ms
+;@~english
+;Set GVCP command timeout time, the default value is 500ms, range: 0-10000ms
+GvcpTimeout=500
+
+;@~chinese
+;U口相机相关参数
+;@~english
+;The parameters of U3V camera
+[U3V]
+;@~chinese
+;设置U3V的传输包大小,Byte,默认为1M,rang:>=0x400
+;@~english
+;Set transfer size of U3V device, the unit is Byte, Default 1M,rang: >=0x400
+TransferSize=1048576
+;@~chinese
+;设置流包间隔超时时间,默认50ms,当超时时间>1000ms会关闭断流恢复机制
+;@~english
+;Set stream payload interval timeout, Default 50ms;
+StreamPayloadTimeout=50
+;@~chinese
+;设置出流寄存器读写超时时间,默认30ms
+;@~english
+;Set stream control register timeout, Default 30ms
+SIControlRegTimeout=30
+;@~chinese
+;设置控制寄存器读写超时时间,默认1000ms
+;除SI寄存器外
+;@~english
+;Set control Reg  timeout ms, Default 1000ms
+;Except SI Reg
+SyncTimeout=1000
+
+;@~chinese
+;CameraLink相机相关参数
+;@~english
+;The parameters of CameraLink camera
+[CAML]
+
+;@~chinese
+;图像处理相关的参数
+;@~english
+;The parameters of image processing
+[IMG_PROCESSING]
+;@~chinese
+;设置插值算法类型,0-快速 1-均衡 2-最优 3-最优+(默认为均衡)
+;@~english
+;Interpolation algorithm type setting, 0-Fast 1-Equilibrium 2-Optimal 3-Optimal+(the default value is 1-Equilibrium)
+BayerCvtQuality=1
+;@~chinese
+;设置插值算法处理线程个数,0-自适应 其他-具体线程个数(1,2,3,...)(默认线程个数为4)
+;@~english
+;Set the interpolation algorithm of thread handle count, 0-self-adapting, other-number of specific thread count(1,2,3,...) (the default thread count is 4)
+BayerCvtThreadNum=4

BIN
mvs_usb_takephoto/lib/armv7hf/MvProducerGEV.cti


BIN
mvs_usb_takephoto/lib/armv7hf/MvProducerU3V.cti


BIN
mvs_usb_takephoto/lib/armv7hf/libFormatConversion.so


+ 1 - 0
mvs_usb_takephoto/lib/armv7hf/libMVGigEVisionSDK.so

@@ -0,0 +1 @@
+libMVGigEVisionSDK.so.4.5.0.3

BIN
mvs_usb_takephoto/lib/armv7hf/libMVGigEVisionSDK.so.4.5.0.3


BIN
mvs_usb_takephoto/lib/armv7hf/libMVRender.so


BIN
mvs_usb_takephoto/lib/armv7hf/libMediaProcess.so


+ 1 - 0
mvs_usb_takephoto/lib/armv7hf/libMvCameraControl.so

@@ -0,0 +1 @@
+libMvCameraControl.so.4.5.0.3

BIN
mvs_usb_takephoto/lib/armv7hf/libMvCameraControl.so.4.5.0.3


+ 1 - 0
mvs_usb_takephoto/lib/armv7hf/libMvCameraControlWrapper.so

@@ -0,0 +1 @@
+libMvCameraControlWrapper.so.4.5.0.1

BIN
mvs_usb_takephoto/lib/armv7hf/libMvCameraControlWrapper.so.4.5.0.1


BIN
mvs_usb_takephoto/lib/armv7hf/libMvSDKVersion.so


+ 1 - 0
mvs_usb_takephoto/lib/armv7hf/libMvUsb3vTL.so

@@ -0,0 +1 @@
+libMvUsb3vTL.so.4.5.0.3

BIN
mvs_usb_takephoto/lib/armv7hf/libMvUsb3vTL.so.4.5.0.3


BIN
mvs_usb_takephoto/lib/armv7hf/libavutil.so


BIN
mvs_usb_takephoto/lib/armv7hf/libswscale.so


BIN
mvs_usb_takephoto/lib/armv7hf/libusb-1.0.so.0


+ 79 - 0
mvs_usb_takephoto/lib/x86_64/32/CommonParameters.ini

@@ -0,0 +1,79 @@
+;@~chinese
+;该配置文件列出了部分可配置的参数,其他可配置参数请参考软件安装路径下 /opt/(软件名)/doc/工业相机SDK可配置化参数表.xlsx
+;修改配置后上层应用程序要重新启动
+;不分设备类型的通用参数
+;@~english
+;The configuration file lists some configurable parameters, other configurable parameters please refer to the software installation path /opt/(Software)/doc/Camera SDK configurable parameter table.xlsx
+;When modifying the configuration, the upper application need restarted
+;Generic parameters that do not distinguish device types
+[COMMON]
+;@~chinese
+;设置SDK内部图像缓存节点个数,若调用接口(MV_CC_SetImageNodeNum)主动设置,则此参数无效;若是外部分配缓存模式(即调用MV_CC_RegisterBuffer)此参数也无效;不支持MV_CAMERALINK_DEVICE 类型的设备
+;SDK实际分配的节点个数 = SDK内部预分配的个数 + ImageNodeNum;
+;不同相机因为取流方式不同,SDK内部预分配的个数不同:比如 双U内部分配默认3个节点
+;@~english
+;Set the number of image cache nodes within the SDK, and if you call the interface (MV_CC_SetImageNodeNum or MV_CC_RegisterBuffer), the parameter is invalid; not support MV_CAMERALINK_DEVICE device
+;The actual number of image cache nodes allocated by the SDK = the number of pre allocated nodes within the SDK + ImageNodeNum;
+;Different cameras default to different pre allocated nodes. For example, for dual USB camera, the default number is 3
+ImageNodeNum=1  
+
+;@~chinese
+;网口相机相关参数
+;@~english
+;The parameters of Gige camera
+[GIGE]
+;@~chinese
+;设置GVCP命令超时时间,默认500ms,范围:0-10000ms
+;@~english
+;Set GVCP command timeout time, the default value is 500ms, range: 0-10000ms
+GvcpTimeout=500
+
+;@~chinese
+;U口相机相关参数
+;@~english
+;The parameters of U3V camera
+[U3V]
+;@~chinese
+;设置U3V的传输包大小,Byte,默认为1M,rang:>=0x400
+;@~english
+;Set transfer size of U3V device, the unit is Byte, Default 1M,rang: >=0x400
+TransferSize=1048576
+;@~chinese
+;设置流包间隔超时时间,默认50ms,当超时时间>1000ms会关闭断流恢复机制
+;@~english
+;Set stream payload interval timeout, Default 50ms;
+StreamPayloadTimeout=50
+;@~chinese
+;设置出流寄存器读写超时时间,默认30ms
+;@~english
+;Set stream control register timeout, Default 30ms
+SIControlRegTimeout=30
+;@~chinese
+;设置控制寄存器读写超时时间,默认1000ms
+;除SI寄存器外
+;@~english
+;Set control Reg  timeout ms, Default 1000ms
+;Except SI Reg
+SyncTimeout=1000
+
+;@~chinese
+;CameraLink相机相关参数
+;@~english
+;The parameters of CameraLink camera
+[CAML]
+
+;@~chinese
+;图像处理相关的参数
+;@~english
+;The parameters of image processing
+[IMG_PROCESSING]
+;@~chinese
+;设置插值算法类型,0-快速 1-均衡 2-最优 3-最优+(默认为均衡)
+;@~english
+;Interpolation algorithm type setting, 0-Fast 1-Equilibrium 2-Optimal 3-Optimal+(the default value is 1-Equilibrium)
+BayerCvtQuality=1
+;@~chinese
+;设置插值算法处理线程个数,0-自适应 其他-具体线程个数(1,2,3,...)(默认线程个数为4)
+;@~english
+;Set the interpolation algorithm of thread handle count, 0-self-adapting, other-number of specific thread count(1,2,3,...) (the default thread count is 4)
+BayerCvtThreadNum=4

BIN
mvs_usb_takephoto/lib/x86_64/32/MvProducerGEV.cti


BIN
mvs_usb_takephoto/lib/x86_64/32/MvProducerU3V.cti


BIN
mvs_usb_takephoto/lib/x86_64/32/libFormatConversion.so


+ 1 - 0
mvs_usb_takephoto/lib/x86_64/32/libMVGigEVisionSDK.so

@@ -0,0 +1 @@
+libMVGigEVisionSDK.so.4.5.0.3

BIN
mvs_usb_takephoto/lib/x86_64/32/libMVGigEVisionSDK.so.4.5.0.3


BIN
mvs_usb_takephoto/lib/x86_64/32/libMVRender.so


BIN
mvs_usb_takephoto/lib/x86_64/32/libMediaProcess.so


+ 1 - 0
mvs_usb_takephoto/lib/x86_64/32/libMvCameraControl.so

@@ -0,0 +1 @@
+libMvCameraControl.so.4.5.0.3

BIN
mvs_usb_takephoto/lib/x86_64/32/libMvCameraControl.so.4.5.0.3


+ 1 - 0
mvs_usb_takephoto/lib/x86_64/32/libMvCameraControlWrapper.so

@@ -0,0 +1 @@
+libMvCameraControlWrapper.so.4.5.0.1

BIN
mvs_usb_takephoto/lib/x86_64/32/libMvCameraControlWrapper.so.4.5.0.1


BIN
mvs_usb_takephoto/lib/x86_64/32/libMvSDKVersion.so


+ 1 - 0
mvs_usb_takephoto/lib/x86_64/32/libMvUsb3vTL.so

@@ -0,0 +1 @@
+libMvUsb3vTL.so.4.5.0.3

BIN
mvs_usb_takephoto/lib/x86_64/32/libMvUsb3vTL.so.4.5.0.3


BIN
mvs_usb_takephoto/lib/x86_64/32/libavutil.so


BIN
mvs_usb_takephoto/lib/x86_64/32/libswscale.so


BIN
mvs_usb_takephoto/lib/x86_64/32/libusb-1.0.so.0


+ 79 - 0
mvs_usb_takephoto/lib/x86_64/64/CommonParameters.ini

@@ -0,0 +1,79 @@
+;@~chinese
+;该配置文件列出了部分可配置的参数,其他可配置参数请参考软件安装路径下 /opt/(软件名)/doc/工业相机SDK可配置化参数表.xlsx
+;修改配置后上层应用程序要重新启动
+;不分设备类型的通用参数
+;@~english
+;The configuration file lists some configurable parameters, other configurable parameters please refer to the software installation path /opt/(Software)/doc/Camera SDK configurable parameter table.xlsx
+;When modifying the configuration, the upper application need restarted
+;Generic parameters that do not distinguish device types
+[COMMON]
+;@~chinese
+;设置SDK内部图像缓存节点个数,若调用接口(MV_CC_SetImageNodeNum)主动设置,则此参数无效;若是外部分配缓存模式(即调用MV_CC_RegisterBuffer)此参数也无效;不支持MV_CAMERALINK_DEVICE 类型的设备
+;SDK实际分配的节点个数 = SDK内部预分配的个数 + ImageNodeNum;
+;不同相机因为取流方式不同,SDK内部预分配的个数不同:比如 双U内部分配默认3个节点
+;@~english
+;Set the number of image cache nodes within the SDK, and if you call the interface (MV_CC_SetImageNodeNum or MV_CC_RegisterBuffer), the parameter is invalid; not support MV_CAMERALINK_DEVICE device
+;The actual number of image cache nodes allocated by the SDK = the number of pre allocated nodes within the SDK + ImageNodeNum;
+;Different cameras default to different pre allocated nodes. For example, for dual USB camera, the default number is 3
+ImageNodeNum=1  
+
+;@~chinese
+;网口相机相关参数
+;@~english
+;The parameters of Gige camera
+[GIGE]
+;@~chinese
+;设置GVCP命令超时时间,默认500ms,范围:0-10000ms
+;@~english
+;Set GVCP command timeout time, the default value is 500ms, range: 0-10000ms
+GvcpTimeout=500
+
+;@~chinese
+;U口相机相关参数
+;@~english
+;The parameters of U3V camera
+[U3V]
+;@~chinese
+;设置U3V的传输包大小,Byte,默认为1M,rang:>=0x400
+;@~english
+;Set transfer size of U3V device, the unit is Byte, Default 1M,rang: >=0x400
+TransferSize=1048576
+;@~chinese
+;设置流包间隔超时时间,默认50ms,当超时时间>1000ms会关闭断流恢复机制
+;@~english
+;Set stream payload interval timeout, Default 50ms;
+StreamPayloadTimeout=50
+;@~chinese
+;设置出流寄存器读写超时时间,默认30ms
+;@~english
+;Set stream control register timeout, Default 30ms
+SIControlRegTimeout=30
+;@~chinese
+;设置控制寄存器读写超时时间,默认1000ms
+;除SI寄存器外
+;@~english
+;Set control Reg  timeout ms, Default 1000ms
+;Except SI Reg
+SyncTimeout=1000
+
+;@~chinese
+;CameraLink相机相关参数
+;@~english
+;The parameters of CameraLink camera
+[CAML]
+
+;@~chinese
+;图像处理相关的参数
+;@~english
+;The parameters of image processing
+[IMG_PROCESSING]
+;@~chinese
+;设置插值算法类型,0-快速 1-均衡 2-最优 3-最优+(默认为均衡)
+;@~english
+;Interpolation algorithm type setting, 0-Fast 1-Equilibrium 2-Optimal 3-Optimal+(the default value is 1-Equilibrium)
+BayerCvtQuality=1
+;@~chinese
+;设置插值算法处理线程个数,0-自适应 其他-具体线程个数(1,2,3,...)(默认线程个数为4)
+;@~english
+;Set the interpolation algorithm of thread handle count, 0-self-adapting, other-number of specific thread count(1,2,3,...) (the default thread count is 4)
+BayerCvtThreadNum=4

BIN
mvs_usb_takephoto/lib/x86_64/64/MvFGProducerCML.cti


+ 0 - 0
mvs_usb_takephoto/lib/x86_64/64/MvFGProducerCXP.cti


Некоторые файлы не были показаны из-за большого количества измененных файлов