为sigrok编写解码器

图片



如果您使用数字技术,则迟早需要逻辑分析仪。可用的障碍之一是DreamSourceLab的DSLogic逻辑分析仪。至少在网站上不止一次提到他:



它的功能是开源代码以及负责解码信号的开源sigrok连同大量令人印象深刻的现有信号解码器列表,该库提供了用于编写自己的API的API。这就是我们要做的。



演示台



, . TTP229-BSF. 8- 16- . Arduino, DSLogic.



图片





, , . , . , , .



sigrok中的每个解码器都是用Python 3编写的独立软件包,并在解码器文件夹下具有自己的目录。与任何Python包一样,解码器包含__init__.py,根据sigrok接受的命名,该文件包含实现本身的pd.py文件。



图片



__init__.py中的代码是标准代码,包括描述协议的文档字符串和解码器导入(d28dee9):



'''
Protocol description.
'''

from .pd import Decoder


pd.py文件包含解码器实现(d28dee9):



class Decoder(srd.Decoder):
    api_version = 3
    id = 'empty'
    name = 'empty'
    longname = 'empty decoder'
    desc = 'Empty decoder that can be loaded by sigrok.'
    license = 'mit'
    inputs = ['logic']
    outputs = ['empty']
    tags = ['Embedded/industrial']
    channels = (
        {'id': 'scl', 'name': 'SCL', 'desc': 'Clock'},
        {'id': 'sdo', 'name': 'SDO', 'desc': 'Data'},
    )

    def start(self):
        pass

    def reset(self):
        pass

    def decode(self):
        pass


这是一个最小的实现,可以由库加载,但不解码任何内容。让我们看一下所需的属性:



  • api_version – Protocol decoder API, . libsigrokdecode 3- Protocol decoder API. .
  • id – , . , .
  • name, longname, desc – , , . .
  • inputs, outputs – . 'logic' . . , , SPI. SPI . , SPI . 'spi'.
  • license, tag – . DSView 1.1.1 + libsigrokdecode tags - .
  • 通道 -解码器使用的信号线列表。输入数据格式为逻辑的解码器需要此属性。


和所需的方法:



  • start() -解码开始之前调用的方法。在此方法中,应为当前解码会话进行设置。
  • reset() -解码停止时调用的方法。应该使解码器返回其初始状态。
  • define() -调用信号解码方法。


处理完解码器的最少实现后,您就可以开始解码实际信号了。



全功能解码器



首先,考虑数据信号的时序图。TTP229-BSF具有几种工作模式,我给出了稍后将要使用的模式的时序图。有关微电路所有工作模式的更多详细信息,请参见其文档。



图片



首先,有必要描述解码器将使用的一组强制线。在这种情况下,有两条时钟线(SCL)和数据线(SDO)。



class Decoder(srd.Decoder):
    ...
    inputs = ['logic']
    channels = (
        {'id': 'scl', 'name': 'SCL', 'desc': 'Clock'},
        {'id': 'sdo', 'name': 'SDO', 'desc': 'Data'},
    )


当微电路检测到按钮按下时,它将在SDO线上设置数据有效(DV)信号,接收器应根据此信号开始读取数据。让我们找到并解码该信号。



sigrok , . . , , . Protocol decoder API . . wait(). . , self.samplenum .



, , – , :



  • 'l'-低电平,逻辑0;
  • 'h'-高级,逻辑1;
  • 'r'-信号上升,从低电平过渡到高电平;
  • 'f'-信号衰减,从高到低状态的转变;
  • 'e'-任意信号变化,上升或下降;
  • 's'-稳定状态,0或1。


因此,为了找到DV信号的开始,需要一个条件来描述SCL线为高电平,并且数据线(SDO)上的信号下降。我们使用条件调用wait()函数并保存样本编号:



        self.wait({0: 'h', 1: 'f'})
        self.dv_block_ss = self.samplenum


为了找到DV信号的末端,有必要设置一个条件,使SCL线保持高电平,而数据线变为高电平:

        self.wait({0: 'h', 1: 'r'})


完成对wait()函数的最后一次调用后,将知道DV信号的开始和结束的样本数。现在该为它创建注释了。为此,将注释添加到解码器并将其分组在一起(annotation_rows):



class Decoder(srd.Decoder):
    ...
    annotations = (
        ('dv', 'Data valid'),
    )
    annotation_rows = (
        ('fields', 'Fields', (0,)),
    )


其中0是属于该组的self.annotations元组中注释的索引。您还需要注册注释的输出:



    def start(self):
        self.out_ann = self.register(srd.OUTPUT_ANN)


现在,您可以放置​​DV信号的注释了。这是通过调用put()函数(f613b83)完成的:



        self.put(self.dv_block_ss, self.samplenum,
                 self.out_ann, [0, ['Data valid', 'DV']])


函数参数:注释开始样本编号(self.dv_block_ss),注释结束样本编号(self.samplenum),注释输出标识符(self.out_ann)和注释数据。数据以注释索引(0)的列表和字符串的嵌套列表(从最长到最短)的形式显示,以显示在说明中。如果指定了多行,则界面可以独立选择显示的行,例如,取决于所使用的比例:







