"""DSView trigger validation and API programming, independent of Qt/cffi.""" import math def pattern(value): return ''.join(str(value).upper().split()) def validate_trigger(trigger, channels, acquisition): trigger = trigger or {'kind': 'none'} kind = trigger.get('kind', 'none') if kind not in ('none', 'simple', 'stages', 'serial'): raise ValueError('Неизвестный тип триггера.') if kind == 'none': return if acquisition == 'internal': raise ValueError('Внутренний тест работает без триггера.') if kind in ('stages', 'serial') and acquisition != 'buffer': raise ValueError('Расширенный и последовательный триггеры требуют буферного режима.') position = trigger.get('position', 50) timeout = trigger.get('timeout', 30) if type(position) is not int or not 0 <= position <= 90: raise ValueError('Позиция триггера: 0…90 %.') if not math.isfinite(timeout) or not 0 <= timeout <= 3600: raise ValueError('Ожидание триггера: 0…3600 с; 0 — без тайм-аута.') def check(value, data=False): value = pattern(value) if len(value) != 16 or any(c not in ('01X' if data else '01XRFC') for c in value): raise ValueError('Условие должно содержать 16 символов: ' + ('0, 1, X.' if data else '0, 1, X, R, F, C.')) if not data and any(c != 'X' and 15-i not in channels for i, c in enumerate(value)): raise ValueError('В триггере указан выключенный канал.') return value if kind == 'simple': value = check(trigger.get('pattern', 'X'*16)) if set(value) == {'X'}: raise ValueError('Выберите хотя бы одно условие триггера.') elif kind == 'stages': stages = trigger.get('stages', []) if not 1 <= len(stages) <= 16: raise ValueError('Число ступеней: 1…16.') for stage in stages: a, b = check(stage['a']), check(stage['b']) if a == b == 'X'*16: raise ValueError('Задайте условие на каждой ступени.') if stage.get('logic', 'and') not in ('and', 'or'): raise ValueError('Логика ступени: И либо ИЛИ.') if type(stage.get('count', 1)) is not int or not 1 <= stage.get('count', 1) <= 2147483647: raise ValueError('Счётчик ступени: 1…2147483647.') else: check(trigger['start']); check(trigger['stop']) clock = check(trigger['clock']) check(trigger.get('compare', 'X'*16)) if not any(c in 'RFC' for c in clock): raise ValueError('В условии такта нужен фронт R, F или C.') if type(trigger['data_channel']) is not int or not 0 <= trigger['data_channel'] <= 15: raise ValueError('Канал последовательных данных: D0…D15.') if trigger['data_channel'] not in channels: raise ValueError('Канал последовательных данных выключен.') if type(trigger['bits']) is not int or not 1 <= trigger['bits'] <= 16: raise ValueError('Число последовательных битов: 1…16.') check(trigger['value'], data=True) def program_trigger(lib, trigger, acquisition, check): """Follow DSView TriggerDock::commit_trigger, including stage count - 1.""" trigger = trigger or {'kind': 'none'} kind = trigger.get('kind', 'none') def call(name, *args): check(getattr(lib, name)(*args), name) call('ds_trigger_reset') call('ds_trigger_set_en', int(kind != 'none')) if kind == 'none': return call('ds_trigger_set_pos', 1 if acquisition == 'stream' else trigger.get('position', 50)) call('ds_trigger_set_mode', {'simple': 0, 'stages': 1, 'serial': 2}[kind]) if kind == 'simple': for ch, value in enumerate(reversed(pattern(trigger['pattern']))): call('ds_trigger_probe_set', ch, ord(value), ord('X')) return def values(index, a, b): call('ds_trigger_stage_set_value', index, 16, ' '.join(pattern(a)).encode('ascii'), ' '.join(pattern(b)).encode('ascii')) if kind == 'stages': stages = trigger['stages'] call('ds_trigger_set_stage', len(stages)-1) for index, stage in enumerate(stages): values(index, stage['a'], stage['b']) logic = int(stage.get('logic', 'and') == 'and') | (int(stage.get('contiguous', False)) << 1) call('ds_trigger_stage_set_logic', index, 16, logic) call('ds_trigger_stage_set_inv', index, 16, int(stage.get('inv_a', False)), int(stage.get('inv_b', False))) call('ds_trigger_stage_set_count', index, 16, stage.get('count', 1), 0) else: call('ds_trigger_set_stage', 3) values(0, trigger['start'], trigger['stop']) values(1, trigger['clock'], trigger.get('compare', 'X'*16)) select = list('X'*16) select[15-trigger['data_channel']] = '0' values(2, ''.join(select), 'X'*16) values(3, trigger['value'], 'X'*16) for index in range(4): call('ds_trigger_stage_set_logic', index, 16, 1) call('ds_trigger_stage_set_inv', index, 16, 0, 0) call('ds_trigger_stage_set_count', 1, 16, 1, 0) call('ds_trigger_stage_set_count', 3, 16, trigger['bits']-1, 0)