logicmso

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Saleae Logic MSO Analysis

Saleae Logic MSO 捕获数据分析

This skill enables analysis of captured signals from Saleae Logic MSO devices using the
saleae-mso-api
Python library. It supports loading binary exports, analyzing signal transitions, and decoding common protocols.
本技能支持使用
saleae-mso-api
Python库分析来自Saleae Logic MSO设备的捕获信号,可加载二进制导出文件、分析信号转换并解码常见协议。

Prerequisites

前置条件

  • saleae-mso-api
    Python package — Do NOT blindly pip install. First check if it's already installed:
    bash
    python3 -c "from saleae.mso_api.binary_files import read_file; print('saleae-mso-api is available')"
    Only if that fails, install it:
    pip install saleae-mso-api
  • Binary export files from Saleae Logic software (
    .bin
    format)
  • saleae-mso-api
    Python包 — 请勿盲目使用pip安装。请先检查是否已安装:
    bash
    python3 -c "from saleae.mso_api.binary_files import read_file; print('saleae-mso-api is available')"
    只有当上述命令执行失败时,才进行安装:
    pip install saleae-mso-api
  • 来自Saleae Logic软件的二进制导出文件(
    .bin
    格式)

Quick Reference

快速参考

Loading Binary Files

加载二进制文件

python
from saleae.mso_api.binary_files import read_file
from pathlib import Path

file_path = Path("capture.bin")
saleae_file = read_file(file_path)
python
from saleae.mso_api.binary_files import read_file
from pathlib import Path

file_path = Path("capture.bin")
saleae_file = read_file(file_path)

Access metadata

访问元数据

print(f"Version: {saleae_file.version}") print(f"Type: {saleae_file.type}")
print(f"Version: {saleae_file.version}") print(f"Type: {saleae_file.type}")

Access data

访问数据

contents = saleae_file.contents
undefined
contents = saleae_file.contents
undefined

Digital Capture Structure

数字捕获数据结构

Digital exports contain
DigitalExport_V1
with chunks:
python
chunk = saleae_file.contents.chunks[0]
数字导出文件包含
DigitalExport_V1
格式的数据块:
python
chunk = saleae_file.contents.chunks[0]

Key attributes:

关键属性:

chunk.initial_state # Starting logic level (0 or 1) chunk.transition_times # numpy array of transition timestamps (seconds) chunk.sample_rate # Capture rate in Hz chunk.begin_time # Capture start time chunk.end_time # Capture end time
undefined
chunk.initial_state # 初始逻辑电平(0代表低电平,1代表高电平) chunk.transition_times # 信号转换时间戳的numpy数组(单位:秒) chunk.sample_rate # 捕获采样率(单位:Hz) chunk.begin_time # 捕获开始时间 chunk.end_time # 捕获结束时间
undefined

Calculating Pulse Durations

计算脉冲持续时间

python
import numpy as np

times = np.array(chunk.transition_times)
durations_ms = np.diff(times) * 1000  # Convert to milliseconds
python
import numpy as np

times = np.array(chunk.transition_times)
durations_ms = np.diff(times) * 1000  # 转换为毫秒

If initial_state is 0 (LOW):

如果初始状态为0(低电平):

- Even indices (0, 2, 4...) = HIGH pulse durations

- 偶数索引(0、2、4...)= 高电平脉冲持续时间

- Odd indices (1, 3, 5...) = LOW gap durations

- 奇数索引(1、3、5...)= 低电平间隔持续时间

If initial_state is 1 (HIGH):

如果初始状态为1(高电平):

- Even indices = LOW gap durations

- 偶数索引 = 低电平间隔持续时间

- Odd indices = HIGH pulse durations

- 奇数索引 = 高电平脉冲持续时间

undefined
undefined

Helper Scripts

辅助脚本

This skill includes helper scripts for common analysis tasks:
本技能包含用于常见分析任务的辅助脚本:

Protocol Analyzer

协议分析器

bash
undefined
bash
undefined

Analyze signal characteristics

分析信号特征

python3 skills/logicmso/analyze_protocol.py capture.bin
python3 skills/logicmso/analyze_protocol.py capture.bin

Show detailed timing histogram

显示详细时序直方图

python3 skills/logicmso/analyze_protocol.py capture.bin --histogram
python3 skills/logicmso/analyze_protocol.py capture.bin --histogram

