Files
2026-06-17 21:56:35 +08:00

223 lines
7.4 KiB
Python

##
## 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()