Sigrok - Custom Protocol Decoder

En los próximos meses estaré usando unos IC de Texas Instruments que se configuran por SPI, y seguramente tendré que debuggear la comunicación SPI entre el PSoC y los IC con el analizador lógico (LA) y Sigrok-cli o Pulseview, pero me da pereza aprenderme los comandos y las direcciones de los registros para saber a que registro le estoy escribiendo/leyendo.
Así que se me ocurrió hacer un PD (Protocol Decoder) para estos IC, asi puedo aprender a hacer los PDs y además aprender Python.

Iré añadiendo al post las cosas que vaya haciendo y aprendiendo.

Primero tenemos que leer la documentación que nos da Sigrok:
 Además podemos checar el código de los PDs que trae sigrok-cli o Pulseview, el código fuente esta disponible aquí.

Introducción

Todos los PDs son escritos en Python (>= 3.0)

Archivos

Para empezar debemos de crear una carpeta nueva dentro del directorio decoders que esta dentro del directorio libsigrokdecode, esta carpeta va a contener dos archivos con extención .py:
  • __init__.py 
  • pd.py
Mis ICs tienen por nombre TDC1000 y TDC7200, así que cree dos carpetas con esos nombres dentro de la libsigrokdecode/decoders/.
En Windows cree una variable de usuario SIGROKDECODE_DIR que apunta a %USERPROFILE%\Desktop\libsigrokdecode\decoders\ , la explicacion en el Protocol decoder HOWTO.
y podemos comprobar que la reconoce escribiendo lo siguiente en una terminal:
$sigrok-cli -V


Y en Ubuntu la cree en /usr/share/libsigrokdecode2/decoders/
y podemos comprobar que la reconoce escribiendo lo siguiente en una terminal:
$sigrok-cli -V

TDC1000 y TDC7200 en Ubuntu
Igualmente PulseView reconoce los Protocol Decoders.


Como no se mucho de Python tomé como base el código del PD para los nRF24L01 que ya esta incorporado en Sigrok, puedes ver su código fuente aquí.

__init__.py

Este es un archivo Python normal, que es requerido en todos los modulos Python. Debe contener una breve descripción de que hace el protocolo, y algunas notas o tips para el usuario de este PD.
Aqui el ejemplo del __init__.py de I2C.
1
2
3
4
5
6
7
8
'''
 I²C (Inter-Integrated Circuit) is a bidirectional, multi-master
 bus using two signals (SCL = serial clock line, SDA = serial data line).
 
 <Insert notes and hints for the user here>
 '''
 
 from .pd import Decoder
La linea "from .pd import Decoder" se asegura que el código del archivo pd.py se importa correctamente cuando se usa este modulo.

pd.py

Este archivo contiene información acerca del decodificador, y el código que ejecuta, mayormente en el método decoder().
A continuación el ejemplo de pd.py del decodificador I2C.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
 import sigrokdecode as srd
 
 class Decoder(srd.Decoder):
     api_version = 2
     id = 'i2c'
     name = 'I²C'
     longname = 'Inter-Integrated Circuit'
     desc = 'Two-wire, multi-master, serial bus.'
     license = 'gplv2+'
     inputs = ['logic']
     outputs = ['i2c']
     channels = (
         {'id': 'scl', 'name': 'SCL', 'desc': 'Serial clock line'},
         {'id': 'sda', 'name': 'SDA', 'desc': 'Serial data line'},
     )
     optional_channels = ()
     options = (
         {'id': 'address_format', 'desc': 'Displayed slave address format',
            'default': 'shifted', 'values': ('shifted', 'unshifted')},
     )
     annotations = (
         ('start', 'Start condition'),
         ('repeat-start', 'Repeat start condition'),
         ('stop', 'Stop condition'),
         ('ack', 'ACK'),
         ('nack', 'NACK'),
         ('bit', 'Data/address bit'),
         ('address-read', 'Address read'),
         ('address-write', 'Address write'),
         ('data-read', 'Data read'),
         ('data-write', 'Data write'),
         ('warnings', 'Human-readable warnings'),
     )
     annotation_rows = (
         ('bits', 'Bits', (5,)),
         ('addr-data', 'Address/Data', (0, 1, 2, 3, 4, 6, 7, 8, 9)),
         ('warnings', 'Warnings', (10,)),
     )
 
     def __init__(self, **kwargs):
         self.state = 'FIND START'
         # And various other variable initializations...
 
     def metadata(self, key, value):
         if key == srd.SRD_CONF_SAMPLERATE:
             self.samplerate = value
 
     def start(self):
         self.out_ann = self.register(srd.OUTPUT_ANN)
 
     def decode(self, ss, es, data):
         for self.samplenum, (scl, sda) in data:
             # Decode the samples.

Para no hacer muy largo el post, la implementación de cada PD la haré en un post diferente:
  • TDC1000
  • TDC7200

Comentarios

Entradas más populares de este blog

PSoC Creator Tools

PSoC5LP Usando el SAR ADC y la señal EoS para manejar una LUT