synchronousTool.py 53.4 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# (C) Semantix Information Technologies.
#
# Semantix Information Technologies is licensing the code of the
# Data Modelling Tools (DMT) in the following dual-license mode:
#
# Commercial Developer License:
#       The DMT Commercial Developer License is the suggested version
# to use for the development of proprietary and/or commercial software.
# This version is for developers/companies who do not want to comply
# with the terms of the GNU Lesser General Public License version 2.1.
#
# GNU LGPL v. 2.1:
#       This version of DMT is the one to use for the development of
# applications, when you are willing to comply with the terms of the
# GNU Lesser General Public License version 2.1.
#
# Note that in both cases, there are no charges (royalties) for the
# generated code.
#
20
'''
21
22
23
24
25
26
Base class for all synchronous tools
'''

import re
import os

27
from typing import IO, Any, Generic, TypeVar  # NOQA pylint: disable=unused-import
28

29
from ..commonPy.utility import panic, inform, panicWithCallStack
30
from ..commonPy.aadlAST import InParam, OutParam, InOutParam, ApLevelContainer, Param
31
from ..commonPy.recursiveMapper import RecursiveMapperGeneric
32
33
from ..commonPy.asnAST import AsnNode
from ..commonPy.asnParser import AST_Lookup, AST_Leaftypes
34
35


36
37
38
TSource = TypeVar('TSource')
TDestin = TypeVar('TDestin')

39
fpga_seen = {}
40
# Add suffix to generated FPGA device driver's (<PI name>_<Language>.vhdl.c) functions to avoid multiple definition errors (conflict with "vm_if")
41
fpgaSuffix = ''
42
43
44
# Add a different suffix to the dispatcher C function (part of device driver)
# Dispatcher <Function Block name>_<PI name><dispatcherSuffix> will delegate to one or the other side (SW or HW)
# If delegation is to HW, then <Function Block name>_<PI name><fpgaSuffix> will be called
45
dispatcherSuffix = "_FPGA_Dispatch"
46
47
48
# FPGA/HW device driver (<PI name>_<Language>.vhdl.c) is being generated (also) when Function Block will exist both as SW and HW, that is, when
# 1) language defined is C or Simulink but on the autogen pass is "seen" as VHDL (so that respective B-mapper is invoked),
# and 2) there are FPGA configurations defined (default is False)
49
genFpgaDevDrv = False
50
51

class SynchronousToolGlueGeneratorGeneric(Generic[TSource, TDestin]):
52
53
54
55

    ##############################################
    # Parts to override for each synchronous tool

56
    def Version(self) -> None:  # pylint: disable=no-self-use
57
58
        panicWithCallStack("Method undefined in a SynchronousToolGlueGenerator...")  # pragma: no cover

59
    def FromToolToASN1SCC(self) -> RecursiveMapperGeneric:  # pylint: disable=no-self-use
60
61
        panicWithCallStack("Method undefined in a SynchronousToolGlueGenerator...")  # pragma: no cover

62
    def FromToolToOSS(self) -> RecursiveMapperGeneric:  # pylint: disable=no-self-use
63
64
        panicWithCallStack("Method undefined in a SynchronousToolGlueGenerator...")  # pragma: no cover

65
    def FromASN1SCCtoTool(self) -> RecursiveMapperGeneric:  # pylint: disable=no-self-use
66
67
        panicWithCallStack("Method undefined in a SynchronousToolGlueGenerator...")  # pragma: no cover

68
    def FromOSStoTool(self) -> RecursiveMapperGeneric:  # pylint: disable=no-self-use
69
70
        panicWithCallStack("Method undefined in a SynchronousToolGlueGenerator...")  # pragma: no cover

71
    def HeadersOnStartup(self, unused_modelingLanguage: str, unused_asnFile: str, unused_subProgram: ApLevelContainer, unused_subProgramImplementation: str, unused_outputDir: str, unused_maybeFVname: str) -> None:  # pylint: disable=no-self-use
72
73
        panicWithCallStack("Method undefined in a SynchronousToolGlueGenerator...")  # pragma: no cover

74
    def SourceVar(self, unused_nodeTypename: str, unused_encoding: str, unused_node: AsnNode, unused_subProgram: ApLevelContainer, unused_subProgramImplementation: str, unused_param: Param, unused_leafTypeDict: AST_Leaftypes, unused_names: AST_Lookup) -> TSource:  # pylint: disable=no-self-use
75
76
        panicWithCallStack("Method undefined in a SynchronousToolGlueGenerator...")  # pragma: no cover

77
    def TargetVar(self, unused_nodeTypename: str, unused_encoding: str, unused_node: AsnNode, unused_subProgram: ApLevelContainer, unused_subProgramImplementation: str, unused_param: Param, unused_leafTypeDict: AST_Leaftypes, unused_names: AST_Lookup) -> TDestin:  # pylint: disable=no-self-use
78
79
        panicWithCallStack("Method undefined in a SynchronousToolGlueGenerator...")  # pragma: no cover

80
    def InitializeBlock(self, unused_modelingLanguage: str, unused_asnFile: str, unused_sp: ApLevelContainer, unused_subProgramImplementation: str, unused_maybeFVname: str) -> None:  # pylint: disable=no-self-use
81
82
        panicWithCallStack("Method undefined in a SynchronousToolGlueGenerator...")  # pragma: no cover

83
    def ExecuteBlock(self, unused_modelingLanguage: str, unused_asnFile: str, unused_sp: ApLevelContainer, unused_subProgramImplementation: str, unused_maybeFVname: str) -> None:  # pylint: disable=no-self-use
84
85
86
87
88
        panicWithCallStack("Method undefined in a SynchronousToolGlueGenerator...")  # pragma: no cover

    ########################################################
    # Parts to possibly override for each synchronous tool

89
    # noinspection PyMethodMayBeStatic
90
    def CleanNameAsToolWants(self, name: str) -> str:  # pylint: disable=no-self-use
91
92
        return re.sub(r'[^a-zA-Z0-9_]', '_', name)

93
    # noinspection PyMethodMayBeStatic
94
    def CleanNameAsADAWants(self, name: str) -> str:  # pylint: disable=no-self-use
95
96
97
98
99
        return re.sub(r'[^a-zA-Z0-9_]', '_', name)

    ##########################################
    # Common parts for all synchronous tools

100
    def __init__(self) -> None:
101
        # The files written to
102
103
104
105
        self.C_HeaderFile = None  # type: IO[Any]
        self.C_SourceFile = None  # type: IO[Any]
        self.ADA_HeaderFile = None  # type: IO[Any]
        self.ADA_SourceFile = None  # type: IO[Any]
106
107
        self.asn_name = ""
        self.supportedEncodings = ['native', 'uper', 'acn']
108
109
        self.dir = None  # type: str
        self.useOSS = None  # type: bool
110

111
112
113
114
115
116
117
118
    def OnStartup(self,
                  modelingLanguage: str,
                  asnFile: str,
                  subProgram: ApLevelContainer,
                  subProgramImplementation: str,
                  outputDir: str,
                  maybeFVname: str,
                  useOSS: bool) -> None:
119
120
121
        # FPGA/HW device driver is being generated (also) when Function Block will exist both as SW and HW, that is, when
        # 1) language defined is C or Simulink but on this autogen pass is "seen" as VHDL (so that respective B-mapper is invoked),
        # and 2) there are FPGA configurations defined
