Rigol DS4000 pass/fail info and question - Page 1
Forum section: electronics / testgear

author: rgaddi
author_rank: Newbie
timestamp: November 29, 2018, 01:19:38 am
content: First, since I'm new here, I should probably lead by being useful, so the next post below will be my Python code for working with Rigol DS4000 pass/fail masks, having reverse-engineered the file format as well as that ever goes (i.e. there's nothing I know to be wrong).That accomplished, anyone know much about using those masks in automated test environments? What I'd like to do is stop on mask fail, have the test software detect that the mask has failed, grab and log the screen image off the scope, and start the mask running again. What I'm finding in practice is that I can't get it running again after a fail. Anyone know which command I should be using for that? I feel like I've triedMASK:OPER RUNand:RUNand combinations of the both of them in various orders, with and without some pauses, and I'm just getting there.

author: rgaddi
author_rank: Newbie
timestamp: November 29, 2018, 01:23:50 am
content: Pass/fail mask reverse-engineering, presented in Python. Boy it would have been easier if my Rigol rep had just been willing to tell me.Code: (python)class PassFailData(bytearray):"""Represents Rigol pass/fail data.Treated as a bytearray, the layout of the mask data is:* An 8 byte constant header* Little-endian uint16 WINDOW_ON, where 0 is no window (full-screen) and1 is a window* Little-endian uint16 WINDOW_LEFT (0-699), ignored if not WINDOW_ON* Little-endian uint16 WINDOW_RIGHT (0-699), ignored if not WINDOW_ON* 700 pairs of (LOWER, UPPER), where each is a byte from 0 (bottom of thescreen) to 255 (top of the screen), working from the left of the screenon to the right. Pairs that index left of WINDOW_LEFT or right ofWINDOW_RIGHT should be (0, 255) so as to enforce no mask.Parameters:arg (str, bytes): If arg is string, it's interpreted as the name ofa .pf file to open. If it's bytes (or a bytearray) then it's theraw data that such a file would contain. The default, None,creates an empty mask... note::This is EXTREMELY experimental. All information about the fileformat has been derived through reverse-engineering and empericalguessing. Test thoroughly before any kind of production use."""DATALEN = 1400FILELEN = DATALEN + 14# First 8 bytes of the file are constant.HEADER = b'\x03\x00\x00\x00x\x05\x0e\x00'def __init__(self, arg=None):# Set up the alternate views onto this array. There is an 8 byte# constant header, then 3 little endian uint16s representing# window on? 0:false, 1: true# window left: 0-699# window right: 0-699self[:] = bytes(self.FILELEN)self._params = np.frombuffer(self, dtype="<u2", count=3, offset=8)self._maskdata = np.frombuffer(self, dtype=np.uint8, offset=14)if arg is None:self[:len(self.HEADER)] = self.HEADERself.upper[:] = 0xFFelif isinstance(arg, str):self.read(arg)elif isinstance(arg, (bytearray, bytes)):self.setdata(arg)else:raise TypeError('invalid arg ' + type(arg).__name__)def setdata(self, data):if len(data) != self.FILELEN:raise ValueError("Incorrect mask data length")if not data.startswith(self.HEADER):log.warning("Bad mask header")self[:] = datadef __repr__(self):wnd = self.windowif wnd:return '{}({}-{})'.format(type(self).__name__, wnd, wnd)else:return '{}(all)'.format(type(self).__name__)def read(self, filename):"""Read a .pf file."""with open(filename, 'rb') as f:self.setdata(f.read(self.FILELEN + 1))@propertydef window(self):"""Pass/fail window extents.Either None or a 2-tuple of (left, right), where both left and rightare in the range 0-699."""if self._params:return tuple(self._params[1:])else:return None@window.setterdef window(self, value):if value is None:self._params = 0elif len(value) != 2:raise ValueError('window must be None or 2-tuple')elif all(0 <= v < 700 for v in value):self._params = 1self._params[1:] = valueelse:raise ValueError('window must have 0 <= left, right < 700')@propertydef lower(self):"""Upper mask limit.700 data points in the range 0-255."""return self._maskdata[0::2]@propertydef upper(self):"""Upper mask limit.700 data points in the range 0-255."""return self._maskdata[1::2]