From b11a1a47163bef6adbe37f60fa0414e1646f4d28 Mon Sep 17 00:00:00 2001 From: Roy Gollub Date: Wed, 14 Aug 2024 16:22:33 +0200 Subject: [PATCH 01/15] # Release 6.0.0 ## New features - Supports FlowConfig feature to provide acquired images - Set external event to trigger camera (see 'setSWTriggerEvent') - Support for custom GigE Vision camera (see 'setCameraModel') - Provide version of module via 'OnNewStatusModuleVersion' - Function 'getParameters' to provide PersistentData parameters - New function 'setSelectedInstance' to replace 'setSelectedCam' - Check if features of module can be used on device and provide this via 'OnNewStatusModuleIsActive' event / 'getStatusModuleActive' function - Function to 'resetModule' to default setup ## Improvements - New UI design available (e.g. selectable via CSK_Module_PersistentData v4.1.0 or higher), see 'OnNewStatusCSKStyle' - check if instance exists if selected - 'loadParameters' returns its success - 'sendParameters' can control if sent data should be saved directly by CSK_Module_PersistentData - Changed log level of some messages from 'info' to 'fine' - Added UI icon and browser tab information --- CHANGELOG.md | 20 + .../UI_sample.png | Bin 0 -> 35885 bytes .../CSK_Module_MultiRemoteCamera.css | 105 +- .../CSK_Module_MultiRemoteCamera.html | 2630 +++++++++++------ ...dule_MultiRemoteCamera_CameraOverview.html | 97 +- ...ultiRemoteCamera_GigEVisionParameters.html | 298 +- .../pages/src/converter.ts | 61 + .../pages/src/index.ts | 17 + CSK_Module_MultiRemoteCamera/project.mf.xml | 175 +- .../scripts/CSK_Module_MultiRemoteCamera.lua | 8 +- .../CSK_MultiRemoteCamera_ImageProcessing.lua | 20 +- .../MultiRemoteCamera_FlowConfig.lua | 30 + .../MultiRemoteCamera_OnNewImage.lua | 67 + .../MultiRemoteCamera_Controller.lua | 426 ++- .../MultiRemoteCamera_Model.lua | 182 +- .../MultiRemoteCamera/helper/checkAPIs.lua | 22 +- README.md | 16 +- docu/CSK_Module_MultiRemoteCamera.html | 1820 +++++++++--- docu/media/UI_Screenshot_GigEVision.png | Bin 57888 -> 90511 bytes docu/media/UI_Screenshot_Main.png | Bin 87958 -> 71875 bytes docu/media/src/UI_sample.pptx | Bin 0 -> 90563 bytes 21 files changed, 4125 insertions(+), 1869 deletions(-) create mode 100644 CSK_Module_MultiRemoteCamera/pages/assets/CSK_Module_MultiRemoteCamera/UI_sample.png create mode 100644 CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/FlowConfig/MultiRemoteCamera_FlowConfig.lua create mode 100644 CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/FlowConfig/MultiRemoteCamera_OnNewImage.lua create mode 100644 docu/media/src/UI_sample.pptx diff --git a/CHANGELOG.md b/CHANGELOG.md index 527dde0..92f7713 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,26 @@ # Changelog All notable changes to this project will be documented in this file. +## Release 6.0.0 + +### New features +- Supports FlowConfig feature to provide acquired images +- Set external event to trigger camera (see 'setSWTriggerEvent') +- Support for custom GigE Vision camera (see 'setCameraModel') +- Provide version of module via 'OnNewStatusModuleVersion' +- Function 'getParameters' to provide PersistentData parameters +- New function 'setSelectedInstance' to replace 'setSelectedCam' +- Check if features of module can be used on device and provide this via 'OnNewStatusModuleIsActive' event / 'getStatusModuleActive' function +- Function to 'resetModule' to default setup + +### Improvements +- New UI design available (e.g. selectable via CSK_Module_PersistentData v4.1.0 or higher), see 'OnNewStatusCSKStyle' +- check if instance exists if selected +- 'loadParameters' returns its success +- 'sendParameters' can control if sent data should be saved directly by CSK_Module_PersistentData +- Changed log level of some messages from 'info' to 'fine' +- Added UI icon and browser tab information + ## Release 5.0.0 ### Improvements diff --git a/CSK_Module_MultiRemoteCamera/pages/assets/CSK_Module_MultiRemoteCamera/UI_sample.png b/CSK_Module_MultiRemoteCamera/pages/assets/CSK_Module_MultiRemoteCamera/UI_sample.png new file mode 100644 index 0000000000000000000000000000000000000000..24f9565ac38460d01b697477a8d2686cae378040 GIT binary patch literal 35885 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 div > div { - max-height: 800px; - min-height: 800px; + max-height: 600px; + min-height: 600px; } .myCustomSlider_CSK_Module_MultiRemoteCamera { @@ -39,3 +66,61 @@ .myCustomMaxWidth1600px_CSK_Module_MultiRemoteCamera { max-width: 1600px; } + +.myCustomFrameLabel_CSK_Module_MultiRemoteCamera { + background: white; + position:relative; + top: calc(-1.2rem); + left: calc(1rem); + font-size: medium; +} + +.myCustomPersistentDataMargin_CSK_Module_MultiRemoteCamera { + margin-top: -53px; + margin-left: 130px; +} + +.myCustomPersistentDataMarginBack_CSK_Module_MultiRemoteCamera { + margin-left: -127px; +} + +.myCustomTabFrame_CSK_Module_MultiRemoteCamera { + width: 98%; + align-self: center; +} + +.myCustomLabel_CSK_Module_MultiRemoteCamera { + font-size:30px; + color: grey; + margin-top: 10px; +} + +.myCustomFrameNoColor_CSK_Module_MultiRemoteCamera { + margin: 6px; + border-radius: 10px; + border-style: solid; + border-width: 0px; + border-color: 007CC1; + background-color: #FFFFFF; +} + +.myCustomMarginTop7PX_CSK_Module_MultiRemoteCamera { + margin-top: 7px; +} + +.myCustomFrame_CSK_Module_MultiRemoteCamera { + margin: 6px; + border-radius: 10px; + border-style: solid; + border-width: 1px; + border-color: #007CC1; + background-color: white; +} + +.myCustomBackground_CSK_Module_MultiRemoteCamera { +} + +.myCustomButton_CSK_Module_MultiRemoteCamera { + border-radius: 30px; + padding-right: 0px; +} \ No newline at end of file diff --git a/CSK_Module_MultiRemoteCamera/pages/pages/CSK_Module_MultiRemoteCamera/CSK_Module_MultiRemoteCamera.html b/CSK_Module_MultiRemoteCamera/pages/pages/CSK_Module_MultiRemoteCamera/CSK_Module_MultiRemoteCamera.html index 165b5e9..8b1f361 100644 --- a/CSK_Module_MultiRemoteCamera/pages/pages/CSK_Module_MultiRemoteCamera/CSK_Module_MultiRemoteCamera.html +++ b/CSK_Module_MultiRemoteCamera/pages/pages/CSK_Module_MultiRemoteCamera/CSK_Module_MultiRemoteCamera.html @@ -1,965 +1,1665 @@ - - - - - - - Some features are only usable / visible when logged in via UserManagement - - - - - - - - - - - Currently waiting for camera boot up... - - - - - - - - - - - - - - - - - - - - - - - - - - This viewer will only work with ImageProcessingMode BOTH or SCRIPT - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SICK Pico/MidiCam2 - - - Basler a2A1920-51gc - - - - - - - - - - GigE Vision parameters - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Disconnect Camera - - - - - - - - - - - - - - Connect camera - - - - - - - - - - - - - - - - - - - - - Currently searching for connected camera... - - - - - - - - - - - - - - - - - MONO8 - - - COLOR8 - - - RAW8 - - - - - - - - - - - - - BOTH (SCRIPT + APP) - - - SCRIPT (process only in module) - - - APP (only forward to other modules) - - - - - - - - - - - SW Trigger / Ethernet - - - Continuous Mode - - - Digital Input - - - - - - - - - - - SW Image Trigger - - - - - - - - - - - - - - - Trigger Pause - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Set FOV - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Save Last Image - - - - - - - - - - - - PublicData - - - SD-Card - - - - - - - - - - - - - - - - - - - - - bmp - - - jpg - - - png - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Load on reboot - - - - - - - - - - - Load Config - - - - - - - - - Save Config - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Add camera instance - - - - - - - Restart all cameras - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Currently waiting for camera boot up... + + + + + + + + + + + + + + + This viewer will only work with ImageProcessingMode BOTH or SCRIPT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Disconnect + + + + + + + + + + + + + + + + Connect + + + + + + + + + + + + + + + + + + + + + + Currently searching for connected camera... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SICK Pico/MidiCam2 + + + Basler a2A1920-51gc + + + Custom + + + + + + + + + + GigE Vision parameters + + + + + + + + + + + + + MONO8 + + + COLOR8 + + + RAW8 + + + + + + + + + + + + + + + + + + + + + + + BOTH (SCRIPT + APP) + + + SCRIPT (process only in module) + + + APP (only forward to other modules) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW Trigger / Ethernet + + + Continuous Mode + + + Digital Input + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW Image Trigger + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PublicData + + + SD-Card + + + + + + + + + + + + + + + + + + + + + bmp + + + jpg + + + png + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Some features are only usable / visible when logged in via UserManagement + + + + + + + + + + + + Module is not supported on this device... + + UI sample + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CSK_Module_MultiRemoteCamera/pages/pages/CSK_Module_MultiRemoteCamera/CSK_Module_MultiRemoteCamera_CameraOverview.html b/CSK_Module_MultiRemoteCamera/pages/pages/CSK_Module_MultiRemoteCamera/CSK_Module_MultiRemoteCamera_CameraOverview.html index 15c6cfb..4bb43e5 100644 --- a/CSK_Module_MultiRemoteCamera/pages/pages/CSK_Module_MultiRemoteCamera/CSK_Module_MultiRemoteCamera_CameraOverview.html +++ b/CSK_Module_MultiRemoteCamera/pages/pages/CSK_Module_MultiRemoteCamera/CSK_Module_MultiRemoteCamera_CameraOverview.html @@ -1,38 +1,59 @@ - - -

Connected cameras:

- - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
+ + +

Connected Cameras

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Module is not supported on this device... + + + + + + + + + + + + + +
+
\ No newline at end of file diff --git a/CSK_Module_MultiRemoteCamera/pages/pages/CSK_Module_MultiRemoteCamera/CSK_Module_MultiRemoteCamera_GigEVisionParameters.html b/CSK_Module_MultiRemoteCamera/pages/pages/CSK_Module_MultiRemoteCamera/CSK_Module_MultiRemoteCamera_GigEVisionParameters.html index e0f2ee5..85fa583 100644 --- a/CSK_Module_MultiRemoteCamera/pages/pages/CSK_Module_MultiRemoteCamera/CSK_Module_MultiRemoteCamera_GigEVisionParameters.html +++ b/CSK_Module_MultiRemoteCamera/pages/pages/CSK_Module_MultiRemoteCamera/CSK_Module_MultiRemoteCamera_GigEVisionParameters.html @@ -1,126 +1,172 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Add config - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Remove - - - - - Update config - - - - - - - - - - - - - - - Please login with user level Service to see this page. - - - - - - - - - + + +

