DSlogic协议开发笔记
参考资料:smiley:
名词解析
- Protocol Decoders (PDs)
协议解码器
- libsigrokdecode
是一个采用C语言编写的共享库,提供了数据流协议解码功能。该协议解码器采用Python(= 3.0)编写。
Decoder class functions
必须的函数
- start(self)
这个函数在解码开始之前被调用。这里可以 [register()](#Decoder registration) 输出类型,检查用户提供的PD选项的有效性,等等。
- decode(self) (解码)
在 non-stacked 解码器中,这个函数由libsigrokdecode后端调用以开始解码。它不接受任何参数,而是进入一个无限循环,并通过调用更通用的wait()方法获取样本。这使得特定的协议解码器从繁琐但常见的任务中解放出来,比如检测边缘,或者在相对于当前位置的特定时间点采样信号。
注意:这个decode(self)方法的签名已经在协议解码器API的第三版中引入,在以前的版本中只有decode(self、startsample、endsample、data)是可用的。
- decode(self, startsample, endsample, data)
…
可选的函数
- metadata(self, key, value)( 元数据 )
用于传递关于数据流的解码器元数据。目前 key
的唯一值是sigrokdecode.SRD_CONF_SAMPLERATE, value
则为数据流的采样率(samplerate),单位为Hz。
Decoder registration
解码器类必须包含几个指定PD元数据的属性。可以使用以下关键字:
Key | Description |
---|---|
api_version | 这个模块使用的libsigrokdecode API版本。现在不是2就是3。 |
id | 此协议解码器的简短唯一标识符。它应该是全小写的,只包含a-z, 0-9和下划线。这必须匹配PD的Python模块名(decoders目录中的子目录名)。siglock -cli工具使用它在命令行上指定PDs。例如:’jtag’, ‘sdcard_spi’, ‘uart’。 |
name | 解码器的名称。当列出可用的PDs时使用。例如:“JTAG”,“SD卡(SPI模式)”,“UART”。 |
longname | 译码器的(长)名。当列出可用的PDs时使用。Example: ‘Joint Test Action Group (IEEE 1149.1)’, ‘Secure Digital card (SPI mode)’, ‘Universal Asynchronous Receiver/Transmitter(UART)’ |
desc | 解码器的自由的一行描述。当列出可用的PDs时使用。应该以句号结束。Example: ‘Protocol for testing, debugging, and flashing ICs.’, ‘Secure Digital card (SPI mode) low-level protocol.’, ‘Asynchronous, serial bus.’. |
license | 提供模块的许可证。这必须是gplv2+(即GNU通用公共许可证2或更高版本),或者gplv3+ (GNU通用公共许可证3或更高版本)。libsigrokdecode中不允许为模块提供其他许可证。 |
inputs | 此解码器需要的输入类型列表。如果解码器从逻辑分析器驱动程序获取输入,则应将其设置为logic,该逻辑将映射到数据籽类型SR_DF_LOGIC。如果它从另一个PD获取输入,则应该将其设置为该PD的输出键的值。它应该符合与id键相同的规则(小写,没有空格,等等)。 |
outputs | 此解码器产生的输出类型列表。如果这个解码器能够将解码后的数据反馈到数据流中,那么它的输出将被标识为该密钥的值。它应该与id键遵循相同的规则。 |
channels | 该密钥包含有关必须提供给该PD的通道(pin)的信息;没有他们,PD将无法工作。例如,SPI解码器必须知道哪个信道有时钟信号。该键包含一个通道条目的元组,其中每个条目都是一个Python dict,其键为id、name和desc。Example: {'id': 'rx', 'name': 'RX', 'desc': 'UART receive line'} . |
optional_channels | PD可选的通道,但不是必须的。该键的格式与上面的通道键相同(dicts的元组)。如果相应的协议解码器没有可选通道,则允许该元组为空。 |
options | 描述此解码器的选项的元组。每个元组条目都是一个Python dict,其键id、desc、缺省值和值。如果PD没有可选的通道,则此元组可以为空。Example: {'id': 'bitorder', 'desc': 'Bit order', 'default': 'msb-first', 'values': ('msb-first', 'lsb-first')} . |
annotations | 此协议解码器可以输出的注释类的列表。此列表的元素是由标识符字符串和可读的描述字符串组成的元组。标识符字符串可以在siglock -cli选项中用于选择特定的注释类型,因此不应该包含空白或特殊字符。 |
annotation_rows | 注释行用于将多个注释类型分组在一起。这个列表的元素是三个元素元组,包括: 1.注释行ID(与其他ID的命名规则相同)。2.注释行的人类可读的名称/描述字符串。3. 包含注释元组中注释类的索引的元组。示例参考 |
binary | 此协议解码器可以输出的二进制输出类型列表,格式与**annotations **列表相同。 |
self.put( )
原型
put(startsample, endsample, output_id, data)
参数
startsample:开始的序号
endsample:结束的序号
output_id:取值看下表
data:根据output_id的不同数据也不同
output_id | funcation |
---|---|
OUTPUT_ANN | 注释信息 |
OUTPUT_PYTHON | |
OUTPUT_BINARY | |
OUTPUT_META |
- OUTPUT_ANN:
这个东西在显示bit数据时会在信号上有小点点指示。
不同缩放级别显示不同内容
Example:self.put(10, 20, self.out_ann, [4, ['Start', 'St', 'S']])
data参数是一个包含两个项的Python列表。第一项是注释索引(由解码器中项的顺序决定)。第二个是注释字符串列表。字符串应该是相同注释文本的长版本和短版本(按长度排序,最长优先),可以由前端根据缩放级别显示不同的注释文本。
- OUTPUT_PYTHON :
输出特定格式的数据么?( 数据内容本身完全依赖于各自的解码器,应该在其pd.py文件中记录。 )
Example:
self.put(10, 20, self.out_python, ['PACKET', ['Foo', 19.7, [1, 2, 3], ('bar', 'baz')]])
数据参数是将传递给堆叠解码器的任意Python对象。格式和内容完全依赖于解码器。通常,包含各种内容的Python列表被传递给堆叠的PDs。
OUTPUT_BINARY:
输出数据0x55 0xaa等等( 二进制格式的索引为4,发出的字节分别为0xfe、0x55、0xaa)
Example:
self.put(10, 20, self.out_binary, [4, b'\xfe\x55\xaa'])
data参数是一个包含两个项的Python列表。第一项是二进制格式的索引(由解码器中项的顺序决定)。第二个是Python bytes对象。
OUTPUT_META :
输出解码出来的数字( 在本例中数据本身是一个浮点数)
Example:
self.put(10, 20, self.out_meta, 15.7)
数据参数是特定类型的Python对象,在各自的register()函数中定义
self.wait()
这是协议解码器用来将查询发送到libsigrokdecode后端的API调用。
从PD的角度来看,这是一个阻塞呼叫。它将阻塞,直到在样本数据中找到指定的条件,然后才将控制权返回给PD。
原型
1 |
|
参数
空参
如果完全不提供conds,或者它是一个空列表[],或者它只是一个“空”条件{},那么后端将直接跳到下一个示例。 (相当于直接进入下一个样本)
Examples:
1 |
|
conds 引脚状态条件(上下沿)
Value | Describe |
---|---|
‘l’ | Low pin value (logical 0) |
‘h’ | High pin value (logical 1) |
‘r’ | Rising edge |
‘f’ | Falling edge |
‘e’ | Either edge (rising or falling) |
‘s’ | 稳定状态 Stable state, the opposite of ‘e’. That is, there was no edge and the current and previous pin value were both low (or both high). |
other | 任何其他值都会产生错误。 |
Examples:
1 |
|
conds 样品跳过条(样本数量)
后端另一个常见的查询是,当解码器想要跳过一定数量的样本时,而不管样本值是什么(因为它们与当前的协议无关)。
这可以通过条件dict中的一个特殊键来实现— ‘skip’ 。 ‘skip’ 键的值是要跳过的样本的整数。
解码器也可以跳过一定的时间,通过使用采样来计算 ‘skip’ 键的正确值。
Examples:
1 |
|
注意
1 |
|
self.skip()
这个函数不知道怎么回事,用了会报错
注意这下面的skip不是wait
在相同的条件下混合通道索引键和“跳过”键通常没有多大意义,然而,在不同的情况下,混合索引键和“跳过”键是非常合理的:
(下面的语句应该是 ((pin7 e)和(pin12 l))或(skip 10000)
)
1 |
|
self.matched
当解码器通过self.wait()请求前端等待多个条件时,当该调用返回时,PD仅知道至少一个条件已匹配。但是,在大多数情况下,它还需要知道哪些条件匹配(或不匹配)。
这是self.matched提供的信息。它是布尔值(True或False)的元组,始终包含与上次self.wait()调用中存在的条件一样多的条目。对于每个条件,各自的布尔值表示此特定条件是否匹配。
Example:
1 |
|
对于’skip’键/值对self。如果达到指定数目的样本,则匹配的tuple将包含一个真值。
Example:
1 |
|
self.samplenum
self.samplenum 相当于一个指针,指示当前解码器解码的样本的位置
self.samplenum是一个特殊属性,对于协议解码器来说是只读的,并且只能由libsigrokdecode后端设置。
self.samplenum 总是在最后一次self.wait()调用返回后的当前绝对样本号(从0开始)。
self.samplerate
采样率
self.has_channel
1 |
|
self.has_channel返回的值似乎是对应通道的值,比如这里返回的应该是3.
一些奇怪的问题
1 |
|
注意到pin_state = self.wait( [{0: 'r'}, {'skip': self.freq_half_samp }] )
语句,把pin_state删掉就可以正常运行,若没删if后面的self.wait就会一直出问题。
- 原因应该是pin_state没打括号,pin_state变成了元组,所以出现这种情况
附录
一些快速处理数据的方法
- 快速计算奇偶校验
1 |
|
- BCD转成整数
1 |
|
- 一种将总线引脚序列转换为数字值的好方法:
1 |
|
- 根据协议命令构造方法名的一个好方法是(假设cmd是8,这将调用self.handle_cmd_0x08函数):
1 |
|
- 一种处理Python缺少枚举类型(对状态、pin索引、注释索引等有用)的方法
1 |
|