Example #1
0
    def __init__(self, name=None):
        GraphWidget.__init__(self)
        if name is not None:
            self._name = name
        ActiveTraceObserver.__init__(self)

        self.params.addChildren([
            {'name':'Redraw after Each', 'type':'bool', 'value':False},
            {'name':'Trace Range', 'key':'tracerng', 'type':'range', 'limits':(0, 0), 'value':(0, 0)},
            {'name':'Point Range', 'key':'pointrng', 'type':'rangegraph', 'limits':(0, 0), 'value':(0, 0), 'graphwidget':self},
            {'name':'Downsampling Mode', 'key':'dsmode', 'type':'list', 'values':{'None':None, 'Subsample':'subsample', 'Mean':'mean', 'Peak':'peak'},
                'value':'peak', 'action':self.plotInputTrace},
            {'name':'Y Axis', 'type':'group', 'expanded':False, 'children':[
                {'name':'Unity', 'type':'list', 'values':{"None":"", "Voltage":"V", "Current":"A"}, 'value':"", 'action':self.plotInputTrace},
                {'name':'Scale Factor', 'type':'float', 'limits':(1E-9, 1E9), 'value':1.0, 'action':self.plotInputTrace},
                {'name':'Offset Factor', 'type':'float', 'limits':(-1E9, 1E9), 'value':0.0, 'action':self.plotInputTrace},
            ]},
            {'name':'X Axis', 'type':'list', 'values':{"Sample":"Pts.", "Time":"s"}, 'value':"Pts.", 'action':self.plotInputTrace},
            {'name':'Redraw', 'type':'action', 'action':self.plotInputTrace},
        ])

        self.findParam('input').setValue(TraceSource.registeredObjects["Trace Management"])
        TraceSource.sigRegisteredObjectsChanged.connect(self.traceSourcesChanged)

        self.resetTraceLimits()
        self.setDefaultYRange(-0.5, 0.5)
        self.YDefault()
Example #2
0
    def __init__(self, name=None):
        GraphWidget.__init__(self)

        self.getParams().addChildren([
            {'name':'Draw Type', 'type':'list', 'key':'drawtype', 'values':['Fastest', 'Normal', 'Detailed'],
             'value':'Normal',
             'help': '%namehdr%'+
                     "Draw types:\n"
                     " * Fast: Group traces into a min/max area;\n"
                     " * Normal: Plot all traces continuously;\n"
                     " * Detailed: Plot all traces individually.\n\n"
                     "Only highlighted traces can be selected in fast/normal modes.\n"
             },
        ])

        self.setObjectName(self.getName())
        self.bselection = QToolBar()
        self.layout().addWidget(self.bselection)
        self.doRedraw = True
        self.enabledbytes = []
        AttackObserver.__init__(self)
        self.initUI(True)

        # Setup the redrawPlot() to be delayed when pressing the Key buttons
        self.delayedRedrawPlot = Timer()
        self.delayedRedrawPlot.timeout.connect(self.redrawPlot)
        self.delayedRedrawPlot.setSingleShot(True)
        self.delayedRedrawPlot.setInterval(1000)
Example #3
0
    def __init__(self, name=None):
        GraphWidget.__init__(self)
        if name is not None:
            self._name = name
        ActiveTraceObserver.__init__(self)

        self.params.addChildren([
            {'name':'Redraw after Each', 'type':'bool', 'value':False},
            {'name':'Trace Range', 'key':'tracerng', 'type':'range', 'limits':(0, 0), 'value':(0, 0)},
            {'name':'Point Range', 'key':'pointrng', 'type':'rangegraph', 'limits':(0, 0), 'value':(0, 0), 'graphwidget':self},
            {'name':'Y Axis', 'type':'group', 'expanded':False, 'children':[
                {'name':'Unity', 'type':'list', 'values':{"None":"", "Voltage":"V", "Current":"A"}, 'value':"", 'action':self.plotInputTrace},
                {'name':'Scale Factor', 'type':'float', 'limits':(1E-9, 1E9), 'value':1.0, 'action':self.plotInputTrace},
                {'name':'Offset Factor', 'type':'float', 'limits':(-1E9, 1E9), 'value':0.0, 'action':self.plotInputTrace},
            ]},
            {'name':'X Axis', 'type':'list', 'values':{"Sample":"Pts.", "Time":"s"}, 'value':"Pts.", 'action':self.plotInputTrace},
            {'name':'Redraw', 'type':'action', 'action':self.plotInputTrace},
        ])

        self.findParam('input').setValue(TraceSource.registeredObjects["Trace Management"])
        TraceSource.sigRegisteredObjectsChanged.connect(self.traceSourcesChanged)

        self.resetTraceLimits()
        self.setDefaultYRange(-0.5, 0.5)
        self.YDefault()
Example #4
0
    def __init__(self, name=None):
        GraphWidget.__init__(self)
        if name is not None:
            self._name = name

        self.getParams().addChildren([
            {'name':'Symbol', 'type':'list', 'values':['o', 's', 't', 'd', '+'], 'value':'o'},
        ])
        self.setDefaultYRange(-0.5, 0.5)
Example #5
0
    def __init__(self, name=None):
        GraphWidget.__init__(self)
        if name is not None:
            self._name = name

        self.getParams().addChildren([
            {
                'name': 'Symbol',
                'type': 'list',
                'values': ['o', 's', 't', 'd', '+'],
                'value': 'o'
            },
        ])
        self.setDefaultYRange(-0.5, 0.5)
    def __init__(self, parentParam=None, name=None):
        GraphWidget.__init__(self)
        if name is not None:
            self._name = name
        ActiveTraceObserver.__init__(self)

        self.params.addChildren([
            {'name':'Redraw after Each', 'type':'bool', 'value':False},
            {'name':'Trace Range', 'key':'tracerng', 'type':'range', 'limits':(0, 0), 'value':(0, 0)},
            {'name':'Point Range', 'key':'pointrng', 'type':'rangegraph', 'limits':(0, 0), 'value':(0, 0), 'graphwidget':self},
            {'name':'Redraw', 'type':'action', 'action':lambda _: self.plotInputTrace()},
        ])

        self.findParam('input').setValue(TraceSource.registeredObjects["Trace Management"])
        TraceSource.sigRegisteredObjectsChanged.connect(self.traceSourcesChanged)

        self.resetTraceLimits()
        self.setDefaultYRange(-0.5, 0.5)
        self.YDefault()
    def __init__(self, parent):
        AutoScript.__init__(self)
        self._autoscript_init = False
        self.parent = parent
        self.poi = POI(self)
        self.poiDock = CWMainGUI.getInstance().addDock(
            self.poi,
            "Partition Comparison POI Table",
            area=Qt.TopDockWidgetArea)
        self.poiDock.hide()
        self.defineName()
        self._traces = None

        self.api = CWCoreAPI.getInstance()
        self.graph = GraphWidget()
        self.bselection = QToolBar()
        self.graph.addWidget(self.bselection)
        self.graphDock = CWMainGUI.getInstance().addDock(
            self.graph,
            "Partition Comparison Graph",
            area=Qt.TopDockWidgetArea)
        self.graphDock.hide()
