Files
DSView-decoders/sl2-100/pd.py
T

322 lines
16 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
##
## This file is part of the libsigrokdecode project.
##
## Copyright (C) 2015 Benjamin Larsson <benjamin@southpole.se>
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, see <http://www.gnu.org/licenses/>.
##
import sigrokdecode as srd
class SamplerateError(Exception):
pass
class Decoder(srd.Decoder):
api_version = 3
id = 'SL2-100'
name = 'SL2-100'
longname = 'SL2-100'
desc = 'SL2-100振镜协议.'
license = 'gplv2+'
inputs = ['logic']
outputs = []
tags = ['IC', 'RFID']
# 必须要绑定的通道定义,将在界面上可见
# id:通道标识, 任意命名
# type:类型,根据需要设置一个值, -1:COMMON,0:SCLK,1:SDATA,2:ADATA
# name:标签名
# desc:该通道的说明
# 注意元组的最后的逗号不能少
channels = (
{'id': 'data', 'name': 'Data', 'desc': 'Data line'},
)
# 提供给用户通过界面设置的参数,根据业务需要来定义
options = (
# 一个数据周期10us
{'id': 'datatime', 'desc': '数据传输时间(ns)', 'default': 10000},
{'id': 'filename', 'desc': '解码输出文件名','default':'d:/sl2-100.csv'},
{'id': 'invert', 'desc': 'Invert Signal?', 'default': 'no','values': ('yes', 'no'), 'idn':'opt_invert'},
)
# 解析结果项定义
# annotations里的每一项可以有2到3个属性,当有3个属性时,第一个表示类型
# 类型对应0-16个颜色,当类型范围在200-299时,将绘制边沿箭头
annotations = (
('highlow', '电平'),
('bit', '数据位'),
('header', 'Header'),
('xpos', 'x坐标'),
('xpos_value', 'x坐标值'),
('xv', 'x坐标效验'),
('header2', 'header2'),
('ypos', 'y坐标'),
('ypos_value', 'y坐标值'),
('yv', 'y坐标效验'),
)
# 解析结果行定义
annotation_rows = (
# (0,)表示可输出第1个定义的annotations类型
('level', '电平', (0,)),
('bits', '数据位', (1,)),
# (2,3,4,5,6,7)表示可输出第2个到第7个定义的annotations类型
('fields', '字段', (2, 3, 5, 6, 7, 9)),
('xpos', 'x坐标值', (4,)),
('ypos', 'y坐标值', (8,)),
)
# 构造函数,自动被调用
def __init__(self):
self.reset()
# 重置函数,在这里做一些重置和定义类私有变量工作
def reset(self):
self.samplerate = None
self.bit_width = 0 #采样次数,400Mhz时计算出来应该是31.25
self.oldsamplenum = 0.0 #采样起始位置
self.ss_first = 0 #当前数据位起始位置
self.first_one = -1 #当前数据位的首电平
self.header_str = ""
self.head_cnt = 0 #hedaer累积的数据位个数
self.header_first = -1 #header起始位置
self.xpos_cnt = 0 #x坐标累积的数据位个数
self.xpos_first = 0 #x坐标起始位置
self.xv_str = ""
self.xv_cnt = 0 #x坐标校验累积的数据位个数
self.xv_first = 0 #x坐标校验起始位置
self.header2_str = ""
self.head2_cnt = 0 #hedaer2累积的数据位个数
self.header2_first = 0 #header2起始位置
self.ypos_cnt = 0 #y坐标累积的数据位个数
self.ypos_first = 0 #y坐标起始位置
self.yv_str = ""
self.yv_cnt = 0 #y坐标校验累积的数据位个数
self.yv_first = 0 #y坐标校验起始位置
self.state = 'HEADER' #当前处理的字段
self.state2 = 'FIND START' #当前处理的字段
self.data = 0 #存放坐标值数据
self.highpin = 0 #当前采样宽度(78.125ns)内高电平数量
self.lowpin = 0 #当前采样宽度(78.125ns)内低电平数量
self.filename = "d:/sl2-100.csv"
self.file = None
self.x_value = 0
def metadata(self, key, value):
if key == srd.SRD_CONF_SAMPLERATE:
self.samplerate = value
#每个电平采样次数,400Mhz时计算出来应该是31.25 = 0.4 * 78.125 = (采样次数/纳秒 * 持续时长/电平)
self.bit_width = (self.samplerate / (1000*1000*1000)) * (self.options['datatime'] / 128)
self.filename = self.options['filename']
# 开始执行解码任务时,由c底层代码自动调用一次
# 这里,完成一些解码结果项annotation类型的注册
# 类型有: OUTPUT_ANN,OUTPUT_PYTHON,OUTPUT_BINARY,OUTPUT_META
# self.register函数是c底层类提供的
def start(self):
self.out_ann = self.register(srd.OUTPUT_ANN)
#数据位处理函数 bit表示当前数据位1还是0 ss表示当前数据位起始位置 es表示当前数据位结束位置
def putbit(self, bit, ss, es):
#标记当前数据位
self.put(ss, es, self.out_ann,[1, [str(bit)]])
#下面处理每个字段
if self.state == 'HEADER':
#self.file.write(self.state+ '\n')
if(self.head_cnt == 0 and bit == 0):# 如果是第一个数据位且为0,则认为是y坐标数据
self.header2_first=self.header_first
self.header2_str += str(bit)
self.head2_cnt = self.head2_cnt+1
self.state = 'HEADER3'
else:
self.header_str += str(bit)
self.head_cnt = self.head_cnt+1
if self.head_cnt == 6:
self.put(self.header_first, es, self.out_ann,[2, ['HEADER_x:' + self.header_str]])
self.state = 'xpos'
self.xpos_first = es
self.xpos_cnt = 0 #当前坐标 位数归零,准备累积
self.data = 0 #当前坐标值归零,准备开始累积
elif self.state == 'xpos':
#self.file.write(self.state+ '\n')
if self.xpos_cnt == 19:
self.data = ((not bit) << self.xpos_cnt) | self.data
else:
self.data = (bit << self.xpos_cnt) | self.data
self.xpos_cnt = self.xpos_cnt+1
if self.xpos_cnt == 20:
self.put(self.xpos_first, es, self.out_ann,[3, ['X坐标:' + ': 0x%x' % self.data + ' = %d' % self.data]])
self.put(self.xpos_first, es, self.out_ann,[4, ['%d' % self.data]])
self.state = 'xpos_v'
self.xv_first = es
self.xv_cnt = 0
self.xv_str = ""
self.x_value=self.data
elif self.state == 'xpos_v':
self.xv_str += str(bit)
self.xv_cnt = self.xv_cnt+1
if self.xv_cnt == 4:
self.put(self.xv_first, es, self.out_ann,[5, ['X校验:'+ self.xv_str]])
self.state = 'HEADER2'
self.header2_first = es
self.head2_cnt = 0
self.header2_str = ""
elif self.state == 'HEADER2':
self.header2_str += str(bit)
self.head2_cnt = self.head2_cnt+1
if self.head2_cnt == 8:
self.put(self.header2_first, es, self.out_ann,[6, ['HEADER_y:' + self.header2_str]])
self.state = 'ypos'
self.ypos_first = es
self.ypos_cnt = 0 #当前坐标 位数归零,准备累积
self.data = 0 #当前坐标值归零,准备开始累积
self.head2_cnt = 0
elif self.state == 'HEADER3':
#self.file.write(self.state+ '\n')
self.header2_str += str(bit)
self.head2_cnt = self.head2_cnt+1
if self.head2_cnt == 6:
self.put(self.header2_first, es, self.out_ann,[6, ['HEADER_y:' + self.header2_str]])
self.state = 'ypos'
self.ypos_first = es
self.ypos_cnt = 0 #当前坐标 位数归零,准备累积
self.data = 0 #当前坐标值归零,准备开始累积
self.head2_cnt = 0
elif self.state == 'ypos':
if self.ypos_cnt == 19:
self.data = ((not bit) << self.ypos_cnt) | self.data
else:
self.data = (bit << self.ypos_cnt) | self.data
self.ypos_cnt = self.ypos_cnt+1
if self.ypos_cnt == 20:
self.put(self.ypos_first, es, self.out_ann,[7, ['y坐标:' + ': 0x%x' % self.data + ' = %d' % self.data]])
self.put(self.ypos_first, es, self.out_ann,[8, [ '%d' % self.data]])
self.state = 'ypos_v'
self.yv_first = es
self.yv_cnt = 0
self.yv_str = ""
self.file.write( '%d' % self.x_value + ',' + '%d' % self.data + '\n')
elif self.state == 'ypos_v':
self.yv_str += str(bit)
self.yv_cnt = self.yv_cnt+1
if self.yv_cnt == 4:
self.put(self.yv_first, es, self.out_ann,[9, ['y校验:' + self.yv_str]])
self.state = 'HEADER'
self.state2 = 'FIND START'
self.header_first = es
self.head_cnt = 0
self.header_str = ""
#差分曼彻斯特解码函数 pin表示当前电平是高(1)还是低(0)
def manchester_decode(self, ss,es,pin):
#标记电平 高/低
self.put(ss, es, self.out_ann, [0, ['高' if pin==1 else'低']])
#记录HEADER起始位置 第一次需要
if self.header_first == -1:
self.header_first = ss
#下面处理数据位
if self.first_one == -1: #处理数据位的首电平
self.first_one = pin
self.ss_first = ss #记录当前数据首电平起始位置
return
else: #处理数据位的第二电平
if self.first_one != pin: #有跳变 输出1
self.putbit(1, self.ss_first, es)
else: #无跳变 输出0
self.putbit(0, self.ss_first, es)
self.first_one = -1 #重置first_one标志,准备下一数据位的处理
# 解码函数,解码任务开始时由c底层代码调用
# 这里不断循环等待所有采样数据被处理完成
# 下面的示例代码是解析某一通道的数据,从向上边沿开始到向下边沿结束,输出它们的样品位置差值,
# 奇数次显示第二行,偶数次显示在第一行,我们只指定annotations里定义的序号
# 软件会自动根据annotation_rows的设置,决定显示在哪一行
def decode(self):
if not self.samplerate:
raise SamplerateError('Cannot decode without samplerate.')
if self.filename != "":
self.file = open(self.filename,'a')
self.file.write('x坐标,y坐标\n')
# Initialize internal state from the very first sample.
(pin,) = self.wait()
if self.oldsamplenum == 0:
self.oldsamplenum = self.samplenum
self.highpin = 0 #当前采样宽度(78.125ns)内高电平数量
self.lowpin = 0 #当前采样宽度(78.125ns)内低电平数量
#当前电平值是否取反
inv = self.options['invert'] == 'yes'
last_samplenum=0
while True:
if self.state2 == 'FIND START':
#self.file.write(self.state2+ '\n')
if inv:
(pin,) = self.wait({0:'h'})
else:
(pin,) = self.wait({0:'l'})
self.oldsamplenum = self.samplenum
#self.file.write('oldsamplenum= %.1f' % self.oldsamplenum+ '\n')
ss = self.samplenum
self.state2 = 'FIND START2'
if self.state2 == 'FIND START2':
#self.file.write(self.state2+ '\n')
(pin,) = self.wait({0:'e'})
start_width = self.samplenum - self.oldsamplenum
self.oldsamplenum = self.samplenum
#self.file.write('oldsamplenum= %.1f' % self.oldsamplenum+ '\n')
if (start_width >= self.bit_width*2.2) :
self.state2 = 'FIND START3'
else:
self.state2 = 'FIND START'
if self.state2 == 'FIND START3':
#self.file.write(self.state2+ '\n')
(pin,) = self.wait()
#当前已经累积的采样宽度
total_width = self.samplenum - self.oldsamplenum
if total_width>=self.bit_width-1 : #累积采样宽度接近设置的采样次数
self.state2 = 'FIND DATA'
es=self.samplenum
self.put(ss, es, self.out_ann, [0, ['header']])
self.oldsamplenum = self.oldsamplenum+self.bit_width-1
#self.file.write('oldsamplenum= %.1f' % self.oldsamplenum+ '\n')
last_samplenum = self.samplenum
self.highpin = pin #当前采样宽度(78.125ns)内高电平数量
self.lowpin = not pin #当前采样宽度(78.125ns)内低电平数量
if self.state2 == 'FIND DATA':
#self.file.write(self.state2+ '\n')
(pin,) = self.wait()
#当前已经累积的采样宽度
total_width = self.samplenum - self.oldsamplenum
#self.file.write('total_width= %.1f pin= %d' % (total_width, pin)+ '\n')
if pin==1:
self.highpin += 1 #当前采样宽度内高电平数量加1
else:
self.lowpin += 1 #当前采样宽度内低电平数量加1
if total_width>=self.bit_width : #累积采样宽度接近设置的采样次数
self.oldsamplenum = self.oldsamplenum+self.bit_width #当前采样结束作为下一采样的开始
#self.file.write('oldsamplenum= %.1f' % self.oldsamplenum+ '\n')
#当前电平起始位置
ss = last_samplenum
#当前电平结束位置
es = self.samplenum
last_samplenum= self.samplenum
self.manchester_decode(ss, es, 1 if self.highpin > 2 else 0)
self.highpin = pin #当前采样宽度(78.125ns)内高电平数量
self.lowpin = not pin #当前采样宽度(78.125ns)内低电平数量
# self.wait()可带参数,也可以不带参数,不带参数时将返回每个采样数据
# 参数{0:'r'}, 0表示匹配channels第1项绑定的通道,'r'表示查找向上边沿
# wait函数可传多个条件,与条件:{0:'f',1:'r'}, 或条件:[{0:'f'},{1:'r'}]
# h:高电平,l:低电平,r:向上边沿,f:向下边沿,e:向上沿或向下沿, n:要么0,要么1
# wait函数前的变量(a,b),对应的数量由定义的channels里的通道数决定,包括可选通道
# optional_channels 。例如:channels和optional_channels共定义了4个通道,
# 则变成(a,b,c,d) = self.wait(),共四个变量
# 底层模块提供的属性:
# 1. self.samplenum 当前wait()调用匹配结束的采样点位置
# 2. self.matched 本次调用wait()后所有通道的匹配结果信息,是一个uint64类型数值,
# 表示0到63个通道的匹配信息,通过位运算来获取具体