فهرست منبع

1,完成大华相机模块的封装,并加入到标准模块框架;2,完成上传统一控制海康和大华相机的camera模块,并完成单元测试

niujiuru 3 هفته پیش
والد
کامیت
a1a527a61d
8فایلهای تغییر یافته به همراه314 افزوده شده و 12 حذف شده
  1. 46 8
      Makefile
  2. 67 0
      camera/takephoto.go
  3. 64 0
      dh_takephoto/bridge.go
  4. 36 0
      dh_takephoto/takephoto.go
  5. 2 2
      hk_takephoto/bridge.go
  6. 2 2
      main.go
  7. 49 0
      tests/camera/main.go
  8. 48 0
      tests/dh_takephoto/main.go

+ 46 - 8
Makefile

@@ -9,7 +9,7 @@ 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
+target ?= armv7hf
 ifeq ($(target),armv7hf)
   GOOS := linux
   GOARCH := arm
@@ -29,7 +29,7 @@ SETGO_ENV = \
 DATE := $(shell date +%Y%m%d_%H%M%S)
 
 # 编译的目标
-all : hk_takephoto.out air720u_4g.out rtu_linux_modules.out
+all : camera_test.out hk_takephoto.out dh_takephoto.out air720u_4g.out rtu_linux_modules.out
 
 # 通用基础库
 libswapi.a :
@@ -39,6 +39,10 @@ libswapi.a :
 libhk_takephoto.a :
 	$(MAKE) -C hk_takephoto target=$(target) $@
 
+# "iRAYPLE"
+libdh_takephoto.a :
+	$(MAKE) -C dh_takephoto target=$(target) $@
+
 # "Air720U"
 libair720u.a :
 	$(MAKE) -C air720u target=$(target) $@
@@ -47,11 +51,11 @@ libair720u.a :
 libair530z.a :
 	$(MAKE) -C air530z target=$(target) $@
 
-#  "EC200U"
+## "EC200U"
 libec200u.a :
 	$(MAKE) -C ec200u target=$(target)  $@
 
-# "YMODEM"
+## "YMODEM"
 libymodem.a :
 	$(MAKE) -C ymodem target=$(target)  $@
 
@@ -63,10 +67,10 @@ else
   LIB1 += -Wl,-Bdynamic -lc -lm -ldl -lpthread -L$(PWD)/hk_takephoto/lib/x86_64/64 -lMvCameraControl
 endif
 hk_takephoto.out : libswapi.a libhk_takephoto.a ./tests/hk_takephoto/main.go
-	mkdir -p ./build/takephoto_test
+	mkdir -p ./build/hk_takephoto_test
 	$(GO) mod tidy
 	$(SETGO_ENV) CGO_LDFLAGS="$(LIB1)" $(GO_BUILD) $(GO_FLAGS) -o $@ ./tests/hk_takephoto/main.go
-	@cp $@ ./build/takephoto_test/$(basename $@)_$(DATE)$(suffix $@)
+	@cp $@ ./build/hk_takephoto_test/$(basename $@)_$(DATE)$(suffix $@)
 	rm -rf $@
 
 # 测4G模块Air720U
@@ -87,10 +91,43 @@ ec200u_4g.out : libswapi.a libec200u.a ./tests/ec200u/main.go
 	@cp $@ ./build/ec200u_test/$(basename $@)_$(DATE)$(suffix $@)
 	rm -rf $@
 
