• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# coding=utf-8
3#   Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
4#    Licensed under the Apache License, Version 2.0 (the "License");
5#    you may not use this file except in compliance with the License.
6#    You may obtain a copy of the License at
7#
8#        http://www.apache.org/licenses/LICENSE-2.0
9#
10#    Unless required by applicable law or agreed to in writing, software
11#    distributed under the License is distributed on an "AS IS" BASIS,
12#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13#    See the License for the specific language governing permissions and
14#    limitations under the License.
15
16"""
17* Description: NV binary create.
18* Create: 2020-3-10
19"""
20from ctypes import *
21import os
22import re
23import ctypes
24import sys
25import pycparser
26
27from parse_msgdefs import Visitor
28from conf_parser import ParserError
29
30nextIsBitfield = 0
31bitField = 0
32bitLength = 0
33lastByteLength = 0
34totalByteLen = 0
35baseByteSize = 0
36# type define
37class generate_data_stream:
38    def __init__(self):
39        self.v = Visitor()
40
41    def phase_etypes(self, file):
42        code = pycparser.parse_file(file)
43        tmp = Visitor()
44        tmp.visit(code)
45        self.v.typedefs.update(tmp.typedefs)
46
47    def is_dec(self, s):
48        try:
49            int(s)
50            return True
51        except ValueError:
52            pass
53        return False
54
55    def is_hex(self, s):
56        try:
57            int(s, 16)
58            return True
59        except ValueError:
60            pass
61        return False
62
63    def byte_len(self, value):
64        if value < 256:
65            return 1
66        elif value < 65536:
67            return 2
68        elif value < 4294967296:
69            return 4
70        else:
71            return 8
72
73# value 的几种case需要分别考虑
74#1.直接数字
75#2.直接字符串
76#3.枚举
77#4.简单数组
78#5.结构体
79#6.结构体数组
80#7.指针
81#8.指针数组
82    def get_value(self, value_str):
83        if self.is_dec(value_str):
84            value = int(value_str)
85            return value
86        elif self.is_hex(value_str):
87            value = int(value_str, 16)
88            return value
89        return None
90
91    def get_char_value(self, value_str):
92        if type(value_str) is int:
93            return value_str
94        if len(value_str) == 1:
95            return ord(value_str)
96        return None
97
98    def get_value_for_array(self, value_str):
99        if '[' not in value_str or ']' not in value_str:
100            return None
101        value_line_list = list(filter(None, re.split(r'[;,\s\"\[\]]\s*', value_str)))
102        return value_line_list
103
104    def get_value_for_char_array(self, value_str):
105        if '\"' not in value_str:
106            return None
107        value_str = value_str.replace('\"','')
108        value_line_list = [x for x in value_str]
109        return value_line_list
110
111    def get_value_str(self, value):
112        value_line_list = list(filter(None, value.split('\n')))
113        value_list = []
114        for i in range(len(value_line_list)):
115            tmp_list = list(filter(None, value_line_list[i].split(' = ')))
116            value_list.append(tmp_list[1])
117        return value_list
118
119    def get_enum_value(self, enum_fields, enum_str):
120        if 1:
121            enum_value = enum_fields.members.get(enum_str)
122            if enum_value is None:
123                msg = "[error] [%s] not a enum value, please check!!" % enum_str
124                raise ParserError(msg)
125            return enum_value
126
127        for field in enum_fields.members:
128            if enum_str == field:
129                return enum_fields.members[field]
130
131    def get_bitfield_value(self, fields, typename, value):
132        global nextIsBitfield
133        global bitField
134        global bitLength
135        global lastByteLength
136        global totalByteLen
137        global baseByteSize
138
139        bufferData = b''
140        bitsize = self.get_value(fields.bitsize)
141        bitLength += bitsize
142
143        if value.bit_length() > bitsize:
144            msg = "[error] [%s]'s value exceeds its bit width!!" % typename
145            raise ParserError(msg)
146        if bitLength == bitsize:
147            baseByteSize = sizeof(fields)
148            totalByteLen = 0
149        writeLen = 0
150        # 前后类型相同,不压缩处理
151        if bitLength > bitsize and sizeof(fields) == lastByteLength:
152            if bitLength > baseByteSize * 8:
153                writelen = max(self.byte_len(bitField), lastByteLength)
154                bufferData += bitField.to_bytes(writelen, byteorder="little", signed=True) if bitField < 0 \
155                    else bitField.to_bytes(writelen, byteorder="little", signed=False)
156                totalByteLen += writelen
157                bitField = 0
158                bitLength = bitsize  # 记录未写入的bit
159        # 前后类型不同,考虑压缩场景
160        elif bitLength > bitsize and sizeof(fields) != lastByteLength:
161            baseByteSize = sizeof(fields) if sizeof(fields) > lastByteLength else lastByteLength
162            if bitLength > baseByteSize * 8: # 不压缩处理
163                writelen = max(self.byte_len(bitField), lastByteLength)
164                bufferData += bitField.to_bytes(writelen, byteorder="little", signed=True) if bitField < 0 \
165                    else bitField.to_bytes(writelen, byteorder="little", signed=False)
166                totalByteLen += writelen
167                # 对齐处理
168                if totalByteLen % sizeof(fields) != 0:
169                    bitField = 0
170                    alignByteLen = sizeof(fields) - totalByteLen if sizeof(fields) > totalByteLen \
171                        else totalByteLen - sizeof(fields)
172                    bufferData += bitField.to_bytes(alignByteLen, byteorder="little", signed=True) if bitField < 0 \
173                        else bitField.to_bytes(alignByteLen, byteorder="little", signed=False)
174                    totalByteLen += alignByteLen
175                bitField = 0
176                bitLength = bitsize
177            if totalByteLen % baseByteSize != 0:  # 非对齐场景,不压缩
178                writelen = max(self.byte_len(bitField), lastByteLength)
179                bufferData += bitField.to_bytes(writelen, byteorder="little", signed=True) if bitField < 0 \
180                    else bitField.to_bytes(writelen, byteorder="little", signed=False)
181                totalByteLen += writelen
182                bitField = 0
183                bitLength = bitsize
184        lastByteLength = sizeof(fields)
185        if bitLength > bitsize:
186            bitField = (bitField | (value << (bitLength - bitsize)))
187        else:
188            bitField = value
189
190        # print("bitsize: ",bitsize)
191        # print("value: ",value)
192        # print("lastByteLength: ",lastByteLength)
193        # print("bitLength: ",bitLength)
194        # print("totalByteLen :", totalByteLen)
195        # print("bitField: ",bitField)
196        if bitLength == (sizeof(fields) * 8):
197            writelen = max(self.byte_len(bitField), sizeof(fields))
198            bufferData += bitField.to_bytes(writelen, byteorder="little", signed=True) if bitField < 0 \
199                else bitField.to_bytes(writelen, byteorder="little", signed=False)
200            totalByteLen += writelen
201            bitField = 0
202            bitLength = 0
203            return bufferData
204        if nextIsBitfield == 0:
205            # 后面非位域,数据输出。如果后面嵌套结构体,结构体起始仍为位域,仍需要考虑压缩
206            writelen = max(self.byte_len(bitField), sizeof(fields))
207            bufferData += bitField.to_bytes(writelen, byteorder="little", signed=True) if bitField < 0 \
208                else bitField.to_bytes(writelen, byteorder="little", signed=False)
209            totalByteLen += writelen
210            bitField = 0
211            bitLength = 0
212            if totalByteLen % baseByteSize != 0:
213                bitField = 0
214                alignByteLen = baseByteSize - (totalByteLen % baseByteSize)
215                bufferData += bitField.to_bytes(alignByteLen, byteorder="little", signed=True) if bitField < 0 \
216                    else bitField.to_bytes(alignByteLen, byteorder="little", signed=False)
217        # print("bufferData: ", bufferData)
218        return bufferData
219
220    def print_type(self, typename, value, isBaseType, isEnum, isSomeKindOfArray, isUnion, isPointer):
221        print("%s, value: %s, isBaseType :" % (typename, value), isBaseType) if isBaseType else None
222        print("%s, value: %s, isEnum :" % (typename, value), isEnum) if isEnum else None
223        print("%s, value: %s, isSomeKindOfArray :" % (typename, value), isSomeKindOfArray) if isSomeKindOfArray else None
224        print("%s, value: %s, isUnion :" % (typename, value), isUnion) if isUnion else None
225        print("%s, value: %s, isPointer :" % (typename, value), isPointer) if isPointer else None
226
227
228    def recursion_parse(self, fields, type_name, value):
229        global nextIsBitfield
230        # print('recurse field: ', fields)
231        # print('recurse type_name: ', type_name)
232        # print('recurse value: ', value)
233        isBitfield = hasattr(fields, "bitsize")
234        isBaseType = not hasattr(fields, "_fields_")
235        isEnum = hasattr(fields, "members")
236        isSomeKindOfArray = issubclass(fields, ctypes.Array)
237        isUnion = isinstance(fields, ctypes.Union)
238        isPointer = hasattr(fields, "contents")
239        #self.print_type(type_name, value, isBaseType, isEnum, isSomeKindOfArray, isUnion, isPointer)
240
241        if ((isBaseType and not isSomeKindOfArray) or isEnum or isPointer) and \
242            (type(value) is list or type(value) is dict):
243                msg = "[error] [%s] is not a array or a structrue, the value cannot be a list or a dict!!" % type_name
244                raise ParserError(msg)
245
246        if not ((isBaseType and not isSomeKindOfArray) or isEnum or isPointer) and \
247            not (type(value) is list or type(value) is dict):
248                msg = "[error] [%s] is a array or a structrue, the value must be a list or a dict!!" % type_name
249                raise ParserError(msg)
250
251        if isUnion and not isSomeKindOfArray and type(value) is list:
252            msg = "[error] [%s] is a union, the value must be a hex or int or a dict!!" % type_name
253            raise ParserError(msg)
254
255        buffer = b''
256        if isEnum:
257            buffer += self.get_enum_value(fields, value).to_bytes(sizeof(fields), byteorder="little")
258            # print("buffer: ", buffer)
259            return buffer
260
261        if isBaseType and not isSomeKindOfArray:
262            # print("base size: ", sizeof(fields))
263            # print("fileds: ", fields)
264            # print("type: ", type(fields))
265            if sizeof(fields) == 1 and \
266               isinstance(value, str) and \
267               not value.startswith('0x') and not value.startswith('0X'):
268                value = self.get_char_value(value)
269            else:
270                value = self.get_value(value)
271
272            if isBitfield:
273                buffer += self.get_bitfield_value(fields, type_name, value)
274            else:
275                buffer += value.to_bytes(sizeof(fields), byteorder="little", signed=True) if value < 0 \
276                    else value.to_bytes(sizeof(fields), byteorder="little", signed=False)
277            # print("buffer: ", buffer)
278            return buffer
279
280        if isUnion and not isSomeKindOfArray:
281            # print("union size: ", sizeof(fields))
282            # union要么指定成员赋值,要么直接整体赋值,不能是list,list无法知道对具体哪个成员赋值
283            if type(value) is not dict:
284                buffer += self.get_value(value).to_bytes(sizeof(fields), byteorder="little")
285            else:
286                # 增加枚举结构的解析
287                pass
288            # print("buffer: ", buffer)
289            return buffer
290
291        if isSomeKindOfArray:
292            if type(value) is not list:
293                msg = "[error] [%s] is a array, the value must be a list!!" % type_name
294                raise ParserError(msg)
295
296            # print("array type: ", fields._type_)
297            # print("array length: ", fields._length_)
298            idx = 0
299            for val in value:
300                buffer += self.recursion_parse(fields._type_, '%s[%d]' % (type_name, idx), val)
301                idx += 1
302            # print("sizeof array [%s]: " % type_name, sizeof(fields))
303            if len(buffer) > sizeof(fields):
304                msg = "[error] the value is oversized the array: [%s]!!" % type_name
305                raise ParserError(msg)
306            buffer += bytearray(sizeof(fields) - len(buffer))
307            # print("buffer: ", buffer)
308            return buffer
309
310        all_types = fields._fields_
311        # print('all_types in struct [%s] : ' % type_name, all_types)
312        if type(value) is list:
313            typesLen = len(all_types)
314            typesIdx = 0
315            for (item, item_class) in all_types:
316                if len(value) == 0:
317                    buffer += bytearray(sizeof(item_class))
318                    continue
319                if typesIdx + 1 < typesLen:
320                    nextField = all_types[typesIdx + 1][1]
321                    nextIsBitfield = hasattr(nextField, "bitsize")
322                else:
323                    nextIsBitfield = 0
324                buffer += self.recursion_parse(item_class, item, value[0])
325                del(value[0])
326                typesIdx += 1
327            if len(value) != 0:
328                msg = "[error] the value is not match the type: [%s]!!" % type_name
329                raise ParserError(msg)
330            return buffer
331
332        if type(value) is dict:
333            typesLen = len(all_types)
334            typesIdx = 0
335            for (item, item_class) in all_types:
336                item_value = value.get(item)
337                if item_value is None:
338                    buffer += bytearray(sizeof(item_class))
339                    continue
340                if typesIdx + 1 < typesLen:
341                    nextField = all_types[typesIdx + 1][1]
342                    nextIsBitfield = hasattr(nextField, "bitsize")
343                else:
344                    nextIsBitfield = 0
345                buffer += self.recursion_parse(item_class, item, item_value)
346                typesIdx += 1
347            return buffer
348
349    def generate(self, struct_name, value):
350        fields = self.v.typedefs.get(struct_name)
351        # print("struct: %s, value: " %struct_name, value)
352        # print('types: ', self.v.typedefs)
353        if fields is None:
354            msg = "[error] not found the type [%s]!" % struct_name
355            raise ParserError(msg)
356        buffer = self.recursion_parse(fields, struct_name, value)
357        return buffer, len(buffer)
358
359
360#DEBUG
361
362if __name__=="__main__":
363    class g_env:
364        flash_size = 0x3000
365        protocolKvIndex = 0
366        appKvIndex = 0x1000
367        secureKvindex = 0x2000
368        KV_STORE_DIR = {'security' : 0 ,'protocol' : 1 ,'application' : 2 ,'asset' : 3 }
369        KV_STATUS_DIR = {'alive':0xffff,'reserved':0,'deprecated':1}
370        KV_PAGE_ID = {'security' : 0xcb7e ,'protocol' : 0xda81 ,'application' : 0x254d ,'backup' : 0x34b2}
371
372    g_kv_pairs = {
373        'yml_test_eg' : {
374            'value' : {
375                'num_supported_bands' : 1,
376                'band_ids' :[8, 7, 6]
377            },
378            'permanence': False
379        },
380        'yml_test_eg2_mixed' : {
381            'value' : {
382                'param1' : 1,
383                'param2' : [[1,2,], [3,4], [5]]
384            },
385            'permanence': False
386        },
387        'yml_test_eg2' : {
388            'value' : [1, [[1,2,], [3,4]]],
389            'permanence': False
390        },
391
392        'test_nv_type_nest_deep' :{
393            'value' : [1, "C", 0,
394                        [[1, 0, 0x2222, [["TEST_NV_ENUM_1"], ["TEST_NV_ENUM_2"]]],
395                        [3, 0, 0x4444, [["TEST_NV_ENUM_3"], ["TEST_NV_ENUM_4"]]]]
396            ],
397            'permanence': False
398        },
399
400        'test_nv_type_nest_deep____pure_value' :{
401            'value' : [1, 0, "C",
402                        [[1, 0x2222, 0, [[0x1111], [0x2222]]]],
403                        [3, 0x4444, 0, [[0x33334444], [0x5555]]]
404            ],
405            'permanence': False
406        },
407        'test_nv_type_nest_deep___dict' :{
408            'value' : [1, [[1,2,], [3,4]]],
409            'permanence': False
410        },
411        'test_nv_type_nest_deep___mixed' :{
412            'value' : [1, [[1,2,], [3,4]]],
413            'permanence': False
414        }
415    }
416
417    struct_name = sys.argv[1]
418    etypes = sys.argv[2]
419    test = generate_data_stream()
420    test.phase_etypes(etypes)
421    nv_file_Bin = bytearray(g_env.flash_size)
422    for i in range(0, g_env.flash_size):
423        nv_file_Bin[i] = 0xFF
424    # SetKvPageHead(nv_file_Bin)
425
426    for keyValueItem in g_kv_pairs:
427        if keyValueItem != struct_name:
428            continue
429        value,value_len = test.generate(struct_name, g_kv_pairs[struct_name]['value'])
430        print("value: ", value)
431        print("value_len: ", value_len)
432        with open('nv.bin', 'wb') as f:
433            f.write(value)
434        break
435