Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
adigie committed Aug 30, 2023
0 parents commit 322b4dd
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__pycache__/
8 changes: 8 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"[python]": {
"editor.defaultFormatter": "ms-python.autopep8",
},
"autopep8.args": [
"--max-line-length=200"
]
}
146 changes: 146 additions & 0 deletions HighLevelAnalyzer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# MCP2515 High Level Analyzer
# For more information and documentation, please go to https://support.saleae.com/extensions/high-level-analyzer-extensions

from enum import IntEnum
from saleae.analyzers import HighLevelAnalyzer, AnalyzerFrame, StringSetting, NumberSetting, ChoicesSetting
from typing import List, Union


class Instructions(IntEnum):
RESET = 0b1100_0000
READ = 0b0000_0011
WRITE = 0b0000_0010
READ_STATUS = 0b1010_0000
RX_STATUS = 0b1011_0000
BIT_MODIFY = 0b0000_0101


REGISTER_MAP = [
['RXF0SIDH', 'RXF3SIDH', 'RXM0SIDH', 'TXB0CTRL', 'TXB1CTRL', 'TXB2CTRL', 'RXB0CTRL', 'RXB1CTRL'],
['RXF0SIDL', 'RXF3SIDL', 'RXM0SIDL', 'TXB0SIDH', 'TXB1SIDH', 'TXB2SIDH', 'RXB0SIDH', 'RXB1SIDH'],
['RXF0EID8', 'RXF3EID8', 'RXM0EID8', 'TXB0SIDL', 'TXB1SIDL', 'TXB2SIDL', 'RXB0SIDL', 'RXB1SIDL'],
['RXF0EID0', 'RXF3EID0', 'RXM0EID0', 'TXB0EID8', 'TXB1EID8', 'TXB2EID8', 'RXB0EID8', 'RXB1EID8'],
['RXF1SIDH', 'RXF4SIDH', 'RXM1SIDH', 'TXB0EID0', 'TXB1EID0', 'TXB2EID0', 'RXB0EID0', 'RXB1EID0'],
['RXF1SIDL', 'RXF4SIDL', 'RXM1SIDL', 'TXB0DLC', 'TXB1DLC', 'TXB2DLC', 'RXB0DLC', 'RXB1DLC'],
['RXF1EID8', 'RXF4EID8', 'RXM1EID8', 'TXB0D0', 'TXB1D0', 'TXB2D0', 'RXB0D0', 'RXB1D0'],
['RXF1EID0', 'RXF4EID0', 'RXM1EID0', 'TXB0D1', 'TXB1D1', 'TXB2D1', 'RXB0D1', 'RXB1D1'],
['RXF2SIDH', 'RXF5SIDH', 'CNF3', 'TXB0D2', 'TXB1D2', 'TXB2D2', 'RXB0D2', 'RXB1D2'],
['RXF2SIDL', 'RXF5SIDL', 'CNF2', 'TXB0D3', 'TXB1D3', 'TXB2D3', 'RXB0D3', 'RXB1D3'],
['RXF2EID8', 'RXF5EID8', 'CNF1', 'TXB0D4', 'TXB1D4', 'TXB2D4', 'RXB0D4', 'RXB1D4'],
['RXF2EID0', 'RXF5EID0', 'CANINTE', 'TXB0D5', 'TXB1D5', 'TXB2D5', 'RXB0D5', 'RXB1D5'],
['BFPCTRL', 'TEC', 'CANINTF', 'TXB0D6', 'TXB1D6', 'TXB2D6', 'RXB0D6', 'RXB1D6'],
['TXRTSCTRL', 'REC', 'EFLG', 'TXB0D7', 'TXB1D7', 'TXB2D7', 'RXB0D7', 'RXB1D7'],
['CANSTAT', 'CANSTAT', 'CANSTAT', 'CANSTAT', 'CANSTAT', 'CANSTAT', 'CANSTAT', 'CANSTAT'],
['CANCTRL', 'CANCTRL', 'CANCTRL', 'CANCTRL', 'CANCTRL', 'CANCTRL', 'CANCTRL', 'CANCTRL']
]


