1. add parsing map IAR compiler file. 2. fix bug in iar_parser.py. All works
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -25,7 +25,10 @@
|
|||||||
/bin*
|
/bin*
|
||||||
/logs*
|
/logs*
|
||||||
/iar_files*
|
/iar_files*
|
||||||
/python
|
/python/iar_parser/.idea
|
||||||
|
/python/iar_parser/.venv
|
||||||
|
/python/iar_parser/__pycache__
|
||||||
|
/python/iar_parser/venv
|
||||||
/build*
|
/build*
|
||||||
/configs/test_cases*
|
/configs/test_cases*
|
||||||
*.Debug
|
*.Debug
|
||||||
|
|||||||
@@ -37,7 +37,8 @@
|
|||||||
|
|
||||||
"one": [
|
"one": [
|
||||||
"test_UART_cmdSetDataInterface.json",
|
"test_UART_cmdSetDataInterface.json",
|
||||||
"test_readSnapshot_HK.json"
|
"test_readSnapshot_HK.json",
|
||||||
|
"test_read_NANDctrlOper.json"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
338
python/iar_parser/elf_parser.py
Normal file
338
python/iar_parser/elf_parser.py
Normal file
@@ -0,0 +1,338 @@
|
|||||||
|
from elftools.elf.elffile import ELFFile
|
||||||
|
from construct.lib import ListContainer
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
class DWARFstructParser:
|
||||||
|
def __init__(self, elf_file, TARGET, out_path):
|
||||||
|
self.elf_file = elf_file
|
||||||
|
self.out_path = out_path
|
||||||
|
self.die_map = {}
|
||||||
|
self.TARGET = TARGET
|
||||||
|
self.struct_json = {
|
||||||
|
"name": self.TARGET,
|
||||||
|
"fields": [],
|
||||||
|
"size": 0
|
||||||
|
}
|
||||||
|
self._build_die_map()
|
||||||
|
|
||||||
|
def _map_type(self, size):
|
||||||
|
if size == 1:
|
||||||
|
return "uint8"
|
||||||
|
if size == 2:
|
||||||
|
return "uint16"
|
||||||
|
if size == 4:
|
||||||
|
return "uint32"
|
||||||
|
if size == 8:
|
||||||
|
return "uint64"
|
||||||
|
return f"bytes[{size}]"
|
||||||
|
|
||||||
|
def _build_die_map(self):
|
||||||
|
try:
|
||||||
|
with open(self.elf_file, "rb") as f:
|
||||||
|
elf = ELFFile(f)
|
||||||
|
if not elf.has_dwarf_info():
|
||||||
|
raise ValueError(f"File {self.elf_file} not contains DWARF-info")
|
||||||
|
|
||||||
|
dwar_finfo = elf.get_dwarf_info()
|
||||||
|
for cu in dwar_finfo.iter_CUs():
|
||||||
|
for die in cu.iter_DIEs():
|
||||||
|
self.die_map[die.offset] = die
|
||||||
|
|
||||||
|
except FileNotFoundError:
|
||||||
|
raise FileNotFoundError(f"file not found in path: {self.elf_file}")
|
||||||
|
except Exception as e:
|
||||||
|
raise RuntimeError(f"error while elf-file reading: {str(e)}")
|
||||||
|
|
||||||
|
def _get_name(self, die):
|
||||||
|
a = die.attributes.get("DW_AT_name")
|
||||||
|
if not a:
|
||||||
|
return None
|
||||||
|
v = a.value
|
||||||
|
if isinstance(v, bytes):
|
||||||
|
return v.decode(errors="ignore")
|
||||||
|
return str(v)
|
||||||
|
|
||||||
|
def _get_type_offset(self, die):
|
||||||
|
a = die.attributes.get("DW_AT_type")
|
||||||
|
if not a:
|
||||||
|
return None
|
||||||
|
|
||||||
|
ref = a.value
|
||||||
|
|
||||||
|
# absolute ref
|
||||||
|
if ref in self.die_map:
|
||||||
|
return ref
|
||||||
|
|
||||||
|
# CU relative ref
|
||||||
|
ref2 = ref + die.cu.cu_offset
|
||||||
|
if ref2 in self.die_map:
|
||||||
|
return ref2
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _resolve(self, die):
|
||||||
|
if die is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
while die.tag in (
|
||||||
|
"DW_TAG_typedef",
|
||||||
|
"DW_TAG_const_type",
|
||||||
|
"DW_TAG_volatile_type",
|
||||||
|
"DW_TAG_restrict_type"
|
||||||
|
):
|
||||||
|
ref = self._get_type_offset(die)
|
||||||
|
|
||||||
|
if ref is None:
|
||||||
|
return die
|
||||||
|
|
||||||
|
target = self.die_map.get(ref)
|
||||||
|
|
||||||
|
if target is None:
|
||||||
|
return die
|
||||||
|
|
||||||
|
die = target
|
||||||
|
|
||||||
|
return die
|
||||||
|
|
||||||
|
def _get_size(self, die):
|
||||||
|
a = die.attributes.get("DW_AT_byte_size")
|
||||||
|
if not a:
|
||||||
|
return 0
|
||||||
|
return int(a.value)
|
||||||
|
|
||||||
|
def _get_member_offset(self, die):
|
||||||
|
a = die.attributes.get("DW_AT_data_member_location")
|
||||||
|
if not a:
|
||||||
|
return 0
|
||||||
|
v = a.value
|
||||||
|
# ordinary int
|
||||||
|
if isinstance(v, int):
|
||||||
|
return v
|
||||||
|
# ListContainer
|
||||||
|
try:
|
||||||
|
# [DWARFExprOp(... args=[11])]
|
||||||
|
for item in v:
|
||||||
|
if hasattr(item, "args"):
|
||||||
|
if len(item.args):
|
||||||
|
return int(item.args[0])
|
||||||
|
# [35, 11]
|
||||||
|
vals = list(v)
|
||||||
|
if len(vals) >= 2 and isinstance(vals[1], int):
|
||||||
|
return vals[1]
|
||||||
|
except:
|
||||||
|
raise RuntimeError(f"unsupported type found in structure {self.TARGET}: {str(v)}")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def _resolve_array(self, die):
|
||||||
|
|
||||||
|
if die.tag != "DW_TAG_array_type":
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
element_type = None
|
||||||
|
count = None
|
||||||
|
|
||||||
|
# search subrange
|
||||||
|
for child in die.iter_children():
|
||||||
|
|
||||||
|
if child.tag != "DW_TAG_subrange_type":
|
||||||
|
continue
|
||||||
|
|
||||||
|
# COUNT
|
||||||
|
if "DW_AT_count" in child.attributes:
|
||||||
|
count = child.attributes["DW_AT_count"].value
|
||||||
|
|
||||||
|
elif "DW_AT_upper_bound" in child.attributes:
|
||||||
|
# upper_bound = N-1
|
||||||
|
count = child.attributes["DW_AT_upper_bound"].value + 1
|
||||||
|
|
||||||
|
# base type array
|
||||||
|
t = die.attributes.get("DW_AT_type")
|
||||||
|
|
||||||
|
if t:
|
||||||
|
element_type = self.die_map[t.value + die.cu.cu_offset]
|
||||||
|
|
||||||
|
return element_type, count
|
||||||
|
|
||||||
|
def _resolve(self, die):
|
||||||
|
while die.tag in ("DW_TAG_typedef", "DW_TAG_const_type", "DW_TAG_volatile_type", "DW_TAG_restrict_type"):
|
||||||
|
ref = self._get_type_offset(die)
|
||||||
|
if ref is None:
|
||||||
|
return die
|
||||||
|
die = self.die_map[ref]
|
||||||
|
|
||||||
|
return die
|
||||||
|
|
||||||
|
def _detect_type(self, die, size):
|
||||||
|
die = self._resolve(die)
|
||||||
|
|
||||||
|
if die is None:
|
||||||
|
return f"bytes[{size}]"
|
||||||
|
|
||||||
|
if die.tag == "DW_TAG_enumeration_type":
|
||||||
|
return "enum"
|
||||||
|
|
||||||
|
if die.tag == "DW_TAG_pointer_type":
|
||||||
|
return "pointer"
|
||||||
|
|
||||||
|
if die.tag == "DW_TAG_base_type":
|
||||||
|
name = self._get_name(die)
|
||||||
|
|
||||||
|
if name:
|
||||||
|
return name
|
||||||
|
|
||||||
|
return self._map_type(size)
|
||||||
|
def _dump_struct(self, die, base=0, prefix=""):
|
||||||
|
die = self._resolve(die)
|
||||||
|
if die.tag != "DW_TAG_structure_type":
|
||||||
|
return
|
||||||
|
|
||||||
|
for child in die.iter_children():
|
||||||
|
if child.tag != "DW_TAG_member":
|
||||||
|
continue
|
||||||
|
|
||||||
|
field_name = self._get_name(child)
|
||||||
|
field_offset = self._get_member_offset(child)
|
||||||
|
|
||||||
|
tref = self._get_type_offset(child)
|
||||||
|
if tref is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
target_die = self.die_map.get(tref)
|
||||||
|
|
||||||
|
if target_die is None:
|
||||||
|
print(
|
||||||
|
f"WARNING: type offset not found "
|
||||||
|
f"(field={field_name}, tref={tref})"
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
|
tdie = self._resolve(target_die)
|
||||||
|
|
||||||
|
if tdie is None:
|
||||||
|
print(
|
||||||
|
f"WARNING: unresolved type "
|
||||||
|
f"(field={field_name})"
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
|
size = self._get_size(tdie)
|
||||||
|
|
||||||
|
fullname = prefix + field_name
|
||||||
|
|
||||||
|
if tdie.tag == "DW_TAG_array_type":
|
||||||
|
|
||||||
|
elem_die, count = self._resolve_array(tdie)
|
||||||
|
|
||||||
|
if elem_die is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
elem_die = self._resolve(elem_die)
|
||||||
|
elem_size = self._get_size(elem_die)
|
||||||
|
|
||||||
|
if count is None:
|
||||||
|
count = 1
|
||||||
|
|
||||||
|
total_size = elem_size * count
|
||||||
|
|
||||||
|
elem_type = self._detect_type(tdie, elem_size)
|
||||||
|
|
||||||
|
self.struct_json["fields"].append({
|
||||||
|
"name": fullname,
|
||||||
|
"offset": base + field_offset,
|
||||||
|
"size": total_size,
|
||||||
|
"array": True,
|
||||||
|
"count": count,
|
||||||
|
"elem_size": elem_size,
|
||||||
|
"elem_type": elem_type
|
||||||
|
})
|
||||||
|
|
||||||
|
continue
|
||||||
|
|
||||||
|
self.struct_json["fields"].append({
|
||||||
|
"name": fullname,
|
||||||
|
"offset": base + field_offset,
|
||||||
|
"size": size,
|
||||||
|
"type": self._detect_type(tdie, size)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
self.struct_json["size"] = max(
|
||||||
|
self.struct_json["size"],
|
||||||
|
base + field_offset + size
|
||||||
|
)
|
||||||
|
|
||||||
|
# recursion nested struct
|
||||||
|
if tdie.tag == "DW_TAG_structure_type":
|
||||||
|
self._dump_struct(
|
||||||
|
tdie,
|
||||||
|
base + field_offset,
|
||||||
|
fullname + "."
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_struct(self, use_typedef=True):
|
||||||
|
find_flag = False
|
||||||
|
|
||||||
|
for die in self.die_map.values():
|
||||||
|
if die.tag != "DW_TAG_typedef":
|
||||||
|
continue
|
||||||
|
|
||||||
|
name = self._get_name(die)
|
||||||
|
if name != self.TARGET:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
find_flag = True
|
||||||
|
ref = self._get_type_offset(die)
|
||||||
|
real = self.die_map[ref]
|
||||||
|
self._dump_struct(real)
|
||||||
|
break
|
||||||
|
|
||||||
|
if find_flag == True:
|
||||||
|
return self.struct_json
|
||||||
|
else:
|
||||||
|
raise RuntimeError(f"struct {self.TARGET} not found in elf-file")
|
||||||
|
|
||||||
|
def save_struct_to_json(self, struct_json):
|
||||||
|
output_file = f"{self.out_path}{self.TARGET}.json"
|
||||||
|
|
||||||
|
with open(output_file, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(struct_json, f, indent=2, ensure_ascii=False)
|
||||||
|
print("\nJSON saved to:", output_file)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# TARGET = "UART_cmdSetNANDsettings_t"
|
||||||
|
# fname = r"C:\Danila\work\sputnik_test\src\sputnik\Debug\c.out"
|
||||||
|
# usage example:
|
||||||
|
# python elf_parser.py -f "C:\Danila\work\sputnik_test\src\sputnik\Debug\c.out" -t "Snapshot_HK_t"
|
||||||
|
|
||||||
|
argparser = argparse.ArgumentParser("elf_parser.py")
|
||||||
|
|
||||||
|
argparser.add_argument('-f', '--elf_file', required=True,
|
||||||
|
help='specify path to elf-file')
|
||||||
|
argparser.add_argument('-t', '--struct_name', required=True,
|
||||||
|
help='specify structure name (\"UART_t\" for example')
|
||||||
|
argparser.add_argument('-o', '--out_path', required=True,
|
||||||
|
help='specify out path with map data file in json format (\"C:/data/\" for example)')
|
||||||
|
|
||||||
|
args = argparser.parse_args()
|
||||||
|
|
||||||
|
try:
|
||||||
|
# elf_file = "C:\Danila\work\sputnik_test\src\sputnik\Debug\c.out"
|
||||||
|
# struct_name = "NANDctrlOper_t"
|
||||||
|
# out_path = "./"
|
||||||
|
# parser = DWARFstructParser(elf_file, struct_name, out_path)
|
||||||
|
|
||||||
|
parser = DWARFstructParser(args.elf_file, args.struct_name, args.out_path)
|
||||||
|
json_struct = parser.get_struct()
|
||||||
|
parser.save_struct_to_json(json_struct)
|
||||||
|
|
||||||
|
except (FileNotFoundError, ValueError, LookupError, IOError) as err:
|
||||||
|
print(f"ERROR code 2: {str(err)}", file=sys.stderr)
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
except Exception as unexpected_arr:
|
||||||
|
print(f"ERROR code 3: {str(unexpected_arr)}", file=sys.stderr)
|
||||||
|
sys.exit(3)
|
||||||
0
python/iar_parser/main.py
Normal file
0
python/iar_parser/main.py
Normal file
168
python/iar_parser/map_parser.py
Normal file
168
python/iar_parser/map_parser.py
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
import json
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
class map_parser:
|
||||||
|
def __init__(self, map_file, out_path):
|
||||||
|
self.map_file = map_file
|
||||||
|
self.out_path = out_path
|
||||||
|
self.map_data = None
|
||||||
|
self._open_map_file()
|
||||||
|
|
||||||
|
def _open_map_file(self):
|
||||||
|
try:
|
||||||
|
with open(self.map_file, 'r', encoding="utf-8") as f:
|
||||||
|
self.map_data = f.read()
|
||||||
|
except FileNotFoundError:
|
||||||
|
raise FileNotFoundError(f"file not found in path: {self.map_file}")
|
||||||
|
except Exception as e:
|
||||||
|
raise RuntimeError(f"error while .map file reading: {str(e)}")
|
||||||
|
|
||||||
|
def get_description_to_json(self, descript_name):
|
||||||
|
entries = {}
|
||||||
|
|
||||||
|
lines = self.map_data.splitlines()
|
||||||
|
|
||||||
|
if "ENTRY LIST" in descript_name:
|
||||||
|
section_lines = []
|
||||||
|
inside_entry_list = False
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
if "ENTRY LIST" in line:
|
||||||
|
inside_entry_list = True
|
||||||
|
continue
|
||||||
|
|
||||||
|
if inside_entry_list:
|
||||||
|
if "********" in line:
|
||||||
|
break
|
||||||
|
section_lines.append(line)
|
||||||
|
|
||||||
|
if not inside_entry_list:
|
||||||
|
raise RuntimeError(f"specified description name: {descript_name} not found in specified .map file")
|
||||||
|
|
||||||
|
# 2. Регулярное выражение для разбора строк (символы ?, $, . внутри \S+)
|
||||||
|
pattern = re.compile(
|
||||||
|
r"^\s*(?P<name>\S+)\s+(?P<address>0x[0-9a-fA-F]+)\s+(?P<size>0x[0-9a-fA-F]+|--)\s+(?P<type>\w+)"
|
||||||
|
)
|
||||||
|
|
||||||
|
for line in section_lines:
|
||||||
|
line = line.strip()
|
||||||
|
match = pattern.match(line)
|
||||||
|
if match:
|
||||||
|
data = match.groupdict()
|
||||||
|
name = data["name"]
|
||||||
|
raw_size = data["size"]
|
||||||
|
|
||||||
|
size_val = None if raw_size == "--" else int(raw_size, 16)
|
||||||
|
|
||||||
|
entries[name] = {
|
||||||
|
"address": data["address"],
|
||||||
|
"size_hex": raw_size if raw_size != "--" else None,
|
||||||
|
"size_bytes": size_val,
|
||||||
|
"type": data["type"],
|
||||||
|
}
|
||||||
|
|
||||||
|
return entries
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise RuntimeError(f"specified description name: {descript_name} not found in .map file or not supported")
|
||||||
|
|
||||||
|
def save_data_to_json(self, data_json, descript_name):
|
||||||
|
output_file = f"{self.out_path}{descript_name.replace(" ", "_")}_map.json"
|
||||||
|
|
||||||
|
with open(output_file, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(data_json, f, indent=2, ensure_ascii=False)
|
||||||
|
print("\nJSON saved to:", output_file)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
#descript_name = "ENTRY LIST"
|
||||||
|
#fname = r"C:\Danila\work\sputnik_test\src\sputnik\Debug\sputnik.map"
|
||||||
|
# usage example:
|
||||||
|
# python elf_parser.py -f "C:\Danila\work\sputnik_test\src\sputnik\Debug\sputnik.map" -s "ENTRY LIST"
|
||||||
|
|
||||||
|
argparser = argparse.ArgumentParser("map_parser.py")
|
||||||
|
|
||||||
|
argparser.add_argument('-f', '--map_file', required=True,
|
||||||
|
help='specify path to map-file')
|
||||||
|
argparser.add_argument('-s', '--section_name', required=True,
|
||||||
|
help='specify section name in .map file (\"ENTRY LIST\" for example')
|
||||||
|
argparser.add_argument('-o', '--out_path', required=True,
|
||||||
|
help='specify out path with map data file in json format (\"C:/data/\" for example)')
|
||||||
|
|
||||||
|
args = argparser.parse_args()
|
||||||
|
|
||||||
|
try:
|
||||||
|
parser = map_parser(args.map_file, args.out_path)
|
||||||
|
data_json = parser.get_description_to_json(args.section_name)
|
||||||
|
parser.save_data_to_json(data_json, args.section_name)
|
||||||
|
|
||||||
|
except (FileNotFoundError, ValueError, LookupError, IOError) as err:
|
||||||
|
print(f"ERROR code 2: {str(err)}", file=sys.stderr)
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
except Exception as unexpected_arr:
|
||||||
|
print(f"Error code 3: {str(unexpected_arr)}", file=sys.stderr)
|
||||||
|
sys.exit(3)
|
||||||
|
|
||||||
|
# def parse_iar_map_text(map_text):
|
||||||
|
# entries = {}
|
||||||
|
#
|
||||||
|
# lines = map_text.splitlines()
|
||||||
|
# section_lines = []
|
||||||
|
# inside_entry_list = False
|
||||||
|
#
|
||||||
|
# for line in lines:
|
||||||
|
# # Если встретили заголовок (независимо от количества звездочек и пробелов)
|
||||||
|
# if "ENTRY LIST" in line:
|
||||||
|
# inside_entry_list = True
|
||||||
|
# continue # Пропускаем саму строку заголовка
|
||||||
|
#
|
||||||
|
# if inside_entry_list:
|
||||||
|
# # Если дошли до следующей крупной секции (строка из множества звезд) — выходим
|
||||||
|
# if "********" in line:
|
||||||
|
# break
|
||||||
|
# section_lines.append(line)
|
||||||
|
#
|
||||||
|
# if not inside_entry_list:
|
||||||
|
# print("Ошибка: Секция ENTRY LIST не найдена в файле.")
|
||||||
|
# return entries
|
||||||
|
#
|
||||||
|
# # 2. Регулярное выражение для разбора строк (символы ?, $, . внутри \S+)
|
||||||
|
# pattern = re.compile(
|
||||||
|
# r"^\s*(?P<name>\S+)\s+(?P<address>0x[0-9a-fA-F]+)\s+(?P<size>0x[0-9a-fA-F]+|--)\s+(?P<type>\w+)"
|
||||||
|
# )
|
||||||
|
#
|
||||||
|
# # 3. Парсим собранные строки
|
||||||
|
# for line in section_lines:
|
||||||
|
# line = line.strip()
|
||||||
|
# match = pattern.match(line)
|
||||||
|
# if match:
|
||||||
|
# data = match.groupdict()
|
||||||
|
# name = data["name"]
|
||||||
|
# raw_size = data["size"]
|
||||||
|
#
|
||||||
|
# size_val = None if raw_size == "--" else int(raw_size, 16)
|
||||||
|
#
|
||||||
|
# entries[name] = {
|
||||||
|
# "address": data["address"],
|
||||||
|
# "size_hex": raw_size if raw_size != "--" else None,
|
||||||
|
# "size_bytes": size_val,
|
||||||
|
# "type": data["type"],
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# return entries
|
||||||
|
#
|
||||||
|
# fname_map = r"C:\Danila\work\sputnik_test\src\sputnik\Debug\sputnik.map"
|
||||||
|
#
|
||||||
|
# with open(fname_map, 'r', encoding="utf-8") as f:
|
||||||
|
# data = f.read()
|
||||||
|
# # print(data)
|
||||||
|
#
|
||||||
|
# result_json = parse_iar_map_text(data)
|
||||||
|
#
|
||||||
|
# json_map_file = "map.json"
|
||||||
|
# with open(json_map_file, 'w', encoding='utf-8') as f:
|
||||||
|
# # Выводим в stdout готовый JSON (Qt-стенд сможет его легко прочесть)
|
||||||
|
# json.dump(result_json, f, indent=2, ensure_ascii=False)
|
||||||
@@ -13,6 +13,8 @@ int main(int argc, char** argv)
|
|||||||
{
|
{
|
||||||
QCoreApplication app(argc, argv);
|
QCoreApplication app(argc, argv);
|
||||||
|
|
||||||
|
printf("Embedded test stand v1.2\n");
|
||||||
|
|
||||||
g_options = CLIParser::parse(argc, argv);
|
g_options = CLIParser::parse(argc, argv);
|
||||||
|
|
||||||
::testing::InitGoogleTest(&argc, argv);
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ path_t UARTFixture::path;
|
|||||||
UART_cmdReadMemory_t UARTFixture::iData;
|
UART_cmdReadMemory_t UARTFixture::iData;
|
||||||
char UARTFixture::cmdDataBuf[UART_DATA_MAX_BYTES];
|
char UARTFixture::cmdDataBuf[UART_DATA_MAX_BYTES];
|
||||||
QVector<QString> UARTFixture::struct_names;
|
QVector<QString> UARTFixture::struct_names;
|
||||||
|
JsonProcessor UARTFixture::json;
|
||||||
QString UARTFixture::logFile;
|
QString UARTFixture::logFile;
|
||||||
extern TestOptions g_options;
|
extern TestOptions g_options;
|
||||||
|
|
||||||
@@ -118,6 +119,7 @@ void UARTFixture::SetUpTestSuite()
|
|||||||
{
|
{
|
||||||
QString msg = QString("%1, path: %2").arg(errOpen.getMessage(), errOpen.getFilePath());
|
QString msg = QString("%1, path: %2").arg(errOpen.getMessage(), errOpen.getFilePath());
|
||||||
writeToLog(msg, false);
|
writeToLog(msg, false);
|
||||||
|
ASSERT_TRUE(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -143,15 +145,7 @@ TEST_P(UARTFixture, JsonCase)
|
|||||||
bool UARTFixture::loadTestCase(const QString& caseFile,
|
bool UARTFixture::loadTestCase(const QString& caseFile,
|
||||||
QJsonObject& cfg, QJsonObject &meta)
|
QJsonObject& cfg, QJsonObject &meta)
|
||||||
{
|
{
|
||||||
QFile caseFileJson(caseFile);
|
json.openJsonFile(caseFile, cfg);
|
||||||
|
|
||||||
if (!caseFileJson.open(QIODevice::ReadOnly))
|
|
||||||
{
|
|
||||||
writeToLog(QString("%1, path: %2").arg("json test case not found", caseFile), false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg = QJsonDocument::fromJson(caseFileJson.readAll()).object();
|
|
||||||
meta = cfg["meta"].toObject();
|
meta = cfg["meta"].toObject();
|
||||||
|
|
||||||
if (cfg.isEmpty() || meta.isEmpty())
|
if (cfg.isEmpty() || meta.isEmpty())
|
||||||
@@ -241,8 +235,6 @@ bool UARTFixture::runTextCase(const QJsonObject& cfg, QString caseFile, QString
|
|||||||
{
|
{
|
||||||
QByteArray tx;
|
QByteArray tx;
|
||||||
QString binaryFname;
|
QString binaryFname;
|
||||||
JsonProcessor json;
|
|
||||||
json.setJsonFile(caseFile);
|
|
||||||
json.jsonGetStrValue(cfg, "binary", binaryFname, jsonObjName);
|
json.jsonGetStrValue(cfg, "binary", binaryFname, jsonObjName);
|
||||||
|
|
||||||
if (!loadBinaryFile(binaryFname, tx)) { return false; }
|
if (!loadBinaryFile(binaryFname, tx)) { return false; }
|
||||||
@@ -254,23 +246,80 @@ bool UARTFixture::runTextCase(const QJsonObject& cfg, QString caseFile, QString
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool UARTFixture::prepareBinaryCommand(const QJsonObject& cfg, QByteArray& data)
|
bool UARTFixture::prepareBinaryCommand(const QJsonObject& cfg, QByteArray& data, QString& caseFile)
|
||||||
{
|
{
|
||||||
// bool ok = false;
|
QJsonObject meta, paramTestCase, map_json, structObj_map;
|
||||||
QJsonObject meta, param;
|
bool ok;
|
||||||
meta = cfg["meta"].toObject();
|
|
||||||
param = meta["parameters"].toObject();
|
|
||||||
|
|
||||||
if (meta.isEmpty() || param.isEmpty())
|
QString map_fname = QString("%1ENTRY_LIST_map.json").arg(path.iar_json_out);
|
||||||
|
json.openJsonFile(map_fname, map_json);
|
||||||
|
|
||||||
|
meta = cfg["meta"].toObject();
|
||||||
|
paramTestCase = meta["parameters"].toObject();
|
||||||
|
|
||||||
|
QString struct_name;
|
||||||
|
json.jsonGetStrValue(paramTestCase, "struct_name", struct_name, "parameters");
|
||||||
|
|
||||||
|
if (meta.isEmpty() || paramTestCase.isEmpty())
|
||||||
{
|
{
|
||||||
writeToLog(QString("'meta' or 'parameters' field not found"), false);
|
writeToLog(QString("'meta' or 'parameters' field not found"), false);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
iData.version = param["version"].toInt();
|
iData.version = json.jsonGetIntValue(paramTestCase, "version", "parameters");
|
||||||
|
|
||||||
if (param["addr_user_set"].toBool())
|
bool addr_user_set = json.jsonGetBoolValue(paramTestCase, "addr_user_set", "parameters");
|
||||||
{ iData.size_bytes = param["size"].toInt(); }
|
bool size_user_set = json.jsonGetBoolValue(paramTestCase, "size_user_set", "parameters");
|
||||||
|
|
||||||
|
if (addr_user_set == false || size_user_set == false)
|
||||||
|
{
|
||||||
|
if (!map_json.contains(struct_name))
|
||||||
|
{
|
||||||
|
writeToLog(QString("'%1' field not found in json file: %2")
|
||||||
|
.arg(struct_name, map_fname), false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
structObj_map = map_json.value(struct_name).toObject();
|
||||||
|
|
||||||
|
if (structObj_map.isEmpty())
|
||||||
|
{
|
||||||
|
writeToLog(QString("'%1' field not found in json file: %2")
|
||||||
|
.arg(struct_name, map_fname), false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addr_user_set)
|
||||||
|
{
|
||||||
|
QString addr;
|
||||||
|
json.jsonGetStrValue(paramTestCase, "address", addr, "parameters");
|
||||||
|
iData.addr_begin = addr.toUInt(&ok, 16);
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
writeToLog(QString("'addr' field has incorrect format in json file: %2")
|
||||||
|
.arg(struct_name, caseFile), false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QString addrStr;
|
||||||
|
json.jsonGetStrValue(structObj_map, "address", addrStr, struct_name);
|
||||||
|
bool addrOk = false;
|
||||||
|
iData.addr_begin = addrStr.toUInt(&addrOk, 16);
|
||||||
|
if (!addrOk)
|
||||||
|
{
|
||||||
|
writeToLog(QString("'address' field has incorrect format in json file: %2")
|
||||||
|
.arg(struct_name, map_fname), false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size_user_set)
|
||||||
|
{ iData.size_bytes = json.jsonGetIntValue(paramTestCase, "size_bytes", "parameters"); }
|
||||||
|
else
|
||||||
|
{ iData.size_bytes = json.jsonGetIntValue(structObj_map, "size_bytes", struct_name); }
|
||||||
|
|
||||||
if (iData.size_bytes >= UART_DATA_MAX_BYTES)
|
if (iData.size_bytes >= UART_DATA_MAX_BYTES)
|
||||||
{
|
{
|
||||||
@@ -278,8 +327,14 @@ bool UARTFixture::prepareBinaryCommand(const QJsonObject& cfg, QByteArray& data)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (param["cmd_from_binary_file"].toBool())
|
bool binaryFile = json.jsonGetBoolValue(paramTestCase, "cmd_from_binary_file", "parameters");
|
||||||
{ return loadBinaryFile(cfg["binary"].toString(), data); }
|
if (binaryFile)
|
||||||
|
{
|
||||||
|
QString binaryPath;
|
||||||
|
json.jsonGetStrValue(cfg, "binary", binaryPath, "");
|
||||||
|
bool ok = loadBinaryFile(binaryPath, data);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
formCmdDataInBuffer();
|
formCmdDataInBuffer();
|
||||||
|
|
||||||
@@ -302,8 +357,6 @@ bool UARTFixture::validateStructField(const QByteArray& rxData,
|
|||||||
QString fieldName, fieldType, op;
|
QString fieldName, fieldType, op;
|
||||||
bool isArray = false;
|
bool isArray = false;
|
||||||
QJsonArray fields;
|
QJsonArray fields;
|
||||||
JsonProcessor json;
|
|
||||||
json.setJsonFile(caseFile);
|
|
||||||
|
|
||||||
json.jsonGetStrValue(fieldCfg, "field", fieldName, jsonObjName);
|
json.jsonGetStrValue(fieldCfg, "field", fieldName, jsonObjName);
|
||||||
json.jsonGetStrValue(fieldCfg, "type", fieldType, jsonObjName);
|
json.jsonGetStrValue(fieldCfg, "type", fieldType, jsonObjName);
|
||||||
@@ -458,7 +511,7 @@ bool UARTFixture::validateBinaryResponse(const QByteArray& rx, const QJsonObject
|
|||||||
QString json_checks_field = "struct_check";
|
QString json_checks_field = "struct_check";
|
||||||
QJsonArray checks = cfg[json_checks_field].toArray();
|
QJsonArray checks = cfg[json_checks_field].toArray();
|
||||||
QString err, errMsgMismatch;
|
QString err, errMsgMismatch;
|
||||||
bool passed;
|
bool passed = false;
|
||||||
|
|
||||||
if (checks.isEmpty())
|
if (checks.isEmpty())
|
||||||
{
|
{
|
||||||
@@ -484,8 +537,6 @@ bool UARTFixture::runBinaryCase(const QJsonObject& cfg, const QJsonObject& meta,
|
|||||||
QByteArray tx;
|
QByteArray tx;
|
||||||
QString struct_name, struct_type, structJsonFileName;
|
QString struct_name, struct_type, structJsonFileName;
|
||||||
QJsonObject param, structJson;
|
QJsonObject param, structJson;
|
||||||
JsonProcessor json;
|
|
||||||
json.setJsonFile(caseFile);
|
|
||||||
|
|
||||||
// find struct_name from test_case
|
// find struct_name from test_case
|
||||||
QString parameters = "parameters";
|
QString parameters = "parameters";
|
||||||
@@ -510,17 +561,9 @@ bool UARTFixture::runBinaryCase(const QJsonObject& cfg, const QJsonObject& meta,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// open json-file with specified struct info and get json object
|
// open json-file with specified struct info and get json object
|
||||||
QFile fileJson(structJsonFileName);
|
json.openJsonFile(structJsonFileName, structJson);
|
||||||
if (!fileJson.open(QIODevice::ReadOnly))
|
|
||||||
{
|
|
||||||
writeToLog(QString("%1 %2, path: %3")
|
|
||||||
.arg("json file not found fo struct", struct_name, structJsonFileName), false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
structJson = QJsonDocument::fromJson(fileJson.readAll()).object();
|
if (!prepareBinaryCommand(cfg, tx, caseFile)) { return false; }
|
||||||
|
|
||||||
if (!prepareBinaryCommand(cfg, tx)) { return false; }
|
|
||||||
if (!sendCommand(tx)) { return false; }
|
if (!sendCommand(tx)) { return false; }
|
||||||
|
|
||||||
QByteArray rx = receiveResponse(cfg);
|
QByteArray rx = receiveResponse(cfg);
|
||||||
@@ -530,15 +573,14 @@ bool UARTFixture::runBinaryCase(const QJsonObject& cfg, const QJsonObject& meta,
|
|||||||
void UARTFixture::runCase(const QString& caseFile)
|
void UARTFixture::runCase(const QString& caseFile)
|
||||||
{
|
{
|
||||||
QJsonObject cfg, meta;
|
QJsonObject cfg, meta;
|
||||||
bool passed = false;
|
|
||||||
QString rx_data_type;
|
|
||||||
JsonProcessor json;
|
|
||||||
json.setJsonFile(caseFile);
|
json.setJsonFile(caseFile);
|
||||||
|
|
||||||
if (!loadTestCase(caseFile, cfg, meta)) { return; }
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (!loadTestCase(caseFile, cfg, meta)) { return; }
|
||||||
|
|
||||||
|
bool passed = false;
|
||||||
|
QString rx_data_type;
|
||||||
json.jsonGetStrValue(meta, "input_data_type", rx_data_type, "meta");
|
json.jsonGetStrValue(meta, "input_data_type", rx_data_type, "meta");
|
||||||
|
|
||||||
if (rx_data_type == "text")
|
if (rx_data_type == "text")
|
||||||
@@ -558,8 +600,22 @@ void UARTFixture::runCase(const QString& caseFile)
|
|||||||
|
|
||||||
if (g_options.delayMs > 0)
|
if (g_options.delayMs > 0)
|
||||||
{ QThread::msleep(g_options.delayMs); }
|
{ QThread::msleep(g_options.delayMs); }
|
||||||
|
}
|
||||||
|
catch (ErrOpenFile &errOpen)
|
||||||
|
{
|
||||||
|
QString msg = QString("%1, path: %2").arg(errOpen.getMessage(), errOpen.getFilePath());
|
||||||
|
writeToLog(msg, false);
|
||||||
}
|
}
|
||||||
catch (ErrInJsonSet &jsonSet)
|
catch (ErrInJsonSet &jsonSet)
|
||||||
|
{
|
||||||
|
if (jsonSet.checkErrFromJson())
|
||||||
|
{
|
||||||
|
QString msg = QString("%1. %2 : %3. file: %4")
|
||||||
|
.arg(jsonSet.getIntro(), jsonSet.getErrMsg(),
|
||||||
|
jsonSet.getErrFromJson(), jsonSet.getFname());
|
||||||
|
writeToLog(msg, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
QString msg = QString("%1. %2: \nJSON parameter: %3\nJSON object: %4.\nfile: %5")
|
QString msg = QString("%1. %2: \nJSON parameter: %3\nJSON object: %4.\nfile: %5")
|
||||||
.arg(jsonSet.getIntro(), jsonSet.getErrMsg(), jsonSet.getParam(),
|
.arg(jsonSet.getIntro(), jsonSet.getErrMsg(), jsonSet.getParam(),
|
||||||
@@ -567,6 +623,7 @@ void UARTFixture::runCase(const QString& caseFile)
|
|||||||
writeToLog(msg, false);
|
writeToLog(msg, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void UARTFixture::serializeCmdDataBuf(void *dataStruct, int countBytes)
|
void UARTFixture::serializeCmdDataBuf(void *dataStruct, int countBytes)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ protected:
|
|||||||
static UART_cmdReadMemory_t iData;
|
static UART_cmdReadMemory_t iData;
|
||||||
static char cmdDataBuf[UART_DATA_MAX_BYTES];
|
static char cmdDataBuf[UART_DATA_MAX_BYTES];
|
||||||
static QVector<QString> struct_names;
|
static QVector<QString> struct_names;
|
||||||
|
static JsonProcessor json;
|
||||||
|
|
||||||
static void serializeCmdDataBuf(void *dataStruct, int countBytes);
|
static void serializeCmdDataBuf(void *dataStruct, int countBytes);
|
||||||
static void formCmdDataInBuffer();
|
static void formCmdDataInBuffer();
|
||||||
@@ -101,7 +102,7 @@ protected:
|
|||||||
bool validateTextResponse(const QByteArray& rx,
|
bool validateTextResponse(const QByteArray& rx,
|
||||||
const QJsonObject& cfg, QString caseFile);
|
const QJsonObject& cfg, QString caseFile);
|
||||||
bool runTextCase(const QJsonObject& cfg, QString caseFile, QString jsonObjName);
|
bool runTextCase(const QJsonObject& cfg, QString caseFile, QString jsonObjName);
|
||||||
bool prepareBinaryCommand(const QJsonObject& cfg, QByteArray& data);
|
bool prepareBinaryCommand(const QJsonObject& cfg, QByteArray& data, QString &caseFile);
|
||||||
|
|
||||||
bool validateStructField(const QByteArray& rxData,
|
bool validateStructField(const QByteArray& rxData,
|
||||||
const QJsonObject& fieldCfg,
|
const QJsonObject& fieldCfg,
|
||||||
|
|||||||
Reference in New Issue
Block a user