Skip to content

Commit dad6318

Browse files
Update version to 1.2.11 in pyproject.toml. Enhance GPIO configuration by adding a '--view' flag to display the current GPIO settings summary without editing. Remove the deprecated 'gpio-status' command to streamline functionality.
1 parent 550a762 commit dad6318

2 files changed

Lines changed: 22 additions & 120 deletions

File tree

chipfoundry_cli/main.py

Lines changed: 21 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,8 @@ def init(project_root):
350350

351351
@main.command('gpio-config')
352352
@click.option('--project-root', required=False, type=click.Path(exists=True, file_okay=False), help='Path to the project directory (defaults to current directory).')
353-
def gpio_config(project_root):
353+
@click.option('--view', is_flag=True, help='Display current GPIO configuration summary without editing.')
354+
def gpio_config(project_root, view):
354355
"""Configure GPIO settings interactively and save to project config and user_defines.v."""
355356
if not project_root:
356357
project_root = os.getcwd()
@@ -547,6 +548,17 @@ def display_summary(gpio_configs, user_to_real_map):
547548
# Initialize gpio_configs
548549
gpio_configs = existing_configs.copy() if existing_configs else {}
549550

551+
# If --view flag is set, just display the summary and return
552+
if view:
553+
if not gpio_configs:
554+
console.print("[yellow]No GPIO configuration found.[/yellow]")
555+
console.print("[dim]Run 'cf gpio-config' to configure GPIOs.[/dim]")
556+
return
557+
console.print(f"\n[bold cyan]GPIO Configuration ({gpio_label})[/bold cyan]")
558+
display_summary(gpio_configs, user_to_real_map)
559+
console.print()
560+
return
561+
550562
# ========================
551563
# HEADER
552564
# ========================
@@ -576,7 +588,7 @@ def get_mode_color(mode_key):
576588
if not mode_key:
577589
return "red"
578590
elif "output" in mode_key:
579-
return "ansi_bright_blue"
591+
return "ansi_bright_green"
580592
elif "input" in mode_key:
581593
return "cyan"
582594
elif "bidirectional" in mode_key:
@@ -1198,118 +1210,6 @@ def action_quit(self) -> None:
11981210
console.print(f"[red]Error updating user_defines.v: {e}[/red]")
11991211

12001212

