diff --git a/CHANGELOG.md b/CHANGELOG.md index b1322c1..fbce9aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,18 @@ # Changelog All notable changes to this project will be documented in this file. +## Release 6.3.0 + +### New features +- Set delay to wait before trying to download latest image from SEC camera (see setSEC100SnapshotDelay) +- Set status if images of SEC camera should be processed internally. Deactivate to save processing time (see setSEC100InternalImageProcessing) +- Provide image binary string via event (see OnNewRawImageCameraNUM) + +### Improvements +- Better handling of SEC images (CSK_Module_MultiHTTPClient version 2.3.0 needed) +- Provide SEC features on devices without image processing +- Improved connection check to SEC camera + ## Release 6.2.0 ### New features 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 98e4f8c..8de7349 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 @@ -291,10 +291,10 @@

- - + + @@ -1558,6 +1558,37 @@

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CSK_Module_MultiRemoteCamera/project.mf.xml b/CSK_Module_MultiRemoteCamera/project.mf.xml index 11dc766..ec824e3 100644 --- a/CSK_Module_MultiRemoteCamera/project.mf.xml +++ b/CSK_Module_MultiRemoteCamera/project.mf.xml @@ -52,6 +52,11 @@ There is also the possibility to edit GigE Vision camera parameters (check also jpg png + + Mode of image. + IMAGE + BINARY + Notify gain of currently selected camera instance. @@ -371,6 +376,23 @@ INFO: Other modules can check via "Script.isServedAsEvent" if event of sepecific Notfiy interface of HTTP client to use for SEC connection. + + released + Example of dynamically created event to transfer incoming raw images of SEC cameras. + +This event is only used if the internal image processing for these raw images is inactive (see 'setSEC100InternalImageProcessing'). + +NUM will be replaced by the number of instance (e.g. "OnNewRawImageCamera1"). + +INFO: Other modules can check via "Script.isServedAsEvent" if event of sepecific instance exists. + + + + + Notify time to wait after SEC snapshot to download the image. + + + + Notify status if SEC raw images should be converted for internal image processing (TRUE) or if only raw images will be forwarrded without conversion to reduce processing time (FALSE). + + Function to register "OnResume" of the module UI (only as helper function). @@ -680,6 +702,14 @@ According to the selected model it will use some predefined GigE Vision paramete Function to set interface of HTTP client to use for SEC100 connection. + + Function to set delay to wait after SEC trigger to download the latest snapshot from the SEC. + + + + Function to set status if received raw images of SEC camera should be converted for internal image processing. Set to FALSE to reduce processing time if raw images should only be forwarded. + + @@ -694,12 +724,13 @@ According to the selected model it will use some predefined GigE Vision paramete data-flow Provide image acquired by camera. - + released Internally used CSK_FlowConfig create function. + @@ -714,7 +745,7 @@ According to the selected model it will use some predefined GigE Vision paramete SICK AG - 6.2.0 + 6.3.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 6e811da..96c93da 100644 --- a/CSK_Module_MultiRemoteCamera/scripts/CSK_Module_MultiRemoteCamera.lua +++ b/CSK_Module_MultiRemoteCamera/scripts/CSK_Module_MultiRemoteCamera.lua @@ -66,9 +66,11 @@ local multiRemoteCameras_Instances = {} -- Handle all instances local multiRemoteCameraController = require('Sensors/MultiRemoteCamera/MultiRemoteCamera_Controller') -- Check if specific APIs are available on device -if _G.availableAPIs.default and _G.availableAPIs.imageProvider then - _G.logger:info("I2D Support = " .. tostring(_G.availableAPIs.I2D) .. ", GigEVision support = " .. tostring(_G.availableAPIs.GigEVision)) - require('Sensors/MultiRemoteCamera/FlowConfig/MultiRemoteCamera_FlowConfig') +if _G.availableAPIs.default then + _G.logger:info("I2D Support = " .. tostring(_G.availableAPIs.I2D) .. ", GigEVision support = " .. tostring(_G.availableAPIs.GigEVision) .. ", SEC support = " .. tostring(_G.availableAPIs.SEC100)) + if _G.availableAPIs.flow then + require('Sensors/MultiRemoteCamera/FlowConfig/MultiRemoteCamera_FlowConfig') + end table.insert(multiRemoteCameras_Instances, multiRemoteCamera_Model.create(1)) -- create(cameraNo:int) multiRemoteCameraController.setMultiRemoteCamera_Instances_Handle(multiRemoteCameras_Instances) -- share handle of instances else diff --git a/CSK_Module_MultiRemoteCamera/scripts/CSK_MultiRemoteCamera_ImageProcessing.lua b/CSK_Module_MultiRemoteCamera/scripts/CSK_MultiRemoteCamera_ImageProcessing.lua index 940b1a7..0166706 100644 --- a/CSK_Module_MultiRemoteCamera/scripts/CSK_MultiRemoteCamera_ImageProcessing.lua +++ b/CSK_Module_MultiRemoteCamera/scripts/CSK_MultiRemoteCamera_ImageProcessing.lua @@ -42,17 +42,35 @@ imageProcessingParams.secUser = scriptParams:get('secUser') imageProcessingParams.secUserPassword = scriptParams:get('secUserPassword') imageProcessingParams.secMode = scriptParams:get('secMode') imageProcessingParams.secWebSocketClientInstance = scriptParams:get('secWebSocketClientInstance') +imageProcessingParams.secSnapshotDelay = scriptParams:get('secSnapshotDelay') +imageProcessingParams.secInternalImageProcessing = scriptParams:get('secInternalImageProcessing') imageProcessingParams.activeInUI = false -- Is this instance currently selected in UI imageProcessingParams.viewerActive = false -- Should the image be shown in viewer -local viewer = View.create(viewerId) -- Viewer to show image +local viewer +if availableAPIs.imageProvider then + viewer = View.create(viewerId) -- Viewer to show image +end local imageQueue = Script.Queue.create() -- Queue to stop processing if increasing too much -local jpeg = Image.Format.JPEG.create() -- Image decoder for SEC100 images +local jpeg + +if availableAPIs.imageProcessing then + jpeg = Image.Format.JPEG.create() -- Image decoder for SEC100 images +end + +local latestChallengeResponse = nil -- Latest challenge response of SEC camera + +local tmrLatestSnapshot = Timer.create() +tmrLatestSnapshot:setExpirationTime(imageProcessingParams.secSnapshotDelay) +tmrLatestSnapshot:setPeriodic(false) -- Event to forward image to other modules Script.serveEvent("CSK_MultiRemoteCamera.OnNewImageCamera" .. cameraNumberString, "MultiRemoteCamera_OnNewImageCamera" .. cameraNumberString, 'object:1:Image, int:?') +-- Event to forward RAW image (binary string) to other modules +Script.serveEvent("CSK_MultiRemoteCamera.OnNewRawImageCamera" .. cameraNumberString, "MultiRemoteCamera_OnNewRawImageCamera" .. cameraNumberString, 'string:1, int:?') + -- Event to forward updated values e.g. through Controller to UI Script.serveEvent("CSK_MultiRemoteCamera.OnNewValueToForward" .. cameraNumberString, "MultiRemoteCamera_OnNewValueToForward" .. cameraNumberString, 'string:1, auto:1') @@ -153,8 +171,10 @@ local function handleOnNewImageProcessing(image, sensorData) if imageProcessingParams.mode == 'SCRIPT' or imageProcessingParams.mode == 'BOTH' then -- OPTION A --> Using image locally in this script if imageProcessingParams.activeInUI == true and imageProcessingParams.viewerActive == true then - viewer:addImage(resImage) - viewer:present() + if availableAPIs.imageProvider then + viewer:addImage(resImage) + viewer:present() + end end end @@ -228,56 +248,92 @@ local function computeResponseHash(challenge, action, user, password) return buildDigest({ha1, nonce, ha2}) end + +-- Function to get new SEC challenge +local function getSECChallenge() + local _, _, challengeResponse = Script.callFunction('CSK_MultiHTTPClient.sendRequest' .. tostring(imageProcessingParams.httpClientInstance), 'POST', 'http://' .. secIP .. '/api/getChallenge', 80, nil, '{"data":{"user": "' .. imageProcessingParams.secUser .. '"}}', 'application/json', false) + latestChallengeResponse = json.decode(challengeResponse:getContent()) +end + +-- Function to create request body for SEC +local function getRequestBody(command, data) + local responseHash = computeResponseHash(latestChallengeResponse.challenge, command, imageProcessingParams.secUser, imageProcessingParams.secUserPassword) + local requestBody + + if data then + requestBody = '{"header":{"user":"' .. imageProcessingParams.secUser .. '","response":"' .. responseHash .. '","realm":"SICK Sensor","opaque":"' .. latestChallengeResponse.challenge.opaque .. '","nonce":"' .. latestChallengeResponse.challenge.nonce .. '"},' .. data .. '}' + else + requestBody = '{"header":{"user":"' .. imageProcessingParams.secUser .. '","response":"' .. responseHash .. '","realm":"SICK Sensor","opaque":"' .. latestChallengeResponse.challenge.opaque .. '","nonce":"' .. latestChallengeResponse.challenge.nonce .. '"}}' + end + return requestBody +end + --- Function to trigger SEC camera ---@param command string Command to send to SEC camera ---@param data string Data for command ---@return bool suc Success of trigger local function triggerSEC(command, data) - local _, challengeResponse = Script.callFunction('CSK_MultiHTTPClient.sendRequest' .. tostring(imageProcessingParams.httpClientInstance), 'POST', 'http://' .. secIP .. '/api/getChallenge', 80, nil, '{"data":{"user": "' .. imageProcessingParams.secUser .. '"}}', 'application/json') - local challengeResponseContent = json.decode(challengeResponse) - if challengeResponseContent.Response then + if latestChallengeResponse == nil then + getSECChallenge() + end - local response = json.decode(challengeResponseContent.Response) + if latestChallengeResponse.challenge then + local requestBody = getRequestBody(command, data) + local requestResponse - if response.challenge then - local responseHash = computeResponseHash(response.challenge, command, imageProcessingParams.secUser, imageProcessingParams.secUserPassword) - local requestBody + if command == 'latestSnapshot' then + _, _, requestResponse = Script.callFunction('CSK_MultiHTTPClient.sendRequest' .. tostring(imageProcessingParams.httpClientInstance), 'POST', 'http://' .. secIP .. '/file/download/' .. command, 80, nil, requestBody, 'image/jpeg', false) - if data then - requestBody = '{"header":{"user":"' .. imageProcessingParams.secUser .. '","response":"' .. responseHash .. '","realm":"SICK Sensor","opaque":"' .. response.challenge.opaque .. '","nonce":"' .. response.challenge.nonce .. '"},' .. data .. '}' - else - requestBody = '{"header":{"user":"' .. imageProcessingParams.secUser .. '","response":"' .. responseHash .. '","realm":"SICK Sensor","opaque":"' .. response.challenge.opaque .. '","nonce":"' .. response.challenge.nonce .. '"}}' + if requestResponse:getStatusCode() ~= 200 then + _G.logger:info(nameOfModule .. ": Did not work. Try again with new challenge.") + getSECChallenge() + requestBody = getRequestBody(command, data) + _, _, requestResponse = Script.callFunction('CSK_MultiHTTPClient.sendRequest' .. tostring(imageProcessingParams.httpClientInstance), 'POST', 'http://' .. secIP .. '/file/download/' .. command, 80, nil, requestBody, 'image/jpeg', false) end - local requestResponse - local responseData - if command == 'latestSnapshot' then - _, requestResponse = Script.callFunction('CSK_MultiHTTPClient.sendRequest' .. tostring(imageProcessingParams.httpClientInstance), 'POST', 'http://' .. secIP .. '/file/download/' .. command, 80, nil, requestBody, 'image/jpeg') - responseData = json.decode(requestResponse) - if responseData.StatusCode == 200 then - local img = jpeg:decode(responseData.Response) + if requestResponse:getStatusCode() == 200 then + local imageContent = requestResponse:getContent() + if availableAPIs.imageProcessing and imageProcessingParams.secInternalImageProcessing then + local img = jpeg:decode(imageContent) handleOnNewImageProcessing(img) - return true else - _G.logger:warning(nameOfModule .. ": Request did not work.") - return false + Script.notifyEvent('MultiRemoteCamera_OnNewRawImageCamera' .. cameraNumberString, imageContent, DateTime.getTimestamp()) end + return true else - _, requestResponse = Script.callFunction('CSK_MultiHTTPClient.sendRequest' .. tostring(imageProcessingParams.httpClientInstance), 'POST', 'http://' .. secIP .. '/api/' .. command, 80, nil, requestBody, 'application/json') - responseData = json.decode(requestResponse) - if responseData.StatusCode ~= 200 then + _G.logger:warning(nameOfModule .. ": Request did not work.") + return false + end + else + _, _, requestResponse = Script.callFunction('CSK_MultiHTTPClient.sendRequest' .. tostring(imageProcessingParams.httpClientInstance), 'POST', 'http://' .. secIP .. '/api/' .. command, 80, nil, requestBody, 'application/json', false) + + local wrongPasword = nil + if command == 'SnapshotMode' then + wrongPasword = string.find(requestResponse:getContent(), 'Access Denied') + end + + if wrongPasword ~= nil then + _G.logger:warning(nameOfModule .. ": No connection to SEC (due to wrong password?).") + latestChallengeResponse = nil + return false + else + if requestResponse:getStatusCode() ~= 200 then + _G.logger:info(nameOfModule .. ": Did not work. Try again with new challenge.") + getSECChallenge() + _, _, requestResponse = Script.callFunction('CSK_MultiHTTPClient.sendRequest' .. tostring(imageProcessingParams.httpClientInstance), 'POST', 'http://' .. secIP .. '/api/' .. command, 80, nil, requestBody, 'application/json', false) + end + + if requestResponse:getStatusCode() ~= 200 then _G.logger:warning(nameOfModule .. ": Request did not work.") return false else return true end end - else - _G.logger:warning(nameOfModule .. ": Request challenge did not work.") - return false end else + _G.logger:warning(nameOfModule .. ": Request challenge did not work.") return false end end @@ -287,8 +343,12 @@ end ---@param format enum Message format. local function unpackBinaryImage(data, format) if format == 'BINARY' then - local img = jpeg:decode(data) - handleOnNewImageProcessing(img) + if availableAPIs.imageProcessing and imageProcessingParams.secInternalImageProcessing then + local img = jpeg:decode(data) + handleOnNewImageProcessing(img) + elseif not imageProcessingParams.secInternalImageProcessing then + Script.notifyEvent('MultiRemoteCamera_OnNewRawImageCamera' .. cameraNumberString, data, DateTime.getTimestamp()) + end end end queue:setFunction(unpackBinaryImage) @@ -297,6 +357,12 @@ queue:setFunction(unpackBinaryImage) --################ SEC100 END ################# --############################################# +-- Function to get latest snapshot after timer expired +local function getLatestSnapshot() + triggerSEC('latestSnapshot') +end +Timer.register(tmrLatestSnapshot, 'OnExpired', getLatestSnapshot) + --- Function to handle updates of processing parameters from Controller ---@param cameraNo int Number of camera instance to update ---@param parameter string Parameter to update @@ -305,8 +371,10 @@ local function handleOnNewImageProcessingParameter(cameraNo, parameter, value) if parameter == 'viewerActive' then imageProcessingParams[parameter] = value if value == false then - viewer:clear() - viewer:present() + if availableAPIs.imageProvider then + viewer:clear() + viewer:present() + end end elseif cameraNo == cameraNumber then if parameter == 'saveLastImage' then @@ -340,18 +408,22 @@ local function handleOnNewImageProcessingParameter(cameraNo, parameter, value) end elseif parameter == 'SEC100_Trigger' then triggerSEC('SnapshotTriggerSnapshot') - Script.sleep(200) - triggerSEC('latestSnapshot') + tmrLatestSnapshot:start() else if not parameter == 'activeInUI' then _G.logger:fine(nameOfModule .. ": Update parameter '" .. parameter .. "' of cameraNo." .. tostring(cameraNo) .. " to value = " .. tostring(value)) end imageProcessingParams[parameter] = value + if parameter == 'secSnapshotDelay' then + tmrLatestSnapshot:setExpirationTime(value) + end end elseif parameter == 'activeInUI' then imageProcessingParams[parameter] = false - viewer:clear() - viewer:present() + if availableAPIs.imageProvider then + viewer:clear() + viewer:present() + end end end Script.register("CSK_MultiRemoteCamera.OnNewImageProcessingParameter", handleOnNewImageProcessingParameter) diff --git a/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/FlowConfig/MultiRemoteCamera_OnNewImage.lua b/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/FlowConfig/MultiRemoteCamera_OnNewImage.lua index 87ee8be..f3b2447 100644 --- a/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/FlowConfig/MultiRemoteCamera_OnNewImage.lua +++ b/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/FlowConfig/MultiRemoteCamera_OnNewImage.lua @@ -32,6 +32,7 @@ local function register(handle, _ , callback) Container.add(handle, "CB_Function", callback) local instance = Container.get(handle, 'Instance') + local imageMode = Container.get(handle, 'ImageMode') -- Check if amount of instances is valid -- if not: add multiple additional instances @@ -46,7 +47,11 @@ local function register(handle, _ , callback) local function localCallback() if callback ~= nil then - Script.callFunction(callback, 'CSK_MultiRemoteCamera.OnNewImageCamera' .. tostring(instance)) + if imageMode == 'BINARY' then + Script.callFunction(callback, 'CSK_MultiRemoteCamera.OnNewRawImageCamera' .. tostring(instance)) + else + Script.callFunction(callback, 'CSK_MultiRemoteCamera.OnNewImageCamera' .. tostring(instance)) + end else _G.logger:warning(nameOfModule .. ": " .. BLOCK_NAMESPACE .. ".CB_Function missing!") end @@ -62,7 +67,7 @@ Script.serveFunction(BLOCK_NAMESPACE ..".register", register) --************************************************************* --************************************************************* -local function create(instance) +local function create(instance, imageMode) -- Check if same instance is already configured if instance < 1 or nil ~= instanceTable[instance] then @@ -73,6 +78,7 @@ local function create(instance) local handle = Container.create() instanceTable[instance] = instance Container.add(handle, 'Instance', instance) + Container.add(handle, 'ImageMode', imageMode or 'Image') Container.add(handle, "CB_Function", "") return handle end diff --git a/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/MultiRemoteCamera_Controller.lua b/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/MultiRemoteCamera_Controller.lua index d5b7c10..3322559 100644 --- a/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/MultiRemoteCamera_Controller.lua +++ b/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/MultiRemoteCamera_Controller.lua @@ -109,6 +109,8 @@ Script.serveEvent('CSK_MultiRemoteCamera.OnNewPasswordSEC', 'MultiRemoteCamera_O Script.serveEvent('CSK_MultiRemoteCamera.OnNewStatusSECMode', 'MultiRemoteCamera_OnNewStatusSECMode') Script.serveEvent('CSK_MultiRemoteCamera.OnNewWebSocketClientInstance', 'MultiRemoteCamera_OnNewWebSocketClientInstance') Script.serveEvent('CSK_MultiRemoteCamera.OnNewStatusSECStreamIsActive', 'MultiRemoteCamera_OnNewStatusSECStreamIsActive') +Script.serveEvent('CSK_MultiRemoteCamera.OnNewStatusSECSnapshotDelay', 'MultiRemoteCamera_OnNewStatusSECSnapshotDelay') +Script.serveEvent('CSK_MultiRemoteCamera.OnNewStatusSECInternalImageProcessing', 'MultiRemoteCamera_OnNewStatusSECInternalImageProcessing') Script.serveEvent('CSK_MultiRemoteCamera.OnNewStatusFlowConfigPriority', 'MultiRemoteCamera_OnNewStatusFlowConfigPriority') Script.serveEvent("CSK_MultiRemoteCamera.OnNewStatusLoadParameterOnReboot", "MultiRemoteCamera_OnNewStatusLoadParameterOnReboot") @@ -299,9 +301,9 @@ local function handleOnExpiredTmrCamera() Script.notifyEvent("MultiRemoteCamera_OnNewStatusModuleVersion", 'v' .. multiRemoteCamera_Model.version) Script.notifyEvent("MultiRemoteCamera_OnNewStatusCSKStyle", multiRemoteCamera_Model.styleForUI) - Script.notifyEvent("MultiRemoteCamera_OnNewStatusModuleIsActive", _G.availableAPIs.default and _G.availableAPIs.imageProvider) + Script.notifyEvent("MultiRemoteCamera_OnNewStatusModuleIsActive", _G.availableAPIs.default and (_G.availableAPIs.imageProvider or _G.availableAPIs.SEC100)) - if _G.availableAPIs.default and _G.availableAPIs.imageProvider then + if _G.availableAPIs.default and (_G.availableAPIs.imageProvider or _G.availableAPIs.SEC100) then updateUserLevel() @@ -343,6 +345,8 @@ local function handleOnExpiredTmrCamera() Script.notifyEvent('MultiRemoteCamera_OnNewStatusSECMode', multiRemoteCamera_Instances[selectedInstance].parameters.secMode) Script.notifyEvent('MultiRemoteCamera_OnNewWebSocketClientInstance', multiRemoteCamera_Instances[selectedInstance].parameters.secWebSocketClientInstance) Script.notifyEvent('MultiRemoteCamera_OnNewStatusSECStreamIsActive', multiRemoteCamera_Instances[selectedInstance].secWebSocketStreamIsActive) + Script.notifyEvent('MultiRemoteCamera_OnNewStatusSECSnapshotDelay', multiRemoteCamera_Instances[selectedInstance].parameters.secSnapshotDelay) + Script.notifyEvent('MultiRemoteCamera_OnNewStatusSECInternalImageProcessing', multiRemoteCamera_Instances[selectedInstance].parameters.secInternalImageProcessing) Script.notifyEvent('MultiRemoteCamera_OnNewShutterTime', multiRemoteCamera_Instances[selectedInstance].parameters.shutterTime) Script.notifyEvent('MultiRemoteCamera_OnNewGain', multiRemoteCamera_Instances[selectedInstance].parameters.gain) @@ -402,7 +406,7 @@ end Timer.register(tmrMonitorCameras, "OnExpired", handleOnExpiredTmrMonitorCameras) local function pageCalled() - if _G.availableAPIs.default and _G.availableAPIs.imageProvider then + if _G.availableAPIs.default and (_G.availableAPIs.imageProvider or _G.availableAPIs.SEC100) then updateUserLevel() -- try to hide user specific content asap end tmrCamera:start() @@ -520,15 +524,20 @@ local function setCameraModel (camModel) end else if camModel == 'PicoMidiCam' then - setGigEVision(false) - if multiRemoteCamera_Instances[selectedInstance].parameters.gigEvision == false then - multiRemoteCamera_Instances[selectedInstance].parameters.cameraModel = camModel + if _G.availableAPIs.I2D then + setGigEVision(false) + if multiRemoteCamera_Instances[selectedInstance].parameters.gigEvision == false then + multiRemoteCamera_Instances[selectedInstance].parameters.cameraModel = camModel + else + _G.logger:warning(nameOfModule .. ": Features of camera model '" .. camModel .. "'' not available.") + end + Script.notifyEvent('MultiRemoteCamera_OnNewCameraModel', multiRemoteCamera_Instances[selectedInstance].parameters.cameraModel) + multiRemoteCamera_Instances[selectedInstance].customCameraActive = false + multiRemoteCamera_Instances[selectedInstance].cameraParameters = 'Others' else - _G.logger:warning(nameOfModule .. ": Features of camera model '" .. camModel .. "'' not available.") + _G.logger:warning(nameOfModule .. ": Pico/MidiCam features not available.") + Script.notifyEvent('MultiRemoteCamera_OnNewCameraModel', multiRemoteCamera_Instances[selectedInstance].parameters.cameraModel) end - Script.notifyEvent('MultiRemoteCamera_OnNewCameraModel', multiRemoteCamera_Instances[selectedInstance].parameters.cameraModel) - multiRemoteCamera_Instances[selectedInstance].customCameraActive = false - multiRemoteCamera_Instances[selectedInstance].cameraParameters = 'Others' else setGigEVision(true) if multiRemoteCamera_Instances[selectedInstance].parameters.gigEvision == true then @@ -592,6 +601,20 @@ local function setSEC100UserPassword(password) end Script.serveFunction('CSK_MultiRemoteCamera.setSEC100UserPassword', setSEC100UserPassword) +local function setSEC100SnapshotDelay(delay) + _G.logger:fine(nameOfModule .. ": Set delay to download latest snapshot to " .. tostring(delay)) + multiRemoteCamera_Instances[selectedInstance].parameters.secSnapshotDelay = delay + Script.notifyEvent('MultiRemoteCamera_OnNewImageProcessingParameter', selectedInstance, 'secSnapshotDelay', delay) +end +Script.serveFunction('CSK_MultiRemoteCamera.setSEC100SnapshotDelay', setSEC100SnapshotDelay) + +local function setSEC100InternalImageProcessing(status) + _G.logger:fine(nameOfModule .. ": Set status to only forward SEC raw images to " .. tostring(status)) + multiRemoteCamera_Instances[selectedInstance].parameters.secInternalImageProcessing = status + Script.notifyEvent('MultiRemoteCamera_OnNewImageProcessingParameter', selectedInstance, 'secInternalImageProcessing', status) +end +Script.serveFunction('CSK_MultiRemoteCamera.setSEC100InternalImageProcessing', setSEC100InternalImageProcessing) + local function connectCamera() -- Try to connect the camera _G.logger:info(nameOfModule .. ": Try to connect to camera no. " .. tostring(selectedInstance)) @@ -749,8 +772,10 @@ local function setSECMode(mode) Script.notifyEvent('MultiRemoteCamera_OnNewStatusSECMode', multiRemoteCamera_Instances[selectedInstance].parameters.secMode) Script.notifyEvent('MultiRemoteCamera_OnNewStatusSECStreamIsActive', multiRemoteCamera_Instances[selectedInstance].secWebSocketStreamIsActive) elseif mode == 'Snapshot' then + setSECStreamStatus(false) multiRemoteCamera_Instances[selectedInstance].parameters.secMode = mode Script.notifyEvent('MultiRemoteCamera_OnNewStatusSECMode', multiRemoteCamera_Instances[selectedInstance].parameters.secMode) + Script.notifyEvent('MultiRemoteCamera_OnNewStatusSECSnapshotDelay', multiRemoteCamera_Instances[selectedInstance].parameters.secSnapshotDelay) CSK_MultiWebSocketClient.setConnectionStatus(false) end Script.notifyEvent('MultiRemoteCamera_OnNewImageProcessingParameter', selectedInstance, 'secMode', multiRemoteCamera_Instances[selectedInstance].parameters.secMode) @@ -980,9 +1005,14 @@ end Script.serveFunction("CSK_MultiRemoteCamera.setTempImageActive", setTempImageActive) local function setViewerActive(status) - _G.logger:fine(nameOfModule .. ": Viewer active: " .. tostring(status)) - viewerActive = status - Script.notifyEvent('MultiRemoteCamera_OnNewImageProcessingParameter', selectedInstance, 'viewerActive', viewerActive) + if _G.availableAPIs.imageProvider then + _G.logger:fine(nameOfModule .. ": Viewer active: " .. tostring(status)) + viewerActive = status + Script.notifyEvent('MultiRemoteCamera_OnNewImageProcessingParameter', selectedInstance, 'viewerActive', viewerActive) + else + _G.logger:info(nameOfModule .. ": Viewer not supported.") + Script.notifyEvent('MultiRemoteCamera_OnNewStatusViewerActive', false) + end end Script.serveFunction("CSK_MultiRemoteCamera.setViewerActive", setViewerActive) @@ -1126,7 +1156,7 @@ end Script.serveFunction('CSK_MultiRemoteCamera.restartAllCameras', restartAllCameras) local function getStatusModuleActive() - return _G.availableAPIs.default and _G.availableAPIs.imageProvider + return _G.availableAPIs.default and (_G.availableAPIs.imageProvider or _G.availableAPIs.SEC100) end Script.serveFunction('CSK_MultiRemoteCamera.getStatusModuleActive', getStatusModuleActive) @@ -1262,7 +1292,7 @@ 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 + if _G.availableAPIs.default and (_G.availableAPIs.imageProvider or _G.availableAPIs.SEC100) then _G.logger:fine(nameOfModule .. ': Try to initially load parameter from CSK_PersistentData module.') -- Check if CSK_PersistentData version is > 1.x.x @@ -1320,12 +1350,12 @@ local function handleOnInitialDataLoaded() end end end -if _G.availableAPIs.default and _G.availableAPIs.imageProvider then +if _G.availableAPIs.default and (_G.availableAPIs.imageProvider or _G.availableAPIs.SEC100) then Script.register("CSK_PersistentData.OnInitialDataLoaded", handleOnInitialDataLoaded) end local function resetModule() - if _G.availableAPIs.default and _G.availableAPIs.specific then + if _G.availableAPIs.default and (_G.availableAPIs.imageProvider or _G.availableAPIs.SEC100) then for i = 1, #multiRemoteCamera_Instances do setSelectedInstance(i) stopCamera() diff --git a/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/MultiRemoteCamera_Model.lua b/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/MultiRemoteCamera_Model.lua index 2e0ae90..cd084e2 100644 --- a/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/MultiRemoteCamera_Model.lua +++ b/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/MultiRemoteCamera_Model.lua @@ -36,7 +36,7 @@ for i = 1, 10 do table.insert(multiRemoteCamera.swTriggerFunctions, triggerCamera) end -if _G.availableAPIs.imageProvider then +if _G.availableAPIs.ethernet then multiRemoteCamera.interfaces = Ethernet.Interface.getInterfaces() table.insert(multiRemoteCamera.interfaces, 'Localhost') end @@ -96,7 +96,11 @@ function multiRemoteCamera.create(cameraNo) self.gigEVisionConfigUITable = nil -- Content of custom GigEVision setting for UI table self.customCameraActive = false -- TRUE if camera model == 'CUSTOM' - self.cameraParameters = 'Others' -- Type of camera parameters to show in UI + if _G.availableAPIs.imageProvider and (_G.availableAPIs.I2D or _G.availableAPIs.GigEVision) then + self.cameraParameters = 'Others' -- Type of camera parameters to show in styleForUI + elseif _G.availableAPIs.SEC100 then + self.cameraParameters = 'SEC100' + end self.triggerFunction = nil -- Internally used function to SW trigger the camera @@ -132,6 +136,8 @@ function multiRemoteCamera.create(cameraNo) self.imageProcessingParams:add('secUserPassword', self.parameters.secUserPassword, "STRING") self.imageProcessingParams:add('secMode', self.parameters.secMode, "STRING") self.imageProcessingParams:add('secWebSocketClientInstance', self.parameters.secWebSocketClientInstance, "INT") + self.imageProcessingParams:add('secSnapshotDelay', self.parameters.secSnapshotDelay, "INT") + self.imageProcessingParams:add('secInternalImageProcessing', self.parameters.secInternalImageProcessing, "BOOL") return self end @@ -233,6 +239,8 @@ function multiRemoteCamera:connectCamera() else _G.logger:warning(nameOfModule .. ": Not possible to connect to Camera No. ".. tostring(self.parameters.cameraNo)) end + Script.notifyEvent('MultiRemoteCamera_OnCameraConnected', self.isConnected) + _G.logger:info(nameOfModule .. ': Connection to camera = ' .. tostring(self.isConnected)) else local instanceAmount = CSK_MultiHTTPClient.getInstancesAmount() if instanceAmount >= self.parameters.httpClientInstance then @@ -250,10 +258,7 @@ function multiRemoteCamera:connectCamera() end end - Script.notifyEvent('MultiRemoteCamera_OnCameraConnected', self.isConnected) - _G.logger:info(nameOfModule .. ': Connection to camera = ' .. tostring(self.isConnected)) Script.notifyEvent("MultiRemoteCamera_OnScanCamera", false) - CSK_MultiRemoteCamera.pageCalled() end diff --git a/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/MultiRemoteCamera_Parameters.lua b/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/MultiRemoteCamera_Parameters.lua index 3a6c608..982911f 100644 --- a/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/MultiRemoteCamera_Parameters.lua +++ b/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/MultiRemoteCamera_Parameters.lua @@ -38,10 +38,18 @@ local function getParameters() multiRemoteCameraParameters.processingFile = 'CSK_MultiRemoteCamera_ImageProcessing' -- Script to use for processing in thread multiRemoteCameraParameters.monitorCamera = false -- Opt. monitor camera status in "CameraOverview" UI multiRemoteCameraParameters.customGigEVisionConfig = {} -- Custom GigEVision setting, content are 3 tables ".parameter", ".type", ".value" - multiRemoteCameraParameters.cameraModel = "PicoMidiCam2" -- 'a2A1920-51gcBAS', 'CustomConfig', 'SEC100' + if _G.availableAPIs.GigEVision then + multiRemoteCameraParameters.cameraModel = "PicoMidiCam2" -- 'a2A1920-51gcBAS', 'CustomConfig', 'SEC100' + elseif _G.availableAPIs.I2D then + multiRemoteCameraParameters.cameraModel = "PicoMidiCam" -- Version 1 + elseif _G.availableAPIs.SEC100 then + multiRemoteCameraParameters.cameraModel = "SEC100" -- 'a2A1920-51gcBAS', 'CustomConfig', 'SEC100' + end multiRemoteCameraParameters.secUser = 'Service' -- User to login to SEC camera multiRemoteCameraParameters.secUserPassword = '' -- User password to login to SEC camera multiRemoteCameraParameters.secMode = 'Snapshot' -- Mode to run SEC camera + multiRemoteCameraParameters.secInternalImageProcessing = true -- Convert raw images for internal image processing (TRUE) or only forward raw images (FALSE) + multiRemoteCameraParameters.secSnapshotDelay = 400 -- Time to wait before downloading latest snapshot -- Image processing parameters multiRemoteCameraParameters.processingMode = "BOTH" -- 'SCRIPT', 'APP', 'BOTH' --> see "setProcessingMode" diff --git a/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/helper/checkAPIs.lua b/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/helper/checkAPIs.lua index bb8148c..04ca94e 100644 --- a/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/helper/checkAPIs.lua +++ b/CSK_Module_MultiRemoteCamera/scripts/Sensors/MultiRemoteCamera/helper/checkAPIs.lua @@ -40,11 +40,17 @@ local function loadSpecificAPIs() Image = require 'API.Image' Image.Provider = {} Image.Provider.RemoteCamera = require 'API.Image.Provider.RemoteCamera' + View = require 'API.View' +end + +local function loadEthernetSpecificAPIs() Ethernet = require 'API.Ethernet' Ethernet.Interface = require 'API.Ethernet.Interface' +end + +-- Function to load flow specific API +local function loadFlowSpecific() Flow = require 'API.Flow' - Image = require 'API.Image' - View = require 'API.View' end -- Function to load specific I2D APIs @@ -66,9 +72,6 @@ local function loadSEC100SpecificAPIs() Hash = {} Hash.SHA256 = require 'API.Hash.SHA256' - Image.Format = {} - Image.Format.JPEG = require 'API.Image.Format.JPEG' - -- Check if related CSK modules are available to be used local appList = Engine.listApps() for i = 1, #appList do @@ -91,10 +94,20 @@ local function loadSEC100StreamSpecificAPIs() end end +local function loadImageProcessingSpecificAPIs() + Image.Format = {} + Image.Format.JPEG = require 'API.Image.Format.JPEG' +end + availableAPIs.default = xpcall(loadAPIs, debug.traceback) -- TRUE if all default APIs were loaded correctly availableAPIs.imageProvider = xpcall(loadSpecificAPIs, debug.traceback) -- TRUE if all specific APIs were loaded correctly availableAPIs.I2D = xpcall(loadI2DSpecificAPIs, debug.traceback) -- TRUE if all I2D specific APIs were loaded correctly availableAPIs.GigEVision = xpcall(loadGigEVisionSpecificAPIs, debug.traceback) -- TRUE if all GigE Vision specific APIs were loaded correctly +availableAPIs.imageProcessing = xpcall(loadImageProcessingSpecificAPIs, debug.traceback) -- TRUE if all SEC100 specific APIs were loaded correctly + +availableAPIs.ethernet = xpcall(loadEthernetSpecificAPIs, debug.traceback) -- TRUE if all default APIs were loaded correctly +availableAPIs.flow = xpcall(loadFlowSpecific, debug.traceback) -- TRUE if all default APIs were loaded correctly + availableAPIs.SEC100 = xpcall(loadSEC100SpecificAPIs, debug.traceback) -- TRUE if all SEC100 specific APIs were loaded correctly availableAPIs.SEC100Stream = xpcall(loadSEC100StreamSpecificAPIs, debug.traceback) -- TRUE if all SEC100 specific APIs were loaded correctly diff --git a/README.md b/README.md index 9a7c139..665f2ee 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Following CSK modules are necessary if you want to run it with SEC cameras: |Module|Version|Remark |--|--|--| -|CSK_Module_MultiHTTPClient|[V2.2.0](https://github.com/SICKAppSpaceCodingStarterKit/CSK_Module_MultiHTTPClient/releases/tag/v2.2.0)| +|CSK_Module_MultiHTTPClient|[V2.3.0](https://github.com/SICKAppSpaceCodingStarterKit/CSK_Module_MultiHTTPClient/releases/tag/v2.3.0)| |CSK_Module_MultiWebSocketClient|[V1.0.0](https://github.com/SICKAppSpaceCodingStarterKit/CSK_Module_MultiWebSocketClient/releases/tag/v1.0.0)| ## Information @@ -26,6 +26,7 @@ Tested on |Device|Firmware|Module version| |--|--|--| +|SIM800|V1.2.0|V6.3.0| |SIM2x00|V1.8.0|V6.1.1| |SIM2x00|V1.8.0|V6.1.0| |SIM1012|V2.4.2|V6.1.0| diff --git a/docu/CSK_Module_MultiRemoteCamera.html b/docu/CSK_Module_MultiRemoteCamera.html index 011b9e9..736ee76 100644 --- a/docu/CSK_Module_MultiRemoteCamera.html +++ b/docu/CSK_Module_MultiRemoteCamera.html @@ -6,7 +6,7 @@ -Documentation - CSK_Module_MultiRemoteCamera 6.2.0 +Documentation - CSK_Module_MultiRemoteCamera 6.3.0