asn2aadlPlus.py 22.6 KB
Newer Older
1
#!/usr/bin/env python3
2
3
4
5
6
7
8
"""
ASN.1 Importer

This is one of the tools that Semantix develops for the European
research project ASSERT. It parses an ASN.1 grammar and generates
references (in AADL) to all the existing types.
"""
9
10
11
12
13
14
import os
import re
import sys
import copy
import shutil
import getopt
15
import hashlib
16
17
import tempfile
import platform
18
19
from subprocess import Popen, PIPE
import distutils.spawn as spawn
20

21
22
from .commonPy import configMT
from .commonPy import asnParser
23
from .commonPy import __version__
24

25
from .commonPy.asnAST import (
26
27
28
    AsnBasicNode, AsnBool, AsnReal, AsnInt,
    AsnEnumerated, AsnString, AsnChoice, AsnSequence,
    AsnSequenceOf, AsnSet, AsnSetOf)
29
30


31
from .commonPy.utility import inform, panic, mysystem
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

# Ada package names per type
g_AdaPackageNameOfType = {}


def cleanNameAsAADLWants(name):
    return re.sub(r'[^a-zA-Z0-9_]', '_', name)


def cleanNameAsAsn1cWants(name):
    return cleanNameAsAADLWants(name)


g_lowerFloat = -1e350
g_upperFloat = 1e350


def verifyNodeRange(node):
    assert isinstance(node, AsnBasicNode)
    if isinstance(node, AsnInt):
52
        if not node._range:
53
54
55
56
57
58
59
60
61
            panic("INTEGER (in %s) must have a range constraint inside ASN.1,\n"
                  "or else we might lose accuracy during runtime!" % node.Location())
        # else:
        #     # asn1c uses C long for ASN.1 INTEGER. Assuming that our platform is 32 bit,
        #     # this allows values from -2147483648 to 2147483647
        #     if node._range[0] < -2147483648L:
        #        panic("INTEGER (in %s) must have a low limit >= -2147483648\n" % node.Location())
        #     if node._range[1] > 2147483647L:
        #        panic("INTEGER (in %s) must have a high limit <= 2147483647\n" % node.Location())
62
63

    if isinstance(node, AsnReal):
64
        if not node._range:
65
            panic(
66
                "REAL (in %s) must have a range constraint inside ASN.1,\n"
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
                "or else we might lose accuracy during runtime!" % node.Location())
        else:
            # asn1c uses C double for ASN.1 REAL.
            # this allows values from -1.7976931348623157E308 to 1.7976931348623157E308
            if node._range[0] == g_lowerFloat:
                panic(
                    "REAL (in %s) must have a low limit >= -1.7976931348623157E308\n"
                    % node.Location())
            if node._range[1] == g_upperFloat:
                panic(
                    "REAL (in %s) must have a high limit <= 1.7976931348623157E308\n"
                    % node.Location())


def calculateForNativeAndASN1SCC(absASN1SCCpath, autosrc, names, inputFiles):
    base = "ShowNativeBuffers"

    acn = " -ACN " if any(x.lower().endswith(".acn") for x in inputFiles) else ""
    inputASN1files = [x for x in inputFiles if not x.lower().endswith('.acn')]

87
88
    # Spawn ASN1SCC.exe compiler - for MacOS define a new sh file calling mono Asn1f2.exe
    if platform.system() == "Windows" or platform.system() == "Darwin":
89
        mysystem("%s -c -uPER -o \"%s\" %s %s" % (absASN1SCCpath, autosrc, acn, '"' + '" "'.join(inputFiles) + '"'))
90
91
92
        for line in os.popen("%s -AdaUses %s" % (absASN1SCCpath, '" "'.join(inputASN1files))):
            g_AdaPackageNameOfType[line.split(':')[0]] = line.split(':')[1].rstrip()
    else:
