chipfoundry-cli 1.2.9__tar.gz → 1.2.11__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.9
3
+ Version: 1.2.11
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
@@ -7,7 +7,7 @@ from chipfoundry_cli.utils import (
7
7
  open_html_in_browser, download_with_progress, update_repo_files,
8
8
  fetch_versions_from_upstream, parse_user_defines_v, update_user_defines_v,
9
9
  get_gpio_config_from_project_json, save_gpio_config_to_project_json,
10
- GPIO_MODES, GPIO_MODE_DESCRIPTIONS
10
+ GPIO_MODES, GPIO_MODE_DESCRIPTIONS, GPIO_HEX_TO_MODE
11
11
  )
12
12
  import os
13
13
  from pathlib import Path
@@ -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()
@@ -527,7 +528,7 @@ def gpio_config(project_root):
527
528
  table = Table(show_header=True, header_style="bold", box=None, padding=(0, 2))
528
529
  table.add_column("Mode", style="cyan", width=24)
529
530
  table.add_column("Count", justify="right", width=6)
530
- table.add_column("GPIOs", style="white")
531
+ table.add_column("GPIOs")
531
532
 
532
533
  # Sort by count (most common first)
533
534
  for mode_key in sorted(mode_groups.keys(), key=lambda k: -len(mode_groups[k])):
@@ -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 "green"
591
+ return "ansi_bright_green"
580
592
  elif "input" in mode_key:
581
593
  return "cyan"
582
594
  elif "bidirectional" in mode_key:
@@ -838,7 +850,7 @@ def gpio_config(project_root):
838
850
  class GPIOGridApp(App):
839
851
  """Textual app for GPIO grid configuration."""
840
852
 
841
- GRID_COLS = 4 # Number of columns in the grid
853
+ GRID_COLS = 6 # Number of columns in the grid
842
854
 
843
855
  CSS = """
844
856
  Screen {
@@ -864,21 +876,21 @@ def gpio_config(project_root):
864
876
  }
865
877
 
866
878
  #gpio-grid {
867
- grid-size: 4;
868
- grid-gutter: 1;
869
- padding: 1;
879
+ grid-size: 6;
880
+ grid-gutter: 0;
881
+ padding: 0;
870
882
  height: auto;
871
883
  width: 100%;
872
884
  }
873
885
 
874
886
  GPIOButton {
875
887
  width: 1fr;
876
- min-width: 24;
888
+ min-width: 20;
877
889
  height: 4;
878
890
  text-align: center;
879
- border: solid green;
891
+ border: solid grey;
880
892
  content-align: center middle;
881
- padding: 0 1;
893
+ padding: 0;
882
894
  }
883
895
 
884
896
  GPIOButton.current {
@@ -1089,10 +1101,9 @@ def gpio_config(project_root):
1089
1101
  """Open mode selection for selected GPIOs."""
1090
1102
  selected = self._get_selected_gpios()
1091
1103
  if not selected:
1092
- # If nothing selected, use the focused one
1093
- focused = self.focused
1094
- if isinstance(focused, GPIOButton):
1095
- selected = [focused.gpio_num]
1104
+ # If nothing selected, use the current one (where cursor is)
1105
+ if 0 <= self.current_index < len(self.gpio_list):
1106
+ selected = [self.gpio_list[self.current_index]]
1096
1107
 
1097
1108
  if selected:
1098
1109
  self.push_screen(ModeSelectScreen(selected), self._apply_mode)
@@ -1102,9 +1113,9 @@ def gpio_config(project_root):
1102
1113
  if mode_key:
1103
1114
  selected = self._get_selected_gpios()
1104
1115
  if not selected:
1105
- focused = self.focused
1106
- if isinstance(focused, GPIOButton):
1107
- selected = [focused.gpio_num]
1116
+ # Use current one if nothing selected
1117
+ if 0 <= self.current_index < len(self.gpio_list):
1118
+ selected = [self.gpio_list[self.current_index]]
1108
1119
 
1109
1120
  for gpio_num in selected:
1110
1121
  real_gpio = self.user_to_real_map[gpio_num]
@@ -1198,6 +1209,7 @@ def gpio_config(project_root):
1198
1209
  except Exception as e:
1199
1210
  console.print(f"[red]Error updating user_defines.v: {e}[/red]")
1200
1211
 
1212
+
1201
1213
  @main.command('push')
1202
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).')
1203
1215
  @click.option('--sftp-host', default=DEFAULT_SFTP_HOST, show_default=True, help='SFTP server hostname.')
@@ -2497,9 +2509,9 @@ def harden(macro, project_root, list_designs, tag, pdk, use_nix, use_docker, dry
2497
2509
  """Harden a macro using LibreLane (OpenLane 2).
