## ## 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 ## 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 . ## import sigrokdecode as srd ann_bit, ann_bit2, ann_stat_bit, ann_type, ann_command, ann_parameter, ann_parity, ann_pos, ann_pos2, ann_logic_x, ann_logic_y, ann_status, ann_warning = range(13) 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-bsl' name = 'XY2-100-bsl' 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'] # 你要的 options options = ( {'id': 'worksize', 'desc': '振镜区域大小', 'default': 60}, {'id': 'resolution', 'desc': '振镜分辨率', 'default': 65536}, {'id': 'filename', 'desc': '解码输出文件名','default':'d:/xy2-100.csv'}, ) channels = ( {'id': 'clk', 'name': 'CLK', 'desc': 'Clock'}, {'id': 'sync', 'name': 'SYNC', 'desc': 'Sync'}, {'id': 'data', 'name': 'DATA X', 'desc': 'X axis data'}, {'id': 'data2', 'name': 'DATA Y', 'desc': 'Y axis data'}, ) optional_channels = ( {'id': 'status', 'name': 'STAT', 'desc': 'X, Y or Z axis status'}, ) annotations = ( ('bit', 'Data Bit X'), ('bit2', 'Data Bit Y'), ('stat_bit', 'Status Bit'), ('type', 'Frame Type'), ('command', 'Command'), ('parameter', 'Parameter'), ('parity', 'Parity'), ('position', 'Position X'), ('position2', 'Position Y'), ('logic_x', 'Logic X'), ('logic_y', 'Logic Y'), ('status', 'Status'), ('warning', 'Human-readable warnings'), ) annotation_rows = ( ('bits', 'Data Bits X', (ann_bit,)), ('bits2', 'Data Bits Y', (ann_bit2,)), ('stat_bits', 'Status Bits', (ann_stat_bit,)), ('data', 'Data', (ann_type, ann_command, ann_parameter, ann_parity)), ('positions', 'Positions X', (ann_pos,)), ('positions2', 'Positions Y', (ann_pos2,)), ('logic_x', 'Logic X', (ann_logic_x,)), ('logic_y', 'Logic Y', (ann_logic_y,)), ('statuses', 'Statuses', (ann_status,)), ('warnings', 'Warnings', (ann_warning,)), ) def __init__(self): self.samplerate = None self.filename = "" self.file = None self.x=0 self.y=0 self.z=0 self.reset() def reset(self): self.bits = [] self.bits2 = [] self.stat_bits = [] self.stat_skip_bit = True def metadata(self, key, value): if key == srd.SRD_CONF_SAMPLERATE: self.samplerate = value self.filename = self.options['filename'] def start(self): self.out_ann = self.register(srd.OUTPUT_ANN) # 读取配置参数 self.worksize = self.options['worksize'] self.resolution = self.options['resolution'] self.half_res = self.resolution / 2 def put_ann(self, ss, es, ann_class, value): self.put(ss, es, self.out_ann, [ann_class, value]) # 计算逻辑坐标 def calc_logic(self, raw_pos): return (raw_pos - self.half_res) * self.worksize / self.resolution def process_bit(self, sync, bit_ss, bit_es, bit_value, bit_value2): # X 轴 self.put_ann(bit_ss, bit_es, ann_bit, ['%d' % bit_value]) self.bits.append((bit_ss, bit_es, bit_value)) # Y 轴 self.put_ann(bit_ss, bit_es, ann_bit2, ['%d' % bit_value2]) self.bits2.append((bit_ss, bit_es, bit_value2)) if sync == 0: self.process_frame(self.bits, ann_pos, ann_logic_x, 0) self.process_frame(self.bits2, ann_pos2, ann_logic_y, 1) self.reset() def process_frame(self, bits, pos_ann_id, logic_ann_id,is_y): if len(bits) < 20: self.put_ann(bits[0][0], bits[-1][1], ann_warning, ['Not enough data bits']) return parity = 0 for ss, es, value in bits[:-1]: parity ^= value par_ss, par_es, par_value = bits[19] parity_even = (par_value == parity) parity_odd = not parity_even type_1_value = bits[0][2] type_3_value = (bits[0][2] << 2) | (bits[1][2] << 1) | bits[2][2] type = frame_type_none parity_status = ['OK'] if parity_even else ['NOK'] type_ss = bits[0][0] type_es = bits[2][1] if (type_1_value == 1) and (parity_odd == 1): type = frame_type_18bit_pos type_es = bits[0][1] elif (type_3_value == 1): type = frame_type_16bit_pos if not parity_even: self.put_ann(bits[0][0], bits[-1][1], ann_warning, ['Parity error']) elif (type_3_value == 7) and (parity_even == 1): type = frame_type_command else: self.put_ann(bits[0][0], bits[-1][1], ann_warning, ['Unknown frame']) return if type == frame_type_16bit_pos: self.put_ann(type_ss, type_es, ann_type, ['16bit Position']) if type == frame_type_18bit_pos: self.put_ann(type_ss, type_es, ann_type, ['18bit Position']) if type == frame_type_command: self.put_ann(type_ss, type_es, ann_type, ['Command']) self.put_ann(par_ss, par_es, ann_parity, parity_status) pos = 0 if type == frame_type_16bit_pos: count = 15 for ss, es, value in bits[3:19]: pos |= value << count count -= 1 elif type == frame_type_18bit_pos: count = 17 for ss, es, value in bits[3:19]: pos |= value << count count -= 1 pos = pos if pos < 131072 else pos - 262144 if(is_y==1): self.y=pos if self.filename != "": self.file.write('%d,%d,%d\n' % (self.x, self.y, self.z)) else: self.x=pos # 显示原始位置 if type in (frame_type_16bit_pos, frame_type_18bit_pos): self.put_ann(type_es, par_ss, pos_ann_id, ['%d' % pos]) # 显示逻辑坐标(3位小数) logic_val = self.calc_logic(pos) self.put_ann(type_es, par_ss, logic_ann_id, ['%.3f' % logic_val]) if type == frame_type_command: count = 7 cmd = 0 cmd_es = 0 for ss, es, value in bits[3:11]: cmd |= value << count count -= 1 cmd_es = es self.put_ann(type_es, cmd_es, ann_command, ['Cmd 0x%X' % cmd]) count = 7 param = 0 for ss, es, value in bits[11:19]: param |= value << count count -= 1 self.put_ann(cmd_es, par_ss, ann_parameter, ['Param 0x%X' % param]) def process_stat_bit(self, sync, bit_ss, bit_es, bit_value): if self.stat_skip_bit: self.stat_skip_bit = False return self.put_ann(bit_ss, bit_es, ann_stat_bit, ['%d' % bit_value]) self.stat_bits.append((bit_ss, bit_es, bit_value)) if (sync == 0) and (len(self.stat_bits) == 19): stat_ss = self.stat_bits[0][0] stat_es = self.stat_bits[18][1] status = 0 count = 18 for ss, es, value in self.stat_bits: status |= value << count count -= 1 self.put_ann(stat_ss, stat_es, ann_status, ['Status 0x%X' % status]) def decode(self): if self.filename != "": self.file = open(self.filename,'w') self.file.write('x,y,z\n') bit_ss = None bit_value = 0 bit_value2 = 0 stat_ss = None stat_value = 0 sync_value = 0 has_stat = self.has_channel(4) while True: clk, sync, data, data2, stat = self.wait({0: 'e'}) if clk == 1: stat_value = stat bit_es = self.samplenum if bit_ss is not None: self.process_bit(sync_value, bit_ss, bit_es, bit_value, bit_value2) bit_ss = self.samplenum else: bit_value = data bit_value2 = data2 sync_value = sync if stat_ss is not None and has_stat: stat_es = self.samplenum self.process_stat_bit(sync_value, stat_ss, stat_es, stat_value) stat_ss = self.samplenum