Maxime Perrotin's avatar
Maxime Perrotin committed
93
        cmd = "mono %s -c -uPER -fp AUTO -typePrefix asn1Scc -o \"%s\" %s %s" % (absASN1SCCpath, autosrc, acn, '"' + '" "'.join(inputFiles) + '"')
94
        res = mysystem(cmd)
95
96
        if res != 0:
            panic("This command failed: %s\n" % cmd)
Maxime Perrotin's avatar
Maxime Perrotin committed
97
        for line in os.popen('mono  %s -fp AUTO -typePrefix asn1Scc -AdaUses "%s"' % (absASN1SCCpath, '" "'.join(inputASN1files))):
98
99
100
101
            g_AdaPackageNameOfType[line.split(':')[0]] = line.split(':')[1].rstrip()

    msgEncoderFile = open(autosrc + os.sep + base + ".stats.c", 'w')

102
    # msgEncoderFile.write('#include "DumpableTypes.h"\n')
103
104
105
106
107
108
109

    for a in inputASN1files:
        msgEncoderFile.write('#include "%s.h"\n' % os.path.splitext(os.path.basename(a))[0])

    uniqueASNfiles = {}
    for asnFile in inputASN1files:
        tmpNames = {}
110
111
        for name in asnParser.g_typesOfFile[asnFile]:
            tmpNames[name] = asnParser.g_names[name]
112
113
114

        uniqueASNfiles[asnFile] = [
            copy.copy(tmpNames),                            # map Typename to type definition class from asnAST
115
116
            copy.copy(asnParser.g_astOfFile[asnFile]),    # list of nameless type definitions
            copy.copy(asnParser.g_leafTypeDict)]   # map from Typename to leafType
117

118
    configMT.outputDir = autosrc + os.sep
119
    # dumpable.CreateDumpableCtypes(uniqueASNfiles)
120

121
    for asnTypename in sorted(list(names.keys())):
122
123
124
125
        node = names[asnTypename]
        if node._isArtificial:
            continue
        cleaned = cleanNameAsAsn1cWants(asnTypename)
Maxime Perrotin's avatar
Maxime Perrotin committed
126
127
        msgEncoderFile.write('static asn1Scc%s sizeof_%s;\n' % (cleaned, cleaned))
        msgEncoderFile.write('char bytesEncoding_%s[asn1Scc%s_REQUIRED_BYTES_FOR_ENCODING];\n' % (cleaned, cleaned))
128
        if acn != "":
Maxime Perrotin's avatar
Maxime Perrotin committed
129
            msgEncoderFile.write('char bytesAcnEncoding_%s[asn1Scc%s_REQUIRED_BYTES_FOR_ACN_ENCODING];\n' % (cleaned, cleaned))
130
    msgEncoderFile.close()
131

132
133
134
    # Code generation - asn1c part
    # Create a dictionary to lookup the asn-types from their corresponding c-type
    namesDict = {}
135
    for asnTypename in sorted(list(names.keys())):
136
137
138
139
140
141
        node = names[asnTypename]
        if node._isArtificial:
            continue
        namesDict[cleanNameAsAsn1cWants(asnTypename)] = asnTypename

    # Get a list of all available compilers
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
142
    platformCompilers = ['gcc']
143
144
    try:
        pipe = Popen("find-supported-compilers", stdout=PIPE).stdout
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
145
        platformCompilers = pipe.read().splitlines()
146
    except OSError as err:
147
        print('Not running in a TASTE Environment: {}\nUsing GCC only for computing sizeofs'.format(str(err)))
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
148
        platformCompilers = ['gcc'.encode()]
149
    # Get the maximum size of each asn1type from all platform compilers
150
    messageSizes = {}
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
151
    for cc in platformCompilers:
152
153
154
        # Compile the generated C-file with each compiler
        pwd = os.getcwd()
        os.chdir(autosrc)
155
        path_to_compiler = spawn.find_executable(cc.decode('utf-8'))
156
        if path_to_compiler is None:
157
            os.chdir(pwd)
158
159
160
            continue
        for cfile in os.listdir("."):
            if cfile.endswith(".c"):
