aboutsummaryrefslogtreecommitdiff
path: root/pyecsca/sca/scope/chipwhisperer.py
blob: 05c8e6914197d0b1be57fcd31a94d3d79b689bda (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
"""
This module provides an oscilloscope class using the ChipWhisperer-Lite scope.
"""
from typing import Optional, Tuple, Sequence, Set

import numpy as np
from chipwhisperer.capture.scopes.OpenADC import OpenADC
from public import public

from .base import Scope, SampleType
from ..trace import Trace


@public
class ChipWhispererScope(Scope):  # pragma: no cover
    """A ChipWhisperer based scope."""

    def __init__(self, scope: OpenADC):
        super().__init__()
        self.scope = scope
        self.triggers: Set[str] = set()

    def open(self) -> None:
        self.scope.con()

    @property
    def channels(self) -> Sequence[str]:
        return []

    def setup_frequency(
        self, frequency: int, pretrig: int, posttrig: int
    ) -> Tuple[int, int]:
        if pretrig != 0:
            raise ValueError("ChipWhisperer does not support pretrig samples.")
        self.scope.clock.clkgen_freq = frequency
        self.scope.samples = posttrig
        return self.scope.clock.freq_ctr, self.scope.samples

    def setup_channel(
        self, channel: str, coupling: str, range: float, offset: float, enable: bool
    ) -> None:
        pass

    def setup_trigger(
        self,
        channel: str,
        threshold: float,
        direction: str,
        delay: int,
        timeout: int,
        enable: bool,
    ) -> None:
        if enable:
            self.triggers.add(channel)
        elif channel in self.triggers:
            self.triggers.remove(channel)
        self.scope.adc.basic_mode = direction
        self.scope.trigger.triggers = " OR ".join(self.triggers)

    def setup_capture(self, channel: str, enable: bool) -> None:
        pass

    def arm(self) -> None:
        self.scope.arm()

    def capture(self, timeout: Optional[int] = None) -> bool:
        return not self.scope.capture()

    def retrieve(
        self, channel: str, type: SampleType, dtype=np.float16
    ) -> Optional[Trace]:
        data = self.scope.get_last_trace()
        if data is None:
            return None
        return Trace(
            np.array(data, dtype=dtype),
            {"sampling_frequency": self.scope.clock.clkgen_freq, "channel": channel},
        )

    def stop(self) -> None:
        pass

    def close(self) -> None:
        self.scope.dis()