sima-cli 0.0.18__py3-none-any.whl → 0.0.20__py3-none-any.whl
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.
- sima_cli/__version__.py +1 -1
- sima_cli/auth/login.py +2 -2
- sima_cli/cli.py +111 -2
- sima_cli/install/__init__.py +0 -0
- sima_cli/install/hostdriver.py +152 -0
- sima_cli/install/optiview.py +85 -0
- sima_cli/install/palette.py +87 -0
- sima_cli/serial/__init__.py +0 -0
- sima_cli/serial/serial.py +114 -0
- sima_cli/update/bmaptool.py +137 -0
- sima_cli/update/bootimg.py +339 -0
- sima_cli/update/netboot.py +408 -0
- sima_cli/update/remote.py +42 -9
- sima_cli/update/updater.py +103 -33
- sima_cli/utils/env.py +2 -3
- sima_cli/utils/net.py +29 -0
- {sima_cli-0.0.18.dist-info → sima_cli-0.0.20.dist-info}/METADATA +3 -1
- {sima_cli-0.0.18.dist-info → sima_cli-0.0.20.dist-info}/RECORD +22 -12
- {sima_cli-0.0.18.dist-info → sima_cli-0.0.20.dist-info}/WHEEL +0 -0
- {sima_cli-0.0.18.dist-info → sima_cli-0.0.20.dist-info}/entry_points.txt +0 -0
- {sima_cli-0.0.18.dist-info → sima_cli-0.0.20.dist-info}/licenses/LICENSE +0 -0
- {sima_cli-0.0.18.dist-info → sima_cli-0.0.20.dist-info}/top_level.txt +0 -0
sima_cli/__version__.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
# sima_cli/__version__.py
|
2
|
-
__version__ = "0.0.
|
2
|
+
__version__ = "0.0.20"
|
sima_cli/auth/login.py
CHANGED
@@ -61,14 +61,14 @@ def login_internal():
|
|
61
61
|
click.echo(f"✅ Identity token is valid")
|
62
62
|
|
63
63
|
# Step 2: Exchange for a short-lived access token (default: 7 days)
|
64
|
-
access_token, user_name = exchange_identity_token(identity_token, exchange_url, expires_in=
|
64
|
+
access_token, user_name = exchange_identity_token(identity_token, exchange_url, expires_in=1209600)
|
65
65
|
|
66
66
|
if not access_token:
|
67
67
|
return click.echo("❌ Failed to acquire short-lived access token.")
|
68
68
|
|
69
69
|
# Step 3: Save token to internal auth config
|
70
70
|
set_auth_token(access_token, internal=True)
|
71
|
-
click.echo(f"💾 Short-lived access token saved successfully for {user_name} (valid for
|
71
|
+
click.echo(f"💾 Short-lived access token saved successfully for {user_name} (valid for 14 days).")
|
72
72
|
|
73
73
|
|
74
74
|
def _login_external():
|
sima_cli/cli.py
CHANGED
@@ -7,10 +7,13 @@ from sima_cli.utils.config_loader import internal_resource_exists
|
|
7
7
|
from sima_cli.mla.meminfo import monitor_simaai_mem_chart
|
8
8
|
from sima_cli.__version__ import __version__
|
9
9
|
from sima_cli.utils.config import CONFIG_PATH
|
10
|
+
from sima_cli.install.optiview import install_optiview
|
11
|
+
from sima_cli.install.hostdriver import install_hostdriver
|
12
|
+
from sima_cli.serial.serial import connect_serial
|
10
13
|
|
11
14
|
# Entry point for the CLI tool using Click's command group decorator
|
12
15
|
@click.group()
|
13
|
-
@click.option('-i', '--internal', is_flag=True, help="Use internal Artifactory resources
|
16
|
+
@click.option('-i', '--internal', is_flag=True, help="Use internal Artifactory resources, Authorized Sima employees only")
|
14
17
|
@click.pass_context
|
15
18
|
def main(ctx, internal):
|
16
19
|
"""
|
@@ -164,7 +167,7 @@ def modelzoo(ctx, ver):
|
|
164
167
|
ctx.obj['ver'] = ver
|
165
168
|
internal = ctx.obj.get("internal", False)
|
166
169
|
if not internal:
|
167
|
-
click.echo(f"
|
170
|
+
click.echo(f"Public developer portal environment is not supported yet..")
|
168
171
|
exit(0)
|
169
172
|
|
170
173
|
pass
|
@@ -217,6 +220,112 @@ def show_mla_memory_usage(ctx):
|
|
217
220
|
monitor_simaai_mem_chart()
|
218
221
|
pass
|
219
222
|
|
223
|
+
|
224
|
+
# ----------------------
|
225
|
+
# bootimg Command
|
226
|
+
# ----------------------
|
227
|
+
@main.command(name="bootimg")
|
228
|
+
@click.option("-v", "--version", required=True, help="Firmware version to download and write (e.g., 1.6.0)")
|
229
|
+
@click.option("--boardtype", type=click.Choice(["modalix", "mlsoc"], case_sensitive=False), default="mlsoc", show_default=True, help="Target board type.")
|
230
|
+
@click.option("--netboot", is_flag=True, default=False, show_default=True, help="Prepare image for network boot and launch TFTP server.")
|
231
|
+
@click.option("--autoflash", is_flag=True, default=False, show_default=True, help="Net boot the DevKit and automatically flash the internal storage")
|
232
|
+
@click.pass_context
|
233
|
+
def bootimg_cmd(ctx, version, boardtype, netboot, autoflash):
|
234
|
+
"""
|
235
|
+
Download and burn a removable media or setup TFTP boot.
|
236
|
+
|
237
|
+
Examples:
|
238
|
+
sima-cli bootimg -v 1.6.0
|
239
|
+
sima-cli bootimg -v 1.6.0 --boardtype mlsoc
|
240
|
+
sima-cli bootimg -v 1.6.0 --boardtype modalix
|
241
|
+
sima-cli bootimg -v 1.6.0 --boardtype modalix --netboot
|
242
|
+
sima-cli bootimg -v 1.6.0 --boardtype modalix --autoflash
|
243
|
+
"""
|
244
|
+
|
245
|
+
from sima_cli.update.bootimg import write_image
|
246
|
+
from sima_cli.update.netboot import setup_netboot
|
247
|
+
|
248
|
+
internal = ctx.obj.get("internal", False)
|
249
|
+
|
250
|
+
click.echo(f"📦 Preparing boot image:")
|
251
|
+
click.echo(f" 🔹 Version : {version}")
|
252
|
+
click.echo(f" 🔹 Board Type: {boardtype}")
|
253
|
+
|
254
|
+
try:
|
255
|
+
boardtype = boardtype if boardtype != 'mlsoc' else 'davinci'
|
256
|
+
if netboot or autoflash:
|
257
|
+
setup_netboot(version, boardtype, internal, autoflash)
|
258
|
+
click.echo("✅ Netboot image prepared and TFTP server is running.")
|
259
|
+
else:
|
260
|
+
write_image(version, boardtype, 'yocto', internal)
|
261
|
+
click.echo("✅ Boot image successfully written.")
|
262
|
+
click.echo("✅ Boot image successfully written.")
|
263
|
+
except Exception as e:
|
264
|
+
click.echo(f"❌ Failed to write boot image: {e}", err=True)
|
265
|
+
ctx.exit(1)
|
266
|
+
|
267
|
+
# ----------------------
|
268
|
+
# install Command
|
269
|
+
# ----------------------
|
270
|
+
SDK_DEPENDENT_COMPONENTS = {"palette", "hostdriver"}
|
271
|
+
SDK_INDEPENDENT_COMPONENTS = {"optiview"}
|
272
|
+
ALL_COMPONENTS = SDK_DEPENDENT_COMPONENTS | SDK_INDEPENDENT_COMPONENTS
|
273
|
+
|
274
|
+
@main.command(name="install")
|
275
|
+
@click.argument("component", type=click.Choice(ALL_COMPONENTS, case_sensitive=False))
|
276
|
+
@click.option("-v", "--version", help="SDK version (required for SDK-dependent components)")
|
277
|
+
@click.pass_context
|
278
|
+
def install_cmd(ctx, component, version):
|
279
|
+
"""
|
280
|
+
Install supported components such as SDKs or tools.
|
281
|
+
|
282
|
+
Examples:
|
283
|
+
|
284
|
+
sima-cli install hostdriver -v 1.6.0
|
285
|
+
|
286
|
+
sima-cli install optiview
|
287
|
+
"""
|
288
|
+
component = component.lower()
|
289
|
+
internal = ctx.obj.get("internal", False)
|
290
|
+
|
291
|
+
if component in SDK_DEPENDENT_COMPONENTS and not version:
|
292
|
+
click.echo(f"❌ The component '{component}' requires a specific SDK version. Please provide one using -v.")
|
293
|
+
ctx.exit(1)
|
294
|
+
|
295
|
+
if component in SDK_INDEPENDENT_COMPONENTS and version:
|
296
|
+
click.echo(f"ℹ️ The component '{component}' does not require an SDK version. Ignoring -v {version}.")
|
297
|
+
|
298
|
+
# Perform the installation logic
|
299
|
+
if component == "palette":
|
300
|
+
click.echo(f"🔧 Installing SDK component 'palette' for version {version} is not implemented yet...")
|
301
|
+
elif component == "hostdriver":
|
302
|
+
click.echo(f"🔧 Installing SDK component 'hostdriver' for version {version}...")
|
303
|
+
install_hostdriver(version=version, internal=internal)
|
304
|
+
elif component == "optiview":
|
305
|
+
click.echo("🔧 Installing tool 'optiview'...")
|
306
|
+
install_optiview()
|
307
|
+
|
308
|
+
click.echo("✅ Installation complete.")
|
309
|
+
|
310
|
+
# ----------------------
|
311
|
+
# Serial Subcommands
|
312
|
+
# ----------------------
|
313
|
+
@main.command(name="serial")
|
314
|
+
@click.option("-b", "--baud", default=115200, show_default=True, help="Baud rate for the serial connection")
|
315
|
+
@click.pass_context
|
316
|
+
def serial_cmd(ctx, baud):
|
317
|
+
"""
|
318
|
+
Connect to the UART serial console of the DevKit.
|
319
|
+
|
320
|
+
Automatically detects the serial port and launches a terminal emulator:
|
321
|
+
|
322
|
+
- macOS: uses 'picocom'
|
323
|
+
|
324
|
+
- Linux: uses 'picocom'
|
325
|
+
|
326
|
+
- Windows: shows PuTTY/Tera Term setup instructions
|
327
|
+
"""
|
328
|
+
connect_serial(ctx, baud)
|
220
329
|
# ----------------------
|
221
330
|
# App Zoo Subcommands
|
222
331
|
# ----------------------
|
File without changes
|
@@ -0,0 +1,152 @@
|
|
1
|
+
import sys
|
2
|
+
import click
|
3
|
+
import os
|
4
|
+
import subprocess
|
5
|
+
from pathlib import Path
|
6
|
+
|
7
|
+
from sima_cli.update.updater import download_image
|
8
|
+
from sima_cli.utils.env import is_pcie_host
|
9
|
+
|
10
|
+
def _check_driver_installation():
|
11
|
+
"""
|
12
|
+
Checks whether the PCIe host driver (sima_mla_drv) and related components are correctly installed.
|
13
|
+
|
14
|
+
Returns:
|
15
|
+
dict: A dictionary with validation results for gstreamer, kernel module, and PCI device.
|
16
|
+
"""
|
17
|
+
results = {}
|
18
|
+
|
19
|
+
# 1. Check GStreamer plugin
|
20
|
+
try:
|
21
|
+
gst_output = subprocess.check_output(["gst-inspect-1.0", "pciehost"], stderr=subprocess.STDOUT, text=True)
|
22
|
+
if "pciehost" in gst_output:
|
23
|
+
results["gstreamer"] = {
|
24
|
+
"success": True,
|
25
|
+
"message": "✅ GStreamer plugin 'pciehost' is installed."
|
26
|
+
}
|
27
|
+
else:
|
28
|
+
results["gstreamer"] = {
|
29
|
+
"success": False,
|
30
|
+
"message": "❌ GStreamer plugin 'pciehost' not found."
|
31
|
+
}
|
32
|
+
except subprocess.CalledProcessError as e:
|
33
|
+
results["gstreamer"] = {
|
34
|
+
"success": False,
|
35
|
+
"message": f"❌ GStreamer check failed: {e.output.strip()}"
|
36
|
+
}
|
37
|
+
|
38
|
+
# 2. Check kernel module
|
39
|
+
try:
|
40
|
+
modinfo_output = subprocess.check_output(["modinfo", "sima_mla_drv"], stderr=subprocess.STDOUT, text=True)
|
41
|
+
if "filename:" in modinfo_output and "sima_mla_drv" in modinfo_output:
|
42
|
+
results["kernel_module"] = {
|
43
|
+
"success": True,
|
44
|
+
"message": "✅ Kernel module 'sima_mla_drv' is installed."
|
45
|
+
}
|
46
|
+
else:
|
47
|
+
results["kernel_module"] = {
|
48
|
+
"success": False,
|
49
|
+
"message": "❌ Kernel module 'sima_mla_drv' not found."
|
50
|
+
}
|
51
|
+
except subprocess.CalledProcessError as e:
|
52
|
+
results["kernel_module"] = {
|
53
|
+
"success": False,
|
54
|
+
"message": f"❌ Kernel module check failed: {e.output.strip()}"
|
55
|
+
}
|
56
|
+
|
57
|
+
# 3. Check PCI device presence
|
58
|
+
try:
|
59
|
+
lspci_output = subprocess.check_output(["lspci", "-vd", "1f06:abcd"], stderr=subprocess.STDOUT, text=True)
|
60
|
+
if "sima_mla_drv" in lspci_output or "1f06:abcd" in lspci_output:
|
61
|
+
results["pci_device"] = {
|
62
|
+
"success": True,
|
63
|
+
"message": "✅ PCIe device (1f06:abcd) detected and bound to 'sima_mla_drv'."
|
64
|
+
}
|
65
|
+
else:
|
66
|
+
results["pci_device"] = {
|
67
|
+
"success": False,
|
68
|
+
"message": "❌ PCIe device not detected."
|
69
|
+
}
|
70
|
+
except subprocess.CalledProcessError as e:
|
71
|
+
results["pci_device"] = {
|
72
|
+
"success": False,
|
73
|
+
"message": f"❌ PCIe device check failed: {e.output.strip()}"
|
74
|
+
}
|
75
|
+
|
76
|
+
return results
|
77
|
+
|
78
|
+
def _print_driver_validation_table(results: dict):
|
79
|
+
"""
|
80
|
+
Prints the driver validation results in a table format with fixed-width columns.
|
81
|
+
"""
|
82
|
+
print("\nDriver Installation Validation:\n")
|
83
|
+
print(f"{'Component':<20} | {'Status':<10} | {'Details'}")
|
84
|
+
print("-" * 60)
|
85
|
+
|
86
|
+
for section, result in results.items():
|
87
|
+
component = section.replace("_", " ").title()
|
88
|
+
status = "PASS" if result["success"] else "FAIL"
|
89
|
+
message = result["message"]
|
90
|
+
print(f"{component:<20} | {status:<10} | {message}")
|
91
|
+
|
92
|
+
def install_hostdriver(version: str, internal: bool = False):
|
93
|
+
"""
|
94
|
+
Install PCIe host driver on supported platforms.
|
95
|
+
|
96
|
+
This function is only valid on PCIe host machines. It downloads the appropriate image
|
97
|
+
package and installs the host driver script if present.
|
98
|
+
|
99
|
+
Args:
|
100
|
+
version (str): Firmware version string (e.g., "1.6.0").
|
101
|
+
internal (bool): Whether to use internal sources for the download.
|
102
|
+
|
103
|
+
Raises:
|
104
|
+
RuntimeError: If the platform is not supported or the driver script is missing.
|
105
|
+
"""
|
106
|
+
if not is_pcie_host():
|
107
|
+
click.echo("❌ This command is only supported on PCIe host Linux machines.")
|
108
|
+
sys.exit(1)
|
109
|
+
|
110
|
+
try:
|
111
|
+
# Step 1: Install system dependencies
|
112
|
+
click.echo("🔧 Installing required system packages...")
|
113
|
+
try:
|
114
|
+
subprocess.run([
|
115
|
+
"sudo", "apt-get", "update"
|
116
|
+
], check=True)
|
117
|
+
subprocess.run([
|
118
|
+
"sudo", "apt-get", "install", "-y",
|
119
|
+
"make", "cmake", "gcc", "g++", "dkms", "doxygen",
|
120
|
+
"libjson-c-dev", "libjsoncpp-dev", "build-essential", "linux-headers-generic"
|
121
|
+
], check=True)
|
122
|
+
click.echo("✅ Dependencies installed successfully.")
|
123
|
+
except subprocess.CalledProcessError as e:
|
124
|
+
raise RuntimeError(f"❌ Failed to install dependencies: {e}")
|
125
|
+
|
126
|
+
# Step 2: Download driver package which is part of the firmware release.
|
127
|
+
click.echo(f"⬇️ Downloading host driver package for version {version}...")
|
128
|
+
extracted_files = download_image(version_or_url=version, board="davinci", swtype="yocto", internal=internal)
|
129
|
+
|
130
|
+
# Find the host driver script in extracted files
|
131
|
+
script_path = next((f for f in extracted_files if f.endswith("sima_pcie_host_pkg.sh")), None)
|
132
|
+
|
133
|
+
if not script_path or not os.path.isfile(script_path):
|
134
|
+
raise RuntimeError("sima_pcie_host_pkg.sh not found in the downloaded package.")
|
135
|
+
|
136
|
+
click.echo(f"📦 Host driver script found: {script_path}")
|
137
|
+
click.confirm("⚠️ This will install drivers on your system using sudo. Continue?", abort=True)
|
138
|
+
|
139
|
+
# Make sure the script is executable
|
140
|
+
os.chmod(script_path, 0o755)
|
141
|
+
|
142
|
+
# Run the script with sudo
|
143
|
+
subprocess.run(["sudo", script_path], check=True)
|
144
|
+
|
145
|
+
click.echo("✅ Host driver installation completed.")
|
146
|
+
|
147
|
+
results = _check_driver_installation()
|
148
|
+
_print_driver_validation_table(results)
|
149
|
+
|
150
|
+
except Exception as e:
|
151
|
+
raise RuntimeError(f"❌ Failed to install host driver: {e}")
|
152
|
+
|
@@ -0,0 +1,85 @@
|
|
1
|
+
import sys
|
2
|
+
import platform
|
3
|
+
import click
|
4
|
+
import json
|
5
|
+
import tarfile
|
6
|
+
import os
|
7
|
+
import subprocess
|
8
|
+
from pathlib import Path
|
9
|
+
from sima_cli.download import download_file_from_url
|
10
|
+
from sima_cli.utils.env import is_sima_board
|
11
|
+
from sima_cli.utils.config_loader import load_resource_config
|
12
|
+
|
13
|
+
def install_optiview():
|
14
|
+
try:
|
15
|
+
# Special path for SiMa DevKit
|
16
|
+
if is_sima_board():
|
17
|
+
click.echo("🛠 Detected SiMa DevKit. Cleaning up existing installation...")
|
18
|
+
subprocess.run(["sudo", "pip3", "uninstall", "-y", "optiview"], check=True)
|
19
|
+
click.echo("📦 Installing Optiview via pip...")
|
20
|
+
subprocess.run(["sudo", "pip3", "install", "optiview"], check=True)
|
21
|
+
click.echo("✅ Optiview installed successfully on DevKit.")
|
22
|
+
return
|
23
|
+
|
24
|
+
cfg = load_resource_config()
|
25
|
+
download_url_base = cfg.get('public').get('download').get('download_url')
|
26
|
+
|
27
|
+
# Normal flow for other platforms
|
28
|
+
click.echo("📥 Fetching Optiview version info...")
|
29
|
+
version_url = f"{download_url_base}optiview/metadata.json"
|
30
|
+
downloads_dir = Path.home() / "Downloads" / "optiview-installer"
|
31
|
+
downloads_dir.mkdir(parents=True, exist_ok=True)
|
32
|
+
|
33
|
+
# Always redownload the metadata file to get the latest version
|
34
|
+
metadata_path = downloads_dir / "metadata.json"
|
35
|
+
if metadata_path.exists():
|
36
|
+
metadata_path.unlink()
|
37
|
+
|
38
|
+
metadata_path = download_file_from_url(version_url, dest_folder=downloads_dir, internal=False)
|
39
|
+
|
40
|
+
with open(metadata_path, "r") as f:
|
41
|
+
version_data = json.load(f)
|
42
|
+
latest_version = version_data.get("latest")
|
43
|
+
|
44
|
+
if not latest_version:
|
45
|
+
raise Exception("Unable to retrieve latest version info.")
|
46
|
+
|
47
|
+
# Determine architecture
|
48
|
+
system = platform.system().lower()
|
49
|
+
machine = platform.machine().lower()
|
50
|
+
|
51
|
+
if system == "darwin" and machine == "arm64":
|
52
|
+
arch = "aarch64"
|
53
|
+
else:
|
54
|
+
arch = "x86_64"
|
55
|
+
|
56
|
+
pkg_url = f"{download_url_base}optiview/optiview-installation-{arch}-{latest_version}.tar.gz"
|
57
|
+
click.echo(f"🌐 Downloading Optiview ({arch} v{latest_version})...")
|
58
|
+
|
59
|
+
archive_path = download_file_from_url(pkg_url, dest_folder=downloads_dir)
|
60
|
+
|
61
|
+
click.echo(f"📦 Extracting to {downloads_dir}...")
|
62
|
+
with tarfile.open(archive_path, "r:gz") as tar:
|
63
|
+
tar.extractall(path=downloads_dir)
|
64
|
+
|
65
|
+
install_script = "install.bat" if system == "windows" else "install.sh"
|
66
|
+
script_path = os.path.join(downloads_dir, install_script)
|
67
|
+
|
68
|
+
if not os.path.isfile(script_path):
|
69
|
+
raise Exception(f"Installation script not found: {script_path}")
|
70
|
+
|
71
|
+
click.echo(f"🚀 Running installer: {install_script}")
|
72
|
+
if system == "windows":
|
73
|
+
subprocess.run(["cmd", "/c", os.path.basename(script_path)], check=True, cwd=downloads_dir)
|
74
|
+
else:
|
75
|
+
subprocess.run(["bash", os.path.basename(script_path)], check=True, cwd=downloads_dir)
|
76
|
+
|
77
|
+
script_name = "run.bat" if platform.system() == "Windows" else "run.sh"
|
78
|
+
click.echo(f"✅ Optiview installed successfully. Run {downloads_dir}/{script_name} to start OptiView")
|
79
|
+
|
80
|
+
except Exception as e:
|
81
|
+
click.echo(f"❌ Installation failed: {e}")
|
82
|
+
sys.exit(1)
|
83
|
+
|
84
|
+
if __name__ == "__main__":
|
85
|
+
install_optiview()
|
@@ -0,0 +1,87 @@
|
|
1
|
+
import sys
|
2
|
+
import platform
|
3
|
+
import click
|
4
|
+
import json
|
5
|
+
import tarfile
|
6
|
+
import os
|
7
|
+
import subprocess
|
8
|
+
from pathlib import Path
|
9
|
+
from sima_cli.download import download_file_from_url
|
10
|
+
from sima_cli.utils.env import is_sima_board
|
11
|
+
from sima_cli.utils.config_loader import load_resource_config
|
12
|
+
|
13
|
+
def build_internal_url(download_url_base, latest_filename):
|
14
|
+
"""Build the URL for internal Palette package."""
|
15
|
+
return f"{download_url_base}palette/{latest_filename}"
|
16
|
+
|
17
|
+
def build_external_url(download_url_base, latest_filename, version):
|
18
|
+
"""Build the URL for external Palette package from SDKx.y.z folder."""
|
19
|
+
return f"{download_url_base}palette/SDK{version}/{latest_filename}"
|
20
|
+
|
21
|
+
def install_palette(internal=False):
|
22
|
+
try:
|
23
|
+
# Check for unsupported platforms
|
24
|
+
system = platform.system().lower()
|
25
|
+
if is_sima_board():
|
26
|
+
click.echo("❌ Palette installation is not supported on SiMa DevKit, please install on Ubuntu 22.04 or Windows 10/11.")
|
27
|
+
sys.exit(1)
|
28
|
+
if system == "darwin":
|
29
|
+
click.echo("❌ Palette installation is not supported on macOS, please install on Ubuntu 22.04 or Windows 10/11.")
|
30
|
+
sys.exit(1)
|
31
|
+
|
32
|
+
# Load configuration for resources
|
33
|
+
cfg = load_resource_config()
|
34
|
+
download_url_base = cfg.get('internal' if internal else 'public').get('download').get('download_url')
|
35
|
+
|
36
|
+
# Fetch Palette version info
|
37
|
+
click.echo(f"📥 Fetching Palette version info ({'internal' if internal else 'external'})...")
|
38
|
+
version_url = f"{download_url_base}palette/metadata.json"
|
39
|
+
downloads_dir = Path.home() / "Downloads" / "palette-installer"
|
40
|
+
downloads_dir.mkdir(parents=True, exist_ok=True)
|
41
|
+
metadata_path = download_file_from_url(version_url, dest_folder=downloads_dir, internal=internal)
|
42
|
+
|
43
|
+
# Read version data
|
44
|
+
with open(metadata_path, "r") as f:
|
45
|
+
version_data = json.load(f)
|
46
|
+
latest_filename = version_data.get("latest")
|
47
|
+
|
48
|
+
if not latest_filename:
|
49
|
+
raise Exception("Unable to retrieve latest filename info.")
|
50
|
+
|
51
|
+
# Extract version from filename (assuming format like palette-installation-<arch>-x.y.z.tar.gz)
|
52
|
+
version = latest_filename.split('-')[-1].replace('.tar.gz', '')
|
53
|
+
|
54
|
+
# Build package URL based on internal or external
|
55
|
+
pkg_url = build_internal_url(download_url_base, latest_filename) if internal else build_external_url(download_url_base, latest_filename, version)
|
56
|
+
click.echo(f"🌐 Downloading Palette ({'internal' if internal else 'external'}: {latest_filename})...")
|
57
|
+
|
58
|
+
# Download the package
|
59
|
+
archive_path = download_file_from_url(pkg_url, dest_folder=downloads_dir, internal=internal)
|
60
|
+
|
61
|
+
# Extract the package
|
62
|
+
click.echo(f"📦 Extracting to {downloads_dir}...")
|
63
|
+
with tarfile.open(archive_path, "r:gz") as tar:
|
64
|
+
tar.extractall(path=downloads_dir)
|
65
|
+
|
66
|
+
# Determine installation script based on platform
|
67
|
+
install_script = "install.bat" if system == "windows" else "install.sh"
|
68
|
+
script_path = os.path.join(downloads_dir, install_script)
|
69
|
+
|
70
|
+
if not os.path.isfile(script_path):
|
71
|
+
raise Exception(f"Installation script not found: {script_path}")
|
72
|
+
|
73
|
+
# Run the installer
|
74
|
+
click.echo(f"🚀 Running installer: {install_script}")
|
75
|
+
if system == "windows":
|
76
|
+
subprocess.run(["cmd", "/c", os.path.basename(script_path)], check=True, cwd=downloads_dir)
|
77
|
+
else:
|
78
|
+
subprocess.run(["bash", os.path.basename(script_path)], check=True, cwd=downloads_dir)
|
79
|
+
|
80
|
+
click.echo(f"✅ Palette installed successfully ({'internal' if internal else 'external'}). Run {downloads_dir}/run.sh to start palette")
|
81
|
+
|
82
|
+
except Exception as e:
|
83
|
+
click.echo(f"❌ {'Internal' if internal else 'External'} installation failed: {e}")
|
84
|
+
sys.exit(1)
|
85
|
+
|
86
|
+
if __name__ == "__main__":
|
87
|
+
install_palette(internal=False)
|
File without changes
|
@@ -0,0 +1,114 @@
|
|
1
|
+
import platform
|
2
|
+
import subprocess
|
3
|
+
import shutil
|
4
|
+
import click
|
5
|
+
from sima_cli.utils.env import is_sima_board
|
6
|
+
|
7
|
+
def connect_serial(ctx, baud):
|
8
|
+
"""
|
9
|
+
Connect to the UART serial console of the DevKit.
|
10
|
+
Automatically installs required tools if missing.
|
11
|
+
"""
|
12
|
+
if is_sima_board():
|
13
|
+
click.echo("🚫 This command is not supported on the DevKit. Please run it from your host machine.")
|
14
|
+
ctx.exit(1)
|
15
|
+
|
16
|
+
system = platform.system()
|
17
|
+
internal = ctx.obj.get("internal", False)
|
18
|
+
|
19
|
+
if system == "Darwin":
|
20
|
+
_connect_mac(baud)
|
21
|
+
elif system == "Linux":
|
22
|
+
_connect_linux(baud)
|
23
|
+
elif system == "Windows":
|
24
|
+
_print_windows_instructions()
|
25
|
+
else:
|
26
|
+
click.echo(f"⚠️ Unsupported OS: {system}. Only macOS, Linux, and Windows are supported.")
|
27
|
+
ctx.exit(1)
|
28
|
+
|
29
|
+
click.echo("✅ Serial session ended.")
|
30
|
+
|
31
|
+
|
32
|
+
def _connect_mac(baud):
|
33
|
+
terminal = "picocom"
|
34
|
+
if not shutil.which(terminal):
|
35
|
+
click.echo("⚙️ 'picocom' is not installed. Attempting to install with Homebrew...")
|
36
|
+
if shutil.which("brew"):
|
37
|
+
subprocess.run(["brew", "install", "picocom"], check=True)
|
38
|
+
else:
|
39
|
+
click.echo("❌ Homebrew not found. Please install Homebrew first: https://brew.sh/")
|
40
|
+
raise SystemExit(1)
|
41
|
+
|
42
|
+
ports = sorted(
|
43
|
+
subprocess.getoutput("ls /dev/tty.usbserial-* /dev/cu.usbserial-* 2>/dev/null").splitlines()
|
44
|
+
)
|
45
|
+
if not ports:
|
46
|
+
click.echo("❌ No USB serial device found.")
|
47
|
+
raise SystemExit(1)
|
48
|
+
|
49
|
+
click.echo(f"Connecting to device with picocom ({baud} baud)...")
|
50
|
+
click.echo("🧷 To exit: Press Ctrl + A, then Ctrl + X")
|
51
|
+
click.echo("📜 Scrollback will work in your terminal as expected.\n")
|
52
|
+
|
53
|
+
if not click.confirm("Proceed to connect?", default=True):
|
54
|
+
click.echo("❎ Connection aborted by user.")
|
55
|
+
return
|
56
|
+
|
57
|
+
port = ports[0]
|
58
|
+
click.echo(f"🔌 Connecting to {port} with picocom (115200 8N1)...")
|
59
|
+
try:
|
60
|
+
subprocess.run([
|
61
|
+
terminal,
|
62
|
+
"-b", f"{baud}",
|
63
|
+
"--databits", "8",
|
64
|
+
"--parity", "n",
|
65
|
+
"--stopbits", "1",
|
66
|
+
port
|
67
|
+
])
|
68
|
+
except KeyboardInterrupt:
|
69
|
+
click.echo("\n❎ Serial connection interrupted by user.")
|
70
|
+
|
71
|
+
|
72
|
+
def _connect_linux(baud):
|
73
|
+
terminal = "picocom"
|
74
|
+
if not shutil.which(terminal):
|
75
|
+
click.echo("⚙️ 'picocom' is not installed. Attempting to install via apt...")
|
76
|
+
if shutil.which("apt-get"):
|
77
|
+
subprocess.run(["sudo", "apt-get", "update"], check=True)
|
78
|
+
subprocess.run(["sudo", "apt-get", "install", "-y", "picocom"], check=True)
|
79
|
+
else:
|
80
|
+
click.echo("❌ 'apt-get' not found. Please install picocom manually.")
|
81
|
+
raise SystemExit(1)
|
82
|
+
|
83
|
+
ports = sorted(
|
84
|
+
subprocess.getoutput("ls /dev/ttyUSB* 2>/dev/null").splitlines()
|
85
|
+
)
|
86
|
+
if not ports:
|
87
|
+
click.echo("❌ No USB serial device found.")
|
88
|
+
raise SystemExit(1)
|
89
|
+
|
90
|
+
port = ports[0]
|
91
|
+
click.echo(f"🔌 Connecting to {port} with picocom ({baud} 8N1)...")
|
92
|
+
try:
|
93
|
+
subprocess.run(
|
94
|
+
["sudo", terminal, "-b", f"{baud}", "--databits", "8", "--parity", "n", "--stopbits", "1", port]
|
95
|
+
)
|
96
|
+
except KeyboardInterrupt:
|
97
|
+
click.echo("\n❎ Serial connection interrupted by user.")
|
98
|
+
|
99
|
+
|
100
|
+
def _print_windows_instructions():
|
101
|
+
click.echo("📘 To connect to the DevKit via a serial terminal on Windows, follow these steps:\n")
|
102
|
+
|
103
|
+
click.echo("1. Identify the COM Port:")
|
104
|
+
click.echo(" • Open **Device Manager** → Expand **Ports (COM & LPT)**.")
|
105
|
+
click.echo(" • Look for an entry like **USB Serial Port (COMx)**.\n")
|
106
|
+
|
107
|
+
click.echo("2. Install and Open a Serial Terminal:")
|
108
|
+
click.echo(" • Use **PuTTY** (Download from https://www.putty.org/) or **Tera Term**.")
|
109
|
+
click.echo(" • Set the **Connection Type** to **Serial**.")
|
110
|
+
click.echo(" • Enter the correct **COM Port** (e.g., COM3).")
|
111
|
+
click.echo(" • Set **Baud Rate** to **115200**.")
|
112
|
+
click.echo(" • Click **Open** to start the connection.\n")
|
113
|
+
|
114
|
+
click.echo("🔌 You are now ready to connect to the DevKit over serial.")
|