类似地,我们为DV信号结束与从微控制器开始读取数据之间的延迟Tw添加注释。接下来,您可以开始解码按钮按下数据。



根据所选择的模式,TTP229-BSF可以使用8个或16个触摸按钮。在这种情况下,发送的数据不包含有关微电路工作模式的信息。因此,对于解码器,值得添加一个选项来指定微电路的工作模式。



class Decoder(srd.Decoder):
    ...
    options = (
        {'id': 'key_num', 'desc': 'Key number', 'default': 8,
         'values': (8, 16)},
    )
    def start(self):
        ...
        self.key_num = self.options['key_num']


选择解码器后,此选项可用于在用户界面中设置值。



从时序图中可以看到,当SCL变为有效(低)电平时,SDO线上的数据将暴露出来,而当信号返回至无源电平时将被保存。此时,微控制器和解码器都可以将数据集记录在SDL线上。SCL回到活动层的过渡可以视为下一次数据传输的开始。在这种情况下,解码功能将类似于(ca9a370):



    def decode(self):
        self.wait({0: 'h', 1: 'f'})
        self.dv_block_ss = self.samplenum

        self.wait({0: 'h', 1: 'r'})
        self.put(self.dv_block_ss, self.samplenum,
                 self.out_ann, [0, ['Data valid', 'DV']])
        self.tw_block_ss = self.samplenum

        self.wait([{0: 'f', 1: 'h'}, {0: 'f', 1: 'f'}])
        self.put(self.tw_block_ss, self.samplenum,
                 self.out_ann, [1, ['Tw', 'Tw']])
        self.bt_block_ss = self.samplenum

        for i in range(self.key_num):
            (scl, sdo) = self.wait({0: 'r'})
            sdo = 0 if sdo else 1

            self.wait({0: 'f'})
            self.put(self.bt_block_ss, self.samplenum,
                     self.out_ann, [2, ['Bit: %d' % sdo, '%d' % sdo]])
            self.bt_block_ss = self.samplenum


但是这种放置注释的方法有一个缺点,即最后一位的注释将一直持续到微控制器读取下一个数据为止。







. . , SCL . , SCL 2 ., . 'skip', , , . , . metadata(). Hz.



    def metadata(self, key, value):
        if key == srd.SRD_CONF_SAMPLERATE:
            self.timeout_samples_num = int(2 * (value / 1000.0))


然后,将使用以下形式的skip来编写解码功能中的条件,并附加检查以确保在读取有关所按下按钮的数据期间,微电路未返回其初始状态(6a0422d)。



    def decode(self):
        ...
        for i in range(self.key_num):
            ...
            self.wait([{0: 'f'}, {'skip': self.timeout_samples_num}])
            self.put(self.bt_block_ss, self.samplenum,
                     self.out_ann, [2, ['Bit: %d' % sdo, '%d' % sdo]])
            if (self.matched & 0b10) and i != (self.key_num - 1):
                break


现在,解码器可以处理完整的数据发送。如果除了有关各个位的信息之外,还添加了关于按下哪个按钮的注释,将非常方便。为此,添加更多注释的描述。由于按下按钮的注释涉及整个数据传输,并且与之前添加的注释相交,因此应将其放在单独的组中。让我们为她创建一组新的批注“关键消息”。91c64e6)。



class Decoder(srd.Decoder):
    ...
    annotations = (
        ('dv', 'Data valid'),
        ('tw', 'Tw'),
        ('bit', 'Bit'),
        ('key', 'Key press status'),
    )
    annotation_rows = (
        ('fields', 'Fields', (0, 1, 2)),
        ('keymsg', 'Key message', (3,)),
    )
    def decode(self):
        ...
        keys_pressed = list()

        for i in range(self.key_num):
            ...
        else:
            key_msg = \
                'Key: %s' % (','.join(keys_pressed)) if keys_pressed else 'Key unpressed'
            key_msg_short = \
                'K: %s' % (','.join(keys_pressed)) if keys_pressed else 'KU'

            self.put(self.dv_block_ss, self.samplenum,
                     self.out_ann, [3, [key_msg, key_msg_short]])






到目前为止,所有代码仅适用于第一条消息。您是否已经注意到解码器名称旁边的19%?这是在decode()函数退出之前已处理的样本的百分比。要处理所有样本,仍然需要在代码周围添加一个无限循环,以对单独的数据48f95fb进行解码



    def decode(self):
        ...
        while True:
            self.wait({Pin.SCL: self.passive_signal, Pin.SDO: self.front_edge})
            self.dv_block_ss = self.samplenum
            ...


因为在搜索下一个样本时,如果wait()函数遍历所有解码,解码将自动结束。作为此更改的结果,将按照KDPV中所示处理所有样本和所有数据传输



最后的接触仍然是增加选择活动信号电平的能力,并且已经准备好用于TTP229-BSF的成熟解码器。最终版本的源代码也可以在GitHub上获得




All Articles