Menulis dekoder untuk sigrok

gambar



Jika Anda bekerja dengan teknologi digital, maka cepat atau lambat ada kebutuhan untuk penganalisa logika. Salah satu yang tersedia untuk amatir radio adalah penganalisis logika DSLogic dari DreamSourceLab. Dia disebutkan lebih dari sekali di situs, setidaknya: satu , dua dan tiga .



Fiturnya adalah open source , dan juga fakta bahwa perpustakaan sigrok open-source bertanggung jawab atas penguraian sinyal . Seiring dengan daftar decoder sinyal yang ada, perpustakaan ini menyediakan API untuk menulis milik Anda. Ini yang akan kita lakukan.



Demo stand



, . TTP229-BSF. 8- 16- . Arduino, DSLogic.



gambar





, , . , . , , .



Setiap decoder di sigrok adalah paket terpisah yang ditulis dengan Python 3 dan memiliki direktori sendiri di folder decoder. Seperti paket Python lainnya, dekoder berisi __init__.py, dan juga, sesuai dengan konvensi penamaan yang digunakan dalam sigrok, pd.py adalah file yang berisi implementasi aktual.



gambar



Kode dalam __init__.py adalah standar dan termasuk docstring yang menjelaskan protokol, dan impor decoder ( d28dee9 ):



'''
Protocol description.
'''

from .pd import Decoder


File pd.py berisi implementasi decoder ( d28dee9 ):



class Decoder(srd.Decoder):
    api_version = 3
    id = 'empty'
    name = 'empty'
    longname = 'empty decoder'
    desc = 'Empty decoder that can be loaded by sigrok.'
    license = 'mit'
    inputs = ['logic']
    outputs = ['empty']
    tags = ['Embedded/industrial']
    channels = (
        {'id': 'scl', 'name': 'SCL', 'desc': 'Clock'},
        {'id': 'sdo', 'name': 'SDO', 'desc': 'Data'},
    )

    def start(self):
        pass

    def reset(self):
        pass

    def decode(self):
        pass


Ini adalah implementasi minimal yang bisa dimuat pustaka, tetapi tidak memecahkan kode apa pun. Mari menganalisis properti yang diperlukan:



  • api_version – Protocol decoder API, . libsigrokdecode 3- Protocol decoder API. .
  • id – , . , .
  • name, longname, desc – , , . .
  • inputs, outputs – . 'logic' . . , , SPI. SPI . , SPI . 'spi'.
  • license, tag – . DSView 1.1.1 + libsigrokdecode tags - .
  • saluran - daftar saluran sinyal yang digunakan oleh decoder. Properti ini diperlukan untuk decoder yang format data inputnya adalah logika.


dan metode yang dibutuhkan:



  • start () - metode yang dipanggil sebelum decoding dimulai. Dalam metode ini, pengaturan untuk sesi pendekodean saat ini harus dibuat.
  • reset () - metode yang dipanggil saat decoding berhenti. Harus mengembalikan dekoder ke kondisi awal.
  • decode () - metode yang dipanggil untuk mendekode sinyal.


Setelah berurusan dengan implementasi minimal decoder, Anda dapat mulai mendekode sinyal nyata.



Dekoder berfitur lengkap



Pertama, mari kita lihat diagram timing sinyal data. TTP229-BSF memiliki beberapa mode operasi, dan saya hanya menunjukkan diagram waktu untuk mode yang akan digunakan di bawah ini. Informasi lebih rinci tentang semua mode operasi dari rangkaian mikro dapat ditemukan dalam dokumentasi untuknya.



gambar



Hal pertama dan terpenting adalah mendeskripsikan sekumpulan baris yang diperlukan dengan mana decoder akan bekerja. Dalam hal ini, ada dua di antaranya, garis jam (SCL) dan garis data (SDO).



class Decoder(srd.Decoder):
    ...
    inputs = ['logic']
    channels = (
        {'id': 'scl', 'name': 'SCL', 'desc': 'Clock'},
        {'id': 'sdo', 'name': 'SDO', 'desc': 'Data'},
    )


Ketika rangkaian mikro mendeteksi sebuah tombol tekan, ia mengatur sinyal Data Valid (DV) pada jalur SDO, yang dengannya penerima harus mulai membaca data. Mari cari dan dekode sinyal ini.



sigrok , . . , , . Protocol decoder API . . wait(). . , self.samplenum .