-# 主测试程序
-LIBS := -Wl,-Bstatic -L./swapi -lswapi -L./hk_takephoto -lhk_takephoto -L./air720u -lair720u -L./air530z -lair530z -L./ec200u -lec200u
+# 大华相机拍照测试
+LIB4 := -Wl,-Bstatic -L./swapi -lswapi -L./dh_takephoto -ldh_takephoto
+ifeq ($(target),armv7hf)
+  LIB4 += -Wl,-Bdynamic -lc -lm -ldl -lpthread -L$(PWD)/dh_takephoto/lib/armv7hf -lMVSDK -liImageProcessing -lImageConvert -llog4cpp -lMvLSCProcess
+	LIB4 += -L$(PWD)/dh_takephoto/lib/armv7hf/GenICam/bin -lGCBase_gcc483_v3_0 -lGenApi_gcc483_v3_0 -lLog_gcc483_v3_0 -llog4cpp_gcc483_v3_0 -lMathParser_gcc483_v3_0 -lNodeMapData_gcc483_v3_0 -lXmlParser_gcc483_v3_0
+else
+  $(error Unsupported target: $(target), only armv7hf is supported)
+endif
+dh_takephoto.out : libswapi.a libdh_takephoto.a ./tests/dh_takephoto/main.go
+	mkdir -p ./build/dh_takephoto_test
+	$(GO) mod tidy
+	$(SETGO_ENV) CGO_LDFLAGS="$(LIB4)" $(GO_BUILD) $(GO_FLAGS) -o $@ ./tests/dh_takephoto/main.go
+	@cp $@ ./build/dh_takephoto_test/$(basename $@)_$(DATE)$(suffix $@)
+	rm -rf $@
+
+# 综合相机测试程序
+LIB5 := -Wl,-Bstatic -L./swapi -lswapi -L./hk_takephoto -lhk_takephoto -L./dh_takephoto -ldh_takephoto
+ifeq ($(target),armv7hf)
+  LIB5 += -Wl,-Bdynamic -lc -lm -ldl -lpthread -L$(PWD)/hk_takephoto/lib/armv7hf/. -lMvCameraControl
+	LIB5 += -L$(PWD)/dh_takephoto/lib/armv7hf -lMVSDK -liImageProcessing -lImageConvert -llog4cpp -lMvLSCProcess
+	LIB5 += -L$(PWD)/dh_takephoto/lib/armv7hf/GenICam/bin -lGCBase_gcc483_v3_0 -lGenApi_gcc483_v3_0 -lLog_gcc483_v3_0 -llog4cpp_gcc483_v3_0 -lMathParser_gcc483_v3_0 -lNodeMapData_gcc483_v3_0 -lXmlParser_gcc483_v3_0
+else
+  $(error Unsupported target: $(target), only armv7hf is supported)
+endif
+camera_test.out : libswapi.a libhk_takephoto.a libdh_takephoto.a ./tests/camera/main.go
+	mkdir -p ./build/camera_test
+	$(GO) mod tidy
+	$(SETGO_ENV) CGO_LDFLAGS="$(LIB5)" $(GO_BUILD) $(GO_FLAGS) -o $@ ./tests/camera/main.go
+	@cp $@ ./build/camera_test/$(basename $@)_$(DATE)$(suffix $@)
+	rm -rf $@
+
+# 综合应用测试程序
+LIBS := -Wl,-Bstatic -L./swapi -lswapi -L./hk_takephoto -lhk_takephoto -L./air720u -lair720u -L./air530z -lair530z -L./ec200u -lec200u -L./dh_takephoto -ldh_takephoto
 ifeq ($(target),armv7hf)
   LIBS += -Wl,-Bdynamic -lc -lm -ldl -lpthread -L$(PWD)/hk_takephoto/lib/armv7hf/. -lMvCameraControl
+	LIBS += -L$(PWD)/dh_takephoto/lib/armv7hf -lMVSDK -liImageProcessing -lImageConvert -llog4cpp -lMvLSCProcess
+	LIBS += -L$(PWD)/dh_takephoto/lib/armv7hf/GenICam/bin -lGCBase_gcc483_v3_0 -lGenApi_gcc483_v3_0 -lLog_gcc483_v3_0 -llog4cpp_gcc483_v3_0 -lMathParser_gcc483_v3_0 -lNodeMapData_gcc483_v3_0 -lXmlParser_gcc483_v3_0
 else
   LIBS += -Wl,-Bdynamic -lc -lm -ldl -lpthread -L$(PWD)/hk_takephoto/lib/x86_64/64 -lMvCameraControl
 endif
@@ -104,6 +141,7 @@ rtu_linux_modules.out : libswapi.a libhk_takephoto.a libair720u.a libair530z.a l
 clean :
 	make -C ./swapi clean
 	make -C ./hk_takephoto clean
+	make -C ./dh_takephoto clean
 	make -C ./air720u clean
 	make -C ./air530z clean
 	make -C ./ec200u  clean

+ 67 - 0
camera/takephoto.go

