add utilities for led and gpio dump and detection

This commit is contained in:
HL Yi
2026-06-21 13:04:04 -05:00
parent f122402bdd
commit ebc6cd06ad
4 changed files with 340 additions and 0 deletions
+139
View File
@@ -0,0 +1,139 @@
# LED GPIO Utilities
This directory contains utility talking to RTL837x switch IC via I2C bus. These scripts are designed to help with monitoring, debugging GPIO, and identifying LED configurations.
## Hardware requirements
To use these utilities, you need:
- A hardware dongle that can communicate with I2C devices. One example is the [I2C-Pico-USB](https://github.com/dquadros/I2C-Pico-USB) which provides USB-to-I2C connectivity.
- Connection between the hardware dongle and the RTL837x's I2C communication port.
## Scripts
### 1. `i2c_read_rtl_gpio.py`
This script reads RTL GPIO register values via I2C and displays changes in GPIO states.
**Features:**
- Reads live RTL GPIO register values via I2C (default address 0x5C)
- Monitors GPIO changes with delta detection
- Allows specification of I2C bus, sleep interval, and ignored GPIO pins
- Shows changes in real-time with GPIO index display
**Usage:**
```bash
# Basic usage (defaults to I2C bus 1, 2s sleep interval)
python3 i2c_read_rtl_gpio.py
# Specify I2C bus
python3 i2c_read_rtl_gpio.py --i2c-bus 0
# Specify sleep interval in seconds
python3 i2c_read_rtl_gpio.py --sleep-interval 5
# Ignore specific GPIO pins
python3 i2c_read_rtl_gpio.py --ignored-ios 28 31 34 44
# Combine options
python3 i2c_read_rtl_gpio.py --i2c-bus 2 --sleep-interval 1 --ignored-ios 28 31
```
**Output Format:**
- Displays register address and data in hex format
- Shows GPIO pins that have changed since last read
- Example: `0044: 00 00 00 00 00 00 00 00`
### 2. `i2c_dump_rtl_regs.py`
This script dumps all register values from an RTL device via I2C.
**Features:**
- Dumps registers sequentially from address 0x0000 to 0xFFFF
- Reads 16 bytes at a time for efficiency
- Configurable I2C bus number
- Provides complete register dump in hex format
**Usage:**
```bash
# Basic usage (defaults to I2C bus 1)
python3 i2c_dump_rtl_regs.py >reg_dump.txt
# Specify I2C bus
python3 i2c_dump_rtl_regs.py --bus 0 >reg_dump.txt
# Or using short option
python3 i2c_dump_rtl_regs.py -b 2 >reg_dump.txt
```
**Output Format:**
- Displays address and 16 bytes of data in hex format
- Example: `0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00`
### 3. `dec_leds_from_dump.py`
This script decodes LED configuration from a register dump file ( the output from `i2c_dump_rtl_regs.py`).
**Features:**
- Parses register dump files (reg_dump.txt format)
- Decodes LED pad configurations and LED sets
- Maps LED types to bit positions based on configuration
- Outputs LED mux configuration and set mappings
**Usage:**
```bash
# Must be run in same directory as reg_dump.txt
python3 dec_leds_from_dump.py
```
**Output Format:**
- LED pad configuration (hex values for each pad)
- LED set configurations with descriptions of LED types
- Port selection mappings
**Requirements:**
- Requires a `reg_dump.txt` file containing the register dump output
## Requirements
All scripts require:
- Python 3
- `smbus2` Python package
Install with:
```bash
pip3 install smbus2
```
## Common Usage Patterns
### Monitoring GPIO Changes
```bash
# Monitor GPIO changes on bus 1 with 1-second intervals
python3 i2c_read_rtl_gpio.py --i2c-bus 1 --sleep-interval 1
```
### Register Analysis
```bash
# Dump all device registers
python3 i2c_dump_rtl_regs.py --bus 2 > reg_dump.txt
# Analyze the register dump to understand LED configuration
python3 dec_leds_from_dump.py
```
## Configuration
All scripts support command-line arguments for flexible configuration:
- `--i2c-bus` or `-b`: Specify I2C bus (default: 1)
- `--sleep-interval` or `-s`: Sleep between reads in seconds (default: 2)
- `--ignored-ios` or `-i`: GPIO pins to ignore (default: [28, 31, 34, 44])
+95
View File
@@ -0,0 +1,95 @@
#!/usr/bin/env python3
#!/usr/bin/env python3
import os
import sys
regs = list(range(65536))
glb_mux = 0x65E0
led3_0_set1 = 0x6528
led1_0_set0 = 0x6548
led_port_sel = 0x654c
def get_word(i):
val = (regs[i+3] <<24) + (regs[i+2]<<16) + (regs[i+1]<<8) + regs[i]
# print(f"READING {i:04x} : {val:08x}")
return val
with open ('reg_dump.txt', 'r') as file:
for line in file:
(addr, data) = line.split(":")
data = [ int(x, 16) for x in data.strip().split(" ") ]
addr = int(addr, 16)
for x in range(len(data)):
regs[addr + x] = data[x]
ledstr = []
ledfmt = []
print("LED pad Configuration:")
for i in range(28):
j = i % 5
if j == 0:
idx = glb_mux + (i//5)*4
val = get_word(idx)
ledval = (val>>(6*j)) &0x3f
ledstr.append(f"{ledval:02x}")
ledfmt.append(f"{i:02x}")
print(f"{' '.join(ledfmt)}")
print(f"{' '.join(ledstr)}")
print(f".led_mux = {{ 0x{', 0x'.join(ledstr)} }},")
LED_TYPES = [
" 2G5",
" TWO_1G",
" 1G",
" 500M",
" 100M",
" 10M",
" LINK",
" LINK_FLASH",
" ACT",
" RX",
" TX",
" COL",
" DUPLEX",
" TRAINING",
" MASTER",
"",
" 10G",
" TWO_5G",
" 5G",
" TWO_2G5",
]
led_set = []
led_set_str = []
print("\nLED-set Configuration:")
print("LED-ID 0 1 2 3")
for i in range(4):
idval = []
idvalstr = []
for id in range(4):
val = 0xffff & ( get_word(led1_0_set0 - 8*i - ((id>>1)<<2)) >> (16*(id&1)) )
valhi = ( 0xf & ( get_word(led3_0_set1 - 4*(i>>1)) >> (16*(i&1) + 4*id)) ) << 16
val += valhi
idval.append(val)
valstr = "("
for bit in range(20):
if val & (1<<bit):
valstr += LED_TYPES[bit]
valstr += ")"
idvalstr.append(valstr)
led_set.append(idval)
led_set_str.append(idvalstr)
idstr = ' '.join([f"{d:05x}" for d in idval])
print(f"SET {i}: {idstr}")
# print(f"{idvalstr}")
portsel = get_word(led_port_sel)
for i in range(3,9):
sel = (portsel>>(i<<1)) & 3
print(f"Port {i}: SET {sel}: {', '.join(led_set_str[sel])}")
+37
View File
@@ -0,0 +1,37 @@
#!/usr/bin/env python3
import time
import argparse
from smbus2 import SMBus, i2c_msg
# Configuration
DEFAULT_I2C_BUS = 1
DEVICE_ADDR = 0x5C # Replace with your device address
NUM_BYTES = 16 # Bytes to read
# Parse command line arguments
parser = argparse.ArgumentParser(description='Dump RTL registers via I2C')
parser.add_argument('-b', '--bus', type=int, default=DEFAULT_I2C_BUS,
help='I2C bus number (default: {})'.format(DEFAULT_I2C_BUS))
args = parser.parse_args()
I2C_BUS = args.bus
# Open I2C bus
with SMBus(I2C_BUS) as bus:
for addr in range (0, 65536, NUM_BYTES):
# Create write message (send register address)
write = i2c_msg.write(DEVICE_ADDR, [addr>>8, addr & 0xff])
# Create read message (read 2 bytes)
read = i2c_msg.read(DEVICE_ADDR, NUM_BYTES)
# Perform combined transaction
bus.i2c_rdwr(write, read)
new_data = list(read)
# Convert read message to string
datastr = " ".join([ f"{x:02x}" for x in new_data])
print(f"{addr:04x}: {datastr}")
+69
View File
@@ -0,0 +1,69 @@
#!/usr/bin/env python3
import time
import sys
import argparse
from smbus2 import SMBus, i2c_msg
# Configuration
I2C_BUS = 1
DEVICE_ADDR = 0x5C # Replace with your device address
NUM_BYTES = 8 # Bytes to read
SLEEP_INTERVAL = 2
# Handle command line arguments for ignored IOs
IGNORED_IOS = [ 28, 31, 34, 44]
# Setup argument parser
parser = argparse.ArgumentParser(description='Read I2C data from RTL GPIO expander')
parser.add_argument('--i2c-bus', '-b', type=int, default=1,
help='I2C bus number (default: 1)')
parser.add_argument('--sleep-interval', '-s', type=int, default=2,
help='Sleep interval in seconds (default: 2)')
parser.add_argument('--ignored-ios', '-i', nargs='*', type=int, default=[28, 31, 34, 44],
help='List of GPIO pins to ignore (default: [28, 31, 34, 44])')
args = parser.parse_args()
I2C_BUS = args.i2c_bus
SLEEP_INTERVAL = args.sleep_interval
IGNORED_IOS = args.ignored_ios
first_read = True
last_data = [ 0 for x in range(NUM_BYTES) ]
# Open I2C bus
with SMBus(I2C_BUS) as bus:
addr = 0x44
while True:
# Create write message (send register address)
write = i2c_msg.write(DEVICE_ADDR, [addr>>8, addr & 0xff])
# Create read message (read NUM_BYTES bytes)
read = i2c_msg.read(DEVICE_ADDR, NUM_BYTES)
# Perform combined transaction
bus.i2c_rdwr(write, read)
new_data = list(read)
if first_read:
delta_data = last_data
first_read = False
else:
delta_data = [new_data[x] ^ last_data[x] for x in range(NUM_BYTES)]
last_data = new_data
# Convert read message to list
datastr = " ".join([ f"{x:02x}" for x in new_data])
deltastr = ""
chg_list = []
for x in range(NUM_BYTES):
if delta_data[x] == 0:
continue
for y in range(8):
if delta_data[x] & ( 1<<y):
idx = x*8 + y
if idx not in IGNORED_IOS:
deltastr += f"\n{' ':8s}GPIO{idx}"
# deltastr = " ".join([ f"{x:02x}" for x in delta_data])
print(f"{addr:04x}: {datastr}{deltastr}")
time.sleep(SLEEP_INTERVAL)