161
                if mysystem('%s -c -std=c99 -I. "%s" 2>"%s.stats.err"' % (path_to_compiler, cfile, base)) != 0:
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
162
                    panic("Compilation with %s failed...\n"
163
                          "(report inside '%s')\n" % (cc, os.path.join(autosrc, base + ".stats.err")))
164
165
166
        os.chdir(pwd)

        # Receive the size information for each value from the compiled object file
167
168
169
170
        if platform.system() == "Darwin":
            nm = "gnm"
        else:
            nm = "nm"
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
171
        for line in os.popen(nm + " --print-size " + autosrc + os.sep + base + ".stats.o").readlines():
172
173
174
175
            try:
                (dummy, size, dummy2, msg) = line.split()
            except ValueError:
                # Ignore lines that are not well-formatted
Maxime Perrotin's avatar
Maxime Perrotin committed
176
                continue
177

178
            # Remove prefix
179
180
181
            asnType = msg.split('_', 1)[1]
            # get asn-type from cleaned type
            asnType = namesDict[asnType]
182
            assert asnType in list(names.keys())
183
184
185
186
            # Find maximum
            messageSizes.setdefault(asnType, 0)
            messageSizes[asnType] = max(int(size, 16), messageSizes[asnType])

187
    return messageSizes
188
189
190
191
192
193
194
195
196


def ASNtoACN(asnFilename):
    replaces = {
        ".asn": ".acn",
        ".asn1": ".acn",
        ".ASN": ".ACN",
        ".ASN1": ".ACN",
    }
197
    for k, v in list(replaces.items()):
198
199
200
201
202
203
        if asnFilename.endswith(k):
            return asnFilename.replace(k, v)
    return asnFilename + ".acn"


def usage():
204
205
    panic("""\
Usage: asn2aadlPlus.py <options> <files> outputDataSpec.aadl
206
207
208
209
210
211
212

Where <files> is a list of ASN.1 and ACN files, and options can be:

    -k, --keep	    Don't delete temporary files
    -a, --aadlv2    Generate AADLv2 compliant output
    -v, --version   Show version number
    -d, --debug	    Enable debug output
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
213
    -f, --fast      Do not emit Source_Data_Size lines (invoke ASN1SCC without uPER or ACN options)
214
    -p, --platform  Comma seperated list of platform compilers (default: gcc)
215
    -h, --help	    This help message""")
216
217
218


def main():
219
220
221
222
223
    if "-pdb" in sys.argv:
        sys.argv.remove("-pdb")  # pragma: no cover
        import pdb  # pragma: no cover pylint: disable=wrong-import-position,wrong-import-order
        pdb.set_trace()  # pragma: no cover

224
    if "-v" in sys.argv:
225
226
227
228
        import pkg_resources  # pragma: no cover
        version = pkg_resources.require("dmt")[0].version  # pragma: no cover
        print("asn2aadlPlus v" + str(version))  # pragma: no cover
        sys.exit(1)  # pragma: no cover
229

Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
230
231
232
233
    keepFiles = False

    projectCache = os.getenv("PROJECT_CACHE")
    if projectCache is not None and not os.path.isdir(projectCache):
234
235
236
237
        try:
            os.mkdir(projectCache)
        except:
            panic("The configured cache folder:\n\n\t" + projectCache + "\n\n...is not there!\n")
238
239
240
241
242
243
244
245
246
247
248

    # Backwards compatibility - the '-acn' option is no longer necessary
    # (we auto-detect ACN files via their extension)
    while "-acn" in sys.argv:
        ofs = sys.argv.index("-acn")
        del sys.argv[ofs]
    if "-aadlv2" in sys.argv:
        ofs = sys.argv.index("-aadlv2")
        sys.argv[ofs] = '--aadlv2'

    try:
249
        optlist, args = getopt.gnu_getopt(sys.argv[1:], "hvkadf", ['help', 'version', 'keep', 'aadlv2', 'debug', 'fast', 'platform='])
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
250
    except getopt.GetoptError:
