Skip to content

Instantly share code, notes, and snippets.

@andyboeh
Created April 4, 2025 22:22
Show Gist options
  • Save andyboeh/b04ff053e42b21cc9af5db20bcf6c554 to your computer and use it in GitHub Desktop.
Save andyboeh/b04ff053e42b21cc9af5db20bcf6c554 to your computer and use it in GitHub Desktop.
Sigrok protocol decoder for elero unidirectional protocol
##
## This file is part of the libsigrokdecode project.
##
## Copyright (C) 2013 Uwe Hermann <[email protected]>
##
## 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/>.
##
'''
Simple Elero unidirectional decoder
'''
from .pd import Decoder
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.
'''
class Ann:
ITEM, NIBBLE, WARN = range(3)
class ChannelError(Exception):
pass
class Decoder(srd.Decoder):
api_version = 3
id = 'elerouni'
name = 'EleroUni'
longname = 'Elero unidirectional protocol'
desc = 'Basic Elero unidirectional decoder'
license = 'gplv2+'
inputs = ['logic']
outputs = ['elero']
tags = ['Util']
started = False
tik = True
channels = (
{'id': 'data', 'name': 'Data', 'desc': 'Data line'},
{'id': 'clk', 'name': 'Clock', 'desc': 'Clock line'},
)
annotations = (
('item', 'Item'),
('nibble', 'Nibble'),
('warning', 'Warning'),
)
annotation_rows = (
('items', 'Items', (Ann.ITEM,)),
('nibbles', 'Nibbles', (Ann.NIBBLE,)),
('warnings', 'Warnings', (Ann.WARN,)),
)
def __init__(self):
self.reset()
print('init')
def reset(self):
self.pend_item = None
self.word_items = []
self.started = False
def start(self):
self.out_python = self.register(srd.OUTPUT_PYTHON)
self.out_ann = self.register(srd.OUTPUT_ANN)
def putg(self, ss, es, ann, txts):
self.put(ss, es, self.out_ann, [ann, txts])
def putpy(self, ss, es, ann, data):
self.put(ss, es, self.out_python, [ann, data])
def detect_idle1(self, window):
idle1 = [1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]
return window == idle1
def detect_idle2(self, window):
idle2 = [0, 0, 0, 0, 1, 1, 1, 1]
return window[4:] == idle2
def decode(self):
print('decode')
# 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.
if not self.has_channel(0) or not self.has_channel(1):
raise ChannelError('Need clock and data channels.')
conds = [{1 : 'r'}]
window = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
ds = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
bits = [0, 0]
nibble = [0, 0, 0, 0]
npos = [0, 0, 0, 0]
data_index = 0
while True:
pins = self.wait(conds)
clock_edge = self.matched[0]
data_state = pins[0]
window.pop(0)
window.append(data_state)
ds.pop(0)
ds.append(self.samplenum)
if self.started:
if self.tik:
bits[0] = data_state
self.tik = False
else:
bits[1] = data_state
self.tik = True
db = -1
if bits[0] == 0 and bits[1] == 1:
self.putg(self.samplenum, self.samplenum, Ann.ITEM, ['0'])
db = 0
elif bits[0] == 1 and bits[1] == 0:
self.putg(self.samplenum, self.samplenum, Ann.ITEM, ['1'])
db = 1
nibble.pop(0)
nibble.append(db)
npos.pop(0)
npos.append(self.samplenum)
if data_index % 4 == 0 and data_index > 0:
if not -1 in nibble:
nibble_string = hex(int("".join(str(x) for x in nibble), 2))
else:
nibble_string = "error"
self.putg(npos[0], self.samplenum, Ann.NIBBLE, [nibble_string])
data_index += 1
if data_index == 65:
data_index = 0
self.started = False
if self.detect_idle1(window):
es = self.samplenum
ss = ds[0]
self.putg(ss, es, Ann.ITEM, ['IDLE1'])
self.started = True
if self.detect_idle2(window):
es = self.samplenum
ss = ds[4]
self.putg(ss, es, Ann.ITEM, ['IDLE2'])
self.started = True
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment