From: Soeren Apel Date: Fri, 10 Jul 2020 18:47:17 +0000 (+0200) Subject: xy2-100: Rewrite PD for XY2-100E compatibility and features X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=ae607f25b5d0bb50132eb07eab93c033351bcf8d;p=libsigrokdecode.git xy2-100: Rewrite PD for XY2-100E compatibility and features --- diff --git a/decoders/xy2-100/pd.py b/decoders/xy2-100/pd.py index 83f9422..4df7085 100644 --- a/decoders/xy2-100/pd.py +++ b/decoders/xy2-100/pd.py @@ -2,6 +2,7 @@ ## This file is part of the libsigrokdecode project. ## ## Copyright (C) 2019 Uli Huber +## Copyright (C) 2020 Soeren Apel ## ## 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 @@ -17,39 +18,42 @@ ## along with this program; if not, see . ## -import re import sigrokdecode as srd -ann_hdrbit, ann_databit, ann_paritybit, ann_bitlegende, ann_pos, ann_warning = range(6) +ann_bit, ann_type, ann_command, ann_parameter, ann_parity, ann_pos, ann_warning = range(7) +frame_type_none, frame_type_command, frame_type_16bit_pos, frame_type_18bit_pos = range(4) class Decoder(srd.Decoder): api_version = 3 id = 'xy2-100' name = 'XY2-100' - longname = 'XY2-100 Galvo Protocol' - desc = 'Serial protocol for Galvo positioning' + longname = 'XY2-100(E) and XY-200(E) galvanometer protocol' + desc = 'Serial protocol for galvanometer positioning in laser systems' license = 'gplv2+' inputs = ['logic'] outputs = [] + tags = ['Embedded/industrial'] + channels = ( - {'id': 'clk', 'name': 'D0', 'desc': 'Clock','default': 0}, - {'id': 'sync', 'name': 'D1', 'desc': 'Sync','default': 1}, - {'id': 'PosX', 'name': 'D2', 'desc': 'X/Y/Z','default': 2}, + {'id': 'clk', 'name': 'CLK', 'desc': 'Clock'}, + {'id': 'sync', 'name': 'SYNC', 'desc': 'Sync'}, + {'id': 'data', 'name': 'DATA', 'desc': 'X, Y or Z axis data'}, ) annotations = ( - ('hdrbit', 'Header bit'), - ('databit', 'Data bit'), - ('paritybit', 'Parity bit'), - ('bitlegende', 'Bit Legende'), - ('position', 'Position Data'), + ('bit', 'Bit'), + ('type', 'Frame Type'), + ('command', 'Command'), + ('parameter', 'Parameter'), + ('parity', 'Parity'), + ('position', 'Position'), ('warning', 'Human-readable warnings'), ) annotation_rows = ( - ('bits', 'Bits', (ann_hdrbit, ann_databit, ann_paritybit)), - ('legende', 'Legende', (ann_bitlegende,)), - ('positions', 'Position', (ann_pos,)), + ('bits', 'Bits', (ann_bit,)), + ('data', 'Data', (ann_type, ann_command, ann_parameter, ann_parity)), + ('positions', 'Positions', (ann_pos,)), ('warnings', 'Warnings', (ann_warning,)), ) @@ -58,9 +62,7 @@ class Decoder(srd.Decoder): self.reset() def reset(self): - self.hdrbits = [] - self.databits = [] - self.paritybits = [] + self.bits = [] def metadata(self, key, value): if key == srd.SRD_CONF_SAMPLERATE: @@ -69,67 +71,133 @@ class Decoder(srd.Decoder): def start(self): self.out_ann = self.register(srd.OUTPUT_ANN) - def putbit(self, ss, es, typ, value): - self.put(ss, es, self.out_ann, [typ, ['%s' % (value)]]) + def put_ann(self, ss, es, ann_class, value): + self.put(ss, es, self.out_ann, [ann_class, value]) + + def process_bit(self, sync, bit_ss, bit_es, bit_value): + self.put_ann(bit_ss, bit_es, ann_bit, ['%d' % bit_value]) + self.bits.append((bit_ss, bit_es, bit_value)) + + if sync == 0: + if len(self.bits) < 20: + self.put_ann(self.bits[0][0], bit_es, ann_warning, ['Not enough data bits']) + self.reset() + return + + # Bit structure: + # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 + # T --------------- 18-bit pos ----------------- PARITY or + # -TYPE-- ------------ 16-bit pos -------------- PARITY or + # -TYPE-- -8-bit command -8-bit parameter value- PARITY + + # Calculate parity, excluding the parity bit itself + parity = 0 + for ss, es, value in self.bits[:-1]: + parity ^= value + + par_ss, par_es, par_value = self.bits[19] + parity_even = 0 + parity_odd = 0 + if (par_value == parity): + parity_even = 1 + else: + parity_odd = 1 + + type_1_value = self.bits[0][2] + type_3_value = (self.bits[0][2] << 2) | (self.bits[1][2] << 1) | self.bits[2][2] + + # Determine frame type + type = frame_type_none + parity_status = ['X', 'Unknown'] + type_ss = self.bits[0][0] + type_es = self.bits[2][1] + + ### 18-bit position + if (type_1_value == 1) and (parity_odd == 1): + type = frame_type_18bit_pos + type_es = self.bits[0][1] + self.put_ann(self.bits[0][0], bit_es, ann_warning, ['Careful: 18-bit position frames with wrong parity and command frames with wrong parity cannot be identified']) + ### 16-bit position + elif (type_3_value == 1): + type = frame_type_16bit_pos + if (parity_even == 1): + parity_status = ['OK'] + else: + parity_status = ['NOK'] + self.put_ann(self.bits[0][0], bit_es, ann_warning, ['Parity error', 'PE']) + ### Command + elif (type_3_value == 7) and (parity_even == 1): + type = frame_type_command + self.put_ann(self.bits[0][0], bit_es, ann_warning, ['Careful: 18-bit position frames with wrong parity and command frames with wrong parity cannot be identified']) + ### Other + else: + self.put_ann(self.bits[0][0], bit_es, ann_warning, ['Error', 'Unknown command or parity error']) + self.reset() + return + + # Output command and parity annotations + if (type == frame_type_16bit_pos): + self.put_ann(type_ss, type_es, ann_type, ['16 bit Position Frame', '16 bit Pos', 'Pos', 'P']) + if (type == frame_type_18bit_pos): + self.put_ann(type_ss, type_es, ann_type, ['18 bit Position Frame', '18 bit Pos', 'Pos', 'P']) + if (type == frame_type_command): + self.put_ann(type_ss, type_es, ann_type, ['Command Frame', 'Command', 'C']) + + self.put_ann(par_ss, par_es, ann_parity, parity_status) + + # Output value + if (type == frame_type_16bit_pos) or (type == frame_type_18bit_pos): + pos = 0 + + if (type == frame_type_16bit_pos): + count = 15 + for ss, es, value in self.bits[3:19]: + pos |= value << count + count -= 1 + pos = pos if pos < 32768 else pos - 65536 + else: + count = 17 + for ss, es, value in self.bits[3:19]: + pos |= value << count + count -= 1 + pos = pos if pos < 131072 else pos - 262144 + + self.put_ann(type_es, par_ss, ann_pos, ['%d' % pos]) + + if (type == frame_type_command): + count = 7 + cmd = 0 + cmd_es = 0 + for ss, es, value in self.bits[3:11]: + cmd |= value << count + count -= 1 + cmd_es = es + self.put_ann(type_es, cmd_es, ann_command, ['Command 0x%X' % cmd, 'Cmd 0x%X' % cmd, '0x%X' % cmd]) + + count = 7 + param = 0 + for ss, es, value in self.bits[11:19]: + param |= value << count + count -= 1 + self.put_ann(cmd_es, par_ss, ann_parameter, ['Parameter 0x%X / %d' % (param, param), '0x%X / %d' % (param, param),'0x%X' % param]) + + self.reset() def decode(self): - headerstart = 0 - datastart = 0 - dataend = 0 - lastsample = 0 + bit_ss = None + bit_es = None + bit_value = 0 + sync_value = 0 + while True: - # Wait for any edge CLK or SYNC - clk, sync, PosX = self.wait({0: 'r'}) - bitstart = self.samplenum - bitend = bitstart+(bitstart-lastsample) - - # start data collection - if sync == 1: - # wait for falling edge clk - clk, sync, PosX = self.wait({0: 'f'}) - if len(self.hdrbits) < 3: - if len(self.hdrbits) == 0: - headerstart = bitstart - self.hdrbits = [(PosX, bitstart, self.samplenum)] + self.hdrbits - self.putbit(bitstart, bitend, ann_hdrbit, PosX) - else: - if len(self.databits) == 0: - datastart = bitstart - self.databits = [(PosX, bitstart, self.samplenum)] + self.databits - #self.putbit(bitstart, self.samplenum+1, ann_databit, PosX) - self.putbit(bitstart,bitend, ann_databit, PosX) - dataend = bitend - - # get parity bit, calculate position - elif sync == 0: - clk, sync, PosX = self.wait({0: 'f'}) - self.paritybits = [PosX] - self.putbit(dataend, bitend, ann_paritybit, PosX) - self.put(dataend,bitend, self.out_ann, [ann_bitlegende, ['Parity' ]]) - self.put(headerstart,datastart, self.out_ann, [ann_bitlegende, ['Header' ]]) - self.put(datastart, dataend, self.out_ann, [ann_bitlegende, ['Position' ]]) - - par=0 - for x in self.hdrbits: - par ^= x[0]&1 - positionX = 0 - stelle = 0 - for x in self.databits: - par ^= x[0]&1 - if x[0] == 1: - positionX = positionX + (1 << stelle) - stelle += 1 - - self.put(datastart, dataend, self.out_ann, [ann_pos, ['%02d' % (positionX)]]) - check = 'NOK' - if PosX == par: - check = 'OK' - self.put(dataend, bitend, self.out_ann, [ann_pos, ['%02s' % (check)]]) - - #self.put(datastart, self.samplenum, self.out_ann, - #[ann_warning, ['%s: %02X' % ('WARNUNG: ', 4711)]]) - - self.databits = [] - self.hdrbits = [] - - lastsample = bitstart + # Wait for any edge on clk + clk, sync, data = self.wait({0: 'e'}) + + if clk == 1: + bit_es = self.samplenum + if bit_ss: + self.process_bit(sync_value, bit_ss, bit_es, bit_value) + bit_ss = self.samplenum + else: + bit_value = data + sync_value = sync