251
252
253
        usage()

    bAADLv2 = False
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
254
    keepFiles = False
255
    bFast = False
256

Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
257
    for opt, unused_arg in optlist:
258
259
260
        if opt in ("-h", "--help"):
            usage()
        elif opt in ("-v", "--version"):
261
            print("ASN2AADL v%s" % __version__)
262
263
            sys.exit(0)
        elif opt in ("-d", "--debug"):
264
            configMT.debugParser = True
265
266
        elif opt in ("-f", "--fast"):
            bFast = True
267
268
269
270
        elif opt in ("-a", "--aadlv2"):
            # Updated, June 2011: AADLv1 no longer supported.
            bAADLv2 = True
        elif opt in ("-k", "--keep"):
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
271
            keepFiles = True
272

273
274
275
    if len(args) < 2:
        usage()

276
    if 'PATH' not in os.environ or os.environ['PATH'] == '':
277
278
279
280
281
282
283
284
285
286
287
        p = os.defpath
    else:
        p = os.environ['PATH']
    for dirent in p.split(os.pathsep):
        if platform.system() == "Windows":
            f = os.path.join(dirent, 'gcc.exe')
        else:
            f = os.path.join(dirent, 'gcc')
        if os.access(f, os.X_OK):
            break
    else:
288
289
        panic("No '%s' found in your PATH... Aborting..." %
              "gcc.exe" if platform.version() == "Windows" else "gcc")
290
291
292
293
294
295
296

    # Check that the ASN.1/ACN files that are passed-in, do in fact exist.
    for x in args[:-1]:
        if not os.path.isfile(x):
            panic("'%s' is not a file!\n" % x)

    aadlFile = args[-1]
297
    inputFiles = [os.path.abspath(x) for x in args[:-1]]
298

299
300
301
302
303
304
305
306
    def md5(filename):
        hash_md5 = hashlib.md5()
        with open(filename, "rb") as f:
            for chunk in iter(lambda: f.read(4096), b""):
                hash_md5.update(chunk)
        return hash_md5.hexdigest()

    def checkIfNoWorkIsNeeded(asnfiles, aadlfile):
307
        oldMD5s = {}
308
309
310
        for line in open(aadlfile):
            if 'InputASN1FileChecksum' in line:
                md5sum, asnfile = line.split(':')[1:3]
311
312
313
314
315
                oldMD5s[asnfile] = md5sum
        # if the output AADL file contained MD5 checksums of the input ASN.1 files
        if oldMD5s:
            def ok(f):
                return os.path.exists(f) and md5(f) == oldMD5s[f]
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
316
            # ...and all the current input ASN.1 files exist in the 'burned' list
317
318
319
320
321
322
323
324
            # that was built inside the previous version of the output AADL file,
            # AND
            # all the current input ASN.1 files exist and their MD5 checksum
            # has remained identical to that burned in the previous version of
            # the output AADL file...
            if all(f in oldMD5s for f in asnfiles) and \
                    all(ok(x) for x in asnfiles):
                # ...then there's no need to redo anything.
325
326
327
328
329
330
331
                inform("No AADL dataview generation is necessary.")
                sys.exit(0)

    if os.path.exists(aadlFile) and all(os.path.exists(x) for x in inputFiles):
        checkIfNoWorkIsNeeded([x for x in inputFiles if not x.lower().endswith(".acn")],
                              aadlFile)

332
333
    # Check if we can skip the work altogether!

334
    # Parse the ASN.1 files (skip the ACN ones)
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
335
336
    asnFiles = [x for x in inputFiles if not x.lower().endswith('.acn')]
    asnParser.ParseAsnFileList(asnFiles)
337
338
339
    autosrc = tempfile.mkdtemp(".asn1c")
    inform("Created temporary directory (%s) for auto-generated files...", autosrc)
    absPathOfAADLfile = os.path.abspath(aadlFile)
