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