@@ -1,6 +1,7 @@
 package camera
 
 import (
+	"errors"
 	"fmt"
 	"os"
 	"os/exec"
@@ -10,12 +11,26 @@ import (
 	"github.com/vishvananda/netlink"
 
 	"hnyfkj.com.cn/rtu/linux/baseapp"
+	"hnyfkj.com.cn/rtu/linux/dh_takephoto"
 	"hnyfkj.com.cn/rtu/linux/hk_takephoto"
 )
 
 // 相机模块的名称
 const MODULE_NAME = "Camera"
 
+// 图像类型
+const (
+	IMG_TYPE_BMP = 1 // 拍照输出"bmp"图像
+	IMG_TYPE_JPG = 2 // 拍照输出"jpg"图像
+)
+
+// 图像水印
+type SImgMark struct {
+	CamModelName    string  // 相机型号名
+	CamSerialNum    string  // 相机序列号
+	ImgExposureTime float64 // 曝光时间值
+}
+
 // 配置连接网口相机的网卡ip
 func SetupEth1ForGigeCamera(cidr string) error {
 	link, err := netlink.LinkByName("eth1")
@@ -109,5 +124,57 @@ initOK:
 		return false
 	}
 
+	if !dh_takephoto.ModuleInit() {
+		return false
+	}
+
 	return true
 }
+
+func GetHKCameraCount() int {
+	return hk_takephoto.GetHKCameraCount()
+}
+
+func GetDHCameraCount() int {
+	return dh_takephoto.GetDHCameraCount()
+}
+
+func GetSupportedCameraCount() int {
+	return GetHKCameraCount() + GetDHCameraCount()
+}
+
+// 单次执行相机拍照, 并保存到文件, 成功返回: 本次拍照图像的水印信息, 失败返回: 错误原因和空的水印信息
+// 参数说明:
+// "imgType"     - 图像保存类型: 1-".bmp", 2-".jpg"
+// "saveImgPath" - 保存的文件名: 根据所选保存图像的类型, 程序会自动校检和处理文件的扩展名(智能)
+// "timeout"     - 等待超时时间, 单位:秒: < 0 表示无超时; 无论超时怎么设置, 首次尝试拍照一定会
+// 执行, 但时间不确定; 拍照成功、超时(相机持续无数据的时间)或发生错误时会自动结束任务.
+func TakePhoto(imgType int, saveImgPath string, timeout int) (SImgMark, error) {
+	var errs []error
+
+	if (imgType != IMG_TYPE_BMP && imgType != IMG_TYPE_JPG) || len(saveImgPath) == 0 {
+		return SImgMark{}, fmt.Errorf("invalid arguments")
+	}
+
+	hkMark, err := hk_takephoto.TakePhoto(imgType, saveImgPath, timeout)
+	if err == nil {
+		return SImgMark{
+			CamModelName:    hkMark.CamModelName,
+			CamSerialNum:    hkMark.CamSerialNum,
+			ImgExposureTime: hkMark.ImgExposureTime,
+		}, nil
+	}
+	errs = append(errs, fmt.Errorf("HK: %w", err))
+
+	dhMark, err := dh_takephoto.TakePhoto(imgType, saveImgPath, timeout)
+	if err == nil {
+		return SImgMark{
+			CamModelName:    dhMark.CamModelName,
+			CamSerialNum:    dhMark.CamSerialNum,
+			ImgExposureTime: dhMark.ImgExposureTime,
+		}, nil
+	}
+	errs = append(errs, fmt.Errorf("DH: %w", err))
+
+	return SImgMark{}, errors.Join(errs...)
+}

+ 64 - 0
dh_takephoto/bridge.go

