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}