, , – , :



  • 'l' - level rendah, logis 0;
  • 'h' - tingkat tinggi, logis 1;
  • 'r' - kenaikan sinyal, transisi dari kondisi rendah ke kondisi tinggi;
  • 'f' - peluruhan sinyal, transisi dari kondisi tinggi ke kondisi rendah;
  • 'e' - mengubah sinyal naik, turun atau turun;
  • 's' adalah kondisi stabil, 0 atau 1.


Jadi, untuk menemukan awal sinyal DV, suatu kondisi yang menggambarkan bahwa jalur SCL tinggi, dan roll-off sinyal terjadi pada jalur data (SDO). Mari kita memanggil fungsi wait () dengan kondisi yang disiapkan dan menyimpan nomor sampel:



        self.wait({0: 'h', 1: 'f'})
        self.dv_block_ss = self.samplenum


untuk menemukan akhir sinyal DV, perlu untuk menetapkan kondisi ketika garis SCL tetap tinggi, dan jalur data menjadi tinggi:

        self.wait({0: 'h', 1: 'r'})


Setelah menyelesaikan panggilan terakhir ke fungsi wait (), nomor sampel dari awal dan akhir sinyal DV akan diketahui. Saatnya membuat anotasi untuk itu. Untuk melakukan ini, tambahkan anotasi ke dekoder dan kelompokkan bersama-sama (annotation_rows):



class Decoder(srd.Decoder):
    ...
    annotations = (
        ('dv', 'Data valid'),
    )
    annotation_rows = (
        ('fields', 'Fields', (0,)),
    )


di mana 0 adalah indeks anotasi di tuple self.annotations yang menjadi milik grup ini. Anda juga perlu mendaftarkan output anotasi:



    def start(self):
        self.out_ann = self.register(srd.OUTPUT_ANN)


Sekarang semuanya siap untuk menempatkan anotasi ke sinyal DV. Ini dilakukan dengan memanggil fungsi put () ( f613b83 ):



        self.put(self.dv_block_ss, self.samplenum,
                 self.out_ann, [0, ['Data valid', 'DV']])


Parameter fungsi: nomor sampel mulai anotasi (self.dv_block_ss), nomor sampel akhir anotasi (self.samplenum), pengidentifikasi output anotasi (self.out_ann) dan data untuk anotasi. Data disajikan dalam bentuk daftar dari indeks anotasi (0) dan daftar garis bersarang, dari yang terpanjang ke yang terpendek, untuk ditampilkan dalam deskripsi. Jika lebih dari satu baris ditentukan, antarmuka dapat secara mandiri memilih garis yang ditampilkan, misalnya, tergantung pada skala yang digunakan:







Demikian pula, kami menambahkan anotasi untuk keterlambatan Tw antara akhir sinyal DV dan awal membaca data dari mikrokontroler. Selanjutnya, Anda dapat mulai mendekode data tombol tekan.



TTP229-BSF, tergantung pada mode yang dipilih, dapat bekerja dengan 8 atau 16 tombol sentuh. Dalam hal ini, data yang dikirimkan tidak mengandung informasi tentang mode operasi dari rangkaian mikro. Oleh karena itu, untuk dekoder, perlu menambahkan opsi yang menentukan mode di mana sirkuit mikro beroperasi.



class Decoder(srd.Decoder):
    ...
    options = (
        {'id': 'key_num', 'desc': 'Key number', 'default': 8,
         'values': (8, 16)},
    )
    def start(self):
        ...
        self.key_num = self.options['key_num']


Opsi ini akan tersedia untuk menetapkan nilai di antarmuka pengguna saat dekoder dipilih.



