I’m trying create an extension that can decode frames with specific devices in mind. These devices read and write in 3 8 bit messages. The first bit is a read/write indicator followed by 6 address bits, 16 data bits and a parity bit. I want to be able to easily determine if the message is r/w and decode the address and data but this is made difficult because the data portion expands 1 bit into the first byte. I’m having trouble figuring out where to start because of the lack of debug options, though I have altered the demo SPI analyzer to generate messages similar to what i expect. Specifically I’m not seeing where i can access the bits to do any operations on them to decode them differently and when looking at the API the AnalyzerFrame object only has these variables exposed. is it even possible to analyze 3 bytes at a time? Any help would be greatly appreciated.
Is the frame really 3 x 8 bit, or can it be considered 1 x 24 bit frame containing a number of fields? If you set the “Bits per transfer” to 24 does that help fix the issue?
If it really is 3 separate bytes you can set up your Python decoder object to fetch three bytes and save them before generating an output frame.
It is 3 x 8 bit transmissions, but selecting 24 bits does grab the frames correctly. Does the dict variable contain all frame in the capture? Also would i do manipulate the decoder in the decode() function? Are there any examples of how this would be done?
The SPI - Frame Format documentation describes MOSI and MISO as containing “bytes” which suggests that all the data bits are contained in those properties.
There are a number of SPI decoder extensions in the downloadable Extensions list in Logic 2. You could install one of those and take a look at the code for it to see how it goes about business. On Windows, with a little digging, you can find the .py file for extensions in %appdata%/Logic/Marketplace/nnn where nnn is a numbered folder.
Thanks for the response. I’m almost there but having an issue returning the new frame.
EDIT:
I’ve update the code and can now get an output, but the instance variables are not being passed in the AnalyzerFrame object. If i remove the class variables i get an error stating they do not exit.
Here is my code
class Hla(HighLevelAnalyzer):
device_setting = ChoicesSetting(choices=('Mixer', 'DAC'))
result_types = {
'Mixer': {
'format': '{{task}} @ Address {{address}} Data: {{data}} with parity {{parity}}. '
# 'format': '{{task}}'
},
'DAC': {
'format': 'Address {{data.address}}'
}
}
task = ''
address = ''
data = ''
parity = ''
def __init__(self):
print("Settings:", self.device_setting)
def decode(self, frame: AnalyzerFrame):
'''
Process a frame from the input analyzer, and optionally return a single `AnalyzerFrame` or a list of `AnalyzerFrame`s.
'''
self.task
self.address
self.data
self.parity
if self.device_setting == 'Mixer':
if not len(frame.data) == 0:
print(frame.data)
if len(frame.data['mosi']) != 3:
print('Set analyser Bits Per Transfer to 24')
return
self.address = ((frame.data['mosi'][0] & 0x7E) >> 1).to_bytes(1, 'big').hex().upper()
parity = (frame.data['mosi'][2] & 0x01)
if parity == 0:
parity = 'Off'
else:
self.parity = 'On'
print(f'Address {self.address}')
print(f'Parity {self.parity}')
if (frame.data['mosi'][0] & 0x80) != 0:
self.task = 'Write Mode'
print(self.task)
self.data = ((frame.data['mosi'][0] & 0x01) << 7)
self.data = ((self.data << 8 ) | (frame.data['mosi'][1] << 7) | ((frame.data['mosi'][2] & 0xFE) >> 1)).to_bytes(2, 'big').hex().upper()
print(f'Data 0x{self.data}')
else:
self.task = 'Read Mode'
print(self.task)
self.data = ((frame.data['miso'][0] & 0x01) << 7)
self.data = ((self.data << 8 ) | (frame.data['miso'][1] << 7) | ((frame.data['miso'][2] & 0xFE) >> 1)).to_bytes(2, 'big').hex().upper()
print(f'Data 0x{self.data}')
return AnalyzerFrame('Mixer', frame.start_time, frame.end_time, {
'task': self.task,
'address': self.address,
'data': self.data,
'parity': self.parity
})
I’m not getting an error, the strings variables are not being passed back in the frame. The rest of the text shows up just not the vars (address, mode, data, parity).
EDIT: Figured out a small part of the issue and adjusted the code. The issue is the format of my returned AnalyzerFrame. i can print the expected message fine before returning the frame.
class Hla(HighLevelAnalyzer):
device_setting = ChoicesSetting(choices=('Mixer', 'DAC'))
result_types = {
'Mixer': {
'format': '{{task}} @ Address {{address}} --- Data: {{data}} with parity {{parity}}'
# 'format': '{{task}}'
},
'DAC': {
'format': 'Address {{result.address}}'
}
}
def __init__(self):
print("Settings:", self.device_setting)
def decode(self, frame: AnalyzerFrame):
'''
Process a frame from the input analyzer, and optionally return a single `AnalyzerFrame` or a list of `AnalyzerFrame`s.
'''
if self.device_setting == 'Mixer':
if not len(frame.data) == 0:
print(frame.data)
if len(frame.data['mosi']) != 3:
print('Set analyser Bits Per Transfer to 24')
return
self.address = ((frame.data['mosi'][0] & 0x7E) >> 1).to_bytes(1, 'big').hex().upper()
self.parity = (frame.data['mosi'][2] & 0x01)
if self.parity == 0:
self.parity = 'Off'
else:
self.parity = 'On'
print(f'Address {self.address}')
print(f'Parity {self.parity}')
if (frame.data['mosi'][0] & 0x80) != 0:
self.task = 'Write Mode'
print(self.task)
self.data = ((frame.data['mosi'][0] & 0x01) << 7)
self.data = ((self.data << 8 ) | (frame.data['mosi'][1] << 7) | ((frame.data['mosi'][2] & 0xFE) >> 1)).to_bytes(2, 'big').hex().upper()
print(f'Data 0x{self.data}')
else:
self.task = 'Read Mode'
print(self.task)
self.data = ((frame.data['miso'][0] & 0x01) << 7)
self.data = ((self.data << 8 ) | (frame.data['miso'][1] << 7) | ((frame.data['miso'][2] & 0xFE) >> 1)).to_bytes(2, 'big').hex().upper()
print(f'Data 0x{self.data}')
print(f'{self.task} @ Address {self.address} --- Data: {self.data} with parity {self.parity}')
return AnalyzerFrame('Mixer', frame.start_time, frame.end_time, {
'task': self.task,
'address': self.address,
'data': self.data,
'parity': self.parity
})
Figured out the issue. Looks like result_types can only return one variable at a time. I got around it by returning a string and building the string with the variables.