2498
2510
 
2499
2511
  Examples:
2500
- cf harden user_proj_example
2512
+ cf harden user_proj_example # Harden a specific macro
2501
2513
  cf harden user_project_wrapper
2502
- cf harden --list
2514
+ cf harden --list # List available macros
2503
2515
  """
2504
2516
  from datetime import datetime
2505
2517
 
@@ -2512,8 +2524,8 @@ def harden(macro, project_root, list_designs, tag, pdk, use_nix, use_docker, dry
2512
2524
 
2513
2525
  project_root_path = Path(project_root)
2514
2526
 
2515
- # Check if project is initialized (skip check for --list, allow graceful return)
2516
- if not list_designs:
2527
+ # Check if project is initialized (skip check for --list or when no macro specified, allow graceful return)
2528
+ if not list_designs and macro:
2517
2529
  if not check_project_initialized(project_root_path, 'harden', dry_run=dry_run, allow_graceful=True):
2518
2530
  console.print(f"[red]✗[/red] Project not initialized. Please run 'cf init' first.")
2519
2531
  console.print("[yellow]Run 'cf setup' first to install OpenLane[/yellow]")
@@ -2527,9 +2539,17 @@ def harden(macro, project_root, list_designs, tag, pdk, use_nix, use_docker, dry
2527
2539
  console.print("[yellow]Run 'cf setup' first to install OpenLane[/yellow]")
2528
2540
  return
2529
2541
 
2530
- # List designs if requested
2542
+ # If no macro specified, show prompt with available macros
2543
+ no_macro_specified = not macro and not list_designs
2544
+ if not macro:
2545
+ list_designs = True
2546
+
2547
+ # List designs if requested (or if no macro specified)
2531
2548
  if list_designs:
2532
- 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]")
2533
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())]
2534
2554
  if designs:
2535
2555
  for design in sorted(designs):
@@ -2544,13 +2564,6 @@ def harden(macro, project_root, list_designs, tag, pdk, use_nix, use_docker, dry
2544
2564
  console.print("[yellow]No macros found in openlane/[/yellow]")
2545
2565
  return
2546
2566
 
2547
- # Macro is required if not listing
2548
- if not macro:
2549
- console.print("[red]✗[/red] Error: MACRO argument is required")
2550
- console.print("[yellow]Usage:[/yellow] cf harden <macro>")
2551
- console.print("[yellow] [/yellow] cf harden --list")
2552
- return
2553
-
2554
2567
  # Check if macro exists
2555
2568
  macro_dir = openlane_dir / macro
2556
2569
  if not macro_dir.exists():
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "chipfoundry-cli"
3
- version = "1.2.9"
3
+ version = "1.2.11"
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"
@@ -18,7 +18,7 @@ toml = ">=0.10,<1.0"
18
18
  httpx = ">=0.24.0,<1.0"
19
19
  textual = ">=0.40.0,<1"
20
20
 
21
- [tool.poetry.dev-dependencies]
21
+ [tool.poetry.group.dev.dependencies]
22
22
  wheel = "*"
23
23
  black = ">=24.4.0,<25"
24
24
  flake8 = ">=4"