diff --git a/CHANGELOG.md b/CHANGELOG.md index 449f8ea..ade7e4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,13 +2,4 @@ All notable changes to this project will be documented in this file. ## Release 0.1.0 -- Initial commit - -### New features -- ... - -### Improvements -- ... - -### Bugfix -- ... \ No newline at end of file +- Initial commit \ No newline at end of file diff --git a/CSK_Module_Fieldbus/pages/assets/legacy/settings.json b/CSK_Module_Fieldbus/pages/assets/legacy/settings.json index 939ec2a..a845df1 100644 --- a/CSK_Module_Fieldbus/pages/assets/legacy/settings.json +++ b/CSK_Module_Fieldbus/pages/assets/legacy/settings.json @@ -1,3 +1,9 @@ { -"showLoginButton": false + "canChangeLanguage": true, + "showLoginButton": false, + "defaultLanguage": "en", + "disableEditMode": true, + "showPageHistory": true, + "compactMode": false, + "canChangeCompactMode": false } \ No newline at end of file diff --git a/CSK_Module_Fieldbus/pages/pages/CSK_Module_Fieldbus/CSK_Module_Fieldbus.css b/CSK_Module_Fieldbus/pages/pages/CSK_Module_Fieldbus/CSK_Module_Fieldbus.css index d215c48..ec7cdb7 100644 --- a/CSK_Module_Fieldbus/pages/pages/CSK_Module_Fieldbus/CSK_Module_Fieldbus.css +++ b/CSK_Module_Fieldbus/pages/pages/CSK_Module_Fieldbus/CSK_Module_Fieldbus.css @@ -5,5 +5,14 @@ margin: 6px; } -.myCustomCssClass_CSK_Module_Fieldbus { +.myCustomMinHeight100p_CSK_Module_Fieldbus { + min-height: 100%; } + +.myCustomMarginBottom4px_CSK_Module_Fieldbus { + margin-bottom: 4px; +} + +.myCustomRedText_CSK_Module_Fieldbus { + color: crimson; +} \ No newline at end of file diff --git a/CSK_Module_Fieldbus/pages/pages/CSK_Module_Fieldbus/CSK_Module_Fieldbus.html b/CSK_Module_Fieldbus/pages/pages/CSK_Module_Fieldbus/CSK_Module_Fieldbus.html index 46565ab..b810ed9 100644 --- a/CSK_Module_Fieldbus/pages/pages/CSK_Module_Fieldbus/CSK_Module_Fieldbus.html +++ b/CSK_Module_Fieldbus/pages/pages/CSK_Module_Fieldbus/CSK_Module_Fieldbus.html @@ -2,85 +2,1728 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Load Config - - - - - - - - - Save Config - - - - - - - - + + +

Fieldbus