122
        global genFpgaDevDrv
123
        # Add suffix to generated FPGA device driver's functions to avoid multiple definition errors (conflict with "vm_if")
124
        global fpgaSuffix
125
126
127
        genFpgaDevDrv = subProgram._fpgaConfigurations is not '' and ((subProgramImplementation.lower() == "c" or subProgramImplementation.lower() == "simulink") and modelingLanguage == "vhdl");
        if genFpgaDevDrv:
            fpgaSuffix = "_Fpga"
128
        else:
129
            # To avoid code duplication, use suffix anyway but as an empty string when not to be applied
130
131
            fpgaSuffix = ''
        
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
        if modelingLanguage == "QGenAda":
            self.dir = outputDir
            self.useOSS = useOSS

            outputADAsourceFilename = self.CleanNameAsADAWants(subProgram._id + "_" + subProgramImplementation) + "_wrapper.adb"
            outputADAsourceFilename = outputADAsourceFilename.lower()
            outputADAheaderFilename = self.CleanNameAsADAWants(subProgram._id + "_" + subProgramImplementation) + "_wrapper.ads"
            outputADAheaderFilename = outputADAheaderFilename.lower()

            inform(str(self.__class__) + ": Creating file '%s'...", outputADAheaderFilename)
            self.ADA_HeaderFile = open(outputDir + outputADAheaderFilename, 'w')

            inform(str(self.__class__) + ": Creating file '%s'...", outputADAsourceFilename)
            self.ADA_SourceFile = open(outputDir + outputADAsourceFilename, 'w')

            self.asn_name = os.path.basename(os.path.splitext(asnFile)[0])

            self.ADA_HeaderFile.write('with taste_dataview;\n')
            self.ADA_HeaderFile.write('use taste_dataview;\n')
            self.ADA_HeaderFile.write('with %s_types;\n' % self.CleanNameAsADAWants(subProgram._id))
            self.ADA_HeaderFile.write('use %s_types;\n\n' % self.CleanNameAsADAWants(subProgram._id))
            self.ADA_HeaderFile.write(
                'package %s is\n\n' %
                self.CleanNameAsADAWants(subProgram._id + "_" + subProgramImplementation + "_wrapper"))

            self.ADA_SourceFile.write('with %s;\n' % self.CleanNameAsADAWants(subProgram._id))
            self.ADA_SourceFile.write('with %s_types;\n' % self.CleanNameAsADAWants(subProgram._id))
            self.ADA_SourceFile.write('use %s_types;\n\n' % self.CleanNameAsADAWants(subProgram._id))
            self.ADA_SourceFile.write(
                'package body %s is\n\n' %
                self.CleanNameAsADAWants(subProgram._id + "_" + subProgramImplementation + "_wrapper"))
        else:
            self.dir = outputDir
            self.useOSS = useOSS

            outputCheaderFilename = \
                self.CleanNameAsToolWants(subProgram._id + "_" + subProgramImplementation) + "." + self.CleanNameAsToolWants(modelingLanguage) + ".h"
            outputCsourceFilename = \
                self.CleanNameAsToolWants(subProgram._id + "_" + subProgramImplementation) + "." + self.CleanNameAsToolWants(modelingLanguage) + ".c"
            outputADAsourceFilename = self.CleanNameAsADAWants(subProgram._id + "_" + subProgramImplementation) + ".adb"
            outputADAsourceFilename = outputADAsourceFilename.lower()
            outputADAheaderFilename = self.CleanNameAsADAWants(subProgram._id + "_" + subProgramImplementation) + ".ads"
            outputADAheaderFilename = outputADAheaderFilename.lower()

            inform(str(self.__class__) + ": Creating file '%s'...", outputCheaderFilename)
            self.C_HeaderFile = open(outputDir + outputCheaderFilename, 'w')

            inform(str(self.__class__) + ": Creating file '%s'...", outputCsourceFilename)
            self.C_SourceFile = open(outputDir + outputCsourceFilename, 'w')

            inform(str(self.__class__) + ": Creating file '%s'...", outputADAheaderFilename)
            self.ADA_HeaderFile = open(outputDir + outputADAheaderFilename, 'w')

            inform(str(self.__class__) + ": Creating file '%s'...", outputADAsourceFilename)
            self.ADA_SourceFile = open(outputDir + outputADAsourceFilename, 'w')

            self.asn_name = os.path.basename(os.path.splitext(asnFile)[0])

            ID = modelingLanguage.upper() + "_" + \
                os.path.basename(asnFile).replace(".", "").upper() + "_" + \
                self.CleanNameAsToolWants(subProgram._id + "_" + subProgramImplementation).upper()
            ID = re.sub(r'[^A-Za-z0-9_]', '_', ID).upper()
            self.C_HeaderFile.write("#ifndef __%s_H__\n" % ID)
            self.C_HeaderFile.write("#define __%s_H__\n\n" % ID)
            self.C_HeaderFile.write("#include <stdlib.h> /* for size_t */\n")
            self.C_HeaderFile.write("\n")

199
            self.C_SourceFile.write("#ifdef __unix__\n")
200
201
202
            self.C_SourceFile.write("#include <stdio.h>\n")
            self.C_SourceFile.write("#include <string.h>\n\n")
            self.C_SourceFile.write("#include <assert.h>\n\n")
203
            self.C_SourceFile.write("#endif\n")
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220

            self.C_SourceFile.write("#include \"%s\"\n" % outputCheaderFilename)

            self.HeadersOnStartup(modelingLanguage, asnFile, subProgram, subProgramImplementation, outputDir, maybeFVname)

            self.ADA_HeaderFile.write('with Interfaces.C.Extensions;\n')
            self.ADA_HeaderFile.write('use Interfaces.C.Extensions;\n\n')
            self.ADA_HeaderFile.write(
                'package %s is\n\n' %
                self.CleanNameAsADAWants(subProgram._id + "_" + subProgramImplementation))

            self.ADA_SourceFile.write('with Interfaces.C.Extensions;\n')
            self.ADA_SourceFile.write('use Interfaces.C.Extensions;\n\n')
            self.ADA_SourceFile.write(
                'package body %s is\n\n' %
                self.CleanNameAsADAWants(subProgram._id + "_" + subProgramImplementation))

221
222
223
224
225
226
227
228
229
    def Encoder(self,
                nodeTypename: str,
                encoding: str,
                node: AsnNode,
                subProgram: ApLevelContainer,
                subProgramImplementation: str,
                param: Param,
                leafTypeDict: AST_Leaftypes,
                names: AST_Lookup) -> None:
230
231
        global fpgaSuffix
        
232
        if encoding.lower() not in self.supportedEncodings:
233
234
            panic(str(self.__class__) + ": in (%s), encoding can be one of %s (not '%s')" % (  # pragma: no cover
                subProgram._id + "." + subProgramImplementation, self.supportedEncodings, encoding))  # pragma: no cover
235
236

        tmpSpName = "Convert_From_%s_To_%s_In_%s_%s" % \
237
238
239
240
            (self.CleanNameAsADAWants(nodeTypename),
             encoding.lower(),
             self.CleanNameAsADAWants(subProgram._id + "_" + subProgramImplementation),
             self.CleanNameAsADAWants(param._id))