Show detected timing clusters

显示检测到的时序聚类

python3 skills/logicmso/analyze_protocol.py capture.bin --clusters
python3 skills/logicmso/analyze_protocol.py capture.bin --clusters

Export transitions to CSV

将信号转换数据导出为CSV

python3 skills/logicmso/analyze_protocol.py capture.bin --export transitions.csv
python3 skills/logicmso/analyze_protocol.py capture.bin --export transitions.csv

Show raw transition values

显示原始转换值

python3 skills/logicmso/analyze_protocol.py capture.bin --raw -n 50
undefined
python3 skills/logicmso/analyze_protocol.py capture.bin --raw -n 50
undefined

Common Protocol Patterns

常见协议模式

UART (Asynchronous Serial)

UART(异步串行协议)

  • Idle state: HIGH
  • Start bit: LOW (1 bit period)
  • Data bits: 8 bits, LSB first
  • Stop bit: HIGH (1-2 bit periods)
  • Common baud rates: 9600, 19200, 38400, 57600, 115200
  • Bit period calculation:
    1/baud_rate
    seconds
  • Identifying features: Consistent bit periods, durations are multiples of base period
  • 空闲状态:高电平
  • 起始位:低电平(持续1个比特周期)
  • 数据位:8位,最低有效位(LSB)优先
  • 停止位:高电平(持续1-2个比特周期)
  • 常见波特率:9600、19200、38400、57600、115200
  • 比特周期计算
    1/baud_rate
  • 识别特征:比特周期一致,持续时间为基础周期的整数倍

SPI (Serial Peripheral Interface)

SPI(串行外设接口)

  • 4 signals: SCLK (clock), MOSI (master out), MISO (master in), CS (chip select)
  • Clock polarity (CPOL): Idle clock state (0=LOW, 1=HIGH)
  • Clock phase (CPHA): Sample edge (0=leading, 1=trailing)
  • Data: Sampled on clock edges, typically 8 bits per transaction
  • Identifying features: Regular clock signal, CS goes LOW during transaction
  • 4路信号:SCLK(时钟)、MOSI(主机输出)、MISO(主机输入)、CS(片选)
  • 时钟极性(CPOL):时钟空闲状态(0=低电平,1=高电平)
  • 时钟相位(CPHA):采样边沿(0=上升沿,1=下降沿)
  • 数据:在时钟边沿采样,通常每笔事务传输8位数据
  • 识别特征:规律的时钟信号,事务期间CS变为低电平

I2C (Inter-Integrated Circuit)

I2C(集成电路间总线)

  • 2 signals: SDA (data), SCL (clock)
  • Idle state: Both HIGH (pulled up)
  • Start condition: SDA falls while SCL is HIGH
  • Stop condition: SDA rises while SCL is HIGH
  • Data: 8 bits + ACK/NACK, MSB first
  • Address: 7-bit (first byte after START)
  • Identifying features: START/STOP conditions, 9 clock pulses per byte (8 data + ACK)
  • 2路信号:SDA(数据)、SCL(时钟)
  • 空闲状态:两路信号均为高电平(上拉)
  • 起始条件:SCL为高电平时,SDA出现下降沿
  • 停止条件:SCL为高电平时,SDA出现上升沿
  • 数据:8位数据+1位ACK/NACK,最高有效位(MSB)优先
  • 地址:7位地址(起始条件后的第一个字节)
  • 识别特征:起始/停止条件,每个字节对应9个时钟脉冲(8位数据+1位ACK)

1-Wire

1-Wire(单总线协议)

  • Single signal: DQ (data/power)
  • Idle state: HIGH (pulled up)
  • Reset pulse: Master pulls LOW for 480us minimum
  • Presence pulse: Slave responds LOW for 60-240us
  • Write 0: LOW for 60-120us
  • Write 1: LOW for 1-15us, then release
  • Read: Master samples 15us after pulling LOW
  • 单路信号:DQ(数据/电源)
  • 空闲状态:高电平(上拉)
  • 复位脉冲:主机拉低电平至少480微秒
  • 存在脉冲:从机响应拉低电平60-240微秒
  • 写0:拉低电平60-120微秒
  • 写1:拉低电平1-15微秒后释放
  • 读操作:主机拉低电平15微秒后采样信号