Seperti yang Anda lihat dari diagram timing, data pada garis SDO diatur ketika SCL pergi ke level aktif (rendah) dan disimpan ketika sinyal kembali ke level pasif. Pada saat ini, baik mikrokontroler dan dekoder dapat memperbaiki set data pada garis SDL. Transisi SCL kembali ke level aktif dapat dianggap sebagai awal pengiriman data berikutnya. Dalam hal ini, fungsi decoding akan terlihat seperti ( ca9a370 ):



    def decode(self):
        self.wait({0: 'h', 1: 'f'})
        self.dv_block_ss = self.samplenum

        self.wait({0: 'h', 1: 'r'})
        self.put(self.dv_block_ss, self.samplenum,
                 self.out_ann, [0, ['Data valid', 'DV']])
        self.tw_block_ss = self.samplenum

        self.wait([{0: 'f', 1: 'h'}, {0: 'f', 1: 'f'}])
        self.put(self.tw_block_ss, self.samplenum,
                 self.out_ann, [1, ['Tw', 'Tw']])
        self.bt_block_ss = self.samplenum

        for i in range(self.key_num):
            (scl, sdo) = self.wait({0: 'r'})
            sdo = 0 if sdo else 1

            self.wait({0: 'f'})
            self.put(self.bt_block_ss, self.samplenum,
                     self.out_ann, [2, ['Bit: %d' % sdo, '%d' % sdo]])
            self.bt_block_ss = self.samplenum


Tetapi pendekatan penempatan anotasi ini memiliki kelemahan, anotasi untuk bit terakhir akan berlanjut sampai data selanjutnya dibaca oleh mikrokontroler.







. . , SCL . , SCL 2 ., . 'skip', , , . , . metadata(). Hz.



    def metadata(self, key, value):
        if key == srd.SRD_CONF_SAMPLERATE:
            self.timeout_samples_num = int(2 * (value / 1000.0))


Kemudian kondisi dalam fungsi decoding akan ditulis menggunakan loncati dalam formulir berikut, ditambah cek tambahan bahwa, saat membaca data tentang tombol yang ditekan, rangkaian mikro tidak kembali ke keadaan awal ( 6a0422d ).



    def decode(self):
        ...
        for i in range(self.key_num):
            ...
            self.wait([{0: 'f'}, {'skip': self.timeout_samples_num}])
            self.put(self.bt_block_ss, self.samplenum,
                     self.out_ann, [2, ['Bit: %d' % sdo, '%d' % sdo]])
            if (self.matched & 0b10) and i != (self.key_num - 1):
                break


Dekoder sekarang dapat menangani pengiriman data yang lengkap. Dan akan lebih mudah jika, selain informasi tentang bit individual, anotasi ditambahkan tentang tombol mana yang ditekan. Untuk melakukan ini, tambahkan deskripsi anotasi lain. Karena anotasi untuk menekan tombol berlaku untuk seluruh pengiriman data dan memotong dengan anotasi yang ditambahkan sebelumnya, maka harus ditempatkan dalam kelompok yang terpisah. Mari buat grup anotasi baru 'Pesan utama' untuk itu. ( 91c64e6 ).



class Decoder(srd.Decoder):
    ...
    annotations = (
        ('dv', 'Data valid'),
        ('tw', 'Tw'),
        ('bit', 'Bit'),
        ('key', 'Key press status'),
    )
    annotation_rows = (
        ('fields', 'Fields', (0, 1, 2)),
        ('keymsg', 'Key message', (3,)),
    )
    def decode(self):
        ...
        keys_pressed = list()

        for i in range(self.key_num):
            ...
        else:
            key_msg = \
                'Key: %s' % (','.join(keys_pressed)) if keys_pressed else 'Key unpressed'
            key_msg_short = \
                'K: %s' % (','.join(keys_pressed)) if keys_pressed else 'KU'

            self.put(self.dv_block_ss, self.samplenum,
                     self.out_ann, [3, [key_msg, key_msg_short]])






Hingga saat itu, semua kode hanya berfungsi dengan paket pertama. Pernahkah Anda memperhatikan 19% di sebelah nama decoder? Ini adalah persentase sampel yang diproses sebelum keluar dari fungsi decode (). Untuk memproses semua sampel, tetap menambahkan loop tanpa akhir di sekitar kode untuk mendekode pengiriman data terpisah ( 48f95fb ).



    def decode(self):
        ...
        while True:
            self.wait({Pin.SCL: self.passive_signal, Pin.SDO: self.front_edge})
            self.dv_block_ss = self.samplenum
            ...


Karena decoding akan secara otomatis berakhir jika fungsi wait () mengulangi semuanya ketika mencari sampel berikutnya. Sebagai hasil dari perubahan ini, semua sampel dan semua transmisi data akan diproses sebagaimana ditunjukkan dalam KDPV .



Sentuhan terakhir tetap menambahkan kemampuan untuk memilih level sinyal aktif dan dekoder penuh untuk TTP229-BSF akan siap. Kode sumber terakhir juga tersedia di GitHub .




All Articles