241
242
243
244
245
246
247
248
249
250
251

        srcVar = self.SourceVar(nodeTypename, encoding, node, subProgram, subProgramImplementation, param, leafTypeDict, names)

        if subProgramImplementation == "QGenAda":
            self.ADA_HeaderFile.write(
                "    procedure Ada_%s(QGen_OUT : in %s; T_OUT : out %s);\n" %
                (tmpSpName, self.CleanNameAsToolWants(nodeTypename), "asn1Scc" + self.CleanNameAsToolWants(nodeTypename)))
            self.ADA_SourceFile.write(
                "    procedure Ada_%s(QGen_OUT : in %s; T_OUT : out %s) is\n" %
                (tmpSpName, self.CleanNameAsToolWants(nodeTypename), "asn1Scc" + self.CleanNameAsToolWants(nodeTypename)))
            self.ADA_SourceFile.write('begin\n')
252

253
            toolToAsn1 = self.FromToolToASN1SCC()
254
            lines = toolToAsn1.Map(
255
256
257
258
                "QGen_OUT",
                "T_OUT",
                node,
                leafTypeDict,
259
                names) if toolToAsn1 else []
260

261
            lines = ["        " + x for x in lines]
262
            self.ADA_SourceFile.write("".join(lines))
263

264
265
266
267
            self.ADA_SourceFile.write(
                "    end Ada_%s;\n\n" % tmpSpName)
        else:
            self.C_HeaderFile.write(
268
                "int %s%s(void *pBuffer, size_t iMaxBufferSize);\n" % (tmpSpName, fpgaSuffix))
269
270
271
272
273
274
275
276
277
278
279
280
281
282
            self.ADA_HeaderFile.write(
                "procedure Ada_%s(pBuffer : in Interfaces.C.char_array; iMaxBufferSize : in Integer; bytesWritten : out Integer);\n" % tmpSpName)
            self.ADA_SourceFile.write(
                "procedure Ada_%s(pBuffer : in Interfaces.C.char_array; iMaxBufferSize : in Integer; bytesWritten : out Integer) is\n" % tmpSpName)
            self.ADA_SourceFile.write(
                "    function C_%s(pBuffer : Interfaces.C.char_array; iMaxBufferSize : Integer) return Integer;\n" % tmpSpName)
            self.ADA_SourceFile.write(
                '    pragma Import(C, C_%s, "%s");\n' % (tmpSpName, tmpSpName))
            self.ADA_SourceFile.write(
                'begin\n'
                '    bytesWritten := C_%s(pBuffer, iMaxBufferSize);\n' % tmpSpName)
            self.ADA_SourceFile.write(
                "end Ada_%s;\n\n" % tmpSpName)
            self.C_SourceFile.write(
283
                "int %s%s(void *pBuffer, size_t iMaxBufferSize)\n{\n" % (tmpSpName, fpgaSuffix))
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307

            if self.useOSS and encoding.lower() == "uper":
                self.C_SourceFile.write(
                    "    STATIC OSS_%s var_%s;\n" %
                    (self.CleanNameAsToolWants(nodeTypename), self.CleanNameAsToolWants(nodeTypename)))
            else:
                self.C_SourceFile.write(
                    "    STATIC asn1Scc%s var_%s;\n" %
                    (self.CleanNameAsToolWants(nodeTypename), self.CleanNameAsToolWants(nodeTypename)))

            if encoding.lower() in ["uper", "acn"]:
                if self.useOSS:
                    self.C_SourceFile.write("    STATIC OssBuf strm;\n")
                else:
                    self.C_SourceFile.write("    int errorCode;\n")
                    self.C_SourceFile.write("    STATIC BitStream strm;\n\n")
                    # setup the asn1c encoder
                    self.C_SourceFile.write("    BitStream_Init(&strm, pBuffer, iMaxBufferSize);\n")

            # Write the mapping code for the message
            if self.useOSS and encoding.lower() == "uper":
                toolToAsn1 = self.FromToolToOSS()
            else:
                toolToAsn1 = self.FromToolToASN1SCC()
308
            lines = toolToAsn1.Map(
309
310
311
312
                srcVar,
                "var_" + self.CleanNameAsToolWants(nodeTypename),
                node,
                leafTypeDict,
313
                names) if toolToAsn1 else []
314

315
            lines = ["    " + x for x in lines]
316
317
318
319
320
321
322
323
324
            self.C_SourceFile.write("".join(lines))

            if self.useOSS and encoding.lower() == "uper":
                # setup the OSS encoder
                self.C_SourceFile.write("\n    strm.value = NULL;\n")
                self.C_SourceFile.write("    strm.length = 0;\n")
                self.C_SourceFile.write(
                    "    if (ossEncode(g_world, OSS_%s_PDU, &var_%s, &strm) != 0) {\n" %
                    (self.CleanNameAsToolWants(nodeTypename), self.CleanNameAsToolWants(nodeTypename)))
325
                self.C_SourceFile.write("#ifdef __unix__\n")
326
                self.C_SourceFile.write(
327
                    '        fprintf(stderr, "Could not encode %s (at %%s, %%d), errorMessage was %%s\\n", __FILE__, __LINE__, ossGetErrMsg(g_world));\n' % nodeTypename)
328
                self.C_SourceFile.write("#endif\n")
329
330
331
332
333
334
335
336
337
338
339
340
                self.C_SourceFile.write("        return -1;\n")
                self.C_SourceFile.write("    } else {\n")
                self.C_SourceFile.write("        assert(strm.length <= iMaxBufferSize);\n")
                self.C_SourceFile.write("        memcpy(pBuffer, strm.value, strm.length);\n")
                self.C_SourceFile.write("        ossFreeBuf(g_world, strm.value);\n")
                self.C_SourceFile.write("        return strm.length;\n")
                self.C_SourceFile.write("    }\n")
                self.C_SourceFile.write("}\n\n")
            elif encoding.lower() in ["uper", "acn"]:
                self.C_SourceFile.write(
                    "    if (asn1Scc%s_%sEncode(&var_%s, &strm, &errorCode, TRUE) == FALSE) {\n" %
                    (self.CleanNameAsToolWants(nodeTypename),
341
                     "ACN_" if encoding.lower() == "acn" else "",
342
                     self.CleanNameAsToolWants(nodeTypename)))
343
                self.C_SourceFile.write("#ifdef __unix__\n")
344
                self.C_SourceFile.write(
345
                    '        fprintf(stderr, "Could not encode %s (at %%s, %%d), errorCode was %%d\\n", __FILE__, __LINE__, errorCode);\n' % nodeTypename)
346
                self.C_SourceFile.write("#endif\n")
347
348
349
350
351
352
353
354
355
356
357
358
                self.C_SourceFile.write("        return -1;\n")
                self.C_SourceFile.write("    } else {\n")
                self.C_SourceFile.write("        return BitStream_GetLength(&strm);\n")
                self.C_SourceFile.write("    }\n")
                self.C_SourceFile.write("}\n\n")
            elif encoding.lower() == "native":
                self.C_SourceFile.write(
                    "    memcpy(pBuffer, &var_%s, sizeof(asn1Scc%s) );\n" %
                    (self.CleanNameAsToolWants(nodeTypename), self.CleanNameAsToolWants(nodeTypename)))
                self.C_SourceFile.write("    return sizeof(asn1Scc%s);\n" % self.CleanNameAsToolWants(nodeTypename))
                self.C_SourceFile.write("}\n\n")

