chipfoundry-cli 1.2.10__tar.gz → 1.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: chipfoundry-cli
3
- Version: 1.2.10
3
+ Version: 1.3.0
4
4
  Summary: CLI tool to automate ChipFoundry project submission to SFTP server
5
5
  Home-page: https://chipfoundry.io
6
6
  License: Apache-2.0
@@ -350,7 +350,8 @@ def init(project_root):
350
350
 
351
351
  @main.command('gpio-config')
352
352
  @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):
354
355
  """Configure GPIO settings interactively and save to project config and user_defines.v."""
355
356
  if not project_root:
356
357
  project_root = os.getcwd()
@@ -547,6 +548,17 @@ def gpio_config(project_root):
547
548
  # Initialize gpio_configs
548
549
  gpio_configs = existing_configs.copy() if existing_configs else {}
549
550
 
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
+
550
562
  # ========================
551
563
  # HEADER
552
564
  # ========================
@@ -576,7 +588,7 @@ def gpio_config(project_root):
576
588
  if not mode_key:
577
589
  return "red"
578
590
  elif "output" in mode_key:
579
- return "ansi_bright_blue"
591
+ return "ansi_bright_green"
580
592
  elif "input" in mode_key:
581
593
  return "cyan"
582
594
  elif "bidirectional" in mode_key:
@@ -719,7 +731,7 @@ def gpio_config(project_root):
719
731
  }
720
732
 
721
733
  .mode-btn-output {
722
- color: green;
734
+ color: ansi_bright_green;
723
735
  }
724
736
 
725
737
  .mode-btn-input {
@@ -1198,118 +1210,6 @@ def gpio_config(project_root):
1198
1210
  console.print(f"[red]Error updating user_defines.v: {e}[/red]")
1199
1211
 
1200
1212
 
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
-
1313
1213
  @main.command('push')
1314
1214
  @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).')
1315
1215
  @click.option('--sftp-host', default=DEFAULT_SFTP_HOST, show_default=True, help='SFTP server hostname.')
@@ -2608,12 +2508,10 @@ def setup(project_root, repo_owner, repo_name, branch, pdk, caravel_lite,
2608
2508
  def harden(macro, project_root, list_designs, tag, pdk, use_nix, use_docker, dry_run):
2609
2509
  """Harden a macro using LibreLane (OpenLane 2).
2610
2510
 
2611
- If no macro is specified, lists all available macros.
2612
-
2613
2511
  Examples:
2614
- cf harden # List available macros
2615
2512
  cf harden user_proj_example # Harden a specific macro
2616
2513
  cf harden user_project_wrapper
2514
+ cf harden --list # List available macros
2617
2515
  """
2618
2516
  from datetime import datetime
2619
2517
 
@@ -2641,13 +2539,17 @@ def harden(macro, project_root, list_designs, tag, pdk, use_nix, use_docker, dry
2641
2539
  console.print("[yellow]Run 'cf setup' first to install OpenLane[/yellow]")
2642
2540
  return
2643
2541
 
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
2645
2544
  if not macro:
2646
2545
  list_designs = True
2647
2546
 
2648
2547
  # List designs if requested (or if no macro specified)
2649
2548
  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]")
2651
2553
  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())]
2652
2554
  if designs:
2653
2555
  for design in sorted(designs):
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "chipfoundry-cli"
3
- version = "1.2.10"
3
+ version = "1.3.0"
4
4
  description = "CLI tool to automate ChipFoundry project submission to SFTP server"
5
5
  authors = ["ChipFoundry <marwan.abbas@chipfoundry.io>"]
6
6
  readme = "README.md"