1201-
@main.command('gpio-status')
1202-
@click.option('--project-root', required=False, type=click.Path(exists=True, file_okay=False), help='Path to the project directory (defaults to current directory).')
1203-
def gpio_status(project_root):
1204-
"""Display current GPIO configuration summary."""
1205-
if not project_root:
1206-
project_root = os.getcwd()
1207-
1208-
project_root = Path(project_root)
1209-
1210-
# Load project config
1211-
project_json_path = project_root / '.cf' / 'project.json'
1212-
if not project_json_path.exists():
1213-
console.print("[red]Error: No project configuration found.[/red]")
1214-
console.print("[dim]Run 'cf gpio-config' first to configure GPIOs.[/dim]")
1215-
return
1216-
1217-
with open(project_json_path, 'r') as f:
1218-
project_config = json.load(f)
1219-
1220-
# GPIO config is stored under project.gpio_config
1221-
project_data = project_config.get('project', {})
1222-
gpio_configs = project_data.get('gpio_config', {})
1223-
if not gpio_configs:
1224-
console.print("[yellow]No GPIO configuration found in project.json[/yellow]")
1225-
console.print("[dim]Run 'cf gpio-config' to configure GPIOs.[/dim]")
1226-
return
1227-
1228-
# Detect project type
1229-
project_type = project_data.get('type')
1230-
if not project_type:
1231-
project_type = detect_project_type(project_root)
1232-
1233-
# Determine GPIO range based on project type
1234-
if project_type == 'caravan':
1235-
user_gpio_range = list(range(0, 32))
1236-
gpio_label = "Caravan"
1237-
else:
1238-
user_gpio_range = list(range(5, 38))
1239-
gpio_label = "Caravel"
1240-
1241-
user_to_real_map = {g: g for g in user_gpio_range}
1242-
1243-
# Convert string keys back to int if needed
1244-
gpio_configs_int = {}
1245-
for k, v in gpio_configs.items():
1246-
try:
1247-
gpio_configs_int[int(k)] = v
1248-
except (ValueError, TypeError):
1249-
gpio_configs_int[k] = v
1250-
1251-
def find_mode_key(mode_value):
1252-
"""Find the mode key for a given mode value (handles hex values)."""
1253-
if not mode_value:
1254-
return None
1255-
# First, try to convert hex to mode constant name
1256-
mode_name = GPIO_HEX_TO_MODE.get(mode_value, mode_value)
1257-
# Then find the short key for that mode constant
1258-
for key, name in GPIO_MODES.items():
1259-
if name == mode_name and key != "invalid":
1260-
return key
1261-
return None
1262-
1263-
def format_gpio_ranges(gpio_list):
1264-
"""Convert [5,6,7,10,11,15] to '5-7, 10-11, 15'."""
1265-
if not gpio_list:
1266-
return "-"
1267-
gpio_list = sorted(gpio_list)
1268-
ranges = []
1269-
start = gpio_list[0]
1270-
end = start
1271-
for g in gpio_list[1:]:
1272-
if g == end + 1:
1273-
end = g
1274-
else:
1275-
ranges.append(f"{start}-{end}" if start != end else str(start))
1276-
start = end = g
1277-
ranges.append(f"{start}-{end}" if start != end else str(start))
1278-
return ", ".join(ranges)
1279-
1280-
# Group by mode
1281-
mode_groups = {}
1282-
for user_gpio, real_gpio in user_to_real_map.items():
1283-
mode_value = gpio_configs_int.get(real_gpio)
1284-
mode_key = find_mode_key(mode_value) if mode_value else None
1285-
if mode_key not in mode_groups:
1286-
mode_groups[mode_key] = []
1287-
mode_groups[mode_key].append(user_gpio)
1288-
1289-
console.print(f"\n[bold cyan]GPIO Configuration ({gpio_label})[/bold cyan]\n")
1290-
1291-
table = Table(show_header=True, header_style="bold", box=None, padding=(0, 2))
1292-
table.add_column("Mode", style="cyan", width=24)
1293-
table.add_column("Count", justify="right", width=6)
1294-
table.add_column("GPIOs")
1295-
1296-
# Sort by count (most common first)
1297-
for mode_key in sorted(mode_groups.keys(), key=lambda k: -len(mode_groups[k])):
1298-
gpios = mode_groups[mode_key]
1299-
display_name = mode_key if mode_key else "[red]unconfigured[/red]"
1300-
style = ""
1301-
if mode_key:
1302-
if "output" in mode_key: style = "[green]"
1303-
elif "input" in mode_key: style = "[cyan]"
1304-
elif "bidirectional" in mode_key: style = "[yellow]"
1305-
elif "analog" in mode_key: style = "[magenta]"
1306-
display_name = f"{style}{mode_key}[/]"
1307-
table.add_row(display_name, str(len(gpios)), format_gpio_ranges(gpios))
1308-
1309-
console.print(table)
1310-
console.print()
1311-
1312-
13131213
@main.command('push')
13141214
@click.option('--project-root', required=False, type=click.Path(exists=True, file_okay=False), help='Path to the local ChipFoundry project directory (defaults to current directory if .cf/project.json exists).')
13151215
@click.option('--sftp-host', default=DEFAULT_SFTP_HOST, show_default=True, help='SFTP server hostname.')
@@ -2608,12 +2508,10 @@ def maybe_abort_no_space(err, step_label):
26082508
def harden(macro, project_root, list_designs, tag, pdk, use_nix, use_docker, dry_run):
26092509
"""Harden a macro using LibreLane (OpenLane 2).
26102510
2611-
If no macro is specified, lists all available macros.
2612-
26132511
Examples:
2614-
cf harden # List available macros
26152512
cf harden user_proj_example # Harden a specific macro
26162513
cf harden user_project_wrapper
2514+
cf harden --list # List available macros
26172515
"""
26182516
from datetime import datetime
26192517

@@ -2641,13 +2539,17 @@ def harden(macro, project_root, list_designs, tag, pdk, use_nix, use_docker, dry
26412539
console.print("[yellow]Run 'cf setup' first to install OpenLane[/yellow]")
26422540
return
26432541

2644-
# If no macro specified, default to listing available macros
2542+
# If no macro specified, show prompt with available macros
2543+
no_macro_specified = not macro and not list_designs
26452544
if not macro:
26462545
list_designs = True
26472546

26482547
# List designs if requested (or if no macro specified)
26492548
if list_designs:
2650-
console.print("[bold cyan]Available macros:[/bold cyan]")
2549+
if no_macro_specified:
2550+
console.print("[yellow]Please specify a macro from this list:[/yellow]")
2551+
else:
2552+
console.print("[bold cyan]Available macros:[/bold cyan]")
26512553
designs = [d.name for d in openlane_dir.iterdir() if d.is_dir() and ((d / 'config.json').exists() or (d / 'config.yaml').exists() or (d / 'config.tcl').exists())]
26522554
if designs:
26532555
for design in sorted(designs):

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "chipfoundry-cli"
3-
version = "1.2.10"
3+
version = "1.2.11"
44
description = "CLI tool to automate ChipFoundry project submission to SFTP server"
55
authors = ["ChipFoundry <marwan.abbas@chipfoundry.io>"]
66
readme = "README.md"

0 commit comments

Comments
 (0)