359
360
361
362
363
364
365
366
367
    def Decoder(self,
                nodeTypename: str,
                encoding: str,
                node: AsnNode,
                subProgram: ApLevelContainer,
                subProgramImplementation: str,
                param: Param,
                leafTypeDict: AST_Leaftypes,
                names: AST_Lookup) -> None:
368
369
        global fpgaSuffix
        
370
371
        tmpSpName = "Convert_From_%s_To_%s_In_%s_%s" % \
            (encoding.lower(),
372
373
374
             self.CleanNameAsADAWants(nodeTypename),
             self.CleanNameAsADAWants(subProgram._id + "_" + subProgramImplementation),
             param._id)
375
376
377
378
379
380
381
382
383
384
385

        targetVar = self.TargetVar(nodeTypename, encoding, node, subProgram, subProgramImplementation, param, leafTypeDict, names)

        if subProgramImplementation == "QGenAda":
            self.ADA_HeaderFile.write(
                "    procedure Ada_%s(T_IN : in %s; QGen_IN : out %s);\n" %
                (tmpSpName, "asn1Scc" + self.CleanNameAsToolWants(nodeTypename), self.CleanNameAsToolWants(nodeTypename)))
            self.ADA_SourceFile.write(
                "    procedure Ada_%s(T_IN : in %s; QGen_IN : out %s) is\n" %
                (tmpSpName, "asn1Scc" + self.CleanNameAsToolWants(nodeTypename), self.CleanNameAsToolWants(nodeTypename)))
            self.ADA_SourceFile.write('    begin\n')
386

387
            asn1ToTool = self.FromASN1SCCtoTool()
388
            lines = asn1ToTool.Map(
389
390
391
392
                "T_IN",
                "QGen_IN",
                node,
                leafTypeDict,
393
                names) if asn1ToTool else []
394
            lines = ["        " + x for x in lines]
395
396

            self.ADA_SourceFile.write("".join(lines))
397

398
399
400
401
402
403
404
405
            self.ADA_SourceFile.write(
                "    end Ada_%s;\n\n" % tmpSpName)
        else:
            if encoding.lower() not in self.supportedEncodings:
                panic(str(self.__class__) + ": in (%s), encoding can be one of %s (not '%s')" %  # pragma: no cover
                      (subProgram._id + "." + subProgramImplementation, self.supportedEncodings, encoding))  # pragma: no cover

            self.C_HeaderFile.write(
406
                "int %s%s(void *pBuffer, size_t iBufferSize);\n" % (tmpSpName, fpgaSuffix))
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421

            self.ADA_HeaderFile.write(
                "procedure Ada_%s(pBuffer : Interfaces.C.char_array; iBufferSize : Integer);\n" % tmpSpName)
            self.ADA_SourceFile.write(
                "procedure Ada_%s(pBuffer : Interfaces.C.char_array; iBufferSize : Integer) is\n" % tmpSpName)
            self.ADA_SourceFile.write(
                "    procedure C_%s(pBuffer : Interfaces.C.char_array; iBufferSize : Integer);\n" % tmpSpName)
            self.ADA_SourceFile.write(
                '    pragma Import(C, C_%s, "%s");\n' % (tmpSpName, tmpSpName))
            self.ADA_SourceFile.write(
                'begin\n'
                '    C_%s(pBuffer, iBufferSize);\n' % tmpSpName)
            self.ADA_SourceFile.write(
                "end Ada_%s;\n\n" % tmpSpName)
            self.C_SourceFile.write(
422
                "int %s%s(void *pBuffer, size_t iBufferSize)\n{\n" % (tmpSpName, fpgaSuffix))
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450

            if self.useOSS and encoding.lower() == "uper":
                self.C_SourceFile.write("    int pdutype = OSS_%s_PDU;\n" % self.CleanNameAsToolWants(nodeTypename))
                self.C_SourceFile.write("    STATIC OssBuf strm;\n")
                self.C_SourceFile.write("    OSS_%s *pVar_%s = NULL;\n\n" %
                                        (self.CleanNameAsToolWants(nodeTypename),
                                         self.CleanNameAsToolWants(nodeTypename)))
                self.C_SourceFile.write("    strm.value = pBuffer;\n")
                self.C_SourceFile.write("    strm.length = iBufferSize;\n")
                self.C_SourceFile.write("    if (0 == ossDecode(g_world, &pdutype, &strm, (void**)&pVar_%s)) {\n" %
                                        self.CleanNameAsToolWants(nodeTypename))
                self.C_SourceFile.write("        /* Decoding succeeded */\n")
            else:
                self.C_SourceFile.write("    STATIC asn1Scc%s var_%s;\n" %
                                        (self.CleanNameAsToolWants(nodeTypename), self.CleanNameAsToolWants(nodeTypename)))
                if encoding.lower() in ["uper", "acn"]:
                    self.C_SourceFile.write("    int errorCode;\n")
                    self.C_SourceFile.write("    STATIC BitStream strm;\n")
                    self.C_SourceFile.write("    BitStream_AttachBuffer(&strm, pBuffer, iBufferSize);\n\n")
                    self.C_SourceFile.write("    if (asn1Scc%s_%sDecode(&var_%s, &strm, &errorCode)) {\n" %
                                            (self.CleanNameAsToolWants(nodeTypename),
                                             "ACN_" if encoding.lower() == "acn" else "",
                                             self.CleanNameAsToolWants(nodeTypename)))
                    self.C_SourceFile.write("        /* Decoding succeeded */\n")
                elif encoding.lower() == "native":
                    self.C_SourceFile.write("    var_%s = *(asn1Scc%s *) pBuffer;\n    {\n" %
                                            (self.CleanNameAsToolWants(nodeTypename),
                                             self.CleanNameAsToolWants(nodeTypename)))
451

452
453
            if self.useOSS and encoding.lower() == "uper":
                asn1ToTool = self.FromOSStoTool()
454
                lines = asn1ToTool.Map(
455
456
457
458
                    "(*pVar_" + self.CleanNameAsToolWants(nodeTypename) + ")",
                    targetVar,
                    node,
                    leafTypeDict,
459
                    names) if asn1ToTool else []
460
461
            else:
                asn1ToTool = self.FromASN1SCCtoTool()
462
                lines = asn1ToTool.Map(
463
464
465
466
                    "var_" + self.CleanNameAsToolWants(nodeTypename),
                    targetVar,
                    node,
                    leafTypeDict,
467
                    names) if asn1ToTool else []
468
            lines = ["        " + x for x in lines]
469
470
471
472
473
474
            self.C_SourceFile.write("".join(lines))

            if self.useOSS and encoding.lower() == "uper":
                self.C_SourceFile.write("        ossFreeBuf(g_world, pVar_%s);\n" % self.CleanNameAsToolWants(nodeTypename))
                self.C_SourceFile.write("        return 0;\n")
                self.C_SourceFile.write("    } else {\n")
475
                self.C_SourceFile.write("#ifdef __unix__\n")
476
                self.C_SourceFile.write(
477
                    '        fprintf(stderr, "Could not decode %s (at %%s, %%d), error message was %%s\\n", __FILE__, __LINE__, ossGetErrMsg(g_world));\n' % nodeTypename)
478
                self.C_SourceFile.write("#endif\n")