@@ -4,3 +4,67 @@ package dh_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 float64 // 曝光时间值
+}
+
+// 获取系统当前USBFS内存大小(MB), 成功返回: >=0, 失败返回: <0值
+func getSysUsbfsMemCurrentSize() int {
+	ret := int(C.DH_GetSysUsbfsMemCurrentSize())
+	return ret
+}
+
+// 设置系统新的USBFS内存大小(MB), 成功返回: 0值, 失败返回: <0值
+func setSysUsbfsMemSize(val int) int {
+	setNewV := C.int(val)
+	ret := int(C.DH_SetSysUsbfsMemSize(setNewV))
+	return ret
+}
+
+// 获取当前已连接的大华相机的数量, 成功返回: >=0, 失败返回: <0值
+func GetDHCameraCount() int {
+	ret := int(C.DH_GetCameraCount())
+	return ret
+}
+
+// 单次执行相机拍照, 并保存到文件, 成功返回: 本次拍照图像的水印信息, 失败返回: 错误原因和空的水印信息
+// 参数说明:
+// "imgType"     - 图像保存类型: 1-".bmp", 2-".jpg"
+// "saveImgPath" - 保存的文件名: 根据所选保存图像的类型, 程序会自动校检和处理文件的扩展名(智能)
+// "timeout"     - 等待超时时间, 单位:秒: < 0 表示无超时; 无论超时怎么设置, 首次尝试拍照一定会
+// 执行, 但时间不确定; 拍照成功、超时(相机持续无数据的时间)或发生错误时会自动结束任务.
+func TakePhoto(imgType int, saveImgPath string, timeout int) (SImgMark, error) {
+	if (imgType != IMG_TYPE_BMP && imgType != IMG_TYPE_JPG) || len(saveImgPath) == 0 {
+		return SImgMark{}, fmt.Errorf("invalid arguments")
+	}
+
+	path := C.CString(saveImgPath)
+	defer C.free(unsafe.Pointer(path))
+
+	var imgMark C.DHImgMark
+	ret := int(C.DH_TakePhoto(C.DHImgType(imgType), path, C.int(timeout), &imgMark))
+	if ret != 0 {
+		return SImgMark{}, fmt.Errorf("an error occurred while calling the C.DH_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: float64(imgMark.imgExposureTime),
+	}, nil
+}

+ 36 - 0
dh_takephoto/takephoto.go

@@ -1 +1,37 @@
 package dh_takephoto
+
+import (
+	"time"
+
+	"hnyfkj.com.cn/rtu/linux/baseapp"
+)
+
+// 相机模块的名称
+const MODULE_NAME = "HuarayTakePhoto"
+
+// 相机模块初始化, 设置必要的运行环境参数, 只有成功才能进行后续的拍照操作
+func ModuleInit() bool {
+	myUsbfsMemSize := 200 // 单位: 兆字节
+	bSetOK := false
+
+	for range 5 {
+		if baseapp.IsExit1() {
+			return false
+		}
+		if getSysUsbfsMemCurrentSize() >= myUsbfsMemSize {
+			bSetOK = true
+			break // 已满足启动拍照程序的条件, 退出循环
+		}
+		ret := setSysUsbfsMemSize(myUsbfsMemSize)
+		if ret == -1 {
+			time.Sleep(1 * time.Second)
+		}
+	}
+
+	if !bSetOK {
+		baseapp.Logger.Errorf("[%s] 无法将系统\"usbfs\"的内存大小设置为: %dMB, 相机模块初始化失败!!", MODULE_NAME, myUsbfsMemSize)
+		return false
+	}
+
+	return true
+}

+ 2 - 2
hk_takephoto/bridge.go

@@ -23,7 +23,7 @@ const (
 type SImgMark struct {
 	CamModelName    string  // 相机型号名
 	CamSerialNum    string  // 相机序列号
-	ImgExposureTime float32 // 曝光时间值
+	ImgExposureTime float64 // 曝光时间值
 }
 
 // 获取系统当前USBFS内存大小(MB), 成功返回: >=0, 失败返回: <0值
@@ -68,6 +68,6 @@ func TakePhoto(imgType int, saveImgPath string, timeout int) (SImgMark, error) {
 	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),
+		ImgExposureTime: float64(imgMark.imgExposureTime),
 	}, nil
 }

+ 2 - 2
main.go

@@ -7,7 +7,7 @@ import (
 
 	gps "hnyfkj.com.cn/rtu/linux/air530z"
 	baseapp "hnyfkj.com.cn/rtu/linux/baseapp"
-	camera1 "hnyfkj.com.cn/rtu/linux/hk_takephoto" // 海康相机
+	camera1 "hnyfkj.com.cn/rtu/linux/camera"
 	netmgrd "hnyfkj.com.cn/rtu/linux/netmgrd"
 	"hnyfkj.com.cn/rtu/linux/sshd"
 )
