| <#-- |
| 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 <plc4c/spi/evaluation_helper.h> |
| #include "${helper.camelCaseToSnakeCase(type.name)}.h" |
| |
| <#-- Helper function to get the discriminator for a given enum type constant --> |
| <#if helper.isDiscriminatedParentTypeDefinition(type)> |
| // Array of discriminator values that match the enum type constants. |
| // (The order is identical to the enum constants so we can use the |
| // enum constant to directly access a given types discriminator values) |
| const ${helper.getCTypeName(type.name)}_discriminator ${helper.getCTypeName(type.name)}_discriminators[] = { |
| <#if helper.getDiscriminatorValues()?has_content> |
| <#list helper.getDiscriminatorValues() as name, typeValues> |
| {/* ${helper.getCTypeName(name)} */ |
| <#list typeValues as key, value>.${key} = <#if value??>${value}<#else>-1</#if><#sep>, </#list>}<#sep >, |
| </#list> |
| </#if> |
| |
| }; |
| |
| // Function returning the discriminator values for a given type constant. |
| ${helper.getCTypeName(type.name)}_discriminator ${helper.getCTypeName(type.name)}_get_discriminator(${helper.getCTypeName(type.name)}_type type) { |
| return ${helper.getCTypeName(type.name)}_discriminators[type]; |
| } |
| |
| // Create an empty NULL-struct |
| static const ${helper.getCTypeName(type.name)} ${helper.getCTypeName(type.name)}_null_const; |
| |
| ${helper.getCTypeName(type.name)} ${helper.getCTypeName(type.name)}_null() { |
| return ${helper.getCTypeName(type.name)}_null_const; |
| } |
| |
| </#if> |
| <#if helper.getAllConstFields()?has_content> |
| |
| // Constant values. |
| <#list helper.getAllConstFields() as parentType, constField> |
| static const ${helper.getLanguageTypeNameForField(constField)} ${helper.getCTypeName(parentType.name)?upper_case}_${helper.camelCaseToSnakeCase(constField.name)?upper_case}_const = ${constField.referenceValue}; |
| ${helper.getLanguageTypeNameForField(constField)} ${helper.getCTypeName(parentType.name)?upper_case}_${helper.camelCaseToSnakeCase(constField.name)?upper_case}() { |
| return ${helper.getCTypeName(parentType.name)?upper_case}_${helper.camelCaseToSnakeCase(constField.name)?upper_case}_const; |
| } |
| </#list> |
| </#if> |
| |
| // 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>${helper.getCTypeName(type.name)}** _message) { |
| uint16_t startPos = plc4c_spi_read_get_pos(io); |
| uint16_t curPos; |
| plc4c_return_code _res = OK; |
| |
| // Allocate enough memory to contain this data structure. |
| (*_message) = malloc(sizeof(${helper.getCTypeName(type.name)})); |
| if(*_message == NULL) { |
| return NO_MEMORY; |
| } |
| <#macro fieldName baseType field>${helper.getFieldName(baseType, field)}</#macro> |
| <#macro fieldParser baseType field indentContent> |
| <#switch field.typeName> |
| <#case "array"> |
| <#assign arrayField = field> |
| |
| <#if indentContent> </#if> // Array field (${arrayField.name}) |
| <#-- Only update curPos if the length expression uses it --> |
| <#if arrayField.loopExpression.contains("curPos")> |
| <#if indentContent> </#if> curPos = plc4c_spi_read_get_pos(io) - startPos; |
| </#if> |
| <#-- In all other cases do we have to work with a list, that is later converted to an array --> |
| <#if indentContent> </#if> plc4c_list* ${arrayField.name} = NULL; |
| <#if indentContent> </#if> plc4c_utils_list_create(&${arrayField.name}); |
| <#if indentContent> </#if> if(${arrayField.name} == NULL) { |
| <#if indentContent> </#if> return NO_MEMORY; |
| <#if indentContent> </#if> } |
| <#if indentContent> </#if> { |
| <#if helper.isCountArrayField(field)> |
| <#if indentContent> </#if> // Count array |
| <#if indentContent> </#if> uint8_t itemCount = ${helper.toParseExpression(baseType, arrayField, arrayField.loopExpression, baseType.parserArguments)}; |
| <#if indentContent> </#if> for(int curItem = 0; curItem < itemCount; curItem++) { |
| <#if indentContent> </#if> <#if !helper.isSimpleTypeReference(arrayField.type)>bool lastItem = curItem == (itemCount - 1);</#if> |
| <#-- Inizialize a local variable with the simple type (Intentionally keeping the java-style names so they can be used in expressions) --> |
| <#if helper.isSimpleTypeReference(arrayField.type)> |
| <#if indentContent> </#if> ${helper.getLanguageTypeNameForTypeReference(arrayField.type)}* _value = malloc(sizeof(${helper.getLanguageTypeNameForTypeReference(arrayField.type)})); |
| <#if indentContent> </#if> _res = ${helper.getReadBufferReadMethodCall(arrayField.type, "_value")}; |
| <#if indentContent> </#if> if(_res != OK) { |
| <#if indentContent> </#if> return _res; |
| <#if indentContent> </#if> } |
| <#if indentContent> </#if> plc4c_utils_list_insert_head_value(${arrayField.name}, _value); |
| <#else> |
| <#-- Inizialize a local variable with the complex type (Intentionally keeping the java-style names so they can be used in expressions) --> |
| <#if indentContent> </#if> ${helper.getCTypeName(arrayField.type.name)}* _value = NULL; |
| <#if indentContent> </#if> _res = ${helper.getCTypeName(arrayField.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*) &_value); |
| <#if indentContent> </#if> if(_res != OK) { |
| <#if indentContent> </#if> return _res; |
| <#if indentContent> </#if> } |
| <#if indentContent> </#if> plc4c_utils_list_insert_head_value(${arrayField.name}, _value); |
| </#if> |
| <#if indentContent> </#if> } |
| <#-- For a length array, we read data till the read position of the buffer reaches a given position --> |
| <#elseif helper.isLengthArrayField(field)> |
| <#if indentContent> </#if> // Length array |
| <#if indentContent> </#if> uint8_t _${arrayField.name}Length = ${helper.toParseExpression(baseType, arrayField, arrayField.loopExpression, baseType.parserArguments)}; |
| <#if indentContent> </#if> uint8_t ${arrayField.name}EndPos = plc4c_spi_read_get_pos(io) + _${arrayField.name}Length; |
| <#if indentContent> </#if> while(plc4c_spi_read_get_pos(io) < ${arrayField.name}EndPos) { |
| <#-- Inizialize a local variable with the simple type (Intentionally keeping the java-style names so they can be used in expressions) --> |
| <#if helper.isSimpleTypeReference(arrayField.type)> |
| <#if indentContent> </#if> ${helper.getLanguageTypeNameForTypeReference(arrayField.type)} _value = ${helper.getNullValueForTypeReference(arrayField.type)}; |
| <#if indentContent> </#if> _res = ${helper.getReadBufferReadMethodCall(arrayField.type, "&_value")}; |
| <#if indentContent> </#if> if(_res != OK) { |
| <#if indentContent> </#if> return _res; |
| <#if indentContent> </#if> } |
| <#if indentContent> </#if> plc4c_utils_list_insert_head_value(${arrayField.name}, &_value); |
| <#else> |
| <#-- Inizialize a local variable with the complex type (Intentionally keeping the java-style names so they can be used in expressions) --> |
| <#if indentContent> </#if> ${helper.getCTypeName(arrayField.type.name)}* _value = NULL; |
| <#if indentContent> </#if> _res = ${helper.getCTypeName(arrayField.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*) &_value); |
| <#if indentContent> </#if> if(_res != OK) { |
| <#if indentContent> </#if> return _res; |
| <#if indentContent> </#if> } |
| <#if indentContent> </#if> plc4c_utils_list_insert_head_value(${arrayField.name}, _value); |
| </#if> |
| <#-- After parsing, update the current position, but only if it's needed --> |
| <#if arrayField.loopExpression.contains("curPos")> |
| <#if indentContent> </#if> curPos = plc4c_spi_read_get_pos(io) - startPos; |
| </#if> |
| <#if indentContent> </#if> } |
| <#-- A terminated array keeps on reading data as long as the termination expression evaluates to false --> |
| <#elseif helper.isTerminatedArrayField(field)> |
| <#if indentContent> </#if> // Terminated array |
| <#if indentContent> </#if> while(!((boolean) (${helper.toParseExpression(baseType, arrayField, arrayField.loopExpression, baseType.parserArguments)}))) { |
| <#-- Inizialize a local variable with the simple type (Intentionally keeping the java-style names so they can be used in expressions) --> |
| <#if helper.isSimpleTypeReference(arrayField.type)> |
| <#if indentContent> </#if> ${helper.getLanguageTypeNameForTypeReference(arrayField.type)} _value = ${helper.getNullValueForTypeReference(arrayField.type)}; |
| <#if indentContent> </#if> _res = ${helper.getReadBufferReadMethodCall(arrayField.type, "&_value")}; |
| <#if indentContent> </#if> if(_res != OK) { |
| <#if indentContent> </#if> return _res; |
| <#if indentContent> </#if> } |
| <#if indentContent> </#if> plc4c_utils_list_insert_head_value(${arrayField.name}, &_value); |
| <#else> |
| <#-- Inizialize a local variable with the complex type (Intentionally keeping the java-style names so they can be used in expressions) --> |
| <#if indentContent> </#if> ${helper.getCTypeName(arrayField.type.name)}* _value = NULL; |
| <#if indentContent> </#if> _res = ${helper.getCTypeName(arrayField.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*) &_value); |
| <#if indentContent> </#if> if(_res != OK) { |
| <#if indentContent> </#if> return _res; |
| <#if indentContent> </#if> } |
| <#if indentContent> </#if> plc4c_utils_list_insert_head_value(${arrayField.name}, _value); |
| </#if> |
| <#-- After parsing, update the current position, but only if it's needed --> |
| <#if arrayField.loopExpression.contains("curPos")> |
| <#if indentContent> </#if> curPos = plc4c_spi_read_get_pos(io) - startPos; |
| </#if> |
| <#if indentContent> </#if> } |
| </#if> |
| <#if indentContent> </#if> } |
| <#if indentContent> </#if> (*_message)-><@fieldName baseType=baseType field=arrayField/> = ${arrayField.name}; |
| <#break> |
| <#case "checksum"> |
| <#assign checksumField = field> |
| <#assign simpleTypeReference = checksumField.type> |
| |
| <#if indentContent> </#if> // Checksum Field (${checksumField.name}) |
| <#if indentContent> </#if> { |
| <#if indentContent> </#if> // Create an array of all the bytes read in this message element so far. |
| <#if indentContent> </#if> byte[] checksumRawData = plc4c_spi_read_get_bytes(io, startPos, plc4c_spi_read_get_pos(io)); |
| <#if indentContent> </#if> ${helper.getLanguageTypeNameForField(field)} _checksumRef = ${helper.getNullValueForTypeReference(checksumField.type)}; |
| <#if indentContent> </#if> _res = ${helper.getReadBufferReadMethodCall(checksumField.type, "&_checksumRef")}; |
| <#if indentContent> </#if> if(_res != OK) { |
| <#if indentContent> </#if> return _res; |
| <#if indentContent> </#if> } |
| <#if indentContent> </#if> ${helper.getLanguageTypeNameForField(field)} _checksum = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(baseType, checksumField, checksumField.checksumExpression, baseType.parserArguments)}); |
| <#if indentContent> </#if> if(_checksum != _checksumRef) { |
| <#if indentContent> </#if> return PARSE_ERROR; |
| <#if indentContent> </#if> // throw new ParseException(String.format("Checksum verification failed. Expected %04X but got %04X",_checksumRef & 0xFFFF, _checksum & 0xFFFF)); |
| <#if indentContent> </#if> } |
| <#if indentContent> </#if> } |
| <#break> |
| <#case "const"> |
| <#assign constField = field> |
| <#assign simpleTypeReference = constField.type> |
| |
| <#if indentContent> </#if> // Const Field (${constField.name}) |
| <#if indentContent> </#if> ${helper.getLanguageTypeNameForField(field)} ${constField.name} = ${helper.getNullValueForTypeReference(constField.type)}; |
| <#if indentContent> </#if> _res = ${helper.getReadBufferReadMethodCall(constField.type, "&" + constField.name)}; |
| <#if indentContent> </#if> if(_res != OK) { |
| <#if indentContent> </#if> return _res; |
| <#if indentContent> </#if> } |
| <#if indentContent> </#if> if(${constField.name} != ${helper.getCTypeName(baseType.name)?upper_case}_${helper.camelCaseToSnakeCase(constField.name)?upper_case}()) { |
| <#if indentContent> </#if> return PARSE_ERROR; |
| <#if indentContent> </#if> // throw new ParseException("Expected constant value " + ${helper.getCTypeName(baseType.name)?upper_case}_${helper.camelCaseToSnakeCase(constField.name)?upper_case} + " but got " + ${constField.name}); |
| <#if indentContent> </#if> } |
| <#break> |
| <#case "discriminator"> |
| <#assign discriminatorField = field> |
| <#assign simpleTypeReference = discriminatorField.type> |
| |
| <#if indentContent> </#if> // Discriminator Field (${discriminatorField.name}) (Used as input to a switch field) |
| <#if indentContent> </#if> ${helper.getLanguageTypeNameForField(field)} ${discriminatorField.name} = ${helper.getNullValueForTypeReference(discriminatorField.type)}; |
| <#if indentContent> </#if> _res = ${helper.getReadBufferReadMethodCall(discriminatorField.type, "&" + discriminatorField.name)}; |
| <#if indentContent> </#if> if(_res != OK) { |
| <#if indentContent> </#if> return _res; |
| <#if indentContent> </#if> } |
| <#break> |
| <#case "enum"> |
| <#assign enumField = field> |
| |
| <#if indentContent> </#if> // Enum field (${enumField.name}) |
| <#if indentContent> </#if> ${helper.getLanguageTypeNameForField(field)} ${enumField.name} = ${helper.getNullValueForTypeReference(enumField.type)}; |
| <#if indentContent> </#if> _res = ${helper.getReadBufferReadMethodCall(helper.getEnumBaseTypeReference(enumField.type), "&" + enumField.name)}; |
| <#if indentContent> </#if> if(_res != OK) { |
| <#if indentContent> </#if> return _res; |
| <#if indentContent> </#if> } |
| <#if indentContent> </#if> (*_message)-><@fieldName baseType=baseType field=enumField/> = ${enumField.name}; |
| <#break> |
| <#case "implicit"> |
| <#assign implicitField = field> |
| <#assign simpleTypeReference = implicitField.type> |
| |
| <#if indentContent> </#if> // Implicit Field (${implicitField.name}) (Used for parsing, but it's value is not stored as it's implicitly given by the objects content) |
| <#if indentContent> </#if> ${helper.getLanguageTypeNameForField(field)} ${implicitField.name} = ${helper.getNullValueForTypeReference(implicitField.type)}; |
| <#if indentContent> </#if> _res = ${helper.getReadBufferReadMethodCall(implicitField.type, "&" + implicitField.name)}; |
| <#if indentContent> </#if> if(_res != OK) { |
| <#if indentContent> </#if> return _res; |
| <#if indentContent> </#if> } |
| <#break> |
| <#case "manualArray"> |
| <#assign manualArrayField = field> |
| |
| <#-- TODO: Implement --> |
| <#break> |
| <#case "manual"> |
| <#assign manualField = field> |
| |
| <#if indentContent> </#if> // Manual Field (${manualField.name})<#-- check if complex --> |
| <#if indentContent> </#if> ${helper.getLanguageTypeNameForField(field)} ${manualField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(baseType, manualField, manualField.parseExpression, baseType.parserArguments)}); |
| <#if indentContent> </#if> (*_message)-><@fieldName baseType=baseType field=manualField/> = ${manualField.name}; |
| <#break> |
| <#case "optional"> |
| <#assign optionalField = field> |
| |
| <#if indentContent> </#if> // Optional Field (${optionalField.name}) (Can be skipped, if a given expression evaluates to false) |
| <#if optionalField.conditionExpression.contains("curPos")> |
| <#if indentContent> </#if> curPos = plc4c_spi_read_get_pos(io) - startPos; |
| </#if> |
| <#if indentContent> </#if> ${helper.getLanguageTypeNameForField(field)}* ${optionalField.name} = NULL; |
| <#if indentContent> </#if> if(${helper.toParseExpression(baseType, field, optionalField.conditionExpression, baseType.parserArguments)}) { |
| <#if indentContent> </#if> ${optionalField.name} = malloc(sizeof(${helper.getLanguageTypeNameForField(field)})); |
| <#if indentContent> </#if> if(${optionalField.name} == NULL) { |
| <#if indentContent> </#if> return NO_MEMORY; |
| <#if indentContent> </#if> } |
| <#if helper.isSimpleTypeReference(optionalField.type)> |
| <#if indentContent> </#if> *${optionalField.name} = ${helper.getNullValueForTypeReference(optionalField.type)}; |
| <#if indentContent> </#if> _res = ${helper.getReadBufferReadMethodCall(optionalField.type, optionalField.name)}; |
| <#else> |
| <#if indentContent> </#if> _res = ${helper.getCTypeName(optionalField.type.name)}_parse(io<#if optionalField.params?has_content>, <#list optionalField.params as parserTerm>${helper.toParseExpression(baseType, optionalField, parserTerm, baseType.parserArguments)}<#sep>, </#sep></#list></#if>, &${optionalField.name}); |
| </#if> |
| <#if indentContent> </#if> if(_res != OK) { |
| <#if indentContent> </#if> return _res; |
| <#if indentContent> </#if> } |
| <#if indentContent> </#if> (*_message)-><@fieldName baseType=baseType field=optionalField/> = ${optionalField.name}; |
| <#if indentContent> </#if> } else { |
| <#if indentContent> </#if> (*_message)-><@fieldName baseType=baseType field=optionalField/> = NULL; |
| <#if indentContent> </#if> } |
| <#break> |
| <#case "padding"> |
| <#assign paddingField = field> |
| <#assign simpleTypeReference = paddingField.type> |
| |
| <#if indentContent> </#if> // Padding Field (padding) |
| <#if indentContent> </#if> { |
| <#if indentContent> </#if> int _timesPadding = (int) ((plc4c_spi_read_has_more(io, ${helper.getNumBits(paddingField.type)})) && (${helper.toParseExpression(baseType, paddingField, paddingField.paddingCondition, baseType.parserArguments)})); |
| <#if indentContent> </#if> while (_timesPadding-- > 0) { |
| <#if indentContent> </#if> // Just read the padding data and ignore it |
| <#if indentContent> </#if> ${helper.getLanguageTypeNameForField(field)} _paddingValue = ${helper.getNullValueForTypeReference(paddingField.type)}; |
| <#if indentContent> </#if> _res = ${helper.getReadBufferReadMethodCall(paddingField.type, "&_paddingValue")}; |
| <#if indentContent> </#if> if(_res != OK) { |
| <#if indentContent> </#if> return _res; |
| <#if indentContent> </#if> } |
| <#if indentContent> </#if> } |
| <#if indentContent> </#if> } |
| <#break> |
| <#case "reserved"> |
| <#assign reservedField = field> |
| <#assign simpleTypeReference = reservedField.type> |
| |
| <#if indentContent> </#if> // Reserved Field (Compartmentalized so the "reserved" variable can't leak) |
| <#if indentContent> </#if> { |
| <#if indentContent> </#if> ${helper.getLanguageTypeNameForField(field)} _reserved = ${helper.getNullValueForTypeReference(reservedField.type)}; |
| <#if indentContent> </#if> _res = ${helper.getReadBufferReadMethodCall(reservedField.type, "&_reserved")}; |
| <#if indentContent> </#if> if(_res != OK) { |
| <#if indentContent> </#if> return _res; |
| <#if indentContent> </#if> } |
| <#if indentContent> </#if> if(_reserved != ${reservedField.referenceValue}) { |
| <#if indentContent> </#if> printf("Expected constant value '%d' but got '%d' for reserved field.", ${reservedField.referenceValue}, _reserved); |
| <#if indentContent> </#if> } |
| <#if indentContent> </#if> } |
| <#break> |
| <#case "simple"> |
| <#assign simpleField = field> |
| |
| <#if indentContent> </#if> // Simple Field (${simpleField.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(simpleField.type)> |
| <#if indentContent> </#if> ${helper.getLanguageTypeNameForField(field)} ${simpleField.name} = ${helper.getNullValueForTypeReference(simpleField.type)}; |
| <#if indentContent> </#if> _res = ${helper.getReadBufferReadMethodCall(simpleField.type, "&" + simpleField.name)}; |
| <#else> |
| <#-- Inizialize a local variable with the complex type (Intentionally keeping the java-style names so they can be used in expressions) --> |
| <#if indentContent> </#if> ${helper.getLanguageTypeNameForField(field)}* ${simpleField.name}; |
| <#if indentContent> </#if> _res = ${helper.getCTypeName(simpleField.type.name)}_parse(io<#if simpleField.params?has_content>, <#list simpleField.params as parserTerm>${helper.toParseExpression(baseType, simpleField, parserTerm, baseType.parserArguments)}<#sep>, </#sep></#list></#if>, (void*) &${simpleField.name}); |
| </#if> |
| <#if indentContent> </#if> if(_res != OK) { |
| <#if indentContent> </#if> return _res; |
| <#if indentContent> </#if> } |
| <#if indentContent> </#if> (*_message)-><@fieldName baseType=baseType field=simpleField/> = ${simpleField.name}; |
| <#break> |
| <#case "switch"> |
| <#assign switchField = field> |
| |
| <#if indentContent> </#if> // Switch Field (Depending on the discriminator values, passes the instantiation to a sub-type) |
| <#list switchField.cases as case> |
| <#if indentContent> </#if> <#if case.discriminatorValues?has_content>if(<#list case.discriminatorValues as discriminatorValue><#if case.discriminatorValues?size > 1>(</#if>${helper.toVariableParseExpression(baseType, switchField, switchField.discriminatorExpressions[discriminatorValue?index], type.parserArguments)} == ${discriminatorValue}<#if case.discriminatorValues?size > 1>)</#if><#sep> && </#sep></#list>) </#if>{ /* ${case.name} */ |
| <#if indentContent> </#if> (*_message)->_type = ${helper.getCTypeName(type.name)}_type_${helper.getCTypeName(case.name)}; |
| <#list case.fields as caseField> |
| <#if indentContent> </#if> <@fieldParser baseType=case field=caseField indentContent=true/> |
| <#sep > |
| |
| </#list> |
| <#if indentContent> </#if> }<#sep> else </#sep> |
| </#list> |
| <#break> |
| <#case "virtual"> |
| <#assign virtualField = field> |
| |
| <#if indentContent> </#if> // Virtual field (Just declare a local variable so we can access it in the parser) |
| <#if indentContent> </#if> ${helper.getLanguageTypeNameForField(field)} ${virtualField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(baseType, virtualField, virtualField.valueExpression, baseType.parserArguments)}); |
| <#break> |
| </#switch> |
| </#macro> |
| <#list type.fields as field> |
| <@fieldParser baseType=type field=field indentContent=false/> |
| </#list> |
| |
| return OK; |
| } |
| |
| plc4c_return_code ${helper.getCTypeName(type.name)}_serialize(plc4c_spi_write_buffer* io, ${helper.getCTypeName(type.name)}* _message<#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; |
| <#macro fieldSerializer baseType field indentContent> |
| <#switch field.typeName> |
| <#case "array"> |
| <#assign arrayField = field> |
| |
| <#if indentContent> </#if> // Array field (${arrayField.name}) |
| <#if indentContent> </#if> { |
| <#if indentContent> </#if> uint8_t itemCount = plc4c_utils_list_size(_message-><@fieldName baseType=baseType field=arrayField/>); |
| <#if indentContent> </#if> for(int curItem = 0; curItem < itemCount; curItem++) { |
| <#-- When parsing simple types, there is nothing that could require the "lastItem" --> |
| <#if !helper.isSimpleTypeReference(arrayField.type)><#if indentContent> </#if> bool lastItem = curItem == (itemCount - 1);</#if> |
| <#if indentContent> </#if> ${helper.getLanguageTypeNameForTypeReference(arrayField.type)}* _value = (${helper.getLanguageTypeNameForTypeReference(arrayField.type)}*) plc4c_utils_list_get_value(_message-><@fieldName baseType=baseType field=arrayField/>, curItem); |
| <#if helper.isSimpleTypeReference(arrayField.type)> |
| <#if indentContent> </#if> ${helper.getWriteBufferWriteMethodCall(arrayField.type, "*_value")}; |
| <#else> |
| <#if indentContent> </#if> _res = ${helper.getCTypeName(arrayField.type.name)}_serialize(io, (void*) _value<#if helper.getSerializerTerms(field.params)?has_content>, <#list helper.getSerializerTerms(field.params) as serializerTerm>${helper.toSerializationExpression(baseType, field, serializerTerm, baseType.parserArguments)}<#sep>, </#sep></#list></#if>); |
| <#if indentContent> </#if> if(_res != OK) { |
| <#if indentContent> </#if> return _res; |
| <#if indentContent> </#if> } |
| </#if> |
| <#if indentContent> </#if> } |
| <#if indentContent> </#if> } |
| <#break> |
| <#--case "checksum"> |
| <#assign checksumField = field> |
| <#assign simpleTypeReference = checksumField.type> |
| |
| <#if indentContent> </#if> // Checksum Field (${checksumField.name}) |
| <#if indentContent> </#if> { |
| <#if indentContent> </#if> // Create an array of all the bytes read in this message element so far. |
| <#if indentContent> </#if> byte[] checksumRawData = plc4c_spi_read_get_bytes(io, startPos, plc4c_spi_read_get_pos(io)); |
| <#if indentContent> </#if> ${helper.getLanguageTypeNameForField(field)} _checksumRef = ${helper.getReadBufferReadMethodCall(checksumField.type)}; |
| <#if indentContent> </#if> ${helper.getLanguageTypeNameForField(field)} _checksum = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(baseType, checksumField, checksumField.checksumExpression, baseType.parserArguments)}); |
| <#if indentContent> </#if> if(_checksum != _checksumRef) { |
| <#if indentContent> </#if> return PARSE_ERROR; |
| <#if indentContent> </#if> // throw new ParseException(String.format("Checksum verification failed. Expected %04X but got %04X",_checksumRef & 0xFFFF, _checksum & 0xFFFF)); |
| <#if indentContent> </#if> } |
| <#if indentContent> </#if> } |
| <#break--> |
| <#case "const"> |
| <#assign constField = field> |
| <#assign simpleTypeReference = constField.type> |
| |
| <#if indentContent> </#if> // Const Field (${constField.name}) |
| <#if indentContent> </#if> ${helper.getWriteBufferWriteMethodCall(constField.type, helper.getCTypeName(baseType.name)?upper_case + "_" + helper.camelCaseToSnakeCase(constField.name)?upper_case + "()")}; |
| <#break> |
| <#case "discriminator"> |
| <#assign discriminatorField = field> |
| <#assign simpleTypeReference = discriminatorField.type> |
| |
| <#if indentContent> </#if> // Discriminator Field (${discriminatorField.name}) |
| <#if indentContent> </#if> ${helper.getWriteBufferWriteMethodCall(discriminatorField.type, helper.getCTypeName(baseType.name) + "_get_discriminator(_message->_type)." + discriminatorField.name)}; |
| <#break> |
| <#case "enum"> |
| <#assign enumField = field> |
| |
| <#if indentContent> </#if> // Enum field (${enumField.name}) |
| <#if indentContent> </#if> _res = ${helper.getWriteBufferWriteMethodCall(helper.getEnumBaseTypeReference(enumField.type), "_message->" + helper.getFieldName(baseType, enumField))}; |
| <#if indentContent> </#if> if(_res != OK) { |
| <#if indentContent> </#if> return _res; |
| <#if indentContent> </#if> } |
| <#break> |
| <#case "implicit"> |
| <#assign implicitField = field> |
| <#assign simpleTypeReference = implicitField.type> |
| |
| <#if indentContent> </#if> // Implicit Field (${implicitField.name}) (Used for parsing, but it's value is not stored as it's implicitly given by the objects content) |
| <#if indentContent> </#if> _res = ${helper.getWriteBufferWriteMethodCall(implicitField.type, helper.toSerializationExpression(baseType, implicitField, implicitField.serializeExpression, baseType.parserArguments))}; |
| <#if indentContent> </#if> if(_res != OK) { |
| <#if indentContent> </#if> return _res; |
| <#if indentContent> </#if> } |
| <#break> |
| <#case "manualArray"> |
| <#assign manualArrayField = field> |
| |
| <#-- TODO: Implement --> |
| <#break> |
| <#case "manual"> |
| <#assign manualField = field> |
| |
| <#if indentContent> </#if> // Manual Field (${manualField.name})<#if indentContent> </#if> { |
| <#if helper.isSimpleTypeReference(manualField.type)> |
| <#if indentContent> </#if> _res = ${helper.getWriteBufferWriteMethodCall(manualField.type, "(${helper.getLanguageTypeNameForTypeReference(arrayField.type)}*) plc4c_utils_list_get_value(_message->" + helper.getFieldName(baseType, arrayField))}; |
| <#else> |
| <#if indentContent> </#if> _res = ${helper.getCTypeName(manualField.type.name)}_serialize(io, (void*) &_value); |
| </#if> |
| <#if indentContent> </#if> if(_res != OK) { |
| <#if indentContent> </#if> return _res; |
| <#if indentContent> </#if> } |
| <#break> |
| <#case "optional"> |
| <#assign optionalField = field> |
| |
| <#if indentContent> </#if> // Optional Field (${optionalField.name}) |
| <#if indentContent> </#if> if(_message-><@fieldName baseType=baseType field=optionalField/> != NULL) { |
| <#if helper.isSimpleTypeReference(optionalField.type)> |
| <#if indentContent> </#if> _res = ${helper.getWriteBufferWriteMethodCall(optionalField.type, "*_message->" + helper.getFieldName(baseType, optionalField))}; |
| <#else> |
| <#if indentContent> </#if> _res = ${helper.getCTypeName(optionalField.type.name)}_serialize(io, _message-><@fieldName baseType=baseType field=optionalField/>); |
| </#if> |
| <#if indentContent> </#if> if(_res != OK) { |
| <#if indentContent> </#if> return _res; |
| <#if indentContent> </#if> } |
| <#if indentContent> </#if> } |
| <#break> |
| <#case "padding"> |
| <#assign paddingField = field> |
| <#assign simpleTypeReference = paddingField.type> |
| |
| <#if indentContent> </#if> // Padding Field (padding) |
| <#if indentContent> </#if> { |
| <#-- We're replacing the "lastItem" with 'false' here as the item itself can't know if it is the last --> |
| <#if indentContent> </#if> int _timesPadding = (int) (${helper.toSerializationExpression(baseType, paddingField, paddingField.paddingCondition, baseType.parserArguments)}); |
| <#if indentContent> </#if> while (_timesPadding-- > 0) { |
| <#if indentContent> </#if> // Just output the default padding data |
| <#if indentContent> </#if> _res = ${helper.getWriteBufferWriteMethodCall(paddingField.type, helper.toParseExpression(baseType, paddingField, paddingField.paddingValue, baseType.parserArguments))}; |
| <#if indentContent> </#if> if(_res != OK) { |
| <#if indentContent> </#if> return _res; |
| <#if indentContent> </#if> } |
| <#if indentContent> </#if> } |
| <#if indentContent> </#if> } |
| <#break> |
| <#case "reserved"> |
| <#assign reservedField = field> |
| <#assign simpleTypeReference = reservedField.type> |
| |
| <#if indentContent> </#if> // Reserved Field |
| <#if indentContent> </#if> _res = ${helper.getWriteBufferWriteMethodCall(reservedField.type, reservedField.referenceValue)}; |
| <#if indentContent> </#if> if(_res != OK) { |
| <#if indentContent> </#if> return _res; |
| <#if indentContent> </#if> } |
| <#break> |
| <#case "simple"> |
| <#assign simpleField = field> |
| |
| <#if indentContent> </#if> // Simple Field (${simpleField.name}) |
| <#if helper.isSimpleTypeReference(simpleField.type)> |
| <#if indentContent> </#if> _res = ${helper.getWriteBufferWriteMethodCall(simpleField.type, "_message->" + helper.getFieldName(baseType, simpleField))}; |
| <#else> |
| <#if indentContent> </#if> _res = ${helper.getCTypeName(simpleField.type.name)}_serialize(io, _message-><@fieldName baseType=baseType field=simpleField/>); |
| </#if> |
| <#if indentContent> </#if> if(_res != OK) { |
| <#if indentContent> </#if> return _res; |
| <#if indentContent> </#if> } |
| <#break> |
| <#case "switch"> |
| <#assign switchField = field> |
| |
| <#if indentContent> </#if> // Switch Field (Depending of the current type, serialize the sub-type elements) |
| <#if indentContent> </#if> switch(_message->_type) { |
| <#list switchField.cases as case> |
| <#if indentContent> </#if> case ${helper.getCTypeName(type.name)}_type_${helper.getCTypeName(case.name)}: { |
| <#list case.fields as caseField> |
| <@fieldSerializer baseType=case field=caseField indentContent=true/> |
| </#list> |
| |
| <#if indentContent> </#if> break; |
| <#if indentContent> </#if> } |
| </#list> |
| <#if indentContent> </#if> } |
| <#break> |
| </#switch> |
| </#macro> |
| <#list type.fields as field> |
| <@fieldSerializer baseType=type field=field indentContent=false/> |
| </#list> |
| |
| return OK; |
| } |
| |
| uint16_t ${helper.getCTypeName(type.name)}_length_in_bytes(${helper.getCTypeName(type.name)}* _message) { |
| return ${helper.getCTypeName(type.name)}_length_in_bits(_message) / 8; |
| } |
| |
| uint16_t ${helper.getCTypeName(type.name)}_length_in_bits(${helper.getCTypeName(type.name)}* _message) { |
| <#macro fieldSize baseType field indentContent> |
| <#switch field.typeName> |
| <#case "array"> |
| <#assign arrayField = field> |
| |
| <#if indentContent> </#if> // Array field |
| <#if helper.isSimpleTypeReference(arrayField.type)> |
| <#assign simpleTypeReference = arrayField.type> |
| <#if indentContent> </#if> lengthInBits += ${simpleTypeReference.sizeInBits} * plc4c_utils_list_size(_message-><@fieldName baseType=baseType field=arrayField/>); |
| <#else> |
| <#if indentContent> </#if> if(_message-><@fieldName baseType=baseType field=arrayField/> != NULL) { |
| <#if indentContent> </#if> plc4c_list_element* curElement = _message-><@fieldName baseType=baseType field=arrayField/>->tail; |
| <#if indentContent> </#if> while (curElement != NULL) { |
| <#if indentContent> </#if> lengthInBits += ${helper.getLengthInBitsFunctionNameForComplexTypedField(arrayField)}((${helper.getLanguageTypeNameForTypeReference(arrayField.type)}*) curElement->value); |
| <#if indentContent> </#if> curElement = curElement->next; |
| <#if indentContent> </#if> } |
| <#if indentContent> </#if> } |
| </#if> |
| <#break> |
| <#case "checksum"> |
| <#assign checksumField = field> |
| <#assign simpleTypeReference = checksumField.type> |
| |
| <#if indentContent> </#if> // Checksum Field (checksum) |
| <#if indentContent> </#if> lengthInBits += ${simpleTypeReference.sizeInBits}; |
| <#break> |
| <#case "const"> |
| <#assign constField = field> |
| <#assign simpleTypeReference = constField.type> |
| |
| <#if indentContent> </#if> // Const Field (${constField.name}) |
| <#if indentContent> </#if> lengthInBits += ${simpleTypeReference.sizeInBits}; |
| <#break> |
| <#case "discriminator"> |
| <#assign discriminatorField = field> |
| <#assign simpleTypeReference = discriminatorField.type> |
| |
| <#if indentContent> </#if> // Discriminator Field (${discriminatorField.name}) |
| <#if indentContent> </#if> lengthInBits += ${simpleTypeReference.sizeInBits}; |
| <#break> |
| <#case "enum"> |
| <#assign enumField = field> |
| |
| <#if indentContent> </#if> // Enum Field (${enumField.name}) |
| <#if indentContent> </#if> lengthInBits += ${helper.getEnumBaseTypeReference(enumField.type).sizeInBits}; |
| <#break> |
| <#case "implicit"> |
| <#assign implicitField = field> |
| <#assign simpleTypeReference = implicitField.type> |
| |
| <#if indentContent> </#if> // Implicit Field (${implicitField.name}) |
| <#if indentContent> </#if> lengthInBits += ${simpleTypeReference.sizeInBits}; |
| <#break> |
| <#case "manualArray"> |
| <#assign manualArrayField = field> |
| |
| <#if indentContent> </#if> // Manual Array Field (${manualArrayField.name}) |
| <#if indentContent> </#if> lengthInBits += ${helper.toParseExpression(type, manualArrayField, manualArrayField.lengthExpression, type.parserArguments)} * 8; |
| <#break> |
| <#case "manual"> |
| <#assign manualField = field> |
| |
| <#if indentContent> </#if> // Manual Field (${manualField.name}) |
| <#if indentContent> </#if> lengthInBits += ${helper.toParseExpression(type, manualField, manualField.lengthExpression, type.parserArguments)} * 8; |
| <#break> |
| <#case "optional"> |
| <#assign optionalField = field> |
| |
| <#if indentContent> </#if> // Optional Field (${optionalField.name}) |
| <#if indentContent> </#if> if(_message-><@fieldName baseType=baseType field=optionalField/> != NULL) { |
| <#if helper.isSimpleTypeReference(optionalField.type)> |
| <#assign simpleTypeReference = optionalField.type> |
| <#if indentContent> </#if> lengthInBits += ${simpleTypeReference.sizeInBits}; |
| <#else> |
| <#if indentContent> </#if> lengthInBits += ${helper.getLengthInBitsFunctionNameForComplexTypedField(optionalField)}(_message-><@fieldName baseType=baseType field=optionalField/>); |
| </#if> |
| <#if indentContent> </#if> } |
| <#break> |
| <#case "padding"> |
| <#assign paddingField = field> |
| <#assign simpleTypeReference = paddingField.type> |
| |
| <#if indentContent> </#if> // Padding Field (padding) |
| <#-- We're replacing the "lastItem" with 'false' here as the item itself can't know if it is the last --> |
| <#if indentContent> </#if> int _needsPadding = (int) (${helper.toSerializationExpression(type, paddingField, paddingField.paddingCondition, type.parserArguments)?replace("lastItem", "false")}); |
| <#if indentContent> </#if> while(_needsPadding-- > 0) { |
| <#if indentContent> </#if> lengthInBits += ${simpleTypeReference.sizeInBits}; |
| <#if indentContent> </#if> } |
| <#break> |
| <#case "reserved"> |
| <#assign reservedField = field> |
| <#assign simpleTypeReference = reservedField.type> |
| |
| <#if indentContent> </#if> // Reserved Field (reserved) |
| <#if indentContent> </#if> lengthInBits += ${simpleTypeReference.sizeInBits}; |
| <#break> |
| <#case "simple"> |
| <#assign simpleField = field> |
| |
| <#if indentContent> </#if> // Simple field (${simpleField.name}) |
| <#if helper.isSimpleTypeReference(simpleField.type)> |
| <#assign simpleTypeReference = simpleField.type> |
| <#if indentContent> </#if> lengthInBits += ${simpleTypeReference.sizeInBits}; |
| <#else> |
| <#if indentContent> </#if> lengthInBits += ${helper.getLengthInBitsFunctionNameForComplexTypedField(simpleField)}(_message-><@fieldName baseType=baseType field=simpleField/>); |
| </#if> |
| <#break> |
| <#case "switch"> |
| <#assign switchField = field> |
| |
| <#if indentContent> </#if> // Depending of the current type, add the length of sub-type elements ... |
| <#if indentContent> </#if> switch(_message->_type) { |
| <#list switchField.cases as case> |
| <#if indentContent> </#if> case ${helper.getCTypeName(type.name)}_type_${helper.getCTypeName(case.name)}: { |
| <#list case.fields as caseField> |
| <@fieldSize baseType=case field=caseField indentContent=true/> |
| <#sep > |
| |
| </#list> |
| |
| <#if indentContent> </#if> break; |
| <#if indentContent> </#if> } |
| </#list> |
| <#if indentContent> </#if> } |
| <#break> |
| <#case "virtual"> |
| <#assign virtualField = field> |
| |
| <#if indentContent> </#if> // A virtual field doesn't have any in- or output. |
| <#break> |
| </#switch> |
| </#macro> |
| uint16_t lengthInBits = 0; |
| <#list type.fields as field> |
| <@fieldSize baseType=type field=field indentContent=false/> |
| </#list> |
| |
| return lengthInBits; |
| } |
| |
| </#if> |
| </#outputformat> |