| <#-- |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| --> |
| <#-- Prevent freemarker from escaping stuff --> |
| <#outputformat "undefined"> |
| <#-- Declare the name and type of variables passed in to the template --> |
| <#-- @ftlvariable name="languageName" type="java.lang.String" --> |
| <#-- @ftlvariable name="protocolName" type="java.lang.String" --> |
| <#-- @ftlvariable name="outputFlavor" type="java.lang.String" --> |
| <#-- @ftlvariable name="helper" type="org.apache.plc4x.language.c.CLanguageTemplateHelper" --> |
| <#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" --> |
| <#-- Declare the name and type of variables declared locally inside the template --> |
| <#-- @ftlvariable name="arrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ArrayField" --> |
| <#-- @ftlvariable name="checksumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ChecksumField" --> |
| <#-- @ftlvariable name="constField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ConstField" --> |
| <#-- @ftlvariable name="discriminatorField" type="org.apache.plc4x.plugins.codegenerator.types.fields.DiscriminatorField" --> |
| <#-- @ftlvariable name="enumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.EnumField" --> |
| <#-- @ftlvariable name="implicitField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ImplicitField" --> |
| <#-- @ftlvariable name="manualArrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualArrayField" --> |
| <#-- @ftlvariable name="manualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualField" --> |
| <#-- @ftlvariable name="optionalField" type="org.apache.plc4x.plugins.codegenerator.types.fields.OptionalField" --> |
| <#-- @ftlvariable name="paddingField" type="org.apache.plc4x.plugins.codegenerator.types.fields.PaddingField" --> |
| <#-- @ftlvariable name="reservedField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ReservedField" --> |
| <#-- @ftlvariable name="simpleField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SimpleField" --> |
| <#-- @ftlvariable name="switchField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SwitchField" --> |
| <#-- @ftlvariable name="virtualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.VirtualField" --> |
| <#-- @ftlvariable name="simpleTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.SimpleTypeReference" --> |
| <#-- @ftlvariable name="complexTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.ComplexTypeReference" --> |
| <#if !helper.isDiscriminatedChildTypeDefinition(type)>${helper.getSourceDirectory()?replace(".", "/")}/${helper.camelCaseToSnakeCase(type.name)}.c |
| /* |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| */ |
| |
| #include <stdio.h> |
| #include <time.h> |
| #include <plc4c/data.h> |
| #include <plc4c/spi/evaluation_helper.h> |
| #include <plc4c/driver_${helper.getProtocolName()}.h> |
| #include "${helper.camelCaseToSnakeCase(type.name)}.h" |
| |
| // Parse function. |
| plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer* io, <#if type.parserArguments?has_content><#list type.parserArguments as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)}<#if !helper.isSimpleTypeReference(parserArgument.type)>*</#if> ${parserArgument.name}<#sep>, </#list>, </#if>plc4c_data** data_item) { |
| uint16_t startPos = plc4c_spi_read_get_pos(io); |
| uint16_t curPos; |
| plc4c_return_code _res = OK; |
| |
| <#list type.switchField.cases as case> |
| <#if case.discriminatorValues?has_content>if(<#list case.discriminatorValues as discriminatorValue><#if case.discriminatorValues?size > 1>(</#if>${helper.toParseExpression(type, null, type.switchField.discriminatorExpressions[discriminatorValue?index], type.parserArguments)} == ${discriminatorValue}<#if case.discriminatorValues?size > 1>)</#if><#sep> && </#sep></#list>) </#if>{ /* ${case.name} */ |
| <#-- (*_message)->_type = ${helper.getCTypeName(type.name)}_type_${helper.getCTypeName(case.name)};--> |
| <#assign skipReturn=false> |
| <#list case.fields as field> |
| <#switch field.typeName> |
| <#case "array"> |
| |
| // Array field (${field.name}) |
| <#-- Only update curPos if the length expression uses it |
| <#if field.loopExpression.contains("curPos")> |
| curPos = io.getPos() - startPos; |
| </#if> |
| <#- If this is a count array, we can directly initialize an array with the given size -> |
| <#if helper.isCountArrayField(field)> |
| // Count array |
| if(${helper.toParseExpression(type, field, field.loopExpression, type.parserArguments)} > Integer.MAX_VALUE) { |
| throw new ParseException("Array count of " + (${helper.toParseExpression(type, field, field.loopExpression, type.parserArguments)}) + " exceeds the maximum allowed count of " + Integer.MAX_VALUE); |
| } |
| ${helper.getLanguageTypeNameForField(field)}[] ${field.name}; |
| { |
| int itemCount = (int) ${helper.toParseExpression(type, field, field.loopExpression, type.parserArguments)}; |
| ${field.name} = new ${helper.getLanguageTypeNameForField(field)}[itemCount]; |
| for(int curItem = 0; curItem < itemCount; curItem++) { |
| ${field.name}[curItem] = <#if helper.isSimpleTypeReference(field.type)>${helper.getReadBufferReadMethodCall(field.type)}<#else>${field.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(field.type, parserArgument?index), true)}) (${helper.toParseExpression(type, field, parserArgument, type.parserArguments)})<#sep>, </#sep></#list></#if>)</#if>; |
| } |
| } |
| <#- In all other cases do we have to work with a list, that is later converted to an array -> |
| <#else> |
| <#- For a length array, we read data till the read position of the buffer reaches a given position -> |
| <#if helper.isLengthArrayField(field)> |
| // Length array |
| int _${field.name}Length = ${helper.toParseExpression(type, field, field.loopExpression, type.parserArguments)}; |
| List<${helper.getLanguageTypeNameForField(field)}> _${field.name}List = new LinkedList<>(); |
| int ${field.name}EndPos = io.getPos() + _${field.name}Length; |
| while(io.getPos() < ${field.name}EndPos) { |
| _${field.name}List.add(<#if helper.isSimpleTypeReference(field.type)>${helper.getReadBufferReadMethodCall(field.type)}<#else>${field.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(field.type, parserArgument?index), true)}) (${helper.toParseExpression(type, field, parserArgument, type.parserArguments)})<#sep>, </#sep></#list></#if>)</#if>); |
| <#- After parsing, update the current position, but only if it's needed -> |
| <#if field.loopExpression.contains("curPos")> |
| curPos = io.getPos() - startPos; |
| </#if> |
| } |
| <#- A terminated array keeps on reading data as long as the termination expression evaluates to false -> |
| <#elseif helper.isTerminatedArrayField(field)> |
| // Terminated array |
| List<${helper.getLanguageTypeNameForField(field)}> _${field.name}List = new LinkedList<>(); |
| while(!((boolean) (${helper.toParseExpression(type, field, field.loopExpression, type.parserArguments)}))) { |
| _${field.name}List.add(<#if helper.isSimpleTypeReference(field.type)>${helper.getReadBufferReadMethodCall(field.type)}<#else>${field.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(field.type, parserArgument?index), true)}) (${helper.toParseExpression(type, field, parserArgument, type.parserArguments)})<#sep>, </#sep></#list></#if>)</#if>); |
| |
| <#- After parsing, update the current position, but only if it's needed -> |
| <#if field.loopExpression.contains("curPos")> |
| curPos = io.getPos() - startPos; |
| </#if> |
| } |
| </#if> |
| <#- |
| Convert the list into an array. However if the array is of a primitive |
| type we have to iterate over it's elements and explicitly cast them. |
| Otherwise a simple toArray call is fine. |
| -> |
| <#if helper.isSimpleTypeReference(field.type)> |
| ${helper.getLanguageTypeNameForField(field)}[] ${field.name} = new ${helper.getLanguageTypeNameForField(field)}[_${field.name}List.size()]; |
| for(int i = 0; i < _${field.name}List.size(); i++) { |
| ${field.name}[i] = (${helper.getLanguageTypeNameForField(field)}) _${field.name}List.get(i); |
| } |
| <#else> |
| ${helper.getLanguageTypeNameForField(field)}[] ${field.name} = _${field.name}List.toArray(new ${helper.getLanguageTypeNameForField(field)}[0]); |
| </#if> |
| </#if> |
| --> |
| <#break> |
| <#case "const"> |
| |
| // Const Field (${field.name}) |
| ${helper.getLanguageTypeNameForField(field)} ${field.name} = ${helper.getReadBufferReadMethodCall(field.type)}; |
| if(${field.name} != ${type.name}.${field.name?upper_case}) { |
| throw new ParseException("Expected constant value " + ${type.name}.${field.name?upper_case} + " but got " + ${field.name}); |
| } |
| <#break> |
| <#case "enum"> |
| |
| // Enum field (${field.name}) |
| ${helper.getLanguageTypeNameForField(field)} ${field.name} = ${helper.getLanguageTypeNameForField(field)}.valueOf(${helper.getReadBufferReadMethodCall(helper.getEnumBaseTypeReference(field.type))}); |
| <#break> |
| <#case "manual"> |
| |
| // Manual Field (${field.name}) |
| ${helper.getLanguageTypeNameForField(field)} ${field.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(type, field, field.parseExpression, type.parserArguments)}); |
| <#--<#switch case.name> |
| <#case "Time"> |
| return new PlcTime(${field.name}); |
| <#break> |
| <#case "Date"> |
| return new PlcDate(${field.name}); |
| <#break> |
| <#case "DateTime"> |
| return new PlcDateTime(${field.name}); |
| <#break> |
| <#case "Struct"> |
| return new PlcStruct(${field.name}); |
| <#break> |
| <#case "String"> |
| return new PlcString(${field.name}); |
| <#break> |
| <#default> |
| return new Plc${case.name}(${field.name}); |
| </#switch> |
| <#assign skipReturn=true> |
| --> |
| <#break> |
| <#case "reserved"> |
| |
| // Reserved Field (Compartmentalized so the "reserved" variable can't leak) |
| { |
| ${helper.getLanguageTypeNameForField(field)} _reserved = ${helper.getNullValueForTypeReference(field.type)}; |
| _res = ${helper.getReadBufferReadMethodCall(field.type, "&_reserved")}; |
| if(_res != OK) { |
| return _res; |
| } |
| if(_reserved != ${field.referenceValue}) { |
| printf("Expected constant value '%d' but got '%d' for reserved field.", ${field.referenceValue}, _reserved); |
| } |
| } |
| <#break> |
| <#case "simple"> |
| |
| // Simple Field (${field.name}) |
| <#-- Inizialize a local variable with the simple type (Intentionally keeping the java-style names so they can be used in expressions) --> |
| <#if helper.isSimpleTypeReference(field.type)> |
| ${helper.getLanguageTypeNameForField(field)} ${field.name} = ${helper.getNullValueForTypeReference(field.type)}; |
| _res = ${helper.getReadBufferReadMethodCall(field.type, "&" + field.name)}; |
| <#else> |
| <#-- Inizialize a local variable with the complex type (Intentionally keeping the java-style names so they can be used in expressions) --> |
| ${helper.getLanguageTypeNameForField(field)}* ${field.name}; |
| _res = ${helper.getCTypeName(field.type.name)}_parse(io<#if field.params?has_content>, <#list field.params as parserTerm>${helper.toParseExpression(baseType, field, parserTerm, baseType.parserArguments)}<#sep>, </#sep></#list></#if>, (void*) &${field.name}); |
| </#if> |
| if(_res != OK) { |
| return _res; |
| } |
| |
| *data_item = plc4c_data_create_${helper.getLanguageTypeNameForField(field)}_data(${field.name}); |
| |
| <#break> |
| </#switch> |
| </#list> |
| }<#sep> else </#sep> |
| </#list> |
| |
| return OK; |
| } |
| |
| plc4c_return_code ${helper.getCTypeName(type.name)}_serialize(plc4c_spi_write_buffer* io, plc4c_data** data_item<#if helper.getSerializerArguments(type.parserArguments)?has_content>, <#list helper.getSerializerArguments(type.parserArguments) as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) { |
| plc4c_return_code _res = OK; |
| |
| return OK; |
| } |
| |
| uint16_t ${helper.getCTypeName(type.name)}_length_in_bytes(plc4c_data* data_item) { |
| return ${helper.getCTypeName(type.name)}_length_in_bits(data_item) / 8; |
| } |
| |
| uint16_t ${helper.getCTypeName(type.name)}_length_in_bits(plc4c_data* data_item) { |
| uint16_t lengthInBits = 0; |
| |
| return lengthInBits; |
| } |
| |
| </#if> |
| </#outputformat> |