def get_register_name(register: int) -> str:
lo = (register & 0x0F)
hi = (register & 0xF0) >> 4
return REGISTER_MAP[lo][hi]


def data_to_str(data: bytes) -> str:
return ' '.join((f'0x{byte:02X}' for byte in data))


class MCP2515Hla(HighLevelAnalyzer):
result_types = {
'instruction': {
'format': '{{data.instruction}}'
},
'control_reg': {
'format': '{{data.control_reg}}'
},
'mask': {
'format': 'Mask: {{data.mask}}'
},
'data': {
'format': 'Data: {{data.data}}'
},
}

def __init__(self) -> None:
self.frames = []

def decode(self, frame: AnalyzerFrame) -> Union[AnalyzerFrame, List[AnalyzerFrame], None]:
'''
Process a frame from the input analyzer, and optionally return a single `AnalyzerFrame` or a list of `AnalyzerFrame`s.
The type and data values in `frame` will depend on the input analyzer.
'''

if frame.type == 'enable':
self.frames = []
elif frame.type == 'result':
self.frames.append(frame)
elif frame.type == 'disable':
return self._decode_frames(self.frames)
else:
raise RuntimeError(f'Unexpected frame type: {frame.type}. Please select SPI as an input analyzer.')

return None

def _decode_frames(self, frames: List[AnalyzerFrame]) -> List[AnalyzerFrame]:
output = []

if len(frames) >= 1:
instruction_frame = frames[0]
instruction = Instructions(instruction_frame.data['mosi'][0])
frame = AnalyzerFrame('instruction',
instruction_frame.start_time,
instruction_frame.end_time,
{
'instruction': instruction.name,
})
output.append(frame)

if len(frames) >= 2:
control_reg_frame = frames[1]
control_reg_name = get_register_name(control_reg_frame.data['mosi'][0])
frame = AnalyzerFrame('control_reg',
control_reg_frame.start_time,
control_reg_frame.end_time,
{
'control_reg': control_reg_name,
})
output.append(frame)

if len(frames) >= 3:
if instruction == Instructions.BIT_MODIFY:
mask_frame = frames[2]
mask = mask_frame.data['mosi'][0]
frame = AnalyzerFrame('mask',
mask_frame.start_time,
mask_frame.end_time,
{
'mask': f'0x{mask:02X}',
})
output.append(frame)

data_frames = frames[3:]
else:
data_frames = frames[2:]

if len(data_frames) > 0:
miso = bytearray()
mosi = bytearray()
for frame in data_frames:
miso.extend(frame.data['miso'])
mosi.extend(frame.data['mosi'])

if instruction == Instructions.READ:
data = miso
else:
data = mosi

frame = AnalyzerFrame('data',
data_frames[0].start_time,
data_frames[-1].end_time,
{
'data': data_to_str(data),
})
output.append(frame)

return output
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

# MCP2515-HLA
Saleae Logic 2 HLA (High Level Analyzer) extension for decoding SPI communication with [MCP2515][1] CAN controller.

## Usage
1. Install this extension in Logic 2 Extensions tab.
2. Add SPI analyzer (Enable/Chip Select signal is required).
3. Add MCP2515-HAL analyzer. Use previously added SPI as `Input Analyzer`.


[1]: https://www.microchip.com/en-us/product/mcp2515
13 changes: 13 additions & 0 deletions extension.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "MCP2515-HLA",
"apiVersion": "1.0.0",
"author": "Adrian Gielniewski",
"version": "0.0.1",
"description": "SPI interface analyzer for MCP2515 CAN controller",
"extensions": {
"MCP2515-HLA": {
"type": "HighLevelAnalyzer",
"entryPoint": "HighLevelAnalyzer.MCP2515Hla"
}
}
}

0 comments on commit 322b4dd

Please sign in to comment.