340
    asn1SccPath = spawn.find_executable('asn1.exe')
341
    if asn1SccPath is None:
342
        panic("ASN1SCC seems not installed on your system (asn1.exe not found in PATH).\n")
343
344
345
346
347
348
349
    absASN1SCCpath = os.path.abspath(asn1SccPath)

    # A, those good old days... I could calculate the buffer size for BER (SIZ), and then compare
    # it to the size for Native (SIZ2, see above) and the max of the two suffices for any conf of the message.
    # CHOICEs, however, changed the picture...  what to put in?
    # Time to use the maximum of Native (SIZ2) and UPER (SIZE) and ACN (SIZ3)...

350
351
352
353
    if not bFast:
        messageSizes = calculateForNativeAndASN1SCC(absASN1SCCpath, autosrc, asnParser.g_names, inputFiles)
        for nodeTypename in list(messageSizes.keys()):
            messageSizes[nodeTypename] = [messageSizes[nodeTypename], (8 * (int((messageSizes[nodeTypename] - 1) / 8)) + 8)]
354
355
356
357
358
359
360

    base = os.path.basename(aadlFile)
    base = re.sub(r'\..*$', '', base)

    # AADL creation
    o = open(absPathOfAADLfile, 'w')
    o.write('--------------------------------------------------------\n')
361
    o.write('--! File generated by asn2aadl v%s: DO NOT EDIT !\n' % __version__)
362
363
364
    o.write('--------------------------------------------------------\n')

    for f in [x for x in inputFiles if not x.lower().endswith(".acn")]:
365
        o.write('--! InputASN1FileChecksum:' + md5(f) + ':' + f + ':\n')
366
367
368
369
370
371
372
    o.write('--------------------------------------------------------\n\n')
    o.write('package DataView\n\npublic\n\n')
    if bAADLv2:
        o.write('  with Data_Model;\n')
        o.write('  with Taste;\n')
        o.write('  with Base_Types;\n')
        o.write('  with Deployment;\n')
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
373
    typesUnusableAsInterfaceParameters = []
374
    if bAADLv2:
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
375
376
        directiveTypes = [
            "Simulink_Tunable_Parameter", "Timer", "Taste_directive"]
377
378
379
380
        for typeName in directiveTypes:
            sourceText = ""
            adaPackageName = "TASTE_Directives"
            moduleName = "TASTE-Directives"
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
381
382
383
384
385
386
387
388
389
390
391
392
            o.write('DATA {typeName}\n'
                    'PROPERTIES\n'
                    '   TASTE::Ada_Package_Name => "{adaPackageName}";\n'
                    '   Type_Source_Name => "{typeNameASN}";\n'
                    '   Deployment::ASN1_Module_Name => "{moduleName}";{sourceText}\n'
                    '   TASTE::Forbid_in_PI => true;\n'
                    'END {typeName};\n'.format(
                        typeName=typeName,
                        typeNameASN=typeName.replace('_', '-'),
                        sourceText=sourceText,
                        adaPackageName=adaPackageName,
                        moduleName=moduleName))
393

394
395
396
397
398
        typesUnusableAsInterfaceParameters = []
        for line in os.popen("badTypes '" + "' '".join(asnFiles) + "'").readlines():
            line = line.strip().replace('-', '_')
            typesUnusableAsInterfaceParameters.append(line)

399
400
401
402
403
404
405
        o.write('''
data Stream_Element_Buffer
    -- Root type for buffer elements
properties
    Data_Model::Data_Representation => Character;
end Stream_Element_Buffer;
''')
406
    for asnTypename in sorted(list(asnParser.g_names.keys())):
407
        node = asnParser.g_names[asnTypename]
408
409
410
411
412
413
        if node._isArtificial:
            continue
        cleanName = cleanNameAsAADLWants(asnTypename)
        o.write('DATA ' + cleanName + '\n')
        o.write('PROPERTIES\n')
        o.write('    -- name of the ASN.1 source file:\n')