Example #8
0
    def __init__(self, name=None):
        GraphWidget.__init__(self)

        self.getParams().addChildren([
            {
                'name':
                'Draw Type',
                'type':
                'list',
                'key':
                'drawtype',
                'values': ['Fastest', 'Normal', 'Detailed'],
                'value':
                'Normal',
                'help':
                '%namehdr%' + "Draw types:\n"
                " * Fast: Group traces into a min/max area;\n"
                " * Normal: Plot all traces continuously;\n"
                " * Detailed: Plot all traces individually.\n\n"
                "Only highlighted traces can be selected in fast/normal modes.\n"
            },
        ])

        self.setObjectName(self.getName())
        self.bselection = QToolBar()
        self.layout().addWidget(self.bselection)
        self.doRedraw = True
        self.enabledbytes = []
        AttackObserver.__init__(self)
        self.initUI(True)

        # Setup the redrawPlot() to be delayed when pressing the Key buttons
        self.delayedRedrawPlot = Timer()
        self.delayedRedrawPlot.timeout.connect(self.redrawPlot)
        self.delayedRedrawPlot.setSingleShot(True)
        self.delayedRedrawPlot.setInterval(1000)
    def __init__(self, parent):
        AutoScript.__init__(self)
        self._autoscript_init = False
        self.parent = parent
        self.poi = POI(self)
        self.poiDock = CWMainGUI.getInstance().addDock(self.poi, "Partition Comparison POI Table", area=Qt.TopDockWidgetArea)
        self.poiDock.hide()
        self.defineName()
        self._traces = None

        self.api = CWCoreAPI.getInstance()
        self.graph = GraphWidget()
        self.bselection = QToolBar()
        self.graph.addWidget(self.bselection)
        self.graphDock = CWMainGUI.getInstance().addDock(self.graph, "Partition Comparison Graph", area=Qt.TopDockWidgetArea)
        self.graphDock.hide()
