from .pd import Decoder
pd.py文件
在bala目录下,建新pd.py文件,用来编写主要的代码。
四、框架代码模板
以下是解码协议代码框架,写在pd.py文件里。所有协议的代码核心部分是一样的。
下面从c模块继承一个类:
import sigrokdecode as srd
class Decoder(srd.Decoder):
api_version = 3
id = 'bala'
name = 'bala'
longname = 'bala protocal'
desc = 'This is an example'
license = 'gplv2+'
inputs = ['logic']
outputs = ['bala']
tags = ['Embedded/industrial']
channels = (
{'id': 'c1', type:0, 'name': 'c1', 'desc': 'chan1-input'},
optional_channels = (
{'id': 'c2', type:0, 'name': 'c2', 'desc': 'chan2-input'},
options = (
{'id': 'debug_bits','desc': 'Print each bit', 'default': 'no', 'values': ('yes', 'no')},
{'id': 'wordsize', 'desc': 'Data wordsize', 'default': 0},
annotations = (
('1', 'data1', 'test1'),
('2', 'data2', 'test2'),
('222', 'data3', 'test3'),
annotation_rows = (
('lab1'
, 'row1', (0,)),
('lab2', 'row2', (1,2)),
def __init__(self):
self.reset()
def reset(self):
self.count = 0
def start(self):
self.out_ann = self.register(srd.OUTPUT_ANN)
def put_ann(self,a,b,ann,data):
self.put(a, b, self.out_ann, [ann, data])
def decode(self):
while True:
(a,b)=self.wait({0:'r'})
self.samplenum
self.matched
到这里,解码协议代码框架模板结束。
五、应用示例
在上面代码框架的基础上,我们接下来实现一个简单的例子。具体是,通过解码某一通道的数据,从一个向上边沿开始到向下边沿结束,输出采样点差值信息。奇数次输出放在第二行,偶数次输出放在第一行。具体编码和说明如下:
def decode(self):
times = 0
rising_sample = 0
flag_arr = [{0:'r'}, {0:'f'}]
flag_dex = 0
while True:
edge = flag_arr[flag_dex]
(a,b) = self.wait(edge)
if flag_dex == 0:
flag_dex = 1
rising_sample = self.samplenum
else:
flag_dex = 0
times += 1
falling_sample = self.samplenum
v = falling_sample - rising_sample
s = '%02X' % v
ann = times % 2
self.put_ann(rising_sample, falling_sample, ann, [s])
六、解码模块工作原理
通过c代码和python代码的互操作,将采样数据交给python分析。经过一系列的处理,最终生成解码结果,用于显示以及供给上层协议作为分析的数据来源。解码模块的核心主要由以下部分组成:
c底层包装类Decoder
在c代码里,给python提供一个经过包装的基类,python可调用基类的一些方法,实现调用c代码的目的。python端通过以下语句导出c代码包装的Decoder类:
import sigrokdecode as srd
python可访问的Decoder基类的方法有:
register方法
用于注册python输出到c底层的消息类型,有:
(1) OUTPUT_ANN,数据输出到屏幕
(2) OUTPUT_PYTHON,数据输出到上层协议
(3) OUTPUT_BINARY
(4) OUTPUT_META
python调用方式:
self.out_ann=self.register(srd.OUTPUT_ANN)
self.out_py=self.register(srd.OUTPUT_PYTHON)
put方法
输出数据到屏幕或上层协议,python调用方式:
self.put(a,b,self.out_ann,[0,['abc']])
其中,a、b为采样点区间值,self.out_ann为注册的消息类型,[0,[‘abc’]], 0为消息类型序号,参考之前的内容;[‘abc’]为消息内容了
wait方法
获得上一次分析位置后的采样数据,可通过参数指定边沿查找条件。
调用方式: self.wait()
可指定参数,如:{0,’r’}表示第1个绑定的通道满足向上边沿的数据;{1,’f’}表示第2个绑定通道足向下边沿的数据。其它条件标志还有:h、l、e、n。
可通过多个条件组成并和或的条件。并条件如:{0:’f’,1:’r’},或条件如:[{0:’f’},{1:’r’}]
has_channel方法
用来叛断某个通道是否绑定,python调用方式:
self.has_channel(0)
0是通道序号。
c底层类给python提供了两个属性:
a. self.samplenum,wait()调用后的采样数据位置;
b. self.matched,wait()调用后道通匹配信息;
python层包装类Decoder
继承至c底层包装的类,由c底层实例化并调用python类的方法,代码如下:
import sigrokdecode as srd
class Decoder(srd.Decoder):
子类Decoder的方法有:
reset方法
这里做一些变量值的重置,以及类的私有变量的定义。变量的定义如:
self.name = 'abc'
start方法
在解码任务开始执行前,c底层代码会调用一次start函数,这里主要是做一些初始化工作,比如注册消息类型,如:
self.out_ann = self.register(srd.OUTPUT_ANN)
self.out_py = self.register(srd.OUTPUT_PYTHON)
decode方法
由c底层调用,在解码任务开始时,c底层启动一个线程,然后在线程里调用decode方法。
在这个函数里,一直循环调用wait函数,不断从c底层读取符合边沿条件的数据,如:
while True:
(a,b) = self.wait()
(a,b)元组里的变量数跟声明的chnnaels里声明的通道数一致,包括可选的通道上。
解码任务执行流程:
(1) 解码任务开始启动;
(2) 上层将采样数据分批推送到底层;
(3) 底层检测并启动一个线程,该线程调用python层的decode函数,不断处理上层推送的数据;
(4) python层经过一系列的计算处理,生成解码结果,通过put函数输出到c底层;
(5) 当所有数据推送完成并经过python层处理,解码任务结束;
七、框架升级更新记录
在DSView版本1.2.0以上,更新以下功能:
end方法
python层的方法,当所有数据处理完成后会被c底层触发
self.last_samplenum属性
c底层提供的属性,其值为所有数据推送完成后最后的数据样位置。当存在end方法时,该属性将被设置
数据多种显示格式
显示的annotation数据部分,可以在2进制、16进制、8进制、10进制、ascii格式间转换。
self.put(s, e, self.out_ann, [1,['%02X' % value])
put函数将数据输出c底层,并在屏幕上显示。其中,value为要显示的数据。在输出到时需要转换为16进制的字符串。当需要让数据支持在多种格式间转换时,代码修改如下:
self.put(s, e, self.out_ann, [1,['@' + '%02X' % value])
它是通过在数据部分前加@符号,告诉c底层这一部分内空是数据部分,如:
'@66FB'
如果存在前缀文字,需要将格式部分和数据部分开,如:
['Data:{$}','D:{$}', '@66FB']
{$}是占位符,系统将数据部分格式化后替换掉占位符,就会变成:Data:66FB