Analysis Workflow

分析流程

Step 1: Initial Exploration

步骤1:初始探索

python
from saleae.mso_api.binary_files import read_file
import numpy as np

f = read_file("capture.bin")
chunk = f.contents.chunks[0]

print(f"Sample rate: {chunk.sample_rate/1e6:.1f} MHz")
print(f"Duration: {chunk.end_time - chunk.begin_time:.3f}s")
print(f"Initial state: {'HIGH' if chunk.initial_state else 'LOW'}")
print(f"Transitions: {len(chunk.transition_times)}")
python
from saleae.mso_api.binary_files import read_file
import numpy as np

f = read_file("capture.bin")
chunk = f.contents.chunks[0]

print(f"采样率:{chunk.sample_rate/1e6:.1f} MHz")
print(f"捕获时长:{chunk.end_time - chunk.begin_time:.3f}秒")
print(f"初始状态:{'高电平' if chunk.initial_state else '低电平'}")
print(f"信号转换次数:{len(chunk.transition_times)}")

Step 2: Analyze Timing Patterns

步骤2:分析时序模式

python
times = np.array(chunk.transition_times)
durations_us = np.diff(times) * 1e6  # microseconds
python
times = np.array(chunk.transition_times)
durations_us = np.diff(times) * 1e6  # 转换为微秒

Separate HIGH and LOW durations

分离高电平和低电平持续时间

high_idx = 0 if chunk.initial_state == 0 else 1 high_durations = durations_us[high_idx::2] low_durations = durations_us[(1-high_idx)::2]
print(f"HIGH pulses: min={min(high_durations):.1f}us, max={max(high_durations):.1f}us") print(f"LOW gaps: min={min(low_durations):.1f}us, max={max(low_durations):.1f}us")
high_idx = 0 if chunk.initial_state == 0 else 1 high_durations = durations_us[high_idx::2] low_durations = durations_us[(1-high_idx)::2]
print(f"高电平脉冲:最小值={min(high_durations):.1f}us,最大值={max(high_durations):.1f}us") print(f"低电平间隔:最小值={min(low_durations):.1f}us,最大值={max(low_durations):.1f}us")

Find unique timing values (cluster detection)

查找唯一时序值(聚类检测)

unique_high = sorted(set(round(d, -1) for d in high_durations)) # Round to 10us unique_low = sorted(set(round(d, -1) for d in low_durations)) print(f"HIGH clusters: {unique_high}") print(f"LOW clusters: {unique_low}")
undefined
unique_high = sorted(set(round(d, -1) for d in high_durations)) # 四舍五入到10微秒 unique_low = sorted(set(round(d, -1) for d in low_durations)) print(f"高电平聚类:{unique_high}") print(f"低电平聚类:{unique_low}")
undefined

Step 3: Identify Protocol

步骤3:识别协议

Based on timing patterns:
  • UART: Consistent bit periods, durations are multiples of base period, idles HIGH
  • SPI/I2C: us-scale timing, needs clock signal analysis, look for regular patterns
  • 1-Wire: Reset pulses ~480us, data pulses 1-120us
基于时序模式:
  • UART:比特周期一致,持续时间为基础周期的整数倍,空闲状态为高电平
  • SPI/I2C:微秒级时序,需要分析时钟信号,寻找规律模式
  • 1-Wire:复位脉冲约480微秒,数据脉冲1-120微秒

Step 4: Decode

步骤4:解码

Once protocol is identified, decode based on protocol rules. For unknown/custom protocols, analyze the timing clusters and bit patterns to determine encoding scheme.
确定协议后,根据协议规则进行解码。对于未知/自定义协议,分析时序聚类和比特模式以确定编码方案。

UART Decoding Example

UART解码示例

python
from saleae.mso_api.binary_files import read_file
import numpy as np

f = read_file("uart_capture.bin")
chunk = f.contents.chunks[0]
times = np.array(chunk.transition_times)

BAUD = 115200
BIT_PERIOD = 1 / BAUD

def decode_uart_byte(start_time, times, bit_period):
    """Decode a single UART byte starting at start_time."""
    byte_val = 0
    for bit_num in range(8):
        # Sample at center of each bit (1.5, 2.5, 3.5... bit periods from start)
        sample_time = start_time + (1.5 + bit_num) * bit_period
        # Find state at sample_time
        idx = np.searchsorted(times, sample_time)
        state = (chunk.initial_state + idx) % 2
        if state:
            byte_val |= (1 << bit_num)  # LSB first
    return byte_val
