2 ## This file is part of the libsigrokdecode project.
4 ## Copyright (C) 2018 Stephan Thiele <stephan.thiele@mailbox.org>
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.
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.
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/>.
20 import sigrokdecode as srd
24 WaitForBreak = 'WAIT_FOR_BREAK'
31 def transit(self, target_state):
32 if not self._transition_allowed(target_state):
34 self.state = target_state
37 def _transition_allowed(self, target_state):
38 if target_state == LinFsm.State.Error:
40 return target_state in self.allowed_state[self.state]
43 self.state = LinFsm.State.WaitForBreak
44 self.uart_idle_count = 0
48 a[LinFsm.State.WaitForBreak] = (LinFsm.State.Sync,)
49 a[LinFsm.State.Sync] = (LinFsm.State.Pid,)
50 a[LinFsm.State.Pid] = (LinFsm.State.Data,)
51 a[LinFsm.State.Data] = (LinFsm.State.Data, LinFsm.State.Checksum)
52 a[LinFsm.State.Checksum] = (LinFsm.State.WaitForBreak,)
53 a[LinFsm.State.Error] = (LinFsm.State.Sync,)
54 self.allowed_state = a
57 self.uart_idle_count = 0
60 class Decoder(srd.Decoder):
64 longname = 'Local Interconnect Network'
65 desc = 'Local Interconnect Network (LIN) protocol.'
71 {'id': 'version', 'desc': 'Protocol version', 'default': 2, 'values': (1, 2)},
75 ('control', 'Protocol info'),
76 ('error', 'Error description'),
77 ('inline_error', 'Protocol violation or error'),
80 ('data_vals', 'Data', (0, 1, 3)),
81 ('errors', 'Errors', (2,)),
91 self.lin_version = None
96 self.out_ann = self.register(srd.OUTPUT_ANN)
97 self.lin_version = self.options['version']
100 self.put(self.ss_block, self.es_block, self.out_ann, data)
102 def wipe_break_null_byte(self, value):
103 # Upon a break condition a null byte is received which must be ignored.
104 if self.fsm.state not in (LinFsm.State.WaitForBreak, LinFsm.State.Error):
105 if len(self.lin_rsp):
106 value = self.lin_rsp.pop()[2]
108 self.lin_header.pop()
111 self.fsm.transit(LinFsm.State.Error)
112 self.handle_error(None)
117 def handle_uart_idle(self):
118 if self.fsm.state not in (LinFsm.State.WaitForBreak, LinFsm.State.Error):
119 self.fsm.uart_idle_count += 1
121 if self.fsm.uart_idle_count == 2:
122 self.fsm.transit(LinFsm.State.Checksum)
123 self.handle_checksum()
126 def handle_wait_for_break(self, value):
127 self.wipe_break_null_byte(value)
129 def handle_break(self, value):
130 if self.fsm.state not in (LinFsm.State.WaitForBreak, LinFsm.State.Error):
131 if self.wipe_break_null_byte(value):
132 self.fsm.transit(LinFsm.State.Checksum)
133 self.handle_checksum()
136 self.fsm.transit(LinFsm.State.Sync)
138 self.putx([1, ['Break condition', 'Break', 'Brk', 'B']])
140 def handle_sync(self, value):
141 self.fsm.transit(LinFsm.State.Pid)
142 self.lin_header.append((self.ss_block, self.es_block, value))
144 def handle_pid(self, value):
145 self.fsm.transit(LinFsm.State.Data)
146 self.lin_header.append((self.ss_block, self.es_block, value))
148 def handle_data(self, value):
149 self.lin_rsp.append((self.ss_block, self.es_block, value))
151 def handle_checksum(self):
152 sync = self.lin_header.pop(0) if len(self.lin_header) else None
154 self.put(sync[0], sync[1], self.out_ann, [0, ['Sync', 'S']])
157 self.put(sync[0], sync[1], self.out_ann,
158 [2, ['Sync is not 0x55', 'Not 0x55', '!= 0x55']])
160 pid = self.lin_header.pop(0) if len(self.lin_header) else None
161 checksum = self.lin_rsp.pop() if len(self.lin_rsp) else None
167 expected_parity = self.calc_parity(pid[2])
168 parity_valid = parity == expected_parity
171 self.put(pid[0], pid[1], self.out_ann, [2, ['P != %d' % expected_parity]])
173 ann_class = 0 if parity_valid else 3
174 self.put(pid[0], pid[1], self.out_ann, [ann_class, [
175 'ID: %02X Parity: %d (%s)' % (id_, parity, 'ok' if parity_valid else 'bad'),
176 'ID: 0x%02X' % id_, 'I: %d' % id_
179 if len(self.lin_rsp):
180 checksum_valid = self.checksum_is_valid(pid[2], self.lin_rsp, checksum[2])
182 for b in self.lin_rsp:
183 self.put(b[0], b[1], self.out_ann, [0, ['Data: 0x%02X' % b[2], 'D: 0x%02X' % b[2]]])
185 ann_class = 0 if checksum_valid else 3
186 self.put(checksum[0], checksum[1], self.out_ann,
187 [ann_class, ['Checksum: 0x%02X' % checksum[2], 'Checksum', 'Chk', 'C']])
189 if not checksum_valid:
190 self.put(checksum[0], checksum[1], self.out_ann, [2, ['Checksum invalid']])
194 self.lin_header.clear()
197 def handle_error(self, dummy):
198 self.putx([3, ['Error', 'Err', 'E']])
200 def checksum_is_valid(self, pid, data, checksum):
201 if self.lin_version == 2:
204 if id_ != 60 and id_ != 61:
210 carry_bits = int(checksum / 256)
211 checksum += carry_bits
213 return checksum & 0xFF == 0xFF
216 def calc_parity(pid):
217 id_ = [((pid & 0x3F) >> i) & 1 for i in range(8)]
219 p0 = id_[0] ^ id_[1] ^ id_[2] ^ id_[4]
220 p1 = not (id_[1] ^ id_[3] ^ id_[4] ^ id_[5])
222 return (p0 << 0) | (p1 << 1)
224 def decode(self, ss, es, data):
225 ptype, rxtx, pdata = data
227 self.ss_block, self.es_block = ss, es
229 # Ignore all UART packets except the actual data packets or BREAK.
231 self.handle_uart_idle()
233 self.handle_break(pdata)
237 # We're only interested in the byte value (not individual bits).
240 # Short LIN overview:
241 # - Message begins with a BREAK (0x00) for at least 13 bittimes.
242 # - Break is always followed by a SYNC byte (0x55).
243 # - Sync byte is followed by a PID byte (Protected Identifier).
244 # - PID byte is followed by 1 - 8 data bytes and a final checksum byte.
246 handler = getattr(self, 'handle_%s' % self.fsm.state.lower())