diff --git a/edge-ai-platform/installer/platform_linux.go b/edge-ai-platform/installer/platform_linux.go index f486301..095f234 100644 --- a/edge-ai-platform/installer/platform_linux.go +++ b/edge-ai-platform/installer/platform_linux.go @@ -43,18 +43,51 @@ func removeSystemLink() { } func installLibusb(installDir string) error { - // Check if already installed - if _, err := exec.LookPath("lsusb"); err == nil { - return nil + // Install libusb if not present + if exec.Command("dpkg", "-s", "libusb-1.0-0-dev").Run() != nil { + cmd := exec.Command("pkexec", "apt-get", "install", "-y", "libusb-1.0-0-dev") + if out, err := cmd.CombinedOutput(); err != nil { + return fmt.Errorf("apt install libusb failed: %s — %w", string(out), err) + } } - cmd := exec.Command("pkexec", "apt-get", "install", "-y", "libusb-1.0-0-dev") - if out, err := cmd.CombinedOutput(); err != nil { - return fmt.Errorf("apt install libusb failed: %s — %w", string(out), err) - } + // Install udev rules so non-root users can access Kneron USB devices + installKneronUdevRules() + return nil } +// installKneronUdevRules writes a udev rule file granting non-root access +// to Kneron KL520/KL720 USB devices and reloads udev. +func installKneronUdevRules() { + const rulesPath = "/etc/udev/rules.d/99-kneron.rules" + + // Skip if already installed + if _, err := os.Stat(rulesPath); err == nil { + return + } + + rules := strings.Join([]string{ + `# Kneron KL520`, + `SUBSYSTEM=="usb", ATTR{idVendor}=="3231", ATTR{idProduct}=="0100", MODE="0666"`, + `# Kneron KL720 KDP (legacy)`, + `SUBSYSTEM=="usb", ATTR{idVendor}=="3231", ATTR{idProduct}=="0200", MODE="0666"`, + `# Kneron KL720 KDP2`, + `SUBSYSTEM=="usb", ATTR{idVendor}=="3231", ATTR{idProduct}=="0720", MODE="0666"`, + }, "\n") + "\n" + + // Write to a temp file then move with pkexec (needs root) + tmpFile := filepath.Join(os.TempDir(), "99-kneron.rules") + if err := os.WriteFile(tmpFile, []byte(rules), 0644); err != nil { + return + } + defer os.Remove(tmpFile) + + exec.Command("pkexec", "cp", tmpFile, rulesPath).Run() + exec.Command("pkexec", "udevadm", "control", "--reload-rules").Run() + exec.Command("pkexec", "udevadm", "trigger").Run() +} + func checkLibusbInstalled() bool { return exec.Command("dpkg", "-s", "libusb-1.0-0-dev").Run() == nil } diff --git a/edge-ai-platform/scripts/install.sh b/edge-ai-platform/scripts/install.sh index 223f3e2..ed5dc00 100755 --- a/edge-ai-platform/scripts/install.sh +++ b/edge-ai-platform/scripts/install.sh @@ -116,6 +116,30 @@ setup_python_venv() { info "Installing pyusb ..." "$VENV_DIR/bin/pip" install --quiet pyusb + # Install KneronPLUS SDK wheel if bundled + local scripts_dir="$INSTALL_DIR/scripts" + local os_type + os_type="$(uname -s)" + local kp_wheel="" + + if [ "$os_type" = "Darwin" ]; then + # macOS wheels are stored in scripts/macos/ subdirectory + kp_wheel="$(ls "$scripts_dir"/macos/KneronPLUS*.whl 2>/dev/null | head -1)" + fi + if [ -z "$kp_wheel" ]; then + kp_wheel="$(ls "$scripts_dir"/KneronPLUS*.whl 2>/dev/null | head -1)" + fi + + if [ -n "$kp_wheel" ]; then + info "Installing Kneron SDK: $(basename "$kp_wheel") ..." + "$VENV_DIR/bin/pip" install --quiet "$kp_wheel" || true + + # On macOS, ad-hoc codesign bundled dylibs for Gatekeeper + if [ "$os_type" = "Darwin" ]; then + find "$VENV_DIR" -path "*/kp/lib/*.dylib" -exec codesign --force --sign - {} \; 2>/dev/null || true + fi + fi + info "Python environment ready" } @@ -141,6 +165,22 @@ setup_libusb() { info "Installing libusb ..." sudo apt-get install -y libusb-1.0-0-dev fi + + # Install udev rules so non-root users can access Kneron USB devices + if [ ! -f /etc/udev/rules.d/99-kneron.rules ]; then + info "Installing Kneron USB udev rules ..." + cat <<'UDEV' | sudo tee /etc/udev/rules.d/99-kneron.rules >/dev/null +# Kneron KL520 +SUBSYSTEM=="usb", ATTR{idVendor}=="3231", ATTR{idProduct}=="0100", MODE="0666" +# Kneron KL720 KDP (legacy) +SUBSYSTEM=="usb", ATTR{idVendor}=="3231", ATTR{idProduct}=="0200", MODE="0666" +# Kneron KL720 KDP2 +SUBSYSTEM=="usb", ATTR{idVendor}=="3231", ATTR{idProduct}=="0720", MODE="0666" +UDEV + sudo udevadm control --reload-rules + sudo udevadm trigger + info "udev rules installed. Please re-plug Kneron USB devices." + fi fi } @@ -186,6 +226,12 @@ setup_launchd_service() { ${INSTALL_DIR}/edge-ai-server + EnvironmentVariables + + PATH + /usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin + + WorkingDirectory ${INSTALL_DIR}