479
480
481
482
483
484
                self.C_SourceFile.write("        return -1;\n")
                self.C_SourceFile.write("    }\n")
                self.C_SourceFile.write("}\n\n")
            elif encoding.lower() in ["uper", "acn"]:
                self.C_SourceFile.write("        return 0;\n")
                self.C_SourceFile.write("    } else {\n")
485
                self.C_SourceFile.write("#ifdef __unix__\n")
486
                self.C_SourceFile.write(
487
                    '        fprintf(stderr, "Could not decode %s (at %%s, %%d), error code was %%d\\n", __FILE__, __LINE__, errorCode);\n' % nodeTypename)
488
                self.C_SourceFile.write("#endif\n")
489
490
491
492
493
494
495
496
                self.C_SourceFile.write("        return -1;\n")
                self.C_SourceFile.write("    }\n")
                self.C_SourceFile.write("}\n\n")
            else:
                self.C_SourceFile.write("        return 0;\n")
                self.C_SourceFile.write("    }\n")
                self.C_SourceFile.write("}\n\n")

497
498
499
500
501
502
503
504
505
    def Common(self,
               nodeTypename: str,
               node: AsnNode,
               subProgram: ApLevelContainer,
               subProgramImplementation: str,
               param: Param,
               leafTypeDict: AST_Leaftypes,
               names: AST_Lookup) -> None:
        if isinstance(param, (InOutParam, InParam)):
506
            self.Decoder(nodeTypename, param._sourceElement._encoding, node, subProgram, subProgramImplementation, param, leafTypeDict, names)
507
        if isinstance(param, (InOutParam, OutParam)):
508
509
            self.Encoder(nodeTypename, param._sourceElement._encoding, node, subProgram, subProgramImplementation, param, leafTypeDict, names)

510
    def OnBasic(self, nodeTypename: str, node: AsnNode, subProgram: ApLevelContainer, subProgramImplementation: str, param: Param, leafTypeDict: AST_Leaftypes, names: AST_Lookup) -> None:
511
512
513
514
        realLeafType = leafTypeDict[nodeTypename]
        inform(str(self.__class__) + ": BASE: %s (%s)", nodeTypename, realLeafType)
        self.Common(nodeTypename, node, subProgram, subProgramImplementation, param, leafTypeDict, names)

515
    def OnSequence(self, nodeTypename: str, node: AsnNode, subProgram: ApLevelContainer, subProgramImplementation: str, param: Param, leafTypeDict: AST_Leaftypes, names: AST_Lookup) -> None:
516
517
518
        inform(str(self.__class__) + ": SEQUENCE: %s", nodeTypename)
        self.Common(nodeTypename, node, subProgram, subProgramImplementation, param, leafTypeDict, names)

519
    def OnSet(self, nodeTypename: str, node: AsnNode, subProgram: ApLevelContainer, subProgramImplementation: str, param: Param, leafTypeDict: AST_Leaftypes, names: AST_Lookup) -> None:
520
521
522
        inform(str(self.__class__) + ": SET: %s", nodeTypename)  # pragma: nocover
        self.Common(nodeTypename, node, subProgram, subProgramImplementation, param, leafTypeDict, names)  # pragma: nocover

523
    def OnEnumerated(self, nodeTypename: str, node: AsnNode, subProgram: ApLevelContainer, subProgramImplementation: str, param: Param, leafTypeDict: AST_Leaftypes, names: AST_Lookup) -> None:
524
525
526
        inform(str(self.__class__) + ": ENUMERATED: %s", nodeTypename)
        self.Common(nodeTypename, node, subProgram, subProgramImplementation, param, leafTypeDict, names)

527
    def OnSequenceOf(self, nodeTypename: str, node: AsnNode, subProgram: ApLevelContainer, subProgramImplementation: str, param: Param, leafTypeDict: AST_Leaftypes, names: AST_Lookup) -> None:
528
529
530
        inform(str(self.__class__) + ": SEQUENCEOF: %s", nodeTypename)
        self.Common(nodeTypename, node, subProgram, subProgramImplementation, param, leafTypeDict, names)

531
    def OnSetOf(self, nodeTypename: str, node: AsnNode, subProgram: ApLevelContainer, subProgramImplementation: str, param: Param, leafTypeDict: AST_Leaftypes, names: AST_Lookup) -> None:
532
533
534
        inform(str(self.__class__) + ": SETOF: %s", nodeTypename)  # pragma: nocover
        self.Common(nodeTypename, node, subProgram, subProgramImplementation, param, leafTypeDict, names)  # pragma: nocover

535
    def OnChoice(self, nodeTypename: str, node: AsnNode, subProgram: ApLevelContainer, subProgramImplementation: str, param: Param, leafTypeDict: AST_Leaftypes, names: AST_Lookup) -> None:
536
537
538
        inform(str(self.__class__) + ": CHOICE: %s", nodeTypename)
        self.Common(nodeTypename, node, subProgram, subProgramImplementation, param, leafTypeDict, names)

539
    def OnShutdown(self, modelingLanguage: str, asnFile: str, sp: ApLevelContainer, subProgramImplementation: str, maybeFVname: str) -> None:
540
        global genFpgaDevDrv
541
542
543
        global fpgaSuffix
        global dispatcherSuffix
        
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
        if modelingLanguage == "QGenAda":
            self.ADA_HeaderFile.write("    procedure Execute_%s (" % self.CleanNameAsADAWants(sp._id + "_" + subProgramImplementation))
            self.ADA_SourceFile.write("    procedure Execute_%s (" % self.CleanNameAsADAWants(sp._id + "_" + subProgramImplementation))
            for param in sp._params:
                if param._id != sp._params[0]._id:
                    self.ADA_HeaderFile.write('; ')
                    self.ADA_SourceFile.write('; ')
                self.ADA_HeaderFile.write(self.CleanNameAsToolWants(param._id) + " : access asn1Scc" + self.CleanNameAsToolWants(param._signal._asnNodename))
                self.ADA_SourceFile.write(self.CleanNameAsToolWants(param._id) + " : access asn1Scc" + self.CleanNameAsToolWants(param._signal._asnNodename))

            self.ADA_HeaderFile.write(");\n")
            self.ADA_SourceFile.write(") is\n")
            for param in sp._params:
                self.ADA_SourceFile.write("        %s : aliased %s;\n" % ("QGen_" + self.CleanNameAsToolWants(param._id), self.CleanNameAsToolWants(param._signal._asnNodename)))
            self.ADA_SourceFile.write("    begin\n\n")
            for param in sp._params:
                nodeTypename = param._signal._asnNodename
                encoding = param._sourceElement._encoding
                tmpSpName = "Ada_Convert_From_%s_To_%s_In_%s_%s" % \
                    (encoding.lower(),
                     self.CleanNameAsADAWants(nodeTypename),
                     self.CleanNameAsADAWants(sp._id + "_" + subProgramImplementation),
                     self.CleanNameAsADAWants(param._id))
                if isinstance(param, InParam):
