]> sigrok.org Git - libsigrokdecode.git/blame - decoders/flexray/pd.py
avr_isp: Add more parts
[libsigrokdecode.git] / decoders / flexray / pd.py
CommitLineData
20d71243
ST
1##
2## This file is part of the libsigrokdecode project.
3##
4## Copyright (C) 2019 Stephan Thiele <stephan.thiele@mailbox.org>
5##
6## This program is free software; you can redistribute it and/or modify
7## it under the terms of the GNU General Public License as published by
8## the Free Software Foundation; either version 2 of the License, or
9## (at your option) any later version.
10##
11## This program is distributed in the hope that it will be useful,
12## but WITHOUT ANY WARRANTY; without even the implied warranty of
13## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14## GNU General Public License for more details.
15##
16## You should have received a copy of the GNU General Public License
17## along with this program; if not, see <http://www.gnu.org/licenses/>.
18##
19
20import sigrokdecode as srd
21
22# Selection of constants as defined in FlexRay specification 3.0.1 Chapter A.1:
23class Const:
24 cChannelIdleDelimiter = 11
25 cCrcInitA = 0xFEDCBA
26 cCrcInitB = 0xABCDEF
27 cCrcPolynomial = 0x5D6DCB
28 cCrcSize = 24
29 cCycleCountMax = 63
30 cdBSS = 2
31 cdCAS = 30
32 cdFES = 2
33 cdFSS = 1
34 cHCrcInit = 0x01A
35 cHCrcPolynomial = 0x385
36 cHCrcSize = 11
37 cSamplesPerBit = 8
38 cSlotIDMax = 2047
39 cStaticSlotIDMax = 1023
40 cVotingSamples = 5
41
42class SamplerateError(Exception):
43 pass
44
45class Decoder(srd.Decoder):
46 api_version = 3
47 id = 'flexray'
48 name = 'FlexRay'
49 longname = 'FlexRay'
50 desc = 'Automotive network communications protocol.'
51 license = 'gplv2+'
52 inputs = ['logic']
53 outputs = []
54 tags = ['Automotive']
55 channels = (
56 {'id': 'channel', 'name': 'Channel', 'desc': 'FlexRay bus channel'},
57 )
58 options = (
59 {'id': 'channel_type', 'desc': 'Channel type', 'default': 'A',
60 'values': ('A', 'B')},
88b84b3c
UH
61 {'id': 'bitrate', 'desc': 'Bitrate (bit/s)', 'default': 10000000,
62 'values': (10000000, 5000000, 2500000)},
20d71243
ST
63 )
64 annotations = (
65 ('data', 'FlexRay payload data'),
66 ('tss', 'Transmission start sequence'),
67 ('fss', 'Frame start sequence'),
68 ('reserved-bit', 'Reserved bit'),
69 ('ppi', 'Payload preamble indicator'),
70 ('null-frame', 'Nullframe indicator'),
71 ('sync-frame', 'Full identifier'),
72 ('startup-frame', 'Startup frame indicator'),
73 ('id', 'Frame ID'),
74 ('length', 'Data length'),
75 ('header-crc', 'Header CRC'),
76 ('cycle', 'Cycle code'),
77 ('data-byte', 'Data byte'),
78 ('frame-crc', 'Frame CRC'),
f4314037 79 ('fes', 'Frame end sequence'),
20d71243 80 ('bss', 'Byte start sequence'),
e144452b 81 ('warning', 'Warning'),
20d71243
ST
82 ('bit', 'Bit'),
83 ('cid', 'Channel idle delimiter'),
84 ('dts', 'Dynamic trailing sequence'),
85 ('cas', 'Collision avoidance symbol'),
86 )
87 annotation_rows = (
88 ('bits', 'Bits', (15, 17)),
89 ('fields', 'Fields', tuple(range(15)) + (18, 19, 20)),
90 ('warnings', 'Warnings', (16,)),
91 )
92
93 def __init__(self):
94 self.reset()
95
96 def reset(self):
97 self.samplerate = None
98 self.reset_variables()
99
100 def start(self):
101 self.out_ann = self.register(srd.OUTPUT_ANN)
102
103 def metadata(self, key, value):
104 if key == srd.SRD_CONF_SAMPLERATE:
88b84b3c 105 bitrate = float(self.options['bitrate'])
20d71243
ST
106 self.samplerate = value
107 self.bit_width = float(self.samplerate) / bitrate
108 self.sample_point = (self.bit_width / 100.0) * self.sample_point_percent
109
110 # Generic helper for FlexRay bit annotations.
111 def putg(self, ss, es, data):
112 left, right = int(self.sample_point), int(self.bit_width - self.sample_point)
113 self.put(ss - left, es + right, self.out_ann, data)
114
115 # Single-FlexRay-bit annotation using the current samplenum.
116 def putx(self, data):
117 self.putg(self.samplenum, self.samplenum, data)
118
119 # Multi-FlexRay-bit annotation from self.ss_block to current samplenum.
120 def putb(self, data):
121 self.putg(self.ss_block, self.samplenum, data)
122
123 # Generic CRC algorithm for any bit size and any data length. Used for
124 # 11-bit header and 24-bit trailer. Not very efficient but at least it
125 # works for now.
126 #
127 # TODO:
128 # - use precalculated tables to increase performance.
129 # - Add support for reverse CRC calculations.
130
131 @staticmethod
132 def crc(data, data_len_bits, polynom, crc_len_bits, iv=0, xor=0):
133 reg = iv ^ xor
134
135 for i in range(data_len_bits - 1, -1, -1):
136 bit = ((reg >> (crc_len_bits - 1)) & 0x1) ^ ((data >> i) & 0x1)
137 reg <<= 1
138 if bit:
139 reg ^= polynom
140
141 mask = (1 << crc_len_bits) - 1
142 crc = reg & mask
143
144 return crc ^ xor
145
146 def reset_variables(self):
147 self.sample_point_percent = 50 # TODO: use vote based sampling
148 self.state = 'IDLE'
149 self.tss_start = self.tss_end = self.frame_type = self.dlc = None
150 self.rawbits = [] # All bits, including byte start sequence bits
151 self.bits = [] # Only actual FlexRay frame bits (no byte start sequence bits)
152 self.curbit = 0 # Current bit of FlexRay frame (bit 0 == FSS)
153 self.last_databit = 999 # Positive value that bitnum+x will never match
154 self.last_xmit_bit = 999 # Positive value that bitnum+x will never match
155 self.ss_block = None
156 self.ss_databytebits = []
157 self.end_of_frame = False
158 self.dynamic_frame = False
159 self.ss_bit0 = None
160 self.ss_bit1 = None
161 self.ss_bit2 = None
162
163 # Poor man's clock synchronization. Use signal edges which change to
164 # dominant state in rather simple ways. This naive approach is neither
165 # aware of the SYNC phase's width nor the specific location of the edge,
166 # but improves the decoder's reliability when the input signal's bitrate
167 # does not exactly match the nominal rate.
168 def dom_edge_seen(self, force=False):
169 self.dom_edge_snum = self.samplenum
170 self.dom_edge_bcount = self.curbit
171
172 # Determine the position of the next desired bit's sample point.
173 def get_sample_point(self, bitnum):
174 samplenum = self.dom_edge_snum
175 samplenum += self.bit_width * (bitnum - self.dom_edge_bcount)
176 samplenum += self.sample_point
177 return int(samplenum)
178
179 def is_bss_sequence(self):
180 # FlexRay uses NRZ encoding and adds a binary 10 sequence before each
181 # byte. After each 8 data bits, a BSS sequence is added but not after
182 # frame CRC.
183
184 if self.end_of_frame:
185 return False
186
187 if (len(self.rawbits) - 2) % 10 == 0:
188 return True
189 elif (len(self.rawbits) - 3) % 10 == 0:
190 return True
191
192 return False
193
194 def handle_bit(self, fr_rx):
195 self.rawbits.append(fr_rx)
196 self.bits.append(fr_rx)
197
198 # Get the index of the current FlexRay frame bit.
199 bitnum = len(self.bits) - 1
200
201 # If this is a byte start sequence remove it from self.bits and ignore it.
202 if self.is_bss_sequence():
203 self.bits.pop()
204
205 if bitnum > 1:
206 self.putx([15, [str(fr_rx)]])
207 else:
208 if len(self.rawbits) == 2:
209 self.ss_bit1 = self.samplenum
210 elif len(self.rawbits) == 3:
211 self.ss_bit2 = self.samplenum
212
213 self.curbit += 1 # Increase self.curbit (bitnum is not affected).
214 return
215 else:
216 if bitnum > 1:
217 self.putx([17, [str(fr_rx)]])
218
219 # Bit 0: Frame start sequence (FSS) bit
220 if bitnum == 0:
221 self.ss_bit0 = self.samplenum
222
223 # Bit 1: Start of header
224 elif bitnum == 1:
225 if self.rawbits[:3] == [1, 1, 0]:
226 self.put(self.tss_start, self.tss_end, self.out_ann,
227 [1, ['Transmission start sequence', 'TSS']])
228
229 self.putg(self.ss_bit0, self.ss_bit0, [17, [str(self.rawbits[:3][0])]])
230 self.putg(self.ss_bit0, self.ss_bit0, [2, ['FSS', 'Frame start sequence']])
231 self.putg(self.ss_bit1, self.ss_bit1, [15, [str(self.rawbits[:3][1])]])
232 self.putg(self.ss_bit2, self.ss_bit2, [15, [str(self.rawbits[:3][2])]])
233 self.putx([17, [str(fr_rx)]])
234 self.putx([3, ['Reserved bit: %d' % fr_rx, 'RB: %d' % fr_rx, 'RB']])
235 else:
236 self.put(self.tss_start, self.tss_end, self.out_ann,
237 [20, ['Collision avoidance symbol', 'CAS']])
238 self.reset_variables()
239
240 # TODO: warning, if sequence is neither [1, 1, 0] nor [1, 1, 1]
241
242 # Bit 2: Payload preamble indicator. Must be 0 if null frame indicator is 0.
243 elif bitnum == 2:
244 self.putx([4, ['Payload preamble indicator: %d' % fr_rx,
245 'PPI: %d' % fr_rx]])
246
247 # Bit 3: Null frame indicator (inversed)
248 elif bitnum == 3:
249 data_type = 'data frame' if fr_rx else 'null frame'
250 self.putx([5, ['Null frame indicator: %s' % data_type,
251 'NF: %d' % fr_rx, 'NF']])
252
253 # Bit 4: Sync frame indicator
254 # Must be 1 if startup frame indicator is 1.
255 elif bitnum == 4:
256 self.putx([6, ['Sync frame indicator: %d' % fr_rx,
257 'Sync: %d' % fr_rx, 'Sync']])
258
259 # Bit 5: Startup frame indicator
260 elif bitnum == 5:
261 self.putx([7, ['Startup frame indicator: %d' % fr_rx,
262 'Startup: %d' % fr_rx, 'Startup']])
263
264 # Remember start of ID (see below).
265 elif bitnum == 6:
266 self.ss_block = self.samplenum
267
268 # Bits 6-16: Frame identifier (ID[10..0])
269 # ID must NOT be 0.
270 elif bitnum == 16:
271 self.id = int(''.join(str(d) for d in self.bits[6:]), 2)
272 self.putb([8, ['Frame ID: %d' % self.id, 'ID: %d' % self.id,
273 '%d' % self.id]])
274
275 # Remember start of payload length (see below).
276 elif bitnum == 17:
277 self.ss_block = self.samplenum
278
279 # Bits 17-23: Payload length (Length[7..0])
280 # Payload length in header is the half of the real payload size.
281 elif bitnum == 23:
282 self.payload_length = int(''.join(str(d) for d in self.bits[17:]), 2)
283 self.putb([9, ['Payload length: %d' % self.payload_length,
284 'Length: %d' % self.payload_length,
285 '%d' % self.payload_length]])
286
287 # Remember start of header CRC (see below).
288 elif bitnum == 24:
289 self.ss_block = self.samplenum
290
291 # Bits 24-34: Header CRC (11-bit) (HCRC[11..0])
292 # Calculation of header CRC is equal on both channels.
293 elif bitnum == 34:
294 bits = ''.join([str(b) for b in self.bits[4:24]])
295 header_to_check = int(bits, 2)
296 expected_crc = self.crc(header_to_check, len(bits),
297 Const.cHCrcPolynomial, Const.cHCrcSize, Const.cHCrcInit)
298 self.header_crc = int(''.join(str(d) for d in self.bits[24:]), 2)
299
300 crc_ok = self.header_crc == expected_crc
301 crc_ann = "OK" if crc_ok else "bad"
302
303 self.putb([10, ['Header CRC: 0x%X (%s)' % (self.header_crc, crc_ann),
304 '0x%X (%s)' % (self.header_crc, crc_ann),
305 '0x%X' % self.header_crc]])
306
307 # Remember start of cycle code (see below).
308 elif bitnum == 35:
309 self.ss_block = self.samplenum
310
311 # Bits 35-40: Cycle code (Cyc[6..0])
312 # Cycle code. Must be between 0 and 63.
313 elif bitnum == 40:
314 self.cycle = int(''.join(str(d) for d in self.bits[35:]), 2)
315 self.putb([11, ['Cycle: %d' % self.cycle, 'Cyc: %d' % self.cycle,
316 '%d' % self.cycle]])
317 self.last_databit = 41 + 2 * self.payload_length * 8
318
319 # Remember all databyte bits, except the very last one.
320 elif bitnum in range(41, self.last_databit):
321 self.ss_databytebits.append(self.samplenum)
322
323 # Bits 41-X: Data field (0-254 bytes, depending on length)
324 # The bits within a data byte are transferred MSB-first.
325 elif bitnum == self.last_databit:
326 self.ss_databytebits.append(self.samplenum) # Last databyte bit.
327 for i in range(2 * self.payload_length):
328 x = 40 + (8 * i) + 1
329 b = int(''.join(str(d) for d in self.bits[x:x + 8]), 2)
330 ss = self.ss_databytebits[i * 8]
331 es = self.ss_databytebits[((i + 1) * 8) - 1]
332 self.putg(ss, es, [12, ['Data byte %d: 0x%02x' % (i, b),
333 'DB%d: 0x%02x' % (i, b), '%02X' % b]])
334 self.ss_databytebits = []
335 self.ss_block = self.samplenum # Remember start of trailer CRC.
336
337 # Trailer CRC (24-bit) (CRC[11..0])
338 # Initialization vector of channel A and B are different, so CRCs are
339 # different for same data.
340 elif bitnum == self.last_databit + 23:
341 bits = ''.join([str(b) for b in self.bits[1:-24]])
342 frame_to_check = int(bits, 2)
343 iv = Const.cCrcInitA if self.options['channel_type'] == 'A' else Const.cCrcInitB
344 expected_crc = self.crc(frame_to_check, len(bits),
345 Const.cCrcPolynomial, Const.cCrcSize, iv=iv)
346 self.frame_crc = int(''.join(str(d) for d in self.bits[self.last_databit:]), 2)
347
348 crc_ok = self.frame_crc == expected_crc
349 crc_ann = "OK" if crc_ok else "bad"
350
351 self.putb([13, ['Frame CRC: 0x%X (%s)' % (self.frame_crc, crc_ann),
352 '0x%X (%s)' % (self.frame_crc, crc_ann),
353 '0x%X' % self.frame_crc]])
354 self.end_of_frame = True
355
356 # Remember start of frame end sequence (see below).
357 elif bitnum == self.last_databit + 24:
358 self.ss_block = self.samplenum
359
360 # Frame end sequence, must be 1 followed by 0.
361 elif bitnum == self.last_databit + 25:
362 self.putb([14, ['Frame end sequence', 'FES']])
363
364 # Check for DTS
365 elif bitnum == self.last_databit + 26:
366 if not fr_rx:
367 self.dynamic_frame = True
368 else:
369 self.last_xmit_bit = bitnum
370 self.ss_block = self.samplenum
371
372 # Remember start of channel idle delimiter (see below).
373 elif bitnum == self.last_xmit_bit:
374 self.ss_block = self.samplenum
375
376 # Channel idle limiter (CID[11..0])
377 elif bitnum == self.last_xmit_bit + Const.cChannelIdleDelimiter - 1:
378 self.putb([18, ['Channel idle delimiter', 'CID']])
379 self.reset_variables()
380
381 # DTS if dynamic frame
382 elif bitnum > self.last_databit + 27:
383 if self.dynamic_frame:
384 if fr_rx:
385 if self.last_xmit_bit == 999:
386 self.putb([19, ['Dynamic trailing sequence', 'DTS']])
387 self.last_xmit_bit = bitnum + 1
388 self.ss_block = self.samplenum
389
390 self.curbit += 1
391
392 def decode(self):
393 if not self.samplerate:
394 raise SamplerateError('Cannot decode without samplerate.')
395
396 while True:
397 # State machine.
398 if self.state == 'IDLE':
399 # Wait for a dominant state (logic 0) on the bus.
400 (fr_rx,) = self.wait({0: 'l'})
401 self.tss_start = self.samplenum
402 (fr_rx,) = self.wait({0: 'h'})
403 self.tss_end = self.samplenum
404 self.dom_edge_seen(force = True)
405 self.state = 'GET BITS'
406 elif self.state == 'GET BITS':
407 # Wait until we're in the correct bit/sampling position.
408 pos = self.get_sample_point(self.curbit)
409 (fr_rx,) = self.wait([{'skip': pos - self.samplenum}, {0: 'f'}])
410 if self.matched[1]:
411 self.dom_edge_seen()
412 if self.matched[0]:
413 self.handle_bit(fr_rx)