class PartitionDisplay(Parameterized, AutoScript):
    _name = "Partition Comparison"

    def __init__(self, parent):
        AutoScript.__init__(self)
        self._autoscript_init = False
        self.parent = parent
        self.poi = POI(self)
        self.poiDock = CWMainGUI.getInstance().addDock(
            self.poi,
            "Partition Comparison POI Table",
            area=Qt.TopDockWidgetArea)
        self.poiDock.hide()
        self.defineName()
        self._traces = None

        self.api = CWCoreAPI.getInstance()
        self.graph = GraphWidget()
        self.bselection = QToolBar()
        self.graph.addWidget(self.bselection)
        self.graphDock = CWMainGUI.getInstance().addDock(
            self.graph,
            "Partition Comparison Graph",
            area=Qt.TopDockWidgetArea)
        self.graphDock.hide()

    def defineName(self):
        self.partObject = Partition()
        partModeList = {}
        for a in self.partObject.supportedMethods:
            partModeList[a.partitionType] = a

        self.diffObject = DifferenceMode()
        diffModeList = {}
        for a in self.diffObject.supportedMethods:
            diffModeList[a.differenceType] = a

        self.addGroup("generatePartitions")
        self.addGroup("generatePartitionStats")
        self.addGroup("generatePartitionDiffs")
        self.addGroup("displayPartitionDiffs")

        self.getParams().addChildren([
            {
                'name': 'Comparison Mode',
                'key': 'diffmode',
                'type': 'list',
                'values': diffModeList,
                'value': self.diffObject.diffMethodClass,
                'action': lambda _: self.updateScript()
            },
            {
                'name': 'Partition Mode',
                'key': 'partmode',
                'type': 'list',
                'values': partModeList,
                'value': self.partObject.partMethodClass,
                'action': lambda _: self.updateScript()
            },
            {
                'name': 'Display',
                'type': 'action',
                'action': lambda _: self.runAction()
            },
            {
                'name': 'Auto-Save Data to Project',
                'key': 'part-saveints',
                'type': 'bool',
                'value': False,
                'action': lambda _: self.updateScript()
            },
            {
                'name': 'Auto-Load Data from Project',
                'key': 'part-loadints',
                'type': 'bool',
                'value': False,
                'action': lambda _: self.updateScript()
            },
            {
                'name':
                'Points of Interest',
                'key':
                'poi',
                'type':
                'group',
                'children': [
                    {
                        'name': 'Selection Mode',
                        'type': 'list',
                        'values': {
                            'Max N Points/Subkey': 'maxn'
                        },
                        'value': 'maxn'
                    },
                    {
                        'name': 'Point Range',
                        'key': 'poi-pointrng',
                        'type': 'range',
                        'limits': (0, 0),
                        'default': (0, 0),
                        'value': (0, 0),
                        'action': lambda _: self.updatePOI()
                    },
                    {
                        'name': 'Num POI/Subkey',
                        'key': 'poi-nummax',
                        'type': 'int',
                        'limits': (1, 200),
                        'value': 1,
                        'action': lambda _: self.updatePOI()
                    },
                    {
                        'name': 'Min Spacing between POI',
                        'key': 'poi-minspace',
                        'type': 'int',
                        'limits': (1, 100E6),
                        'value': 1,
                        'step': 100,
                        'action': lambda _: self.updatePOI()
                    },
                    {
                        'name': 'Hill detection',
                        'key': 'poi-hilldet',
                        'type': 'bool',
                        'value': True,
                        'tip': "Extend the bounds downhill for each peak",
                        'action': lambda _: self.updatePOI()
                    },
                    # {'name':'Threshold', 'key':'threshold', 'type':'int', 'visible':False},
                    {
                        'name': 'Open POI Table',
                        'type': 'action',
                        'action': lambda _: self.poiDock.show()
                    },
                ]
            },
        ])

    def updatePOI(self, _=None):
        self.updateScript()

        if self._autoscript_init == False:
            return

        # Some sort of race condition - applying Therac-25 type engineering and just
        # randomly hope this is enough delay
        QTimer.singleShot(
            500, lambda: self.runScriptFunction.emit(
                "TraceExplorerDialog_PartitionDisplay_findPOI"))

    def setBytePlot(self, num, sel):
        self.enabledbytes[num] = sel
        if self.doRedraw:
            self.redrawPlot()

    def setByteAll(self, status):
        self.doRedraw = False
        for i, t in enumerate(self.byteNumAct):
            t.defaultWidget().setChecked(status)
            self.setBytePlot(i, status)
        self.doRedraw = True
        self.redrawPlot()

    def redrawPlot(self):
        self.graph.clearPushed()

        for bnum in range(0, self.numKeys):
            if self.enabledbytes[bnum]:
                self.graph.setColorInt(bnum, self.numKeys)
                self.graph.passTrace(self.SADList[bnum],
                                     pen=pg.mkPen(pg.intColor(bnum, 16)),
                                     idString=str(bnum))

    def updateScript(self, ignored=None):
        ##Partitioning & Differences
        try:
            diffMethodStr = self.findParam('diffmode').getValue().__name__
            partMethodStr = self.findParam('partmode').getValue().__name__
        except AttributeError as e:
            return

        self.importsAppend(
            'from chipwhisperer.analyzer.utils.Partition import PartitionRandDebug, PartitionRandvsFixed, PartitionEncKey, PartitionHWIntermediate, PartitionHDLastRound'
        )
        self.importsAppend(
            'from chipwhisperer.analyzer.utils.TraceExplorerScripts.PartitionDisplay import DifferenceModeTTest, DifferenceModeSAD'
        )
        self.importsAppend(
            'from chipwhisperer.analyzer.ui.CWAnalyzerGUI import CWAnalyzerGUI'
        )

        self.addGroup("displayPartitionStats")
        self.addVariable('displayPartitionStats', 'ted', 'self.')
        self.addFunction('displayPartitionStats',
                         'setTraceSource',
                         'UserScript.traces',
                         obj='ted')
        self.addFunction('displayPartitionStats',
                         'parent.getProgressIndicator',
                         '',
                         'progressBar',
                         obj='ted')
        self.addFunction('displayPartitionStats',
                         'partObject.setPartMethod',
                         partMethodStr,
                         obj='ted')
        self.addFunction('displayPartitionStats',
                         'partObject.generatePartitions',
                         'saveFile=True, loadFile=False',
                         'partData',
                         obj='ted')
        self.addFunction(
            'displayPartitionStats',
            'generatePartitionStats',
            'partitionData={"partclass":%s, "partdata":partData}, saveFile=True, progressBar=progressBar'
            % partMethodStr,
            'partStats',
            obj='ted')
        self.addFunction(
            'displayPartitionStats',
            'generatePartitionDiffs',
            '%s, statsInfo={"partclass":%s, "stats":partStats}, saveFile=True, loadFile=False, progressBar=progressBar'
            % (diffMethodStr, partMethodStr),
            'partDiffs',
            obj='ted')
        self.addFunction('displayPartitionStats',
                         'displayPartitions',
                         'differences={"partclass":%s, "diffs":partDiffs}' %
                         partMethodStr,
                         obj='ted')
        self.addFunction('displayPartitionStats',
                         'poi.setDifferences',
                         'partDiffs',
                         obj='ted')

        ##Points of Interest
        ptrng = self.findParam(["Points of Interest",
                                'poi-pointrng']).getValue()
        self.addGroup("findPOI")
        self.addVariable('findPOI', 'ted', 'self.')
        self.addFunction(
            'findPOI',
            'poi.calcPOI',
            'numMax=%d, pointRange=(%d, %d), minSpace=%d' %
            (self.findParam(["Points of Interest", 'poi-nummax'
                             ]).getValue(), ptrng[0], ptrng[1],
             self.findParam(["Points of Interest", 'poi-minspace'
                             ]).getValue()),
            obj='ted')

        #Check if this updateScript was called as a result of showing the TraceExplorer window
        if ignored == "traceexplorer_show":
            self._autoscript_init = True

    def generatePartitionStats(self,
                               partitionData={
                                   "partclass": None,
                                   "partdata": None
                               },
                               saveFile=False,
                               loadFile=False,
                               tRange=(0, -1),
                               progressBar=None):

        traces = self._traces

        if tRange[1] < 0:
            tRange = (tRange[0], traces.numTraces() + 1 + tRange[1])

        self.partObject.setPartMethod(partitionData["partclass"])

        self.numKeys = len(
            self.partObject.partMethod.getPartitionNum(traces, 0))

        numPoints = traces.numPoints()

        if loadFile:
            cfgsecs = self.api.project().getDataConfig(
                sectionName="Trace Statistics",
                subsectionName="Total Trace Statistics")
            foundsecs = []
            for cfg in cfgsecs:
                desiredsettings = {}
                desiredsettings["tracestart"] = tRange[0]
                desiredsettings["traceend"] = tRange[1]
                desiredsettings[
                    "partitiontype"] = self.partObject.partMethod.__class__.__name__
                if self.api.project().checkDataConfig(cfg, desiredsettings):
                    foundsecs.append(cfg)
        else:
            foundsecs = []

        if len(foundsecs) > 1:
            IOError("Too many sections!!!")
        elif len(foundsecs) == 1:
            fname = self.api.project().convertDataFilepathAbs(
                foundsecs[0]["filename"])
            stats = np.load(fname)
        else:
            # Array to hold average + stddev of all traces/partitions
            A_k = []
            A_j = []
            Q_k = []
            dataArrays = [A_k, A_j, Q_k]
            ACnt = []
            for bnum in range(0, self.numKeys):
                for d in dataArrays:
                    d.append([])
                ACnt.append([])
                for i in range(0,
                               self.partObject.partMethod.getNumPartitions()):
                    for d in dataArrays:
                        d[bnum].append(np.zeros(numPoints))
                    ACnt[bnum].append(0)

            # Get segment list
            segList = traces.getSegmentList()

            if progressBar:
                progressBar.setWindowTitle("Phase 1: Trace Statistics")
                progressBar.setMaximum(
                    bnum)  # len(segList['offsetList']) * self.numKeys)
                progressBar.show()

            # TODO: Double-check this fix
            # for tsegn, segtrace in enumerate(segList['offsetList']):
            tsegn = 0
            if progressBar: progressBar.setText("Segment %d" % tsegn)

            # Average data needs to be calculated
            # Require partition list
            partData = partitionData["partdata"]

            # print "Calculating Average + Std-Dev"
            # Std-Dev calculation:
            # A[0] = 0
            # A[k] = A[k-1] + (x[k] - A[k-1]) / k
            # Q[0] = 0
            # Q[k] = Q[k-1] + (x[k] - A[k-1])(x[k] - A[k])
            for bnum in range(0, self.numKeys):
                progressBar.updateStatus(tsegn * self.numKeys + bnum)
                if progressBar.wasAborted():
                    break
                for i in range(0,
                               self.partObject.partMethod.getNumPartitions()):
                    util.updateUI()
                    tlist = partData[bnum][i]
                    if len(tlist) > 0:
                        for tnum in tlist:
                            if tnum > tRange[0] and tnum < tRange[1]:
                                t = traces.getTrace(tnum)
                                ACnt[bnum][i] += 1
                                A_k[bnum][i] = A_k[bnum][i] + (
                                    t - A_j[bnum][i]) / ACnt[bnum][i]
                                Q_k[bnum][i] = Q_k[bnum][i] + (
                                    (t - A_j[bnum][i]) * (t - A_k[bnum][i]))
                                A_j[bnum][i] = A_k[bnum][i]

            if progressBar.wasAborted():
                progressBar.hide()
                return

            # Finally get variance
            for bnum in range(0, self.numKeys):
                for i in range(0,
                               self.partObject.partMethod.getNumPartitions()):
                    # TODO: Should be using population variance or sample variance (e.g. /n or /n-1)?
                    #      Since this is taken over very large sample sizes I imagine it won't matter
                    #      ultimately.
                    Q_k[bnum][i] = Q_k[bnum][i] / max(ACnt[bnum][i] - 1, 1)

            # Average is in A_k
            stats = {"mean": A_k, "variance": Q_k, "number": ACnt}

            # Wasn't cancelled - save this to project file for future use if requested
            if saveFile:
                progressBar.setText("Saving Mean/Variance Partitions")
                cfgsec = self.api.project().addDataConfig(
                    sectionName="Trace Statistics",
                    subsectionName="Total Trace Statistics")
                cfgsec["tracestart"] = tRange[0]
                cfgsec["traceend"] = tRange[1]
                cfgsec[
                    "partitiontype"] = self.partObject.partMethod.__class__.__name__
                fname = self.api.project().getDataFilepath(
                    'tracestats-%s-%d-%s.npz' %
                    (cfgsec["partitiontype"], tRange[0], tRange[1]),
                    'analysis')

                # Save mean/variance for trace
                np.savez(fname["abs"], mean=A_k, variance=Q_k, number=ACnt)
                cfgsec["filename"] = fname["rel"]

        progressBar.hide()
        return stats

    def generatePartitionDiffs(self,
                               diffModule,
                               statsInfo={
                                   "partclass": None,
                                   "stats": None
                               },
                               saveFile=False,
                               loadFile=False,
                               tRange=(0, -1),
                               progressBar=None):

        traces = self._traces

        if tRange[1] < 0:
            tRange = (tRange[0], traces.numTraces() + 1 + tRange[1])

        self.partObject.setPartMethod(statsInfo["partclass"])
        self.diffObject.setDiffMethod(diffModule)

        self.numKeys = len(
            self.partObject.partMethod.getPartitionNum(traces, 0))

        numPoints = traces.numPoints()

        foundsecs = []
        if loadFile:
            cfgsecs = self.api.project().getDataConfig(
                sectionName="Trace Statistics",
                subsectionName="Partition Differences")
            for cfg in cfgsecs:
                desiredsettings = {}
                desiredsettings["tracestart"] = tRange[0]
                desiredsettings["traceend"] = tRange[1]
                desiredsettings[
                    "partitiontype"] = self.partObject.partMethod.__class__.__name__
                desiredsettings[
                    "comparetype"] = self.diffObject.mode.moduleName
                if self.api.project().checkDataConfig(cfg, desiredsettings):
                    foundsecs.append(cfg)
        else:
            cfgsecs = []

        if len(foundsecs) > 1:
            IOError("Too many sections!!!")
        elif len(foundsecs) == 1:
            fname = self.api.project().convertDataFilepathAbs(
                foundsecs[0]["filename"])
            SADList = np.load(fname)
        else:
            progressBar.setWindowTitle(
                "Phase 2: Calculating Partition Differences")
            progressBar.setText("Calculating all Differences based on " +
                                self.diffObject.mode.differenceType)
            SADList = self.diffObject.difference(
                self.numKeys, self.partObject.partMethod.getNumPartitions(),
                None, numPoints, statsInfo["stats"], progressBar)

            if saveFile:
                cfgsec = self.api.project().addDataConfig(
                    sectionName="Trace Statistics",
                    subsectionName="Partition Differences")
                cfgsec["tracestart"] = tRange[0]
                cfgsec["traceend"] = tRange[1]
                cfgsec[
                    "partitiontype"] = self.partObject.partMethod.__class__.__name__
                cfgsec["comparetype"] = self.diffObject.mode.moduleName
                fname = self.api.project().getDataFilepath(
                    'partdiffs-%s-%s-%d-%s.npy' %
                    (cfgsec["partitiontype"], cfgsec["comparetype"], tRange[0],
                     tRange[1]), 'analysis')
                np.save(fname["abs"], SADList)
                cfgsec["filename"] = fname["rel"]

        progressBar.updateStatus(progressBar.maximum)
        progressBar.setWindowTitle('Debug Fail')
        if progressBar.wasAborted():
            return

        self.SADList = SADList
        return SADList

    def displayPartitions(self,
                          differences={
                              "partclass": None,
                              "diffs": None
                          },
                          tRange=(0, -1)):
        self.graphDock.show()
        traces = self._traces

        if tRange[1] < 0:
            tRange = (tRange[0], traces.numTraces() + 1 + tRange[1])

        self.partObject.setPartMethod(differences["partclass"])
        self.numKeys = len(
            self.partObject.partMethod.getPartitionNum(traces, 0))
        self.SADList = differences["diffs"]

        # Place byte selection option on graph
        if hasattr(self, 'enabledbytes') and len(
                self.enabledbytes) == self.numKeys:
            pass
        else:
            self.enabledbytes = [False] * self.numKeys

        self.doRedraw = True

        self.byteNumAct = []
        for i in range(0, self.numKeys):
            ql = QToolButton()
            ql.setText('%d' % i)
            color = pg.intColor(i, self.numKeys)
            ql.setStyleSheet("color: rgb(%d, %d, %d)" %
                             (color.red(), color.green(), color.blue()))
            qa = QWidgetAction(self.graph)
            qa.setDefaultWidget(ql)
            qa.setStatusTip('%d' % i)
            ql.setCheckable(True)
            ql.setChecked(self.enabledbytes[i])
            ql.clicked[bool].connect(partial(self.setBytePlot, i))
            self.byteNumAct.append(qa)

        byteNumAllOn = QAction('All On', self.graph)
        byteNumAllOff = QAction('All Off', self.graph)
        byteNumAllOn.triggered.connect(partial(self.setByteAll, True))
        byteNumAllOff.triggered.connect(partial(self.setByteAll, False))

        self.bselection.clear()
        for i in range(0, self.numKeys):
            self.bselection.addAction(self.byteNumAct[i])
        self.bselection.addAction(byteNumAllOn)
        self.bselection.addAction(byteNumAllOff)
        self.graph.setPersistance(True)

        self.poi.setDifferences(self.SADList)

        self.findParam(["Points of Interest", 'poi-pointrng']).setLimits(
            (0, len(self.SADList[0])))
        self.findParam(["Points of Interest", 'poi-pointrng']).setValue(
            (0, len(self.SADList[0])))
        self.redrawPlot()

    def runAction(self):
        self.runScriptFunction.emit(
            'TraceExplorerDialog_PartitionDisplay_displayPartitionStats')

    def setTraceSource(self, traces):
        self._traces = traces
        self.partObject.setTraceSource(self._traces)
    def __init__(self, name=None):
        GraphWidget.__init__(self)
        if name is not None:
            self._name = name
        ActiveTraceObserver.__init__(self)

        self.params.addChildren([
            {
                'name': 'Redraw after Each',
                'type': 'bool',
                'value': False
            },
            #{'name':'Trace Range', 'key':'tracerng', 'type':'range', 'limits':(0, 0), 'value':(0, 0)},
            {
                'name':
                'Trace(s) to Plot',
                'key':
                'tracecmd',
                'type':
                'str',
                'value':
                '0',
                'help':
                '%namehdr%' +
                "Selects a trace or two to plot. You can specify ranges, individual traces, and colours. Example commands:\n"
                +
                " ==================== ========================================================== \n"
                + "  Plot Command          Result"
                "  0                     Plots trace #0\n" +
                "  0-10                  Plots trace #0 - #10 inclusive\n" +
                "  0, 2-5, 9             Plots trace #0, #2-5 inclusive, and #9\n"
                +
                "  0(r), 3-6(g), 22(b)   Plots trace #0 in red, #3-#6 in green, and #22 in blue\n"
                +
                "  2(#F005)              Plots trace #2 in red (RGB=F00) with Alpha of 0.3125\n"
                + "  3(#B0171F)            Plots trace #3 in 'india red'\n\n" +
                " ==================== ========================================================== \n"
                +
                "Colour strings are passed to pyqtgraph.mkPen as a string. This means you can specify the following:\n"
                +
                " =============== ========================================== \n"
                +
                "  Colour String    Description                             \n"
                +
                " =============== ========================================== \n"
                +
                "     c              One of  r, g, b, c, m, y, k, w         \n"
                +
                "     RGB            Hexadecimal string, may begin with #   \n"
                +
                "     RGBA           Hexadecimal string with alpha value    \n"
                +
                "     RRGGBB                                                \n"
                +
                "     RRGGBBAA                                              \n"
                +
                " =============== ========================================== \n"
            },
            {
                'name': 'Point Range',
                'key': 'pointrng',
                'type': 'rangegraph',
                'limits': (0, 0),
                'value': (0, 0),
                'graphwidget': self
            },
            {
                'name': 'Downsampling Mode',
                'key': 'dsmode',
                'type': 'list',
                'values': {
                    'None': None,
                    'Subsample': 'subsample',
                    'Mean': 'mean',
                    'Peak': 'peak'
                },
                'value': 'peak',
                'action': self.plotInputTrace
            },
            {
                'name':
                'Y Axis',
                'type':
                'group',
                'expanded':
                False,
                'children': [
                    {
                        'name': 'Unity',
                        'type': 'list',
                        'values': {
                            "None": "",
                            "Voltage": "V",
                            "Current": "A"
                        },
                        'value': "",
                        'action': self.plotInputTrace
                    },
                    {
                        'name': 'Scale Factor',
                        'type': 'float',
                        'limits': (1E-9, 1E9),
                        'value': 1.0,
                        'action': self.plotInputTrace
                    },
                    {
                        'name': 'Offset Factor',
                        'type': 'float',
                        'limits': (-1E9, 1E9),
                        'value': 0.0,
                        'action': self.plotInputTrace
                    },
                ]
            },
            {
                'name': 'X Axis',
                'type': 'list',
                'values': {
                    "Sample": "Pts.",
                    "Time": "s"
                },
                'value': "Pts.",
                'action': self.plotInputTrace
            },
            {
                'name':
                'T-Statistic',
                'key':
                'tstat',
                'type':
                'group',
                'expanded':
                True,
                'children': [
                    {
                        'name': 'Enable',
                        'key': 'enable',
                        'type': 'bool',
                        'value': False
                    },
                    {
                        'name': 'Leakage Type',
                        'key': 'type',
                        'type': 'list',
                        'values': ['Text In', 'Text Out', 'Key', 'None'],
                        'value': 'Text In'
                    },
                    {
                        'name': 'Trace Range',
                        'key': 'range',
                        'type': 'range',
                        'limits': (0, 0),
                        'value': (0, 0)
                    },
                ]
            },
            {
                'name': 'Redraw',
                'type': 'action',
                'action': self.plotInputTrace
            },
        ])

        self.findParam('input').setValue(
            TraceSource.registeredObjects["Trace Management"])
        TraceSource.sigRegisteredObjectsChanged.connect(
            self.traceSourcesChanged)

        self.resetTraceLimits()
        self.setDefaultYRange(-0.5, 0.5)
        self.YDefault()