568
569
570
571
572
                    self.ADA_SourceFile.write(
                        '        %s(%s.all, QGen_%s);\n' % (
                            tmpSpName,
                            self.CleanNameAsToolWants(param._id),
                            self.CleanNameAsToolWants(param._id)))
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590

            self.ADA_SourceFile.write("\n        %s.comp (" % self.CleanNameAsADAWants(sp._id))
            for param in sp._params:
                if param._id != sp._params[0]._id:
                    self.ADA_SourceFile.write(', ')
                self.ADA_SourceFile.write("QGen_" + self.CleanNameAsToolWants(param._id))
            self.ADA_SourceFile.write(");\n\n")

            # Encode outputs
            for param in sp._params:
                nodeTypename = param._signal._asnNodename
                encoding = param._sourceElement._encoding
                tmpSpName = "Ada_Convert_From_%s_To_%s_In_%s_%s" % \
                    (self.CleanNameAsADAWants(nodeTypename),
                     encoding.lower(),
                     self.CleanNameAsADAWants(sp._id + "_" + subProgramImplementation),
                     param._id)
                if isinstance(param, InOutParam) or isinstance(param, OutParam):
591
592
593
594
595
                    self.ADA_SourceFile.write(
                        '        %s(QGen_%s, %s.all);\n' % (
                            tmpSpName,
                            self.CleanNameAsToolWants(param._id),
                            self.CleanNameAsToolWants(param._id)))
596
597
598
599
600
601
602
603
604
            self.ADA_SourceFile.write("    end Execute_%s;\n" % self.CleanNameAsADAWants(sp._id + "_" + subProgramImplementation))
            self.ADA_SourceFile.write(
                'end %s;\n' %
                self.CleanNameAsADAWants(sp._id + "_" + subProgramImplementation + "_wrapper"))
            self.ADA_HeaderFile.write(
                'end %s;\n' %
                self.CleanNameAsADAWants(sp._id + "_" + subProgramImplementation + "_wrapper"))

        else:
605
606
607
            if genFpgaDevDrv:
                if maybeFVname not in fpga_seen:
                    fpga_seen[maybeFVname] = 'no_init_yet';
Tiago Jorge's avatar
Tiago Jorge committed
608
                else:
609
                    fpga_seen[maybeFVname] = 'with_init_already'
610
            
611
612
            if genFpgaDevDrv:
                # Execute() returns if interaction with FPGA HW is successful, that is, if HW writes and reads are successful (0) or not (-1)
613
                self.C_HeaderFile.write("int Execute_%s%s();\n" % (self.CleanNameAsADAWants(sp._id + "_" + subProgramImplementation), fpgaSuffix))
614
615
            else:    
                self.C_HeaderFile.write("void Execute_%s();\n" % self.CleanNameAsADAWants(sp._id + "_" + subProgramImplementation))
616
            if maybeFVname != "":
617
                if not (genFpgaDevDrv and maybeFVname in fpga_seen and fpga_seen[maybeFVname] is 'with_init_already'):
Tiago Jorge's avatar
Tiago Jorge committed
618
                    self.C_HeaderFile.write("void init_%s%s();\n" % (self.CleanNameAsADAWants(maybeFVname), fpgaSuffix))
619
                if genFpgaDevDrv:
620
                    # Return to dispatcher if HW delegation via Execute() is successful (0) or not (-1).
621
                    self.C_HeaderFile.write("int %s_%s%s(" % (self.CleanNameAsADAWants(maybeFVname), self.CleanNameAsADAWants(sp._id), fpgaSuffix))
622
623
                else:
                    self.C_HeaderFile.write("void %s_%s%s(" % (self.CleanNameAsADAWants(maybeFVname), self.CleanNameAsADAWants(sp._id), fpgaSuffix))
624
            else:  # pragma: no cover
625
626
                self.C_HeaderFile.write("void %s_init%s();\n" % (self.CleanNameAsADAWants(sp._id), fpgaSuffix))  # pragma: no cover
                self.C_HeaderFile.write("void %s%s(" % (self.CleanNameAsADAWants(sp._id), fpgaSuffix))  # pragma: no cover
627
628
629
630
631
632
633
634
            for param in sp._params:
                if param._id != sp._params[0]._id:
                    self.C_HeaderFile.write(', ')
                if isinstance(param, InParam):
                    self.C_HeaderFile.write('void *p' + self.CleanNameAsToolWants(param._id) + ', size_t size_' + self.CleanNameAsToolWants(param._id))
                else:
                    self.C_HeaderFile.write('void *p' + self.CleanNameAsToolWants(param._id) + ', size_t *pSize_' + self.CleanNameAsToolWants(param._id))
            self.C_HeaderFile.write(");\n")
635
636
            
            # Check if Function Block will exist both as SW and HW. If yes generate dispatcher function (to delegate to SW or HW).
637
638
639
            # Dispatcher <Function Block name>_<PI name><dispatcherSuffix> is part of the FPGA device driver <PI name>_<Language>.vhdl.h/c
            # Dispatcher can return: 0 (successfully delegated to HW), 1 (delegated to SW), 2 (unsuccessfully delegated to HW)
            # Here being added to the .h file
640
            if genFpgaDevDrv:
641
                if maybeFVname != "":
642
                    self.C_HeaderFile.write("int %s_%s%s(" % (self.CleanNameAsADAWants(maybeFVname), self.CleanNameAsADAWants(sp._id), dispatcherSuffix))
643
                else:  # pragma: no cover
644
                    self.C_HeaderFile.write("int %s%s(" % (self.CleanNameAsADAWants(sp._id), dispatcherSuffix))  # pragma: no cover                    
645
646
647
648
649
650
651
652
653
                for param in sp._params:
                    if param._id != sp._params[0]._id:
                        self.C_HeaderFile.write(', ')
                    if isinstance(param, InParam):
                        self.C_HeaderFile.write('void *p' + self.CleanNameAsToolWants(param._id) + ', size_t size_' + self.CleanNameAsToolWants(param._id))
                    else:
                        self.C_HeaderFile.write('void *p' + self.CleanNameAsToolWants(param._id) + ', size_t *pSize_' + self.CleanNameAsToolWants(param._id))
                self.C_HeaderFile.write(");\n")            
            
654
655
            self.C_HeaderFile.write("\n#endif\n")

656
657
            if genFpgaDevDrv:
                # Execute() returns if interaction with FPGA HW is successful, that is, if HW writes and reads are successful (0) or not (-1)
658
                self.C_SourceFile.write("int Execute_%s%s()\n{\n" % (self.CleanNameAsADAWants(sp._id + "_" + subProgramImplementation), fpgaSuffix))
659
660
            else:
                self.C_SourceFile.write("void Execute_%s()\n{\n" % self.CleanNameAsADAWants(sp._id + "_" + subProgramImplementation))
661
662
663
664
            self.ExecuteBlock(modelingLanguage, asnFile, sp, subProgramImplementation, maybeFVname)
            self.C_SourceFile.write("}\n\n")

            if maybeFVname != "":
665
                if not (genFpgaDevDrv and maybeFVname in fpga_seen and fpga_seen[maybeFVname] is 'with_init_already'):
Tiago Jorge's avatar
Tiago Jorge committed
666
                    self.C_SourceFile.write("void init_%s%s()\n" % (self.CleanNameAsADAWants(maybeFVname), fpgaSuffix))
667
668
            else:  # pragma: no cover
                self.C_SourceFile.write("void %s_init()\n" % self.CleanNameAsADAWants(sp._id))  # pragma: no cover
669
            if not (genFpgaDevDrv and maybeFVname in fpga_seen and fpga_seen[maybeFVname] is 'with_init_already'):
