Compare commits

...
25 Commits
Author SHA1 Message Date
chenyue f51ee5ad9e 增加署名信息 2026-08-16 01:38:18 +08:00
chenyue 4eac2e84e4 描述中增加署名信息 2026-08-16 01:37:27 +08:00
chenyue a7b3539cde 虽然按文档,反馈数据应该上升沿采样,但是实际上发现下降沿采样更准确. 2026-08-16 01:32:49 +08:00
chenyue 4b4100f520 完成初版xy2-100-E解析 2026-08-16 01:24:18 +08:00
chenyue b43dab1fee 改为覆盖文件 2026-08-03 11:31:04 +08:00
chenyue ffbe4291d7 支持路径为空时不输出 2026-07-30 20:07:56 +08:00
chenyue 894d4e2e22 在江磊的基础上增加文本输出 2026-07-30 20:04:11 +08:00
chenyue 7d4c7628d9 增加一个脚本可以读取csv文件并转发到UDP中 2026-07-30 15:22:00 +08:00
chenyue 83cb665bc8 微调采样位置,使结果正确. 2026-07-09 21:33:54 +08:00
chenyue ed561b6b1c 增加信号取反功能 2026-07-09 17:25:53 +08:00
chenyue 628dc87c94 修正y在前时导出文件错误的问题 2026-07-08 19:04:40 +08:00
chenyue 07f85682ca 修正x,y顺序错误的情况 2026-07-08 19:00:03 +08:00
chenyue 5fe99d20e5 修正位置最高位值要取反 2026-07-08 18:16:27 +08:00
chenyue 2df599dc14 更新sl2-100的实现,修正文本导出,将x,y坐标单独显示在不同的行. 2026-07-08 15:45:47 +08:00
chenyue deeacd2270 增加sl2-100协议解析 2026-07-08 14:53:24 +08:00
chenyue 03f71f35b2 增加说明文档 2026-06-18 11:01:14 +08:00
chenyue d7040f1029 合并xy2-100 2026-06-18 10:57:36 +08:00
chenyue 1c81c2e075 增加counter,和parallel解码器 2026-06-18 10:45:25 +08:00
chenyue 51dd512ff8 分离数据到不同的行 2026-06-17 21:56:35 +08:00
chenyue 051bbaeb5f 增加数据类型转换 2026-06-17 21:48:32 +08:00
chenyue 62b37bb2d9 能显示数值 2026-06-17 21:42:37 +08:00
chenyue 45d1e8d0ef 首次能正常解析 2026-06-17 21:16:46 +08:00
chenyue 7012873c90 初版可以用,但是最后一个位解析有问题。 2026-06-17 09:38:19 +08:00
chenyue 7ff53f177d 修正bug 2026-04-23 22:52:08 +08:00
chenyue 1f140e9b0b 增加一路数据解析 2026-04-23 22:08:20 +08:00
21 changed files with 1959 additions and 7 deletions
+25
View File
@@ -0,0 +1,25 @@
##
## This file is part of the libsigrokdecode project.
##
## Copyright (C) 2012 Uwe Hermann <uwe@hermann-uwe.de>
##
## 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/>.
##
'''
I²C (Inter-Integrated Circuit) is a bidirectional, multi-master
bus using two signals (SCL = serial clock line, SDA = serial data line).
'''
from .pd import Decoder
Binary file not shown.
Binary file not shown.
+222
View File
@@ -0,0 +1,222 @@
##
## This file is part of the libsigrokdecode project.
##
## Copyright (C) 2010-2016 Uwe Hermann <uwe@hermann-uwe.de>
## Copyright (C) 2019 DreamSourceLab <support@dreamsourcelab.com>
##
## 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/>.
##
# BiSS-C decoder (default): MSB-first, sample on SCL rising edge.
# Frame: 25 data bits + 6 CRC (CRC-6, polynomial x^6 + x^1 + x^0 (0x43) commonly used in BiSS)
import sigrokdecode as srd
'''
OUTPUT_PYTHON format:
Packet:
[<ptype>, <pdata>]
<ptype>:
- 'START' (START condition)
- 'START REPEAT' (Repeated START condition)
- 'ADDRESS READ' (Slave address, read)
- 'ADDRESS WRITE' (Slave address, write)
- 'DATA READ' (Data, read)
- 'DATA WRITE' (Data, write)
- 'STOP' (STOP condition)
- 'ACK' (ACK bit)
- 'NACK' (NACK bit)
- 'BITS' (<pdata>: list of data/address bits and their ss/es numbers)
<pdata> is the data or address byte associated with the 'ADDRESS*' and 'DATA*'
command. Slave addresses do not include bit 0 (the READ/WRITE indication bit).
For example, a slave address field could be 0x51 (instead of 0xa2).
For 'START', 'START REPEAT', 'STOP', 'ACK', and 'NACK' <pdata> is None.
'''
# CMD: [annotation-type-index, long annotation, short annotation]
proto = {
'BIT': [0, 'Bit', 'B'],
'START': [1, 'Start', 'S'],
'ASC': [2, 'arc start cds', 'ARC'],
'P': [3, 'P', 'P'],
'S': [4, 'S', 'S'],
'ERR': [5, 'err', 'err'],
'CRC': [6, 'CRC', 'CRC'],
'STOP': [7, 'Stop', 'P'],
}
class Decoder(srd.Decoder):
api_version = 3
id = '1:biss'
name = '1:BiSS'
longname = 'BiSS-C Encoder/Decoder'
desc = 'BiSS-C position sensor serial protocol (default decoding)'
license = 'gplv2+'
inputs = ['logic']
outputs = ['biss']
tags = ['Embedded/industrial']
channels = (
{'id': 'scl', 'type': 8, 'name': 'SCL', 'desc': 'Clock', 'idn':'dec_1biss_chan_scl'},
{'id': 'sda', 'type': 108, 'name': 'SDA', 'desc': 'Serial data line', 'idn':'dec_1i2c_chan_sda'},
)
annotations = (
('208', 'bit', 'Data/address bit'),
('207', 'start', 'Start condition'),
('6', 'asc', 'arc start cds'),
('5', 'data1', 'p'),
('0', 'data2', 's'),
('112', 'error', 'Address read'),
('111', 'crc', 'Address write'),
('201', 'stop', 'Stop condition'),
('202', 'value', 'value'),
('203', 'value1', 'value2'),
)
annotation_rows = (
('bits', 'Bits', (0,)),
('p', 'p', ( 8,)),
('s', 's', ( 9,)),
('flag', 'Flag', ( 1, 2,3,4,5, 6, 7)),
)
binary = (
('address-read', 'Address read'),
('address-write', 'Address write'),
('data-read', 'Data read'),
('data-write', 'Data write'),
)
def __init__(self):
self.reset()
def reset(self):
self.samplerate = None
self.ss = self.es = self.ss_byte = -1
self.bitcount = 0
self.databyte = 0
self.state = 'FIND START'
self.pdu_start = None
self.pdu_bits = 0
self.bits = []
def start(self):
self.out_python = self.register(srd.OUTPUT_PYTHON)
self.out_ann = self.register(srd.OUTPUT_ANN)
self.out_binary = self.register(srd.OUTPUT_BINARY)
self.out_bitrate = self.register(srd.OUTPUT_META,
meta=(int, 'Bitrate', 'Bitrate from Start bit to Stop bit'))
def putx(self, data):
self.put(self.ss, self.es, self.out_ann, data)
def putp(self, data):
self.put(self.ss, self.es, self.out_python, data)
def putb(self, data):
self.put(self.ss, self.es, self.out_binary, data)
def handle_start(self):
self.ss, self.es = self.samplenum, self.samplenum
self.pdu_start = self.samplenum
cmd = 'START'
self.putp([cmd, None])
self.putx([proto[cmd][0], proto[cmd][1:]])
self.state = 'FIND DATA'
self.bitcount = self.databyte = 0
self.bits = []
def handle_stop(self):
cmd = 'STOP'
self.ss, self.es = self.samplenum, self.samplenum
self.putp([cmd, None])
self.putx([proto[cmd][0], proto[cmd][1:]])
self.state = 'FIND START'
self.bits = []
# Gather 8 bits of data plus the ACK/NACK bit.
def handle_data(self, scl, sda,cmd,size,next_state,num):
# 记录数据值
self.databyte <<= 1
self.databyte |= sda
# 记录数据的起始位置
if self.bitcount == 0:
self.ss_byte = self.samplenum
# Store individual bits and their start/end samplenumbers.
# In the list, index 0 represents the LSB (I2C transmits MSB-first).
self.bits.insert(0, [sda, self.samplenum, self.samplenum])
self.bitcount += 1
if self.bitcount == 2:
self.bitwidth = self.bits[0][2] - self.bits[1][2]
if self.bitcount > 1:
self.bits[1][2] = self.samplenum
if self.bitcount == size:
self.bits[0][2] += self.bitwidth
# Return if we haven't collected all 8 + 1 bits, yet.
if self.bitcount < size:
return
d = self.databyte
self.ss, self.es = self.ss_byte, self.samplenum + self.bitwidth
# self.putp(['BITS', self.bits])
# self.putp([cmd, d])
# self.putb([bin_class, d])
for bit in self.bits:
self.put(bit[1], bit[2], self.out_ann, [0, ['%d' % bit[0]]])
self.put(self.ss, self.es, self.out_ann, [num, ['{$}', d]])
self.putx([proto[cmd][0], proto[cmd][1:]])
# Done with this packet.
self.bitcount = self.databyte = 0
self.bits = []
self.state = next_state
def decode(self):
while True:
# State machine.
if self.state == 'FIND START':
self.wait({0: 'h', 1: 'f'})
self.handle_start()
elif self.state == 'FIND DATA':
(scl, sda) = self.wait([{0: 'f'}])
self.handle_data(scl, sda,'ASC',3,'FIND DATA1',1)
elif self.state == 'FIND DATA1':
(scl, sda) = self.wait([{0: 'f'}])
self.handle_data(scl, sda,'P',13,'FIND DATA2',8)
elif self.state == 'FIND DATA2':
(scl, sda) = self.wait([{0: 'f'}])
self.handle_data(scl, sda,'S',13,'FIND ERR',9)
elif self.state == 'FIND ERR':
(scl, sda) = self.wait([{0: 'f'}])
self.handle_data(scl, sda,'ERR',2,'FIND CRC',1)
elif self.state == 'FIND CRC':
(scl, sda) = self.wait([{0: 'f'}])
self.handle_data(scl, sda,'CRC',6,'FIND STOP',1)
elif self.state == 'FIND STOP':
(scl, sda) = self.wait([{0: 'h', 1: 'r'}])
self.handle_stop()
+28
View File
@@ -0,0 +1,28 @@
##
## This file is part of the libsigrokdecode project.
##
## Copyright (C) 2018 Stefan Brüns <stefan.bruens@rwth-aachen.de>
##
## 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/>.
##
'''
This decoder is a simple edge counter.
It can count rising and/or falling edges, provides an optional reset
signal. It can also divide the count to e.g. count the number of
fixed-length words (where a word corresponds to e.g. 9 clock edges).
'''
from .pd import Decoder
Binary file not shown.
Binary file not shown.
+145
View File
@@ -0,0 +1,145 @@
##
## This file is part of the libsigrokdecode project.
##
## Copyright (C) 2018 Stefan Brüns <stefan.bruens@rwth-aachen.de>
##
## 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
PIN_DATA, PIN_RESET = range(2)
ROW_EDGE, ROW_WORD, ROW_RESET = range(3)
class Decoder(srd.Decoder):
api_version = 3
id = 'counter'
name = 'Counter'
longname = 'Edge counter'
desc = 'Count the number of edges in a signal.'
license = 'gplv2+'
inputs = ['logic']
outputs = []
tags = ['Util']
channels = (
{'id': 'data', 'name': 'Data', 'desc': 'Data line', 'idn':'dec_counter_chan_data'},
)
optional_channels = (
{'id': 'reset', 'name': 'Reset', 'desc': 'Reset line', 'idn':'dec_counter_opt_chan_reset'},
)
annotations = (
('edge_count', 'Edge count'),
('word_count', 'Word count'),
('word_reset', 'Word reset'),
)
annotation_rows = (
('edge_counts', 'Edges', (ROW_EDGE,)),
('word_counts', 'Words', (ROW_WORD,)),
('word_resets', 'Word resets', (ROW_RESET,)),
)
options = (
{'id': 'data_edge', 'desc': 'Edges to count (data)', 'default': 'any',
'values': ('any', 'rising', 'falling'), 'idn':'dec_counter_opt_data_edge'},
{'id': 'divider', 'desc': 'Count divider (word width)', 'default': 0, 'idn':'dec_counter_opt_divider'},
{'id': 'reset_edge', 'desc': 'Edge which clears counters (reset)',
'default': 'falling', 'values': ('rising', 'falling'), 'idn':'dec_counter_opt_reset_edge'},
{'id': 'edge_off', 'desc': 'Edge counter value after start/reset', 'default': 0, 'idn':'dec_counter_opt_edge_off'},
{'id': 'word_off', 'desc': 'Word counter value after start/reset', 'default': 0, 'idn':'dec_counter_opt_word_off'},
{'id': 'dead_cycles', 'desc': 'Ignore this many edges after reset', 'default': 0, 'idn':'dec_counter_opt_dead_cycles'},
{'id': 'start_with_reset', 'desc': 'Assume decode starts with reset',
'default': 'no', 'values': ('no', 'yes'), 'idn':'dec_counter_opt_start_with_reset'},
)
def __init__(self):
self.reset()
def reset(self):
pass
def metadata(self, key, value):
if key == srd.SRD_CONF_SAMPLERATE:
self.samplerate = value
def start(self):
self.out_ann = self.register(srd.OUTPUT_ANN)
def putc(self, cls, ss, annlist):
self.put(ss, self.samplenum, self.out_ann, [cls, annlist])
def decode(self):
opt_edge_map = {'rising': 'r', 'falling': 'f', 'any': 'e'}
data_edge = self.options['data_edge']
divider = self.options['divider']
if divider < 0:
divider = 0
reset_edge = self.options['reset_edge']
condition = [{PIN_DATA: opt_edge_map[data_edge]}]
have_reset = self.has_channel(PIN_RESET)
if have_reset:
cond_reset = len(condition)
condition.append({PIN_RESET: opt_edge_map[reset_edge]})
edge_count = int(self.options['edge_off'])
edge_start = None
word_count = int(self.options['word_off'])
word_start = None
if self.options['start_with_reset'] == 'yes':
dead_count = int(self.options['dead_cycles'])
else:
dead_count = 0
while True:
self.wait(condition)
now = self.samplenum
if have_reset and (self.matched & (0b1 <<cond_reset)):
edge_count = int(self.options['edge_off'])
edge_start = now
word_count = int(self.options['word_off'])
word_start = now
self.putc(ROW_RESET, now, ['Word reset', 'Reset', 'Rst', 'R'])
dead_count = int(self.options['dead_cycles'])
continue
if dead_count:
dead_count -= 1
edge_start = now
word_start = now
continue
# Implementation note: In the absence of a RESET condition
# before the first data edge, any arbitrary choice of where
# to start the annotation is valid. One may choose to emit a
# narrow annotation (where ss=es), or assume that the cycle
# which corresponds to the counter value started at sample
# number 0. We decided to go with the latter here, to avoid
# narrow annotations (see bug #1210). None of this matters in
# the presence of a RESET condition in the input stream.
if edge_start is None:
edge_start = 0
if word_start is None:
word_start = 0
edge_count += 1
self.putc(ROW_EDGE, edge_start, ["{:d}".format(edge_count)])
edge_start = now
word_edge_count = edge_count - int(self.options['edge_off'])
if divider and (word_edge_count % divider) == 0:
word_count += 1
self.putc(ROW_WORD, word_start, ["{:d}".format(word_count)])
word_start = now
+34
View File
@@ -0,0 +1,34 @@
##
## This file is part of the libsigrokdecode project.
##
## Copyright (C) 2013 Uwe Hermann <uwe@hermann-uwe.de>
##
## 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/>.
##
'''
This protocol decoder can decode synchronous parallel buses with various
number of data bits/channels and one (optional) clock line.
If no clock line is supplied, the decoder works slightly differently in
that it interprets every transition on any of the supplied data channels
like there had been a clock transition.
It is required to use the lowest data channels, and use consecutive ones.
For example, for a 4-bit sync parallel bus, channels D0/D1/D2/D3 (and CLK)
should be used. Using combinations like D7/D12/D3/D15 is not supported.
For an 8-bit bus you should use D0-D7, for a 16-bit bus use D0-D15 and so on.
'''
from .pd import Decoder
Binary file not shown.
Binary file not shown.
+260
View File
@@ -0,0 +1,260 @@
##
## This file is part of the libsigrokdecode project.
##
## Copyright (C) 2013-2016 Uwe Hermann <uwe@hermann-uwe.de>
##
## 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
from common.srdhelper import bitpack
'''
OUTPUT_PYTHON format:
Packet:
[<ptype>, <pdata>]
<ptype>, <pdata>
- 'ITEM', [<item>, <itembitsize>]
- 'WORD', [<word>, <wordbitsize>, <worditemcount>]
<item>:
- A single item (a number). It can be of arbitrary size. The max. number
of bits in this item is specified in <itembitsize>.
<itembitsize>:
- The size of an item (in bits). For a 4-bit parallel bus this is 4,
for a 16-bit parallel bus this is 16, and so on.
<word>:
- A single word (a number). It can be of arbitrary size. The max. number
of bits in this word is specified in <wordbitsize>. The (exact) number
of items in this word is specified in <worditemcount>.
<wordbitsize>:
- The size of a word (in bits). For a 2-item word with 8-bit items
<wordbitsize> is 16, for a 3-item word with 4-bit items <wordbitsize>
is 12, and so on.
<worditemcount>:
- The size of a word (in number of items). For a 4-item word (no matter
how many bits each item consists of) <worditemcount> is 4, for a 7-item
word <worditemcount> is 7, and so on.
'''
def channel_list(num_channels):
l = [{'id': 'clk', 'name': 'CLK', 'desc': 'Clock line'}]
for i in range(num_channels):
d = {'id': 'd%d' % i, 'name': 'D%d' % i, 'desc': 'Data line %d' % i}
l.append(d)
return tuple(l)
class ChannelError(Exception):
pass
NUM_CHANNELS = 32
class Decoder(srd.Decoder):
api_version = 3
id = 'parallel'
name = 'Parallel'
longname = 'Parallel sync bus'
desc = 'Generic parallel synchronous bus.'
license = 'gplv2+'
inputs = ['logic']
outputs = ['parallel']
tags = ['Util']
optional_channels = channel_list(NUM_CHANNELS)
options = (
{'id': 'clock_edge', 'desc': 'Clock edge to sample on',
'default': 'rising', 'values': ('rising', 'falling'), 'idn':'dec_parallel_opt_clock_edge'},
{'id': 'wordsize', 'desc': 'Data wordsize (# bus cycles)',
'default': 0, 'idn':'dec_parallel_opt_wordsize'},
{'id': 'endianness', 'desc': 'Data endianness',
'default': 'little', 'values': ('little', 'big'), 'idn':'dec_parallel_opt_endianness'},
)
annotations = (
('items', 'Items'),
('words', 'Words'),
)
annotation_rows = (
('items', 'Items', (0,)),
('words', 'Words', (1,)),
)
def __init__(self):
self.reset()
def reset(self):
self.items = []
self.saved_item = None
self.saved_word = None
self.ss_word = self.es_word = None
self.first = True
self.have_clock = True
self.prv_dex = 0
self.num_item_bits = None
def start(self):
self.out_python = self.register(srd.OUTPUT_PYTHON)
self.out_ann = self.register(srd.OUTPUT_ANN)
def putpw(self, data):
self.put(self.ss_word, self.es_word, self.out_python, data)
def putw(self, data):
self.put(self.ss_word, self.es_word, self.out_ann, data)
def put_ann(self, s, e, data):
self.put(s, e, self.out_ann, data)
def put_py(self, s, e, data):
self.put(s, e, self.out_python, data)
def handle_bits(self, item):
# If a word was previously accumulated, then emit its annotation
# now after its end samplenumber became available.
cur_dex = self.samplenum
# Defer annotations for individual items until the next sample
# is taken, and the previous sample's end samplenumber has
# become available.
if self.first:
# Save the start sample and item for later (no output yet).
if not self.have_clock:
self.put_py(self.prv_dex, cur_dex, ['ITEM', self.saved_item])
self.put_ann(self.prv_dex, cur_dex, [0, [self.fmt_item.format(self.saved_item)]])
self.first = False
self.saved_item = item
else:
# Output the saved item (from the last CLK edge to the current).
self.put_py(self.prv_dex, cur_dex, ['ITEM', self.saved_item])
self.put_ann(self.prv_dex, cur_dex, [0, [self.fmt_item.format(self.saved_item)]])
self.saved_item = item
self.prv_dex = cur_dex
self.handel_word(item, cur_dex)
#word
def handel_word(self, item, cur_dex):
if self.saved_word is not None:
if self.options['wordsize'] > 0:
self.es_word = cur_dex
self.putw([1, [self.fmt_word.format(self.saved_word)]])
self.putpw(['WORD', self.saved_word])
self.saved_word = None
if item is None:
return
# Get as many items as the configured wordsize specifies.
if not self.items:
self.ss_word = cur_dex
self.items.append(item)
ws = self.options['wordsize']
if len(self.items) < ws:
return
# Collect words and prepare annotation details, but defer emission
# until the end samplenumber becomes available.
endian = self.options['endianness']
if endian == 'big':
self.items.reverse()
word = sum([self.items[i] << (i * self.num_item_bits) for i in range(ws)])
self.saved_word = word
self.items = []
def end(self):
cur_dex = self.last_samplenum
#the last annotation
if self.saved_item != None:
self.put_py(self.prv_dex, cur_dex, ['ITEM', self.saved_item])
self.put_ann(self.prv_dex, cur_dex, [0, [self.fmt_item.format(self.saved_item)]])
self.handel_word(None, cur_dex)
def decode(self):
# Determine which (optional) channels have input data. Insist in
# a non-empty input data set. Cope with sparse connection maps.
# Store enough state to later "compress" sampled input data.
max_possible = len(self.optional_channels)
idx_channels = [
idx if self.has_channel(idx) else None
for idx in range(max_possible)
]
has_channels = [idx for idx in idx_channels if idx is not None]
if not has_channels:
raise ChannelError('At least one channel has to be supplied.')
max_connected = max(has_channels)
self.have_clock = self.has_channel(0)
self.prv_dex = self.samplenum
have_clock = self.have_clock
# Determine .wait() conditions, depending on the presence of a
# clock signal. Either inspect samples on the configured edge of
# the clock, or inspect samples upon ANY edge of ANY of the pins
# which provide input data.
if have_clock:
edge = self.options['clock_edge'][0]
conds = {0: edge} #'f' or 'r'
else:
conds = [{idx: 'e'} for idx in has_channels]
# Pre-determine which input data to strip off, the width of
# individual items and multiplexed words, as well as format
# strings here. This simplifies call sites which run in tight
# loops later.
idx_strip = max_connected + 1
num_item_bits = idx_strip - 1
num_word_items = self.options['wordsize']
num_word_bits = num_item_bits * num_word_items
num_digits = (num_item_bits + 3) // 4
self.fmt_item = "@{{:0{}X}}".format(num_digits)
num_digits = (num_word_bits + 3) // 4
self.fmt_word = "@{{:0{}X}}".format(num_digits)
self.num_item_bits = num_item_bits
# Keep processing the input stream. Assume "always zero" for
# not-connected input lines. Pass data bits (all inputs except
# clock) to the handle_bits() method.
is_first = True
the_conds = conds
while True:
if not have_clock and is_first:
#get the value at sample 0
conds = None
else:
conds = the_conds
(clk, d0, d1, d2, d3, d4, d5, d6, d7,d8, d9,d10 ,d11 ,d12 ,d13 ,d14 ,d15 ,d16 ,d17 ,d18 ,d19 ,d20 ,d21 ,d22 ,d23 ,d24 ,d25 ,d26 ,d27 ,d28 ,d29 ,d30 ,d31 ) = self.wait(conds)
pins = (clk, d0, d1, d2, d3, d4, d5, d6, d7,d8, d9, d10, d11, d12,d13 ,d14 ,d15 ,d16 ,d17 ,d18 ,d19 ,d20 ,d21 ,d22 ,d23 ,d24 ,d25 ,d26 ,d27 ,d28 ,d29 ,d30 ,d31 )
bits = [0 if idx is None else pins[idx] for idx in idx_channels]
item = bitpack(bits[1:idx_strip])
if not have_clock and is_first:
is_first = False
self.saved_item = item
continue
self.handle_bits(item)
+40
View File
@@ -0,0 +1,40 @@
## xy2-100解码器
2025-9-24 chenyue
### 问题
DSView默认的xy2-100解码器,解析的位置数据是错误的(比如0x7fff被错误解析为-32769,0x8000被解析为0)。
### 解决方案
采用修正后的解码器xy2-100-bsl,修正后的振镜位置区间为[0,65535]
### 使用方法
将附件中的解码器xy2-100-bsl解压后放到DSview安装目录(C:\Program Files\DSView\decoders),重新启动DSView既可以看到新的解码器xy2-100-bsl
## 如何合并git子项目
#!/bin/bash
### 配置变量
主仓库路径="../"
要合并的仓库URL="xy2-100-bsl"
子目录名="xy2-100-cy"
分支名="master" # 或 master
### 克隆要合并的仓库
git clone "$要合并的仓库URL" temp-repo
cd temp-repo
### 使用 filter-repo 移动文件
git filter-repo --to-subdirectory-filter "$子目录名"
### 返回主仓库
cd "$主仓库路径"
### 添加远程并合并
git remote add temp-remote ./temp-repo
git fetch temp-remote
git merge temp-remote/$分支名 --allow-unrelated-histories -m "合并 $子目录名 到子目录"
### 清理
git remote remove temp-remote
+20
View File
@@ -0,0 +1,20 @@
##
## 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/>.
##
from .pd import Decoder
+322
View File
@@ -0,0 +1,322 @@
##
## 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振镜协议 by chenyue.'
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个通道的匹配信息,通过位运算来获取具体�
+97
View File
@@ -0,0 +1,97 @@
##
## SL2-100 UDP Forwarder
## 监控 CSV 文件,将新行通过 UDP 发送到目标端口
##
## 用法: python udp_forwarder.py [csv文件路径] [目标IP] [目标端口]
## 示例: python udp_forwarder.py d:/sl2-100.csv 127.0.0.1 12345
## 默认: python udp_forwarder.py d:/sl2-100.csv 127.0.0.1 12345
##
import socket
import sys
import os
import time
def main():
# 默认参数
csv_file = "d:/sl2-100.csv"
target_host = "192.168.1.155"
target_port = 41234
# 命令行参数解析
if len(sys.argv) >= 2:
csv_file = sys.argv[1]
if len(sys.argv) >= 3:
target_host = sys.argv[2]
if len(sys.argv) >= 4:
target_port = int(sys.argv[3])
print(f"[UDP Forwarder] 启动")
print(f" CSV 文件: {csv_file}")
print(f" UDP 目标: {target_host}:{target_port}")
print(f" 等待 CSV 文件生成...")
# 创建 UDP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 等待 CSV 文件出现
while not os.path.exists(csv_file):
time.sleep(0.1)
print(f" CSV 文件已发现,开始监控...")
# 读取文件初始大小(跳过表头)
file_size = os.path.getsize(csv_file)
with open(csv_file, 'r', encoding='gbk') as f:
header = f.readline() # 跳过 "x坐标,y坐标" 表头
file_size = os.path.getsize(csv_file)
print(f" 已跳过表头: {header.strip()}")
# 轮询文件变化
while True:
try:
current_size = os.path.getsize(csv_file)
if current_size < file_size:
# 文件被截断了(重新开始),重新定位
print(f" 检测到文件被重置,重新开始跟踪")
file_size = current_size
with open(csv_file, 'r', encoding='gbk') as f:
f.readline() # 跳过表头
file_size = os.path.getsize(csv_file)
if current_size > file_size:
# 有新数据写入
with open(csv_file, 'r', encoding='gbk') as f:
f.seek(file_size)
new_lines = f.read()
file_size = current_size
# 逐行发送
for line in new_lines.strip().split('\n'):
line = line.strip()+',0'
if line:
data = (line + '\n').encode('utf-8')
sock.sendto(data, (target_host, target_port))
print(f" UDP -> {target_host}:{target_port}: {line}")
time.sleep(0.01) # 10ms 轮询间隔
except FileNotFoundError:
print(f" CSV 文件丢失,等待重新创建...")
while not os.path.exists(csv_file):
time.sleep(0.5)
file_size = 0
print(f" CSV 文件重新出现,继续监控...")
except KeyboardInterrupt:
print(f"\n[UDP Forwarder] 已停止")
break
except Exception as e:
print(f" 错误: {e}")
time.sleep(0.5)
sock.close()
if __name__ == '__main__':
main()
+28
View File
@@ -0,0 +1,28 @@
##
## This file is part of the libsigrokdecode project.
##
## Copyright (C) 2019 Uli Huber
##
## 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/>.
##
'''
XY2-100 is a serial bus for connecting galvo systems to controllers
Details:
http://www.newson.be/doc.php?id=XY2-100
'''
from .pd import Decoder
+312
View File
@@ -0,0 +1,312 @@
##
## This file is part of the libsigrokdecode project.
##
## Copyright (C) 2019 Uli Huber
## Copyright (C) 2020 Soeren Apel
##
## 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
ann_bit, ann_bit2, ann_bit3, ann_bit4, ann_stat_bit, ann_type, ann_command, ann_parameter, ann_parity, ann_pos, ann_pos2, ann_pos3, ann_pos4, ann_status, ann_warning = range(15)
frame_type_none, frame_type_command, frame_type_16bit_pos, frame_type_18bit_pos = range(4)
class Decoder(srd.Decoder):
api_version = 3
id = 'xy2-100-E'
name = 'XY2-100-E'
longname = 'XY2-100-E(E) and XY-200(E) galvanometer protocol'
desc = 'Serial protocol for galvanometer positioning in laser systems by chenyue'
license = 'gplv2+'
inputs = ['logic']
outputs = []
tags = ['Embedded/industrial']
# 你要的 options
options = (
{'id': 'worksize', 'desc': '振镜区域大小', 'default': 60},
{'id': 'resolution', 'desc': '振镜分辨率', 'default': 65536},
{'id': 'filename', 'desc': '解码输出文件名','default':'d:/xy2-100.csv'},
)
channels = (
{'id': 'clk', 'name': 'CLK', 'desc': 'Clock'},
{'id': 'sync', 'name': 'SYNC', 'desc': 'Sync'},
{'id': 'data', 'name': 'DATA X', 'desc': 'X axis data'},
{'id': 'data2', 'name': 'DATA Y', 'desc': 'Y axis data'},
{'id': 'data3', 'name': 'DATA X return', 'desc': 'X axis data return'},
{'id': 'data4', 'name': 'DATA Y return', 'desc': 'Y axis data return'},
)
optional_channels = (
{'id': 'status', 'name': 'STAT', 'desc': 'X, Y or Z axis status'},
)
annotations = (
('bit', 'Data Bit X'),
('bit2', 'Data Bit Y'),
('bit3', 'Data Bit X Return'),
('bit4', 'Data Bit Y Return'),
('stat_bit', 'Status Bit'),
('type', 'Frame Type'),
('command', 'Command'),
('parameter', 'Parameter'),
('parity', 'Parity'),
('position', 'Position X'),
('position2', 'Position Y'),
('position3', 'Position X Return'),
('position4', 'Position Y Return'),
('status', 'Status'),
('warning', 'Human-readable warnings'),
)
annotation_rows = (
('bits', 'Data Bits X', (ann_bit,)),
('bits2', 'Data Bits Y', (ann_bit2,)),
('bits3', 'Data Bits X Return', (ann_bit3,)),
('bits4', 'Data Bits Y Return', (ann_bit4,)),
('stat_bits', 'Status Bits', (ann_stat_bit,)),
('data', 'Data', (ann_type, ann_command, ann_parameter, ann_parity)),
('positions', 'Positions X', (ann_pos,)),
('positions2', 'Positions Y', (ann_pos2,)),
('positions3', 'Positions X Return', (ann_pos3,)),
('positions4', 'Positions Y Return', (ann_pos4,)),
('statuses', 'Statuses', (ann_status,)),
('warnings', 'Warnings', (ann_warning,)),
)
def __init__(self):
self.samplerate = None
self.filename = ""
self.file = None
self.x=0
self.y=0
self.x1=0
self.y1=0
self.reset()
def reset(self):
self.bits = []
self.bits2 = []
self.bits3 = []
self.bits4 = []
self.stat_bits = []
self.stat_skip_bit = True
def metadata(self, key, value):
if key == srd.SRD_CONF_SAMPLERATE:
self.samplerate = value
self.filename = self.options['filename']
def start(self):
self.out_ann = self.register(srd.OUTPUT_ANN)
# 读取配置参数
self.worksize = self.options['worksize']
self.resolution = self.options['resolution']
self.half_res = self.resolution / 2
def put_ann(self, ss, es, ann_class, value):
self.put(ss, es, self.out_ann, [ann_class, value])
# 计算逻辑坐标
def calc_logic(self, raw_pos):
return (raw_pos - self.half_res) * self.worksize / self.resolution
def process_bit(self, sync, bit_ss, bit_es, bit_value, bit_value2):
# X 轴
self.put_ann(bit_ss, bit_es, ann_bit, ['%d' % bit_value])
self.bits.append((bit_ss, bit_es, bit_value))
# Y 轴
self.put_ann(bit_ss, bit_es, ann_bit2, ['%d' % bit_value2])
self.bits2.append((bit_ss, bit_es, bit_value2))
if sync == 0:
self.process_frame(self.bits, ann_pos, 0)
self.process_frame(self.bits2, ann_pos2, 1)
self.process_frame(self.bits3, ann_pos3, 2)
self.process_frame(self.bits4, ann_pos4, 3)
self.reset()
def process_bit2(self, sync, bit_ss, bit_es, bit_value3, bit_value4):
self.put_ann(bit_ss, bit_es, ann_bit3, ['%d' % bit_value3])
self.bits3.append((bit_ss, bit_es, bit_value3))
self.put_ann(bit_ss, bit_es, ann_bit4, ['%d' % bit_value4])
self.bits4.append((bit_ss, bit_es, bit_value4))
def process_frame(self, bits, pos_ann_id, ch):
if len(bits) < 20:
if bits:
self.put_ann(bits[0][0], bits[-1][1], ann_warning, ['Not enough data bits'])
return
parity = 0
for ss, es, value in bits[:-1]:
parity ^= value
par_ss, par_es, par_value = bits[19]
parity_even = (par_value == parity)
parity_odd = not parity_even
type_1_value = bits[0][2]
type_3_value = (bits[0][2] << 2) | (bits[1][2] << 1) | bits[2][2]
type = frame_type_none
parity_status = ['OK'] if parity_even else ['NOK']
type_ss = bits[0][0]
type_es = bits[2][1]
if (type_1_value == 1) and (parity_odd == 1):
type = frame_type_18bit_pos
type_es = bits[0][1]
elif (type_3_value == 1):
type = frame_type_16bit_pos
#if not parity_even:
# self.put_ann(bits[0][0], bits[-1][1], ann_warning, ['Parity error'])
elif (type_3_value == 7) and (parity_even == 1):
type = frame_type_command
else:
type = frame_type_16bit_pos
# self.put_ann(bits[0][0], bits[-1][1], ann_warning, ['Unknown frame'])
# return
if type == frame_type_16bit_pos:
self.put_ann(type_ss, type_es, ann_type, ['16bit Position'])
if type == frame_type_18bit_pos:
self.put_ann(type_ss, type_es, ann_type, ['18bit Position'])
if type == frame_type_command:
self.put_ann(type_ss, type_es, ann_type, ['Command'])
self.put_ann(par_ss, par_es, ann_parity, parity_status)
pos = 0
if type == frame_type_16bit_pos:
count = 15
for ss, es, value in bits[3:19]:
pos |= value << count
count -= 1
elif type == frame_type_18bit_pos:
count = 17
for ss, es, value in bits[3:19]:
pos |= value << count
count -= 1
pos = pos if pos < 131072 else pos - 262144
if ch == 0:
self.x=pos
elif ch == 1:
self.y=pos
elif ch == 2:
if pos>=32768:
pos=pos-32768
else :
pos=pos+32768
self.x1=pos
elif ch == 3:
if pos>=32768:
pos=pos-32768
else :
pos=pos+32768
self.y1=pos
if self.file is not None:
self.file.write('%d,%d,%d,%d\n' % (self.x, self.y, self.x1, self.y1))
# 显示原始位置
if type in (frame_type_16bit_pos, frame_type_18bit_pos):
self.put_ann(type_es, par_ss, pos_ann_id, ['%d' % pos])
if type == frame_type_command:
count = 7
cmd = 0
cmd_es = 0
for ss, es, value in bits[3:11]:
cmd |= value << count
count -= 1
cmd_es = es
self.put_ann(type_es, cmd_es, ann_command, ['Cmd 0x%X' % cmd])
count = 7
param = 0
for ss, es, value in bits[11:19]:
param |= value << count
count -= 1
self.put_ann(cmd_es, par_ss, ann_parameter, ['Param 0x%X' % param])
def process_stat_bit(self, sync, bit_ss, bit_es, bit_value):
if self.stat_skip_bit:
self.stat_skip_bit = False
return
self.put_ann(bit_ss, bit_es, ann_stat_bit, ['%d' % bit_value])
self.stat_bits.append((bit_ss, bit_es, bit_value))
if (sync == 0) and (len(self.stat_bits) == 19):
stat_ss = self.stat_bits[0][0]
stat_es = self.stat_bits[18][1]
status = 0
count = 18
for ss, es, value in self.stat_bits:
status |= value << count
count -= 1
self.put_ann(stat_ss, stat_es, ann_status, ['Status 0x%X' % status])
def decode(self):
try:
self.decode_impl()
finally:
if self.file is not None:
self.file.close()
self.file = None
def decode_impl(self):
if self.filename != "":
try:
self.file = open(self.filename, 'w')
self.file.write('x,y,x1,y1\n')
except OSError as e:
print('xy2-100-E: cannot open %s: %s' % (self.filename, e))
self.file = None
bit_ss = None
bit2_ss = None
bit_value = 0
bit_value2 = 0
stat_ss = None
stat_value = 0
sync_value = 0
has_stat = self.has_channel(6)
while True:
clk, sync, data, data2, data3, data4, stat = self.wait({0: 'e'})
if clk == 1:# rising edge
stat_value = stat
bit_es = self.samplenum
if bit_ss is not None:
self.process_bit(sync_value, bit_ss, bit_es, bit_value, bit_value2)
bit_ss = self.samplenum
else:# falling edge
bit_value = data
bit_value2 = data2
bit_value3 = data3
bit_value4 = data4
sync_value = sync
bit2_es = self.samplenum
if bit2_ss is not None:
self.process_bit2(sync_value, bit2_ss, bit2_es, bit_value3, bit_value4)
bit2_ss = self.samplenum
if stat_ss is not None and has_stat:
stat_es = self.samplenum
self.process_stat_bit(sync_value, stat_ss, stat_es, stat_value)
stat_ss = self.samplenum
+28
View File
@@ -0,0 +1,28 @@
##
## This file is part of the libsigrokdecode project.
##
## Copyright (C) 2019 Uli Huber
##
## 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/>.
##
'''
XY2-100 is a serial bus for connecting galvo systems to controllers
Details:
http://www.newson.be/doc.php?id=XY2-100
'''
from .pd import Decoder
+262
View File
@@ -0,0 +1,262 @@
##
## This file is part of the libsigrokdecode project.
##
## Copyright (C) 2019 Uli Huber
## Copyright (C) 2020 Soeren Apel
##
## 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
ann_bit, ann_bit2, ann_stat_bit, ann_type, ann_command, ann_parameter, ann_parity, ann_pos, ann_pos2, ann_logic_x, ann_logic_y, ann_status, ann_warning = range(13)
frame_type_none, frame_type_command, frame_type_16bit_pos, frame_type_18bit_pos = range(4)
class Decoder(srd.Decoder):
api_version = 3
id = 'xy2-100-bsl'
name = 'XY2-100-bsl'
longname = 'XY2-100(E) and XY-200(E) galvanometer protocol'
desc = 'Serial protocol for galvanometer positioning in laser systems'
license = 'gplv2+'
inputs = ['logic']
outputs = []
tags = ['Embedded/industrial']
# 你要的 options
options = (
{'id': 'worksize', 'desc': '振镜区域大小', 'default': 60},
{'id': 'resolution', 'desc': '振镜分辨率', 'default': 65536},
{'id': 'filename', 'desc': '解码输出文件名','default':'d:/xy2-100.csv'},
)
channels = (
{'id': 'clk', 'name': 'CLK', 'desc': 'Clock'},
{'id': 'sync', 'name': 'SYNC', 'desc': 'Sync'},
{'id': 'data', 'name': 'DATA X', 'desc': 'X axis data'},
{'id': 'data2', 'name': 'DATA Y', 'desc': 'Y axis data'},
)
optional_channels = (
{'id': 'status', 'name': 'STAT', 'desc': 'X, Y or Z axis status'},
)
annotations = (
('bit', 'Data Bit X'),
('bit2', 'Data Bit Y'),
('stat_bit', 'Status Bit'),
('type', 'Frame Type'),
('command', 'Command'),
('parameter', 'Parameter'),
('parity', 'Parity'),
('position', 'Position X'),
('position2', 'Position Y'),
('logic_x', 'Logic X'),
('logic_y', 'Logic Y'),
('status', 'Status'),
('warning', 'Human-readable warnings'),
)
annotation_rows = (
('bits', 'Data Bits X', (ann_bit,)),
('bits2', 'Data Bits Y', (ann_bit2,)),
('stat_bits', 'Status Bits', (ann_stat_bit,)),
('data', 'Data', (ann_type, ann_command, ann_parameter, ann_parity)),
('positions', 'Positions X', (ann_pos,)),
('positions2', 'Positions Y', (ann_pos2,)),
('logic_x', 'Logic X', (ann_logic_x,)),
('logic_y', 'Logic Y', (ann_logic_y,)),
('statuses', 'Statuses', (ann_status,)),
('warnings', 'Warnings', (ann_warning,)),
)
def __init__(self):
self.samplerate = None
self.filename = ""
self.file = None
self.x=0
self.y=0
self.z=0
self.reset()
def reset(self):
self.bits = []
self.bits2 = []
self.stat_bits = []
self.stat_skip_bit = True
def metadata(self, key, value):
if key == srd.SRD_CONF_SAMPLERATE:
self.samplerate = value
self.filename = self.options['filename']
def start(self):
self.out_ann = self.register(srd.OUTPUT_ANN)
# 读取配置参数
self.worksize = self.options['worksize']
self.resolution = self.options['resolution']
self.half_res = self.resolution / 2
def put_ann(self, ss, es, ann_class, value):
self.put(ss, es, self.out_ann, [ann_class, value])
# 计算逻辑坐标
def calc_logic(self, raw_pos):
return (raw_pos - self.half_res) * self.worksize / self.resolution
def process_bit(self, sync, bit_ss, bit_es, bit_value, bit_value2):
# X 轴
self.put_ann(bit_ss, bit_es, ann_bit, ['%d' % bit_value])
self.bits.append((bit_ss, bit_es, bit_value))
# Y 轴
self.put_ann(bit_ss, bit_es, ann_bit2, ['%d' % bit_value2])
self.bits2.append((bit_ss, bit_es, bit_value2))
if sync == 0:
self.process_frame(self.bits, ann_pos, ann_logic_x, 0)
self.process_frame(self.bits2, ann_pos2, ann_logic_y, 1)
self.reset()
def process_frame(self, bits, pos_ann_id, logic_ann_id,is_y):
if len(bits) < 20:
self.put_ann(bits[0][0], bits[-1][1], ann_warning, ['Not enough data bits'])
return
parity = 0
for ss, es, value in bits[:-1]:
parity ^= value
par_ss, par_es, par_value = bits[19]
parity_even = (par_value == parity)
parity_odd = not parity_even
type_1_value = bits[0][2]
type_3_value = (bits[0][2] << 2) | (bits[1][2] << 1) | bits[2][2]
type = frame_type_none
parity_status = ['OK'] if parity_even else ['NOK']
type_ss = bits[0][0]
type_es = bits[2][1]
if (type_1_value == 1) and (parity_odd == 1):
type = frame_type_18bit_pos
type_es = bits[0][1]
elif (type_3_value == 1):
type = frame_type_16bit_pos
if not parity_even:
self.put_ann(bits[0][0], bits[-1][1], ann_warning, ['Parity error'])
elif (type_3_value == 7) and (parity_even == 1):
type = frame_type_command
else:
self.put_ann(bits[0][0], bits[-1][1], ann_warning, ['Unknown frame'])
return
if type == frame_type_16bit_pos:
self.put_ann(type_ss, type_es, ann_type, ['16bit Position'])
if type == frame_type_18bit_pos:
self.put_ann(type_ss, type_es, ann_type, ['18bit Position'])
if type == frame_type_command:
self.put_ann(type_ss, type_es, ann_type, ['Command'])
self.put_ann(par_ss, par_es, ann_parity, parity_status)
pos = 0
if type == frame_type_16bit_pos:
count = 15
for ss, es, value in bits[3:19]:
pos |= value << count
count -= 1
elif type == frame_type_18bit_pos:
count = 17
for ss, es, value in bits[3:19]:
pos |= value << count
count -= 1
pos = pos if pos < 131072 else pos - 262144
if(is_y==1):
self.y=pos
if self.filename != "":
self.file.write('%d,%d,%d\n' % (self.x, self.y, self.z))
else:
self.x=pos
# 显示原始位置
if type in (frame_type_16bit_pos, frame_type_18bit_pos):
self.put_ann(type_es, par_ss, pos_ann_id, ['%d' % pos])
# 显示逻辑坐标(3位小数)
logic_val = self.calc_logic(pos)
self.put_ann(type_es, par_ss, logic_ann_id, ['%.3f' % logic_val])
if type == frame_type_command:
count = 7
cmd = 0
cmd_es = 0
for ss, es, value in bits[3:11]:
cmd |= value << count
count -= 1
cmd_es = es
self.put_ann(type_es, cmd_es, ann_command, ['Cmd 0x%X' % cmd])
count = 7
param = 0
for ss, es, value in bits[11:19]:
param |= value << count
count -= 1
self.put_ann(cmd_es, par_ss, ann_parameter, ['Param 0x%X' % param])
def process_stat_bit(self, sync, bit_ss, bit_es, bit_value):
if self.stat_skip_bit:
self.stat_skip_bit = False
return
self.put_ann(bit_ss, bit_es, ann_stat_bit, ['%d' % bit_value])
self.stat_bits.append((bit_ss, bit_es, bit_value))
if (sync == 0) and (len(self.stat_bits) == 19):
stat_ss = self.stat_bits[0][0]
stat_es = self.stat_bits[18][1]
status = 0
count = 18
for ss, es, value in self.stat_bits:
status |= value << count
count -= 1
self.put_ann(stat_ss, stat_es, ann_status, ['Status 0x%X' % status])
def decode(self):
if self.filename != "":
self.file = open(self.filename,'w')
self.file.write('x,y,z\n')
bit_ss = None
bit_value = 0
bit_value2 = 0
stat_ss = None
stat_value = 0
sync_value = 0
has_stat = self.has_channel(4)
while True:
clk, sync, data, data2, stat = self.wait({0: 'e'})
if clk == 1:
stat_value = stat
bit_es = self.samplenum
if bit_ss is not None:
self.process_bit(sync_value, bit_ss, bit_es, bit_value, bit_value2)
bit_ss = self.samplenum
else:
bit_value = data
bit_value2 = data2
sync_value = sync
if stat_ss is not None and has_stat:
stat_es = self.samplenum
self.process_stat_bit(sync_value, stat_ss, stat_es, stat_value)
stat_ss = self.samplenum
+136 -7
View File
@@ -20,13 +20,13 @@
import sigrokdecode as srd
ann_bit, ann_stat_bit, ann_type, ann_command, ann_parameter, ann_parity, ann_pos, ann_status, ann_warning = range(9)
ann_bit,ann_bit2, ann_stat_bit, ann_type, ann_command, ann_parameter, ann_parity, ann_type2, ann_command2, ann_parameter2, ann_parity2, ann_pos,ann_pos2, ann_status, ann_warning, ann_warning2 = range(16)
frame_type_none, frame_type_command, frame_type_16bit_pos, frame_type_18bit_pos = range(4)
class Decoder(srd.Decoder):
api_version = 3
id = 'xy2-100-bsl'
name = 'XY2-100-bsl'
id = 'xy2-100-cy'
name = 'XY2-100-cy'
longname = 'XY2-100(E) and XY-200(E) galvanometer protocol'
desc = 'Serial protocol for galvanometer positioning in laser systems'
license = 'gplv2+'
@@ -40,38 +40,53 @@ class Decoder(srd.Decoder):
{'id': 'sync', 'name': 'SYNC', 'desc': 'Sync'},
{'id': 'data', 'name': 'DATA', 'desc': 'X, Y or Z axis data'},
)
optional_channels = (
optional_channels = (
{'id': 'data2', 'name': 'DATA2', 'desc': 'X, Y or Z axis data'},
{'id': 'status', 'name': 'STAT', 'desc': 'X, Y or Z axis status'},
)
annotations = (
('bit', 'Data Bit'),
('bit', 'Data Bit'),
('stat_bit', 'Status Bit'),
('type', 'Frame Type'),
('command', 'Command'),
('parameter', 'Parameter'),
('parity', 'Parity'),
('type', 'Frame Type'),
('command', 'Command'),
('parameter', 'Parameter'),
('parity', 'Parity'),
('position', 'Position'),
('position', 'Position'),
('status', 'Status'),
('warning', 'Human-readable warnings'),
('warning', 'Human-readable warnings'),
)
annotation_rows = (
('bits', 'Data Bits', (ann_bit,)),
('bits2', 'Data Bits2', (ann_bit2,)),
('stat_bits', 'Status Bits', (ann_stat_bit,)),
('data', 'Data', (ann_type, ann_command, ann_parameter, ann_parity)),
('data2', 'Data2', (ann_type2, ann_command2, ann_parameter2, ann_parity2)),
('positions', 'Positions', (ann_pos,)),
('positions2', 'Positions2', (ann_pos2,)),
('statuses', 'Statuses', (ann_status,)),
('warnings', 'Warnings', (ann_warning,)),
('warnings', 'Warnings', (ann_warning2,)),
)
def __init__(self):
self.samplerate = None
self.reset()
self.reset2()
def reset(self):
self.bits = []
self.stat_bits = []
self.stat_skip_bit = True
def reset2(self):
self.bits2 = []
def metadata(self, key, value):
if key == srd.SRD_CONF_SAMPLERATE:
@@ -192,6 +207,116 @@ class Decoder(srd.Decoder):
self.reset()
def process_bit2(self, sync, bit_ss, bit_es, bit2_value):
self.put_ann(bit_ss, bit_es, ann_bit2, ['%d' % bit2_value])
self.bits2.append((bit_ss, bit_es, bit2_value))
if sync == 0:
if len(self.bits2) < 20:
self.put_ann(self.bits2[0][0], bit_es, ann_warning2, ['Not enough data bits 0x%X' % len(self.bits2)])
self.reset2()
return
# Bit structure:
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
# T --------------- 18-bit pos ----------------- PARITY or
# -TYPE-- ------------ 16-bit pos -------------- PARITY or
# -TYPE-- -8-bit command -8-bit parameter value- PARITY
# Calculate parity, excluding the parity bit itself
parity = 0
for ss, es, value in self.bits2[:-1]:
parity ^= value
par_ss, par_es, par_value = self.bits2[19]
parity_even = 0
parity_odd = 0
if (par_value == parity):
parity_even = 1
else:
parity_odd = 1
type_1_value = self.bits2[0][2]
type_3_value = (self.bits2[0][2] << 2) | (self.bits2[1][2] << 1) | self.bits2[2][2]
# Determine frame type
type = frame_type_none
parity_status = ['X', 'Unknown']
type_ss = self.bits2[0][0]
type_es = self.bits2[2][1]
### 18-bit position
if (type_1_value == 1) and (parity_odd == 1):
type = frame_type_18bit_pos
type_es = self.bits2[0][1]
self.put_ann(self.bits2[0][0], bit_es, ann_warning2, ['Careful: 18-bit position frames with wrong parity and command frames with wrong parity cannot be identified'])
### 16-bit position
elif (type_3_value == 1):
type = frame_type_16bit_pos
if (parity_even == 1):
parity_status = ['OK']
else:
parity_status = ['NOK']
self.put_ann(self.bits2[0][0], bit_es, ann_warning2, ['Parity error', 'PE'])
### Command
elif (type_3_value == 7) and (parity_even == 1):
type = frame_type_command
self.put_ann(self.bits2[0][0], bit_es, ann_warning2, ['Careful: 18-bit position frames with wrong parity and command frames with wrong parity cannot be identified'])
### Other
else:
self.put_ann(self.bits2[0][0], bit_es, ann_warning2, ['Error', 'Unknown command or parity error'])
self.reset2()
return
# Output command and parity annotations
if (type == frame_type_16bit_pos):
self.put_ann(type_ss, type_es, ann_type2, ['16 bit Position Frame', '16 bit Pos', 'Pos', 'P'])
if (type == frame_type_18bit_pos):
self.put_ann(type_ss, type_es, ann_type2, ['18 bit Position Frame', '18 bit Pos', 'Pos', 'P'])
if (type == frame_type_command):
self.put_ann(type_ss, type_es, ann_type2, ['Command Frame', 'Command', 'C'])
self.put_ann(par_ss, par_es, ann_parity2, parity_status)
# Output value
if (type == frame_type_16bit_pos) or (type == frame_type_18bit_pos):
pos = 0
if (type == frame_type_16bit_pos):
count = 15
for ss, es, value in self.bits2[3:19]:
pos |= value << count
count -= 1
# pos = pos if pos < 32768 else pos - 65536
else:
count = 17
for ss, es, value in self.bits2[3:19]:
pos |= value << count
count -= 1
pos = pos if pos < 131072 else pos - 262144
self.put_ann(type_es, par_ss, ann_pos2, ['%d' % pos])
if (type == frame_type_command):
count = 7
cmd = 0
cmd_es = 0
for ss, es, value in self.bits2[3:11]:
cmd |= value << count
count -= 1
cmd_es = es
self.put_ann(type_es, cmd_es, ann_command2, ['Command 0x%X' % cmd, 'Cmd 0x%X' % cmd, '0x%X' % cmd])
count = 7
param = 0
for ss, es, value in self.bits2[11:19]:
param |= value << count
count -= 1
self.put_ann(cmd_es, par_ss, ann_parameter2, ['Parameter 0x%X / %d' % (param, param), '0x%X / %d' % (param, param),'0x%X' % param])
self.reset2()
def process_stat_bit(self, sync, bit_ss, bit_es, bit_value):
if self.stat_skip_bit:
self.stat_skip_bit = False
@@ -215,15 +340,16 @@ class Decoder(srd.Decoder):
bit_ss = None
bit_es = None
bit_value = 0
bit2_value = 0
stat_ss = None
stat_es = None
stat_value = 0
sync_value = 0
has_stat = self.has_channel(3)
has_data2 = self.has_channel(3)
has_stat = self.has_channel(4)
while True:
# Wait for any edge on clk
clk, sync, data, stat = self.wait({0: 'e'})
clk, sync, data, data2, stat = self.wait({0: 'e'})
if clk == 1:
stat_value = stat
@@ -231,9 +357,12 @@ class Decoder(srd.Decoder):
bit_es = self.samplenum
if bit_ss:
self.process_bit(sync_value, bit_ss, bit_es, bit_value)
if has_data2:
self.process_bit2(sync_value, bit_ss, bit_es, bit2_value)
bit_ss = self.samplenum
else:
bit_value = data
bit2_value = data2
sync_value = sync
stat_es = self.samplenum