├── __init__.py ├── stdf ├── __init__.py ├── stdf_writer.py ├── stdf_reader.py └── stdf_v4.json ├── tests ├── __init__.py ├── .cache │ └── v │ │ └── cache │ │ └── lastfailed ├── stdf_test.json ├── test_reads.py └── test_writes.py ├── MANIFEST.in ├── .idea └── vcs.xml ├── README.md ├── LICENSE.txt ├── sample.py └── setup.py /__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /stdf/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include *.md *.txt -------------------------------------------------------------------------------- /tests/.cache/v/cache/lastfailed: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # STDF Reader 2 | This library is meant to read the binary STDF file (*.std), which is 3 | the standard test data format commonly used by Automated Test Equipment 4 | such as Teradyne, Advantest and LTX testers. 5 | 6 | ### Installation 7 | pip install stdf 8 | 9 | ### Usage 10 | from stdf.stdf_reader import Reader() 11 | stdf = Reader() 12 | stdf.load_stdf_file(stdf_file='input_file.std') 13 | 14 | for rec_name, header, body in stdf: 15 | # iterate stdf file record by record, starting from 'FAR' record. 16 | 17 | if rec_name == 'FAR': 18 | # body is a dictionary with field name as keys. 19 | cpu_type = body['CPU_TYPE'] 20 | 21 | ### Documentation 22 | Visit https://pythonhosted.org/stdf/ 23 | 24 | ### Limitation 25 | - STDF V4 format only. 26 | - Python 3.3 and above. 27 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2016 Cahyo Primawidodo 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 7 | to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of 10 | the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 13 | THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 15 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 16 | THE SOFTWARE. -------------------------------------------------------------------------------- /tests/stdf_test.json: -------------------------------------------------------------------------------- 1 | { 2 | "T1U": { 3 | "rec_typ": 11, 4 | "rec_sub": 1, 5 | "body": [ 6 | ["UNSIGNED_1", "U1"], 7 | ["UNSIGNED_2", "U2"], 8 | ["UNSIGNED_4", "U4"] 9 | ] 10 | }, 11 | 12 | "T1I": { 13 | "rec_typ": 11, 14 | "rec_sub": 2, 15 | "body": [ 16 | ["SIGNED_1", "I1"], 17 | ["SIGNED_2", "I2"], 18 | ["SIGNED_4", "I4"] 19 | ] 20 | }, 21 | 22 | "T1F": { 23 | "rec_typ": 11, 24 | "rec_sub": 3, 25 | "body": [ 26 | ["FLOAT", "R4"], 27 | ["DOUBLE", "R8"] 28 | ] 29 | }, 30 | 31 | "T1N": { 32 | "rec_typ": 11, 33 | "rec_sub": 4, 34 | "body": [ 35 | ["NIBBLE_1", "N1"], 36 | ["NIBBLE_2", "N1"] 37 | ] 38 | }, 39 | 40 | "TCn": { 41 | "rec_typ": 11, 42 | "rec_sub": 5, 43 | "body": [ 44 | ["STRING_1", "Cn"], 45 | ["STRING_2", "Cn"], 46 | ["STRING_7", "Cn"] 47 | ] 48 | }, 49 | 50 | "TBn": { 51 | "rec_typ": 11, 52 | "rec_sub": 6, 53 | "body": [ 54 | ["BYTE_1", "Bn"], 55 | ["BYTE_2", "Bn"], 56 | ["BYTE_7", "Bn"] 57 | ] 58 | }, 59 | 60 | "TA1": { 61 | "rec_typ": 11, 62 | "rec_sub": 7, 63 | "body": [ 64 | ["ARR_ICNT", "U1"], 65 | ["ARR_U1", "K0U1"], 66 | ["ARR_U2", "K0U2"], 67 | ["ARR_I1", "K0I1"], 68 | ["ARR_I2", "K0I2"], 69 | ["ARR_R4", "K0R4"], 70 | ["ARR_R8", "K0R8"] 71 | ] 72 | }, 73 | 74 | "TA2": { 75 | "rec_typ": 11, 76 | "rec_sub": 8, 77 | "body": [ 78 | ["ARR_ICNT", "U1"], 79 | ["ARR_N1", "K0N1"], 80 | ["ARR_Cn", "K0Cn"], 81 | ["ARR_Bn", "K0Bn"] 82 | ] 83 | } 84 | } -------------------------------------------------------------------------------- /sample.py: -------------------------------------------------------------------------------- 1 | """The MIT License (MIT) 2 | Copyright (c) 2016 Cahyo Primawidodo 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 7 | to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of 10 | the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 13 | THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 15 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 16 | THE SOFTWARE.""" 17 | 18 | from stdf.stdf_reader import Reader 19 | from stdf.stdf_writer import Writer 20 | import logging 21 | from pathlib import Path 22 | 23 | __author__ = 'cahyo primawidodo 2016' 24 | 25 | 26 | if __name__ == '__main__': 27 | 28 | logging.basicConfig(level=logging.INFO) 29 | 30 | p = Path('/Users/cahyo/Documents/data/oca') 31 | in_file = str(p / 'ASETKH-UFLX0058_1_WSBU-NN450-12B-04p1_1_DP5403.K2_15_20150303175521.stdf') 32 | 33 | stdf = Reader() 34 | stdf.load_stdf_file(stdf_file=in_file) 35 | 36 | with open('output.txt', mode='wt', encoding='utf-8') as fout: 37 | for rec_name, header, body in stdf: 38 | 39 | for r in rec_name: 40 | fout.write(r) 41 | 42 | if fout.tell() % 100 == 0: 43 | fout.write('\n') 44 | 45 | for k, v in body.items(): 46 | fout.write('.') 47 | 48 | if fout.tell() % 100 == 0: 49 | fout.write('\n') 50 | -------------------------------------------------------------------------------- /tests/test_reads.py: -------------------------------------------------------------------------------- 1 | """The MIT License (MIT) 2 | Copyright (c) 2016 Cahyo Primawidodo 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 7 | to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of 10 | the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 13 | THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 15 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 16 | THE SOFTWARE.""" 17 | 18 | import pytest 19 | import struct 20 | import io 21 | from stdf.stdf_reader import Reader 22 | 23 | @pytest.fixture() 24 | def rd(): 25 | return Reader('/Users/cahyo/Dropbox/programming/python/STDFReader/tests/stdf_test.json') 26 | 27 | 28 | def test_read_unsigned(rd): 29 | 30 | r = struct.pack('/my_data' 101 | # data_files=[('my_data', ['data/data_file'])], 102 | 103 | # To provide executable scripts, use entry points in preference to the 104 | # "scripts" keyword. Entry points provide cross-platform support and allow 105 | # pip to create the appropriate form of executable for the target platform. 106 | entry_points={ 107 | 'console_scripts': [ 108 | 'stdf=stdf_reader:Reader', 109 | ], 110 | }, 111 | ) -------------------------------------------------------------------------------- /tests/test_writes.py: -------------------------------------------------------------------------------- 1 | """The MIT License (MIT) 2 | Copyright (c) 2016 Cahyo Primawidodo 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 7 | to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of 10 | the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 13 | THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 15 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 16 | THE SOFTWARE.""" 17 | 18 | import pytest 19 | import struct 20 | from stdf.stdf_writer import Writer 21 | 22 | @pytest.fixture() 23 | def w(): 24 | return Writer('/Users/cahyo/Dropbox/programming/python/STDFReader/tests/stdf_test.json') 25 | 26 | 27 | def test_write_unsigned(w): 28 | data = { 29 | 'UNSIGNED_1': 0x81, 30 | 'UNSIGNED_2': 0x8001, 31 | 'UNSIGNED_4': 0x80000001 32 | } 33 | 34 | r = w.pack_record('T1U', data) 35 | u = struct.unpack(' bytearray: 148 | body_fmt = '' 149 | body_data = [] 150 | odd_nibble = True 151 | 152 | for field_name, fmt_raw in field_fmt: 153 | item = field_data[field_name] 154 | 155 | if fmt_raw.startswith('K'): 156 | mo = re.match('^K([0xn])(\w{2})', fmt_raw) 157 | n = self.__get_multiplier(field_name, body_data) 158 | fmt_act = mo.group(2) 159 | 160 | for i in range(n): 161 | 162 | fmt, dat, odd_nibble = self.__construct_body(fmt_act, item[i], body_data, odd_nibble) 163 | 164 | body_fmt += fmt 165 | body_data.extend(dat) 166 | 167 | else: 168 | fmt, dat, odd_nibble = self.__construct_body(fmt_raw, item, body_data, odd_nibble) 169 | 170 | body_fmt += fmt 171 | body_data.extend(dat) 172 | 173 | return body_fmt, body_data 174 | 175 | @staticmethod 176 | def _pack_header(length, typ, sub) -> bytearray: 177 | header_fmt = 'HBB' 178 | header_data = [length, typ, sub] 179 | return header_fmt, header_data 180 | 181 | def pack_record(self, rec_name, data): 182 | 183 | mapping = self.STDF_TYPE[rec_name]['body'] 184 | fmt_b, data_b = self._pack_body(mapping, data) 185 | 186 | rec_len = struct.calcsize('HBB' + fmt_b) - 4 187 | rec_typ = self.STDF_TYPE[rec_name]['rec_typ'] 188 | rec_sub = self.STDF_TYPE[rec_name]['rec_sub'] 189 | fmt_h, data_h = self._pack_header(rec_len, rec_typ, rec_sub) 190 | 191 | fmt = fmt_h + fmt_b 192 | *d, = data_h + data_b 193 | 194 | return struct.pack(self.e + fmt, *d) 195 | 196 | def pack_FAR(self): 197 | 198 | r = self.pack_record('FAR', {'CPU_TYPE': 2, 'STDF_VER': 4}) 199 | return r 200 | -------------------------------------------------------------------------------- /stdf/stdf_reader.py: -------------------------------------------------------------------------------- 1 | """The MIT License (MIT) 2 | Copyright (c) 2016 Cahyo Primawidodo 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 7 | to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of 10 | the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 13 | THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 15 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 16 | THE SOFTWARE.""" 17 | 18 | import json 19 | import io 20 | import struct 21 | import logging 22 | import re 23 | import math 24 | from os import path 25 | 26 | __author__ = 'cahyo primawidodo 2016' 27 | 28 | 29 | class Reader: 30 | HEADER_SIZE = 4 31 | 32 | def __init__(self, stdf_ver_json=None): 33 | self.log = logging.getLogger(self.__class__.__name__) 34 | self.STDF_TYPE = {} 35 | self.STDF_IO = io.BytesIO(b'') 36 | self.REC_NAME = {} 37 | self.FMT_MAP = {} 38 | self.e = '<' 39 | 40 | self.body_start = 0 41 | 42 | self._load_byte_fmt_mapping() 43 | self._load_stdf_type(json_file=stdf_ver_json) 44 | 45 | def _load_stdf_type(self, json_file): 46 | 47 | if json_file is None: 48 | here = path.abspath(path.dirname(__file__)) 49 | input_file = path.join(here, 'stdf_v4.json') 50 | else: 51 | input_file = json_file 52 | 53 | self.log.info('loading STDF configuration file = {}'.format(input_file)) 54 | with open(input_file) as fp: 55 | self.STDF_TYPE = json.load(fp) 56 | 57 | for k, v in self.STDF_TYPE.items(): 58 | typ_sub = (v['rec_typ'], v['rec_sub']) 59 | self.REC_NAME[typ_sub] = k 60 | 61 | def _load_byte_fmt_mapping(self): 62 | self.FMT_MAP = { 63 | "U1": "B", 64 | "U2": "H", 65 | "U4": "I", 66 | "U8": "Q", 67 | "I1": "b", 68 | "I2": "h", 69 | "I4": "i", 70 | "I8": "q", 71 | "R4": "f", 72 | "R8": "d", 73 | "B1": "B", 74 | "C1": "c", 75 | "N1": "B" 76 | } 77 | 78 | def load_stdf_file(self, stdf_file): 79 | self.log.info('opening STDF file = {}'.format(stdf_file)) 80 | with open(stdf_file, mode='rb') as fs: 81 | self.STDF_IO = io.BytesIO(fs.read()) 82 | self.log.info('detecting STDF file size = {}'.format(len(self.STDF_IO.getvalue()))) 83 | 84 | def read_record(self): 85 | header = self._read_and_unpack_header() 86 | 87 | if header: 88 | rec_size, _, _ = header 89 | self.log.debug('BODY start at tell={:0>8}'.format(self.STDF_IO.tell())) 90 | body_raw = self._read_body(rec_size) 91 | rec_name, body = self._unpack_body(header, body_raw) 92 | self.log.debug('BODY end at tell={:0>8}'.format(self.STDF_IO.tell())) 93 | 94 | if rec_name == 'FAR': 95 | self.__set_endian(body['CPU_TYPE']) 96 | 97 | return rec_name, header, body 98 | 99 | else: 100 | self.log.info('closing STDF_IO at tell={:0>8}'.format(self.STDF_IO.tell())) 101 | self.STDF_IO.close() 102 | return False 103 | 104 | def _read_and_unpack_header(self): 105 | header_raw = self.STDF_IO.read(self.HEADER_SIZE) 106 | 107 | header = False 108 | if header_raw: 109 | header = struct.unpack(self.e + 'HBB', header_raw) 110 | rec_name = self.REC_NAME.setdefault((header[1], header[2]), 'UNK') 111 | self.log.debug('len={:0>3}, rec={}'.format(header[0], rec_name)) 112 | 113 | return header 114 | 115 | def _read_body(self, rec_size): 116 | self.body_start = self.STDF_IO.tell() 117 | body_raw = io.BytesIO(self.STDF_IO.read(rec_size)) 118 | assert len(body_raw.getvalue()) == rec_size 119 | return body_raw 120 | 121 | def _unpack_body(self, header, body_raw): 122 | rec_len, rec_typ, rec_sub = header 123 | typ_sub = (rec_typ, rec_sub) 124 | rec_name = self.REC_NAME.setdefault(typ_sub, 'UNK') 125 | max_tell = rec_len 126 | odd_nibble = True 127 | 128 | body = {} 129 | if rec_name in self.STDF_TYPE: 130 | for field, fmt_raw in self.STDF_TYPE[rec_name]['body']: 131 | self.log.debug('field={}, fmt_raw={}'.format(field, fmt_raw)) 132 | 133 | if fmt_raw == 'N1' and not odd_nibble: 134 | pass 135 | elif body_raw.tell() >= max_tell: 136 | break 137 | 138 | array_data = [] 139 | if fmt_raw.startswith('K'): 140 | mo = re.match('^K([0xn])(\w{2})', fmt_raw) 141 | n = self.__get_multiplier(field, body) 142 | fmt_act = mo.group(2) 143 | 144 | for i in range(n): 145 | data, odd_nibble = self.__get_data(fmt_act, body_raw, odd_nibble) 146 | array_data.append(data) 147 | 148 | body[field] = array_data 149 | odd_nibble = True 150 | 151 | elif fmt_raw.startswith('V'): 152 | vn_map = ['B0', 'U1', 'U2', 'U4', 'I1', 'I2', 153 | 'I4', 'R4', 'R8', 'Cn', 'Bn', 'Dn', 'N1'] 154 | n, = struct.unpack('H', body_raw.read(2)) 155 | 156 | for i in range(n): 157 | idx, = struct.unpack(self.e + 'B', body_raw.read(1)) 158 | fmt_vn = vn_map[idx] 159 | 160 | data, odd_nibble = self.__get_data(fmt_vn, body_raw, odd_nibble) 161 | array_data.append(data) 162 | 163 | body[field] = array_data 164 | odd_nibble = True 165 | 166 | else: 167 | body[field], odd_nibble = self.__get_data(fmt_raw, body_raw, odd_nibble) 168 | 169 | else: 170 | self.log.warn('record name={} ({}, {}), not found in self.STDF_TYPE'.format(rec_name, rec_typ, rec_sub)) 171 | 172 | body_raw.close() 173 | return rec_name, body 174 | 175 | def __get_data(self, fmt_act, body_raw, odd_nibble): 176 | data = 0 177 | if fmt_act == 'N1': 178 | if odd_nibble: 179 | nibble, = struct.unpack(self.e + 'B', body_raw.read(1)) 180 | _, data = nibble >> 4, nibble & 0xF 181 | odd_nibble = False 182 | else: 183 | body_raw.seek(-1, 1) 184 | nibble, = struct.unpack(self.e + 'B', body_raw.read(1)) 185 | data, _ = nibble >> 4, nibble & 0xF 186 | odd_nibble = True 187 | else: 188 | fmt, buf = self.__get_format_and_buffer(fmt_act, body_raw) 189 | 190 | if fmt: 191 | d = struct.unpack(fmt, buf) 192 | data = d[0] if len(d) == 1 else d 193 | odd_nibble = True 194 | 195 | return data, odd_nibble 196 | 197 | def __get_format_and_buffer(self, fmt_raw, body_raw): 198 | fmt = self.__get_format(fmt_raw, body_raw) 199 | if fmt: 200 | size = struct.calcsize(fmt) 201 | buf = body_raw.read(size) 202 | self.log.debug('fmt={}, buf={}'.format(fmt, buf)) 203 | return fmt, buf 204 | else: 205 | return 0, 0 206 | 207 | def __get_format(self, fmt_raw, body_raw): 208 | self.log.debug('fmt_raw={}, body_raw={}'.format(fmt_raw, body_raw)) 209 | 210 | if fmt_raw in self.FMT_MAP: 211 | return self.FMT_MAP[fmt_raw] 212 | 213 | elif fmt_raw == 'Sn': 214 | buf = body_raw.read(2) 215 | n, = struct.unpack(self.e + 'H', buf) 216 | posfix = 's' 217 | 218 | elif fmt_raw == 'Cn': 219 | buf = body_raw.read(1) 220 | n, = struct.unpack(self.e + 'B', buf) 221 | posfix = 's' 222 | 223 | elif fmt_raw == 'Bn': 224 | buf = body_raw.read(1) 225 | n, = struct.unpack(self.e + 'B', buf) 226 | posfix = 'B' 227 | 228 | elif fmt_raw == 'Dn': 229 | buf = body_raw.read(2) 230 | h, = struct.unpack(self.e + 'H', buf) 231 | n = math.ceil(h/8) 232 | posfix = 'B' 233 | else: 234 | raise ValueError(fmt_raw, body_raw.tell(), body_raw.__sizeof__()) 235 | 236 | return str(n) + posfix if n else '' 237 | 238 | def __set_endian(self, cpu_type): 239 | if cpu_type == 1: 240 | self.e = '>' 241 | elif cpu_type == 2: 242 | self.e = '<' 243 | else: 244 | self.log.critical('Value of FAR: CPU_TYPE is not 1 or 2. Invalid endian.') 245 | raise IOError(cpu_type) 246 | 247 | @staticmethod 248 | def __get_multiplier(field, body): 249 | if field == 'SITE_NUM': 250 | return body['SITE_CNT'] # SDR (1, 80) 251 | 252 | elif field == 'PMR_INDX': 253 | return body['INDX_CNT'] # PGR (1, 62) 254 | 255 | elif field in ['GRP_INDX', 'GRP_MODE', 'GRP_RADX', 'PGM_CHAR', 'RTN_CHAR', 'PGM_CHAL', 'RTN_CHAL']: 256 | return body['GRP_CNT'] # PLR (1, 63) 257 | 258 | elif field in ['RTN_INDX', 'RTN_STAT']: 259 | return body['RTN_ICNT'] # FTR (15, 20) 260 | 261 | elif field in ['PGM_INDX', 'PGM_STAT']: 262 | return body['PGM_ICNT'] # FTR (15, 20) 263 | 264 | elif field in ['RTN_STAT', 'RTN_INDX']: 265 | return body['RTN_ICNT'] # MPR (15, 15) 266 | 267 | elif field in ['RTN_RSLT']: 268 | return body['RSLT_CNT'] # MPR (15, 15) 269 | 270 | elif field in ['UPD_NAM']: 271 | return body['UPD_CNT'] # VUR (0, 30) 272 | 273 | elif field in ["PAT_BGN", "PAT_END", "PAT_FILE", "PAT_FILE", "PAT_LBL", "FILE_UID", "ATPG_DSC", "SRC_ID"]: 274 | return body["LOCP_CNT"] # PSR (1, 90) 275 | 276 | elif field in ["PMR_INDX", "ATPG_NAM"]: 277 | return body["LOCM_CNT"] # NMR (1, 91) 278 | 279 | elif field in ["CHN_LIST"]: 280 | return body["CHN_CNT"] # SSR (1, 93) 281 | 282 | elif field in ["M_CLKS"]: 283 | return body["MSTR_CNT"] # CDR (1, 94) 284 | 285 | elif field in ["S_CLKS"]: 286 | return body["SLAV_CNT"] # CDR (1, 94) 287 | 288 | elif field in ["CELL_LST"]: 289 | return body["LST_CNT"] # CDR (1, 94) 290 | 291 | else: 292 | raise ValueError 293 | 294 | def __iter__(self): 295 | return self 296 | 297 | def __next__(self): 298 | r = self.read_record() 299 | if r: 300 | return r 301 | else: 302 | raise StopIteration 303 | -------------------------------------------------------------------------------- /stdf/stdf_v4.json: -------------------------------------------------------------------------------- 1 | { 2 | "FAR": { 3 | "rec_typ": 0, 4 | "rec_sub": 10, 5 | "body": [ 6 | ["CPU_TYPE", "U1"], 7 | ["STDF_VER", "U1"] 8 | ] 9 | }, 10 | 11 | "ATR": { 12 | "rec_typ": 0, 13 | "rec_sub": 20, 14 | "body": [ 15 | ["MOD_TIM", "U4"], 16 | ["CMD_LINE", "Cn"] 17 | ] 18 | }, 19 | 20 | "VUR": { 21 | "rec_typ": 0, 22 | "rec_sub": 30, 23 | "body": [ 24 | ["UPD_CNT", "U1"], 25 | ["UPD_NAM", "K0Cn"] 26 | ] 27 | }, 28 | 29 | "MIR": { 30 | "rec_typ": 1, 31 | "rec_sub": 10, 32 | "body": [ 33 | ["SETUP_T", "U4"], 34 | ["START_T", "U4"], 35 | ["STAT_NUM", "U1"], 36 | ["MODE_COD", "C1"], 37 | ["RTST_COD", "C1"], 38 | ["PROT_COD", "C1"], 39 | ["BURN_TIM", "U2"], 40 | ["CMOD_COD", "C1"], 41 | ["LOT_ID", "Cn"], 42 | ["PART_TYP", "Cn"], 43 | ["NODE_NAM", "Cn"], 44 | ["TSTR_TYP", "Cn"], 45 | ["JOB_NAM", "Cn"], 46 | ["JOB_REV", "Cn"], 47 | ["SBLOT_ID", "Cn"], 48 | ["OPER_NAM", "Cn"], 49 | ["EXEC_TYP", "Cn"], 50 | ["EXEC_VER", "Cn"], 51 | ["TEST_COD", "Cn"], 52 | ["TST_TEMP", "Cn"], 53 | ["USER_TXT", "Cn"], 54 | ["AUX_FILE", "Cn"], 55 | ["PKG_TYP", "Cn"], 56 | ["FAMLY_ID", "Cn"], 57 | ["DATE_COD", "Cn"], 58 | ["FACIL_ID", "Cn"], 59 | ["FLOOR_ID", "Cn"], 60 | ["PROC_ID", "Cn"], 61 | ["OPER_FRQ", "Cn"], 62 | ["SPEC_NAM", "Cn"], 63 | ["SPEC_VER", "Cn"], 64 | ["FLOW_ID", "Cn"], 65 | ["SETUP_ID", "Cn"], 66 | ["DSGN_REV", "Cn"], 67 | ["ENG_ID", "Cn"], 68 | ["ROM_COD", "Cn"], 69 | ["SERL_NUM", "Cn"], 70 | ["SUPR_NAM", "Cn"] 71 | ] 72 | }, 73 | 74 | "MRR": { 75 | "rec_typ": 1, 76 | "rec_sub": 20, 77 | "body": [ 78 | ["FINISH_T", "U4"], 79 | ["DISP_COD", "C1"], 80 | ["USR_DESC", "Cn"], 81 | ["EXC_DESC", "Cn"] 82 | ] 83 | }, 84 | 85 | "PCR": { 86 | "rec_typ": 1, 87 | "rec_sub": 30, 88 | "body": [ 89 | ["HEAD_NUM", "U1"], 90 | ["SITE_NUM", "U1"], 91 | ["PART_CNT", "U4"], 92 | ["RTST_CNT", "U4"], 93 | ["ABRT_CNT", "U4"], 94 | ["GOOD_CNT", "U4"], 95 | ["FUNC_CNT", "U4"] 96 | ] 97 | }, 98 | 99 | "HBR": { 100 | "rec_typ": 1, 101 | "rec_sub": 40, 102 | "body": [ 103 | ["HEAD_NUM", "U1"], 104 | ["SITE_NUM", "U1"], 105 | ["HBIN_NUM", "U2"], 106 | ["HBIN_CNT", "U4"], 107 | ["HBIN_PF", "C1"], 108 | ["HBIN_NAM", "Cn"] 109 | ] 110 | }, 111 | 112 | "SBR": { 113 | "rec_typ": 1, 114 | "rec_sub": 50, 115 | "body": [ 116 | ["HEAD_NUM", "U1"], 117 | ["SITE_NUM", "U1"], 118 | ["SBIN_NUM", "U2"], 119 | ["SBIN_CNT", "U4"], 120 | ["SBIN_PF", "C1"], 121 | ["SBIN_NAM", "Cn"] 122 | ] 123 | }, 124 | 125 | "PMR": { 126 | "rec_typ": 1, 127 | "rec_sub": 60, 128 | "body": [ 129 | ["PMR_INDX", "U2"], 130 | ["CHAN_TYP", "U2"], 131 | ["CHAN_NAM", "Cn"], 132 | ["PHY_NAM", "Cn"], 133 | ["LOG_NAM", "Cn"], 134 | ["HEAD_NUM", "U1"], 135 | ["SITE_NUM", "U1"] 136 | ] 137 | }, 138 | 139 | "PGR": { 140 | "rec_typ": 1, 141 | "rec_sub": 62, 142 | "body": [ 143 | ["GRP_INDX", "U2"], 144 | ["GRP_NAM", "Cn"], 145 | ["INDX_CNT", "U2"], 146 | ["PMR_INDX", "K0U2"] 147 | ] 148 | }, 149 | 150 | "PLR": { 151 | "rec_typ": 1, 152 | "rec_sub": 63, 153 | "body": [ 154 | ["GRP_CNT", "U2"], 155 | ["GRP_INDX", "K0U2"], 156 | ["GRP_MODE", "K0U2"], 157 | ["GRP_RADX", "K0U1"], 158 | ["PGM_CHAR", "K0Cn"], 159 | ["RTN_CHAR", "K0Cn"], 160 | ["PGM_CHAL", "K0Cn"], 161 | ["RTN_CHAL", "K0Cn"] 162 | ] 163 | }, 164 | 165 | "RDR": { 166 | "rec_typ": 1, 167 | "rec_sub": 70, 168 | "body": [ 169 | ["NUM_BINS", "U2"], 170 | ["RTST_BIN", "K0U2"] 171 | ] 172 | }, 173 | 174 | "SDR": { 175 | "rec_typ": 1, 176 | "rec_sub": 80, 177 | "body": [ 178 | ["HEAD_NUM", "U1"], 179 | ["SITE_GRP", "U1"], 180 | ["SITE_CNT", "U1"], 181 | ["SITE_NUM", "K0U1"], 182 | ["HAND_TYP", "Cn"], 183 | ["HAND_ID", "Cn"], 184 | ["CARD_TYP", "Cn"], 185 | ["CARD_ID", "Cn"], 186 | ["LOAD_TYP", "Cn"], 187 | ["LOAD_ID", "Cn"], 188 | ["DIB_TYP", "Cn"], 189 | ["DIB_ID", "Cn"], 190 | ["CABL_TYP", "Cn"], 191 | ["CABL_ID", "Cn"], 192 | ["CONT_TYP", "Cn"], 193 | ["CONT_ID", "Cn"], 194 | ["LASR_TYP", "Cn"], 195 | ["LASR_ID", "Cn"], 196 | ["EXTR_TYP", "Cn"], 197 | ["EXTR_ID", "Cn"] 198 | ] 199 | }, 200 | 201 | "PSR": { 202 | "rec_typ": 1, 203 | "rec_sub": 90, 204 | "body": [ 205 | ["CONT_FLG", "B1"], 206 | ["PSR_INDX", "U2"], 207 | ["PSR_NAM", "Cn"], 208 | ["OPT_FLG", "B1"], 209 | ["TOTP_CNT", "U2"], 210 | ["LOCP_CNT", "U2"], 211 | ["PAT_BGN", "K0U8"], 212 | ["PAT_END", "K0U8"], 213 | ["PAT_FILE", "K0Cn"], 214 | ["PAT_FILE", "K0Cn"], 215 | ["PAT_LBL", "K0Cn"], 216 | ["FILE_UID", "K0Cn"], 217 | ["ATPG_DSC", "K0Cn"], 218 | ["SRC_ID", "K0Cn"] 219 | ] 220 | }, 221 | 222 | "NMR": { 223 | "rec_typ": 1, 224 | "rec_sub": 91, 225 | "body": [ 226 | ["CONT_FLG", "B1"], 227 | ["NMR_INDX", "U2"], 228 | ["TOTM_CNT", "U2"], 229 | ["LOCM_CNT", "U2"], 230 | ["PMR_INDX", "K0U2"], 231 | ["ATPG_NAM", "K0Cn"] 232 | ] 233 | }, 234 | 235 | "CNR": { 236 | "rec_typ": 1, 237 | "rec_sub": 92, 238 | "body": [ 239 | ["CHN_NUM", "U2"], 240 | ["BIT_POS", "U4"], 241 | ["CELL_NAM", "Sn"] 242 | ] 243 | }, 244 | 245 | "SSR": { 246 | "rec_typ": 1, 247 | "rec_sub": 93, 248 | "body": [ 249 | ["SSR_NAM", "Cn"], 250 | ["CHN_CNT", "U2"], 251 | ["CHN_LIST", "K0U2"] 252 | ] 253 | }, 254 | 255 | "CDR": { 256 | "rec_typ": 1, 257 | "rec_sub": 94, 258 | "body": [ 259 | ["CONT_FLG", "B1"], 260 | ["CDR_INDX", "U2"], 261 | ["CHN_NAM", "Cn"], 262 | ["CHN_LEN", "U4"], 263 | ["SIN_PIN", "U2"], 264 | ["SOUT_PIN", "U2"], 265 | ["MSTR_CNT", "U1"], 266 | ["M_CLKS", "K0U2"], 267 | ["SLAV_CNT", "U1"], 268 | ["S_CLKS", "K0U2"], 269 | ["INV_VAL", "U1"], 270 | ["LST_CNT", "U2"], 271 | ["CELL_LST", "K0Sn"] 272 | ] 273 | }, 274 | 275 | "WIR": { 276 | "rec_typ": 2, 277 | "rec_sub": 10, 278 | "body": [ 279 | ["HEAD_NUM", "U1"], 280 | ["SITE_GRP", "U1"], 281 | ["START_T", "U4"], 282 | ["WAFER_ID", "Cn"] 283 | ] 284 | }, 285 | 286 | "WRR": { 287 | "rec_typ": 2, 288 | "rec_sub": 20, 289 | "body": [ 290 | ["HEAD_NUM", "U1"], 291 | ["SITE_GRP", "U1"], 292 | ["FINISH_T", "U4"], 293 | ["PART_CNT", "U4"], 294 | ["RTST_CNT", "U4"], 295 | ["ABRT_CNT", "U4"], 296 | ["GOOD_CNT", "U4"], 297 | ["FUNC_CNT", "U4"], 298 | ["WAFER_ID", "Cn"], 299 | ["FABWF_ID", "Cn"], 300 | ["FRAME_ID", "Cn"], 301 | ["MASK_ID", "Cn"], 302 | ["USR_DESC", "Cn"], 303 | ["EXC_DESC", "Cn"] 304 | ] 305 | }, 306 | 307 | "WCR": { 308 | "rec_typ": 2, 309 | "rec_sub": 30, 310 | "body": [ 311 | ["WAFR_SIZ", "R4"], 312 | ["DIE_HT", "R4"], 313 | ["DIE_WID", "R4"], 314 | ["WF_UNITS", "U1"], 315 | ["WF_FLAT", "C1"], 316 | ["CENTER_X", "I2"], 317 | ["CENTER_Y", "I2"], 318 | ["POS_X", "C1"], 319 | ["POS_Y", "C1"] 320 | ] 321 | }, 322 | 323 | "PIR": { 324 | "rec_typ": 5, 325 | "rec_sub": 10, 326 | "body": [ 327 | ["HEAD_NUM", "U1"], 328 | ["SITE_NUM", "U1"] 329 | ] 330 | }, 331 | 332 | "PRR": { 333 | "rec_typ": 5, 334 | "rec_sub": 20, 335 | "body": [ 336 | ["HEAD_NUM", "U1"], 337 | ["SITE_NUM", "U1"], 338 | ["PART_FLG", "B1"], 339 | ["NUM_TEST", "U2"], 340 | ["HARD_BIN", "U2"], 341 | ["SOFT_BIN", "U2"], 342 | ["X_COORD", "I2"], 343 | ["Y_COORD", "I2"], 344 | ["TEST_T", "U4"], 345 | ["PART_ID", "Cn"], 346 | ["PART_TXT", "Cn"], 347 | ["PART_FIX", "Bn"] 348 | ] 349 | }, 350 | 351 | "TSR": { 352 | "rec_typ": 10, 353 | "rec_sub": 30, 354 | "body": [ 355 | ["HEAD_NUM", "U1"], 356 | ["SITE_NUM", "U1"], 357 | ["TEST_TYP", "C1"], 358 | ["TEST_NUM", "U4"], 359 | ["EXEC_CNT", "U4"], 360 | ["FAIL_CNT", "U4"], 361 | ["ALRM_CNT", "U4"], 362 | ["TEST_NAM", "Cn"], 363 | ["SEQ_NAME", "Cn"], 364 | ["TEST_LBL", "Cn"], 365 | ["OPT_FLAG", "B1"], 366 | ["TEST_TIM", "R4"], 367 | ["TEST_MIN", "R4"], 368 | ["TEST_MAX", "R4"], 369 | ["TST_SUMS", "R4"], 370 | ["TST_SQRS", "R4"] 371 | ] 372 | }, 373 | 374 | "PTR": { 375 | "rec_typ": 15, 376 | "rec_sub": 10, 377 | "body": [ 378 | ["TEST_NUM","U4"], 379 | ["HEAD_NUM","U1"], 380 | ["SITE_NUM","U1"], 381 | ["TEST_FLG","B1"], 382 | ["PARM_FLG","B1"], 383 | ["RESULT","R4"], 384 | ["TEST_TXT","Cn"], 385 | ["ALARM_ID","Cn"], 386 | ["OPT_FLAG","B1"], 387 | ["RES_SCAL","I1"], 388 | ["LLM_SCAL","I1"], 389 | ["HLM_SCAL","I1"], 390 | ["LO_LIMIT","R4"], 391 | ["HI_LIMIT","R4"], 392 | ["UNITS","Cn"], 393 | ["C_RESFMT","Cn"], 394 | ["C_LLMFMT","Cn"], 395 | ["C_HLMFMT","Cn"], 396 | ["LO_SPEC","R4"], 397 | ["HI_SPEC","R4"] 398 | ] 399 | }, 400 | 401 | "MPR": { 402 | "rec_typ": 15, 403 | "rec_sub": 15, 404 | "body": [ 405 | ["TEST_NUM","U4"], 406 | ["HEAD_NUM","U1"], 407 | ["SITE_NUM","U1"], 408 | ["TEST_FLG","B1"], 409 | ["PARM_FLG","B1"], 410 | ["RTN_ICNT","U2"], 411 | ["RSLT_CNT","U2"], 412 | ["RTN_STAT","K0N1"], 413 | ["RTN_RSLT","K0R4"], 414 | ["TEST_TXT","Cn"], 415 | ["ALARM_ID","Cn"], 416 | ["OPT_FLAG","B1"], 417 | ["RES_SCAL","I1"], 418 | ["LLM_SCAL","I1"], 419 | ["HLM_SCAL","I1"], 420 | ["LO_LIMIT","R4"], 421 | ["HI_LIMIT","R4"], 422 | ["START_IN","R4"], 423 | ["INCR_IN","R4"], 424 | ["RTN_INDX","K0U2"], 425 | ["UNITS","Cn"], 426 | ["UNITS_IN","Cn"], 427 | ["C_RESFMT","Cn"], 428 | ["C_LLMFMT","Cn"], 429 | ["C_HLMFMT","Cn"], 430 | ["LO_SPEC","R4"], 431 | ["HI_SPEC","R4"] 432 | ] 433 | }, 434 | 435 | "FTR": { 436 | "rec_typ": 15, 437 | "rec_sub": 20, 438 | "body": [ 439 | ["TEST_NUM","U4"], 440 | ["HEAD_NUM","U1"], 441 | ["SITE_NUM","U1"], 442 | ["TEST_FLG","B1"], 443 | ["OPT_FLAG","B1"], 444 | ["CYCL_CNT","U4"], 445 | ["REL_VADR","U4"], 446 | ["REPT_CNT","U4"], 447 | ["NUM_FAIL","U4"], 448 | ["XFAIL_AD","I4"], 449 | ["YFAIL_AD","I4"], 450 | ["VECT_OFF","I2"], 451 | ["RTN_ICNT","U2"], 452 | ["PGM_ICNT","U2"], 453 | ["RTN_INDX","K0U2"], 454 | ["RTN_STAT","K0N1"], 455 | ["PGM_INDX","K0U2"], 456 | ["PGM_STAT","K0N1"], 457 | ["FAIL_PIN","Dn"], 458 | ["VECT_NAM","Cn"], 459 | ["TIME_SET","Cn"], 460 | ["OP_CODE","Cn"], 461 | ["TEST_TXT","Cn"], 462 | ["ALARM_ID","Cn"], 463 | ["PROG_TXT","Cn"], 464 | ["RSLT_TXT","Cn"], 465 | ["PATG_NUM","U1"], 466 | ["SPIN_MAP","Dn"] 467 | ] 468 | }, 469 | 470 | "STR": { 471 | "rec_typ": 15, 472 | "rec_sub": 30, 473 | "body": [ 474 | ["HEAD_NUM","U1"], 475 | ["SITE_NUM","U1"], 476 | ["TEST_TYP","C1"], 477 | ["TEST_NUM","U4"], 478 | ["EXEC_CNT","U4"], 479 | ["FAIL_CNT","U4"], 480 | ["ALRM_CNT","U4"], 481 | ["TEST_NAM","Cn"], 482 | ["SEQ_NAME","Cn"], 483 | ["TEST_LBL","Cn"], 484 | ["OPT_FLAG","B1"], 485 | ["TEST_TIM","R4"], 486 | ["TEST_MIN","R4"], 487 | ["TEST_MAX","R4"], 488 | ["TST_SUMS","R4"], 489 | ["TST_SQRS","R4"] 490 | ] 491 | }, 492 | 493 | "BPS": { 494 | "rec_typ": 20, 495 | "rec_sub": 10, 496 | "body": [ 497 | ["SEQ_NAME","Cn"] 498 | ] 499 | }, 500 | 501 | "EPS": { 502 | "rec_typ": 20, 503 | "rec_sub": 20, 504 | "body": [ 505 | 506 | ] 507 | }, 508 | 509 | "GDR": { 510 | "rec_typ": 50, 511 | "rec_sub": 10, 512 | "body": [ 513 | ["GEN_DATA", "Vn"] 514 | ] 515 | }, 516 | 517 | "DTR": { 518 | "rec_typ": 50, 519 | "rec_sub": 30, 520 | "body": [ 521 | ["TEXT_DAT", "Cn"] 522 | ] 523 | } 524 | 525 | } --------------------------------------------------------------------------------