From ebc6cd06ade47f50bf84f26fc49e6b42252160b3 Mon Sep 17 00:00:00 2001 From: HL Yi Date: Sun, 21 Jun 2026 13:04:04 -0500 Subject: [PATCH] add utilities for led and gpio dump and detection --- tools/led_gpio_utils/README.md | 139 +++++++++++++++++++++ tools/led_gpio_utils/dec_leds_from_dump.py | 95 ++++++++++++++ tools/led_gpio_utils/i2c_dump_rtl_regs.py | 37 ++++++ tools/led_gpio_utils/i2c_read_rtl_gpio.py | 69 ++++++++++ 4 files changed, 340 insertions(+) create mode 100644 tools/led_gpio_utils/README.md create mode 100755 tools/led_gpio_utils/dec_leds_from_dump.py create mode 100755 tools/led_gpio_utils/i2c_dump_rtl_regs.py create mode 100755 tools/led_gpio_utils/i2c_read_rtl_gpio.py diff --git a/tools/led_gpio_utils/README.md b/tools/led_gpio_utils/README.md new file mode 100644 index 0000000..4205e68 --- /dev/null +++ b/tools/led_gpio_utils/README.md @@ -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]) diff --git a/tools/led_gpio_utils/dec_leds_from_dump.py b/tools/led_gpio_utils/dec_leds_from_dump.py new file mode 100755 index 0000000..92a1d88 --- /dev/null +++ b/tools/led_gpio_utils/dec_leds_from_dump.py @@ -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<>(i<<1)) & 3 + print(f"Port {i}: SET {sel}: {', '.join(led_set_str[sel])}") diff --git a/tools/led_gpio_utils/i2c_dump_rtl_regs.py b/tools/led_gpio_utils/i2c_dump_rtl_regs.py new file mode 100755 index 0000000..de69a55 --- /dev/null +++ b/tools/led_gpio_utils/i2c_dump_rtl_regs.py @@ -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}") \ No newline at end of file diff --git a/tools/led_gpio_utils/i2c_read_rtl_gpio.py b/tools/led_gpio_utils/i2c_read_rtl_gpio.py new file mode 100755 index 0000000..0c505c6 --- /dev/null +++ b/tools/led_gpio_utils/i2c_read_rtl_gpio.py @@ -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<