GigE Vision Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Please login with user level Service to see this page. + + + + + + + + + + + + + + + Module is not supported on this device... + + + + + + + +
+
\ No newline at end of file diff --git a/CSK_Module_MultiRemoteCamera/pages/src/converter.ts b/CSK_Module_MultiRemoteCamera/pages/src/converter.ts index 952a00f..1af1a7b 100644 --- a/CSK_Module_MultiRemoteCamera/pages/src/converter.ts +++ b/CSK_Module_MultiRemoteCamera/pages/src/converter.ts @@ -11,4 +11,65 @@ export function changeID(id) { viewerElement.setAttribute('viewer-id', id); viewerElement.triggerResume(); return id; +} + +export function changeStyle(theme) { + const style: HTMLStyleElement = document.createElement('style'); + style.id ='blub' + if (theme == 'CSK_Style'){ + var headerToolbar = `.sopasjs-ui-header-toolbar-wrapper { background-color: #FFFFFF; }` + var uiHeader = `.sopasjs-ui-header>.app-logo { margin-right:0px; }` + var appLogo = `.app-logo { background-color:#FFFFFF; background-image: url(data:image/png;base64,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) }` + var uiNavbar =`.sopasjs-ui-navbar-wrapper { background-color: #737F85; }` + var navbarMenuLiActive = `.sopasjs-navbar-menu>li.active { background-color: #283c45; }` + var navbarMenuLiActiveA = `.sopasjs-navbar-menu>li.active>a { background-color: #283c45; }` + var navbarMeluLi = `.sopasjs-navbar-menu>li { color: #FFFFFF; }` + var navbarMeluLiA = `.sopasjs-navbar-menu>li>a { color: #FFFFFF; }` + var headerToolbarButtonHighlight = `.sopasjs-ui-header-toolbar-button.sopasjs-ui-navigation-navbutton>a.highlight { background-color: #737F85; }` + var toolbarButton = `.sopasjs-ui-header-toolbar-button>a { color: #283c45; }` + + var customBackground = `.CSK_Module_MultiRemoteCamera .myCustomBackground_CSK_Module_MultiRemoteCamera { background-color: #737F8522; }` // font-family: "Open Sans"; }` + + style.innerHTML = headerToolbar; + style.innerHTML += uiHeader; + style.innerHTML += appLogo; + style.innerHTML += uiNavbar; + style.innerHTML += navbarMenuLiActive; + style.innerHTML += navbarMenuLiActiveA; + style.innerHTML += navbarMeluLi; + style.innerHTML += navbarMeluLiA; + style.innerHTML += headerToolbarButtonHighlight; + style.innerHTML += toolbarButton; + + style.innerHTML += customBackground; + } + else if (theme == 'None'){ + var headerToolbar = `.sopasjs-ui-header-toolbar-wrapper { background-color: #007fc3; }` + var uiHeader = `.sopasjs-ui-header>.app-logo { margin-right:10px; }` + var appLogo = `.app-logo { background-color:#007fc3; background-image: url('data:image/png;base64,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') }` + var uiNavbar =`.sopasjs-ui-navbar-wrapper { background-color: #f6f8f9; }` + var navbarMenuLiActive = `.sopasjs-navbar-menu>li.active { background-color: #007fc3; }` + var navbarMenuLiActiveA = `.sopasjs-navbar-menu>li.active>a { background-color: #007fc3; }` + var navbarMeluLi = `.sopasjs-navbar-menu>li { color: #697987; }` + var navbarMeluLiA = `.sopasjs-navbar-menu>li>a { color: #505f6b; }` + var headerToolbarButtonHighlight = `.sopasjs-ui-header-toolbar-button.sopasjs-ui-navigation-navbutton>a.highlight { background-color: #006093; }` + var toolbarButton = `.sopasjs-ui-header-toolbar-button>a { color: #cce5f3; }` + + var customBackground = `.CSK_Module_MultiRemoteCamera .myCustomBackground_CSK_Module_MultiRemoteCamera { background-color: #fff; }` // font-family: "sans-serif"; }` + + style.innerHTML = headerToolbar; + style.innerHTML += uiHeader; + style.innerHTML += appLogo; + style.innerHTML += uiNavbar; + style.innerHTML += navbarMenuLiActive; + style.innerHTML += navbarMenuLiActiveA; + style.innerHTML += navbarMeluLi; + style.innerHTML += navbarMeluLiA; + style.innerHTML += headerToolbarButtonHighlight; + style.innerHTML += toolbarButton; + + style.innerHTML += customBackground; + } + document.head.append(style); + return theme } \ No newline at end of file diff --git a/CSK_Module_MultiRemoteCamera/pages/src/index.ts b/CSK_Module_MultiRemoteCamera/pages/src/index.ts index e69de29..0965da1 100644 --- a/CSK_Module_MultiRemoteCamera/pages/src/index.ts +++ b/CSK_Module_MultiRemoteCamera/pages/src/index.ts @@ -0,0 +1,17 @@ +document.addEventListener('sopasjs-ready', () => { + const page_1 = document.querySelector('div.sopasjs-ui-navbar-wrapper > div > ul > li:nth-child(3) > a > i'); + page_1.classList.remove('fa-file'); + page_1.classList.add('fa-video-camera'); + + const page_2 = document.querySelector('div.sopasjs-ui-navbar-wrapper > div > ul > li:nth-child(4) > a > i'); + page_2.classList.remove('fa-file'); + page_2.classList.add('fa-eye'); + + const page_3 = document.querySelector('div.sopasjs-ui-navbar-wrapper > div > ul > li:nth-child(5) > a > i'); + page_3.classList.remove('fa-file'); + page_3.classList.add('fa-list-ul'); + + setTimeout(() => { + document.title = 'CSK_Module_MultiRemoteCamera' + }, 500); +}) \ No newline at end of file diff --git a/CSK_Module_MultiRemoteCamera/project.mf.xml b/CSK_Module_MultiRemoteCamera/project.mf.xml index 7a63721..3b93c9a 100644 --- a/CSK_Module_MultiRemoteCamera/project.mf.xml +++ b/CSK_Module_MultiRemoteCamera/project.mf.xml @@ -12,18 +12,20 @@ Incoming images can be forwarded to other apps / modules (see "setProcessingMode {empty} + **Typical features to use: ** + {empty} + -1) If multiple camera instances are available, selecte a specific camera via "setSelectedCam" + +1) If multiple camera instances are available, selecte a specific camera via "setSelectedInstance" + 2) Set camera IP via "setCameraIP" + 3) Select if GigE Vision camera or not via "setGigEVision" + -3) Opt. use set-Function like setResizeFactor, setShutterTime, ... + -3) Set processing mode via "setProcessingMode" + -4) Start camera via "connectCamera" + +4) If it is a GigE Vision camera, select camera model via 'setCameraModel'. + +5) Opt. use set-Function like setResizeFactor, setShutterTime, ... + +6) Set processing mode via "setProcessingMode" + +7) Start camera via "connectCamera" + {empty} + There is also the possibility to edit GigE Vision camera parameters (check also available UI). + - Camera type. - SICK Pico/MidiCam2 - Basler a2A1920-51gc + Camera type. For some camera models it will internally use some predefined GigE Vision parameters. Otherwise use 'Custom'. + SICK Pico/MidiCam2 + Basler a2A1920-51gc + CustomConfig Camera color type. @@ -300,120 +302,145 @@ INFO: Other modules can check via "Script.isServedAsEvent" if event of sepecific Notify if module is curently waiting for camera boot up. + + Notify if camera model 'Custom' is selected. + + + + Notify event to trigger camera if in SW mode. + + + + Notify if FlowConfig should have priority for FlowConfig relevant configurations. + + + + Notify UI style to use for CSK modules. + + + + Notify version of module. + + + + Notify if module can be used on device. + + Function to register "OnResume" of the module UI (only as helper function). - Set shutter time of currently selected camera instance (see "setSelectedCam"). + Set shutter time of currently selected camera instance (see "setSelectedInstance"). - Set gain of currently selected camera instance (see "setSelectedCam"). + Set gain of currently selected camera instance (see "setSelectedInstance"). - Set framerate (in FIXED_FREQUENCY mode) of currently selected camera instance (see "setSelectedCam"). + Set framerate (in FIXED_FREQUENCY mode) of currently selected camera instance (see "setSelectedInstance"). - Set resize factor used in module internal image processing of currently selected camera instance (see "setSelectedCam"). + Set resize factor used in module internal image processing of currently selected camera instance (see "setSelectedInstance"). - Set acquisition mode of currently selected camera instance (see "setSelectedCam"). + Set acquisition mode of currently selected camera instance (see "setSelectedInstance"). - Set Field of view in x-direction in [pixel] of currently selected camera instance (see "setSelectedCam"). + + Set Field of view in x-direction in [pixel] of currently selected camera instance (see "setSelectedInstance"). + Needs to be activated via "setFOV" after this. - Set Field of view in y-direction in [pixel] of currently selected camera instance (see "setSelectedCam"). + + Set Field of view in y-direction in [pixel] of currently selected camera instance (see "setSelectedInstance"). + Needs to be activated via "setFOV" after this. - Activate preconfigured field of view of currently selected camera instance (see "setSelectedCam"). + Activate preconfigured field of view of currently selected camera instance (see "setSelectedInstance"). - Trigger SW trigger on currently selected camera instance (see "setSelectedCam"). + Trigger SW trigger on currently selected camera instance (see "setSelectedInstance"). - Set trigger delay (in HARDWARE_TRIGGER mode) used in cFlow of currently selected camera instance (see "setSelectedCam"). + Set trigger delay (in HARDWARE_TRIGGER mode) used in cFlow of currently selected camera instance (see "setSelectedInstance"). - Connect to currently selected camera instance (see "setSelectedCam"). + Connect to currently selected camera instance (see "setSelectedInstance"). - Set IP of currently selected camera instance (see "setSelectedCam"). + Set IP of currently selected camera instance (see "setSelectedInstance"). - Get IP of currently selected camera instance (see "setSelectedCam"). + Get IP of currently selected camera instance (see "setSelectedInstance"). - Get acquisition mode of currently selected camera instance (see "setSelectedCam"). + Get acquisition mode of currently selected camera instance (see "setSelectedInstance"). - Get framerate (in FIXED_FREQUENCY mode) of currently selected camera instance (see "setSelectedCam"). + Get framerate (in FIXED_FREQUENCY mode) of currently selected camera instance (see "setSelectedInstance"). - Get resize factor used in module internal image processing of currently selected camera instance (see "setSelectedCam"). + Get resize factor used in module internal image processing of currently selected camera instance (see "setSelectedInstance"). - Get gain of currently selected camera instance (see "setSelectedCam"). + Get gain of currently selected camera instance (see "setSelectedInstance"). - Get shutter time of currently selected camera instance (see "setSelectedCam"). + Get shutter time of currently selected camera instance (see "setSelectedInstance"). - Get trigger delay (in HARDWARE_TRIGGER mode) used in cFlow of currently selected camera instance (see "setSelectedCam"). + Get trigger delay (in HARDWARE_TRIGGER mode) used in cFlow of currently selected camera instance (see "setSelectedInstance"). - Get Field of view in x-direction in [pixel] of currently selected camera instance (see "setSelectedCam"). + Get Field of view in x-direction in [pixel] of currently selected camera instance (see "setSelectedInstance"). - Get Field of view in y-direction in [pixel] of currently selected camera instance (see "setSelectedCam"). + Get Field of view in y-direction in [pixel] of currently selected camera instance (see "setSelectedInstance"). - Start currently selected camera (see 'setSelectedCam'). + Start currently selected camera (see "setSelectedInstance"). - Stop currently selected camera (see 'setSelectedCam'). + Stop currently selected camera (see "setSelectedInstance"). - Set color mode of currently selected camera instance (see "setSelectedCam"). + Set color mode of currently selected camera instance (see "setSelectedInstance"). - Get color mode of currently selected camera instance (see "setSelectedCam"). + Get color mode of currently selected camera instance (see "setSelectedInstance"). - Select single camera instance (first select a instance, after that other functions like "set"-function will use this camera instance). + [DEPRECATED] See 'setSelectedInstance'. + +Select single camera instance (first select a instance, after that other functions like "set"-function will use this camera instance). - Get currently selected camera instance (see "setSelectedCam"). + Get currently selected camera instance (see "setSelectedInstance"). - Use preset trigger delay (in HARDWARE_TRIGGER mode) used in cFlow of currently selected camera instance (see "setSelectedCam"). + Use preset trigger delay (in HARDWARE_TRIGGER mode) used in cFlow of currently selected camera instance (see "setSelectedInstance"). - Get info if currently selected camera instance is a GigEVision camera (see "setSelectedCam"). + Get info if currently selected camera instance is a GigEVision camera (see "setSelectedInstance"). @@ -426,9 +453,7 @@ Needs to be activated via "setFOV" after this. Send parameters to CSK_PersistentData module if possible to save them. - - - Load parameters for this module from the CSK_PersistentData module if possible and use them. + Set GigEVision ParameterName to add for custom GigE Vision setting (see "addGigEVisionConfig"). @@ -495,7 +520,7 @@ INFO: Please make sure to restart the cameras (e.g. via "restartAllCameras()" ) - Function to disconnect currently selected camera instance (see "setSelectedCam"). + Function to disconnect currently selected camera instance (see 'setSelectedInstance'). Select GigE Vision Parameter to edit in UI. @@ -533,13 +558,77 @@ IMPORTANT: As instances start their own threads, the module needs to be restarte Function to restart all camera instances. - Connected camera-model like Midicam2 or Basler-Camera. - + Connected camera-model like Midicam2, Basler-Camera or CustomConfig. + +According to the selected model it will use some predefined GigE Vision parameters. Otherwise select ' CustomConfig'. + + + + Select single camera instance (first select a instance, after that other functions like "set"-function will use this camera instance). + + + + Function to set event to trigger new image in SW mode. + + + + Function to configure if FlowConfig should have priority for FlowConfig relevant configuration. + + + + Function to get status if module is active. + + + + Function to clear FlowConfig relevant configurations. + + + Load parameters for this module from the CSK_PersistentData module if possible and use them. + + + + released + Function to get all parameters of the client in JSON format. + + + + + Function to reset main configuration of module. + + released + Crown to provide CSK_FlowConfig relevant features. + + + released + Provide image acquired by camera. + + + data-flow + Provide image acquired by camera. + + + + + released + Internally used CSK_FlowConfig create function. + + + + + released + Internally used CSK_FlowConfig register function. + + + + + + + + SICK AG - 5.0.0 + 6.0.0 low false false diff --git a/CSK_Module_MultiRemoteCamera/scripts/CSK_Module_MultiRemoteCamera.lua b/CSK_Module_MultiRemoteCamera/scripts/CSK_Module_MultiRemoteCamera.lua index 729e8ab..b200c8e 100644 --- a/CSK_Module_MultiRemoteCamera/scripts/CSK_Module_MultiRemoteCamera.lua +++ b/CSK_Module_MultiRemoteCamera/scripts/CSK_Module_MultiRemoteCamera.lua @@ -25,10 +25,10 @@ --************************************************************************** --**********************Start Global Scope ********************************* --************************************************************************** ------------------------------------------------------------ -- If app property "LuaLoadAllEngineAPI" is FALSE, use this to load and check for required APIs -- This can improve performance of garbage collection _G.availableAPIs = require('Sensors/MultiRemoteCamera/helper/checkAPIs') -- can be used to adjust function scope of the module related on available APIs of the device + ----------------------------------------------------------- -- Logger _G.logger = Log.SharedLogger.create('ModuleLogger') @@ -66,12 +66,14 @@ local multiRemoteCameras_Instances = {} -- Handle all instances local multiRemoteCameraController = require('Sensors/MultiRemoteCamera/MultiRemoteCamera_Controller') -- Check if specific APIs are available on device -if availableAPIs.imageProvider then +if _G.availableAPIs.default and availableAPIs.imageProvider then _G.logger:info("I2D Support = " .. tostring(_G.availableAPIs.I2D) .. ", GigEVision support = " .. tostring(_G.availableAPIs.GigEVision)) + local setInstanceHandle = require('Sensors/MultiRemoteCamera/FlowConfig/MultiRemoteCamera_FlowConfig') table.insert(multiRemoteCameras_Instances, multiRemoteCamera_Model.create(1)) -- create(cameraNo:int) multiRemoteCameraController.setMultiRemoteCamera_Instances_Handle(multiRemoteCameras_Instances) -- share handle of instances + setInstanceHandle(multiRemoteCameras_Instances) else - _G.logger:warning("CSK_MultiRemoteCamera : Features of this module are not supported on this device. Missing APIs.") + _G.logger:warning("CSK_MultiRemoteCamera : Relevant CROWN(s) not available on device. Module is not supported...") end --************************************************************************** diff --git a/CSK_Module_MultiRemoteCamera/scripts/CSK_MultiRemoteCamera_ImageProcessing.lua b/CSK_Module_MultiRemoteCamera/scripts/CSK_MultiRemoteCamera_ImageProcessing.lua index ea189a8..efda404 100644 --- a/CSK_Module_MultiRemoteCamera/scripts/CSK_MultiRemoteCamera_ImageProcessing.lua +++ b/CSK_Module_MultiRemoteCamera/scripts/CSK_MultiRemoteCamera_ImageProcessing.lua @@ -61,14 +61,14 @@ local function saveImage(img) File.mkdir('/public/images/camera' .. cameraNumberString) end local list = File.list("/public/images/camera" .. cameraNumberString) - _G.logger:info(nameOfModule .. ': Try to save new image in public folder from camera No.' .. cameraNumberString) + _G.logger:fine(nameOfModule .. ': Try to save new image in public folder from camera No.' .. cameraNumberString) local suc if list == nil then suc = Image.save(img, "public/images/camera" .. cameraNumberString .. "/" .. imageProcessingParams.imageFilePrefix .. "1." .. imageProcessingParams.imageSaveFormat, compression) else suc = Image.save(img, "public/images/camera" .. cameraNumberString .. "/" .. imageProcessingParams.imageFilePrefix .. tostring(#list+1) .. "." .. imageProcessingParams.imageSaveFormat, compression) end - _G.logger:info(nameOfModule .. ': Succes of saving new image in public folder:' .. tostring(suc)) + _G.logger:fine(nameOfModule .. ': Succes of saving new image in public folder:' .. tostring(suc)) else _G.logger:info(nameOfModule .. ": Disk nearly full! Will save no image from camera No." .. cameraNumberString) end @@ -81,14 +81,14 @@ local function saveImage(img) local freeSpace = File.getDiskFree("/sdcard/0/") if freeSpace >10000000 then local list = File.list("/sdcard/0/images/camera" .. cameraNumberString) - _G.logger:info(nameOfModule .. ': Try to save new image on SD card from camera No.' .. cameraNumberString) + _G.logger:fine(nameOfModule .. ': Try to save new image on SD card from camera No.' .. cameraNumberString) local suc if list == nil then suc = Image.save(img, "/sdcard/0/images/camera" .. cameraNumberString .. "/" .. imageProcessingParams.imageFilePrefix .. "1." .. imageProcessingParams.imageSaveFormat, compression) else suc = Image.save(img, "/sdcard/0/images/camera" .. cameraNumberString .. "/" .. imageProcessingParams.imageFilePrefix .. tostring(#list+1) .. "." .. imageProcessingParams.imageSaveFormat, compression) end - _G.logger:info(nameOfModule .. ': Succes of saving new image on SD card:' .. tostring(suc)) + _G.logger:fine(nameOfModule .. ': Succes of saving new image on SD card:' .. tostring(suc)) else _G.logger:info(nameOfModule .. ": Disk nearly full! Will save no image from camera No." .. cameraNumberString) end @@ -106,7 +106,7 @@ end ---@param sensorData SensorData Sensor data local function handleOnNewImageProcessing(image, sensorData) local tic = DateTime.getTimestamp() - --_G.logger:info(nameOfModule .. ": New Image cam" .. cameraNumberString) --> For debugging + --_G.logger:fine(nameOfModule .. ": New Image cam" .. cameraNumberString) --> For debugging -- Release temp Image if lastImage ~= nil then @@ -122,7 +122,7 @@ local function handleOnNewImageProcessing(image, sensorData) local resImage = image if imageQueueSize >= imageProcessingParams.maxImageQueueSize then - _G.logger:info(nameOfModule .. ": Warning! ImageQueue of camera " .. cameraNumberString .. "is >= " .. tostring(imageProcessingParams.maxImageQueueSize) .. "! Stop processing images! Data loss possible...") + _G.logger:warning(nameOfModule .. ": Warning! ImageQueue of camera " .. cameraNumberString .. "is >= " .. tostring(imageProcessingParams.maxImageQueueSize) .. "! Stop processing images! Data loss possible...") else if imageProcessingParams.saveAllImages then @@ -149,7 +149,7 @@ local function handleOnNewImageProcessing(image, sensorData) if imageProcessingParams.mode == 'APP' or imageProcessingParams.mode == 'BOTH' then -- OPTION B --> Forward image to other modules - _G.logger:info(nameOfModule .. ": Sending image = " .. cameraNumberString) --> For debugging + _G.logger:fine(nameOfModule .. ": Sending image = " .. cameraNumberString) --> For debugging --print("Time till sending image =" .. tostring(DateTime.getTimestamp()-tic)) -- For debugging only Script.notifyEvent('MultiRemoteCamera_OnNewImageCamera' .. cameraNumberString, resImage, tic) end @@ -173,7 +173,7 @@ end --- Function to register on "OnNewImage"-event of image provider ---@param camera handle Image Provider local function registerCamera(camera) - _G.logger:info(nameOfModule .. ": Register camera " .. cameraNumberString) + _G.logger:fine(nameOfModule .. ": Register camera " .. cameraNumberString) Image.Provider.RemoteCamera.register(camera, "OnNewImage", handleOnNewImageProcessing) imageQueue:setFunction(handleOnNewImageProcessing) Script.releaseObject(camera) @@ -183,7 +183,7 @@ Script.register("CSK_MultiRemoteCamera.OnRegisterCamera" .. cameraNumberString, --- Function to deregister on "OnNewImage"-event of image provider ---@param camera handle Image Provider local function deregisterCamera(camera) - _G.logger:info(nameOfModule .. ": DeRegister camera " .. cameraNumberString) + _G.logger:fine(nameOfModule .. ": DeRegister camera " .. cameraNumberString) Image.Provider.RemoteCamera.deregister(camera, "OnNewImage", handleOnNewImageProcessing) imageQueue:clear() Script.releaseObject(camera) @@ -206,7 +206,7 @@ local function handleOnNewImageProcessingParameter(cameraNo, parameter, value) saveImage(lastImage) else if not parameter == 'activeInUI' then - _G.logger:info(nameOfModule .. ": Update parameter '" .. parameter .. "' of cameraNo." .. tostring(cameraNo) .. " to value = " .. tostring(value)) + _G.logger:fine(nameOfModule .. ": Update parameter '" .. parameter .. "' of cameraNo." .. tostring(cameraNo) .. " to value = " .. tostring(value)) end imageProcessingParams[parameter] = value end diff --git a/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/FlowConfig/MultiRemoteCamera_FlowConfig.lua b/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/FlowConfig/MultiRemoteCamera_FlowConfig.lua new file mode 100644 index 0000000..ffda0cd --- /dev/null +++ b/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/FlowConfig/MultiRemoteCamera_FlowConfig.lua @@ -0,0 +1,30 @@ +--***************************************************************** +-- Here you will find all the required content to provide specific +-- features of this module via the 'CSK FlowConfig'. +--***************************************************************** + +require('Sensors.MultiRemoteCamera.FlowConfig.MultiRemoteCamera_OnNewImage') + +-- Reference to the multiRemoteCamera_Instances handle +local multiRemoteCamera_Instances + +--- Function to react if FlowConfig was updated +local function handleOnClearOldFlow() + if _G.availableAPIs.default and _G.availableAPIs.imageProvider then + for i = 1, #multiRemoteCamera_Instances do + if multiRemoteCamera_Instances[i].parameters.flowConfigPriority then + CSK_MultiRemoteCamera.clearFlowConfigRelevantConfiguration() + break + end + end + end +end +Script.register('CSK_FlowConfig.OnClearOldFlow', handleOnClearOldFlow) + +--- Function to get access to the multiRemoteCamera_Instances +---@param handle handle Handle of multiRemoteCamera_Instances object +local function setMultiRemoteCamera_Instances_Handle(handle) + multiRemoteCamera_Instances = handle +end + +return setMultiRemoteCamera_Instances_Handle \ No newline at end of file diff --git a/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/FlowConfig/MultiRemoteCamera_OnNewImage.lua b/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/FlowConfig/MultiRemoteCamera_OnNewImage.lua new file mode 100644 index 0000000..daca709 --- /dev/null +++ b/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/FlowConfig/MultiRemoteCamera_OnNewImage.lua @@ -0,0 +1,67 @@ +-- Block namespace +local BLOCK_NAMESPACE = "MultiRemoteCamera_FC.OnNewImage" +local nameOfModule = 'CSK_MultiRemoteCamera' + +--************************************************************* +--************************************************************* + +-- Required to keep track of already allocated resource +local instanceTable = {} + +local function register(handle, _ , callback) + + Container.remove(handle, "CB_Function") + Container.add(handle, "CB_Function", callback) + + local instance = Container.get(handle, 'Instance') + + -- Check if amount of instances is valid + -- if not: add multiple additional instances + while true do + local amount = CSK_MultiRemoteCamera.getInstancesAmount() + if amount < instance then + CSK_MultiRemoteCamera.addInstance() + else + break + end + end + + local function localCallback() + if callback ~= nil then + Script.callFunction(callback, 'CSK_MultiRemoteCamera.OnNewImageCamera' .. tostring(instance)) + else + _G.logger:warning(nameOfModule .. ": " .. BLOCK_NAMESPACE .. ".CB_Function missing!") + end + end + Script.register('CSK_FlowConfig.OnNewFlowConfig', localCallback) + + return true +end +Script.serveFunction(BLOCK_NAMESPACE ..".register", register) + +--************************************************************* +--************************************************************* + +local function create(instance) + + -- Check if same instance is already configured + if instance < 1 or nil ~= instanceTable[instance] then + _G.logger:warning(nameOfModule .. ': Instance invalid already in use, please choose another one') + return nil + else + -- Otherwise create handle and store the restriced resource + local handle = Container.create() + instanceTable[instance] = instance + Container.add(handle, 'Instance', instance) + Container.add(handle, "CB_Function", "") + return handle + end +end +Script.serveFunction(BLOCK_NAMESPACE .. ".create", create) + +--- Function to reset instances if FlowConfig was cleared +local function handleOnClearOldFlow() + Script.releaseObject(instanceTable) + instanceTable = {} +end +Script.register('CSK_FlowConfig.OnClearOldFlow', handleOnClearOldFlow) \ No newline at end of file diff --git a/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/MultiRemoteCamera_Controller.lua b/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/MultiRemoteCamera_Controller.lua index d77d6b8..5ea3da0 100644 --- a/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/MultiRemoteCamera_Controller.lua +++ b/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/MultiRemoteCamera_Controller.lua @@ -47,6 +47,9 @@ Script.serveEvent("CSK_MultiRemoteCamera.OnRegisterCameraNUM", "MultiRemoteCamer -- Real events -------------------------------------------------- +Script.serveEvent('CSK_MultiRemoteCamera.OnNewStatusModuleVersion', 'MultiRemoteCamera_OnNewStatusModuleVersion') +Script.serveEvent('CSK_MultiRemoteCamera.OnNewStatusCSKStyle', 'MultiRemoteCamera_OnNewStatusCSKStyle') +Script.serveEvent('CSK_MultiRemoteCamera.OnNewStatusModuleIsActive', 'MultiRemoteCamera_OnNewStatusModuleIsActive') Script.serveEvent('CSK_MultiRemoteCamera.OnNewStatusWaitingForCameraBootUp', 'MultiRemoteCamera_OnNewStatusWaitingForCameraBootUp') Script.serveEvent("CSK_MultiRemoteCamera.OnNewCameraList", "MultiRemoteCamera_OnNewCameraList") @@ -70,12 +73,11 @@ Script.serveEvent("CSK_MultiRemoteCamera.OnNewFOVX", "MultiRemoteCamera_OnNewFOV Script.serveEvent("CSK_MultiRemoteCamera.OnNewFOVY", "MultiRemoteCamera_OnNewFOVY") Script.serveEvent('CSK_MultiRemoteCamera.OnNewImageSizeToShare', 'MultiRemoteCamera_OnNewImageSizeToShare') Script.serveEvent("CSK_MultiRemoteCamera.OnSWTriggerActive", "MultiRemoteCamera_OnSWTriggerActive") +Script.serveEvent('CSK_MultiRemoteCamera.OnNewSWTriggerEvent', 'MultiRemoteCamera_OnNewSWTriggerEvent') Script.serveEvent("CSK_MultiRemoteCamera.OnNewStatusDigitalTriggerPause", "MultiRemoteCamera_OnNewStatusDigitalTriggerPause") Script.serveEvent("CSK_MultiRemoteCamera.OnNewHardwareTriggerDelay", "MultiRemoteCamera_OnNewHardwareTriggerDelay") Script.serveEvent("CSK_MultiRemoteCamera.OnHWTriggerActive", "MultiRemoteCamera_OnHWTriggerActive") Script.serveEvent("CSK_MultiRemoteCamera.OnNewImageProcessingParameter", "MultiRemoteCamera_OnNewImageProcessingParameter") -Script.serveEvent("CSK_MultiRemoteCamera.OnPersistentDataModuleAvailable", "MultiRemoteCamera_OnPersistentDataModuleAvailable") -Script.serveEvent("CSK_MultiRemoteCamera.OnNewParameterName", "MultiRemoteCamera_OnNewParameterName") Script.serveEvent("CSK_MultiRemoteCamera.OnNewGigEVisionTableContent", "MultiRemoteCamera_OnNewGigEVisionTableContent") Script.serveEvent("CSK_MultiRemoteCamera.OnNewGigEVisionConfigTableContent", "MultiRemoteCamera_OnNewGigEVisionConfigTableContent") Script.serveEvent("CSK_MultiRemoteCamera.OnNewGigEVisionCurrentParameter", "MultiRemoteCamera_OnNewGigEVisionCurrentParameter") @@ -89,7 +91,6 @@ Script.serveEvent("CSK_MultiRemoteCamera.OnNewImageQueueCamera", "MultiRemoteCam Script.serveEvent("CSK_MultiRemoteCamera.OnNewFPSCamera", "MultiRemoteCamera_OnNewFPSCamera") Script.serveEvent("CSK_MultiRemoteCamera.OnNewStatusSaveAllImagesActive", "MultiRemoteCamera_OnNewStatusSaveAllImagesActive") Script.serveEvent("CSK_MultiRemoteCamera.OnNewStatusTempImageActive", "MultiRemoteCamera_OnNewStatusTempImageActive") -Script.serveEvent("CSK_MultiRemoteCamera.OnNewStatusLoadParameterOnReboot", "MultiRemoteCamera_OnNewStatusLoadParameterOnReboot") Script.serveEvent("CSK_MultiRemoteCamera.OnNewCameraOverviewTable", "MultiRemoteCamera_OnNewCameraOverviewTable") Script.serveEvent("CSK_MultiRemoteCamera.OnNewProcessingMode", "MultiRemoteCamera_OnNewProcessingMode") Script.serveEvent("CSK_MultiRemoteCamera.OnNewSwitchMode", "MultiRemoteCamera_OnNewSwitchMode") @@ -97,12 +98,19 @@ Script.serveEvent("CSK_MultiRemoteCamera.OnNewMonitoring", "MultiRemoteCamera_On Script.serveEvent("CSK_MultiRemoteCamera.OnNewMonitoringState", "MultiRemoteCamera_OnNewMonitoringState") --for UI Script.serveEvent("CSK_MultiRemoteCamera.OnNewMonitoringStateCams", "MultiRemoteCamera_OnNewMonitoringStateCams") +Script.serveEvent('CSK_MultiRemoteCamera.OnNewStatusFlowConfigPriority', 'MultiRemoteCamera_OnNewStatusFlowConfigPriority') +Script.serveEvent("CSK_MultiRemoteCamera.OnNewStatusLoadParameterOnReboot", "MultiRemoteCamera_OnNewStatusLoadParameterOnReboot") +Script.serveEvent("CSK_MultiRemoteCamera.OnPersistentDataModuleAvailable", "MultiRemoteCamera_OnPersistentDataModuleAvailable") +Script.serveEvent("CSK_MultiRemoteCamera.OnNewParameterName", "MultiRemoteCamera_OnNewParameterName") + Script.serveEvent("CSK_MultiRemoteCamera.OnUserLevelOperatorActive", "MultiRemoteCamera_OnUserLevelOperatorActive") Script.serveEvent("CSK_MultiRemoteCamera.OnUserLevelMaintenanceActive", "MultiRemoteCamera_OnUserLevelMaintenanceActive") Script.serveEvent("CSK_MultiRemoteCamera.OnUserLevelServiceActive", "MultiRemoteCamera_OnUserLevelServiceActive") Script.serveEvent("CSK_MultiRemoteCamera.OnUserLevelAdminActive", "MultiRemoteCamera_OnUserLevelAdminActive") Script.serveEvent('CSK_MultiRemoteCamera.OnNewCameraModel', 'MultiRemoteCamera_OnNewCameraModel') +Script.serveEvent('CSK_MultiRemoteCamera.OnNewStatusCustomCamera', 'MultiRemoteCamera_OnNewStatusCustomCamera') + Script.serveEvent('CSK_MultiRemoteCamera.OnNewNumberOfCameras', 'MultiRemoteCamera_OnNewNumberOfCameras') --************************* UI Events End ********************************** @@ -264,65 +272,76 @@ end --- Function to send all relevant values to UI on resume local function handleOnExpiredTmrCamera() - updateUserLevel() - Script.notifyEvent('MultiRemoteCamera_OnNewNumberOfCameras', string.format("%s", #multiRemoteCamera_Instances)) - Script.notifyEvent('MultiRemoteCamera_OnNewStatusWaitingForCameraBootUp', bootUpStatus) - Script.notifyEvent('MultiRemoteCamera_OnNewCameraList', helperFuncs.createStringListBySize(#multiRemoteCamera_Instances)) - Script.notifyEvent('MultiRemoteCamera_OnNewSelectedCam', selectedInstance) - Script.notifyEvent('MultiRemoteCamera_OnNewViewerID', 'multiRemoteCameraViewer' .. tostring(selectedInstance)) - Script.notifyEvent('MultiRemoteCamera_OnCameraConnected', multiRemoteCamera_Instances[selectedInstance].isConnected) - Script.notifyEvent('MultiRemoteCamera_OnScanCamera', false) - Script.notifyEvent('MultiRemoteCamera_OnCurrentCameraIP', multiRemoteCamera_Instances[selectedInstance].parameters.cameraIP) - Script.notifyEvent('MultiRemoteCamera_OnNewColorMode', multiRemoteCamera_Instances[selectedInstance].parameters.colorMode) - Script.notifyEvent('MultiRemoteCamera_OnNewStatusViewerActive', viewerActive) - Script.notifyEvent('MultiRemoteCamera_OnNewImageProcessingParameter', selectedInstance, 'viewerActive', viewerActive) - Script.notifyEvent('MultiRemoteCamera_OnNewGigEVisionStatus', multiRemoteCamera_Instances[selectedInstance].parameters.gigEvision) - if multiRemoteCamera_Instances[selectedInstance].parameters.gigEvision then - Script.notifyEvent('MultiRemoteCamera_OnNewGigEVisionParameters', multiRemoteCamera_Instances[selectedInstance].gigEVisionParameterList) - Script.notifyEvent('MultiRemoteCamera_OnNewGigEVisionCurrentParameter', multiRemoteCamera_Instances[selectedInstance].gigEVisionCurrentParameter) - Script.notifyEvent('MultiRemoteCamera_OnNewGigEVisionParameterType', multiRemoteCamera_Instances[selectedInstance].gigEVisionParameterType) - Script.notifyEvent('MultiRemoteCamera_OnNewGigEVisionValue', tostring(multiRemoteCamera_Instances[selectedInstance].gigEVisionParameterValue)) - if multiRemoteCamera_Instances[selectedInstance].gigEVisionParameterUITable then - Script.notifyEvent('MultiRemoteCamera_OnNewGigEVisionTableContent', multiRemoteCamera_Instances[selectedInstance].gigEVisionParameterUITable) + Script.notifyEvent("MultiRemoteCamera_OnNewStatusModuleVersion", multiRemoteCamera_Model.version) + Script.notifyEvent("MultiRemoteCamera_OnNewStatusCSKStyle", multiRemoteCamera_Model.styleForUI) + Script.notifyEvent("MultiRemoteCamera_OnNewStatusModuleIsActive", _G.availableAPIs.default and _G.availableAPIs.imageProvider) + + if _G.availableAPIs.default and _G.availableAPIs.imageProvider then + + updateUserLevel() + + Script.notifyEvent('MultiRemoteCamera_OnNewNumberOfCameras', string.format("%s", #multiRemoteCamera_Instances)) + Script.notifyEvent('MultiRemoteCamera_OnNewStatusWaitingForCameraBootUp', bootUpStatus) + Script.notifyEvent('MultiRemoteCamera_OnNewCameraList', helperFuncs.createStringListBySize(#multiRemoteCamera_Instances)) + Script.notifyEvent('MultiRemoteCamera_OnNewSelectedCam', selectedInstance) + Script.notifyEvent('MultiRemoteCamera_OnNewViewerID', 'multiRemoteCameraViewer' .. tostring(selectedInstance)) + Script.notifyEvent('MultiRemoteCamera_OnCameraConnected', multiRemoteCamera_Instances[selectedInstance].isConnected) + Script.notifyEvent('MultiRemoteCamera_OnScanCamera', false) + Script.notifyEvent('MultiRemoteCamera_OnCurrentCameraIP', multiRemoteCamera_Instances[selectedInstance].parameters.cameraIP) + Script.notifyEvent('MultiRemoteCamera_OnNewColorMode', multiRemoteCamera_Instances[selectedInstance].parameters.colorMode) + Script.notifyEvent('MultiRemoteCamera_OnNewStatusViewerActive', viewerActive) + Script.notifyEvent('MultiRemoteCamera_OnNewImageProcessingParameter', selectedInstance, 'viewerActive', viewerActive) + Script.notifyEvent('MultiRemoteCamera_OnNewGigEVisionStatus', multiRemoteCamera_Instances[selectedInstance].parameters.gigEvision) + if multiRemoteCamera_Instances[selectedInstance].parameters.gigEvision then + Script.notifyEvent('MultiRemoteCamera_OnNewGigEVisionParameters', multiRemoteCamera_Instances[selectedInstance].gigEVisionParameterList) + Script.notifyEvent('MultiRemoteCamera_OnNewGigEVisionCurrentParameter', multiRemoteCamera_Instances[selectedInstance].gigEVisionCurrentParameter) + Script.notifyEvent('MultiRemoteCamera_OnNewGigEVisionParameterType', multiRemoteCamera_Instances[selectedInstance].gigEVisionParameterType) + Script.notifyEvent('MultiRemoteCamera_OnNewGigEVisionValue', tostring(multiRemoteCamera_Instances[selectedInstance].gigEVisionParameterValue)) + if multiRemoteCamera_Instances[selectedInstance].gigEVisionParameterUITable then + Script.notifyEvent('MultiRemoteCamera_OnNewGigEVisionTableContent', multiRemoteCamera_Instances[selectedInstance].gigEVisionParameterUITable) + end + if multiRemoteCamera_Instances[selectedInstance].gigEVisionConfigUITable then + Script.notifyEvent('MultiRemoteCamera_OnNewGigEVisionConfigTableContent', multiRemoteCamera_Instances[selectedInstance].gigEVisionConfigUITable) + end end - if multiRemoteCamera_Instances[selectedInstance].gigEVisionConfigUITable then - Script.notifyEvent('MultiRemoteCamera_OnNewGigEVisionConfigTableContent', multiRemoteCamera_Instances[selectedInstance].gigEVisionConfigUITable) + Script.notifyEvent('MultiRemoteCamera_OnNewMonitoring', multiRemoteCamera_Instances[selectedInstance].parameters.monitorCamera) + Script.notifyEvent('MultiRemoteCamera_OnNewSwitchMode', multiRemoteCamera_Instances[selectedInstance].parameters.switchMode) + + Script.notifyEvent('MultiRemoteCamera_OnNewShutterTime', multiRemoteCamera_Instances[selectedInstance].parameters.shutterTime) + Script.notifyEvent('MultiRemoteCamera_OnNewGain', multiRemoteCamera_Instances[selectedInstance].parameters.gain) + Script.notifyEvent('MultiRemoteCamera_OnNewFramerate', multiRemoteCamera_Instances[selectedInstance].parameters.framerate) + Script.notifyEvent('MultiRemoteCamera_OnNewResizeFactor', multiRemoteCamera_Instances[selectedInstance].imageProcessingParams:get('resizeFactor')) + Script.notifyEvent('MultiRemoteCamera_OnNewAcquisitionMode', multiRemoteCamera_Instances[selectedInstance].parameters.acquisitionMode) + Script.notifyEvent('MultiRemoteCamera_OnNewImageQueueCamera', '-') + Script.notifyEvent('MultiRemoteCamera_OnNewFPSCamera', '-') + Script.notifyEvent('MultiRemoteCamera_OnNewFOVX', {multiRemoteCamera_Instances[selectedInstance].parameters.xStartFOV, multiRemoteCamera_Instances[selectedInstance].parameters.xEndFOV}) + Script.notifyEvent('MultiRemoteCamera_OnNewFOVY', {multiRemoteCamera_Instances[selectedInstance].parameters.yStartFOV, multiRemoteCamera_Instances[selectedInstance].parameters.yEndFOV}) + checkTriggerMode(multiRemoteCamera_Instances[selectedInstance].parameters.acquisitionMode) + Script.notifyEvent('MultiRemoteCamera_OnNewSWTriggerEvent', multiRemoteCamera_Instances[selectedInstance].parameters.swTriggerEvent) + Script.notifyEvent('MultiRemoteCamera_OnNewHardwareTriggerDelay', multiRemoteCamera_Instances[selectedInstance].parameters.hardwareTriggerDelay) + Script.notifyEvent('MultiRemoteCamera_OnNewStatusDigitalTriggerPause', multiRemoteCamera_Instances[selectedInstance].digTriggerStatus) + Script.notifyEvent('MultiRemoteCamera_OnNewParameterName', multiRemoteCamera_Instances[selectedInstance].parametersName) + Script.notifyEvent('MultiRemoteCamera_OnPersistentDataModuleAvailable', multiRemoteCamera_Instances[selectedInstance].persistentModuleAvailable) + Script.notifyEvent('MultiRemoteCamera_OnNewStatusSaveAllImagesActive', multiRemoteCamera_Instances[selectedInstance].parameters.saveAllImages) + Script.notifyEvent('MultiRemoteCamera_OnNewStatusTempImageActive', multiRemoteCamera_Instances[selectedInstance].parameters.tempSaveImage) + Script.notifyEvent('MultiRemoteCamera_OnNewSavingImagesPath', multiRemoteCamera_Instances[selectedInstance].parameters.savingImagePath) + Script.notifyEvent('MultiRemoteCamera_OnNewImageFilePrefix', multiRemoteCamera_Instances[selectedInstance].parameters.imageFilePrefix) + Script.notifyEvent('MultiRemoteCamera_OnNewImageSaveFormat', multiRemoteCamera_Instances[selectedInstance].parameters.imageSaveFormat) + if multiRemoteCamera_Instances[selectedInstance].parameters.imageSaveFormat == 'jpg' then + Script.notifyEvent('MultiRemoteCamera_OnNewFormatCompression', multiRemoteCamera_Instances[selectedInstance].parameters.imageSaveJpgFormatCompression) + elseif multiRemoteCamera_Instances[selectedInstance].parameters.imageSaveFormat == 'png' then + Script.notifyEvent('MultiRemoteCamera_OnNewFormatCompression', multiRemoteCamera_Instances[selectedInstance].parameters.imageSavePngFormatCompression) end + Script.notifyEvent('MultiRemoteCamera_OnNewLoggingMessage', "") + Script.notifyEvent("MultiRemoteCamera_OnNewStatusFlowConfigPriority", multiRemoteCamera_Instances[selectedInstance].parameters.flowConfigPriority) + Script.notifyEvent('MultiRemoteCamera_OnNewStatusLoadParameterOnReboot', multiRemoteCamera_Instances[selectedInstance].parameterLoadOnReboot) + Script.notifyEvent('MultiRemoteCamera_OnNewImageProcessingParameter', selectedInstance, 'activeInUI', true) + Script.notifyEvent('MultiRemoteCamera_OnNewProcessingMode', multiRemoteCamera_Instances[selectedInstance].parameters.processingMode) + Script.notifyEvent('MultiRemoteCamera_OnNewMonitoringState', multiRemoteCamera_Instances[selectedInstance].cameraIsPingAble) + Script.notifyEvent('MultiRemoteCamera_OnNewCameraModel', multiRemoteCamera_Instances[selectedInstance].parameters.cameraModel) + Script.notifyEvent('MultiRemoteCamera_OnNewStatusCustomCamera', multiRemoteCamera_Instances[selectedInstance].customCameraActive) + handleUpdateCameraOverviewPage() end - Script.notifyEvent('MultiRemoteCamera_OnNewMonitoring', multiRemoteCamera_Instances[selectedInstance].parameters.monitorCamera) - Script.notifyEvent('MultiRemoteCamera_OnNewSwitchMode', multiRemoteCamera_Instances[selectedInstance].parameters.switchMode) - - Script.notifyEvent('MultiRemoteCamera_OnNewShutterTime', multiRemoteCamera_Instances[selectedInstance].parameters.shutterTime) - Script.notifyEvent('MultiRemoteCamera_OnNewGain', multiRemoteCamera_Instances[selectedInstance].parameters.gain) - Script.notifyEvent('MultiRemoteCamera_OnNewFramerate', multiRemoteCamera_Instances[selectedInstance].parameters.framerate) - Script.notifyEvent('MultiRemoteCamera_OnNewResizeFactor', multiRemoteCamera_Instances[selectedInstance].imageProcessingParams:get('resizeFactor')) - Script.notifyEvent('MultiRemoteCamera_OnNewAcquisitionMode', multiRemoteCamera_Instances[selectedInstance].parameters.acquisitionMode) - Script.notifyEvent('MultiRemoteCamera_OnNewImageQueueCamera', '-') - Script.notifyEvent('MultiRemoteCamera_OnNewFPSCamera', '-') - Script.notifyEvent('MultiRemoteCamera_OnNewFOVX', {multiRemoteCamera_Instances[selectedInstance].parameters.xStartFOV, multiRemoteCamera_Instances[selectedInstance].parameters.xEndFOV}) - Script.notifyEvent('MultiRemoteCamera_OnNewFOVY', {multiRemoteCamera_Instances[selectedInstance].parameters.yStartFOV, multiRemoteCamera_Instances[selectedInstance].parameters.yEndFOV}) - checkTriggerMode(multiRemoteCamera_Instances[selectedInstance].parameters.acquisitionMode) - Script.notifyEvent('MultiRemoteCamera_OnNewHardwareTriggerDelay', multiRemoteCamera_Instances[selectedInstance].parameters.hardwareTriggerDelay) - Script.notifyEvent('MultiRemoteCamera_OnNewStatusDigitalTriggerPause', multiRemoteCamera_Instances[selectedInstance].digTriggerStatus) - Script.notifyEvent('MultiRemoteCamera_OnNewParameterName', multiRemoteCamera_Instances[selectedInstance].parametersName) - Script.notifyEvent('MultiRemoteCamera_OnPersistentDataModuleAvailable', multiRemoteCamera_Instances[selectedInstance].persistentModuleAvailable) - Script.notifyEvent('MultiRemoteCamera_OnNewStatusSaveAllImagesActive', multiRemoteCamera_Instances[selectedInstance].parameters.saveAllImages) - Script.notifyEvent('MultiRemoteCamera_OnNewStatusTempImageActive', multiRemoteCamera_Instances[selectedInstance].parameters.tempSaveImage) - Script.notifyEvent('MultiRemoteCamera_OnNewSavingImagesPath', multiRemoteCamera_Instances[selectedInstance].parameters.savingImagePath) - Script.notifyEvent('MultiRemoteCamera_OnNewImageFilePrefix', multiRemoteCamera_Instances[selectedInstance].parameters.imageFilePrefix) - Script.notifyEvent('MultiRemoteCamera_OnNewImageSaveFormat', multiRemoteCamera_Instances[selectedInstance].parameters.imageSaveFormat) - if multiRemoteCamera_Instances[selectedInstance].parameters.imageSaveFormat == 'jpg' then - Script.notifyEvent('MultiRemoteCamera_OnNewFormatCompression', multiRemoteCamera_Instances[selectedInstance].parameters.imageSaveJpgFormatCompression) - elseif multiRemoteCamera_Instances[selectedInstance].parameters.imageSaveFormat == 'png' then - Script.notifyEvent('MultiRemoteCamera_OnNewFormatCompression', multiRemoteCamera_Instances[selectedInstance].parameters.imageSavePngFormatCompression) - end - Script.notifyEvent('MultiRemoteCamera_OnNewLoggingMessage', "") - Script.notifyEvent('MultiRemoteCamera_OnNewStatusLoadParameterOnReboot', multiRemoteCamera_Instances[selectedInstance].parameterLoadOnReboot) - Script.notifyEvent('MultiRemoteCamera_OnNewImageProcessingParameter', selectedInstance, 'activeInUI', true) - Script.notifyEvent('MultiRemoteCamera_OnNewProcessingMode', multiRemoteCamera_Instances[selectedInstance].parameters.processingMode) - Script.notifyEvent('MultiRemoteCamera_OnNewMonitoringState', multiRemoteCamera_Instances[selectedInstance].cameraIsPingAble) - Script.notifyEvent('MultiRemoteCamera_OnNewCameraModel', multiRemoteCamera_Instances[selectedInstance].parameters.cameraModel) - handleUpdateCameraOverviewPage() end Timer.register(tmrCamera, "OnExpired", handleOnExpiredTmrCamera) @@ -334,7 +353,7 @@ local function handleOnExpiredTmrMonitorCameras() Script.notifyEvent('MultiRemoteCamera_OnNewMonitoringStateCams', i, multiRemoteCamera_Instances[i].cameraIsPingAble) if multiRemoteCamera_Instances[i].cameraIsPingAble then - _G.logger:info(nameOfModule .. ": Ping camera " .. tostring(i) .." with ip: " .. multiRemoteCamera_Instances[i].parameters.cameraIP .." : " .. tostring(multiRemoteCamera_Instances[i].cameraIsPingAble)) + _G.logger:fine(nameOfModule .. ": Ping camera " .. tostring(i) .." with ip: " .. multiRemoteCamera_Instances[i].parameters.cameraIP .." : " .. tostring(multiRemoteCamera_Instances[i].cameraIsPingAble)) else _G.logger:warning(nameOfModule .. ": Ping camera " .. tostring(i) .." with ip: " .. multiRemoteCamera_Instances[i].parameters.cameraIP .." : " .. tostring(multiRemoteCamera_Instances[i].cameraIsPingAble)) tmrCamera:start() -- Update UI @@ -345,10 +364,10 @@ end Timer.register(tmrMonitorCameras, "OnExpired", handleOnExpiredTmrMonitorCameras) local function pageCalled() - if _G.availableAPIs.imageProvider then + if _G.availableAPIs.default and _G.availableAPIs.imageProvider then updateUserLevel() -- try to hide user specific content asap - tmrCamera:start() end + tmrCamera:start() return '' end Script.serveFunction("CSK_MultiRemoteCamera.pageCalled", pageCalled) @@ -360,14 +379,19 @@ local function setFlowHandle(handle) end funcs.setFlowHandle = setFlowHandle -local function setSelectedCam(camNo) - selectedInstance = camNo - _G.logger:info(nameOfModule .. ": New selected camera = " .. tostring(selectedInstance)) - multiRemoteCamera_Instances[selectedInstance].activeInUI = true - Script.notifyEvent('MultiRemoteCamera_OnNewImageProcessingParameter', selectedInstance, 'activeInUI', true) - tmrCamera:start() +local function setSelectedInstance(camNo) + if #multiRemoteCamera_Instances >= camNo then + selectedInstance = camNo + _G.logger:fine(nameOfModule .. ": New selected camera = " .. tostring(selectedInstance)) + multiRemoteCamera_Instances[selectedInstance].activeInUI = true + Script.notifyEvent('MultiRemoteCamera_OnNewImageProcessingParameter', selectedInstance, 'activeInUI', true) + tmrCamera:start() + else + _G.logger:warning(nameOfModule .. ": Selected instance does not exist.") + end end -Script.serveFunction("CSK_MultiRemoteCamera.setSelectedCam", setSelectedCam) +Script.serveFunction("CSK_MultiRemoteCamera.setSelectedCam", setSelectedInstance) +Script.serveFunction("CSK_MultiRemoteCamera.setSelectedInstance", setSelectedInstance) local function getSelectedCam() return selectedInstance @@ -380,7 +404,7 @@ end Script.serveFunction('CSK_MultiRemoteCamera.getInstancesAmount', getInstancesAmount ) local function addInstance() - _G.logger:info(nameOfModule .. ": Add instance") + _G.logger:fine(nameOfModule .. ": Add instance") table.insert(multiRemoteCamera_Instances, multiRemoteCamera_Model.create(#multiRemoteCamera_Instances+1)) multiRemoteCamera_Instances[#multiRemoteCamera_Instances].parameters.switchMode = multiRemoteCamera_Instances[1].parameters.switchMode @@ -402,7 +426,7 @@ Script.serveFunction('CSK_MultiRemoteCamera.addInstance', addInstance) local function resetInstances() _G.logger:info(nameOfModule .. ": Reset instances.") - setSelectedCam(1) + setSelectedInstance(1) local totalAmount = #multiRemoteCamera_Instances while totalAmount > 1 do Script.releaseObject(multiRemoteCamera_Instances[totalAmount]) @@ -416,13 +440,19 @@ Script.serveFunction('CSK_MultiRemoteCamera.resetInstances', resetInstances) -- ********************* UI Setting / Submit Functions Start ******************** local function setCameraModel (camModel) - _G.logger:info(nameOfModule .. ": Set camera model = " .. tostring(camModel)) + _G.logger:fine(nameOfModule .. ": Set camera model = " .. tostring(camModel)) multiRemoteCamera_Instances[selectedInstance].parameters.cameraModel = camModel + if camModel == 'CustomConfig' then + multiRemoteCamera_Instances[selectedInstance].customCameraActive = true + else + multiRemoteCamera_Instances[selectedInstance].customCameraActive = false + end + Script.notifyEvent('MultiRemoteCamera_OnNewStatusCustomCamera', multiRemoteCamera_Instances[selectedInstance].customCameraActive) end Script.serveFunction('CSK_MultiRemoteCamera.setCameraModel', setCameraModel ) local function setCameraIP(ip) - _G.logger:info(nameOfModule .. ": Setting new IP = " .. ip .. ' for camera No.' .. tostring(selectedInstance)) + _G.logger:fine(nameOfModule .. ": Setting new IP = " .. ip .. ' for camera No.' .. tostring(selectedInstance)) if checkIP(ip) == true then multiRemoteCamera_Instances[selectedInstance].parameters.cameraIP = ip Script.notifyEvent('MultiRemoteCamera_OnNewIPCheck', false) @@ -439,7 +469,7 @@ Script.serveFunction("CSK_MultiRemoteCamera.getCameraIP", getCameraIP) local function connectCamera() -- Try to connect the camera - _G.logger:info(nameOfModule .. ": Try to connecto to camera no. " .. tostring(selectedInstance)) + _G.logger:info(nameOfModule .. ": Try to connect to camera no. " .. tostring(selectedInstance)) multiRemoteCamera_Instances[selectedInstance]:connectCamera() if multiRemoteCamera_Instances[selectedInstance].isConnected and multiRemoteCamera_Instances[selectedInstance].parameters.monitorCamera then handleOnExpiredTmrMonitorCameras () @@ -477,7 +507,7 @@ local function setGigEVision(status) elseif status == false and _G.availableAPIs.I2D == false then multiRemoteCamera_Instances[selectedInstance].parameters.gigEvision = true end - _G.logger:info(nameOfModule .. ": Set GigEVision of camera no. " .. tostring(selectedInstance) .. ": " .. tostring(multiRemoteCamera_Instances[selectedInstance].parameters.gigEvision)) + _G.logger:fine(nameOfModule .. ": Set GigEVision of camera no. " .. tostring(selectedInstance) .. ": " .. tostring(multiRemoteCamera_Instances[selectedInstance].parameters.gigEvision)) Script.notifyEvent('MultiRemoteCamera_OnNewGigEVisionStatus', multiRemoteCamera_Instances[selectedInstance].parameters.gigEvision) end @@ -493,13 +523,13 @@ local function setSwitchMode (status) multiRemoteCamera_Instances[i].parameters.switchMode = status multiRemoteCamera_Instances[i]:setNewConfig() end - _G.logger:info(nameOfModule .. ": Set camera switch mode for all cameras = " .. tostring(status)) + _G.logger:fine(nameOfModule .. ": Set camera switch mode for all cameras = " .. tostring(status)) end Script.serveFunction("CSK_MultiRemoteCamera.setSwitchMode", setSwitchMode) local function setCameraMonitoring (state) multiRemoteCamera_Instances[selectedInstance].parameters.monitorCamera = state - _G.logger:info(nameOfModule .. ": Status of camera monitoring of camera no. " .. tostring(selectedInstance) .. " = " .. tostring(state)) + _G.logger:fine(nameOfModule .. ": Status of camera monitoring of camera no. " .. tostring(selectedInstance) .. " = " .. tostring(state)) if state == true and multiRemoteCamera_Instances[selectedInstance].isConnected then handleOnExpiredTmrMonitorCameras () tmrMonitorCameras:start() @@ -520,7 +550,7 @@ end Script.serveFunction("CSK_MultiRemoteCamera.setCameraMonitoring", setCameraMonitoring) local function setColorMode(mode) - _G.logger:info(nameOfModule .. ": Set color mode = " .. tostring(mode)) + _G.logger:fine(nameOfModule .. ": Set color mode = " .. tostring(mode)) multiRemoteCamera_Instances[selectedInstance]:setColorMode(mode) end Script.serveFunction("CSK_MultiRemoteCamera.setColorMode", setColorMode) @@ -530,12 +560,40 @@ local function getColorMode() end Script.serveFunction("CSK_MultiRemoteCamera.getColorMode", getColorMode) +local function cameraSoftwareTrigger() + _G.logger:info(nameOfModule .. ": SW trigger") + multiRemoteCamera_Instances[selectedInstance].CameraProvider:snapshot() +end +Script.serveFunction("CSK_MultiRemoteCamera.cameraSoftwareTrigger", cameraSoftwareTrigger) + +local function cameraSpecificSoftwareTrigger(cameraNo) + _G.logger:info(nameOfModule .. ": SW trigger camera no." .. tostring(cameraNo)) + multiRemoteCamera_Instances[cameraNo].CameraProvider:snapshot() +end +Script.serveFunction("CSK_MultiRemoteCamera.cameraSpecificSoftwareTrigger", cameraSpecificSoftwareTrigger) + +local function setSWTriggerEvent(event) + Script.deregister(multiRemoteCamera_Instances[selectedInstance].parameters.swTriggerEvent, multiRemoteCamera_Instances[selectedInstance].triggerFunction) + multiRemoteCamera_Instances[selectedInstance].parameters.swTriggerEvent = event + + if multiRemoteCamera_Instances[selectedInstance].parameters.acquisitionMode == 'SOFTWARE_TRIGGER' then + _G.logger:info(nameOfModule .. ": Set SW trigger event to " .. tostring(event)) + local function triggerCamera() + cameraSpecificSoftwareTrigger(selectedInstance) + end + multiRemoteCamera_Instances[selectedInstance].triggerFunction = triggerCamera + Script.register(event, multiRemoteCamera_Instances[selectedInstance].triggerFunction) + end +end +Script.serveFunction('CSK_MultiRemoteCamera.setSWTriggerEvent', setSWTriggerEvent) + local function setAcquisitionMode(mode) - _G.logger:info(nameOfModule .. ": Set acquisition mode = " .. tostring(mode)) + _G.logger:fine(nameOfModule .. ": Set acquisition mode = " .. tostring(mode)) multiRemoteCamera_Instances[selectedInstance].digTriggerStatus = false Script.notifyEvent("MultiRemoteCamera_OnNewStatusDigitalTriggerPause", false) checkTriggerMode(mode) multiRemoteCamera_Instances[selectedInstance]:setAcquisitionMode(mode) + setSWTriggerEvent(multiRemoteCamera_Instances[selectedInstance].parameters.swTriggerEvent) handleUpdateCameraOverviewPage() end Script.serveFunction("CSK_MultiRemoteCamera.setAcquisitionMode", setAcquisitionMode) @@ -546,7 +604,7 @@ end Script.serveFunction("CSK_MultiRemoteCamera.getAcquisitionMode", getAcquisitionMode) local function setHardwareTriggerDelay(value) - _G.logger:info(nameOfModule .. ": Set hardware trigger delay = " .. tostring(value)) + _G.logger:fine(nameOfModule .. ": Set hardware trigger delay = " .. tostring(value)) multiRemoteCamera_Instances[selectedInstance].parameters.hardwareTriggerDelay = value if multiRemoteCamera_Instances[selectedInstance].parameters.triggerDelayBlockName ~= nil and cameraFlow ~= nil then cameraFlow:updateParameter(multiRemoteCamera_Instances[selectedInstance].parameters.triggerDelayBlockName, "DelayTime", value) @@ -562,12 +620,12 @@ Script.serveFunction("CSK_MultiRemoteCamera.getHardwareTriggerDelay", getHardwar local function setDigitalTriggerPause() if multiRemoteCamera_Instances[selectedInstance].digTriggerStatus == true then multiRemoteCamera_Instances[selectedInstance].digTriggerStatus = false - _G.logger:info(nameOfModule .. ": Set trigger pause: false") + _G.logger:fine(nameOfModule .. ": Set trigger pause: false") Script.notifyEvent("MultiRemoteCamera_OnNewStatusDigitalTriggerPause", multiRemoteCamera_Instances[selectedInstance].digTriggerStatus) multiRemoteCamera_Instances[selectedInstance]:startCamera() else multiRemoteCamera_Instances[selectedInstance].digTriggerStatus = true - _G.logger:info(nameOfModule .. ": Set trigger pause: true") + _G.logger:fine(nameOfModule .. ": Set trigger pause: true") Script.notifyEvent("MultiRemoteCamera_OnNewStatusDigitalTriggerPause", multiRemoteCamera_Instances[selectedInstance].digTriggerStatus) multiRemoteCamera_Instances[selectedInstance]:stopCamera() end @@ -575,7 +633,7 @@ end Script.serveFunction("CSK_MultiRemoteCamera.setDigitalTriggerPause", setDigitalTriggerPause) local function setFOVX(values) - _G.logger:info(nameOfModule .. ": Preset FOV X = " .. tostring(values[1]) .. " - " .. values[2]) + _G.logger:fine(nameOfModule .. ": Preset FOV X = " .. tostring(values[1]) .. " - " .. values[2]) multiRemoteCamera_Instances[selectedInstance].parameters.xStartFOV = values[1] multiRemoteCamera_Instances[selectedInstance].parameters.xEndFOV = values[2] Script.notifyEvent('MultiRemoteCamera_OnNewFOVX', values) @@ -588,7 +646,7 @@ end Script.serveFunction("CSK_MultiRemoteCamera.getFOVX", getFOVX) local function setFOVY(values) - _G.logger:info(nameOfModule .. ": Preset FOV Y = " .. tostring(values[1]) .. " - " .. values[2]) + _G.logger:fine(nameOfModule .. ": Preset FOV Y = " .. tostring(values[1]) .. " - " .. values[2]) multiRemoteCamera_Instances[selectedInstance].parameters.yStartFOV = values[1] multiRemoteCamera_Instances[selectedInstance].parameters.yEndFOV = values[2] Script.notifyEvent('MultiRemoteCamera_OnNewFOVY', values) @@ -601,14 +659,14 @@ end Script.serveFunction("CSK_MultiRemoteCamera.getFOVY", getFOVY) local function setFOV() - _G.logger:info(nameOfModule .. ": Set FOV") + _G.logger:fine(nameOfModule .. ": Set FOV") multiRemoteCamera_Instances[selectedInstance]:setFOV() Script.notifyEvent('MultiRemoteCamera_OnNewImageSizeToShare', "CSK_MultiRemoteCamera.OnNewImageCamera" .. tostring(selectedInstance)) end Script.serveFunction("CSK_MultiRemoteCamera.setFOV", setFOV) local function setShutterTime(shutterTime) - _G.logger:info(nameOfModule .. ": Set shutter time = " .. tostring(shutterTime)) + _G.logger:fine(nameOfModule .. ": Set shutter time = " .. tostring(shutterTime)) multiRemoteCamera_Instances[selectedInstance]:setShutterTime(shutterTime) handleUpdateCameraOverviewPage() end @@ -620,7 +678,7 @@ end Script.serveFunction("CSK_MultiRemoteCamera.getShutterTime", getShutterTime) local function setGain(gain) - _G.logger:info(nameOfModule .. ": Set gain = " .. tostring(gain)) + _G.logger:fine(nameOfModule .. ": Set gain = " .. tostring(gain)) multiRemoteCamera_Instances[selectedInstance]:setGain(gain) handleUpdateCameraOverviewPage() end @@ -632,7 +690,7 @@ end Script.serveFunction("CSK_MultiRemoteCamera.getGain", getGain) local function setFramerate(framerate) - _G.logger:info(nameOfModule .. ": Set framerate = " .. tostring(framerate)) + _G.logger:fine(nameOfModule .. ": Set framerate = " .. tostring(framerate)) multiRemoteCamera_Instances[selectedInstance]:setFramerate(framerate) end Script.serveFunction("CSK_MultiRemoteCamera.setFramerate", setFramerate) @@ -643,7 +701,7 @@ end Script.serveFunction("CSK_MultiRemoteCamera.getFramerate", getFramerate) local function setResizeFactor(factor) - _G.logger:info(nameOfModule .. ": Set resize factor = " .. tostring(factor)) + _G.logger:fine(nameOfModule .. ": Set resize factor = " .. tostring(factor)) multiRemoteCamera_Instances[selectedInstance].parameters.resizeFactor = factor multiRemoteCamera_Instances[selectedInstance].imageProcessingParams:update('resizeFactor', multiRemoteCamera_Instances[selectedInstance].parameters.resizeFactor) Script.notifyEvent('MultiRemoteCamera_OnNewImageProcessingParameter', selectedInstance, 'resizeFactor', multiRemoteCamera_Instances[selectedInstance].parameters.resizeFactor) @@ -657,7 +715,7 @@ end Script.serveFunction("CSK_MultiRemoteCamera.getResizeFactor", getResizeFactor) local function setProcessingMode(mode) - _G.logger:info(nameOfModule .. ": Set processing mode = " .. tostring(mode)) + _G.logger:fine(nameOfModule .. ": Set processing mode = " .. tostring(mode)) multiRemoteCamera_Instances[selectedInstance].parameters.processingMode = mode multiRemoteCamera_Instances[selectedInstance].imageProcessingParams:update('mode', multiRemoteCamera_Instances[selectedInstance].parameters.processingMode) Script.notifyEvent('MultiRemoteCamera_OnNewImageProcessingParameter', selectedInstance, 'mode', multiRemoteCamera_Instances[selectedInstance].parameters.processingMode) @@ -669,20 +727,8 @@ local function getProcessingMode() end Script.serveFunction("CSK_MultiRemoteCamera.getProcessingMode", getProcessingMode) -local function cameraSoftwareTrigger() - _G.logger:info(nameOfModule .. ": SW trigger") - multiRemoteCamera_Instances[selectedInstance].CameraProvider:snapshot() -end -Script.serveFunction("CSK_MultiRemoteCamera.cameraSoftwareTrigger", cameraSoftwareTrigger) - -local function cameraSpecificSoftwareTrigger(cameraNo) - _G.logger:info(nameOfModule .. ": SW trigger camera no." .. tostring(cameraNo)) - multiRemoteCamera_Instances[cameraNo].CameraProvider:snapshot() -end -Script.serveFunction("CSK_MultiRemoteCamera.cameraSpecificSoftwareTrigger", cameraSpecificSoftwareTrigger) - local function setImageFilePrefix(prefix) - _G.logger:info(nameOfModule .. ": Set image file prefix: " .. tostring(prefix)) + _G.logger:fine(nameOfModule .. ": Set image file prefix: " .. tostring(prefix)) multiRemoteCamera_Instances[selectedInstance].parameters.imageFilePrefix = prefix Script.notifyEvent('MultiRemoteCamera_OnNewImageProcessingParameter', selectedInstance, 'imageFilePrefix', prefix) end @@ -691,7 +737,7 @@ Script.serveFunction("CSK_MultiRemoteCamera.setImageFilePrefix", setImageFilePre local function setSavingPath(path) if path == '/sdcard/0/' then if File.exists(path) then - _G.logger:info(nameOfModule .. ': Changed image saving path to SD Card for camera No.' .. tostring(selectedInstance)) + _G.logger:fine(nameOfModule .. ': Changed image saving path to SD Card for camera No.' .. tostring(selectedInstance)) multiRemoteCamera_Instances[selectedInstance].parameters.savingImagePath = path Script.notifyEvent('MultiRemoteCamera_OnNewImageProcessingParameter', selectedInstance, 'savingImagePath', '/sdcard/0/') else @@ -704,13 +750,13 @@ local function setSavingPath(path) else multiRemoteCamera_Instances[selectedInstance].parameters.savingImagePath = '/public/' Script.notifyEvent('MultiRemoteCamera_OnNewImageProcessingParameter', selectedInstance, 'savingImagePath', '/public/') - _G.logger:info(nameOfModule .. ': Changed saving path to public folder for camera No.' .. tostring(selectedInstance)) + _G.logger:fine(nameOfModule .. ': Changed saving path to public folder for camera No.' .. tostring(selectedInstance)) end end Script.serveFunction("CSK_MultiRemoteCamera.setSavingPath", setSavingPath) local function setImageSaveFormat(format) - _G.logger:info(nameOfModule .. ": Set image save formate: " .. tostring(format)) + _G.logger:fine(nameOfModule .. ": Set image save formate: " .. tostring(format)) multiRemoteCamera_Instances[selectedInstance].parameters.imageSaveFormat = format Script.notifyEvent('MultiRemoteCamera_OnNewImageProcessingParameter', selectedInstance, 'imageSaveFormat', format) Script.notifyEvent('MultiRemoteCamera_OnNewImageSaveFormat', multiRemoteCamera_Instances[selectedInstance].parameters.imageSaveFormat) @@ -723,7 +769,7 @@ end Script.serveFunction("CSK_MultiRemoteCamera.setImageSaveFormat", setImageSaveFormat) local function setImageSaveFormatCompression(comp) - _G.logger:info(nameOfModule .. ": Set image save compression: " .. tostring(comp)) + _G.logger:fine(nameOfModule .. ": Set image save compression: " .. tostring(comp)) if multiRemoteCamera_Instances[selectedInstance].parameters.imageSaveFormat == 'jpg' then multiRemoteCamera_Instances[selectedInstance].parameters.imageSaveJpgFormatCompression = comp Script.notifyEvent('MultiRemoteCamera_OnNewImageProcessingParameter', selectedInstance, 'imageSaveJpgFormatCompression', comp) @@ -741,14 +787,14 @@ end Script.serveFunction("CSK_MultiRemoteCamera.triggerImageSaving", triggerImageSaving) local function setSaveAllImages(status) - _G.logger:info(nameOfModule .. ": Save all images: " .. tostring(status)) + _G.logger:fine(nameOfModule .. ": Save all images: " .. tostring(status)) multiRemoteCamera_Instances[selectedInstance].parameters.saveAllImages = status Script.notifyEvent('MultiRemoteCamera_OnNewImageProcessingParameter', selectedInstance, 'saveAllImages', status) end Script.serveFunction("CSK_MultiRemoteCamera.setSaveAllImages", setSaveAllImages) local function setTempImageActive(status) - _G.logger:info(nameOfModule .. ": Save temporarily latest images: " .. tostring(status)) + _G.logger:fine(nameOfModule .. ": Save temporarily latest images: " .. tostring(status)) multiRemoteCamera_Instances[selectedInstance].parameters.tempSaveImage = status Script.notifyEvent('MultiRemoteCamera_OnNewImageProcessingParameter', selectedInstance, 'tempSaveImage', status) Script.notifyEvent('MultiRemoteCamera_OnNewStatusTempImageActive', status) @@ -756,20 +802,20 @@ end Script.serveFunction("CSK_MultiRemoteCamera.setTempImageActive", setTempImageActive) local function setViewerActive(status) - _G.logger:info(nameOfModule .. ": Viewer active: " .. tostring(status)) + _G.logger:fine(nameOfModule .. ": Viewer active: " .. tostring(status)) viewerActive = status Script.notifyEvent('MultiRemoteCamera_OnNewImageProcessingParameter', selectedInstance, 'viewerActive', viewerActive) end Script.serveFunction("CSK_MultiRemoteCamera.setViewerActive", setViewerActive) local function updateConfig() - _G.logger:info(nameOfModule .. ": Update config.") + _G.logger:fine(nameOfModule .. ": Update config.") multiRemoteCamera_Instances[selectedInstance]:setNewConfig() end Script.serveFunction("CSK_MultiRemoteCamera.updateConfig", updateConfig) local function addGigEVisionConfig() - _G.logger:info(nameOfModule .. ": Add custom GigE Vision parameter value.") + _G.logger:fine(nameOfModule .. ": Add custom GigE Vision parameter value.") local newConfig = {} newConfig.parameter = multiRemoteCamera_Instances[selectedInstance].gigEVisionCurrentParameter newConfig.type = multiRemoteCamera_Instances[selectedInstance].gigEVisionParameterType @@ -782,7 +828,7 @@ end Script.serveFunction("CSK_MultiRemoteCamera.addGigEVisionConfig", addGigEVisionConfig) local function removeGigEVisionConfig() - _G.logger:info(nameOfModule .. ": Remove custom GigE Vision parameter value.") + _G.logger:fine(nameOfModule .. ": Remove custom GigE Vision parameter value.") if multiRemoteCamera_Instances[selectedInstance].gigEVisionSelectedConfig then table.remove(multiRemoteCamera_Instances[selectedInstance].parameters.customGigEVisionConfig, multiRemoteCamera_Instances[selectedInstance].gigEVisionSelectedConfig) multiRemoteCamera_Instances[selectedInstance].gigEVisionConfigUITable = multiRemoteCamera_Instances[selectedInstance].helperFuncs.createModuleJsonList('gigEConfig', multiRemoteCamera_Instances[selectedInstance].parameters.customGigEVisionConfig) @@ -792,7 +838,7 @@ end Script.serveFunction("CSK_MultiRemoteCamera.removeGigEVisionConfig", removeGigEVisionConfig) local function setGigEVisionParameterName(name) - _G.logger:info(nameOfModule .. ": Set GigE Vision parameter name: " .. tostring(name)) + _G.logger:fine(nameOfModule .. ": Set GigE Vision parameter name: " .. tostring(name)) multiRemoteCamera_Instances[selectedInstance].gigEVisionCurrentParameter = name multiRemoteCamera_Instances[selectedInstance].gigEVisionParameterType = multiRemoteCamera_Instances[selectedInstance].gigEVisionParameterAllTypes[name] multiRemoteCamera_Instances[selectedInstance].gigEVisionParameterValue = multiRemoteCamera_Instances[selectedInstance].gigEVisionParameterAllValues[name] @@ -828,7 +874,7 @@ local function setSelection(selection, pattern) end local function selectGigEVisionConfig(selection) - _G.logger:info(nameOfModule .. ": Select GigE Vision config no." .. tostring(selection)) + _G.logger:fine(nameOfModule .. ": Select GigE Vision config no." .. tostring(selection)) multiRemoteCamera_Instances[selectedInstance].gigEVisionSelectedConfig = selection end Script.serveFunction("CSK_MultiRemoteCamera.selectGigEVisionConfig", selectGigEVisionConfig) @@ -836,7 +882,7 @@ Script.serveFunction("CSK_MultiRemoteCamera.selectGigEVisionConfig", selectGigEV local function selectGigEVisionConfigViaUITable(selection) local selected = setSelection(selection, '"No":"') if selected ~= "" then - _G.logger:info(nameOfModule .. ": Select GigE Vision config no." .. tostring(selected)) + _G.logger:fine(nameOfModule .. ": Select GigE Vision config no." .. tostring(selected)) multiRemoteCamera_Instances[selectedInstance].gigEVisionSelectedConfig = tonumber(selected) else _G.logger:info(nameOfModule .. ": Selection error.") @@ -856,14 +902,16 @@ end Script.serveFunction("CSK_MultiRemoteCamera.selectGigEVisionParameterNameViaUITable", selectGigEVisionParameterNameViaUITable) local function setGigEVisionParameterValue(value) - _G.logger:info(nameOfModule .. ": Set GigE Vision parameter value: " .. tostring(value)) + _G.logger:fine(nameOfModule .. ": Set GigE Vision parameter value: " .. tostring(value)) multiRemoteCamera_Instances[selectedInstance].gigEVisionParameterValue = value end Script.serveFunction("CSK_MultiRemoteCamera.setGigEVisionParameterValue", setGigEVisionParameterValue) --- Function to update processing parameters within the processing threads local function updateImageProcessingParameter() - _G.logger:info(nameOfModule .. ": Update image processing parameter.") + _G.logger:fine(nameOfModule .. ": Update image processing parameter.") + + setSWTriggerEvent(multiRemoteCamera_Instances[selectedInstance].parameters.swTriggerEvent) setProcessingMode(multiRemoteCamera_Instances[selectedInstance].parameters.processingMode) setResizeFactor(multiRemoteCamera_Instances[selectedInstance].parameters.resizeFactor) setSaveAllImages(multiRemoteCamera_Instances[selectedInstance].parameters.saveAllImages) @@ -899,17 +947,36 @@ local function restartAllCameras() end Script.serveFunction('CSK_MultiRemoteCamera.restartAllCameras', restartAllCameras) +local function getStatusModuleActive() + return _G.availableAPIs.default and _G.availableAPIs.imageProvider +end +Script.serveFunction('CSK_MultiRemoteCamera.getStatusModuleActive', getStatusModuleActive) + +local function clearFlowConfigRelevantConfiguration() + -- Nothing to do so far +end +Script.serveFunction('CSK_MultiRemoteCamera.clearFlowConfigRelevantConfiguration', clearFlowConfigRelevantConfiguration) + +local function getParameters(instanceNo) + if instanceNo <= #multiRemoteCamera_Instances then + return multiRemoteCamera_Instances[instanceNo].helperFuncs.json.encode(multiRemoteCamera_Instances[instanceNo].parameters) + else + return '' + end +end +Script.serveFunction('CSK_MultiRemoteCamera.getParameters', getParameters) + -- ***************************************************************** -- Following function can be adapted for CSK_PersistentData module usage -- ***************************************************************** local function setParameterName(name) - _G.logger:info(nameOfModule .. ": Set parameter name: " .. tostring(name)) + _G.logger:fine(nameOfModule .. ": Set parameter name: " .. tostring(name)) multiRemoteCamera_Instances[selectedInstance].parametersName = name end Script.serveFunction("CSK_MultiRemoteCamera.setParameterName", setParameterName) -local function sendParameters() +local function sendParameters(noDataSave) if multiRemoteCamera_Instances[selectedInstance].persistentModuleAvailable then CSK_PersistentData.addParameter(helperFuncs.convertTable2Container(multiRemoteCamera_Instances[selectedInstance].parameters), multiRemoteCamera_Instances[selectedInstance].parametersName) @@ -919,8 +986,10 @@ local function sendParameters() else CSK_PersistentData.setModuleParameterName(nameOfModule, multiRemoteCamera_Instances[selectedInstance].parametersName, multiRemoteCamera_Instances[selectedInstance].parameterLoadOnReboot, tostring(selectedInstance)) end - _G.logger:info(nameOfModule .. ": Send camera parameters with name '" .. multiRemoteCamera_Instances[selectedInstance].parametersName .. "' to CSK_PersistentData module.") - CSK_PersistentData.saveData() + _G.logger:fine(nameOfModule .. ": Send camera parameters with name '" .. multiRemoteCamera_Instances[selectedInstance].parametersName .. "' to CSK_PersistentData module.") + if not noDataSave then + CSK_PersistentData.saveData() + end else _G.logger:warning(nameOfModule .. ": CSK_PersistentData module not available.") end @@ -935,31 +1004,44 @@ local function loadParameters() multiRemoteCamera_Instances[selectedInstance].parameters = helperFuncs.convertContainer2Table(data) multiRemoteCamera_Instances[selectedInstance]:setNewConfig() updateImageProcessingParameter() + pageCalled() + return true else _G.logger:warning(nameOfModule .. ": Loading parameters from CSK_PersistentData module did not work.") + pageCalled() + return false end else _G.logger:warning(nameOfModule .. ": CSK_PersistentData module not available.") + pageCalled() + return false end - pageCalled() end Script.serveFunction("CSK_MultiRemoteCamera.loadParameters", loadParameters) local function setLoadOnReboot(status) multiRemoteCamera_Instances[selectedInstance].parameterLoadOnReboot = status - _G.logger:info(nameOfModule .. ": Set new status to load setting on reboot: " .. tostring(status)) + _G.logger:fine(nameOfModule .. ": Set new status to load setting on reboot: " .. tostring(status)) + Script.notifyEvent("MultiRemoteCamera_OnNewStatusLoadParameterOnReboot", status) handleUpdateCameraOverviewPage() end Script.serveFunction("CSK_MultiRemoteCamera.setLoadOnReboot", setLoadOnReboot) +local function setFlowConfigPriority(status) + multiRemoteCamera_Instances[selectedInstance].parameters.flowConfigPriority = status + _G.logger:fine(nameOfModule .. ": Set new status of FlowConfig priority: " .. tostring(status)) + Script.notifyEvent("MultiRemoteCamera_OnNewStatusFlowConfigPriority", multiRemoteCamera_Instances[selectedInstance].parameters.flowConfigPriority) +end +Script.serveFunction('CSK_MultiRemoteCamera.setFlowConfigPriority', setFlowConfigPriority) + --- Function to setup cameras after bootup local function setupCamerasAfterBootUp() - _G.logger:info(nameOfModule .. ': Setup camera after bootUp.') + _G.logger:fine(nameOfModule .. ': Setup camera after bootUp.') local isOneConnected = false for i = 1, #multiRemoteCamera_Instances do if multiRemoteCamera_Instances[i].parameterLoadOnReboot then - CSK_MultiRemoteCamera.setSelectedCam(i) + CSK_MultiRemoteCamera.setSelectedInstance(i) CSK_MultiRemoteCamera.loadParameters() CSK_MultiRemoteCamera.connectCamera() updateImageProcessingParameter() @@ -976,62 +1058,80 @@ Timer.register(tmrCameraBootUp, 'OnExpired', setupCamerasAfterBootUp) --- Function to react on initial load of persistent parameters local function handleOnInitialDataLoaded() + if _G.availableAPIs.default and _G.availableAPIs.imageProvider then - _G.logger:info(nameOfModule .. ': Try to initially load parameter from CSK_PersistentData module.') - -- Check if CSK_PersistentData version is > 1.x.x - if string.sub(CSK_PersistentData.getVersion(), 1, 1) == '1' then - - _G.logger:warning(nameOfModule .. ': CSK_PersistentData module is too old and will not work. Please update CSK_PersistentData module.') + _G.logger:fine(nameOfModule .. ': Try to initially load parameter from CSK_PersistentData module.') + -- Check if CSK_PersistentData version is > 1.x.x + if string.sub(CSK_PersistentData.getVersion(), 1, 1) == '1' then - for j = 1, #multiRemoteCamera_Instances do - multiRemoteCamera_Instances[j].persistentModuleAvailable = false - end - else + _G.logger:warning(nameOfModule .. ': CSK_PersistentData module is too old and will not work. Please update CSK_PersistentData module.') - local bootUpBreak = false + for j = 1, #multiRemoteCamera_Instances do + multiRemoteCamera_Instances[j].persistentModuleAvailable = false + end + else - -- Check if CSK_PersistentData version is >= 3.0.0 - if tonumber(string.sub(CSK_PersistentData.getVersion(), 1, 1)) >= 3 then - local parameterName, loadOnReboot, totalInstances = CSK_PersistentData.getModuleParameterName(nameOfModule, '1') - -- Check for amount if instances to create - if totalInstances then - local c = 2 - while c <= totalInstances do - addInstance() - c = c+1 + local bootUpBreak = false + + -- Check if CSK_PersistentData version is >= 3.0.0 + if tonumber(string.sub(CSK_PersistentData.getVersion(), 1, 1)) >= 3 then + local parameterName, loadOnReboot, totalInstances = CSK_PersistentData.getModuleParameterName(nameOfModule, '1') + -- Check for amount if instances to create + if totalInstances then + local c = 2 + while c <= totalInstances do + addInstance() + c = c+1 + end end end - end - for i = 1, #multiRemoteCamera_Instances do - local parameterName, loadOnReboot = CSK_PersistentData.getModuleParameterName(nameOfModule, tostring(i)) - - if parameterName then - multiRemoteCamera_Instances[i].parametersName = parameterName - multiRemoteCamera_Instances[i].parameterLoadOnReboot = loadOnReboot + if not multiRemoteCamera_Instances then + return end - if multiRemoteCamera_Instances[i].parameterLoadOnReboot then - bootUpBreak = true + for i = 1, #multiRemoteCamera_Instances do + local parameterName, loadOnReboot = CSK_PersistentData.getModuleParameterName(nameOfModule, tostring(i)) + + if parameterName then + multiRemoteCamera_Instances[i].parametersName = parameterName + multiRemoteCamera_Instances[i].parameterLoadOnReboot = loadOnReboot + end + + if multiRemoteCamera_Instances[i].parameterLoadOnReboot then + bootUpBreak = true + end end - end - if bootUpBreak then - _G.logger:info(nameOfModule .. ": Wait for camera(s) power bootUp") + if bootUpBreak then + _G.logger:info(nameOfModule .. ": Wait for camera(s) power bootUp") - tmrCameraBootUp:start() - bootUpStatus = true - Script.notifyEvent('MultiRemoteCamera_OnNewStatusWaitingForCameraBootUp', bootUpStatus) + tmrCameraBootUp:start() + bootUpStatus = true + Script.notifyEvent('MultiRemoteCamera_OnNewStatusWaitingForCameraBootUp', bootUpStatus) - else - setupCamerasAfterBootUp() + else + setupCamerasAfterBootUp() + end end end end -if _G.availableAPIs.imageProvider then +if _G.availableAPIs.default and _G.availableAPIs.imageProvider then Script.register("CSK_PersistentData.OnInitialDataLoaded", handleOnInitialDataLoaded) end +local function resetModule() + if _G.availableAPIs.default and _G.availableAPIs.specific then + for i = 1, #multiRemoteCamera_Instances do + setSelectedInstance(i) + stopCamera() + end + pageCalled() + end +end +Script.serveFunction('CSK_MultiRemoteCamera.resetModule', resetModule) +Script.register("CSK_PersistentData.OnResetAllModules", resetModule) + -- ************************************************* -- END of functions for CSK_PersistentData module usage -- ************************************************* diff --git a/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/MultiRemoteCamera_Model.lua b/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/MultiRemoteCamera_Model.lua index fa5a702..416e30c 100644 --- a/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/MultiRemoteCamera_Model.lua +++ b/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/MultiRemoteCamera_Model.lua @@ -25,6 +25,22 @@ end local multiRemoteCamera = {} multiRemoteCamera.__index = multiRemoteCamera +multiRemoteCamera.styleForUI = 'None' -- Optional parameter to set UI style +multiRemoteCamera.version = Engine.getCurrentAppVersion() -- Version of module + +--************************************************************************** +--********************** End Global Scope ********************************** +--************************************************************************** +--**********************Start Function Scope ******************************* +--************************************************************************** + +--- Function to react on UI style change +local function handleOnStyleChanged(theme) + multiRemoteCamera.styleForUI = theme + Script.notifyEvent("MultiRemoteCamera_OnNewStatusCSKStyle", multiRemoteCamera.styleForUI) +end +Script.register('CSK_PersistentData.OnNewStatusCSKStyle', handleOnStyleChanged) + --- Function to create new instance ---@param cameraNo int Number of instance ---@return table[] self Instance of multiRemoteCamera @@ -48,13 +64,12 @@ function multiRemoteCamera.create(cameraNo) self.parameterLoadOnReboot = false -- Status if parameter dataset should be loaded on app/device reboot self.isConnected = false -- Is camera connected/available - self.activeInUI = false -- Is current camera selected via UI (see "setSelectedCam") + self.activeInUI = false -- Is current camera selected via UI (see "setSelectedInstance") self.digTriggerStatus = false -- digital trigger modus active self.gigEVisionParameterList = '' -- JSON list of available GigE Vision parameters self.gigEVisionCurrentParameter = '' -- current selected GigE Vision parameter self.gigEVisionParameterType = 'Integer' -- type of current selected GigE Vision parameter self.gigEVisionParameterValue = '-' -- Value of current selected GigE Vision parameter - self.triggerFlow = Flow.create() -- Flow to trigger camera via cFlow self.cameraIsPingAble = false -- Status of latest ping check self.scriptIsStarted = false -- Status of processing script startedin own thread @@ -67,7 +82,12 @@ function multiRemoteCamera.create(cameraNo) self.gigEVisionSelectedConfig = nil -- Selected entry of custom GigEVision setting self.gigEVisionConfigUITable = nil -- Content of custom GigEVision setting for UI table + self.customCameraActive = false -- TRUE if camera model == 'CUSTOM' + + self.triggerFunction = nil -- Internally used function to SW trigger the camera + self.parameters = {} + self.parameters.flowConfigPriority = CSK_FlowConfig ~= nil or false -- Status if FlowConfig should have priority for FlowConfig relevant configurations self.parameters.cameraNo = cameraNo -- Instance no of this camera self.parameters.camSum = cameraNo -- Amount of all cameras self.parameters.switchMode = false -- Is camera connected via switch to SIM? @@ -77,11 +97,12 @@ function multiRemoteCamera.create(cameraNo) else self.parameters.gigEvision = false end - self.parameters.cameraIP = '192.168.1.10' .. tostring(cameraNo) -- IP of camera + self.parameters.cameraIP = '192.168.1.10' .. tostring(cameraNo-1) -- IP of camera self.parameters.shutterTime = 20000 -- Shutter time to use self.parameters.gain = 1.0 -- Gain self.parameters.framerate = 1 -- Frame rate in "FIXED_FREQUENCY" mode self.parameters.acquisitionMode = 'SOFTWARE_TRIGGER' -- 'FIXED_FREQUENCY' / 'SOFTWARE_TRIGGER' / 'HARDWARE_TRIGGER' + self.parameters.swTriggerEvent = '' -- Opt. event to trigger camera in SW mode self.parameters.hardwareTriggerDelay = 0 -- Opt. delay for HW trigger self.parameters.triggerDelayBlockName = nil -- Name of specific delay bock within cFlow self.parameters.colorMode = 'MONO8' --'COLOR8' / 'MONO8' / 'RAW8' @@ -92,8 +113,7 @@ function multiRemoteCamera.create(cameraNo) self.parameters.processingFile = 'CSK_MultiRemoteCamera_ImageProcessing' -- Script to use for processing in thread self.parameters.monitorCamera = false -- Opt. monitor camera status in "CameraOverview" UI self.parameters.customGigEVisionConfig = {} -- Custom GigEVision setting, content are 3 tables ".parameter", ".type", ".value" - self.parameters.cameraModel = "PicoMidiCam2" --a2A1920-51gcBAS - + self.parameters.cameraModel = "PicoMidiCam2" -- 'a2A1920-51gcBAS', 'CustomConfig' -- Image processing parameters self.parameters.processingMode = "BOTH" -- 'SCRIPT', 'APP', 'BOTH' --> see "setProcessingMode" @@ -213,7 +233,7 @@ function multiRemoteCamera:connectCamera() end else - _G.logger:info(nameOfModule .. ": Not possible to connect to Camera No. ".. tostring(self.parameters.cameraNo)) + _G.logger:warning(nameOfModule .. ": Not possible to connect to Camera No. ".. tostring(self.parameters.cameraNo)) end CSK_MultiRemoteCamera.pageCalled() end @@ -244,78 +264,87 @@ end --- Function to set new camera config function multiRemoteCamera:setNewConfig() if self.isConnected == true then - _G.logger:info(nameOfModule .. ": Set new config:") + _G.logger:fine(nameOfModule .. ": Set new config:") self.CameraProvider:stop() if self.parameters.gigEvision then self.CameraConfig = Image.Provider.RemoteCamera.GigEVisionConfig.create() - _G.logger:info(nameOfModule .. ": GigEVision Config") - _G.logger:info(nameOfModule .. ": Mode = " .. self.parameters.acquisitionMode) - _G.logger:info(nameOfModule .. ": Camera-Model: " .. self.parameters.cameraModel) - - if self.parameters.cameraModel == "PicoMidiCam2" then - self.CameraConfig:setParameterString("AcquisitionMode", "Continuous") - self.CameraConfig:setParameterString("TriggerSelector", "ExposureStart") - - if self.parameters.acquisitionMode == 'FIXED_FREQUENCY' then - self.CameraConfig:setParameterString("TriggerMode", "Off") - self.CameraConfig:setParameterFloat("AcquisitionFrameRate", self.parameters.framerate) - - elseif self.parameters.acquisitionMode == 'HARDWARE_TRIGGER' then - self.CameraConfig:setParameterString("TriggerMode", "On") - self.CameraConfig:setParameterString("TriggerSource", "Line0") - self.CameraConfig:setParameterString("TriggerActivation", "RisingEdge") + _G.logger:fine(nameOfModule .. ": GigEVision Config") + _G.logger:fine(nameOfModule .. ": Camera-Model: " .. self.parameters.cameraModel) + _G.logger:fine(nameOfModule .. ": Mode = " .. self.parameters.acquisitionMode) + + if self.parameters.cameraModel ~= "CustomConfig" then + self.customCameraActive = false + _G.logger:fine(nameOfModule .. ": Camera-Model: " .. self.parameters.cameraModel) + _G.logger:fine(nameOfModule .. ": Mode = " .. self.parameters.acquisitionMode) + + if self.parameters.cameraModel == "PicoMidiCam2" then + self.CameraConfig:setParameterString("AcquisitionMode", "Continuous") + self.CameraConfig:setParameterString("TriggerSelector", "ExposureStart") + + if self.parameters.acquisitionMode == 'FIXED_FREQUENCY' then + self.CameraConfig:setParameterString("TriggerMode", "Off") + self.CameraConfig:setParameterFloat("AcquisitionFrameRate", self.parameters.framerate) + + elseif self.parameters.acquisitionMode == 'HARDWARE_TRIGGER' then + self.CameraConfig:setParameterString("TriggerMode", "On") + self.CameraConfig:setParameterString("TriggerSource", "Line0") + self.CameraConfig:setParameterString("TriggerActivation", "RisingEdge") + + elseif self.parameters.acquisitionMode == 'SOFTWARE_TRIGGER' and self.parameters.gigEvision then + self.CameraConfig:setParameterString("TriggerSource", "Software") + self.CameraConfig:setParameterString("TriggerMode", "On") + end - elseif self.parameters.acquisitionMode == 'SOFTWARE_TRIGGER' and self.parameters.gigEvision then - self.CameraConfig:setParameterString("TriggerSource", "Software") - self.CameraConfig:setParameterString("TriggerMode", "On") + elseif self.parameters.cameraModel == "a2A1920-51gcBAS" then + self.CameraConfig:setParameterString("AcquisitionMode", "Continuous") + self.CameraConfig:setParameterString("TriggerSelector", "FrameStart") + self.CameraConfig:setParameterString("BslLightSourcePreset", "Daylight5000K") + self.CameraConfig:setParameterString("BalanceWhiteAuto", "Off") + + if self.parameters.acquisitionMode == 'FIXED_FREQUENCY' then + self.CameraConfig:setParameterString("TriggerMode", "Off") + self.CameraConfig:setParameterInteger("AcquisitionFrameRateEnable", 1) + self.CameraConfig:setParameterFloat("AcquisitionFrameRate", + self.parameters.framerate) + + elseif self.parameters.acquisitionMode == 'HARDWARE_TRIGGER' then + self.CameraConfig:setParameterString("TriggerMode", "On") + self.CameraConfig:setParameterString("LineSelector", "Line1") + self.CameraConfig:setParameterString("LineMode", "Input") + self.CameraConfig:setParameterString("TriggerSource", "Line1") + self.CameraConfig:setParameterString("TriggerActivation", "RisingEdge") + + elseif self.parameters.acquisitionMode == 'SOFTWARE_TRIGGER' then + self.CameraConfig:setParameterString("TriggerMode", "On") + self.CameraConfig:setParameterString("TriggerSource", "Software") + end end - elseif self.parameters.cameraModel == "a2A1920-51gcBAS" then - self.CameraConfig:setParameterString("AcquisitionMode", "Continuous") - self.CameraConfig:setParameterString("TriggerSelector", "FrameStart") - self.CameraConfig:setParameterString("BslLightSourcePreset", "Daylight5000K") - self.CameraConfig:setParameterString("BalanceWhiteAuto", "Off") - - if self.parameters.acquisitionMode == 'FIXED_FREQUENCY' then - self.CameraConfig:setParameterString("TriggerMode", "Off") - self.CameraConfig:setParameterInteger("AcquisitionFrameRateEnable", 1) - self.CameraConfig:setParameterFloat("AcquisitionFrameRate", - self.parameters.framerate) - - elseif self.parameters.acquisitionMode == 'HARDWARE_TRIGGER' then - self.CameraConfig:setParameterString("TriggerMode", "On") - self.CameraConfig:setParameterString("LineSelector", "Line1") - self.CameraConfig:setParameterString("LineMode", "Input") - self.CameraConfig:setParameterString("TriggerSource", "Line1") - self.CameraConfig:setParameterString("TriggerActivation", "RisingEdge") - - elseif self.parameters.acquisitionMode == 'SOFTWARE_TRIGGER' then - self.CameraConfig:setParameterString("TriggerMode", "On") - self.CameraConfig:setParameterString("TriggerSource", "Software") - end - end + -- Cameras on single ethernet switch mode + if self.parameters.switchMode then + -- Available network load divided by the amount of connected cameras = value for DeviceLinkThroughputLimit in MBit/s + -- Insert value in byte/s (value for DeviceLinkThroughputLimit divided by 8bit) + if deviceType == "SIM1012" or deviceType == "SIM1004" then + self.CameraConfig:setParameterInteger("DeviceLinkThroughputLimit", 300000000 / self.parameters.camSum / 8) + else + self.CameraConfig:setParameterInteger("DeviceLinkThroughputLimit", 1000000000 / self.parameters.camSum / 8) + end - -- Cameras on single ethernet switch mode - if self.parameters.switchMode then - -- Available network load divided by the amount of connected cameras = value for DeviceLinkThroughputLimit in MBit/s - -- Insert value in byte/s (value for DeviceLinkThroughputLimit divided by 8bit) - if deviceType == "SIM1012" or deviceType == "SIM1004" then - self.CameraConfig:setParameterInteger("DeviceLinkThroughputLimit", 300000000 / self.parameters.camSum / 8) + -- Set this value even if not in switch mode to prevent image errors else - self.CameraConfig:setParameterInteger("DeviceLinkThroughputLimit", 1000000000 / self.parameters.camSum / 8) + if deviceType == "SIM1012" or deviceType == "SIM1004" then + self.CameraConfig:setParameterInteger("DeviceLinkThroughputLimit", 300000000 / 8) + end end - -- Set this value even if not in switch mode to prevent image errors - else - if deviceType == "SIM1012" or deviceType == "SIM1004" then - self.CameraConfig:setParameterInteger("DeviceLinkThroughputLimit", 300000000 / 8) + if deviceType ~= "SIM4000" then + self.CameraConfig:setParameterInteger("[Stream]GevStreamReceiveSocketSize", 4194304) end - end - if deviceType ~= "SIM4000" then - self.CameraConfig:setParameterInteger("[Stream]GevStreamReceiveSocketSize", 4194304) + else + self.customCameraActive = true end -- Custom GigE Vision config @@ -331,38 +360,41 @@ function multiRemoteCamera:setNewConfig() suc = self.CameraConfig:setParameterFloat(self.parameters.customGigEVisionConfig[i].parameter, tonumber(self.parameters.customGigEVisionConfig[i].value)) end - _G.logger:info(nameOfModule .. ": Success of new GigEVision value for parameter " .. self.parameters.customGigEVisionConfig[i].parameter .. ", value = " .. tostring(self.parameters.customGigEVisionConfig[i].value) .. " = " .. tostring(suc)) + _G.logger:fine(nameOfModule .. ": Success of new GigEVision value for parameter " .. self.parameters.customGigEVisionConfig[i].parameter .. ", value = " .. tostring(self.parameters.customGigEVisionConfig[i].value) .. " = " .. tostring(suc)) end end else --No GigEVision Camera self.CameraConfig = Image.Provider.RemoteCamera.I2DConfig.create() - _G.logger:info(nameOfModule .. ": I2D Config") + _G.logger:fine(nameOfModule .. ": I2D Config") if self.parameters.switchMode then self.CameraConfig:setPacketInterval(self.parameters.camSum * 20) end - _G.logger:info(nameOfModule .. ": Mode = " .. self.parameters.acquisitionMode) + _G.logger:fine(nameOfModule .. ": Mode = " .. self.parameters.acquisitionMode) if self.parameters.acquisitionMode == 'FIXED_FREQUENCY' then self.CameraConfig:setFrameRate(self.parameters.framerate) - _G.logger:info(nameOfModule .. ": Framerate = " .. self.parameters.framerate) + _G.logger:fine(nameOfModule .. ": Framerate = " .. self.parameters.framerate) elseif self.parameters.acquisitionMode == 'HARDWARE_TRIGGER' then self.CameraConfig:setHardwareTriggerMode("LO_HI") end self.CameraConfig:setColorMode(self.parameters.colorMode) - _G.logger:info(nameOfModule .. ": ColorMode = " .. self.parameters.colorMode) + _G.logger:fine(nameOfModule .. ": ColorMode = " .. self.parameters.colorMode) self.CameraConfig:setAcquisitionMode(self.parameters.acquisitionMode) end - self.CameraConfig:setShutterTime(self.parameters.shutterTime) - self.CameraConfig:setGainFactor(self.parameters.gain) - self.CameraConfig:setFieldOfView(self.parameters.xStartFOV, self.parameters.xEndFOV, self.parameters.yStartFOV, self.parameters.yEndFOV) + if self.parameters.cameraModel ~= "CustomConfig" then + + self.CameraConfig:setShutterTime(self.parameters.shutterTime) + self.CameraConfig:setGainFactor(self.parameters.gain) + self.CameraConfig:setFieldOfView(self.parameters.xStartFOV, self.parameters.xEndFOV, self.parameters.yStartFOV, self.parameters.yEndFOV) - _G.logger:info(nameOfModule .. ": Shutter time = " .. tostring(self.parameters.shutterTime)) - _G.logger:info(nameOfModule .. ": Gain = " .. tostring(self.parameters.gain)) + _G.logger:fine(nameOfModule .. ": Shutter time = " .. tostring(self.parameters.shutterTime)) + _G.logger:fine(nameOfModule .. ": Gain = " .. tostring(self.parameters.gain)) + end local configSuc = self.CameraProvider:setConfig(self.CameraConfig) if configSuc then @@ -381,7 +413,7 @@ function multiRemoteCamera:setNewConfig() end else - _G.logger:info(nameOfModule .. ": Did not set new config to camera No. " .. tostring(self.parameters.cameraNo) .. ", because no camera is connected.") + _G.logger:warning(nameOfModule .. ": Did not set new config to camera No. " .. tostring(self.parameters.cameraNo) .. ", because no camera is connected.") end end diff --git a/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/helper/checkAPIs.lua b/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/helper/checkAPIs.lua index 2244c07..7505d5f 100644 --- a/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/helper/checkAPIs.lua +++ b/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/helper/checkAPIs.lua @@ -5,23 +5,21 @@ local availableAPIs = {} +-- Function to load all default APIs local function loadAPIs() CSK_MultiRemoteCamera = require 'API.CSK_MultiRemoteCamera' + Log = require 'API.Log' + Log.Handler = require 'API.Log.Handler' + Log.SharedLogger = require 'API.Log.SharedLogger' + Container = require 'API.Container' DateTime = require 'API.DateTime' Engine = require 'API.Engine' - Ethernet = require 'API.Ethernet' File = require 'API.File' - Flow = require 'API.Flow' - Image = require 'API.Image' - Log = require 'API.Log' - Log.Handler = require 'API.Log.Handler' - Log.SharedLogger = require 'API.Log.SharedLogger' Object = require 'API.Object' Timer = require 'API.Timer' - View = require 'API.View' -- Check if related CSK modules are available to be used local appList = Engine.listApps() @@ -30,20 +28,30 @@ local function loadAPIs() CSK_PersistentData = require 'API.CSK_PersistentData' elseif appList[i] == 'CSK_Module_UserManagement' then CSK_UserManagement = require 'API.CSK_UserManagement' + elseif appList[i] == 'CSK_Module_FlowConfig' then + CSK_FlowConfig = require 'API.CSK_FlowConfig' end end end +-- Function to load specific APIs local function loadSpecificAPIs() -- If you want to check for specific APIs/functions supported on the device the module is running, place relevant APIs here + Image = require 'API.Image' Image.Provider = {} Image.Provider.RemoteCamera = require 'API.Image.Provider.RemoteCamera' + Ethernet = require 'API.Ethernet' + Flow = require 'API.Flow' + Image = require 'API.Image' + View = require 'API.View' end +-- Function to load specific I2D APIs local function loadI2DSpecificAPIs() Image.Provider.RemoteCamera.I2DConfig = require 'API.Image.Provider.RemoteCamera.I2DConfig' end +-- Function to load specific GigE Vision APIs local function loadGigEVisionSpecificAPIs() Image.Provider.RemoteCamera.GigEVisionConfig = require 'API.Image.Provider.RemoteCamera.GigEVisionConfig' end diff --git a/README.md b/README.md index 3d3d5e3..95ebed8 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ Module to setup a single or multiple camera(s) connected to a SIM or SAE. -![](https://github.com/SICKAppSpaceCodingStarterKit/CSK_Module_MultiRemoteCamera/blob/main/docu/media/UI_Screenshot_Main.png) +![](./docu/media/UI_Screenshot_Main.png) -![](https://github.com/SICKAppSpaceCodingStarterKit/CSK_Module_MultiRemoteCamera/blob/main/docu/media/UI_Screenshot_GigEVision.png) +![](./docu/media/UI_Screenshot_GigEVision.png) ## How to Run @@ -16,10 +16,14 @@ For further information check out the [documentation](https://raw.githack.com/SI Tested on -1. SIM1012 - Firmware 2.2.0 -2. SIM2500 - Firmware 1.3.0 -3. SIM4000 - Firmware 1.10.2 -4. SICK AppEngine - Firmware 1.3.2 +|Device|Firmware|Module version +|--|--|--| +|SIM1012|V2.4.2|V6.0.0| +|SIM1012|V2.2.0| -Documentation - CSK_Module_MultiRemoteCamera 5.0.0 +Documentation - CSK_Module_MultiRemoteCamera 6.0.0