Example #12
0
class PartitionDisplay(Parameterized, AutoScript):
    _name = "Partition Comparison"

    def __init__(self, parent):
        AutoScript.__init__(self)
        self._autoscript_init = False
        self.parent = parent
        self.poi = POI(self)
        self.poiDock = CWMainGUI.getInstance().addDock(self.poi, "Partition Comparison POI Table", area=Qt.TopDockWidgetArea)
        self.poiDock.hide()
        self.defineName()
        self._traces = None

        self.api = CWCoreAPI.getInstance()
        self.graph = GraphWidget()
        self.bselection = QToolBar()
        self.graph.addWidget(self.bselection)
        self.graphDock = CWMainGUI.getInstance().addDock(self.graph, "Partition Comparison Graph", area=Qt.TopDockWidgetArea)
        self.graphDock.hide()

    def defineName(self):
        self.partObject = Partition(self)
        partModeList = {}
        for a in self.partObject.supportedMethods:
            partModeList[a.partitionType] = a

        self.diffObject = DifferenceMode()
        diffModeList = {}
        for a in self.diffObject.supportedMethods:
            diffModeList[a.differenceType] = a

        self.addGroup("generatePartitions")
        self.addGroup("generatePartitionStats")
        self.addGroup("generatePartitionDiffs")
        self.addGroup("displayPartitionDiffs")

        self.getParams().addChildren([
              {'name':'Comparison Mode', 'key':'diffmode', 'type':'list', 'values':diffModeList, 'value':self.diffObject.diffMethodClass, 'action':lambda _: self.updateScript()},
              {'name':'Partition Mode', 'key':'partmode', 'type':'list', 'values':partModeList, 'value':self.partObject.partMethodClass, 'action':lambda _: self.updateScript()},
              {'name':'Display', 'type':'action', 'action':lambda _:self.runAction()},

              {'name':'Auto-Save Data to Project', 'key':'part-saveints', 'type':'bool', 'value':False, 'action':lambda _: self.updateScript()},
              {'name':'Auto-Load Data from Project', 'key':'part-loadints', 'type':'bool', 'value':False, 'action':lambda _: self.updateScript()},

              {'name':'Points of Interest', 'key':'poi', 'type':'group', 'children':[
                 {'name':'Selection Mode', 'type':'list', 'values':{'Max N Points/Subkey':'maxn'}, 'value':'maxn'},
                 {'name':'Point Range', 'key':'poi-pointrng', 'type':'range', 'limits':(0, 0), 'default':(0, 0), 'value':(0, 0), 'action':lambda _: self.updatePOI()},
                 {'name':'Num POI/Subkey', 'key':'poi-nummax', 'type':'int', 'limits':(1, 200), 'value':1, 'action':lambda _: self.updatePOI()},
                 {'name':'Min Spacing between POI', 'key':'poi-minspace', 'type':'int', 'limits':(1, 100E6), 'value':1, 'step':100, 'action':lambda _: self.updatePOI()},
                 {'name':'Hill detection', 'key':'poi-hilldet', 'type':'bool', 'value':True, 'tip':"Extend the bounds downhill for each peak", 'action':lambda _: self.updatePOI()},
                 # {'name':'Threshold', 'key':'threshold', 'type':'int', 'visible':False},
                 {'name':'Open POI Table', 'type':'action', 'action':lambda _: self.poiDock.show()},
              ]},
        ])

    def updatePOI(self, ignored=None):
        self.updateScript()

        if self._autoscript_init == False:
            return

        # Some sort of race condition - applying Therac-25 type engineering and just
        # randomly hope this is enough delay
        QTimer.singleShot(500, lambda:self.runScriptFunction.emit("TraceExplorerDialog_PartitionDisplay_findPOI"))

    def setBytePlot(self, num, sel):
        self.enabledbytes[num] = sel
        if self.doRedraw:
            self.redrawPlot()

    def setByteAll(self, status):
        self.doRedraw = False
        for i, t in enumerate(self.byteNumAct):
            t.defaultWidget().setChecked(status)
            self.setBytePlot(i, status)
        self.doRedraw = True
        self.redrawPlot()

    def redrawPlot(self):
        self.graph.clearPushed()

        for bnum in range(0, self.numKeys):
            if self.enabledbytes[bnum]:
                self.graph.setColorInt(bnum, self.numKeys)
                self.graph.passTrace(self.SADList[bnum], pen=pg.mkPen(pg.intColor(bnum, 16)), idString = str(bnum))

    def updateScript(self, ignored=None):
        ##Partitioning & Differences
        try:
            diffMethodStr = self.findParam('diffmode').getValue().__name__
            partMethodStr = self.findParam('partmode').getValue().__name__
        except AttributeError as e:
            return

        self.importsAppend('from chipwhisperer.analyzer.utils.Partition import PartitionRandDebug, PartitionRandvsFixed, PartitionEncKey, PartitionHWIntermediate, PartitionHDLastRound')
        self.importsAppend('from chipwhisperer.analyzer.utils.TraceExplorerScripts.PartitionDisplay import DifferenceModeTTest, DifferenceModeSAD')
        self.importsAppend('from chipwhisperer.analyzer.ui.CWAnalyzerGUI import CWAnalyzerGUI')

        self.addGroup("displayPartitionStats")
        self.addVariable('displayPartitionStats', 'ted', 'self.')
        self.addFunction('displayPartitionStats', 'setTraceSource', 'UserScript.traces', obj='ted')
        self.addFunction('displayPartitionStats', 'parent.getProgressIndicator', '', 'progressBar', obj='ted')
        self.addFunction('displayPartitionStats', 'partObject.setPartMethod', partMethodStr, obj='ted')
        self.addFunction('displayPartitionStats', 'partObject.generatePartitions', 'saveFile=True, loadFile=False', 'partData', obj='ted')
        self.addFunction('displayPartitionStats', 'generatePartitionStats',
                            'partitionData={"partclass":%s, "partdata":partData}, saveFile=True, progressBar=progressBar' % partMethodStr,
                            'partStats', obj='ted')
        self.addFunction('displayPartitionStats', 'generatePartitionDiffs',
                            '%s, statsInfo={"partclass":%s, "stats":partStats}, saveFile=True, loadFile=False, progressBar=progressBar'%
                            (diffMethodStr, partMethodStr),
                            'partDiffs', obj='ted')
        self.addFunction('displayPartitionStats', 'displayPartitions', 'differences={"partclass":%s, "diffs":partDiffs}' % partMethodStr, obj='ted')
        self.addFunction('displayPartitionStats', 'poi.setDifferences', 'partDiffs', obj='ted')

        ##Points of Interest
        ptrng = self.findParam(["Points of Interest",'poi-pointrng']).getValue()
        self.addGroup("findPOI")
        self.addVariable('findPOI', 'ted', 'self.')
        self.addFunction('findPOI', 'poi.calcPOI', 'numMax=%d, pointRange=(%d, %d), minSpace=%d' % (
                            self.findParam(["Points of Interest",'poi-nummax']).getValue(),
                            ptrng[0], ptrng[1],
                            self.findParam(["Points of Interest",'poi-minspace']).getValue()),
                          obj='ted')

        #Check if this updateScript was called as a result of showing the TraceExplorer window
        if ignored == "traceexplorer_show":
            self._autoscript_init = True

    def generatePartitionStats(self, partitionData={"partclass":None, "partdata":None}, saveFile=False, loadFile=False,  tRange=(0, -1), progressBar=None):

        traces = self._traces

        if tRange[1] < 0:
            tRange = (tRange[0], traces.numTraces() + 1 + tRange[1])

        self.partObject.setPartMethod(partitionData["partclass"])

        self.numKeys = len(self.partObject.partMethod.getPartitionNum(traces, 0))

        numPoints = traces.numPoints()

        if loadFile:
            cfgsecs = self.api.project().getDataConfig(sectionName="Trace Statistics", subsectionName="Total Trace Statistics")
            foundsecs = []
            for cfg in cfgsecs:
                desiredsettings = {}
                desiredsettings["tracestart"] = tRange[0]
                desiredsettings["traceend"] = tRange[1]
                desiredsettings["partitiontype"] = self.partObject.partMethod.__class__.__name__
                if self.api.project().checkDataConfig(cfg, desiredsettings):
                    foundsecs.append(cfg)
        else:
            foundsecs = []

        if len(foundsecs) > 1:
            IOError("Too many sections!!!")
        elif len(foundsecs) == 1:
            fname = self.api.project().convertDataFilepathAbs(foundsecs[0]["filename"])
            stats = np.load(fname)
        else:
            # Array to hold average + stddev of all traces/partitions
            A_k = []
            A_j = []
            Q_k = []
            dataArrays = [A_k, A_j, Q_k]
            ACnt = []
            for bnum in range(0, self.numKeys):
                for d in dataArrays:
                    d.append([])
                ACnt.append([])
                for i in range(0, self.partObject.partMethod.getNumPartitions()):
                    for d in dataArrays:
                        d[bnum].append(np.zeros(numPoints))
                    ACnt[bnum].append(0)

            # Get segment list
            segList = traces.getSegmentList()

            if progressBar:
                progressBar.setWindowTitle("Phase 1: Trace Statistics")
                progressBar.setMaximum(bnum)  # len(segList['offsetList']) * self.numKeys)
                progressBar.show()

            # TODO: Double-check this fix
            # for tsegn, segtrace in enumerate(segList['offsetList']):
            tsegn = 0
            if progressBar: progressBar.setText("Segment %d" % tsegn)

            # Average data needs to be calculated
            # Require partition list
            partData = partitionData["partdata"]


            # print "Calculating Average + Std-Dev"
            # Std-Dev calculation:
            # A[0] = 0
            # A[k] = A[k-1] + (x[k] - A[k-1]) / k
            # Q[0] = 0
            # Q[k] = Q[k-1] + (x[k] - A[k-1])(x[k] - A[k])
            for bnum in range(0, self.numKeys):
                progressBar.updateStatus(tsegn * self.numKeys + bnum)
                if progressBar.wasAborted():
                    break
                for i in range(0, self.partObject.partMethod.getNumPartitions()):
                    util.updateUI()
                    tlist = partData[bnum][i]
                    if len(tlist) > 0:
                        for tnum in tlist:
                            if tnum > tRange[0] and tnum < tRange[1]:
                                t = traces.getTrace(tnum)
                                ACnt[bnum][i] += 1
                                A_k[bnum][i] = A_k[bnum][i] + (t - A_j[bnum][i]) / ACnt[bnum][i]
                                Q_k[bnum][i] = Q_k[bnum][i] + ((t - A_j[bnum][i]) * (t - A_k[bnum][i]))
                                A_j[bnum][i] = A_k[bnum][i]

            if progressBar.wasAborted():
                progressBar.hide()
                return

            # Finally get variance
            for bnum in range(0, self.numKeys):
                    for i in range(0, self.partObject.partMethod.getNumPartitions()):
                        # TODO: Should be using population variance or sample variance (e.g. /n or /n-1)?
                        #      Since this is taken over very large sample sizes I imagine it won't matter
                        #      ultimately.
                        Q_k[bnum][i] = Q_k[bnum][i] / max(ACnt[bnum][i] - 1, 1)

            # Average is in A_k
            stats = {"mean":A_k, "variance":Q_k, "number":ACnt}

            # Wasn't cancelled - save this to project file for future use if requested
            if saveFile:
                progressBar.setText("Saving Mean/Variance Partitions")
                cfgsec = self.api.project().addDataConfig(sectionName="Trace Statistics", subsectionName="Total Trace Statistics")
                cfgsec["tracestart"] = tRange[0]
                cfgsec["traceend"] = tRange[1]
                cfgsec["partitiontype"] = self.partObject.partMethod.__class__.__name__
                fname = self.api.project().getDataFilepath('tracestats-%s-%d-%s.npz' % (cfgsec["partitiontype"], tRange[0], tRange[1]), 'analysis')

                # Save mean/variance for trace
                np.savez(fname["abs"], mean=A_k, variance=Q_k, number=ACnt)
                cfgsec["filename"] = fname["rel"]

        progressBar.hide()
        return stats

    def generatePartitionDiffs(self, diffModule, statsInfo={"partclass":None, "stats":None}, saveFile=False, loadFile=False, tRange=(0, -1), progressBar=None):

        traces = self._traces

        if tRange[1] < 0:
            tRange = (tRange[0], traces.numTraces() + 1 + tRange[1])

        self.partObject.setPartMethod(statsInfo["partclass"])
        self.diffObject.setDiffMethod(diffModule)

        self.numKeys = len(self.partObject.partMethod.getPartitionNum(traces, 0))

        numPoints = traces.numPoints()

        foundsecs = []
        if loadFile:
            cfgsecs = self.api.project().getDataConfig(sectionName="Trace Statistics", subsectionName="Partition Differences")
            for cfg in cfgsecs:
                desiredsettings = {}
                desiredsettings["tracestart"] = tRange[0]
                desiredsettings["traceend"] = tRange[1]
                desiredsettings["partitiontype"] = self.partObject.partMethod.__class__.__name__
                desiredsettings["comparetype"] = self.diffObject.mode.moduleName
                if self.api.project().checkDataConfig(cfg, desiredsettings):
                    foundsecs.append(cfg)
        else:
            cfgsecs = []

        if len(foundsecs) > 1:
            IOError("Too many sections!!!")
        elif len(foundsecs) == 1:
            fname = self.api.project().convertDataFilepathAbs(foundsecs[0]["filename"])
            SADList = np.load(fname)
        else:
            progressBar.setWindowTitle("Phase 2: Calculating Partition Differences")
            progressBar.setText("Calculating all Differences based on " + self.diffObject.mode.differenceType)
            SADList = self.diffObject.difference(self.numKeys, self.partObject.partMethod.getNumPartitions(), None, numPoints, statsInfo["stats"], progressBar)

            if saveFile:
                cfgsec = self.api.project().addDataConfig(sectionName="Trace Statistics", subsectionName="Partition Differences")
                cfgsec["tracestart"] = tRange[0]
                cfgsec["traceend"] = tRange[1]
                cfgsec["partitiontype"] = self.partObject.partMethod.__class__.__name__
                cfgsec["comparetype"] = self.diffObject.mode.moduleName
                fname = self.api.project().getDataFilepath('partdiffs-%s-%s-%d-%s.npy' % (cfgsec["partitiontype"], cfgsec["comparetype"], tRange[0], tRange[1]), 'analysis')
                np.save(fname["abs"], SADList)
                cfgsec["filename"] = fname["rel"]

        progressBar.updateStatus(progressBar.maximum)
        progressBar.setWindowTitle('Debug Fail')
        if progressBar.wasAborted():
            return

        self.SADList = SADList
        return SADList

    def displayPartitions(self, differences={"partclass":None, "diffs":None}, tRange=(0, -1)):
        self.graphDock.show()
        traces = self._traces

        if tRange[1] < 0:
            tRange = (tRange[0], traces.numTraces() + 1 + tRange[1])

        self.partObject.setPartMethod(differences["partclass"])
        self.numKeys = len(self.partObject.partMethod.getPartitionNum(traces, 0))
        self.SADList = differences["diffs"]

        # Place byte selection option on graph
        if hasattr(self, 'enabledbytes') and len(self.enabledbytes) == self.numKeys:
            pass
        else:
            self.enabledbytes = [False] * self.numKeys

        self.doRedraw = True

        self.byteNumAct = []
        for i in range(0, self.numKeys):
            ql = QToolButton()
            ql.setText('%d' % i)
            color = pg.intColor(i, self.numKeys)
            ql.setStyleSheet("color: rgb(%d, %d, %d)" % (color.red(), color.green(), color.blue()))
            qa = QWidgetAction(self.graph)
            qa.setDefaultWidget(ql)
            qa.setStatusTip('%d' % i)
            ql.setCheckable(True)
            ql.setChecked(self.enabledbytes[i])
            ql.clicked[bool].connect(partial(self.setBytePlot, i))
            self.byteNumAct.append(qa)

        byteNumAllOn = QAction('All On', self.graph)
        byteNumAllOff = QAction('All Off', self.graph)
        byteNumAllOn.triggered.connect(partial(self.setByteAll, True))
        byteNumAllOff.triggered.connect(partial(self.setByteAll, False))

        self.bselection.clear()
        for i in range(0, self.numKeys):
            self.bselection.addAction(self.byteNumAct[i])
        self.bselection.addAction(byteNumAllOn)
        self.bselection.addAction(byteNumAllOff)
        self.graph.setPersistance(True)

        self.poi.setDifferences(self.SADList)

        self.findParam(["Points of Interest",'poi-pointrng']).setLimits((0, len(self.SADList[0])))
        self.findParam(["Points of Interest",'poi-pointrng']).setValue((0, len(self.SADList[0])))
        self.redrawPlot()

    def runAction(self):
        self.runScriptFunction.emit('TraceExplorerDialog_PartitionDisplay_displayPartitionStats')

    def setTraceSource(self, traces):
        self._traces = traces
        self.partObject.setTraceSource(self._traces)