Tiago Jorge's avatar
Tiago Jorge committed
670
671
672
673
674
675
                self.C_SourceFile.write("{\n")
                self.InitializeBlock(modelingLanguage, asnFile, sp, subProgramImplementation, maybeFVname)
                # self.C_SourceFile.write("    extern void InitializeGlue();\n")
                # self.C_SourceFile.write("    InitializeGlue();\n")
                self.C_SourceFile.write("}\n\n")

676
            if maybeFVname != "":
677
                if genFpgaDevDrv:
678
                    # Return to dispatcher if HW delegation via Execute() is successful (0) or not (-1).
679
                    self.C_SourceFile.write("int %s_%s%s(" % (self.CleanNameAsADAWants(maybeFVname), self.CleanNameAsADAWants(sp._id), fpgaSuffix))
680
681
                else:
                    self.C_SourceFile.write("void %s_%s%s(" % (self.CleanNameAsADAWants(maybeFVname), self.CleanNameAsADAWants(sp._id), fpgaSuffix))
682
683
684
685
686
687
688
689
690
691
692
            else:  # pragma: no cover
                self.C_SourceFile.write("void %s(" % self.CleanNameAsADAWants(sp._id))  # pragma: no cover
            for param in sp._params:
                if param._id != sp._params[0]._id:
                    self.C_SourceFile.write(', ')
                if isinstance(param, InParam):
                    self.C_SourceFile.write('void *p' + self.CleanNameAsToolWants(param._id) + ', size_t size_' + self.CleanNameAsToolWants(param._id))
                else:
                    self.C_SourceFile.write('void *p' + self.CleanNameAsToolWants(param._id) + ', size_t *pSize_' + self.CleanNameAsToolWants(param._id))
            self.C_SourceFile.write(")\n{\n")

693
694
695
696
697
698
699
            # Call Dispatcher function
            # Dispatcher will delegate to one or the other side (SW or HW) depending on whether the value of the global variable storing the current
            # configuration equals one of those configurations defined for the target Function Block (in IV field listing the FPGA configurations)
            # Mechanism is as follows:
            # 1) SW side glue <PI name>_<Language>.<Language>.h/c calls HW side glue (device driver) <PI name>_<Language>.vhdl.h/c
            #   specifically <Function Block name>_<PI name> function calls the Dispatcher <Function Block name>_<PI name><dispatcherSuffix>
            # 2) Dispatcher in HW side delegates back to SW side (when returning 1 or 2) or to FPGA (and returns 0)
700
            # 3) If successfully delegated to HW (returning 0), afterwards SW side returns immediately so to avoid calling up SW side as well
701
            #   Otherwise execution continues up trough "normal" SW side calling
702
            if sp._fpgaConfigurations is not '' and subProgramImplementation.lower() == "simulink" and modelingLanguage != "vhdl":
703
                self.C_SourceFile.write('    // Calling Fpga VHDL dispatcher function\n')
704
705
706
707
708
709
710
711
712
713
714
715
716
                self.C_SourceFile.write('    if (0 == %s_%s%s (' % \
                                                    (self.CleanNameAsADAWants(maybeFVname),
                                                     self.CleanNameAsADAWants(sp._id),
                                                     dispatcherSuffix))
                for param in sp._params:
                    if param._id != sp._params[0]._id:
                        self.C_SourceFile.write(', ')
                    if isinstance(param, InParam):
                        self.C_SourceFile.write('p' + self.CleanNameAsToolWants(param._id) + ', size_' + self.CleanNameAsToolWants(param._id))
                    else:
                        self.C_SourceFile.write('p' + self.CleanNameAsToolWants(param._id) + ', pSize_' + self.CleanNameAsToolWants(param._id))                                                
                self.C_SourceFile.write(")) return;\n")
                
717
718
            if genFpgaDevDrv:
                # Check if FPGA is ready before converting parameters and initiating exchanges with HW
719
720
721
722
723
724
                self.C_SourceFile.write('    // Check if FPGA is ready.\n')
                self.C_SourceFile.write('    extern const char globalFpgaStatus_%s[];\n' % (self.CleanNameAsADAWants(maybeFVname)))
                self.C_SourceFile.write('    if(strcmp(globalFpgaStatus_%s, FPGA_READY)){\n' % (self.CleanNameAsADAWants(maybeFVname)))
                self.C_SourceFile.write('       return -1;\n')
                self.C_SourceFile.write('    }\n\n')

725
726
727
728
            # Decode inputs
            for param in sp._params:
                nodeTypename = param._signal._asnNodename
                encoding = param._sourceElement._encoding
729
                tmpSpName = "Convert_From_%s_To_%s_In_%s_%s%s" % \
730
731
732
                    (encoding.lower(),
                     self.CleanNameAsADAWants(nodeTypename),
                     self.CleanNameAsADAWants(sp._id + "_" + subProgramImplementation),
733
734
                     self.CleanNameAsADAWants(param._id),
                     fpgaSuffix)
735
736
737
738
739
740
741
742
743
744
745
746
                if isinstance(param, InParam):
                    self.C_SourceFile.write('    %s(p%s, size_%s);\n' %
                                            (tmpSpName,
                                             self.CleanNameAsToolWants(param._id),
                                             self.CleanNameAsToolWants(param._id)))
                elif isinstance(param, InOutParam):
                    self.C_SourceFile.write('    %s(p%s, *pSize_%s);\n' %  # pragma: no cover
                                            (tmpSpName,
                                             self.CleanNameAsToolWants(param._id),
                                             self.CleanNameAsToolWants(param._id)))  # pragma: no cover

            # Do functional work
747
            if genFpgaDevDrv:
748
                # Check if HW delegation via Execute() is successful: return -1 to Dispatcher if not (so SW side can be called as fallback)
749
                self.C_SourceFile.write("    if(Execute_%s%s()) return -1;\n" % (self.CleanNameAsADAWants(sp._id + "_" + subProgramImplementation), fpgaSuffix))
750
751
            else:
                self.C_SourceFile.write("    Execute_%s();\n" % self.CleanNameAsADAWants(sp._id + "_" + subProgramImplementation))
752
753
754
755
756

            # Encode outputs
            for param in sp._params:
                nodeTypename = param._signal._asnNodename
                encoding = param._sourceElement._encoding
757
                tmpSpName = "Convert_From_%s_To_%s_In_%s_%s%s" % \
758
759
760
                    (self.CleanNameAsADAWants(nodeTypename),
                     encoding.lower(),
                     self.CleanNameAsADAWants(sp._id + "_" + subProgramImplementation),
761
762
                     param._id,
                     fpgaSuffix)
763
764
765
766
767
768
                if isinstance(param, InOutParam) or isinstance(param, OutParam):
                    self.C_SourceFile.write('    *pSize_%s = %s(p%s, %s);\n' %
                                            (self.CleanNameAsToolWants(param._id),
                                             tmpSpName,
                                             self.CleanNameAsToolWants(param._id),
                                             param._signal._asnSize))
769
            if genFpgaDevDrv:
770
                # HW delegation via Execute() was successful, so return 0 to Dispatcher
771
                self.C_SourceFile.write("    return 0;\n")
772
773
            self.C_SourceFile.write("}\n\n")

774
            # Check if Function Block will exist both as SW and HW. If yes generate dispatcher function (to delegate to SW or HW).
775
776
777
            # Dispatcher <Function Block name>_<PI name><dispatcherSuffix> is part of the FPGA device driver <PI name>_<Language>.vhdl.h/c
            # Dispatcher can return: 0 (successfully delegated to HW), 1 (delegated to SW), 2 (unsuccessfully delegated to HW)
            # Here being added to the .c file
