From cb13f28d2efd6d41a276cfe0f6668918791acb2f Mon Sep 17 00:00:00 2001 From: gg Date: Fri, 17 Jan 2025 16:23:24 +0100 Subject: [PATCH 1/3] hikrobot smart camera login ok --- src/components/hikrobot_sc.py | 2 ++ src/test/hikrobot_sc/test_hikrobot_sc.py | 46 ++++++++++++++++++------ src/ui/test/test.py | 1 - 3 files changed, 38 insertions(+), 11 deletions(-) create mode 100644 src/components/hikrobot_sc.py diff --git a/src/components/hikrobot_sc.py b/src/components/hikrobot_sc.py new file mode 100644 index 0000000..8ec73f5 --- /dev/null +++ b/src/components/hikrobot_sc.py @@ -0,0 +1,2 @@ +MV_MAX_DEVICE_NUM=256 +MV_VS_OK=0x00000000 diff --git a/src/test/hikrobot_sc/test_hikrobot_sc.py b/src/test/hikrobot_sc/test_hikrobot_sc.py index de44caa..beb781c 100644 --- a/src/test/hikrobot_sc/test_hikrobot_sc.py +++ b/src/test/hikrobot_sc/test_hikrobot_sc.py @@ -1,10 +1,11 @@ import ctypes import os - +from ctypes import * # Load the MvVisionSensorControl library -mv_lib = ctypes.windll.LoadLibrary("bin/MvVisionSensorControl.dll") +mv_lib = ctypes.windll.LoadLibrary("src/test/hikrobot_sc/bin/MvVisionSensorControl.dll") + +from src.components.hikrobot_sc import * -MV_MAX_DEVICE_NUM=256 # Define the necessary structures and constants from MvVisionSensorDefine.h class MV_VS_DEVICE_INFO(ctypes.Structure): _fields_ = [ @@ -27,8 +28,6 @@ class MV_VS_DEVICE_INFO(ctypes.Structure): ("nReserved", ctypes.c_uint * 8), # Reserved ] -MV_MAX_DEVICE_NUM = 256 # Maximum number of supported devices - class MV_VS_DEVICE_INFO_LIST(ctypes.Structure): _fields_ = [ @@ -37,12 +36,16 @@ class MV_VS_DEVICE_INFO_LIST(ctypes.Structure): ] -# Define MV_VS_OK from MvVSErrorDefine.h (assuming it's 0) -MV_VS_OK = 0 - # Define function signatures -mv_lib.MV_VS_EnumDevices.argtypes = [ctypes.POINTER(MV_VS_DEVICE_INFO_LIST)] -mv_lib.MV_VS_EnumDevices.restype = ctypes.c_int +mv_lib.MV_VS_EnumDevices.argtypes = [POINTER(MV_VS_DEVICE_INFO_LIST)] +mv_lib.MV_VS_EnumDevices.restype = c_int + +mv_lib.MV_VS_CreateHandle.argtypes = [POINTER(c_void_p), c_void_p] # Assuming pHandle is a void* and pstDeviceInfo is a struct +mv_lib.MV_VS_CreateHandle.restype = c_int + +mv_lib.MV_VS_Login.argtypes = [c_void_p, c_char_p, c_char_p] +mv_lib.MV_VS_Login.restype = c_int + def print_device_info(device_info_list): num_devices=device_info_list.nDeviceNum @@ -57,6 +60,8 @@ def print_device_info(device_info_list): def main(): + global MV_VS_OK + print("SC2016 TEST") device_info_list = MV_VS_DEVICE_INFO_LIST() @@ -75,6 +80,27 @@ def main(): print("Find No Devices!") return -2 + if device_info_list.nDeviceNum == 2: + print("Starting dual camera test!") + # Define MV_VS_OK (replace with the actual value) + MV_VS_OK = 0 + MV_VS_DEVICE_INFO_1 = device_info_list.pDeviceInfo[0]; + MV_VS_DEVICE_INFO_2 = device_info_list.pDeviceInfo[1]; + pHandle1 = c_void_p() + pHandle2 = c_void_p() + nRet1 = mv_lib.MV_VS_CreateHandle(byref(pHandle1), MV_VS_DEVICE_INFO_1) + nRet2 = mv_lib.MV_VS_CreateHandle(byref(pHandle2), MV_VS_DEVICE_INFO_2) + if nRet1 != MV_VS_OK or nRet2 != MV_VS_OK: + print(f"Create Handle failed! [{nRet1:#x} {nRet2:#x}]") + return + nRet1 = mv_lib.MV_VS_Login(pHandle1, b"Admin", b"Abc1234") + nRet2 = mv_lib.MV_VS_Login(pHandle2, b"Admin", b"Abc1234") + if nRet1 != MV_VS_OK or nRet2 != MV_VS_OK: + print(f"Login failed! [{nRet1:#x} {nRet2:#x}]") + return + else: + print("Login OK") + return 0 if __name__ == "__main__": diff --git a/src/ui/test/test.py b/src/ui/test/test.py index bbb35c9..1a045d4 100755 --- a/src/ui/test/test.py +++ b/src/ui/test/test.py @@ -6,7 +6,6 @@ import weakref from datetime import datetime, timedelta from PyQt5.QtCore import QTimer, pyqtSlot from PyQt5.QtWidgets import QMessageBox -from component import Component from lib.db import Archive, Recipes, Users from lib.helpers import get_shift from lib.helpers.step import Step From 7f7fa062664260a37aeb2ec0d4f26c780c4feea9 Mon Sep 17 00:00:00 2001 From: gg Date: Fri, 17 Jan 2025 19:17:09 +0100 Subject: [PATCH 2/3] hikrobot smart camera almost getting data --- src/components/hikrobot_dll.py | 233 +++++++++++++++++++++++ src/components/hikrobot_sc.py | 76 +++++++- src/test/hikrobot_sc/test_hikrobot_sc.py | 74 +++---- 3 files changed, 338 insertions(+), 45 deletions(-) create mode 100644 src/components/hikrobot_dll.py diff --git a/src/components/hikrobot_dll.py b/src/components/hikrobot_dll.py new file mode 100644 index 0000000..c2ce528 --- /dev/null +++ b/src/components/hikrobot_dll.py @@ -0,0 +1,233 @@ +import ctypes +import struct +from ctypes import * +import sys + +MV_MAX_DEVICE_NUM=256 +MV_VS_OK=0x00000000 +CHUNK_MASK_IMAGE_PORT=60005536 +CHUNK_RESULT_PORT=60005537 + +mv_lib = ctypes.windll.LoadLibrary("src/test/hikrobot_sc/bin/MvVisionSensorControl.dll") + +# define structures +from ctypes import * + +class MvVSGvspPixelType(c_int): + MVVS_PixelType_Undefined = 0xFFFFFFFF + + MVVS_PixelType_Mono1p = (0x0037) + MVVS_PixelType_Mono2p = (0x0038) + MVVS_PixelType_Mono4p = (0x0039) + MVVS_PixelType_Mono8 = (0x0001) + MVVS_PixelType_Mono8_Signed = (0x0002) + MVVS_PixelType_Mono10 = (0x0003) + MVVS_PixelType_Mono10_Packed = (0x0004) + MVVS_PixelType_Mono12 = (0x0005) + MVVS_PixelType_Mono12_Packed = (0x0006) + MVVS_PixelType_Mono14 = (0x0025) + MVVS_PixelType_Mono16 = (0x0007) + + MVVS_PixelType_BayerGR8 = (0x0008) + MVVS_PixelType_BayerRG8 = (0x0009) + MVVS_PixelType_BayerGB8 = (0x000A) + MVVS_PixelType_BayerBG8 = (0x000B) + MVVS_PixelType_BayerGR10 = (0x000C) + MVVS_PixelType_BayerRG10 = (0x000D) + MVVS_PixelType_BayerGB10 = (0x000E) + MVVS_PixelType_BayerBG10 = (0x000F) + MVVS_PixelType_BayerGR12 = (0x0010) + MVVS_PixelType_BayerRG12 = (0x0011) + MVVS_PixelType_BayerGB12 = (0x0012) + MVVS_PixelType_BayerBG12 = (0x0013) + MVVS_PixelType_BayerGR10_Packed = (0x0026) + MVVS_PixelType_BayerRG10_Packed = (0x0027) + MVVS_PixelType_BayerGB10_Packed = (0x0028) + MVVS_PixelType_BayerBG10_Packed = (0x0029) + MVVS_PixelType_BayerGR12_Packed = (0x002A) + MVVS_PixelType_BayerRG12_Packed = (0x002B) + MVVS_PixelType_BayerGB12_Packed = (0x002C) + MVVS_PixelType_BayerBG12_Packed = (0x002D) + MVVS_PixelType_BayerGR16 = (0x002E) + MVVS_PixelType_BayerRG16 = (0x002F) + MVVS_PixelType_BayerGB16 = (0x0030) + MVVS_PixelType_BayerBG16 = (0x0031) + + MVVS_PixelType_RGB8_Packed = (0x0014) + MVVS_PixelType_BGR8_Packed = (0x0015) + MVVS_PixelType_RGBA8_Packed = (0x0016) + MVVS_PixelType_BGRA8_Packed = (0x0017) + MVVS_PixelType_RGB10_Packed = (0x0018) + MVVS_PixelType_BGR10_Packed = (0x0019) + MVVS_PixelType_RGB12_Packed = (0x001A) + MVVS_PixelType_BGR12_Packed = (0x001B) + MVVS_PixelType_RGB16_Packed = (0x0033) + MVVS_PixelType_BGR16_Packed = (0x004B) + MVVS_PixelType_RGBA16_Packed = (0x0064) + MVVS_PixelType_BGRA16_Packed = (0x0051) + MVVS_PixelType_RGB10V1_Packed = (0x001C) + MVVS_PixelType_RGB10V2_Packed = (0x001D) + MVVS_PixelType_RGB12V1_Packed = (0X0034) + MVVS_PixelType_RGB565_Packed = (0x0035) + MVVS_PixelType_BGR565_Packed = (0X0036) + + MVVS_PixelType_YUV411_Packed = (0x001E) + MVVS_PixelType_YUV422_Packed = (0x001F) + MVVS_PixelType_YUV422_YUYV_Packed = (0x0032) + MVVS_PixelType_YUV444_Packed = (0x0020) + MVVS_PixelType_YCBCR8_CBYCR = (0x003A) + MVVS_PixelType_YCBCR422_8 = (0x003B) + MVVS_PixelType_YCBCR422_8_CBYCRY = (0x0043) + MVVS_PixelType_YCBCR411_8_CBYYCRYY = (0x003C) + MVVS_PixelType_YCBCR601_8_CBYCR = (0x003D) + MVVS_PixelType_YCBCR601_422_8 = (0x003E) + MVVS_PixelType_YCBCR601_422_8_CBYCRY = (0x0044) + MVVS_PixelType_YCBCR601_411_8_CBYYCRYY = (0x003F) + MVVS_PixelType_YCBCR709_8_CBYCR = (0x0040) + MVVS_PixelType_YCBCR709_422_8 = (0x0041) + MVVS_PixelType_YCBCR709_422_8_CBYCRY = (0x0045) + MVVS_PixelType_YCBCR709_411_8_CBYYCRYY = (0x0042) + + MVVS_PixelType_RGB8_Planar = (0x0021) + MVVS_PixelType_RGB10_Planar = (0x0022) + MVVS_PixelType_RGB12_Planar = (0x0023) + MVVS_PixelType_RGB16_Planar = (0x0024) + + MVVS_PixelType_Jpeg = (0x0001) + +class MV_VS_DATA(Structure): + _fields_ = [ + ("pImage", POINTER(c_char)), # Pointer of Image + ("nImageLen", c_uint), # The Length of Image + ("nImageWidth", c_uint), # Image Width + ("nImageHeight", c_uint), # Image Height + ("nImageNum", c_uint64), # Image Number + ("enPixelType", c_int), # Pixel Type (assuming MvVSGvspPixelType is an enum) + + ("nDevTimeStampHigh", c_uint), # Timestamp high 32 bits + ("nDevTimeStampLow", c_uint), # Timestamp low 32 bits + ("nReserved0", c_uint), # Reserved, 8-byte aligned + ("nHostTimeStamp", c_int64), # Host-generated timestamp + + ("pChunkData", POINTER(c_char)), # Chunk data + ("nChunkDataLen", c_uint), # Chunk Length + + ("nReserved", c_uint * 64), # Reserved + ] + +class MV_VS_DEVICE_INFO(ctypes.Structure): + _fields_ = [ + ("nMajorVer", ctypes.c_ushort), # GigE protocol Major Version + ("nMinorVer", ctypes.c_ushort), # GigE protocol Minor Version + ("nMacAddrHigh", ctypes.c_uint), # High MAC Address + ("nMacAddrLow", ctypes.c_uint), # Low MAC Address + ("nIpCfgOption", ctypes.c_uint), # Supported IP Configuration Options + ("nIpCfgCurrent", ctypes.c_uint), # IP Configuration + ("nCurrentIp", ctypes.c_uint), # Current IP + ("nCurrentSubNetMask", ctypes.c_uint), # Current Subnet Mask + ("nDefultGateWay", ctypes.c_uint), # Current Gateway + ("chManufacturerName", ctypes.c_char * 32), # Manufacturer Name + ("chModelName", ctypes.c_char * 32), # Model Name + ("chDeviceVersion", ctypes.c_char * 32), # Device Version + ("chManufacturerSpecificInfo", ctypes.c_char * 48), # Manufacturer Specific Info + ("chSerialNumber", ctypes.c_char * 16), # Serial Number + ("chUserDefinedName", ctypes.c_char * 16), # User Defined Name + ("nNetExport", ctypes.c_uint), # IP address of connected network port + ("nReserved", ctypes.c_uint * 8), # Reserved + ] + + +class MV_VS_DEVICE_INFO_LIST(ctypes.Structure): + _fields_ = [ + ("nDeviceNum", ctypes.c_uint), # Online Device Number + ("pDeviceInfo", ctypes.POINTER(MV_VS_DEVICE_INFO) * MV_MAX_DEVICE_NUM), # Device info array + ] + + +# Define function signatures + +mv_lib.MV_VS_GetResultData.argtypes = [c_void_p, POINTER(MV_VS_DATA), c_int] +mv_lib.MV_VS_GetResultData.restype = c_int + +mv_lib.MV_VS_ReleaseResultData.argtypes = [ctypes.c_void_p, ctypes.POINTER(MV_VS_DATA)] +mv_lib.MV_VS_ReleaseResultData.restype = ctypes.c_int + +mv_lib.MV_VS_EnumDevices.argtypes = [POINTER(MV_VS_DEVICE_INFO_LIST)] +mv_lib.MV_VS_EnumDevices.restype = c_int + +mv_lib.MV_VS_CreateHandle.argtypes = [POINTER(c_void_p), c_void_p] # Assuming pHandle is a void* and pstDeviceInfo is a struct +mv_lib.MV_VS_CreateHandle.restype = c_int + +mv_lib.MV_VS_Login.argtypes = [c_void_p, c_char_p, c_char_p] +mv_lib.MV_VS_Login.restype = c_int + +mv_lib.MV_VS_SetBoolValue.argtypes = [c_void_p, c_char_p, c_bool] +mv_lib.MV_VS_SetBoolValue.restype = c_int + +mv_lib.MV_VS_SetEnumValue.argtypes = [c_void_p, c_char_p, c_uint] +mv_lib.MV_VS_SetEnumValue.restype = c_int + +mv_lib.MV_VS_StartRun.argtypes = [c_void_p] # handle +mv_lib.MV_VS_StartRun.restype = c_int + + +def MV_VS_GetFrame(handle): + nRet = MV_VS_OK + stFrameData = MV_VS_DATA() + + + nRet = mv_lib.MV_VS_GetResultData(handle, byref(stFrameData), 2000) + if nRet == MV_VS_OK: + # Print frame information + print( + f"Frame Width: [{stFrameData.nImageWidth}], Height: [{stFrameData.nImageHeight}], ImageLen: [{stFrameData.nImageLen}]") + + # Process chunk data + currentDataTag = 0 + while stFrameData.nChunkDataLen > currentDataTag: + chunkLength = \ + struct.unpack_from(" stFrameData.nChunkDataLen - 8 - currentDataTag: + # Handle exception + break + + if chunkID == CHUNK_RESULT_PORT: # Result data in JSON format + chResultInfo = ctypes.cast( + stFrameData.pChunkData + (stFrameData.nChunkDataLen - 8 - chunkLength - currentDataTag), + ctypes.POINTER(ctypes.c_char)) + print(f"chResultInfo [{chResultInfo.value.decode()}] end") + + elif chunkID == CHUNK_MASK_IMAGE_PORT: # Mask image data + maskModID = struct.unpack_from(" currentDataTag: + chunkLength = struct.unpack_from(" stFrameData.nChunkDataLen - 8 - currentDataTag: + # Handle exception + break + + if chunkID == CHUNK_RESULT_PORT: # Result data in JSON format + chResultInfo = ctypes.cast(stFrameData.pChunkData + (stFrameData.nChunkDataLen - 8 - chunkLength - currentDataTag), ctypes.POINTER(ctypes.c_char)) + print(f"chResultInfo [{chResultInfo.value.decode()}] end") + + elif chunkID == CHUNK_MASK_IMAGE_PORT: # Mask image data + maskModID = struct.unpack_from(" Date: Tue, 21 Jan 2025 10:52:13 +0100 Subject: [PATCH 3/3] dev --- src/components/pipe_cutter_component.py | 87 +++++++-------------- src/ui/test_pipe_cutter/test_pipe_cutter.py | 6 +- 2 files changed, 32 insertions(+), 61 deletions(-) diff --git a/src/components/pipe_cutter_component.py b/src/components/pipe_cutter_component.py index 2022552..dfc2791 100644 --- a/src/components/pipe_cutter_component.py +++ b/src/components/pipe_cutter_component.py @@ -1,11 +1,9 @@ -import logging -import time - from .modbus_component import ModbusComponent +import logging class PipeCutterComponent(ModbusComponent): - def __init__(self, config=None, name="pipe_cutter", period=1, lazy=True, paused=False, threaded=True): + def __init__(self, config=None, name=None, period=1, lazy=True, paused=False, threaded=True): """Initialize the Pipe Cutter Component.""" super().__init__(config=config, name=name, period=period, lazy=lazy, paused=paused, threaded=threaded) self.log = logging.getLogger(self.name) @@ -13,74 +11,49 @@ class PipeCutterComponent(ModbusComponent): self.current_od_of_pipe = None self.machine_status = None + def config_changed(self): + super().config_changed() + + def read_total_length(self): - """Read the total length (Register 4X30).""" + """Read the total length from Register 4X30.""" try: - self.current_total_length = self.read(register_address=30, data_type="16bit_uint") - self.log.info(f"Total length (Register 4X30): {self.current_total_length}") + self.current_total_length = self._read(register=30) + self.log.info(f"Total Length Read (Register 4X30): {self.current_total_length}") return self.current_total_length except Exception as e: - self.log.error(f"Failed to read total length (Register 4X30): {e}") + self.log.error(f"Error reading total length: {e}") raise def read_od_of_pipe(self): - """Read the OD of the pipe (Register 4X60).""" + """Read the OD of the pipe from Register 4X60.""" try: - self.current_od_of_pipe = self.read(register_address=60, data_type="16bit_uint") - self.log.info(f"OD of the pipe (Register 4X60): {self.current_od_of_pipe}") + self.current_od_of_pipe = self._read(register=60) + self.log.info(f"OD of Pipe Read (Register 4X60): {self.current_od_of_pipe}") return self.current_od_of_pipe except Exception as e: - self.log.error(f"Failed to read OD of the pipe (Register 4X60): {e}") + self.log.error(f"Error reading OD of pipe: {e}") raise def read_machine_status(self): + """Read the machine status from Register 4X766.""" try: - self.machine_status = self.read(register_address=1,register=766 ,data_type="16bit_uint") - self.log.info(f"Machine status (Register 4X766): {self.machine_status}") + if not hasattr(self, 'client') or self.client is None: + self.log.error( + "Attempting to read machine status but 'client' is not initialized.") + raise AttributeError( + "'PipeCutterComponent' object has no attribute 'client'.") + + self.machine_status = self._read(register=766) + self.log.info(f"Machine Status Read (Register 4X766): {self.machine_status}") return self.machine_status - except Exception as e: - self.log.error(f"Failed to read machine status (Register 4X766): {e}") + except AttributeError as ae: + # Log more detailed instance state for debugging + self.log.error( + f"AttributeError while reading machine status: {ae}. Component State: " + f"name={self.name}, config={self.config}, client={getattr(self, 'client', None)}" + ) raise - - def write_total_length(self, value): - try: - self.write(register_address=1,register=30, value=value, data_type="16bit_uint") - self.log.info(f"Wrote total length (Register 4X30): {value}") except Exception as e: - self.log.error(f"Failed to write total length (Register 4X30): {e}") + self.log.error(f"Error reading machine status: {e}") raise - - def write_od_of_pipe(self, value): - try: - self.write(register_address=1,register=60, value=value, data_type="16bit_uint") - self.log.info(f"Wrote OD of pipe (Register 4X60): {value}") - except Exception as e: - self.log.error(f"Failed to write OD of pipe (Register 4X60): {e}") - raise - - def write_bit_with_delay(self, register_address, bit_position, delay_ms): - """ - Set a specific bit in a Modbus register, wait for a specified time, and reset it. - - :param register_address: The register address to write to. - :param bit_position: The bit position to modify (0-15). - :param delay_ms: The delay in milliseconds before resetting the bit to 0 . - """ - try: - # Step 1: Set the bit to 1 - current_value = self.read(register_address, data_type="16bit_uint") - new_value = current_value | (1 << bit_position) # Set the bit - self.write(register_address, new_value, data_type="16bit_uint") - self.log.info(f"Set bit {bit_position} in register {register_address} to 1") - - # Step 2: Wait for the specified delay - time.sleep(delay_ms / 1000) # Convert milliseconds to seconds - - # Step 3: Reset the bit to 0 - current_value = self.read(register_address, data_type="16bit_uint") - new_value = current_value & ~(1 << bit_position) # Clear the bit - self.write(register_address, new_value, data_type="16bit_uint") - self.log.info(f"Reset bit {bit_position} in register {register_address} to 0") - except Exception as e: - self.log.error(f"Failed to set and reset bit {bit_position} in register {register_address}: {e}") - raise \ No newline at end of file diff --git a/src/ui/test_pipe_cutter/test_pipe_cutter.py b/src/ui/test_pipe_cutter/test_pipe_cutter.py index 5f62bb4..6d4b515 100644 --- a/src/ui/test_pipe_cutter/test_pipe_cutter.py +++ b/src/ui/test_pipe_cutter/test_pipe_cutter.py @@ -11,10 +11,8 @@ class Test_Pipe_Cutter(Test_Test): A class to manage and operate a pipe cutter machine in a test environment. """ - def __init__(self, config, components, recipe=None, run_once=False, - reset_on_start=False, enable_override=False, bench_name="generic", step=None,): - super().__init__(components=components, recipe=recipe, step=None, run_once=run_once, - reset_on_start=reset_on_start, enable_override=enable_override,) + def __init__(self, config, components, recipe=None, run_once=False,reset_on_start=False, enable_override=False, bench_name="generic", step=None,): + super().__init__(components=components, recipe=recipe, step=None, run_once=run_once,reset_on_start=reset_on_start, enable_override=enable_override,) self.bench_name = bench_name self.cutter = PipeCutterComponent() self.current_cut_length = 0.0