Files
templates/python/logic_analyzer/dslogic_trigger.py

107 lines
5.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""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)