778
779
780
781
782
783
            # Detailed description:
            # Delegate to one or the other side (SW or HW) depending on whether the value of a global variable storing the current
            # configuration (p_szGlobalState) equals one of those configurations listed (fConfigList) for the target Function Block in its respective IV field.
            # If so, OR such list defines the "magic" word "AllModes", computation will be delegated to HW/FPGA (<Function Block name>_<PI name><fpgaSuffix> will be called).
            # Otherwise, FPGA is not called and computation will proceed in SW through the "usual" SW side/glue counterpart.
            # Debug level logs (LOGDEBUG) can be used to track this delegation during testing.
784
            if genFpgaDevDrv:
785
                if maybeFVname != "":
786
                    self.C_SourceFile.write("int %s_%s%s(" % (self.CleanNameAsADAWants(maybeFVname), self.CleanNameAsADAWants(sp._id), dispatcherSuffix))
787
                else:  # pragma: no cover
788
                    self.C_SourceFile.write("int %s%s(" % (self.CleanNameAsADAWants(sp._id), dispatcherSuffix))  # pragma: no cover                    
789
790
791
792
793
794
795
796
                for param in sp._params:
                    if param._id != sp._params[0]._id:
                        self.C_SourceFile.write(', ')
                    if isinstance(param, InParam):
                        self.C_SourceFile.write('void *p' + self.CleanNameAsToolWants(param._id) + ', size_t size_' + self.CleanNameAsToolWants(param._id))
                    else:
                        self.C_SourceFile.write('void *p' + self.CleanNameAsToolWants(param._id) + ', size_t *pSize_' + self.CleanNameAsToolWants(param._id))
                self.C_SourceFile.write(")\n{\n")
797
798
                self.C_SourceFile.write('    /*\n')
                self.C_SourceFile.write('    Delegate to one or the other side (SW or HW) depending on whether the value of a global variable storing the current\n')
799
800
801
802
                self.C_SourceFile.write('    configuration (p_szGlobalState) equals one of those configurations listed (fConfigList) for the target Function Block in its respective IV field.\n')
                self.C_SourceFile.write('    If so, OR such list defines the "magic" word "AllModes", computation will be delegated to HW/FPGA (<Function Block name>_<PI name><fpgaSuffix> will be called).\n')
                self.C_SourceFile.write('    Otherwise, FPGA is not called and computation will proceed in SW through the "usual" SW side/glue counterpart.\n')
                self.C_SourceFile.write('    Debug level logs (LOGDEBUG) can be used to track this delegation during testing.\n')
803
                self.C_SourceFile.write('    */\n')
804
805
806
                self.C_SourceFile.write('    extern const char p_szGlobalState[];\n')
                self.C_SourceFile.write('    char *fConfig;\n')
                self.C_SourceFile.write('    char fConfigList[30] = "%s";\n' % (sp._fpgaConfigurations))
807
                self.C_SourceFile.write('    char allModes[] = "AllModes";\n')
808
                self.C_SourceFile.write('    fConfig = strtok(fConfigList, ",");\n')
809
                self.C_SourceFile.write('    while( fConfig != NULL ) {\n')
810
                self.C_SourceFile.write('       if(!strcmp(p_szGlobalState, fConfig) || !strcmp(allModes, fConfig)){\n')
811
                self.C_SourceFile.write('           // delegate to HW\n')
812
                self.C_SourceFile.write('           LOGDEBUG("[ <-?-> <-?-> <-?-> %s Dispatcher <-?-> <-?-> <-?-> ] Delegating to HW ... \\n");\n' % (self.CleanNameAsADAWants(maybeFVname)))
813
                self.C_SourceFile.write("           if(%s_%s%s(" % (self.CleanNameAsADAWants(maybeFVname), self.CleanNameAsADAWants(sp._id), fpgaSuffix))
814
815
816
817
818
819
820
                for param in sp._params:
                    if param._id != sp._params[0]._id:
                        self.C_SourceFile.write(', ')
                    if isinstance(param, InParam):
                        self.C_SourceFile.write('p' + self.CleanNameAsToolWants(param._id) + ', size_' + self.CleanNameAsToolWants(param._id))
                    else:
                        self.C_SourceFile.write('p' + self.CleanNameAsToolWants(param._id) + ', pSize_' + self.CleanNameAsToolWants(param._id))
821
822
                self.C_SourceFile.write(")){\n")
                self.C_SourceFile.write('               // HW error, return 2\n')
823
                self.C_SourceFile.write('               LOGERROR("[ <-?-> <-?-> <-?-> %s Dispatcher <-?-> <-?-> <-?-> ] HW error! (FALLBACK: SW)\\n");\n' % (self.CleanNameAsADAWants(maybeFVname)))
824
825
                self.C_SourceFile.write('               return 2;\n')
                self.C_SourceFile.write('           }\n')
826
827
828
                self.C_SourceFile.write('           // delegated to HW, return 0\n')
                self.C_SourceFile.write('           return 0;\n')
                self.C_SourceFile.write('       }\n')
829
                self.C_SourceFile.write('       fConfig = strtok(NULL, ",");\n')
830
                self.C_SourceFile.write('    }\n')
831
                self.C_SourceFile.write('    LOGDEBUG("[ <-?-> <-?-> <-?-> %s Dispatcher <-?-> <-?-> <-?-> ] Delegating to SW ...\\n");\n' % (self.CleanNameAsADAWants(maybeFVname)))
832
833
                self.C_SourceFile.write('    // delegate to SW, return 1\n')
                self.C_SourceFile.write('    return 1;\n')
834
835
                self.C_SourceFile.write("}\n\n")

836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
            self.ADA_HeaderFile.write(
                "procedure Ada_Execute_%s;\n" % self.CleanNameAsADAWants(sp._id + "_" + subProgramImplementation))
            self.ADA_HeaderFile.write('\nend %s;\n' % self.CleanNameAsADAWants(sp._id + "_" + subProgramImplementation))
            self.ADA_SourceFile.write(
                "procedure Ada_Execute_%s is\n" %
                self.CleanNameAsADAWants(sp._id + "_" + subProgramImplementation))
            self.ADA_SourceFile.write(
                "    procedure C_Execute_%s;\n" %
                self.CleanNameAsADAWants(sp._id + "_" + subProgramImplementation))
            self.ADA_SourceFile.write(
                '    pragma Import(C, C_Execute_%s, "Execute_%s");\n' %
                (
                    self.CleanNameAsADAWants(sp._id + "_" + subProgramImplementation),
                    self.CleanNameAsToolWants(sp._id + "_" + subProgramImplementation),
                ))

            self.ADA_SourceFile.write(
                'begin\n    C_Execute_%s;\n' %
                self.CleanNameAsADAWants(sp._id + "_" + subProgramImplementation))
            self.ADA_SourceFile.write(
                "end Ada_Execute_%s;\n\n" %
                self.CleanNameAsADAWants(sp._id + "_" + subProgramImplementation))
            self.ADA_SourceFile.write('\nend %s;\n' % self.CleanNameAsADAWants(sp._id + "_" + subProgramImplementation))
859
860
861


SynchronousToolGlueGenerator = SynchronousToolGlueGeneratorGeneric[str, str]