+ + + + + + + DISABLED + + + ProfinetIO + + + EtherNet/IP + + + + + + + + + + Set / Restart + + + + + + + + + + + + + + + + + + + + + + + + + + + + AUTOMATIC_OPEN + + + EXPLICIT_OPEN + + + + + + + + + + Open + + + + + + + + + + CONFIRMED_MESSAGING + + + RAW + + + + + + + + + + Close + + + + + + + + + + + + + + + + + + STATIC + + + BOOTP + + + DHCP + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Get config + + + + + + + + + Set config + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Remanent + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Get DAP IM Data + + + + + Set DAP IM data + + + + + Store DAP I&M data + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Load Config + + + + + + + + + Save Config + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Refresh ControlBit Status + + + + + WriteCtrlBits + + + + + + + + + + + + + + + + + + + + + Data types +
+ PLC   <->   AppSpace +
+
+ BYTE   -   U_BYTE / U_INT1   (0 ... 255) +
+ WORD   -   U_INT2   (0 ... 65535) +
+ DWORD   -   U_INT4   (0 ... 4294967295) +
+ LWord   -   U_INT8   (0 ... 18446744073709551615) +
+
+ SINT   -   S_INT1   (-128 ... +127) +
+ INT   -   S_INT2   (-32768 ... +32767) +
+ DINT   -   S_INT4   (-2147483648 ... +2147483647) +
+ LINT   -   S_INT8   (-9223372036854775808 ... +9223372036854775807) +
+
+ USINT   -   U_BYTE / U_INT1   (0 ... 255) +
+ UINT   -   U_INT2   (0 ... 65535) +
+ UDINT   -   U_INT4   (0 ... 4294967295) +
+ ULINT   -   U_INT8   (0 ... 18446744073709551615) +
+
+ REAL   -   FLOAT   (-3.402823e+38 ... -1.175495e-38 / +1.175495e-38 ... +3.402823e+38) +
+ LREAL   -   DOUBLE   (-1.7976931348623158e+308 ... -2.2250738585072014e-308 / +2.2250738585072014e-308 ... +1.7976931348623158e+308) +
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + Convert data + + + + + + + + + Big Endian + + + + + + + + + + CHAR + + + DOUBLE + + + FLOAT + + + S_BYTE + + + S_INT1 + + + S_INT2 + + + S_INT4 + + + S_INT8 + + + S_LONG + + + S_SHORT + + + U_BYTE + + + U_INT1 + + + U_INT2 + + + U_INT4 + + + U_INT8 + + + U_LONG + + + U_SHORT + + + + + + + + + + Add / Edit + + + + + + + Delete + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Up + + + + + + + Down + + + + + + + + + + + + + + + + + Set value + + + + + + + Reset All + + + + + + + + + +
+
+
+
+
+ + + + + + + + + + + + + Data types +
+ PLC   <->   AppSpace +
+
+ BYTE   -   U_BYTE / U_INT1   (0 ... 255) +
+ WORD   -   U_INT2   (0 ... 65535) +
+ DWORD   -   U_INT4   (0 ... 4294967295) +
+ LWord   -   U_INT8   (0 ... 18446744073709551615) +
+
+ SINT   -   S_INT1   (-128 ... +127) +
+ INT   -   S_INT2   (-32768 ... +32767) +
+ DINT   -   S_INT4   (-2147483648 ... +2147483647) +
+ LINT   -   S_INT8   (-9223372036854775808 ... +9223372036854775807) +
+
+ USINT   -   U_BYTE / U_INT1   (0 ... 255) +
+ UINT   -   U_INT2   (0 ... 65535) +
+ UDINT   -   U_INT4   (0 ... 4294967295) +
+ ULINT   -   U_INT8   (0 ... 18446744073709551615) +
+
+ REAL   -   FLOAT   (-3.402823e+38 ... -1.175495e-38 / +1.175495e-38 ... +3.402823e+38) +
+ LREAL   -   DOUBLE   (-1.7976931348623158e+308 ... -2.2250738585072014e-308 / +2.2250738585072014e-308 ... +1.7976931348623158e+308) +
+
+
+
+
+
+ + + + + + + + + + + + + + Convert data + + + + + + + + + Big Endian + + + + + + + + + + CHAR + + + DOUBLE + + + FLOAT + + + S_BYTE + + + S_INT1 + + + S_INT2 + + + S_INT4 + + + S_INT8 + + + S_LONG + + + S_SHORT + + + U_BYTE + + + U_INT1 + + + U_INT2 + + + U_INT4 + + + U_INT8 + + + U_LONG + + + U_SHORT + + + + + + + + + + Add / Edit + + + + + + + Delete + + + + + + + + + + + + + + + + + + + + + + + + + + + Up + + + + + + + Down + + + + + + + + + + + + + + + + Each data will be forwarded by a dynamically created event identified by its name like 'CSK_Fieldbus.OnNewData_[NAME]' + + + + + + +
+
+
+
+
+
+
+
+
+
@@ -100,7 +1743,5 @@
- - diff --git a/CSK_Module_Fieldbus/project.mf.xml b/CSK_Module_Fieldbus/project.mf.xml index 8c5cdf2..d8fc150 100644 --- a/CSK_Module_Fieldbus/project.mf.xml +++ b/CSK_Module_Fieldbus/project.mf.xml @@ -1,79 +1,563 @@ - - - - - This is an automatically generated CROWN (description not necessary). - - - released - Please fill in information regarding: What is the idea of this module and its features? + -How to use this module in general.... like: + -{empty} + -Typically the features of this module are used like this (check also main script of this module): + -**1) Setup** + -ToDo + -{empty} + -**2) Something else...** + - - - - Notify status if parameters should be loaded on app/device boot up. - - - - Notify status if features of CSK_PersistendData module are available. - - - - Event to call if module tried to load parameters and should be ready. - - - Notify name of persistent data parameter. - - - - Status of Operator userlevel. Used internally in combination with the CSK_UserManagement module if available. - - - - Status of Maintenance userlevel. Used internally in combination with the CSK_UserManagement module if available. - - - - Status of Service userlevel. Used internally in combination with the CSK_UserManagement module if available. - - - - Status of Admin userlevel. Used internally in combination with the CSK_UserManagement module if available. - - - - Function to set the name of the parameters if saved/loaded via the CSK_PersistentData module. - - - - 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. - - - Configure if this module should load its saved parameters at app/device boot up. - - - - Function to register "OnResume" of the module UI (only as helper function). - - - - - SICK AG - 0.1.0 - low - false - false - false - true - - - + + + + + This is an automatically generated CROWN (description not necessary). + + + released + Module to provide fieldbus (Profinet / EtherNet/IP) functionality. + +This module is helpful to forward data to/from other modules to communicate to a connected PLC. + +{empty} + +Typically the features of this module are used like this (check also main script of this module): + +{empty} + +**1) Selecte protocol** + +Select a fieldbus protocol to use via 'setProtocol' and trigger a device reboot to activate the protocol via 'submitProtocol'. + +After the reboot open the connection via 'openCommunication'. + +{empty} + +**2) ControlBits** + +To read the currently active ControlBits use 'refreshControlBits' and the events 'OnNewStatusControlBitsIn', 'OnNewStatusControlBitsInTable', 'OnNewStatusControlBitsOut', 'OnNewStatusControlBitsOut'. + +It is possible to set the ControlBitsIn by presetting them via 'setControlBitsIn'/'setSpecificControlBit' and to send them via 'writeControlBitsInViaUI'. + +To set a bitmask for the ControlBitsIn make use of 'setBitMask' or 'setSpecificBitMaskBit'. + +{empty} + +**3) Data to transmit** + +It is possible to define the data structure and source of the transmitted data. + +To do this preconfigure the data entry via 'setDataNameTransmit', 'setRegisteredEventTransmit', 'setConvertDataTransmit', 'setBigEndianTransmit', 'setDataTypeTransmit' and after that add this data via 'addDataToTransmitViaUI'. + +Based on the data received by the configured event (see 'setRegisteredEventTransmit') it will forward this data via fieldbus communication. + +{empty} + +**4) Data to receive** + +It is possible to define the data structure of the data to receive from the PLC. + +To do this preconfigure the data entry via 'setDataNameReceive', 'setConvertDataReceive', 'setBigEndianReceive', 'setDataTypeReceive' and after that add this data via 'addDataToReceiveViaUI'. + +The received data values will be provided via dynamically created events (see 'CSK_Fieldbus.OnNewData_DATANAME') and the full data via event 'CSK_Fieldbus.OnNewStatusReceivedData'. + + + Fieldbus protocol. + PROFINET + EtherNet_IP + EtherCAT + + + Mode for calling Fieldbus 'create' function. + EXPLICIT_OPEN + AUTOMATIC_OPEN + + + Fieldbus TransmissionMode + RAW + CONFIRMED_MESSAGING + + + Addressing mode for the IP address assignment. + DHCP + BOOTP + STATIC + + + Types of data to transmit + S_INT2 + S_BYTE + U_INT2 + U_BYTE + S_SHORT + U_SHORT + U_INT1 + U_INT8 + U_INT4 + S_INT1 + S_INT4 + U_LONG + S_INT8 + DOUBLE + FLOAT + S_LONG + CHAR + + + + Notify status if parameters should be loaded on app/device boot up. + + + + Notify status if features of CSK_PersistendData module are available. + + + + Event to call if module tried to load parameters and should be ready. + + + Notify name of persistent data parameter. + + + + Status of Operator userlevel. Used internally in combination with the CSK_UserManagement module if available. + + + + Status of Maintenance userlevel. Used internally in combination with the CSK_UserManagement module if available. + + + + Status of Service userlevel. Used internally in combination with the CSK_UserManagement module if available. + + + + Status of Admin userlevel. Used internally in combination with the CSK_UserManagement module if available. + + + + Notify current selected fieldbus protocol. + + + + Notify if Fieldbus features should be used. + + + + Notify fieldbus create mode. + + + + Notify fieldbus transmission mode. + + + + Notify preset data to be transmitted. + + + + Notify preset ControlBitsIn to write. + + + + Notify bit mask to use for preset control bits to write. + + + + Notify latest ControlBitsOut received from the PLC. + + + + Notify status of the fieldbus communication. + + + + Notify if fieldbus communication is currently 'OPENED' or 'ONLINE'. + + + + Notify info of fieldbus communication. + + + + Notify current value of the control bits transmitted to the PLC. + + + + Notify addressing mode for EtherNet/IP IP assignment. + + + + Notify IP address of EtherNet/IP network. + + + + Notfify subnet mask of EtherNet/IP network. + + + + Notfify gateway of EtherNet/IP network. + + + + Notfify primary name server of EtherNet/IP network. + + + + Notfify secondary name server of EtherNet/IP network. + + + + Notfify domain name of EtherNet/IP network. + + + + Notfify MAC address of specified interface of EtherNet/IP network. + + + + Notify name of the device in the Profinet network. + + + + Notify IP address of ProfinetIO network. + + + + Notfify subnet mask of ProfinetIO network. + + + + Notfify gateway of ProfinetIO network. + + + + Notfify if the ProfinetIO network configuration tool set the IP address settings permanently. + + + + Notfify MAC address of specified interface of ProfinetIO network. + + + + Notify descriptor as used for the ProfinetIO DAP’s I&M3 data. + + + + Notify hardware revision as used for the DAP used in the I&M0 data. + + + + Notify installation date as used for the DAP’s I&M2 data. + + + + Notify software revision for the DAP (device access point) used in the I&M0 data. + + + + Notify function tag as used for the DAP’s I&M1 data. + + + + Notify location tag as used for the DAP’s I&M1 data. + + + + Notify currently active fieldbus protocol. + + + + Notify if explicit mode is selected. + + + + Notify name of event to receive data to transmit. + + + + Notify name of preconfigured transmit data. + + + + Notify preconfigured status if data needs to be converted to binary before transmission. + + + + Notify if big endian should be used to convert data to transmit (otherwise little endian will be used). + + + + Notify preconfigured data type of data to transmit. + + + + Notify list of data entires to use for data transmission. + + + + Notify temporarily set data to transmit on selected data position. + + + + Notify fieldbus relevant log message. + + + + Notify ControlBitsOut as boolean table. + + + + Notify control bits IN as boolean table. + + + + Notify bitmask of control bits IN as boolean table. + + + + Notfiy received data. + + + + Notify name of preconfigured data to receive. + + + + Notify list of data entires to use for data receiving. + + + + Notify preconfigured status if data needs to be converted to binary after receiving. + + + + Notify if big endian should be used to convert received data (otherwise little endian will be used). + + + + Notify preconfigured data type of data to receive. + + + + Dynamically created event to provide received data from PLC via event. + +NAME will be replaced by data identifier (e.g. 'CSK_Fieldbus.OnNewData_Data1'). + + + + Notify info text to restart device. + + + + Function to set the name of the parameters if saved/loaded via the CSK_PersistentData module. + + + + 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. + + + + Configure if this module should load its saved parameters at app/device boot up. + + + + Function to register "OnResume" of the module UI (only as helper function). + + + + Function to set fiedlbus protocol to use. + + + + Function to open fieldbus communication. + + + + Function to close fieldbus communication. + + + Function to refresh data of ControlBitsIn/Out + + + Function to preset data to transmit. + + + + Function to transmit preset data (see 'setDataToTransmit'). + + + Function to preset controlBitsIn to write/transmit to PLC. + + + + Function to preset bitmask to use for preset ControlBitsIn to write. + + + + Function to write preset ControlBitsIn to the PLC. + + + Function to set create mode of fieldbus communication. + + + + Function to set transmission mode. + + + + Function to set preset fieldbus protocol (see 'setProtocol') and restart device. + + + Function to get EtherNetIP configuration. + + + Function to setup preconfigured EtherNet/IP config. + + + Function to set addressing mode of EtherNetIP communication. + + + + Function to preset IP for EtherNet/IP communication. + + + + Function to preset subnet mask for EtherNet/IP communication. + + + + Function to preset gateway for EtherNet/IP communication. + + + + Function to preset primary name server for EtherNet/IP communication. + + + + Function to preset secondary name server for EtherNet/IP communication. + + + + Function to preset domain name for EtherNet/IP communication. + + + + Function to preset ProfinetIO device name. + + + + Function to preset IP for ProfinetIO communication. + + + + Function to preset subnet mask for ProfinetIO communication. + + + + Function to preset gateway for ProfinetIO communication. + + + + Function to get ProfinetIO configuration. + + + Function apply ProfinetIO configuration. + + + Function to store ProfinetIO configuration. + + + Function to set ProfinetIO DAP IM configuration. + + + Function to get ProfinetIO DAP IM data. + + + Function to store ProfinetIO DAP I&M data. + + + Function to set descriptor for the DAPs I&M3 data. + + + + Function to set the installation date for the DAPs I&M2 data. + + + + Function to set the function tag for the DAPs I&M1 data. + + + + Function to set location tag for the DAPs I&M1 data. + + + + Function to set event to receive data to transmit via fieldbus for new/selected data entry. + + + + Function to add preconfigured data to transmit. + + + Function to preconfigure name of data entry to transmit. + + + + Function to preconfigure if internally received data (via event) needs to be converted before transmission. + + + + Function to preconfigure if data to transmit uses big endianness. Will use little endian per default. + + + + Function to preconfigure type of data to convert data before transmission. + + + + Function to select transmit data entry in UI. + + + + Function to delete preselected data entry. + + + Function to move the position of the transmit data about one position higher. + + + Function to move the position of the selected transmit data about one position lower. + + + Function to set temporarily data of in UI selected data postion to transmit. + + + + Function to set preconfigured data to in UI selected data position (see 'setTempTransmitData'). + +After that it will transmit the full data to the fieldbus. + + + Function to set specific ControlBitIn (bit range from 0-15). + + + + Function to set specific bit of bitmask (bit range from 0-15). + + + + Function to preconfigure name of data entry to receive. + + + + Function to preconfigure if received data form PLC needs to be converted before transmission. + + + + Function to preconfigure if received data uses big endianness. Will use little endian per default. + + + + Function to preconfigure type of data to convert received data. + + + + Function to add preconfigured data to receive. + + + Function to delete preselected data entry. + + + Function to move the position of the selected data to receive about one position lower. + + + Function to move the position of the data to receive about one position higher. + + + Function to select data entry in UI. + + + + Function to reset all data to transmit. + + + + SICK AG + 1.0.1 + low + false + false + false + false + + + diff --git a/CSK_Module_Fieldbus/scripts/CSK_Module_Fieldbus.lua b/CSK_Module_Fieldbus/scripts/CSK_Module_Fieldbus.lua index ff8b407..97d9e01 100644 --- a/CSK_Module_Fieldbus/scripts/CSK_Module_Fieldbus.lua +++ b/CSK_Module_Fieldbus/scripts/CSK_Module_Fieldbus.lua @@ -29,13 +29,13 @@ -- 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('Communication/Fieldbus/helper/checkAPIs') -- can be used to adjust function scope of the module related on available APIs of the device +_G.availableAPIs = require('Communication/Fieldbus/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') _G.logHandle = Log.Handler.create() _G.logHandle:attachToSharedLogger('ModuleLogger') -_G.logHandle:setConsoleSinkEnabled(false) --> Set to TRUE if CSK_Logger module is not used +_G.logHandle:setConsoleSinkEnabled(true) --> Set to TRUE if CSK_Logger module is not used _G.logHandle:setLevel("ALL") _G.logHandle:applyConfig() ----------------------------------------------------------- @@ -62,17 +62,51 @@ local function main() -- Can be used e.g. like this ---------------------------------------------------------------------------------------- - -- _G.fieldbus_Model.doSomething() -- if you want to start a function -- ... CSK_Fieldbus.pageCalled() -- Update UI -end -Script.register("Engine.OnStarted", main) + --[[ + CSK_Fieldbus.setDataNameReceive('Data1') + CSK_Fieldbus.setDataTypeReceive('U_INT2') + CSK_Fieldbus.addDataToReceiveViaUI() + + CSK_Fieldbus.setDataNameReceive('Data2') + CSK_Fieldbus.setDataTypeReceive('U_INT4') + CSK_Fieldbus.addDataToReceiveViaUI() + + CSK_Fieldbus.setDataTypeTransmit('U_BYTE') + for i=1, 6 do + CSK_Fieldbus.setDataNameTransmit('Data' ..tostring(i)) + CSK_Fieldbus.addDataToTransmitViaUI() + end + + CSK_Fieldbus.setDataTypeTransmit('S_INT2') + for i=7, 10 do + CSK_Fieldbus.setDataNameTransmit('Data' ..tostring(i)) + CSK_Fieldbus.addDataToTransmitViaUI() + end ---OR + CSK_Fieldbus.setDataTypeTransmit('U_BYTE') + for i=11, 18 do + CSK_Fieldbus.setDataNameTransmit('Data' ..tostring(i)) + CSK_Fieldbus.addDataToTransmitViaUI() + end --- Call function after persistent data was loaded ---Script.register("CSK_Fieldbus.OnDataLoadedOnReboot", main) + CSK_Fieldbus.setDataTypeTransmit('U_INT8') + for i=19, 31 do + CSK_Fieldbus.setDataNameTransmit('Data' ..tostring(i)) + CSK_Fieldbus.addDataToTransmitViaUI() + end + + CSK_Fieldbus.setDataTypeTransmit('U_BYTE') + for i=32, 33 do + CSK_Fieldbus.setDataNameTransmit('Data' ..tostring(i)) + CSK_Fieldbus.addDataToTransmitViaUI() + end +]] + +end +Script.register("Engine.OnStarted", main) --************************************************************************** --**********************End Function Scope ********************************* diff --git a/CSK_Module_Fieldbus/scripts/Communication/Fieldbus/Fieldbus_Controller.lua b/CSK_Module_Fieldbus/scripts/Communication/Fieldbus/Fieldbus_Controller.lua index 4092e0e..3776f01 100644 --- a/CSK_Module_Fieldbus/scripts/Communication/Fieldbus/Fieldbus_Controller.lua +++ b/CSK_Module_Fieldbus/scripts/Communication/Fieldbus/Fieldbus_Controller.lua @@ -15,12 +15,89 @@ local tmrFieldbus = Timer.create() tmrFieldbus:setExpirationTime(300) tmrFieldbus:setPeriodic(false) +-- Timer to wait for other modules to be ready to register to their events +local tmrWaitForSetupOfOtherModules = Timer.create() +tmrWaitForSetupOfOtherModules:setExpirationTime(1000) +tmrWaitForSetupOfOtherModules:setPeriodic(false) + -- Reference to global handle local fieldbus_Model -- ************************ UI Events Start ******************************** +-- Only to prevent WARNING messages, but these are only examples/placeholders for dynamically created events/functions +---------------------------------------------------------------- +Script.serveEvent('CSK_Fieldbus.OnNewData_NAME', 'Fieldbus_OnNewData_NAME') +---------------------------------------------------------------- + +-- Real events +-------------------------------------------------- +Script.serveEvent('CSK_Fieldbus.OnNewStatusLogMessage', 'Fieldbus_OnNewStatusLogMessage') +Script.serveEvent('CSK_Fieldbus.OnNewStatusRestartInfo', 'Fieldbus_OnNewStatusRestartInfo') + +Script.serveEvent('CSK_Fieldbus.OnNewStatusReceivedData', 'Fieldbus_OnNewStatusReceivedData') + +Script.serveEvent('CSK_Fieldbus.OnNewStatusFieldbusActive', 'Fieldbus_OnNewStatusFieldbusActive') +Script.serveEvent('CSK_Fieldbus.OnNewStatusFieldbusStatus', 'Fieldbus_OnNewStatusFieldbusStatus') + +Script.serveEvent('CSK_Fieldbus.OnNewStatusActiveProtocol', 'Fieldbus_OnNewStatusActiveProtocol') + +Script.serveEvent('CSK_Fieldbus.OnNewStatusProtocol', 'Fieldbus_OnNewStatusProtocol') +Script.serveEvent('CSK_Fieldbus.OnNewStatusFieldbusFeatureActive', 'Fieldbus_OnNewStatusFieldbusFeatureActive') + +Script.serveEvent('CSK_Fieldbus.OnNewStatusFieldbusInfo', 'Fieldbus_OnNewStatusFieldbusInfo') + +Script.serveEvent('CSK_Fieldbus.OnNewStatusCreateMode', 'Fieldbus_OnNewStatusCreateMode') +Script.serveEvent('CSK_Fieldbus.OnNewStatusExplicitModeActive', 'Fieldbus_OnNewStatusExplicitModeActive') + +Script.serveEvent('CSK_Fieldbus.OnNewStatusTransmissionMode', 'Fieldbus_OnNewStatusTransmissionMode') + +Script.serveEvent('CSK_Fieldbus.OnNewStatusControlBitsIn', 'Fieldbus_OnNewStatusControlBitsIn') +Script.serveEvent('CSK_Fieldbus.OnNewStatusControlBitsOut', 'Fieldbus_OnNewStatusControlBitsOut') +Script.serveEvent('CSK_Fieldbus.OnNewStatusControlBitsOutTable', 'Fieldbus_OnNewStatusControlBitsOutTable') + +Script.serveEvent('CSK_Fieldbus.OnNewStatusControlBitsInToWrite', 'Fieldbus_OnNewStatusControlBitsInToWrite') +Script.serveEvent('CSK_Fieldbus.OnNewStatusControlBitsInTable', 'Fieldbus_OnNewStatusControlBitsInTable') +Script.serveEvent('CSK_Fieldbus.OnNewStatusBitMask', 'Fieldbus_OnNewStatusBitMask') +Script.serveEvent('CSK_Fieldbus.OnNewStatusControlBitsInBitMaskTable', 'Fieldbus_OnNewStatusControlBitsInBitMaskTable') + +Script.serveEvent('CSK_Fieldbus.OnNewStatusDataTransmissionList', 'Fieldbus_OnNewStatusDataTransmissionList') +Script.serveEvent('CSK_Fieldbus.OnNewStatusRegisteredEventTransmit', 'Fieldbus_OnNewStatusRegisteredEventTransmit') +Script.serveEvent('CSK_Fieldbus.OnNewStatusDataNameTransmit', 'Fieldbus_OnNewStatusDataNameTransmit') +Script.serveEvent('CSK_Fieldbus.OnNewStatusConvertDataTransmit', 'Fieldbus_OnNewStatusConvertDataTransmit') +Script.serveEvent('CSK_Fieldbus.OnNewStatusBigEndianTransmit', 'Fieldbus_OnNewStatusBigEndianTransmit') +Script.serveEvent('CSK_Fieldbus.OnNewStatusDataTypeTransmit', 'Fieldbus_OnNewStatusDataTypeTransmit') +Script.serveEvent('CSK_Fieldbus.OnNewStatusTempDataTransmit', 'Fieldbus_OnNewStatusTempDataTransmit') +Script.serveEvent('CSK_Fieldbus.OnNewStatusDataToTransmit', 'Fieldbus_OnNewStatusDataToTransmit') + +Script.serveEvent('CSK_Fieldbus.OnNewStatusDataReceivingList', 'Fieldbus_OnNewStatusDataReceivingList') +Script.serveEvent('CSK_Fieldbus.OnNewStatusDataNameReceive', 'Fieldbus_OnNewStatusDataNameReceive') +Script.serveEvent('CSK_Fieldbus.OnNewStatusConvertDataReceive', 'Fieldbus_OnNewStatusConvertDataReceive') +Script.serveEvent('CSK_Fieldbus.OnNewStatusBigEndianReceive', 'Fieldbus_OnNewStatusBigEndianReceive') +Script.serveEvent('CSK_Fieldbus.OnNewStatusDataTypeReceive', 'Fieldbus_OnNewStatusDataTypeReceive') + +Script.serveEvent('CSK_Fieldbus.OnNewStatusEtherNetIPAddressingMode', 'Fieldbus_OnNewStatusEtherNetIPAddressingMode') +Script.serveEvent('CSK_Fieldbus.OnNewStatusEtherNetIPIPAddress', 'Fieldbus_OnNewStatusEtherNetIPIPAddress') +Script.serveEvent('CSK_Fieldbus.OnNewStatusEtherNetIPSubnetMask', 'Fieldbus_OnNewStatusEtherNetIPSubnetMask') +Script.serveEvent('CSK_Fieldbus.OnNewStatusEtherNetIPGateway', 'Fieldbus_OnNewStatusEtherNetIPGateway') +Script.serveEvent('CSK_Fieldbus.OnNewStatusEtherNetIPNameServer', 'Fieldbus_OnNewStatusEtherNetIPNameServer') +Script.serveEvent('CSK_Fieldbus.OnNewStatusEtherNetIPNameServer2', 'Fieldbus_OnNewStatusEtherNetIPNameServer2') +Script.serveEvent('CSK_Fieldbus.OnNewStatusEtherNetIPDomainName', 'Fieldbus_OnNewStatusEtherNetIPDomainName') +Script.serveEvent('CSK_Fieldbus.OnNewStatusEtherNetIPMACAddress', 'Fieldbus_OnNewStatusEtherNetIPMACAddress') + +Script.serveEvent('CSK_Fieldbus.OnNewStatusProfinetIODeviceName', 'Fieldbus_OnNewStatusProfinetIODeviceName') +Script.serveEvent('CSK_Fieldbus.OnNewStatusProfinetIOIPAddress', 'Fieldbus_OnNewStatusProfinetIOIPAddress') +Script.serveEvent('CSK_Fieldbus.OnNewStatusProfinetIOSubnetMask', 'Fieldbus_OnNewStatusProfinetIOSubnetMask') +Script.serveEvent('CSK_Fieldbus.OnNewStatusProfinetIOGateway', 'Fieldbus_OnNewStatusProfinetIOGateway') +Script.serveEvent('CSK_Fieldbus.OnNewStatusProfinetIORemanent', 'Fieldbus_OnNewStatusProfinetIORemanent') +Script.serveEvent('CSK_Fieldbus.OnNewStatusProfinetIOMACAddress', 'Fieldbus_OnNewStatusProfinetIOMACAddress') + +Script.serveEvent('CSK_Fieldbus.OnNewStatusDAPIMDescriptor', 'Fieldbus_OnNewStatusDAPIMDescriptor') +Script.serveEvent('CSK_Fieldbus.OnNewStatusDAPIMHardwareRev', 'Fieldbus_OnNewStatusDAPIMHardwareRev') +Script.serveEvent('CSK_Fieldbus.OnNewStatusDAPIMInstallationDate', 'Fieldbus_OnNewStatusDAPIMInstallationDate') +Script.serveEvent('CSK_Fieldbus.OnNewStatusDAPIMSoftwareRev', 'Fieldbus_OnNewStatusDAPIMSoftwareRev') +Script.serveEvent('CSK_Fieldbus.OnNewStatusDAPIMTagFunction', 'Fieldbus_OnNewStatusDAPIMTagFunction') +Script.serveEvent('CSK_Fieldbus.OnNewStatusDAPIMTagLocation', 'Fieldbus_OnNewStatusDAPIMTagLocation') --- Script.serveEvent("CSK_Fieldbus.OnNewEvent", "Fieldbus_OnNewEvent") Script.serveEvent("CSK_Fieldbus.OnNewStatusLoadParameterOnReboot", "Fieldbus_OnNewStatusLoadParameterOnReboot") Script.serveEvent("CSK_Fieldbus.OnPersistentDataModuleAvailable", "Fieldbus_OnPersistentDataModuleAvailable") Script.serveEvent("CSK_Fieldbus.OnNewParameterName", "Fieldbus_OnNewParameterName") @@ -31,18 +108,7 @@ Script.serveEvent('CSK_Fieldbus.OnUserLevelMaintenanceActive', 'Fieldbus_OnUserL Script.serveEvent('CSK_Fieldbus.OnUserLevelServiceActive', 'Fieldbus_OnUserLevelServiceActive') Script.serveEvent('CSK_Fieldbus.OnUserLevelAdminActive', 'Fieldbus_OnUserLevelAdminActive') --- ... - -- ************************ UI Events End ********************************** - ---[[ ---- Some internal code docu for local used function -local function functionName() - -- Do something - -end -]] - --************************************************************************** --********************** End Global Scope ********************************** --************************************************************************** @@ -103,17 +169,97 @@ local function updateUserLevel() end end +--TODO not needed? +--[[ +local function checkExplicitMode() + if fieldbus_Model.parameters.createMode == 'EXPLICIT_OPEN' then + Script.notifyEvent("Fieldbus_OnNewStatusExplicitModeActive", true) + else + Script.notifyEvent("Fieldbus_OnNewStatusExplicitModeActive", false) + end +end +]] + --- Function to send all relevant values to UI on resume local function handleOnExpiredTmrFieldbus() updateUserLevel() - -- Script.notifyEvent("Fieldbus_OnNewEvent", false) + fieldbus_Model.boolControlBitsToWrite = fieldbus_Model.boolControlBitsOut + + Script.notifyEvent("Fieldbus_OnNewStatusActiveProtocol", fieldbus_Model.fbMode) + + Script.notifyEvent("Fieldbus_OnNewStatusFieldbusStatus", fieldbus_Model.currentStatus) + Script.notifyEvent("Fieldbus_OnNewStatusFieldbusActive", fieldbus_Model.opened) + Script.notifyEvent("Fieldbus_OnNewStatusRestartInfo", '') + + Script.notifyEvent("Fieldbus_OnNewStatusFieldbusInfo", fieldbus_Model.helperFuncs.jsonLine2Table(fieldbus_Model.info)) + Script.notifyEvent("Fieldbus_OnNewStatusProtocol", fieldbus_Model.parameters.protocol) + + Script.notifyEvent("Fieldbus_OnNewStatusDataTransmissionList", fieldbus_Model.helperFuncs.createJsonListTransmissionData(fieldbus_Model.parameters.dataNamesTransmit, fieldbus_Model.parameters.registeredEventsTransmit, fieldbus_Model.parameters.dataTypesTransmit, fieldbus_Model.parameters.convertDataTypesTransmit, fieldbus_Model.parameters.bigEndiansTransmit, fieldbus_Model.readableDataToTransmit, fieldbus_Model.selectedDataTransmit)) + Script.notifyEvent("Fieldbus_OnNewStatusDataNameTransmit", fieldbus_Model.dataNameTransmit) + Script.notifyEvent("Fieldbus_OnNewStatusRegisteredEventTransmit", fieldbus_Model.registerEventTransmit) + Script.notifyEvent("Fieldbus_OnNewStatusConvertDataTransmit", fieldbus_Model.convertDataTransmit) + Script.notifyEvent("Fieldbus_OnNewStatusBigEndianTransmit", fieldbus_Model.bigEndianTransmit) + Script.notifyEvent("Fieldbus_OnNewStatusDataTypeTransmit", fieldbus_Model.dataTypeTransmit) + Script.notifyEvent("Fieldbus_OnNewStatusTempDataTransmit", tostring(fieldbus_Model.tempDataTransmit)) + + Script.notifyEvent("Fieldbus_OnNewStatusDataReceivingList", fieldbus_Model.helperFuncs.createJsonListReceiveData(fieldbus_Model.parameters.dataNamesReceive, fieldbus_Model.parameters.dataTypesReceive, fieldbus_Model.parameters.convertDataTypesReceive, fieldbus_Model.parameters.bigEndiansReceive, fieldbus_Model.dataReceived, fieldbus_Model.selectedDataReceive)) + Script.notifyEvent("Fieldbus_OnNewStatusDataNameReceive", fieldbus_Model.dataNameReceive) + Script.notifyEvent("Fieldbus_OnNewStatusConvertDataReceive", fieldbus_Model.convertDataReceive) + Script.notifyEvent("Fieldbus_OnNewStatusBigEndianReceive", fieldbus_Model.bigEndianReceive) + Script.notifyEvent("Fieldbus_OnNewStatusDataTypeReceive", fieldbus_Model.dataTypeReceive) + + Script.notifyEvent("Fieldbus_OnNewStatusControlBitsIn", fieldbus_Model.controlBitsIn) + Script.notifyEvent("Fieldbus_OnNewStatusControlBitsOut", fieldbus_Model.controlBitsOut) + + Script.notifyEvent("Fieldbus_OnNewStatusControlBitsOutTable", fieldbus_Model.boolControlBitsOut) + Script.notifyEvent("Fieldbus_OnNewStatusControlBitsInTable", fieldbus_Model.boolControlBitsIn) + Script.notifyEvent("Fieldbus_OnNewStatusControlBitsInBitMaskTable", fieldbus_Model.boolBitMask) + + Script.notifyEvent("Fieldbus_OnNewStatusControlBitsInToWrite", fieldbus_Model.controlBitsToWrite) + Script.notifyEvent("Fieldbus_OnNewStatusBitMask", fieldbus_Model.bitMask) + + if fieldbus_Model.fbMode == 'DISABLED' then + Script.notifyEvent("Fieldbus_OnNewStatusFieldbusFeatureActive", false) + else + Script.notifyEvent("Fieldbus_OnNewStatusFieldbusFeatureActive", true) + + Script.notifyEvent("Fieldbus_OnNewStatusCreateMode", fieldbus_Model.parameters.createMode) + --checkExplicitMode() + + Script.notifyEvent("Fieldbus_OnNewStatusTransmissionMode", fieldbus_Model.parameters.transmissionMode) + + if fieldbus_Model.fbMode == 'EtherNetIP' then + Script.notifyEvent("Fieldbus_OnNewStatusEtherNetIPAddressingMode", fieldbus_Model.parameters.etherNetIP.addressingMode) + Script.notifyEvent("Fieldbus_OnNewStatusEtherNetIPIPAddress", fieldbus_Model.parameters.etherNetIP.ipAddress) + Script.notifyEvent("Fieldbus_OnNewStatusEtherNetIPSubnetMask", fieldbus_Model.parameters.etherNetIP.netmask) + Script.notifyEvent("Fieldbus_OnNewStatusEtherNetIPGateway", fieldbus_Model.parameters.etherNetIP.gateway) + Script.notifyEvent("Fieldbus_OnNewStatusEtherNetIPNameServer", fieldbus_Model.parameters.etherNetIP.nameServer) + Script.notifyEvent("Fieldbus_OnNewStatusEtherNetIPNameServer2", fieldbus_Model.parameters.etherNetIP.nameServer2) + Script.notifyEvent("Fieldbus_OnNewStatusEtherNetIPDomainName", fieldbus_Model.parameters.etherNetIP.domainName) + Script.notifyEvent("Fieldbus_OnNewStatusEtherNetIPMACAddress", fieldbus_Model.parameters.etherNetIP.macAddress) + + elseif fieldbus_Model.fbMode == 'ProfinetIO' then + Script.notifyEvent("Fieldbus_OnNewStatusProfinetIODeviceName", fieldbus_Model.parameters.profinetIO.deviceName) + Script.notifyEvent("Fieldbus_OnNewStatusProfinetIOIPAddress", fieldbus_Model.parameters.profinetIO.ipAddress) + Script.notifyEvent("Fieldbus_OnNewStatusProfinetIOSubnetMask", fieldbus_Model.parameters.profinetIO.netmask) + Script.notifyEvent("Fieldbus_OnNewStatusProfinetIOGateway", fieldbus_Model.parameters.profinetIO.gateway) + Script.notifyEvent("Fieldbus_OnNewStatusProfinetIORemanent", fieldbus_Model.parameters.profinetIO.remanent) + Script.notifyEvent("Fieldbus_OnNewStatusProfinetIOMACAddress", fieldbus_Model.parameters.profinetIO.macAddress) + + Script.notifyEvent("Fieldbus_OnNewStatusDAPIMDescriptor", fieldbus_Model.parameters.profinetIO.dapImDescriptor) + Script.notifyEvent("Fieldbus_OnNewStatusDAPIMHardwareRev", fieldbus_Model.parameters.profinetIO.dapImHardwareRev) + Script.notifyEvent("Fieldbus_OnNewStatusDAPIMInstallationDate", fieldbus_Model.parameters.profinetIO.dapImInstallDate) + Script.notifyEvent("Fieldbus_OnNewStatusDAPIMSoftwareRev", fieldbus_Model.parameters.profinetIO.dapImSoftwareRevPrefix .. '.' .. tostring(fieldbus_Model.parameters.profinetIO.dapImSoftwareRevFuncEnhancement) .. '.' .. tostring(fieldbus_Model.parameters.profinetIO.dapImSoftwareRevBugFix) .. '.' .. tostring(fieldbus_Model.parameters.profinetIO.dapImSoftwareRevInternalChange)) + Script.notifyEvent("Fieldbus_OnNewStatusDAPIMTagFunction", fieldbus_Model.parameters.profinetIO.dapImTagFunction) + Script.notifyEvent("Fieldbus_OnNewStatusDAPIMTagLocation", fieldbus_Model.parameters.profinetIO.dapImTagLocation) + end + end Script.notifyEvent("Fieldbus_OnNewStatusLoadParameterOnReboot", fieldbus_Model.parameterLoadOnReboot) Script.notifyEvent("Fieldbus_OnPersistentDataModuleAvailable", fieldbus_Model.persistentModuleAvailable) Script.notifyEvent("Fieldbus_OnNewParameterName", fieldbus_Model.parametersName) - -- ... end Timer.register(tmrFieldbus, "OnExpired", handleOnExpiredTmrFieldbus) @@ -126,20 +272,684 @@ local function pageCalled() end Script.serveFunction("CSK_Fieldbus.pageCalled", pageCalled) ---[[ -local function setSomething(value) - _G.logger:info(nameOfModule .. ": Set new value = " .. value) - fieldbus_Model.varA = value +local function setProtocol(protocol) + _G.logger:fine(nameOfModule .. ": Set protocol to: " .. tostring(protocol)) + fieldbus_Model.parameters.protocol = protocol + handleOnExpiredTmrFieldbus() + + if (fieldbus_Model.parameters.protocol == 'ProfinetIO' and Parameters.get('FBmode') ~= 1) or (fieldbus_Model.parameters.protocol == 'EtherNetIP' and Parameters.get('FBmode') ~= 2) or (fieldbus_Model.parameters.protocol == 'DISABLED' and Parameters.get('FBmode') ~= 0) then + Script.notifyEvent("Fieldbus_OnNewStatusRestartInfo", 'Device restart needed to activate new protocol!') + else + Script.notifyEvent("Fieldbus_OnNewStatusRestartInfo", '') + end end -Script.serveFunction("CSK_Fieldbus.setSomething", setSomething) -]] +Script.serveFunction('CSK_Fieldbus.setProtocol', setProtocol) + +local function restartDevice() + Parameters.savePermanent() + if CSK_PersistentData then + CSK_Fieldbus.sendParameters() + end + fieldbus_Model.info = "Rebooting the device NOW! Reason: 'Change fieldbus protocol.'" + Script.notifyEvent("Fieldbus_OnNewStatusFieldbusInfo", fieldbus_Model.info) + Engine.reboot('Change fieldbus protocol.') +end + +local function submitProtocol() + if fieldbus_Model.parameters.protocol == 'ProfinetIO' and Parameters.get('FBmode') ~= 1 then + Parameters.set('FBmode', 1) + restartDevice() + elseif fieldbus_Model.parameters.protocol == 'EtherNetIP' and Parameters.get('FBmode') ~= 2 then + Parameters.set('FBmode', 2) + restartDevice() + elseif fieldbus_Model.parameters.protocol == 'DISABLED' and Parameters.get('FBmode') ~= 0 then + Parameters.set('FBmode', 0) + restartDevice() + end +end +Script.serveFunction('CSK_Fieldbus.submitProtocol', submitProtocol) + +local function setCreateMode(mode) + if fieldbus_Model.currentStatus == 'CLOSED' then + fieldbus_Model.parameters.createMode = mode + if mode == 'AUTOMATIC_OPEN' then + fieldbus_Model.parameters.transmissionMode = 'CONFIRMED_MESSAGING' + Script.notifyEvent("Fieldbus_OnNewStatusTransmissionMode", fieldbus_Model.parameters.transmissionMode) + end + else + _G.logger:info("Connection needs to be closed to configure the create mode.") + Script.notifyEvent("Fieldbus_OnNewStatusCreateMode", fieldbus_Model.parameters.createMode) + end + --checkExplicitMode() +end +Script.serveFunction('CSK_Fieldbus.setCreateMode', setCreateMode) + +local function setTransmissionMode(mode) + if fieldbus_Model.parameters.createMode == 'EXPLICIT_OPEN' then + fieldbus_Model.setTransmissionMode(mode) + else + _G.logger:info("Transmission mode only configurable if 'create mode' is 'EXPLICIT_OPEN'.") + Script.notifyEvent("Fieldbus_OnNewStatusTransmissionMode", fieldbus_Model.parameters.transmissionMode) + fieldbus_Model.info = "Transmission mode only configurable if 'create mode' is 'EXPLICIT_OPEN'." + Script.notifyEvent("Fieldbus_OnNewStatusFieldbusInfo", fieldbus_Model.info) + end +end +Script.serveFunction('CSK_Fieldbus.setTransmissionMode', setTransmissionMode) + +local function openCommunication() + local success = false + if fieldbus_Model.currentStatus == 'CLOSED' then + _G.logger:info(nameOfModule .. ": Open communciation.") + success = fieldbus_Model.openCommunication() + else + _G.logger:fine("Connection already active.") + end + return success +end +Script.serveFunction('CSK_Fieldbus.openCommunication', openCommunication) + +local function closeCommunication() + _G.logger:info(nameOfModule .. ": Close communication.") + fieldbus_Model.closeCommunication() + + fieldbus_Model.info = 'No info available.' + Script.notifyEvent("Fieldbus_OnNewStatusFieldbusInfo", fieldbus_Model.info) +end +Script.serveFunction('CSK_Fieldbus.closeCommunication', closeCommunication) + +local function refreshControlBits() + fieldbus_Model.readControlBitsIn() + fieldbus_Model.readControlBitsOut() +end +Script.serveFunction('CSK_Fieldbus.refreshControlBits', refreshControlBits) + +local function setDataToTransmit(data) + _G.logger:fine(nameOfModule .. ": Set data to transmit to: " .. tostring(data)) + fieldbus_Model.dataToTransmit = data +end +Script.serveFunction('CSK_Fieldbus.setDataToTransmit', setDataToTransmit) + +local function transmitViaUI() + fieldbus_Model.transmit(fieldbus_Model.dataToTransmit) +end +Script.serveFunction('CSK_Fieldbus.transmitViaUI', transmitViaUI) + +local function setControlBitsIn(controlBits) + _G.logger:fine(nameOfModule .. ": Set controlBits to: " .. tostring(controlBits)) + fieldbus_Model.controlBitsToWrite = controlBits + fieldbus_Model.boolControlBitsToWrite = fieldbus_Model.helperFuncs.toBits(fieldbus_Model.controlBitsToWrite) + Script.notifyEvent("Fieldbus_OnNewStatusControlBitsInTable", fieldbus_Model.boolControlBitsToWrite) +end +Script.serveFunction('CSK_Fieldbus.setControlBitsIn', setControlBitsIn) + +local function setSpecificControlBitIn(values) + local value = false + local pos = tonumber(values[2]) + if values[1] == 'true' then + value = true + end + if pos then + fieldbus_Model.boolControlBitsToWrite[pos+1] = value + fieldbus_Model.controlBitsToWrite = fieldbus_Model.helperFuncs.toNumber(fieldbus_Model.boolControlBitsToWrite) + Script.notifyEvent("Fieldbus_OnNewStatusControlBitsInToWrite", fieldbus_Model.controlBitsToWrite) + --print(fieldbus_Model.controlBitsToWrite) + end +end +Script.serveFunction('CSK_Fieldbus.setSpecificControlBitIn', setSpecificControlBitIn) + +local function setBitMask(bitMask) + _G.logger:fine(nameOfModule .. ": Set bitMask to: " .. tostring(bitMask)) + fieldbus_Model.bitMask = bitMask + fieldbus_Model.boolBitMask = fieldbus_Model.helperFuncs.toBits(fieldbus_Model.bitMask) + Script.notifyEvent("Fieldbus_OnNewStatusControlBitsInBitMaskTable", fieldbus_Model.boolBitMask) +end +Script.serveFunction('CSK_Fieldbus.setBitMask', setBitMask) + +local function setSpecificBitMaskBit(values) + local value = false + local pos = tonumber(values[2]) + if values[1] == 'true' then + value = true + end + if pos then + fieldbus_Model.boolBitMask[pos+1] = value + fieldbus_Model.bitMask = fieldbus_Model.helperFuncs.toNumber(fieldbus_Model.boolBitMask) + Script.notifyEvent("Fieldbus_OnNewStatusBitMask", fieldbus_Model.bitMask) + --print(fieldbus_Model.bitMask) + end +end +Script.serveFunction('CSK_Fieldbus.setSpecificBitMaskBit', setSpecificBitMaskBit) + +local function writeControlBitsInViaUI() + fieldbus_Model.writeControlBitsIn(fieldbus_Model.controlBitsToWrite, fieldbus_Model.bitMask) +end +Script.serveFunction('CSK_Fieldbus.writeControlBitsInViaUI', writeControlBitsInViaUI) + +local function setAddressingMode(mode) + if FieldBus.Config.EtherNetIP.setAddressingMode(mode) then + _G.logger:fine(string.format("ENIP: Setting addressing mode to '%s' succeeded", mode)) + else + _G.logger:severe(string.format("ENIP: Setting addressing mode to '%s' failed", mode)) + end + fieldbus_Model.parameters.etherNetIP.addressingMode = mode + Script.notifyEvent("Fieldbus_OnNewStatusEtherNetIPAddressingMode", fieldbus_Model.parameters.etherNetIP.addressingMode) + fieldbus_Model.getInfo() +end +Script.serveFunction('CSK_Fieldbus.setAddressingMode', setAddressingMode) + +local function setEtherNetIPIP(ip) + if ip ~= "0.0.0.0" then + -- Convert IPs and netmask to numbers + local a, b, c, d = ip:match("(%d+)%.(%d+)%.(%d+)%.(%d+)") + local ipNum = tonumber(a) * 256^3 + tonumber(b) * 256^2 + tonumber(c) * 256 + tonumber(d) + a, b, c, d = fieldbus_Model.parameters.etherNetIP.netmask:match("(%d+)%.(%d+)%.(%d+)%.(%d+)") + local nmNum = tonumber(a) * 256^3 + tonumber(b) * 256^2 + tonumber(c) * 256 + tonumber(d) + a, b, c, d = fieldbus_Model.parameters.etherNetIP.gateway:match("(%d+)%.(%d+)%.(%d+)%.(%d+)") + local gwNum = tonumber(a) * 256^3 + tonumber(b) * 256^2 + tonumber(c) * 256 + tonumber(d) + + -- Perform bitwise AND between IP address and netmask to get the network address + local networkAddress = ipNum & nmNum + local gwNetworkAddress = gwNum & nmNum + + -- Check if IP address and gateway are in the same network + if networkAddress == gwNetworkAddress then + _G.logger:fine(nameOfModule .. ": Preset EtherNet/IP IP to: " .. tostring(ip)) + else + _G.logger:fine(nameOfModule .. ": Store old valid EtherNet/IP IP address since current preset IP address is out of range with Gw address.") + fieldbus_Model.parameters.etherNetIP.ipAddress2 = fieldbus_Model.parameters.etherNetIP.ipAddress + end + fieldbus_Model.parameters.etherNetIP.ipAddress = ip + Script.notifyEvent("Fieldbus_OnNewStatusEtherNetIPIPAddress", fieldbus_Model.parameters.etherNetIP.ipAddress) +else + _G.logger:warning(nameOfModule .. ": Can't set EtherNet/IP IP address to '0.0.0.0'") + fieldbus_Model.info ="Can't set EtherNet/IP IP to '0.0.0.0'" + Script.notifyEvent("Fieldbus_OnNewStatusFieldbusInfo", fieldbus_Model.info) + end + Script.notifyEvent("Fieldbus_OnNewStatusEtherNetIPIPAddress", fieldbus_Model.parameters.etherNetIP.ipAddress) +end +Script.serveFunction('CSK_Fieldbus.setEtherNetIPIP', setEtherNetIPIP) + +local function setEtherNetIPSubnetMask(netmask) + if netmask ~= "0.0.0.0" then + -- Convert IPs and netmask to numbers + local a, b, c, d = fieldbus_Model.parameters.etherNetIP.ipAddress:match("(%d+)%.(%d+)%.(%d+)%.(%d+)") + local ipNum = tonumber(a) * 256^3 + tonumber(b) * 256^2 + tonumber(c) * 256 + tonumber(d) + a, b, c, d = netmask:match("(%d+)%.(%d+)%.(%d+)%.(%d+)") + local nmNum = tonumber(a) * 256^3 + tonumber(b) * 256^2 + tonumber(c) * 256 + tonumber(d) + a, b, c, d = fieldbus_Model.parameters.etherNetIP.gateway:match("(%d+)%.(%d+)%.(%d+)%.(%d+)") + local gwNum = tonumber(a) * 256^3 + tonumber(b) * 256^2 + tonumber(c) * 256 + tonumber(d) + + -- Perform bitwise AND between IP address and netmask to get the network address + local networkAddress = ipNum & nmNum + local gwNetworkAddress = gwNum & nmNum + + -- Check if IP address and gateway are in the same network + if networkAddress == gwNetworkAddress then + _G.logger:fine(nameOfModule .. ": Preset EtherNet/IP Netmask: " .. tostring(netmask)) + else + _G.logger:fine(nameOfModule .. ": Store old valid EtherNet/IP Netmask since current preset IP address is out of range with Gw address.") + fieldbus_Model.parameters.etherNetIP.netmask2 = fieldbus_Model.parameters.etherNetIP.netmask + end + fieldbus_Model.parameters.etherNetIP.netmask = netmask + Script.notifyEvent("Fieldbus_OnNewStatusEtherNetIPSubnetMask", fieldbus_Model.parameters.etherNetIP.netmask) + else + _G.logger:warning(nameOfModule .. ": Can't set EtherNet/IP Netmask to '0.0.0.0'") + fieldbus_Model.info ="Can't set EtherNet/IP Netmask to '0.0.0.0'" + Script.notifyEvent("Fieldbus_OnNewStatusFieldbusInfo", fieldbus_Model.info) + end + Script.notifyEvent("Fieldbus_OnNewStatusEtherNetIPSubnetMask", fieldbus_Model.parameters.etherNetIP.netmask) +end +Script.serveFunction('CSK_Fieldbus.setEtherNetIPSubnetMask', setEtherNetIPSubnetMask) + +local function setEtherNetIPGateway(gateway) + -- Convert IPs and netmask to numbers + local a, b, c, d = fieldbus_Model.parameters.etherNetIP.ipAddress:match("(%d+)%.(%d+)%.(%d+)%.(%d+)") + local ipNum = tonumber(a) * 256^3 + tonumber(b) * 256^2 + tonumber(c) * 256 + tonumber(d) + a, b, c, d = fieldbus_Model.parameters.etherNetIP.netmask:match("(%d+)%.(%d+)%.(%d+)%.(%d+)") + local nmNum = tonumber(a) * 256^3 + tonumber(b) * 256^2 + tonumber(c) * 256 + tonumber(d) + a, b, c, d = gateway:match("(%d+)%.(%d+)%.(%d+)%.(%d+)") + local gwNum = tonumber(a) * 256^3 + tonumber(b) * 256^2 + tonumber(c) * 256 + tonumber(d) + + -- Perform bitwise AND between IP address and netmask to get the network address + local networkAddress = ipNum & nmNum + local gwNetworkAddress = gwNum & nmNum + + -- Check if IP address and gateway are in the same network + if networkAddress == gwNetworkAddress then + _G.logger:fine(nameOfModule .. ": Preset EtherNet/IP GW address: " .. tostring(gateway)) + else + _G.logger:fine(nameOfModule .. ": Store old valid EtherNet/IP GW address since current preset IP address is out of range with Gw address.") + fieldbus_Model.parameters.etherNetIP.gateway2 = fieldbus_Model.parameters.etherNetIP.gateway + end + fieldbus_Model.parameters.etherNetIP.gateway = gateway + Script.notifyEvent("Fieldbus_OnNewStatusEtherNetIPGateway", fieldbus_Model.parameters.etherNetIP.gateway) +end +Script.serveFunction('CSK_Fieldbus.setEtherNetIPGateway', setEtherNetIPGateway) + +local function setEtherNetIPNameServer(nameServer) + _G.logger:fine(nameOfModule .. ": Preset EtherNet/IP Primary name server: " .. tostring(nameServer)) + fieldbus_Model.parameters.etherNetIP.nameServer = nameServer + Script.notifyEvent("Fieldbus_OnNewStatusEtherNetIPNameServer", fieldbus_Model.parameters.etherNetIP.nameServer) +end +Script.serveFunction('CSK_Fieldbus.setEtherNetIPNameServer', setEtherNetIPNameServer) + +local function setEtherNetIPNameServer2(nameServer2) + _G.logger:fine(nameOfModule .. ": Preset EtherNet/IP Secondary name server: " .. tostring(nameServer2)) + fieldbus_Model.parameters.etherNetIP.nameServer2 = nameServer2 + Script.notifyEvent("Fieldbus_OnNewStatusEtherNetIPNameServer2", fieldbus_Model.parameters.etherNetIP.nameServer2) +end +Script.serveFunction('CSK_Fieldbus.setEtherNetIPNameServer2', setEtherNetIPNameServer2) + +local function setEtherNetIPDomainName(domainName) + _G.logger:fine(nameOfModule .. ": Preset EtherNet/IP domain name: " .. tostring(domainName)) + fieldbus_Model.parameters.etherNetIP.domainName = domainName + Script.notifyEvent("Fieldbus_OnNewStatusEtherNetIPDomainName", fieldbus_Model.parameters.etherNetIP.domainName) +end +Script.serveFunction('CSK_Fieldbus.setEtherNetIPDomainName', setEtherNetIPDomainName) + +local function getEtherNetIPConfig() + _G.logger:fine(nameOfModule .. ": Get EtherNet/IP configuration.") + fieldbus_Model.getEtherNetIPConfig() +end +Script.serveFunction('CSK_Fieldbus.getEtherNetIPConfig', getEtherNetIPConfig) + +local function setEtherNetIPConfig() + _G.logger:fine(nameOfModule .. ": Activate preset EtherNet/IP configuration.") + fieldbus_Model.setEtherNetIPConfig() +end +Script.serveFunction('CSK_Fieldbus.setEtherNetIPConfig', setEtherNetIPConfig) + +-- ProfinetIO + +local function setProfinetIODeviceName(name) + _G.logger:fine(nameOfModule .. ": Preset device name to: " .. tostring(name)) + fieldbus_Model.parameters.profinetIO.deviceName = name +end +Script.serveFunction('CSK_Fieldbus.setProfinetIODeviceName', setProfinetIODeviceName) + +local function setProfinetIOIP(ip) + _G.logger:fine(nameOfModule .. ": Preset ProfinetIO IP to: " .. tostring(ip)) + fieldbus_Model.parameters.profinetIO.ipAddress = ip +end +Script.serveFunction('CSK_Fieldbus.setProfinetIOIP', setProfinetIOIP) + +local function setProfinetIOSubnetMask(netmask) + _G.logger:fine(nameOfModule .. ": Preset ProfinetIO subnet mask: " .. tostring(netmask)) + fieldbus_Model.parameters.profinetIO.netmask = netmask +end +Script.serveFunction('CSK_Fieldbus.setProfinetIOSubnetMask', setProfinetIOSubnetMask) + +local function setProfinetIOGateway(gateway) + _G.logger:fine(nameOfModule .. ": Preset ProfinetIO gateway: " .. tostring(gateway)) + fieldbus_Model.parameters.profinetIO.gateway = gateway +end +Script.serveFunction('CSK_Fieldbus.setProfinetIOGateway', setProfinetIOGateway) + +local function getProfinetIOConfig() + _G.logger:fine(nameOfModule .. ": Get ProfinetIO configuration.") + fieldbus_Model.getProfinetIOConfigInfo() +end +Script.serveFunction('CSK_Fieldbus.getProfinetIOConfig', getProfinetIOConfig) + +local function applyProfinetIOConfig() + _G.logger:fine(nameOfModule .. ": Activate preset ProfinetIO configuration.") + fieldbus_Model.applyProfinetIOConfig() +end +Script.serveFunction('CSK_Fieldbus.applyProfinetIOConfig', applyProfinetIOConfig) + +local function storeProfinetIOConfig() + _G.logger:fine(nameOfModule .. ": Store ProfinetIO configuration.") + fieldbus_Model.storeProfinetIOConfig() +end +Script.serveFunction('CSK_Fieldbus.storeProfinetIOConfig', storeProfinetIOConfig) + +local function setDAPIMDescriptor(descriptor) + _G.logger:fine(nameOfModule .. ": Preset DAP IM descriptoer to: " .. tostring(descriptor)) + fieldbus_Model.parameters.profinetIO.dapImDescriptor = descriptor +end +Script.serveFunction('CSK_Fieldbus.setDAPIMDescriptor', setDAPIMDescriptor) + +local function setDAPIMInstallationDate(date) + _G.logger:fine(nameOfModule .. ": Preset DAP IM installation date to: " .. tostring(date)) + fieldbus_Model.parameters.profinetIO.dapImInstallDate = date +end +Script.serveFunction('CSK_Fieldbus.setDAPIMInstallationDate', setDAPIMInstallationDate) + +local function setDAPIMTagFunction(tag) + _G.logger:fine(nameOfModule .. ": Preset DAP IM function tag to: " .. tostring(tag)) + fieldbus_Model.parameters.profinetIO.tagFunction = tag +end +Script.serveFunction('CSK_Fieldbus.setDAPIMTagFunction', setDAPIMTagFunction) + +local function setDAPIMTagLocation(location) + _G.logger:fine(nameOfModule .. ": Preset DAP IM location tag to: " .. tostring(location)) + fieldbus_Model.parameters.profinetIO.tagLocation = location +end +Script.serveFunction('CSK_Fieldbus.setDAPIMTagLocation', setDAPIMTagLocation) + +local function getDAPIMConfig() + _G.logger:fine(nameOfModule .. ": Get ProfinetIO DAP I&M data.") + fieldbus_Model.getDapImConfigInfo() +end +Script.serveFunction('CSK_Fieldbus.getDAPIMConfig', getDAPIMConfig) + +local function setDAPIMConfig() + _G.logger:fine(nameOfModule .. ": Set ProfinetIO DAP I&M data.") + fieldbus_Model.setDapImConfig() +end +Script.serveFunction('CSK_Fieldbus.setDAPIMConfig', setDAPIMConfig) + +local function storeDAPIMData() + _G.logger:fine(nameOfModule .. ": Store DAP I&M data.") + fieldbus_Model.storeDapImData() +end +Script.serveFunction('CSK_Fieldbus.storeDAPIMData', storeDAPIMData) + +local function setDataNameTransmit(name) + _G.logger:fine(nameOfModule .. ": Preset DataName to transmit: " .. tostring(name)) + fieldbus_Model.dataNameTransmit = name +end +Script.serveFunction('CSK_Fieldbus.setDataNameTransmit', setDataNameTransmit) + +local function setDataNameReceive(name) + _G.logger:fine(nameOfModule .. ": Preset DataName to receive: " .. tostring(name)) + fieldbus_Model.dataNameReceive = name +end +Script.serveFunction('CSK_Fieldbus.setDataNameReceive', setDataNameReceive) + +local function setRegisteredEventTransmit(eventName) + _G.logger:fine(nameOfModule .. ": Preset event to register for transmit data to: " .. tostring(eventName)) + fieldbus_Model.registerEventTransmit = eventName +end +Script.serveFunction('CSK_Fieldbus.setRegisteredEventTransmit', setRegisteredEventTransmit) + +local function setConvertDataTransmit(status) + _G.logger:fine(nameOfModule .. ": Preset status to convert transmit data to: " .. tostring(status)) + fieldbus_Model.convertDataTransmit = status +end +Script.serveFunction('CSK_Fieldbus.setConvertDataTransmit', setConvertDataTransmit) + +local function setConvertDataReceive(status) + _G.logger:fine(nameOfModule .. ": Preset status to convert received data to: " .. tostring(status)) + fieldbus_Model.convertDataReceive = status +end +Script.serveFunction('CSK_Fieldbus.setConvertDataReceive', setConvertDataReceive) + +local function setBigEndianTransmit(status) + _G.logger:fine(nameOfModule .. ": Preset status of big endian of transmit data to: " .. tostring(status)) + fieldbus_Model.bigEndianTransmit = status +end +Script.serveFunction('CSK_Fieldbus.setBigEndianTransmit', setBigEndianTransmit) + +local function setBigEndianReceive(status) + _G.logger:fine(nameOfModule .. ": Preset status of big endian of received data to: " .. tostring(status)) + fieldbus_Model.bigEndianReceive = status +end +Script.serveFunction('CSK_Fieldbus.setBigEndianReceive', setBigEndianReceive) + +local function setDataTypeTransmit(dataType) + _G.logger:fine(nameOfModule .. ": Preset data type of transmit to: " .. tostring(dataType)) + fieldbus_Model.dataTypeTransmit = dataType +end +Script.serveFunction('CSK_Fieldbus.setDataTypeTransmit', setDataTypeTransmit) + +local function setDataTypeReceive(dataType) + _G.logger:fine(nameOfModule .. ": Preset type or received data to: " .. tostring(dataType)) + fieldbus_Model.dataTypeReceive = dataType +end +Script.serveFunction('CSK_Fieldbus.setDataTypeReceive', setDataTypeReceive) + +local function editDataToTransfer(dataName) + + Script.deregister(fieldbus_Model.parameters.registeredEventsTransmit[dataName], fieldbus_Model.dataUpdateFunctions[dataName]) + + fieldbus_Model.parameters.registeredEventsTransmit[dataName] = fieldbus_Model.registerEventTransmit + fieldbus_Model.parameters.convertDataTypesTransmit[dataName] = fieldbus_Model.convertDataTransmit + fieldbus_Model.parameters.bigEndiansTransmit[dataName] = fieldbus_Model.bigEndianTransmit + fieldbus_Model.parameters.dataTypesTransmit[dataName] = fieldbus_Model.dataTypeTransmit + + fieldbus_Model.registerToEvent(fieldbus_Model.parameters.registeredEventsTransmit[dataName], tonumber(fieldbus_Model.selectedDataTransmit), dataName) + + fieldbus_Model.totalDataSizeTransmit = fieldbus_Model.helperFuncs.getDataSize(fieldbus_Model.parameters.dataTypesTransmit) + Script.notifyEvent('Fieldbus_OnNewStatusLogMessage', "New transmit data size = " .. tostring(fieldbus_Model.totalDataSizeTransmit)) +end + +local function addDataToTransmitViaUI() + if fieldbus_Model.selectedDataTransmit == '' then + if not fieldbus_Model.parameters.registeredEventsTransmit[fieldbus_Model.dataNameTransmit] then + _G.logger:fine(nameOfModule .. ": Add data to transmit.") + fieldbus_Model.addDataTransmit(fieldbus_Model.dataNameTransmit, fieldbus_Model.registerEventTransmit, fieldbus_Model.convertDataTransmit, fieldbus_Model.dataTypeTransmit, fieldbus_Model.bigEndianTransmit) + else + _G.logger:warning(nameOfModule .. ": Transmit data with this name already exists.") + end + else + local posName = fieldbus_Model.parameters.dataNamesTransmit[tonumber(fieldbus_Model.selectedDataTransmit)] + if posName == fieldbus_Model.dataNameTransmit then + _G.logger:fine(nameOfModule .. ": Edit data to transmit.") + editDataToTransfer(posName) + else + _G.logger:info(nameOfModule .. ": Not possible to rename transmit data. Delete first and add new one...") + fieldbus_Model.dataNameTransmit = fieldbus_Model.parameters.dataNamesTransmit[tonumber(fieldbus_Model.selectedDataTransmit)] + Script.notifyEvent("Fieldbus_OnNewStatusDataNameTransmit", fieldbus_Model.dataNameTransmit) + end + end + fieldbus_Model.totalDataSizeTransmit = fieldbus_Model.helperFuncs.getDataSize(fieldbus_Model.parameters.dataTypesTransmit) + Script.notifyEvent('Fieldbus_OnNewStatusLogMessage', "New transmit data size = " .. tostring(fieldbus_Model.totalDataSizeTransmit)) + handleOnExpiredTmrFieldbus() +end +Script.serveFunction('CSK_Fieldbus.addDataToTransmitViaUI', addDataToTransmitViaUI) + +local function deleteDataToTransmitViaUI() + if fieldbus_Model.selectedDataTransmit ~= '' and tonumber(fieldbus_Model.selectedDataTransmit) then + _G.logger:fine(nameOfModule .. ": Delete data entry no." .. fieldbus_Model.selectedDataTransmit) + fieldbus_Model.removeDataTransmit(tonumber(fieldbus_Model.selectedDataTransmit)) + fieldbus_Model.selectedDataTransmit = '' + end + fieldbus_Model.totalDataSizeTransmit = fieldbus_Model.helperFuncs.getDataSize(fieldbus_Model.parameters.dataTypesTransmit) + Script.notifyEvent('Fieldbus_OnNewStatusLogMessage', "New transmit data size = " .. tostring(fieldbus_Model.totalDataSizeTransmit)) + handleOnExpiredTmrFieldbus() +end +Script.serveFunction('CSK_Fieldbus.deleteDataToTransmitViaUI', deleteDataToTransmitViaUI) + +local function dataTransmitPositionUp() + if fieldbus_Model.selectedDataTransmit ~= '' and tonumber(fieldbus_Model.selectedDataTransmit) then + fieldbus_Model.dataTransmitPositionUp(tonumber(fieldbus_Model.selectedDataTransmit)) + end + handleOnExpiredTmrFieldbus() +end +Script.serveFunction('CSK_Fieldbus.dataTransmitPositionUp', dataTransmitPositionUp) + +local function dataTransmitPositionDown() + if fieldbus_Model.selectedDataTransmit ~= '' and tonumber(fieldbus_Model.selectedDataTransmit) then + fieldbus_Model.dataTransmitPositionDown(tonumber(fieldbus_Model.selectedDataTransmit)) + end + handleOnExpiredTmrFieldbus() +end +Script.serveFunction('CSK_Fieldbus.dataTransmitPositionDown', dataTransmitPositionDown) + +--- Function to edit data to receive +---@param dataName string Name/identifier of data to update +local function editDataToReceive(dataName) + + fieldbus_Model.parameters.convertDataTypesReceive[dataName] = fieldbus_Model.convertDataReceive + fieldbus_Model.parameters.bigEndiansReceive[dataName] = fieldbus_Model.bigEndianReceive + fieldbus_Model.parameters.dataTypesReceive[dataName] = fieldbus_Model.dataTypeReceive + + fieldbus_Model.totalDataSizeReceive = fieldbus_Model.helperFuncs.getDataSize(fieldbus_Model.parameters.dataTypesReceive) + Script.notifyEvent('Fieldbus_OnNewStatusLogMessage', "New data size to receive = " .. tostring(fieldbus_Model.totalDataSizeReceive)) +end + +local function addDataToReceiveViaUI() + if fieldbus_Model.selectedDataReceive == '' then + if not fieldbus_Model.parameters.convertDataTypesReceive[fieldbus_Model.dataNameReceive] then + _G.logger:fine(nameOfModule .. ": Add data to receive.") + fieldbus_Model.addDataReceive(fieldbus_Model.dataNameReceive, fieldbus_Model.convertDataReceive, fieldbus_Model.dataTypeReceive, fieldbus_Model.bigEndianReceive) + else + _G.logger:warning(nameOfModule .. ": Data with this name already exists.") + end + else + local posName = fieldbus_Model.parameters.dataNamesReceive[tonumber(fieldbus_Model.selectedDataReceive)] + if posName == fieldbus_Model.dataNameReceive then + _G.logger:fine(nameOfModule .. ": Edit data to receive.") + editDataToReceive(posName) + else + _G.logger:info(nameOfModule .. ": Not possible to rename data. Delete first and add new one...") + fieldbus_Model.dataNameReceive = fieldbus_Model.parameters.dataNamesReceive[tonumber(fieldbus_Model.selectedDataReceive)] + Script.notifyEvent("Fieldbus_OnNewStatusDataNameReceive", fieldbus_Model.dataNameReceive) + end + end + fieldbus_Model.totalDataSizeReceive = fieldbus_Model.helperFuncs.getDataSize(fieldbus_Model.parameters.dataTypesReceive) + Script.notifyEvent('Fieldbus_OnNewStatusLogMessage', "New data size to receive = " .. tostring(fieldbus_Model.totalDataSizeReceive)) + handleOnExpiredTmrFieldbus() +end +Script.serveFunction('CSK_Fieldbus.addDataToReceiveViaUI', addDataToReceiveViaUI) + +local function deleteDataToReceiveViaUI() + if fieldbus_Model.selectedDataReceive ~= '' and tonumber(fieldbus_Model.selectedDataReceive) then + _G.logger:fine(nameOfModule .. ": Delete receive data entry no." .. fieldbus_Model.selectedDataReceive) + fieldbus_Model.removeDataReceive(tonumber(fieldbus_Model.selectedDataReceive)) + fieldbus_Model.selectedDataReceive = '' + end + fieldbus_Model.totalDataSizeReceive = fieldbus_Model.helperFuncs.getDataSize(fieldbus_Model.parameters.dataTypesReceive) + Script.notifyEvent('Fieldbus_OnNewStatusLogMessage', "New data size to receive = " .. tostring(fieldbus_Model.totalDataSizeReceive)) + handleOnExpiredTmrFieldbus() +end +Script.serveFunction('CSK_Fieldbus.deleteDataToReceiveViaUI', deleteDataToReceiveViaUI) + +local function dataReceivePositionUp() + if fieldbus_Model.selectedDataReceive ~= '' and tonumber(fieldbus_Model.selectedDataReceive) then + fieldbus_Model.dataReceivePositionUp(tonumber(fieldbus_Model.selectedDataReceive)) + end + handleOnExpiredTmrFieldbus() +end +Script.serveFunction('CSK_Fieldbus.dataReceivePositionUp', dataReceivePositionUp) + +local function dataReceivePositionDown() + if fieldbus_Model.selectedDataReceive ~= '' and tonumber(fieldbus_Model.selectedDataReceive) then + fieldbus_Model.dataReceivePositionDown(tonumber(fieldbus_Model.selectedDataReceive)) + end + handleOnExpiredTmrFieldbus() +end +Script.serveFunction('CSK_Fieldbus.dataReceivePositionDown', dataReceivePositionDown) + +--- Function to check if selection in UIs DynamicTable can find related pattern +---@param selection string Full text of selection +---@param pattern string Pattern to search for +local function checkSelection(selection, pattern) + if selection ~= "" then + local _, pos = string.find(selection, pattern) + if pos == nil then + else + pos = tonumber(pos) + if pattern ~= '"selected":true' then + local endPos = string.find(selection, '"', pos+1) + local tempSelection = string.sub(selection, pos+1, endPos-1) + if tempSelection ~= nil and tempSelection ~= '-' then + return tempSelection + end + else + return '' + end + end + end + return nil +end + +local function selectDataTransmitViaUI(selection) + local tempSelection = checkSelection(selection, '"DTC_IDTransmit":"') + if tempSelection then + local isSelected = checkSelection(selection, '"selected":true') + if isSelected then + _G.logger:fine(nameOfModule .. ": Selected data no." .. tostring(tempSelection)) + fieldbus_Model.selectedDataTransmit = tempSelection + + local tempName = fieldbus_Model.parameters.dataNamesTransmit[tonumber(tempSelection)] + + fieldbus_Model.dataNameTransmit = tempName + fieldbus_Model.registerEventTransmit = fieldbus_Model.parameters.registeredEventsTransmit[tempName] + fieldbus_Model.convertDataTransmit = fieldbus_Model.parameters.convertDataTypesTransmit[tempName] + fieldbus_Model.bigEndianTransmit = fieldbus_Model.parameters.bigEndiansTransmit[tempName] + fieldbus_Model.dataTypeTransmit = fieldbus_Model.parameters.dataTypesTransmit[tempName] + + Script.notifyEvent("Fieldbus_OnNewStatusDataNameTransmit", fieldbus_Model.dataNameTransmit) + Script.notifyEvent("Fieldbus_OnNewStatusRegisteredEventTransmit", fieldbus_Model.registerEventTransmit) + Script.notifyEvent("Fieldbus_OnNewStatusConvertDataTransmit", fieldbus_Model.convertDataTransmit) + Script.notifyEvent("Fieldbus_OnNewStatusBigEndianTransmit", fieldbus_Model.bigEndianTransmit) + Script.notifyEvent("Fieldbus_OnNewStatusDataTypeTransmit", fieldbus_Model.dataTypeTransmit) + else + fieldbus_Model.selectedDataTransmit = '' + end + handleOnExpiredTmrFieldbus() + end +end +Script.serveFunction('CSK_Fieldbus.selectDataTransmitViaUI', selectDataTransmitViaUI) + +local function selectDataReceiveViaUI(selection) + local tempSelection = checkSelection(selection, '"DTC_IDReceive":"') + if tempSelection then + local isSelected = checkSelection(selection, '"selected":true') + if isSelected then + _G.logger:fine(nameOfModule .. ": Selected receive data no." .. tostring(tempSelection)) + fieldbus_Model.selectedDataReceive = tempSelection + + local tempName = fieldbus_Model.parameters.dataNamesReceive[tonumber(tempSelection)] + + fieldbus_Model.dataNameReceive = tempName + fieldbus_Model.convertDataReceive = fieldbus_Model.parameters.convertDataTypesReceive[tempName] + fieldbus_Model.bigEndianReceive = fieldbus_Model.parameters.bigEndiansReceive[tempName] + fieldbus_Model.dataTypeReceive = fieldbus_Model.parameters.dataTypesReceive[tempName] + + Script.notifyEvent("Fieldbus_OnNewStatusDataNameReceive", fieldbus_Model.dataNameReceive) + Script.notifyEvent("Fieldbus_OnNewStatusConvertDataReceive", fieldbus_Model.convertDataReceive) + Script.notifyEvent("Fieldbus_OnNewStatusBigEndianReceive", fieldbus_Model.bigEndianReceive) + Script.notifyEvent("Fieldbus_OnNewStatusDataTypeReceive", fieldbus_Model.dataTypeReceive) + else + fieldbus_Model.selectedDataReceive = '' + end + handleOnExpiredTmrFieldbus() + end +end +Script.serveFunction('CSK_Fieldbus.selectDataReceiveViaUI', selectDataReceiveViaUI) + +local function setTempTransmitData(data) + fieldbus_Model.tempDataTransmit = data +end +Script.serveFunction('CSK_Fieldbus.setTempTransmitData', setTempTransmitData) + +local function triggerTempDataViaUI() + if fieldbus_Model.selectedDataTransmit ~= '' then + + local value + if fieldbus_Model.parameters.dataTypesTransmit[fieldbus_Model.dataNameTransmit] == 'CHAR' or fieldbus_Model.parameters.dataTypesTransmit[fieldbus_Model.dataNameTransmit] == 'STRING' then + value = fieldbus_Model.tempDataTransmit + else + value = tonumber(fieldbus_Model.tempDataTransmit) + end + + -- Temporarily activate conversion + local tempConvertStatus = fieldbus_Model.parameters.convertDataTypesTransmit[fieldbus_Model.dataNameTransmit] + fieldbus_Model.parameters.convertDataTypesTransmit[fieldbus_Model.dataNameTransmit] = true + fieldbus_Model.dataUpdateFunctions[fieldbus_Model.dataNameTransmit](value) + fieldbus_Model.parameters.convertDataTypesTransmit[fieldbus_Model.dataNameTransmit] = tempConvertStatus + else + _G.logger:fine(nameOfModule .. ": No data position selected.") + end + handleOnExpiredTmrFieldbus() +end +Script.serveFunction('CSK_Fieldbus.triggerTempDataViaUI', triggerTempDataViaUI) + +local function resetTransmitData() + fieldbus_Model.resetTransmitData() + handleOnExpiredTmrFieldbus() +end +Script.serveFunction('CSK_Fieldbus.resetTransmitData', resetTransmitData) -- ***************************************************************** -- 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)) fieldbus_Model.parametersName = name end Script.serveFunction("CSK_Fieldbus.setParameterName", setParameterName) @@ -148,7 +958,7 @@ local function sendParameters() if fieldbus_Model.persistentModuleAvailable then CSK_PersistentData.addParameter(fieldbus_Model.helperFuncs.convertTable2Container(fieldbus_Model.parameters), fieldbus_Model.parametersName) CSK_PersistentData.setModuleParameterName(nameOfModule, fieldbus_Model.parametersName, fieldbus_Model.parameterLoadOnReboot) - _G.logger:info(nameOfModule .. ": Send Fieldbus parameters with name '" .. fieldbus_Model.parametersName .. "' to CSK_PersistentData module.") + _G.logger:fine(nameOfModule .. ": Send Fieldbus parameters with name '" .. fieldbus_Model.parametersName .. "' to CSK_PersistentData module.") CSK_PersistentData.saveData() else _G.logger:warning(nameOfModule .. ": CSK_PersistentData module not available.") @@ -156,15 +966,44 @@ local function sendParameters() end Script.serveFunction("CSK_Fieldbus.sendParameters", sendParameters) -local function loadParameters() +--- Function to register on events provided e.g. by other modules (optionally react on timer started after loading of persistent parameters) +local function registerToEvents() + for key, value in ipairs(fieldbus_Model.parameters.dataNamesTransmit) do + fieldbus_Model.addEmptySpace(fieldbus_Model.parameters.dataTypesTransmit[value]) + fieldbus_Model.registerToEvent(fieldbus_Model.parameters.registeredEventsTransmit[value], key, value) + end +end +Timer.register(tmrWaitForSetupOfOtherModules, 'OnExpired', registerToEvents) + +local function loadParameters(wait) if fieldbus_Model.persistentModuleAvailable then local data = CSK_PersistentData.getParameter(fieldbus_Model.parametersName) if data then _G.logger:info(nameOfModule .. ": Loaded parameters from CSK_PersistentData module.") fieldbus_Model.parameters = fieldbus_Model.helperFuncs.convertContainer2Table(data) - -- If something needs to be configured/activated with new loaded data, place this here: - -- ... - -- ... + + -- If something needs to be configured/activated with new loaded data, place this here + local fbMode = Parameters.get('FBmode') + if (fbMode == 0 and fieldbus_Model.fbMode ~= 'DISABLED') or (fbMode == 1 and fieldbus_Model.fbMode ~= 'ProfinetIO') or ( fbMode == 2 and fieldbus_Model.fbMode ~= 'EtherNetIP') then + _G.logger:warning(nameOfModule .. ": Current fieldbus protocol of device differs from parameter setup. Please restart device.") + return + end + + fieldbus_Model.deregisterAllEvents() + + if not wait then + registerToEvents() + end + + fieldbus_Model.dataReceived = {} + for key, value in ipairs(fieldbus_Model.parameters.dataNamesReceive) do + fieldbus_Model.dataReceived[value] = '-' + fieldbus_Model.serveReceiveEvent(value) + end + + if fieldbus_Model.parameters.active == true then + fieldbus_Model.openCommunication() + end CSK_Fieldbus.pageCalled() else @@ -178,7 +1017,7 @@ Script.serveFunction("CSK_Fieldbus.loadParameters", loadParameters) local function setLoadOnReboot(status) fieldbus_Model.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)) end Script.serveFunction("CSK_Fieldbus.setLoadOnReboot", setLoadOnReboot) @@ -197,10 +1036,13 @@ local function handleOnInitialDataLoaded() if parameterName then fieldbus_Model.parametersName = parameterName fieldbus_Model.parameterLoadOnReboot = loadOnReboot + else + fieldbus_Model.create() end if fieldbus_Model.parameterLoadOnReboot then - loadParameters() + tmrWaitForSetupOfOtherModules:start() -- Start timer to wait for events which could be provided by other modules + loadParameters(true) end Script.notifyEvent('Fieldbus_OnDataLoadedOnReboot') end diff --git a/CSK_Module_Fieldbus/scripts/Communication/Fieldbus/Fieldbus_Model.lua b/CSK_Module_Fieldbus/scripts/Communication/Fieldbus/Fieldbus_Model.lua index a9886c7..ef98737 100644 --- a/CSK_Module_Fieldbus/scripts/Communication/Fieldbus/Fieldbus_Model.lua +++ b/CSK_Module_Fieldbus/scripts/Communication/Fieldbus/Fieldbus_Model.lua @@ -31,26 +31,133 @@ setFieldbus_ModelHandle(fieldbus_Model) --Loading helper functions if needed fieldbus_Model.helperFuncs = require('Communication/Fieldbus/helper/funcs') --- Optionally check if specific API was loaded via ---[[ -if _G.availableAPIs.specific then --- ... doSomething ... +-- Check if specific API was loaded via +fieldbus_Model.moduleActive = _G.availableAPIs.specific + +-- Check if needed CROWN is available on device +if FieldBus == nil then + fieldbus_Model.moduleActive = false + _G.logger:warning(nameOfModule .. ': CROWN is not available. Module is not supported...') end -]] ---[[ --- Create parameters / instances for this module -fieldbus_Model.object = Image.create() -- Use any AppEngine CROWN -fieldbus_Model.counter = 1 -- Short docu of variable -fieldbus_Model.varA = 'value' -- Short docu of variable ---... -]] +local fbMode = Parameters.get('FBmode') +if fbMode == 1 then + fieldbus_Model.fbMode = 'ProfinetIO' +elseif fbMode == 2 then + fieldbus_Model.fbMode = 'EtherNetIP' +else + fieldbus_Model.fbMode = 'DISABLED' +end + +fieldbus_Model.handle = nil -- Fieldbus handle +fieldbus_Model.opened = false -- Status if fieldbus handle was opended. +fieldbus_Model.currentStatus = 'CLOSED' -- Current status of the fieldbus communication. +fieldbus_Model.info = 'No info available.' -- Information of the fieldbus component. + +fieldbus_Model.controlBitsIn = 0 -- Current value of the control bits transmitted to the PLC. +fieldbus_Model.boolControlBitsIn = {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false} -- Status of ControlBitsIN as boolean table +fieldbus_Model.controlBitsOut = 0 -- Current value of the control bits received from the PLC. +fieldbus_Model.boolControlBitsOut = {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false} -- Status of ControlBitsOUT as boolean table +fieldbus_Model.controlBitsToWrite = 0 -- Preset control bits to write. +fieldbus_Model.boolControlBitsToWrite = {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false} -- Status of ControlBitsIN to write as boolean table +fieldbus_Model.bitMask = 65535 -- Preset bitMask to use for controlBits. +fieldbus_Model.boolBitMask = {true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true} -- Status of mask of ControlBitsIN to write as boolean table + +fieldbus_Model.port = 'P1' -- Fieldbus port, e.g. 'P2' + +fieldbus_Model.dataUpdateFunctions = {} -- Functions to update transmit data +fieldbus_Model.transmissionDataList = '' -- List of data entries for transmission + +fieldbus_Model.selectedDataTransmit = '' -- Number of selected data entry in UI table +fieldbus_Model.selectedDataReceive = '' -- Number of selected data entry in UI table +fieldbus_Model.tempDataTransmit = '' -- Data to temporarily set for selected transmit data + +fieldbus_Model.dataToTransmit = {} -- Preset data to transmit (binary) +fieldbus_Model.readableDataToTransmit = {} -- Readbale preset data to transmit +fieldbus_Model.fullDataToTransmit = '' -- Full binary string including all data to transmit +fieldbus_Model.dataNameTransmit = 'DataName' -- Preconfigured name of data to setup for transmission +fieldbus_Model.registerEventTransmit = 'OtherModule.OnNewEvent' -- Preconfigured event to register to receive transmit data +fieldbus_Model.convertDataTransmit = true -- Preconfigured status if received data should be converted before transmission +fieldbus_Model.bigEndianTransmit = true -- Preconfigured status of endianness for data to transmit, little endian per default +fieldbus_Model.dataTypeTransmit = 'U_INT1' -- Preconfigured data type of data to setup for transmission +fieldbus_Model.totalDataSizeTransmit = 0 -- Sum of data size to transmit + +fieldbus_Model.dataReceived = {} -- Holding received values per data entry +fieldbus_Model.dataNameReceive = 'DataName' -- Preconfigured name of data to setup for receiving +fieldbus_Model.convertDataReceive = true -- Preconfigured status if received data should be converted before transmission +fieldbus_Model.bigEndianReceive = true -- Preconfigured status of endianness for data to transmit, little endian per default +fieldbus_Model.dataTypeReceive = 'U_INT1' -- Preconfigured data type of data to setup for transmission +fieldbus_Model.totalDataSizeReceive = 0 -- Sum of data size to transmit -- Parameters to be saved permanently if wanted fieldbus_Model.parameters = {} ---fieldbus_Model.parameters.paramA = 'paramA' -- Short docu of variable ---fieldbus_Model.parameters.paramB = 123 -- Short docu of variable ---... +fieldbus_Model.parameters.protocol = 'DISABLED' -- Type of fieldbus communication, e.g. 'DISABLED' (0) / 'ProfinetIO' (1) / 'EtherNetIP' (2) / 'ETHERCAT' (not available yet) +fieldbus_Model.parameters.createMode = 'EXPLICIT_OPEN' -- or 'EXPLICIT_OPEN', AUTOMATIC_OPEN +fieldbus_Model.parameters.transmissionMode = 'RAW' -- or 'RAW', CONFIRMED_MESSAGING +fieldbus_Model.parameters.active = false -- Status if fieldbus connection should be established + +fieldbus_Model.parameters.dataNamesTransmit = {} -- List of names/identifiers of data entries to transmit +fieldbus_Model.parameters.registeredEventsTransmit = {} -- List of names of event to receive data to transmit +fieldbus_Model.parameters.convertDataTypesTransmit = {} -- Status if received data needs to be converted to binary or is already binary +fieldbus_Model.parameters.dataTypesTransmit = {} -- Data types of values to transmit +fieldbus_Model.parameters.bigEndiansTransmit = {} -- Little endian per default + +fieldbus_Model.parameters.dataNamesReceive = {} -- List of names/identifiers of data entries to transmit +fieldbus_Model.parameters.convertDataTypesReceive = {} -- Status if received data needs to be converted to binary or is already binary +fieldbus_Model.parameters.dataTypesReceive = {} -- Data types of values to transmit +fieldbus_Model.parameters.bigEndiansReceive = {} -- Little endian per default + +fieldbus_Model.parameters.etherNetIP = {} +fieldbus_Model.parameters.etherNetIP.storageRequestDataPath = '/public/FieldBus/EtherNetIP/StorageData.dat' -- Path to store fieldbus storage data. +fieldbus_Model.parameters.etherNetIP.addressingMode = 'STATIC' -- or 'DHCP' / 'BOOTP' +fieldbus_Model.parameters.etherNetIP.ipAddress = '192.168.0.1' -- IP address +fieldbus_Model.parameters.etherNetIP.ipAddress2 = '192.168.0.1' -- IP address +fieldbus_Model.parameters.etherNetIP.netmask = '255.255.255.0' -- Subnet mask +fieldbus_Model.parameters.etherNetIP.netmask2 = '255.255.255.0' -- Subnet mask +fieldbus_Model.parameters.etherNetIP.gateway = '0.0.0.0' -- Gateway address +fieldbus_Model.parameters.etherNetIP.gateway2 = '0.0.0.0' -- Gateway address +fieldbus_Model.parameters.etherNetIP.nameServer = '0.0.0.0' -- Primary name server +fieldbus_Model.parameters.etherNetIP.nameServer2 = '0.0.0.0' -- Secondary name server +fieldbus_Model.parameters.etherNetIP.domainName = '' -- Domain name +fieldbus_Model.parameters.etherNetIP.macAddress = '' -- MAC address of fieldbus implementation. + +fieldbus_Model.parameters.profinetIO = {} +fieldbus_Model.parameters.profinetIO.storageRequestDataPath = '/public/FieldBus/ProfinetIO/StorageData.dat' -- Path to store fieldbus storage data. +fieldbus_Model.parameters.profinetIO.deviceName = '' -- Device name +fieldbus_Model.parameters.profinetIO.remanent = false -- Status if the network configuration tool sets the current name of the device permanently (true), that is, it will be reloaded after a restart of the device. +fieldbus_Model.parameters.profinetIO.ipAddress = '0.0.0.0' -- IP address +fieldbus_Model.parameters.profinetIO.netmask = '255.255.255.0' -- Subnet mask +fieldbus_Model.parameters.profinetIO.gateway = '0.0.0.0' -- Gateway address +fieldbus_Model.parameters.profinetIO.macAddress = '' -- MAC address of fieldbus implementation. + +fieldbus_Model.parameters.profinetIO.dapImDescriptor = 'Descriptor' -- The descriptor (a.k.a. 'comment') as used for the DAP’s (device access point) I&M3 data. +fieldbus_Model.parameters.profinetIO.dapImHardwareRev = 0 -- Hardware revision as used for the DAP (device access point) used in the I&M0 data. +fieldbus_Model.parameters.profinetIO.dapImInstallDate = 'YYYY-MM-DD' -- Installation date as used for the DAP’s (device access point) I&M2 data. + +-- Software revision for the DAP (device access point) used in the I&M0 data. +fieldbus_Model.parameters.profinetIO.dapImSoftwareRevPrefix = 'Prefix' -- Prefix character of the software revision of this I&M0 data. +fieldbus_Model.parameters.profinetIO.dapImSoftwareRevFuncEnhancement = 0 -- Functional enhancement identifier of the software revision of this I&M0 data. +fieldbus_Model.parameters.profinetIO.dapImSoftwareRevBugFix = 0 -- Bug fix identifier of the software revision of this I&M0 data. +fieldbus_Model.parameters.profinetIO.dapImSoftwareRevInternalChange = 0 -- Internal change identifier of the software revision of this I&M0 data. + +fieldbus_Model.parameters.profinetIO.dapImTagFunction = 'PlantDesignation' -- Function tag (a.k.a. 'plant designation') as used for the DAP’s (device access point) I&M1 data. +fieldbus_Model.parameters.profinetIO.dapImTagLocation = 'LocationIdentifier' -- Location tag (a.k.a. 'location identifier') as used for the DAP’s (device access point) I&M1 data. + +--- Function to create folder if it does not exists +---@param folder string Name of folder to create if it does not exists already +local function createFolder(folder) + local folderExists = File.isdir(folder) + if not folderExists then + local suc = File.mkdir(folder) + if not suc then + _G.logger:warning(nameOfModule .. ': Not possible to create folder on device.') + end + end +end +-- Create default folders for the module +createFolder('/public/FieldBus') +createFolder('/public/FieldBus/EtherNetIP') +createFolder('/public/FieldBus/ProfinetIO') --************************************************************************** --********************** End Global Scope ********************************** @@ -58,15 +165,873 @@ fieldbus_Model.parameters = {} --**********************Start Function Scope ******************************* --************************************************************************** +--- Function to get various information about the fieldbus, its componentes and internals. +local function getInfo() + fieldbus_Model.info = FieldBus.getInfo(fieldbus_Model.handle) + Script.notifyEvent("Fieldbus_OnNewStatusFieldbusInfo", fieldbus_Model.helperFuncs.jsonLine2Table(fieldbus_Model.info)) +end +fieldbus_Model.getInfo = getInfo + +--- Function to get status information about the fieldbus. +local function getStatus() + fieldbus_Model.currentStatus = FieldBus.getStatus(fieldbus_Model.handle) + Script.notifyEvent("Fieldbus_OnNewStatusFieldbusStatus", fieldbus_Model.currentStatus) +end +fieldbus_Model.getStatus = getStatus + +----------------------- +-- EtherNet/IP relevant +----------------------- + + +local function getEtherNetIPConfig() + local ipAddress, netmask, gateway, nameServer, nameServer2, domainName = FieldBus.Config.EtherNetIP.getInterfaceConfig() + if ipAddress ~= '0.0.0.0' and netmask ~= '0.0.0.0' then + fieldbus_Model.parameters.etherNetIP.ipAddress = ipAddress + Script.notifyEvent("Fieldbus_OnNewStatusEtherNetIPIPAddress", fieldbus_Model.parameters.etherNetIP.ipAddress) + fieldbus_Model.parameters.etherNetIP.netmask = netmask + Script.notifyEvent("Fieldbus_OnNewStatusEtherNetIPGateway", fieldbus_Model.parameters.etherNetIP.gateway) + fieldbus_Model.parameters.etherNetIP.gateway = gateway + Script.notifyEvent("Fieldbus_OnNewStatusEtherNetIPSubnetMask", fieldbus_Model.parameters.etherNetIP.netmask) + fieldbus_Model.parameters.etherNetIP.nameServer = nameServer + Script.notifyEvent("Fieldbus_OnNewStatusEtherNetIPNameServer", fieldbus_Model.parameters.etherNetIP.nameServer) + fieldbus_Model.parameters.etherNetIP.nameServer2 = nameServer2 + Script.notifyEvent("Fieldbus_OnNewStatusEtherNetIPNameServer2", fieldbus_Model.parameters.etherNetIP.nameServer2) + fieldbus_Model.parameters.etherNetIP.domainName = domainName + Script.notifyEvent("Fieldbus_OnNewStatusEtherNetIPDomainName", fieldbus_Model.parameters.etherNetIP.domainName) + end + if fieldbus_Model.handle then + getInfo() + getStatus() + else + fieldbus_Model.info ="Fieldbus handle not created yet." + Script.notifyEvent("Fieldbus_OnNewStatusFieldbusInfo", fieldbus_Model.info) + end +end +fieldbus_Model.getEtherNetIPConfig = getEtherNetIPConfig + +-- Function to set EtherNet/IP config +local function setEtherNetIPConfig() + if fieldbus_Model.parameters.etherNetIP.ipAddress ~= '0.0.0.0' and fieldbus_Model.parameters.etherNetIP.netmask ~= '0.0.0.0' then + -- Convert IPs and netmask to numbers + local a, b, c, d = fieldbus_Model.parameters.etherNetIP.ipAddress:match("(%d+)%.(%d+)%.(%d+)%.(%d+)") + local ipNum = tonumber(a) * 256^3 + tonumber(b) * 256^2 + tonumber(c) * 256 + tonumber(d) + a, b, c, d = fieldbus_Model.parameters.etherNetIP.netmask:match("(%d+)%.(%d+)%.(%d+)%.(%d+)") + local nmNum = tonumber(a) * 256^3 + tonumber(b) * 256^2 + tonumber(c) * 256 + tonumber(d) + a, b, c, d = fieldbus_Model.parameters.etherNetIP.gateway:match("(%d+)%.(%d+)%.(%d+)%.(%d+)") + local gwNum = tonumber(a) * 256^3 + tonumber(b) * 256^2 + tonumber(c) * 256 + tonumber(d) + + -- Perform bitwise AND between IP address and Netmask to get the network address + local networkAddress = ipNum & nmNum + local gwNetworkAddress = gwNum & nmNum + + -- Check if IP address and GW address are in the same network + if networkAddress == gwNetworkAddress then + if FieldBus.Config.EtherNetIP.setInterfaceConfig( + fieldbus_Model.parameters.etherNetIP.ipAddress, + fieldbus_Model.parameters.etherNetIP.netmask, + fieldbus_Model.parameters.etherNetIP.gateway, + fieldbus_Model.parameters.etherNetIP.nameServer, + fieldbus_Model.parameters.etherNetIP.nameServer2, + fieldbus_Model.parameters.etherNetIP.domainName + ) then + if fieldbus_Model.handle then + getInfo() + getStatus() + else + fieldbus_Model.info ="Fieldbus handle not created yet." + Script.notifyEvent("Fieldbus_OnNewStatusFieldbusInfo", fieldbus_Model.info) + end + else + print(fieldbus_Model.currentStatus) + _G.logger:warning("Cannot set the Ethernet connection. The configuration is not valid.") + fieldbus_Model.info = "Cannot set the Ethernet connection. The configuration is not valid." + end + else + -- Convert backup IP address to numbers + a, b, c, d = fieldbus_Model.parameters.etherNetIP.ipAddress2:match("(%d+)%.(%d+)%.(%d+)%.(%d+)") + ipNum = tonumber(a) * 256^3 + tonumber(b) * 256^2 + tonumber(c) * 256 + tonumber(d) + + -- Perform bitwise AND between backup IP address and Netmask to get the network address + networkAddress = ipNum & nmNum + gwNetworkAddress = gwNum & nmNum + + -- Check if IP address and gateway are in the same network + if networkAddress == gwNetworkAddress then + if FieldBus.Config.EtherNetIP.setInterfaceConfig( + fieldbus_Model.parameters.etherNetIP.ipAddress2, + fieldbus_Model.parameters.etherNetIP.netmask, + fieldbus_Model.parameters.etherNetIP.gateway, + fieldbus_Model.parameters.etherNetIP.nameServer, + fieldbus_Model.parameters.etherNetIP.nameServer2, + fieldbus_Model.parameters.etherNetIP.domainName + ) then + if fieldbus_Model.handle then + getInfo() + getStatus() + else + fieldbus_Model.info ="Fieldbus handle not created yet." + Script.notifyEvent("Fieldbus_OnNewStatusFieldbusInfo", fieldbus_Model.info) + end + else + print(fieldbus_Model.currentStatus) + _G.logger:warning("Cannot set the Ethernet connection. The configuration is not valid.") + fieldbus_Model.info = "Cannot set the Ethernet connection. The configuration is not valid." + end + else + _G.logger:warning("Cannot set the Ethernet connection. The configuration is not valid. IP address and GW address out of range.") + fieldbus_Model.info = "Cannot set the Ethernet connection. The configuration is not valid. IP address and GW address out of range." + end + end + else + _G.logger:warning("IP Address / NetMask = " .. tostring(fieldbus_Model.parameters.etherNetIP.ipAddress) .. " / " .. tostring(fieldbus_Model.parameters.etherNetIP.netmask)) + fieldbus_Model.info = "Cannot set the Ethernet connection. IP Address / NetMask = " .. tostring(fieldbus_Model.parameters.etherNetIP.ipAddress) .. " / " .. tostring(fieldbus_Model.parameters.etherNetIP.netmask) + end + Script.notifyEvent("Fieldbus_OnNewStatusFieldbusInfo", fieldbus_Model.info) +end +fieldbus_Model.setEtherNetIPConfig = setEtherNetIPConfig + + +--- +---@param addressingMode FieldBus.Config.EtherNetIP.AddressingMode Addressing mode for the ip parameters. +local function handleOnAddressingModeChanged(addressingMode) + _G.logger:fine("New EtherNet/IP Addressing Mode: " .. addressingMode) + fieldbus_Model.parameters.etherNetIP.addressingMode = addressingMode + Script.notifyEvent("Fieldbus_OnNewStatusEtherNetIPAddressingMode", fieldbus_Model.parameters.etherNetIP.addressingMode) +end +Script.register('FieldBus.Config.EtherNetIP.OnAddressingModeChanged', handleOnAddressingModeChanged) + + +-- Function to react on received EtherNet/IP interface config. +---@param ipAddress string IP address. +---@param netmask string Subnetmask. +---@param gateway string Gateway IP address. +---@param nameServer? string Primary name server. +---@param nameServer2? string Secondary name server. +---@param domainName? string Default domain name. +local function handleOnEthernetIPInterfaceConfigChanged(ipAddress, netmask, gateway, nameServer, nameServer2, domainName) + if ipAddress ~= '0.0.0.0' and netmask ~= '0.0.0.0' then + _G.logger:fine("New EtherNet/IP interface config: " .. ipAddress) +-- _G.logger:finer("IP Address / NetMask = " .. tostring(ipAddress) .. ' / ' .. tostring(netmask)) + fieldbus_Model.parameters.etherNetIP.ipAddress = ipAddress + fieldbus_Model.parameters.etherNetIP.netmask = netmask +-- _G.logger:finer("Gateway = " .. tostring(gateway)) + fieldbus_Model.parameters.etherNetIP.gateway = gateway + if nameServer and nameServer2 then +-- _G.logger:finer("Nameserver 1 / 2 = " .. tostring(nameServer) .. ' / ' .. tostring(nameServer2)) + fieldbus_Model.parameters.etherNetIP.nameServer = nameServer + fieldbus_Model.parameters.etherNetIP.nameServer2 = nameServer2 + else + if nameServer then +-- _G.logger:finer("Nameserver 1 = " .. tostring(nameServer)) + fieldbus_Model.parameters.etherNetIP.nameServer = nameServer + end + if nameServer2 then +-- _G.logger:finer("Nameserver 2 = " .. tostring(nameServer2)) + fieldbus_Model.parameters.etherNetIP.nameServer2 = nameServer2 + end + end + if domainName then +-- _G.logger:finer("DomainName = " .. tostring(domainName)) + fieldbus_Model.parameters.etherNetIP.domainName = domainName + end + elseif not fieldbus_Model.parameters.etherNetIP.addressingMode == 'STATIC' then + _G.logger:warning("IP Address / NetMask = " .. tostring(ipAddress) .. ' / ' .. tostring(netmask)) + end + fieldbus_Model.parameters.etherNetIP.macAddress = FieldBus.Config.EtherNetIP.getMACAddress() + if nil == fieldbus_Model.parameters.etherNetIP.macAddress then + _G.logger:warning("ENIP: FieldBus.Config.EtherNetIP.getMACAddress returned NIL!!!") + fieldbus_Model.parameters.etherNetIP.macAddress = '' + end + getInfo() + getStatus() +end + +-- Function to react on FieldbusStoreRequest +---@param storageHandle FieldBus.StorageRequest Object containing the data to be saved or loaded +local function handleOnEtherNetIPFieldbusStorageRequest(storageHandle) + local storageOperation = FieldBus.StorageRequest.getOperation(storageHandle) + --_G.logger:fine("ENIP: onFieldbusStorageRequest event received, operation: " .. storageOperation) + local dataToStore = FieldBus.StorageRequest.getData(storageHandle) + local dataFromFile = nil + local storageResult = false + if storageOperation == "SAVE" then --FieldBus.StorageRequest.StorageOperation.Save + -- store in a file + local handle = File.open(fieldbus_Model.parameters.etherNetIP.storageRequestDataPath, 'wb') + if handle then + File.write(handle, dataToStore) + File.close(handle) + storageResult = true + else + _G.logger:severe(string.format("Failed to open file for saving of storage data!")) + end + end + if storageOperation == "LOAD" then --FieldBus.StorageRequest.StorageOperation.Load + -- load from a file + local handle = File.open(fieldbus_Model.parameters.etherNetIP.storageRequestDataPath, 'rb') + if handle then + dataFromFile = File.read(handle) + File.close(handle) + storageResult = FieldBus.StorageRequest.setData(storageHandle, dataFromFile) + if storageResult == false then + _G.logger:severe(string.format("Setting data at storage request failed")) + end + else + _G.logger:severe(string.format("Failed to open file to load storage data from!")) + storageResult = false + end + end + FieldBus.StorageRequest.notifyResult(storageHandle, storageResult) + CSK_Fieldbus.pageCalled() +end + +----------------------- +-- ProfinetIO relevant +----------------------- + +--- Function to apply ProfinetIO config +local function applyProfinetIOConfig() + local suc = FieldBus.Config.ProfinetIO.applyConfig() + _G.logger:fine("Success of ApplyConfig = " .. tostring(suc)) +end +fieldbus_Model.applyProfinetIOConfig = applyProfinetIOConfig + +--- Function to store ProfinetIO config +local function storeProfinetIOConfig() + local suc = FieldBus.Config.ProfinetIO.storeConfig() + _G.logger:fine('Store config = ' .. tostring(suc)) +end +fieldbus_Model.storeProfinetIOConfig = storeProfinetIOConfig + +--- Function to react on received ProfinetIO DeviceName. +---@param deviceName string Currently active name of the device +---@param remanent bool True if the network configuration tool sets the current name of the device permanently, that is, it will be reloaded after a restart of the device. +local function handleOnDeviceNameChanged(deviceName, remanent) + _G.logger:fine("Received DeviceName info!") + _G.logger:fine("Name = " .. tostring(deviceName)) + _G.logger:fine("Remanent = " .. tostring(remanent)) + + fieldbus_Model.parameters.profinetIO.deviceName = deviceName + fieldbus_Model.parameters.profinetIO.remanent = remanent + + FieldBus.Config.ProfinetIO.setDeviceName(fieldbus_Model.parameters.profinetIO.deviceName) + applyProfinetIOConfig() + + if remanent == true then + storeProfinetIOConfig() + end + + CSK_Fieldbus.pageCalled() + +end + +-- Function to react on received ProfinetIO interface config. +---@param ipAddress string Currently active (applied) IP address +---@param subnetMask string Currently active (applied) subnet mask +---@param gateway string Currently active (applied) gateway address +---@param remanent bool True if the network configuration tool sets the current IP address settings permanently, that is, it will be reloaded after a restart of the device. +local function handleOnProfinetIOInterfaceConfigChanged(ipAddress, subnetMask, gateway, remanent) + _G.logger:fine("New ProfinetIO interface config:") + _G.logger:fine("IP Address / NetMask = " .. tostring(ipAddress) .. ' / ' .. tostring(subnetMask)) + _G.logger:fine("Gateway = " .. tostring(gateway)) + _G.logger:fine("Remanent = " .. tostring(remanent)) + + fieldbus_Model.parameters.profinetIO.ipAddress = ipAddress + fieldbus_Model.parameters.profinetIO.subnetMask = subnetMask + fieldbus_Model.parameters.profinetIO.gateway = gateway + fieldbus_Model.parameters.profinetIO.remanent = remanent + + FieldBus.Config.ProfinetIO.setInterfaceConfig(fieldbus_Model.parameters.profinetIO.ipAddress, fieldbus_Model.parameters.profinetIO.subnetMask, fieldbus_Model.parameters.profinetIO.gateway) + + applyProfinetIOConfig() + + if remanent == true then + storeProfinetIOConfig() + end + CSK_Fieldbus.pageCalled() + +end + +--- Function to get DAP I&M Config info +local function getDapImConfigInfo() + fieldbus_Model.parameters.profinetIO.dapImDescriptor = FieldBus.Config.ProfinetIO.getDapImDescriptor() + fieldbus_Model.parameters.profinetIO.dapImHardwareRev = FieldBus.Config.ProfinetIO.getDapImHardwareRev() + fieldbus_Model.parameters.profinetIO.dapImInstallDate = FieldBus.Config.ProfinetIO.getDapImInstallDate() + fieldbus_Model.parameters.profinetIO.dapImSoftwareRevPrefix, fieldbus_Model.parameters.profinetIO.dapImSoftwareRevFuncEnhancement, fieldbus_Model.parameters.profinetIO.dapImSoftwareRevBugFix, fieldbus_Model.parameters.profinetIO.dapImSoftwareRevInternalChange = FieldBus.Config.ProfinetIO.getDapImSoftwareRev() + fieldbus_Model.parameters.profinetIO.tagFunction = FieldBus.Config.ProfinetIO.getDapImTagFunction() + fieldbus_Model.parameters.profinetIO.tagLocation = FieldBus.Config.ProfinetIO.getDapImTagLocation() +end +fieldbus_Model.getDapImConfigInfo = getDapImConfigInfo + +--- Function to set DAP I&M config +local function setDapImConfig() + FieldBus.Config.ProfinetIO.setDapImDescriptor(fieldbus_Model.parameters.profinetIO.dapImDescriptor) + FieldBus.Config.ProfinetIO.setDapImInstallDate(fieldbus_Model.parameters.profinetIO.dapImInstallDate) + FieldBus.Config.ProfinetIO.setDapImTagFunction(fieldbus_Model.parameters.profinetIO.tagFunction) + FieldBus.Config.ProfinetIO.setDapImTagLocation(fieldbus_Model.parameters.profinetIO.tagLocation) +end +fieldbus_Model.setDapImConfig = setDapImConfig + +--- Function to store DAP I&M config +local function storeDapImData() + local suc = FieldBus.Config.ProfinetIO.storeDapImData() +end +fieldbus_Model.storeDapImData = storeDapImData + +--- Function to get DAP I&M config +local function getProfinetIOConfigInfo() + fieldbus_Model.parameters.profinetIO.deviceName = FieldBus.Config.ProfinetIO.getDeviceName() + fieldbus_Model.parameters.profinetIO.ipAddress, fieldbus_Model.parameters.profinetIO.subnetMask, fieldbus_Model.parameters.profinetIO.gateway, fieldbus_Model.parameters.profinetIO.remanent = FieldBus.Config.ProfinetIO.getInterfaceConfig() + + local macAddress = FieldBus.Config.ProfinetIO.getMACAddress('INTERFACE') + if macAddress then + fieldbus_Model.parameters.profinetIO.macAddress = macAddress + else + fieldbus_Model.parameters.profinetIO.macAddress = '' + end + getDapImConfigInfo() + + CSK_Fieldbus.pageCalled() + +end +fieldbus_Model.getProfinetIOConfigInfo = getProfinetIOConfigInfo + +--- Function to react on FieldbusStoreRequest +---@param storageHandle FieldBus.StorageRequest Object containing the data to be saved or loaded +local function handleOnProfinetIOFieldbusStorageRequest(storageHandle) + local operation = FieldBus.StorageRequest.getOperation(storageHandle) + _G.logger:fine('StorageRequest operation = ' .. tostring(operation)) + if operation == 'LOAD' then + -- Check if file exists + local dataFile = File.open(fieldbus_Model.parameters.profinetIO.storageRequestDataPath, 'rb') + local setSuc = false + + if dataFile then + local data = File.read(dataFile) + File.close(dataFile) + setSuc = FieldBus.StorageRequest.setData(storageHandle, data) + _G.logger:fine("Setting data = " .. tostring(setSuc)) + getProfinetIOConfigInfo() + else + _G.logger:info("Not able to LOAD data.") + end + + if setSuc then + FieldBus.StorageRequest.notifyResult(storageHandle, true) + else + FieldBus.StorageRequest.notifyResult(storageHandle, false) + end + + elseif operation == 'SAVE' then + local data = FieldBus.StorageRequest.getData(storageHandle) + local dataFile = File.open(fieldbus_Model.parameters.profinetIO.storageRequestDataPath, 'wb') + + local suc = File.write(dataFile, data) + File.close(dataFile) + _G.logger:fine("Result to write SR = " .. tostring(suc)) + + if suc then + FieldBus.StorageRequest.notifyResult(storageHandle, true) + else + FieldBus.StorageRequest.notifyResult(storageHandle, false) + end + CSK_Fieldbus.pageCalled() + end +end + +--TODO only for SIM2000Eco... +-------------------------------------- --[[ --- Some internal code docu for local used function to do something ----@param content auto Some info text if function is not already served -local function doSomething(content) - _G.logger:info(nameOfModule .. ": Do something") - fieldbus_Model.counter = fieldbus_Model.counter + 1 +local function getProtocolInfo() + protocol = FieldBus.Config.getProtocol() +end +fieldbus_Model.getProtocolInfo = getProtocolInfo + +local function setProtocolConfig() + Fieldbus_Controller.Config.setProtocol() end -fieldbus_Model.doSomething = doSomething +fieldbus_Model.setProtocolConfig = setProtocolConfig ]] +-------------------------------------- + +----------------------- +-- General functions -- +----------------------- + +-- Function to react on received data of PLC. +---@param data binary Received data. +local function handleOnNewData(data) + local dataSize = #data + _G.logger:fine("Received " .. tostring(dataSize) .. " Bytes = " .. tostring(data)) + Script.notifyEvent('Fieldbus_OnNewStatusLogMessage', "Received " .. tostring(dataSize) .. " Bytes") + Script.notifyEvent("Fieldbus_OnNewStatusReceivedData", data) + + local startPos = 1 + for _, value in ipairs(fieldbus_Model.parameters.dataNamesReceive) do + local dataSize = fieldbus_Model.helperFuncs.getTypeSize(fieldbus_Model.parameters.dataTypesReceive[value]) + if dataSize ~= nil then + local dataPart = string.sub(data, startPos, startPos+dataSize-1) + + -- check if value needs to be unpacked first + if fieldbus_Model.parameters.convertDataTypesReceive[value] and dataPart ~= nil then + dataPart = fieldbus_Model.helperFuncs.convertFromBinary(dataPart, fieldbus_Model.parameters.dataTypesReceive[value], fieldbus_Model.parameters.bigEndiansReceive[value]) + end + + fieldbus_Model.dataReceived[value] = dataPart + Script.notifyEvent('Fieldbus_OnNewData_' .. value, dataPart) + startPos = startPos + dataSize + else + break + end + end + Script.notifyEvent("Fieldbus_OnNewStatusDataReceivingList", fieldbus_Model.helperFuncs.createJsonListReceiveData(fieldbus_Model.parameters.dataNamesReceive, fieldbus_Model.parameters.dataTypesReceive, fieldbus_Model.parameters.convertDataTypesReceive, fieldbus_Model.parameters.bigEndiansReceive, fieldbus_Model.dataReceived, fieldbus_Model.selectedDataReceive)) +end + +--- Function to react on received ctrl bits of PLC. +---@param ctrlBits int ctrl bits out +local function handleOnControlBitsOutChanged(ctrlBits) + _G.logger:fine("New CtrlBitsOut = " .. tostring(ctrlBits)) + fieldbus_Model.controlBitsOut = ctrlBits + Script.notifyEvent("Fieldbus_OnNewStatusControlBitsOut", fieldbus_Model.controlBitsOut) + fieldbus_Model.boolControlBitsOut = fieldbus_Model.helperFuncs.toBits(fieldbus_Model.controlBitsOut) + Script.notifyEvent("Fieldbus_OnNewStatusControlBitsOutTable", fieldbus_Model.boolControlBitsOut) +end + +--TODO +local function deregisterFieldbusEvents() + if fieldbus_Model.handle then + --FieldBus.deregister(fieldbus_Model.handle, 'OnStatusChanged', handleOnStatusChanged) + FieldBus.deregister(fieldbus_Model.handle, 'OnNewData', handleOnNewData) + FieldBus.deregister(fieldbus_Model.handle, 'OnControlBitsOutChanged', handleOnControlBitsOutChanged) + end + Script.deregister('FieldBus.Config.EtherNetIP.OnFieldbusStorageRequest', handleOnEtherNetIPFieldbusStorageRequest) + Script.deregister('FieldBus.Config.EtherNetIP.OnAddressingModeChanged', handleOnAddressingModeChanged) + Script.deregister('FieldBus.Config.EtherNetIP.OnInterfaceConfigChanged', handleOnEthernetIPInterfaceConfigChanged) + Script.deregister('FieldBus.Config.ProfinetIO.OnFieldbusStorageRequest', handleOnProfinetIOFieldbusStorageRequest) + Script.deregister('FieldBus.Config.ProfinetIO.OnDeviceNameChanged', handleOnDeviceNameChanged) + Script.deregister('FieldBus.Config.ProfinetIO.OnInterfaceConfigChanged', handleOnProfinetIOInterfaceConfigChanged) +end + +-- Function to react on new state of the fieldbus communication. +---@param status FieldBus.Status New state of the fieldbus communication. +local function handleOnStatusChanged(status) + _G.logger:info("New status = " .. tostring(status)) + fieldbus_Model.currentStatus = status + Script.notifyEvent("Fieldbus_OnNewStatusFieldbusStatus", fieldbus_Model.currentStatus) + getInfo() + if fieldbus_Model.currentStatus == 'CLOSED' then + fieldbus_Model.opened = false + deregisterFieldbusEvents() + Script.releaseObject(fieldbus_Model.handle) + fieldbus_Model.handle = nil + collectgarbage() + elseif status == 'OPENED' then + fieldbus_Model.opened = true + CSK_Fieldbus.setEtherNetIPConfig() + elseif status == 'ONLINE' then + fieldbus_Model.opened = true + elseif status == 'OFFLINE' or status == 'ERROR' then + fieldbus_Model.opened = false + end + Script.notifyEvent("Fieldbus_OnNewStatusFieldbusActive", fieldbus_Model.opened) +end + +--- Function to create fieldbus communication handle +local function create() + if fieldbus_Model.fbMode ~= 'DISABLED' then + if not fieldbus_Model.handle then + fieldbus_Model.handle = FieldBus.create(fieldbus_Model.parameters.createMode) + if fieldbus_Model.handle then + FieldBus.setMode(fieldbus_Model.handle, fieldbus_Model.parameters.transmissionMode) + _G.logger:fine("Successfully created Fieldbus handle.") + getInfo() + getStatus() + + deregisterFieldbusEvents() + FieldBus.register(fieldbus_Model.handle, 'OnStatusChanged', handleOnStatusChanged) + FieldBus.register(fieldbus_Model.handle, 'OnNewData', handleOnNewData) + FieldBus.register(fieldbus_Model.handle, 'OnControlBitsOutChanged', handleOnControlBitsOutChanged) + if fieldbus_Model.fbMode == 'EtherNetIP' then + Script.register('FieldBus.Config.EtherNetIP.OnFieldbusStorageRequest', handleOnEtherNetIPFieldbusStorageRequest) + Script.register('FieldBus.Config.EtherNetIP.OnAddressingModeChanged', handleOnAddressingModeChanged) + Script.register('FieldBus.Config.EtherNetIP.OnInterfaceConfigChanged', handleOnEthernetIPInterfaceConfigChanged) + setEtherNetIPConfig() + + elseif fieldbus_Model.fbMode == 'ProfinetIO' then + Script.register('FieldBus.Config.ProfinetIO.OnFieldbusStorageRequest', handleOnProfinetIOFieldbusStorageRequest) + Script.register('FieldBus.Config.ProfinetIO.OnDeviceNameChanged', handleOnDeviceNameChanged) + Script.register('FieldBus.Config.ProfinetIO.OnInterfaceConfigChanged', handleOnProfinetIOInterfaceConfigChanged) + + end + else + _G.logger:warning("Not able to create Fieldbus handle.") + end + else + _G.logger:fine("Handle already exists.") + end + end +end +fieldbus_Model.create = create + +--- Function to set transmission mode +---@param mode string Mode to use +local function setTransmissionMode(mode) + if fieldbus_Model.opened == false then + if fieldbus_Model.parameters.createMode == 'EXPLICIT_OPEN' and fieldbus_Model.opened ~= true then + fieldbus_Model.parameters.transmissionMode = mode + if fieldbus_Model.handle then + FieldBus.setMode(fieldbus_Model.handle, fieldbus_Model.parameters.transmissionMode) + end + else + _G.logger:info("Transmission mode only selectable if create mode is 'EXPLICIT_OPEN'.") + end + else + _G.logger:info("Cannot set mode of fieldbus, it is already open.") + end + Script.notifyEvent("Fieldbus_OnNewStatusTransmissionMode", fieldbus_Model.parameters.transmissionMode) +end +fieldbus_Model.setTransmissionMode = setTransmissionMode + +--- Function to open fieldbus communication +local function openCommunication() + local success = false + create() + fieldbus_Model.parameters.active = true + if fieldbus_Model.handle then + if fieldbus_Model.parameters.createMode == 'EXPLICIT_OPEN' then + fieldbus_Model.handle:open() + end + success = true + else + _G.logger:warning("Not able to open fieldbus communication.") + end + return success +end +fieldbus_Model.openCommunication = openCommunication + +--- Function to close fieldbus communication +local function closeCommunication() + if fieldbus_Model.handle then + fieldbus_Model.handle:close() + fieldbus_Model.parameters.active = false + end +end +fieldbus_Model.closeCommunication = closeCommunication + +--- Function to read controlBitsIn +local function readControlBitsIn() + if fieldbus_Model.handle then + fieldbus_Model.controlBitsIn = fieldbus_Model.handle:readControlBitsIn() + Script.notifyEvent("Fieldbus_OnNewStatusControlBitsIn", fieldbus_Model.controlBitsIn) + fieldbus_Model.boolControlBitsIn = fieldbus_Model.helperFuncs.toBits(fieldbus_Model.controlBitsIn) + Script.notifyEvent("Fieldbus_OnNewStatusControlBitsInTable", fieldbus_Model.boolControlBitsIn) + end +end +fieldbus_Model.readControlBitsIn = readControlBitsIn + +--- Function to read controlBitsOut +local function readControlBitsOut() + if fieldbus_Model.handle then + fieldbus_Model.controlBitsOut = fieldbus_Model.handle:readControlBitsOut() + Script.notifyEvent("Fieldbus_OnNewStatusControlBitsOut", fieldbus_Model.controlBitsOut) + fieldbus_Model.boolControlBitsOut = fieldbus_Model.helperFuncs.toBits(fieldbus_Model.controlBitsOut) + Script.notifyEvent("Fieldbus_OnNewStatusControlBitsOutTable", fieldbus_Model.boolControlBitsOut) + end +end +fieldbus_Model.readControlBitsOut = readControlBitsOut + +--- Function to transmit data +---@param data binary Data content to transmit +local function transmit(data) + if fieldbus_Model.handle then + local numberOfBytes = fieldbus_Model.handle:transmit(data) + if numberOfBytes ~= 0 then + _G.logger:fine("Send " .. tostring(numberOfBytes) .. " data Bytes.") + Script.notifyEvent('Fieldbus_OnNewStatusLogMessage', "Send " .. tostring(numberOfBytes) .. " data Bytes.") + else + _G.logger:warning("Transmit error.") + Script.notifyEvent('Fieldbus_OnNewStatusLogMessage', "Transmit error.") + end + else + _G.logger:info("No connection available to transmit.") + Script.notifyEvent('Fieldbus_OnNewStatusLogMessage', "No connection available to transmit.") + end +end +fieldbus_Model.transmit = transmit + +--- Function to write controlBitsIn +---@param controlBits int Bits to write +---@param bitMask int Mask to use for bits +local function writeControlBitsIn(controlBits, bitMask) + if fieldbus_Model.handle then + _G.logger:fine("Send controlBits") + fieldbus_Model.handle:writeControlBitsIn(controlBits, bitMask) + end +end +fieldbus_Model.writeControlBitsIn = writeControlBitsIn + +--- Function to write data to table to transmit +---@param pos int Position of data to update +---@param data auto Data content to set +local function updateTransmitData(pos, data) + --_G.logger:fine("Set data" .. tostring(pos) .. ' with data = ' .. tostring(data)) --DEBUG + fieldbus_Model.dataToTransmit[pos] = data + + fieldbus_Model.fullDataToTransmit = '' + for key, value in ipairs(fieldbus_Model.dataToTransmit) do + fieldbus_Model.fullDataToTransmit = fieldbus_Model.fullDataToTransmit .. value + end + + --DEBUG + --[[ + local readableTransmitData = '' + for key, value in ipairs(fieldbus_Model.readableDataToTransmit) do + if readableTransmitData == '' then + readableTransmitData = value + else + readableTransmitData = readableTransmitData .. ',' .. value + end + end + _G.logger:fine("Send: " .. readableTransmitData) + + -- Additional debugging + --_G.logger:fine(fieldbus_Model.fullDataToTransmit) + --_G.logger:fine(#fieldbus_Model.fullDataToTransmit) + --Script.notifyEvent('Fieldbus_OnNewStatusLogMessage', tostring(fieldbus_Model.fullDataToTransmit) .. ', Send data bytes = ' .. tostring(#fieldbus_Model.fullDataToTransmit)) + --Script.notifyEvent("Fieldbus_OnNewStatusDataToTransmit", fieldbus_Model.dataToTransmit) + ]] + + --TODO + --print(fieldbus_Model.fullDataToTransmit) + --print(#fieldbus_Model.fullDataToTransmit) + + if fieldbus_Model.currentStatus == 'ONLINE' then + transmit(fieldbus_Model.fullDataToTransmit) + end +end +fieldbus_Model.updateTransmitData = updateTransmitData + +--- Function to register to event of (other) module to receive data and to transmit/forward it +---@param eventName int Name of event to register +---@param dataPosition auto Position of data +---@param dataName string Identifier of data +local function registerToEvent(eventName, dataPosition, dataName) + + local emptyData = fieldbus_Model.helperFuncs.getEmptyBinaryContent(fieldbus_Model.parameters.dataTypesTransmit[dataName]) + if fieldbus_Model.dataToTransmit[dataPosition] then + fieldbus_Model.dataToTransmit[dataPosition] = emptyData + else + table.insert(fieldbus_Model.dataToTransmit, emptyData) + end + + if fieldbus_Model.readableDataToTransmit[dataPosition] then + fieldbus_Model.readableDataToTransmit[dataPosition] = 'empty' + else + table.insert(fieldbus_Model.readableDataToTransmit, 'empty') + end + + local function updateData(data) + _G.logger:fine("Set data" .. tostring(dataPosition) .. ' with data = ' .. tostring(data)) + fieldbus_Model.readableDataToTransmit[dataPosition] = data + + if fieldbus_Model.parameters.convertDataTypesTransmit[dataName] then + data = fieldbus_Model.helperFuncs.convertToBinary(data, fieldbus_Model.parameters.dataTypesTransmit[dataName], fieldbus_Model.parameters.bigEndiansTransmit[dataName]) + end + updateTransmitData(dataPosition, data) + end + fieldbus_Model.dataUpdateFunctions[dataName] = updateData + + Script.register(eventName, fieldbus_Model.dataUpdateFunctions[dataName]) +end +fieldbus_Model.registerToEvent = registerToEvent + +--- Function to deregister from all events for data to transmit +local function deregisterAllEvents() + for key, value in pairs(fieldbus_Model.parameters.dataNamesTransmit) do + Script.deregister(fieldbus_Model.parameters.registeredEventsTransmit[value], fieldbus_Model.dataUpdateFunctions[value]) + end + fieldbus_Model.dataToTransmit = {} + fieldbus_Model.readableDataToTransmit = {} +end +fieldbus_Model.deregisterAllEvents = deregisterAllEvents + +--- Function to register all events for data to transmit +local function registerAllEvents() + for key, value in ipairs(fieldbus_Model.parameters.dataNamesTransmit) do + registerToEvent(fieldbus_Model.parameters.registeredEventsTransmit[value], key, value) + end +end +fieldbus_Model.registerAllEvents = registerAllEvents + +--- Function to add empty value (but with correct byte size) for data to transmit +---@param dataType string Type of data +local function addEmptySpace(dataType) + -- Insert empty spaces according to dataType... + local emptyData = fieldbus_Model.helperFuncs.getEmptyBinaryContent(dataType) + table.insert(fieldbus_Model.dataToTransmit, emptyData) + table.insert(fieldbus_Model.readableDataToTransmit, 'empty') +end +fieldbus_Model.addEmptySpace = addEmptySpace + +--- Function to add new data entry to transmit +---@param dataName string Name/identifier of data +---@param eventName string Name of event to register +---@param convert bool Status if incoming value needs to be converted to binary +---@param dataType string Type of data +---@param bigEndian bool Type of endianess +local function addDataTransmit(dataName, eventName, convert, dataType, bigEndian) + table.insert(fieldbus_Model.parameters.dataNamesTransmit, dataName) + addEmptySpace(dataType) + + fieldbus_Model.parameters.dataTypesTransmit[dataName] = dataType + fieldbus_Model.parameters.registeredEventsTransmit[dataName] = eventName + fieldbus_Model.parameters.convertDataTypesTransmit[dataName] = convert + fieldbus_Model.parameters.bigEndiansTransmit[dataName] = bigEndian + + registerToEvent(eventName, #fieldbus_Model.parameters.dataNamesTransmit, dataName) +end +fieldbus_Model.addDataTransmit = addDataTransmit + +--- Function to serve events to notify for received values +---@param dataName string Name/identifier of data +local function serveReceiveEvent(dataName) + if not Script.isServedAsEvent('CSK_Fieldbus.OnNewData_' .. dataName) then + Script.serveEvent('CSK_Fieldbus.OnNewData_' .. dataName, 'Fieldbus_OnNewData_' .. dataName, 'auto:?') + end +end +fieldbus_Model.serveReceiveEvent = serveReceiveEvent + +--- Function to add new data entry to receive +---@param dataName string Name/identifier of data +---@param convert bool Status if incoming value needs to be converted to binary +---@param dataType string Type of data +---@param bigEndian bool Type of endianess +local function addDataReceive(dataName, convert, dataType, bigEndian) + table.insert(fieldbus_Model.parameters.dataNamesReceive, dataName) + + fieldbus_Model.parameters.dataTypesReceive[dataName] = dataType + fieldbus_Model.parameters.convertDataTypesReceive[dataName] = convert + fieldbus_Model.parameters.bigEndiansReceive[dataName] = bigEndian + fieldbus_Model.dataReceived[dataName] = '-' + + serveReceiveEvent(dataName) + +end +fieldbus_Model.addDataReceive = addDataReceive + +--- Function to remove data entry to transmit +---@param dataNo int Number of data entry +local function removeDataTransmit(dataNo) + local dataName = fieldbus_Model.parameters.dataNamesTransmit[dataNo] + + deregisterAllEvents() + + fieldbus_Model.parameters.dataTypesTransmit[dataName] = nil + fieldbus_Model.parameters.registeredEventsTransmit[dataName] = nil + fieldbus_Model.parameters.convertDataTypesTransmit[dataName] = nil + fieldbus_Model.parameters.bigEndiansTransmit[dataName] = nil + + table.remove(fieldbus_Model.parameters.dataNamesTransmit, dataNo) + registerAllEvents() + collectgarbage() +end +fieldbus_Model.removeDataTransmit = removeDataTransmit + +--- Function to remove data entry to receive +---@param dataNo int Number of data entry +local function removeDataReceive(dataNo) + local dataName = fieldbus_Model.parameters.dataNamesReceive[dataNo] + + fieldbus_Model.parameters.dataTypesReceive[dataName] = nil + fieldbus_Model.parameters.convertDataTypesReceive[dataName] = nil + fieldbus_Model.parameters.bigEndiansReceive[dataName] = nil + fieldbus_Model.dataReceived[dataName] = nil + + table.remove(fieldbus_Model.parameters.dataNamesReceive, dataNo) +end +fieldbus_Model.removeDataReceive = removeDataReceive + +--- Function to move the position of the transmit data about one position higher +---@param dataNo int Position of data +local function dataTransmitPositionUp(dataNo) + if dataNo ~= 1 then + deregisterAllEvents() + + local tempDataName = fieldbus_Model.parameters.dataNamesTransmit[dataNo] + table.insert(fieldbus_Model.parameters.dataNamesTransmit, dataNo-1, tempDataName) + table.remove(fieldbus_Model.parameters.dataNamesTransmit, dataNo+1) + collectgarbage() + + registerAllEvents() + fieldbus_Model.selectedDataTransmit = tostring(dataNo-1) + end +end +fieldbus_Model.dataTransmitPositionUp = dataTransmitPositionUp + +--- Function to move the position of the data to receive about one position higher +---@param dataNo int Position of data +local function dataReceivePositionUp(dataNo) + if dataNo ~= 1 then + + local tempDataName = fieldbus_Model.parameters.dataNamesReceive[dataNo] + table.insert(fieldbus_Model.parameters.dataNamesReceive, dataNo-1, tempDataName) + table.remove(fieldbus_Model.parameters.dataNamesReceive, dataNo+1) + collectgarbage() + + fieldbus_Model.selectedDataReceive = tostring(dataNo-1) + end +end +fieldbus_Model.dataReceivePositionUp = dataReceivePositionUp + +--- Function to move the position of the data to transmit about one position lower +---@param dataNo int Position of data +local function dataTransmitPositionDown(dataNo) + if dataNo ~= #fieldbus_Model.parameters.dataNamesTransmit then + deregisterAllEvents() + + local tempDataName = fieldbus_Model.parameters.dataNamesTransmit[dataNo] + table.remove(fieldbus_Model.parameters.dataNamesTransmit, dataNo) + table.insert(fieldbus_Model.parameters.dataNamesTransmit, dataNo+1, tempDataName) + collectgarbage() + + registerAllEvents() + fieldbus_Model.selectedDataTransmit = tostring(dataNo+1) + end +end +fieldbus_Model.dataTransmitPositionDown = dataTransmitPositionDown + +--- Function to move the position of the data to receive about one position lower +---@param dataNo int Position of data +local function dataReceivePositionDown(dataNo) + if dataNo ~= #fieldbus_Model.parameters.dataNamesReceive then + + local tempDataName = fieldbus_Model.parameters.dataNamesReceive[dataNo] + table.remove(fieldbus_Model.parameters.dataNamesReceive, dataNo) + table.insert(fieldbus_Model.parameters.dataNamesReceive, dataNo+1, tempDataName) + collectgarbage() + + fieldbus_Model.selectedDataReceive = tostring(dataNo+1) + end +end +fieldbus_Model.dataReceivePositionDown = dataReceivePositionDown + +--- Function to reset all data to transmit +local function resetTransmitData() + for key, value in ipairs(fieldbus_Model.parameters.dataNamesTransmit) do + local emptyData = fieldbus_Model.helperFuncs.getEmptyBinaryContent(fieldbus_Model.parameters.dataTypesTransmit[value]) + fieldbus_Model.dataToTransmit[key] = emptyData + fieldbus_Model.readableDataToTransmit[key] = 'empty' + end + + if fieldbus_Model.currentStatus == 'ONLINE' then + fieldbus_Model.fullDataToTransmit = '' + for key, value in ipairs(fieldbus_Model.dataToTransmit) do + fieldbus_Model.fullDataToTransmit = fieldbus_Model.fullDataToTransmit .. value + end + transmit(fieldbus_Model.fullDataToTransmit) + end +end +fieldbus_Model.resetTransmitData = resetTransmitData --************************************************************************* --********************** End Function Scope ******************************* diff --git a/CSK_Module_Fieldbus/scripts/Communication/Fieldbus/FlowConfig/Fieldbus_FlowConfig.lua b/CSK_Module_Fieldbus/scripts/Communication/Fieldbus/FlowConfig/Fieldbus_FlowConfig.lua new file mode 100644 index 0000000..9de3c7d --- /dev/null +++ b/CSK_Module_Fieldbus/scripts/Communication/Fieldbus/FlowConfig/Fieldbus_FlowConfig.lua @@ -0,0 +1,31 @@ +--***************************************************************** +-- Here you will find all the required content to provide specific +-- features of this module via the 'CSK FlowConfig'. +--***************************************************************** + +require('Communication.Fieldbus.FlowConfig.Fieldbus_OnNewData') +require('Communication.Fieldbus.FlowConfig.Fieldbus_Transmit') + +-- Reference to the fieldbus_Instances handle +local fieldbus_Instances + +--- Function to react if FlowConfig was updated +local function handleOnClearOldFlow() + if _G.availableAPIs.default and _G.availableAPIs.specific then + for i = 1, #fieldbus_Instances do + if fieldbus_Instances[i].parameters.flowConfigPriority then + CSK_Fieldbus.clearFlowConfigRelevantConfiguration() + break + end + end + end +end +Script.register('CSK_FlowConfig.OnClearOldFlow', handleOnClearOldFlow) + +--- Function to get access to the fieldbus_Instances +---@param handle handle Handle of fieldbus_Instances object +local function setFieldbus_Instances_Handle(handle) + fieldbus_Instances = handle +end + +return setFieldbus_Instances_Handle \ No newline at end of file diff --git a/CSK_Module_Fieldbus/scripts/Communication/Fieldbus/helper/checkAPIs.lua b/CSK_Module_Fieldbus/scripts/Communication/Fieldbus/helper/checkAPIs.lua index 929c733..36ea4f4 100644 --- a/CSK_Module_Fieldbus/scripts/Communication/Fieldbus/helper/checkAPIs.lua +++ b/CSK_Module_Fieldbus/scripts/Communication/Fieldbus/helper/checkAPIs.lua @@ -6,14 +6,16 @@ local availableAPIs = {} local function loadAPIs() - CSK_ModuleName = require 'API.CSK_ModuleName' + CSK_Fieldbus = require 'API.CSK_Fieldbus' Container = require 'API.Container' Engine = require 'API.Engine' + File = require 'API.File' Log = require 'API.Log' Log.Handler = require 'API.Log.Handler' Log.SharedLogger = require 'API.Log.SharedLogger' Object = require 'API.Object' + Parameters = require 'API.Parameters' Timer = require 'API.Timer' -- Check if related CSK modules are available to be used @@ -30,7 +32,11 @@ end local function loadSpecificAPIs() -- If you want to check for specific APIs/functions supported on the device the module is running, place relevant APIs here -- e.g.: - -- NTPClient = require 'API.NTPClient' + FieldBus = require 'API.FieldBus' + FieldBus.Config = require 'API.FieldBus.Config' + FieldBus.Config.EtherNetIP = require 'API.FieldBus.Config.EtherNetIP' + FieldBus.Config.ProfinetIO = require 'API.FieldBus.Config.ProfinetIO' + FieldBus.StorageRequest = require 'API.FieldBus.StorageRequest' end availableAPIs.default = xpcall(loadAPIs, debug.traceback) -- TRUE if all default APIs were loaded correctly diff --git a/CSK_Module_Fieldbus/scripts/Communication/Fieldbus/helper/funcs.lua b/CSK_Module_Fieldbus/scripts/Communication/Fieldbus/helper/funcs.lua index b1c30bf..7c6ed55 100644 --- a/CSK_Module_Fieldbus/scripts/Communication/Fieldbus/helper/funcs.lua +++ b/CSK_Module_Fieldbus/scripts/Communication/Fieldbus/helper/funcs.lua @@ -142,6 +142,423 @@ local function createStringListBySimpleTable(content) end funcs.createStringListBySimpleTable = createStringListBySimpleTable +--- Function to convert value out of binary string +---@param value binary Binary string +---@param format string Format the value is packed +---@param bigEndian bool Status if big endian is used. Otherwise little endian is active +---@return auto result Converted value +local function convertFromBinary(value, format, bigEndian) + local result + local endianness = '<' -- little endian per default + if bigEndian == true then + endianness = '>' + end + + if format == 'DOUBLE' then + result = string.unpack(endianness .. 'd', value) + elseif format == 'FLOAT' then + result = string.unpack(endianness .. 'f', value) + elseif format == 'S_BYTE' then + result = string.unpack(endianness .. 'b', value) + elseif format == 'S_INT1' then + result = string.unpack(endianness .. 'i1', value) + elseif format == 'S_INT2' then + result = string.unpack(endianness .. 'i2', value) + elseif format == 'S_INT4' then + result = string.unpack(endianness .. 'i4', value) + elseif format == 'S_INT8' then + result = string.unpack(endianness .. 'i8', value) + elseif format == 'S_LONG' then + result = string.unpack(endianness .. 'l', value) + elseif format == 'S_SHORT' then + result = string.unpack(endianness .. 'h', value) + elseif format == 'U_BYTE' then + result = string.unpack(endianness .. 'B', value) + elseif format == 'U_INT1' then + result = string.unpack(endianness .. 'I1', value) + elseif format == 'U_INT2' then + result = string.unpack(endianness .. 'I2', value) + elseif format == 'U_INT4' then + result = string.unpack(endianness .. 'I4', value) + elseif format == 'U_INT8' then + result = string.unpack(endianness .. 'I8', value) + elseif format == 'U_LONG' then + result = string.unpack(endianness .. 'L', value) + elseif format == 'U_SHORT' then + result = string.unpack(endianness .. 'H', value) + elseif format == 'CHAR' then + result = string.unpack(endianness .. 'c1', value) + --elseif format == 'STRING' then + --result = string.unpack(endianness .. 'c14xx', value) + --result = string.unpack(endianness .. 's2', value) + end + return result +end +funcs.convertFromBinary = convertFromBinary + +--- Function to convert value to binary string +---@param value auto Value to convert +---@param format string Format the value is packed +---@param bigEndian bool Status if big endian is used. Otherwise little endian is active +---@return binary result Converted value +local function convertToBinary(value, format, bigEndian) + local result + local endianness = '<' -- little endian per default + if bigEndian == true then + endianness = '>' + end + + if format == 'DOUBLE' then + result = string.pack(endianness .. 'd', value) + elseif format == 'FLOAT' then + result = string.pack(endianness .. 'f', value) + elseif format == 'S_BYTE' then + result = string.pack(endianness .. 'b', value) + elseif format == 'S_INT1' then + result = string.pack(endianness .. 'i1', value) + elseif format == 'S_INT2' then + result = string.pack(endianness .. 'i2', value) + elseif format == 'S_INT4' then + result = string.pack(endianness .. 'i4', value) + elseif format == 'S_INT8' then + result = string.pack(endianness .. 'i8', value) + elseif format == 'S_LONG' then + result = string.pack(endianness .. 'l', value) + elseif format == 'S_SHORT' then + result = string.pack(endianness .. 'h', value) + elseif format == 'U_BYTE' then + result = string.pack(endianness .. 'B', value) + elseif format == 'U_INT1' then + result = string.pack(endianness .. 'I1', value) + elseif format == 'U_INT2' then + result = string.pack(endianness .. 'I2', value) + elseif format == 'U_INT4' then + result = string.pack(endianness .. 'I4', value) + elseif format == 'U_INT8' then + result = string.pack(endianness .. 'I8', value) + elseif format == 'U_LONG' then + result = string.pack(endianness .. 'L', value) + elseif format == 'U_SHORT' then + result = string.pack(endianness .. 'H', value) + elseif format == 'CHAR' then + if #value >= 2 then + value = string.sub(value, 1, 1) + end + result = string.pack(endianness .. 'c1', value) + --elseif format == 'STRING' then + -- if #value >= 15 then + -- value = string.sub(value, 1, 14) + -- end + -- result = string.pack(endianness .. 's2', value) + end + return result +end +funcs.convertToBinary = convertToBinary + +--- Function to create binary string with size of related format and value '0' +---@param format string Format the value is packed +---@return binary result Empty value +local function getEmptyBinaryContent(format) + local result + + if format == 'DOUBLE' then + result = string.pack('d', 0) + elseif format == 'FLOAT' then + result = string.pack('f', 0) + elseif format == 'S_BYTE' then + result = string.pack('b', 0) + elseif format == 'S_INT1' then + result = string.pack('i1', 0) + elseif format == 'S_INT2' then + result = string.pack('i2', 0) + elseif format == 'S_INT4' then + result = string.pack('i4', 0) + elseif format == 'S_INT8' then + result = string.pack('i8', 0) + elseif format == 'S_LONG' then + result = string.pack('l', 0) + elseif format == 'S_SHORT' then + result = string.pack('h', 0) + elseif format == 'U_BYTE' then + result = string.pack('B', 0) + elseif format == 'U_INT1' then + result = string.pack('I1', 0) + elseif format == 'U_INT2' then + result = string.pack('I2', 0) + elseif format == 'U_INT4' then + result = string.pack('I4', 0) + elseif format == 'U_INT8' then + result = string.pack('I8', 0) + elseif format == 'U_LONG' then + result = string.pack('L', 0) + elseif format == 'U_SHORT' then + result = string.pack('H', 0) + elseif format == 'CHAR' then + result = string.pack('x', '') + --elseif format == 'STRING' then + -- result = string.pack('s2', '') + end + + return result +end +funcs.getEmptyBinaryContent = getEmptyBinaryContent + +--- Function to create a json string out of data transmission entries +---@param dataName string[] Table with names of data entries +---@param registerEvent string[] Table with names of registered events of data entries +---@param dataType string[] Table with data types of data entries +---@param convertData string[] Table with info if data needs to be converted +---@param bigEndian string[] Table with info about endianness of data entries +---@param values string[] Table with values to transmit +---@param selectedParam string Currently selected parameter +---@return string jsonstring JSON string +local function createJsonListTransmissionData(dataName, registerEvent, dataType, convertData, bigEndian, values, selectedParam) + + local list = {} + if dataName == nil then + list = {{DTC_IDTransmit = '-', DTC_NameTransmit = '-', DTC_EventTransmit = '-', DTC_DataTypeTransmit = '-', DTC_ConvertTransmit = '-', DTC_BigEndianTransmit = '-', DTC_ValueTransmit = '-'},} + else + + for key, value in ipairs(dataName) do + local isSelected = false + if tostring(key) == selectedParam then + isSelected = true + end + table.insert(list, {DTC_IDTransmit = tostring(key), DTC_NameTransmit = value, DTC_EventTransmit = registerEvent[value], DTC_DataTypeTransmit = dataType[value], DTC_ConvertTransmit = convertData[value], DTC_BigEndianTransmit = bigEndian[value], DTC_ValueTransmit = tostring(values[key]), selected = isSelected}) + end + + if #list == 0 then + list = {{DTC_IDTransmit = '-', DTC_NameTransmit = '-', DTC_EventTransmit = '-', DTC_DataTypeTransmit = '-', DTC_ConvertTransmit = '-', DTC_BigEndianTransmit = '-', DTC_ValueTransmit = '-'},} + end + end + + local jsonstring = funcs.json.encode(list) + return jsonstring +end +funcs.createJsonListTransmissionData = createJsonListTransmissionData + +--- Function to create a json string out of data receive entries +---@param dataName string[] Table with names of data entries +---@param dataType string[] Table with data types of data entries +---@param convertData string[] Table with info if data needs to be converted +---@param bigEndian string[] Table with info about endianness of data entries +---@param values string[] Table with received values +---@param selectedParam string Currently selected parameter +---@return string jsonstring JSON string +local function createJsonListReceiveData(dataName, dataType, convertData, bigEndian, values, selectedParam) + + local list = {} + if dataName == nil then + list = {{DTC_IDReceive = '-', DTC_NameReceive = '-', DTC_DataTypeReceive = '-', DTC_ConvertReceive = '-', DTC_BigEndianReceive = '-', DTC_ValueReceive = '-'},} + else + + for key, value in ipairs(dataName) do + local isSelected = false + if tostring(key) == selectedParam then + isSelected = true + end + table.insert(list, {DTC_IDReceive = tostring(key), DTC_NameReceive = value, DTC_DataTypeReceive = dataType[value], DTC_ConvertReceive = convertData[value], DTC_BigEndianReceive = bigEndian[value], DTC_ValueReceive = tostring(values[value]), selected = isSelected}) + end + + if #list == 0 then + list = {{DTC_IDReceive = '-', DTC_NameReceive = '-', DTC_DataTypeReceive = '-', DTC_ConvertReceive = '-', DTC_BigEndianReceive = '-', DTC_ValueReceive = '-'},} + end + end + + local jsonstring = funcs.json.encode(list) + return jsonstring +end +funcs.createJsonListReceiveData = createJsonListReceiveData + +--- Function to convert number to related bit table +---@param num int Number to convert +---@return bool[]? allValues Table of boolean values per bit +local function toBits(num) + local res = '' + local allValues = {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false} + for i = 16, 1, -1 do + local temp = math.fmod(num, 2) + if temp == 1 then + allValues[(16+1)-i] = true + end + num = math.floor((num - temp)/2) + end + if num == 0 then + return allValues + else + return nil + end +end +funcs.toBits = toBits + +--- Function to convert bit values to related number +---@param values bool[]? Bit structure to convert +---@return int result Number +local function toNumber(values) + local result = 0 + for key, value in ipairs(values) do + if value == true then + result = result + 2^(key -1) + end + end + return result +end +funcs.toNumber = toNumber + +--- Function to get info about the total data size +---@param data string[] Table with info about data types to use +---@return int size Sum of all bytes of data types +local function getDataSize(data) + local size = 0 + for key, value in pairs(data) do + if value == 'DOUBLE' then + size = size + 8 + elseif value == 'FLOAT' then + size = size + 4 + elseif value == 'S_BYTE' then + size = size + 1 + elseif value == 'S_INT1' then + size = size + 1 + elseif value == 'S_INT2' then + size = size + 2 + elseif value == 'S_INT4' then + size = size + 4 + elseif value == 'S_INT8' then + size = size + 8 + elseif value == 'S_LONG' then + size = size + 4 + elseif value == 'S_SHORT' then + size = size + 2 + elseif value == 'U_BYTE' then + size = size + 1 + elseif value == 'U_INT1' then + size = size + 1 + elseif value == 'U_INT2' then + size = size + 2 + elseif value == 'U_INT4' then + size = size + 4 + elseif value == 'U_INT8' then + size = size + 8 + elseif value == 'U_LONG' then + size = size + 4 + elseif value == 'U_SHORT' then + size = size + 2 + elseif value == 'CHAR' then + size = size + 1 + --elseif value == 'STRING' then + -- size = size + 16 + end + end + return size +end +funcs.getDataSize = getDataSize + +--- Function to get info about the data size of a specific data type +---@param dataType string Data type to use +---@return int? result Amount of bytes of data type +local function getTypeSize(dataType) + if dataType == 'DOUBLE' then + return 8 + elseif dataType == 'FLOAT' then + return 4 + elseif dataType == 'S_BYTE' then + return 1 + elseif dataType == 'S_INT1' then + return 1 + elseif dataType == 'S_INT2' then + return 2 + elseif dataType == 'S_INT4' then + return 4 + elseif dataType == 'S_INT8' then + return 8 + elseif dataType == 'S_LONG' then + return 4 + elseif dataType == 'S_SHORT' then + return 2 + elseif dataType == 'U_BYTE' then + return 1 + elseif dataType == 'U_INT1' then + return 1 + elseif dataType == 'U_INT2' then + return 2 + elseif dataType == 'U_INT4' then + return 4 + elseif dataType == 'U_INT8' then + return 8 + elseif dataType == 'U_LONG' then + return 4 + elseif dataType == 'U_SHORT' then + return 2 + elseif dataType == 'CHAR' then + return 1 + --elseif dataType == 'STRING' then + -- return 16 + else + return nil + end +end +funcs.getTypeSize = getTypeSize + +local function addTabs(str, tab) + if tab > 0 then + for _=1, tab do + str = '\t' .. str + end + end + return str +end +local function min(arr) + if #arr == 0 then + return nil + end + table.sort(arr) + return arr[1] +end + +local function jsonLine2Table(intiStr, startInd, tab, resStr) + if not intiStr then return '' end + if not startInd then startInd = 1 end + if not tab then tab = 0 end + if not resStr then resStr = '' end + local compArray = {} + local nextSqBrOp = string.find(intiStr, '%[', startInd) + if nextSqBrOp then table.insert(compArray, nextSqBrOp) end + local nextSqBrCl = string.find(intiStr, '%]', startInd) + if nextSqBrCl then table.insert(compArray, nextSqBrCl) end + local nextCuBrCl = string.find(intiStr, '}', startInd) + if nextCuBrCl then table.insert(compArray, nextCuBrCl) end + local nextCuBrOp = string.find(intiStr, '{', startInd) + if nextCuBrOp then table.insert(compArray, nextCuBrOp) end + local nextComma = string.find(intiStr, ',', startInd) + if nextComma then table.insert(compArray, nextComma) end + local minVal = min(compArray) + if minVal then + local currentSymbol = string.sub(intiStr, minVal, minVal) + local content = '' + if startInd < minVal then + content = string.sub(intiStr, startInd, minVal-1) + end + if minVal == nextCuBrOp or minVal == nextSqBrOp then + resStr = resStr .. addTabs(content .. currentSymbol .. '\n', tab) + tab = tab + 1 + + elseif minVal == nextCuBrCl or minVal == nextSqBrCl then + resStr = resStr .. addTabs(content, tab) .. '\n' + tab = tab - 1 + resStr = resStr .. addTabs(currentSymbol, tab) + elseif nextComma and minVal == nextComma then + if content == '' then + resStr = resStr.. currentSymbol .. '\n' + else + resStr = resStr .. addTabs(content .. currentSymbol .. '\n', tab) + end + end + resStr = jsonLine2Table(intiStr, minVal+1, tab, resStr) + end + return resStr +end +funcs.jsonLine2Table = jsonLine2Table + return funcs --************************************************************************** diff --git a/README.md b/README.md index 3c9d355..0778b78 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,27 @@ # CSK_Module_Fieldbus -## INFO: Draft version. Not further developed / tested so far! Check for available GitHub forks of this repository to see latest updates. +Module to provide fieldbus communication functionality. -Module / Application to provide [...] functionality. - -*If available, please also add a screenshot/gif of the UI of the module here placed within /docu/media/ (see code)* -![](https://github.com/SICKAppSpaceCodingStarterKit/[REPO_OF_MODULE]/blob/main/docu/media/UI_Screenshot.png) +![](./docu/media/UI_Screenshot.png) ## How to Run -[***...please fill with informations...***] -For further information check out the [documentation](https://raw.githack.com/SICKAppSpaceCodingStarterKit/[REPO_OF_MODULE]/main/docu/CSK_Module_[MODULENAME].html) [update link] in the folder "docu". +The app includes an intuitive GUI to setup the fieldbus communication. +For further information check out the [documentation](https://raw.githack.com/golluroSICKAG/CSK_Module_Fieldbus/main/docu/CSK_Module_Fieldbus.html) in the folder "docu". ## Information Tested on: -[Device] - [firmware] -... - -[***optionally***] -Following CSK modules are used for this application via Git subtrees and should NOT be further developed within this repository (see [contribution guideline](https://github.com/SICKAppSpaceCodingStarterKit/.github/blob/main/Contribution_Guideline.md) of this GitHub organization): - - * CSK_Module_XYZ (release/tag v1.2.3) - -This application / module is part of the SICK AppSpace Coding Starter Kit developing approach. -It is programmed in an object oriented way. Some of the modules use kind of "classes" in Lua to make it possible to reuse code / classes in other projects. -In general it is not neccessary to code this way, but the architecture of this app can serve as a sample to be used especially for bigger projects and to make it easier to share code. +|Device|Firmware|Module version +|--|--|--| +|SIM 2x00|V1.5.0|V0.1.0| +|SIM 2x00|V1.7.0|V1.0.0| + +This module is part of the SICK AppSpace Coding Starter Kit developing approach. +It is programmed in an object-oriented way. Some of the modules use kind of "classes" in Lua to make it possible to reuse code / classes in other projects. +In general, it is not neccessary to code this way, but the architecture of this app can serve as a sample to be used especially for bigger projects and to make it easier to share code. Please check the [documentation](https://github.com/SICKAppSpaceCodingStarterKit/.github/blob/main/docu/SICKAppSpaceCodingStarterKit_Documentation.md) of CSK for further information. ## Topics -Coding Starter Kit, CSK, Module, SICK-AppSpace, [key_words] +Coding Starter Kit, CSK, Module, SICK-AppSpace, Fieldbus, Profinet, EtherCat, Ethernet/IP, PLC diff --git a/docu/CSK_Module_Fieldbus.html b/docu/CSK_Module_Fieldbus.html index 3cd178a..bf61348 100644 --- a/docu/CSK_Module_Fieldbus.html +++ b/docu/CSK_Module_Fieldbus.html @@ -6,7 +6,7 @@ -Documentation - CSK_Module_Fieldbus 0.1.0 +Documentation - CSK_Module_Fieldbus 1.0.0