414
415
        # o.write('    Source_Text => ("%s");\n' % os.path.basename(asnParser.g_names[asnTypename]._asnFilename))
        o.write('    Source_Text => ("%s");\n' % asnParser.g_names[asnTypename]._asnFilename)
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
416
        prefix = "TASTE::" if bAADLv2 else ""
417
        possibleACN = ASNtoACN(asnParser.g_names[asnTypename]._asnFilename)
418
        if bAADLv2 and os.path.exists(possibleACN):
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
419
            prefix2 = "TASTE::" if bAADLv2 else "assert_properties::"
420
421
422
423
424
425
            base = os.path.splitext(os.path.basename(possibleACN))[0]
            fname = base.replace("-", "_")
            o.write('    %sEncodingDefinitionFile => classifier(DataView::ACN_%s);\n' % (prefix2, fname))
        o.write('    %sAda_Package_Name => "%s";\n' % (prefix, g_AdaPackageNameOfType[asnTypename]))
        if bAADLv2:
            o.write('    Deployment::ASN1_Module_Name => "%s";\n' % g_AdaPackageNameOfType[asnTypename].replace('_', '-'))
426
        if os.getenv('UPD') is None:
427
            o.write('    Source_Language => (ASN1);\n')
428
429
430
431
432
433
        if not bFast:
            o.write('    -- Size of a buffer to cover all forms of message representation:\n')
            le_size = 0 if asnTypename not in messageSizes else messageSizes[asnTypename][0]
            o.write('    -- Real message size is %d; suggested aligned message buffer is...\n' % le_size)
            le_size_rounded = 0 if asnTypename not in messageSizes else messageSizes[asnTypename][1]
            o.write('    Source_Data_Size => %d B%s;\n' % (le_size_rounded, bAADLv2 and "ytes" or ""))
434
435
        o.write('    -- name of the corresponding data type in the source file:\n')
        o.write('    Type_Source_Name => "%s";\n' % asnTypename)
436
        o.write('    TASTE::Position_In_File => [ line => %s ; column => 1 ; ];\n' % node._lineno)
437
        o.write('    -- what kind of type is this?\n')
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
438
        prefix = "TASTE" if bAADLv2 else "assert_properties"
439
        o.write('    %s::ASN1_Basic_Type =>' % prefix)
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
        if isinstance(node, AsnBool):
            o.write('aBOOLEAN;\n')
        elif isinstance(node, AsnInt):
            o.write('aINTEGER;\n')
        elif isinstance(node, AsnReal):
            o.write('aREAL;\n')
        elif isinstance(node, AsnEnumerated):
            o.write('aENUMERATED;\n')
        elif isinstance(node, AsnString):
            o.write('aSTRING;\n')
        elif isinstance(node, AsnChoice):
            o.write('aCHOICE;\n')
        elif isinstance(node, AsnSequence):
            o.write('aSEQUENCE;\n')
        elif isinstance(node, AsnSequenceOf):
            o.write('aSEQUENCEOF;\n')
        elif isinstance(node, AsnSet):
            o.write('aSET;\n')
        elif isinstance(node, AsnSetOf):
            o.write('aSETOF;\n')
        else:
            panic("Unsupported ASN.1 type: %s" % node._leafType)
462
463
        if asnTypename in typesUnusableAsInterfaceParameters:
            o.write('    TASTE::Forbid_in_PI => true;\n')
464
        o.write('END ' + cleanName + ';\n\n')
465
466
        o.write('DATA IMPLEMENTATION ' + cleanName + '.impl\n')
        o.write('END ' + cleanName + '.impl;\n\n')
467
        if os.getenv('UPD') is None:
468
469
470
471
472
473
474
            o.write('DATA ' + cleanName + '_Buffer_Max\n')
            o.write('END ' + cleanName + '_Buffer_Max;\n\n')

            o.write('DATA IMPLEMENTATION ' + cleanName + '_Buffer_Max.impl\n')
            o.write('    -- Buffer to hold a marshalled data of type ' + cleanName + "\n")
            o.write('PROPERTIES\n')
            o.write('    Data_Model::Data_Representation => array;\n')