@@ -114,7 +114,7 @@ func main() {
 	sshd.ModuleInit("", "", "")
 
 	// 05, 初始化相机拍照模块
-	if !camera1.ModuleInit() {
+	if !camera1.ModuleInit(true, "192.168.100.123/24", "192.168.100.100") { //支持网口
 		goto end_p
 	}
 

+ 49 - 0
tests/camera/main.go

@@ -0,0 +1,49 @@
+package main
+
+import (
+	"fmt"
+	"time"
+
+	"hnyfkj.com.cn/rtu/linux/baseapp"
+	camera "hnyfkj.com.cn/rtu/linux/camera"
+)
+
+func main() {
+	baseapp.ModuleInit()
+	if !camera.ModuleInit(true, "192.168.100.123/24", "192.168.100.100") {
+		return
+	}
+
+	baseapp.Logger.Infof("Get HK camera count: %d", camera.GetHKCameraCount())
+	baseapp.Logger.Infof("Get DH camera count: %d", camera.GetDHCameraCount())
+
+	baseapp.Logger.Infof("开始拍照测试 ...")
+	imgType := 0
+	imgFile := ""
+	for i := range 9 {
+		switch i {
+		case 0:
+			imgType = camera.IMG_TYPE_BMP
+			imgFile = fmt.Sprintf("./test%d.bmp", i+1)
+		default:
+			imgType = camera.IMG_TYPE_JPG
+			imgFile = fmt.Sprintf("./test%d.jpg", i+1)
+		}
+
+		var imgMark camera.SImgMark
+		var err error
+
+		start := time.Now()
+		imgMark, err = camera.TakePhoto(imgType, imgFile, 5*60)
+		elapsed := time.Since(start).Milliseconds()
+
+		if err == nil {
+			baseapp.Logger.Infof("输出: \"%s\", 用时: %dms, 拍照信息: %+v", imgFile, elapsed, imgMark)
+		} else {
+			baseapp.Logger.Errorf("拍照时发生错误: %v, 用时: %dms, 请修复所有问题后重试!!", err, elapsed)
+		}
+
+		time.Sleep(1 * time.Second) // 轮询拍照测试时, 给系统预留一定的相机释放时间
+	}
+	baseapp.Logger.Info("拍照测试任务结束")
+}

+ 48 - 0
tests/dh_takephoto/main.go

@@ -0,0 +1,48 @@
+package main
+
+import (
+	"fmt"
+	"time"
+
+	"hnyfkj.com.cn/rtu/linux/baseapp"
+	camera "hnyfkj.com.cn/rtu/linux/dh_takephoto"
+)
+
+func main() {
+	baseapp.ModuleInit()
+	if !camera.ModuleInit() {
+		return
+	}
+
+	baseapp.Logger.Infof("Get DH camera count: %d", camera.GetDHCameraCount())
+
+	baseapp.Logger.Infof("开始拍照测试 ...")
+	imgType := 0
+	imgFile := ""
+	for i := range 9 {
+		switch i {
+		case 0:
+			imgType = camera.IMG_TYPE_BMP
+			imgFile = fmt.Sprintf("./test%d.bmp", i+1)
+		default:
+			imgType = camera.IMG_TYPE_JPG
+			imgFile = fmt.Sprintf("./test%d.jpg", i+1)
+		}
+
+		var imgMark camera.SImgMark
+		var err error
+
+		start := time.Now()
+		imgMark, err = camera.TakePhoto(imgType, imgFile, 5*60)
+		elapsed := time.Since(start).Milliseconds()
+
+		if err == nil {
+			baseapp.Logger.Infof("输出: \"%s\", 用时: %dms, 拍照信息: %+v", imgFile, elapsed, imgMark)
+		} else {
+			baseapp.Logger.Errorf("拍照时发生错误: %v, 用时: %dms, 请修复所有问题后重试!!", err, elapsed)
+		}
+
+		time.Sleep(1 * time.Second) // 轮询拍照测试时, 给系统预留一定的相机释放时间
+	}
+	baseapp.Logger.Info("拍照测试任务结束")
+}