blob: 602bb14204508960a60f4c8e7cee1ed2a9d6bcb0 [file] [log] [blame]
<#--
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 &gt; 1>(</#if>${helper.toParseExpression(type, null, type.switchField.discriminatorExpressions[discriminatorValue?index], type.parserArguments)} == ${discriminatorValue}<#if case.discriminatorValues?size &gt; 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>