Maxime Perrotin's avatar
Maxime Perrotin committed
475
            o.write('    Data_Model::Dimension => (%d); -- Size of the buffer\n' % le_size_rounded)
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
476
            o.write('    Source_Data_Size => %d Bytes; -- Size of the buffer in bytes\n' % le_size_rounded)
477
478
479
480
481
482
483
484
485
486
487
488
489
            if bAADLv2:
                o.write('    Data_Model::Base_Type => (classifier (DataView::Stream_Element_Buffer));\n')
            else:
                o.write('    Data_Model::Base_Type => (data ASSERT_Types::Stream_Element);\n')
            o.write('END ' + cleanName + '_Buffer_Max.impl;\n\n')

            o.write('DATA ' + cleanName + '_Buffer\n')
            o.write('END ' + cleanName + '_Buffer;\n\n')

            o.write('DATA IMPLEMENTATION ' + cleanName + '_Buffer.impl\n')
            o.write('    -- Buffer to hold a marshalled data of type ' + cleanName + "\n")
            o.write('SUBCOMPONENTS\n')
            o.write('    Buffer : data ' + cleanName + '_Buffer_Max.impl;\n')
490
            o.write('    Length : data Base_Types::%s;\n' % (bAADLv2 and "Unsigned_32" or "uint32"))
491
492
            o.write('PROPERTIES\n')
            o.write('    Data_Model::Data_Representation => Struct;\n')
493
494
            o.write('    Source_Data_Size => %d Bytes; -- Size of the buffer in bytes\n' % (
                le_size_rounded + 16))
495
496
            o.write('END ' + cleanName + '_Buffer.impl;\n\n')

497
498
499
500
501
502
503
504
    # Generate a SYSTEM in the DataView, otherwise Ocarina cannot parse it
    # standalone. This allows buildsupport to get the list of ASN.1 files
    # and modules, which is otherwise not visible unless those for which
    # at least one type is referenced in a provided interface.
    o.write('SYSTEM Taste_DataView\n')
    o.write('END    Taste_DataView;\n\n')
    o.write('SYSTEM IMPLEMENTATION Taste_DataView.others\n')
    o.write('SUBCOMPONENTS\n')
505
    for asnTypename in sorted(list(asnParser.g_names.keys())):
506
507
508
509
        node = asnParser.g_names[asnTypename]
        if node._isArtificial:
            continue
        cleanName = cleanNameAsAADLWants(asnTypename)
510
        o.write('   %s : DATA %s.impl;\n' % (cleanName, cleanName))
511
512
    o.write('END Taste_DataView.others;\n')

513
    listOfAsn1Files = {}
514
    for asnTypename in sorted(list(asnParser.g_names.keys())):
515
        listOfAsn1Files[asnParser.g_names[asnTypename]._asnFilename] = 1
516
517

    if bAADLv2:
518
        for asnFilename in sorted(list(listOfAsn1Files.keys())):
519
520
521
522
523
524
525
            base = os.path.splitext(os.path.basename(asnFilename))[0]
            possibleACN = ASNtoACN(asnFilename)
            if os.path.exists(possibleACN):
                fname = base.replace("-", "_")
                o.write('DATA ACN_' + fname + '\n')
                o.write('PROPERTIES\n')
                o.write('    Source_Text => ("' + possibleACN + '");\n')
526
                o.write('    Source_Language => (ACN);\n')
527
528
529
530
531
532
                o.write('END ACN_' + fname + ';\n\n')

    o.write('end DataView;\n')
    o.close()

    # Remove generated code
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
533
    if not keepFiles:
534
535
        shutil.rmtree(autosrc)
    else:
536
537
        print("Generated message buffers in '%s'" % autosrc)
    # os.chdir(pwd)
538

Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
539

540
if __name__ == "__main__":
541
    main()
542
543

# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4