Skip to content

Commit 2915e76

Browse files
Merge pull request #3 from golluroSICKAG/main
# Release 2.1.0
2 parents 015ece5 + 19212bd commit 2915e76

7 files changed

Lines changed: 218 additions & 70 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
# Changelog
22
All notable changes to this project will be documented in this file.
33

4+
## Release 2.1.0
5+
6+
### New features
7+
Now it is possible to read subindexes (even if the subindex access is not supported). Requires IODD interpreter v2.1.0 or more
8+
9+
### Improvements
10+
- Speeding up of data parsing when reading from IO-Link device
11+
412
## Release 2.0.0
513

614
### New features

CSK_Module_MultiIOLinkSMI/project.mf.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1056,7 +1056,7 @@ Provide IOLink data via event.</desc>
10561056
</crown>
10571057
</crown>
10581058
<meta key="author">SICK AG</meta>
1059-
<meta key="version">2.0.0</meta>
1059+
<meta key="version">2.1.0</meta>
10601060
<meta key="priority">low</meta>
10611061
<meta key="copy-protected">false</meta>
10621062
<meta key="read-protected">false</meta>

CSK_Module_MultiIOLinkSMI/scripts/CSK_MultiIOLinkSMI_Processing.lua

Lines changed: 109 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,61 @@ Script.serveFunction('CSK_MultiIOLinkSMI.writeParameterByteArray_' .. multiIOLin
359359
-- Read Messages --------------------------------------------------------------------
360360
-------------------------------------------------------------------------------------
361361

362+
363+
local ioddReadMessagesFunctions = {}
364+
365+
local function updateFunctions()
366+
ioddReadMessagesFunctions = {}
367+
for messageName, messageInfo in pairs(ioddReadMessages) do
368+
ioddReadMessagesFunctions[messageName] = {}
369+
if not messageInfo.dataInfo then
370+
goto nextMessage
371+
end
372+
local includeDataMode = (messageInfo.dataInfo.ProcessData and messageInfo.dataInfo.Parameters)
373+
if includeDataMode then
374+
ioddReadMessagesFunctions[messageName] = {
375+
ProcessData = {},
376+
Parameters = {}
377+
}
378+
for dataMode, dataModeInfo in pairs(messageInfo.dataInfo) do
379+
if dataMode == "ProcessData" then
380+
for dataPointID, dataPointInfo in pairs(dataModeInfo) do
381+
ioddReadMessagesFunctions[messageName][dataMode][dataPointID] = {
382+
getDataFunction = readBinaryProcessData,
383+
processFunctions = converter.getParameterReadFunctions(dataPointInfo)
384+
}
385+
end
386+
elseif dataMode == "Parameters" then
387+
for dataPointID, dataPointInfo in pairs(dataModeInfo) do
388+
ioddReadMessagesFunctions[messageName][dataMode][dataPointID] = {
389+
getDataFunction = function() return readBinaryServiceData(tonumber(dataPointInfo.info.index), 0) end,
390+
processFunctions = converter.getParameterReadFunctions(dataPointInfo)
391+
}
392+
end
393+
end
394+
end
395+
else
396+
if messageInfo.dataInfo.ProcessData then
397+
for dataPointID, dataPointInfo in pairs(messageInfo.dataInfo.ProcessData) do
398+
ioddReadMessagesFunctions[messageName][dataPointID] = {
399+
getDataFunction = readBinaryProcessData,
400+
processFunctions = converter.getParameterReadFunctions(dataPointInfo)
401+
}
402+
end
403+
elseif messageInfo.dataInfo.Parameters then
404+
for dataPointID, dataPointInfo in pairs(messageInfo.dataInfo.Parameters) do
405+
ioddReadMessagesFunctions[messageName][dataPointID] = {
406+
getDataFunction = function() return readBinaryServiceData(tonumber(dataPointInfo.info.index), 0) end,
407+
processFunctions = converter.getParameterReadFunctions(dataPointInfo)
408+
}
409+
end
410+
end
411+
end
412+
::nextMessage::
413+
end
414+
end
415+
416+
362417
-- Read preconfigured message
363418
---@param messageName string Name of the message to read.
364419
---@return bool success Success of reading.
@@ -367,42 +422,65 @@ local function readIODDMessage(messageName)
367422
if not ioddReadMessages[messageName] or not ioddReadMessages[messageName].dataInfo then
368423
return false, "No data selected for read"
369424
end
425+
local message = {}
426+
local ts1 = DateTime.getTimestamp()
370427
local success = true
371-
local messageContent = {}
372-
local includeDataMode = (ioddReadMessages[messageName].dataInfo.ProcessData and ioddReadMessages[messageName].dataInfo.Parameters)
373-
if ioddReadMessages[messageName].dataInfo.ProcessData then
374-
local readSuccess, receivedData = readProcessData(ioddReadMessages[messageName].dataInfo.ProcessData)
375-
if not readSuccess then
376-
success = false
377-
end
378-
if includeDataMode then
379-
messageContent.ProcessData = receivedData
380-
else
381-
messageContent = receivedData
382-
end
383-
end
384-
if ioddReadMessages[messageName].dataInfo.Parameters then
385-
if includeDataMode then
386-
messageContent.Parameters = {}
428+
if ioddReadMessagesFunctions[messageName].ProcessData and ioddReadMessagesFunctions[messageName].Parameters then
429+
message = {
430+
ProcessData = {},
431+
Parameters = {}
432+
}
433+
for dataMode, dataModeInfo in pairs(ioddReadMessagesFunctions[messageName]) do
434+
for datapointId, datapointInfo in pairs(dataModeInfo) do
435+
message[dataMode][datapointId] = {}
436+
local binData = datapointInfo.getDataFunction()
437+
if not binData then
438+
success = false
439+
for k, v in pairs(datapointInfo.processFunctions) do
440+
if type(v) == "function" then
441+
message[dataMode][datapointId][k] = "null"
442+
else
443+
message[dataMode][datapointId][k] = {value = "null"}
444+
end
445+
end
446+
else
447+
for k, v in pairs(datapointInfo.processFunctions) do
448+
if type(v) == "function" then
449+
message[dataMode][datapointId][k] = v(binData)
450+
else
451+
message[dataMode][datapointId][k] = {value = v.value(binData)}
452+
end
453+
end
454+
end
455+
end
387456
end
388-
for dataPointID, dataPointInfo in pairs(ioddReadMessages[messageName].dataInfo.Parameters) do
389-
local readSuccess, receivedData = readParameter(dataPointInfo)
390-
if not readSuccess then
457+
else
458+
for datapointId, datapointInfo in pairs(ioddReadMessagesFunctions[messageName]) do
459+
message[datapointId] = {}
460+
local binData = datapointInfo.getDataFunction()
461+
if not binData then
391462
success = false
392-
end
393-
if includeDataMode then
394-
messageContent.Parameters[dataPointID] = receivedData
463+
for k, v in pairs(datapointInfo.processFunctions) do
464+
if type(v) == "function" then
465+
message[datapointId][k] = "null"
466+
else
467+
message[datapointId][k] = {value = "null"}
468+
end
469+
end
395470
else
396-
messageContent[dataPointID] = receivedData
471+
for k, v in pairs(datapointInfo.processFunctions) do
472+
if type(v) == "function" then
473+
message[datapointId][k] = v(binData)
474+
else
475+
message[datapointId][k] = {value = v.value(binData)}
476+
end
477+
end
397478
end
398479
end
399480
end
400-
local jsonMessageContent = json.encode(messageContent)
401-
ioddReadMessagesResults[messageName] = success
402-
ioddLatestReadMessages[messageName] = jsonMessageContent
403-
return success, jsonMessageContent
481+
return success, json.encode(message)
404482
end
405-
Script.serveFunction('CSK_MultiIOLinkSMI.readIODDMessage' .. multiIOLinkSMIInstanceNumberString, readIODDMessage, 'string:1:', 'bool:1:,string:?:')
483+
Script.serveFunction('CSK_MultiIOLinkSMI.readIODDMessage' .. multiIOLinkSMIInstanceNumberString, readIODDMessage, 'string:1:', 'bool:1,string:?:')
406484

407485
--- Update configuration of read messages
408486
local function updateIODDReadMessages()
@@ -419,19 +497,7 @@ local function updateIODDReadMessages()
419497
end
420498
ioddReadMessagesTimers = {}
421499
ioddReadMessagesRegistrations = {}
422-
for messageName, messageInfo in pairs(ioddReadMessages) do
423-
if helperFuncs.getTableSize(messageInfo.dataInfo) == 0 then
424-
goto nextMessage
425-
end
426-
for dataMode, dataModeInfo in pairs(messageInfo.dataInfo) do
427-
if dataMode == "ProcessData" or dataMode == "Parameters" then
428-
for dataPointID, dataPointInfo in pairs(dataModeInfo) do
429-
ioddReadMessages[messageName].dataInfo[dataMode][dataPointID] = converter.renameDatatype(dataPointInfo)
430-
end
431-
end
432-
end
433-
::nextMessage::
434-
end
500+
updateFunctions()
435501
local queueFunctions = {}
436502
for messageName, messageInfo in pairs(ioddReadMessages) do
437503
if helperFuncs.getTableSize(messageInfo.dataInfo) == 0 then
@@ -447,6 +513,8 @@ local function updateIODDReadMessages()
447513
end
448514
local timestamp1 = DateTime.getTimestamp()
449515
local success, jsonMessageContent = readIODDMessage(messageName)
516+
ioddReadMessagesResults[messageName] = success
517+
ioddLatestReadMessages[messageName] = jsonMessageContent
450518
local errorMessage = ''
451519
local queueSize = ioddReadMessagesQueue:getSize()
452520
if not success then

CSK_Module_MultiIOLinkSMI/scripts/Communication/MultiIOLinkSMI/helper/DataConverter.lua

Lines changed: 91 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -126,21 +126,10 @@ local function toBinaryString(data, byteLength)
126126
end
127127
converter.toBinaryString = toBinaryString
128128

129-
-------------------------------------------------------------------------------------
130-
-- Reverse the byteorder
131-
local function reverseBinaryString(binString)
132-
local l_result = ""
133-
for l_index = #binString, 1, -1 do
134-
l_result = l_result .. string.sub(binString, l_index, l_index)
135-
end
136-
137-
return l_result
138-
end
139-
converter.reverseBinaryString = reverseBinaryString
140-
141129
-------------------------------------------------------------------------------------
142130
-- Disassemble data
143131

132+
-- Gets necessary bits out of the bytes
144133
local function extract(n, field, width)
145134
-- Shift right by 'field' to get the bits starting at 'field' in the least significant bits
146135
local shifted = n >> field
@@ -150,18 +139,100 @@ local function extract(n, field, width)
150139
return shifted & mask
151140
end
152141

153-
local function disassembleData(data, startBit, bitLength)
154-
local l_startByte = math.floor(startBit / 8) + 1
155-
local l_startBitInByte = startBit % 8
142+
-- Bitwise processing of the incoming binary string
143+
local function disassembleData(data, bitOffset, bitLength)
144+
local byteLength = string.len(data)
145+
local l_startBit = byteLength*8 - bitLength - bitOffset + 1
146+
local l_startByte = math.ceil(l_startBit / 8)
147+
local l_startBitInByte = l_startBit % 8 - 1
156148
local l_byteLengthItem = math.ceil(bitLength / 8)
157-
local l_revRawData = reverseBinaryString(data)
158-
local l_dataAsNumber = string.unpack("<I" .. tostring(l_byteLengthItem), l_revRawData, l_startByte)
149+
local l_dataAsNumber = string.unpack(">I" .. tostring(l_byteLengthItem), data, l_startByte)
159150
local l_extractedValue = extract(l_dataAsNumber, l_startBitInByte, bitLength)
160151
local l_asBinaryString = toBinaryString(l_extractedValue, l_byteLengthItem)
161152
return l_asBinaryString
162153
end
163154
converter.disassembleData = disassembleData
164155

156+
-- Read functions for each simple use case
157+
local readConverters = {
158+
BooleanT = function(data)
159+
if string.unpack("B", data) == 0 then
160+
return false
161+
else
162+
return true
163+
end
164+
end,
165+
IntegerT = function(data)
166+
return string.unpack(">i" .. #data, data)
167+
end,
168+
UIntegerT = function(data)
169+
return string.unpack(">I" .. #data, data)
170+
end,
171+
Float32T = function(data)
172+
return string.unpack(">f", data)
173+
end,
174+
StringT = function(data)
175+
local l_zeroTermination = string.find(data, utf8.char(0))
176+
if l_zeroTermination then
177+
return string.sub(data, 1, l_zeroTermination - 1)
178+
else
179+
return data
180+
end
181+
end,
182+
OctetStringT = function(data)
183+
local l_zeroTermination = string.find(data, utf8.char(0))
184+
if l_zeroTermination then
185+
return string.sub(data, 1, l_zeroTermination - 1)
186+
else
187+
return data
188+
end
189+
end
190+
}
191+
192+
-- Function for reading a subindex
193+
local function getSimpleSubindexReadFunction(dataPointInfo, bitLength)
194+
local functionToReturn
195+
if tonumber(dataPointInfo.bitOffset) % 8 == 0 and getDatatypeBitlength(dataPointInfo) % 8 == 0 and bitLength % 8 == 0 then
196+
local startByteNew = bitLength / 8 - dataPointInfo.bitOffset/8 - getDatatypeBitlength(dataPointInfo)/8 + 1
197+
local endByteNew = bitLength / 8 - dataPointInfo.bitOffset/8
198+
functionToReturn = function(binData)
199+
return readConverters[dataPointInfo.type](string.sub(binData, startByteNew, endByteNew))
200+
end
201+
else
202+
local bitOffset = tonumber(dataPointInfo.bitOffset)
203+
local bitLength = getDatatypeBitlength(dataPointInfo)
204+
functionToReturn = function(binData)
205+
return readConverters[dataPointInfo.type](disassembleData(binData, bitOffset, bitLength))
206+
end
207+
end
208+
return functionToReturn
209+
end
210+
211+
-- Function with no bitwise operations in case the type is simple
212+
local function getSimpleIndexReadFunction(dataPointInfo)
213+
local functionToReturn = function(binData)
214+
return readConverters[dataPointInfo.type](binData)
215+
end
216+
return functionToReturn
217+
end
218+
219+
-- Gets the fastest and simpliest function for each selected parameter
220+
local function getParameterReadFunctions(parameterInfo)
221+
local parameterReadFunctions = {}
222+
if parameterInfo.info.type == 'ArrayT' or parameterInfo.info.type == 'RecordT' then
223+
for subindexId, subindexinfo in pairs(parameterInfo.subindeces) do
224+
parameterReadFunctions[subindexId] = {
225+
value = getSimpleSubindexReadFunction(subindexinfo.info, parameterInfo.info.BitLength)
226+
}
227+
end
228+
else
229+
parameterReadFunctions.value = getSimpleIndexReadFunction(parameterInfo.info)
230+
end
231+
return parameterReadFunctions
232+
end
233+
converter.getParameterReadFunctions = getParameterReadFunctions
234+
235+
165236
-------------------------------------------------------------------------------------
166237
-- Convert a raw binary data from IO-Link device to a meaningful Lua table
167238
local function getReadServiceDataResult(binData, parameterInfo)
@@ -179,6 +250,7 @@ local function getReadServiceDataResult(binData, parameterInfo)
179250
elseif parameterInfo.Datatype.type == 'RecordT' then
180251
for _, SingleItem in ipairs(parameterInfo.Datatype.RecordItem) do
181252
local binaryData = disassembleData(binData, tonumber(SingleItem.bitOffset), getDatatypeBitlength(SingleItem.Datatype))
253+
182254
Result[SingleItem.Name] = {
183255
value = toDataType(binaryData, SingleItem.Datatype.type)
184256
}
@@ -206,7 +278,6 @@ local function getReadProcessDataResult(binData, processDataInfo)
206278
end
207279
converter.getReadProcessDataResult = getReadProcessDataResult
208280

209-
210281
--Return a JSON payload of expacted format filled with null values in case reading of a Parameter has failed
211282
local function getFailedReadServiceDataResult(parameterInfo)
212283
local Result = {}
@@ -316,7 +387,7 @@ local function getComplexServiceDataToWrite(parameterInfo, data)
316387
local byteLength = math.ceil(getDatatypeBitlength(parameterInfo.Datatype) / 8)
317388
if parameterInfo.Datatype.type == 'ArrayT' then
318389
bitArray = makeEmptyBitArray(getDatatypeBitlength(parameterInfo.Datatype))
319-
390+
320391
local simpleDataBitLength = getDatatypeBitlength(parameterInfo.Datatype.Datatype)
321392
local bitIndexer = 0
322393
for i = 1, tonumber(parameterInfo.Datatype.count) do
@@ -340,7 +411,7 @@ local function getComplexServiceDataToWrite(parameterInfo, data)
340411
getDatatypeBitlength(SingleItem.Datatype)
341412
)
342413
end
343-
local json = require('Communication/MultiIOLinkSMI/helper/Json')
414+
344415
end
345416
local bin = ''
346417
for i = 1, byteLength do

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ Tested on
5959

6060
|Device|Firmware version|Module version|
6161
|--|--|--|
62+
|SIM1012|V2.4.2|V2.1.0|
6263
|SIM1012|V2.4.2|V2.0.0|
6364
|SICK AppEngine|V1.7.0|V2.0.0|
6465
|SIM1012|V2.3.0|v1.0.0|

0 commit comments

Comments
 (0)