python
from saleae.mso_api.binary_files import read_file
import numpy as np

f = read_file("uart_capture.bin")
chunk = f.contents.chunks[0]
times = np.array(chunk.transition_times)

BAUD = 115200
BIT_PERIOD = 1 / BAUD

def decode_uart_byte(start_time, times, bit_period):
    """解码从start_time开始的单个UART字节。"""
    byte_val = 0
    for bit_num in range(8):
        # 在每个比特的中间位置采样(从起始点开始1.5、2.5、3.5...个比特周期)
        sample_time = start_time + (1.5 + bit_num) * bit_period
        # 查找采样时间点的信号状态
        idx = np.searchsorted(times, sample_time)
        state = (chunk.initial_state + idx) % 2
        if state:
            byte_val |= (1 << bit_num)  # 最低有效位优先
    return byte_val

Find start bits (falling edges when idle HIGH)

查找起始位(空闲高电平时的下降沿)

decoded_bytes = [] i = 0 while i < len(times) - 1: # Look for falling edge (start bit) if chunk.initial_state == 1 or i > 0: byte_val = decode_uart_byte(times[i], times, BIT_PERIOD) decoded_bytes.append(byte_val) # Skip to next potential start bit (after stop bit) i += 1 while i < len(times) and times[i] < times[i-1] + 10 * BIT_PERIOD: i += 1 else: i += 1
print("Decoded:", bytes(decoded_bytes))
undefined
decoded_bytes = [] i = 0 while i < len(times) - 1: # 查找下降沿(起始位) if chunk.initial_state == 1 or i > 0: byte_val = decode_uart_byte(times[i], times, BIT_PERIOD) decoded_bytes.append(byte_val) # 跳转到下一个潜在的起始位(跳过停止位) i += 1 while i < len(times) and times[i] < times[i-1] + 10 * BIT_PERIOD: i += 1 else: i += 1
print("解码结果:", bytes(decoded_bytes))
undefined

CTF Tips

CTF技巧

  1. Unknown protocol: Start with
    analyze_protocol.py --clusters
    to see timing distribution
  2. Multiple channels: Export each channel separately, identify clock vs data lines
  3. Inverted signals: Some captures have inverted logic levels
  4. Timing variations: Real hardware has jitter, use threshold-based detection
  5. Partial captures: Check if capture starts mid-transmission
  6. Custom protocols: Look for repeating patterns, identify sync/framing bytes
  1. 未知协议:先运行
    analyze_protocol.py --clusters
    查看时序分布
  2. 多通道数据:单独导出每个通道的数据,区分时钟线和数据线
  3. 信号反转:部分捕获数据的逻辑电平是反转的
  4. 时序偏差:实际硬件存在抖动,使用基于阈值的检测方法
  5. 不完整捕获:检查捕获是否在传输过程中开始
  6. 自定义协议:寻找重复模式,识别同步/帧字节

Troubleshooting

故障排查

"No module named 'saleae.mso_api'"

提示“No module named 'saleae.mso_api'”

First verify it's truly missing:
bash
python3 -c "from saleae.mso_api.binary_files import read_file"
Only if the import fails, install it:
bash
pip install saleae-mso-api
先确认库确实未安装:
bash
python3 -c "from saleae.mso_api.binary_files import read_file"
只有当导入失败时,再执行安装:
bash
pip install saleae-mso-api

Empty or corrupt file

文件为空或损坏

Check file size and try re-exporting from Saleae Logic software.
检查文件大小,尝试从Saleae Logic软件重新导出。

No transitions detected

未检测到信号转换

  • Signal may be constant (stuck high/low)
  • Check if correct channel was exported
  • Verify trigger settings in original capture
  • 信号可能为恒定电平(一直高/低)
  • 检查是否导出了正确的通道
  • 验证原始捕获中的触发设置

Timing seems wrong

时序结果异常

  • Check sample rate matches original capture settings
  • Verify time units (seconds vs milliseconds vs microseconds)
  • 检查采样率是否与原始捕获设置一致
  • 确认时间单位(秒、毫秒、微秒)是否正确