diff --git a/local_service_win/LocalAPI/legacy_plus121_runner.py b/local_service_win/LocalAPI/legacy_plus121_runner.py new file mode 100644 index 0000000..62f60a1 --- /dev/null +++ b/local_service_win/LocalAPI/legacy_plus121_runner.py @@ -0,0 +1,297 @@ +from __future__ import annotations + +import ctypes +import hashlib +import json +import os +import sys +import time +from pathlib import Path +from typing import Any, Dict + +KDP_MAGIC_CONNECTION_PASS = 536173391 +KP_SUCCESS = 0 +KP_RESET_REBOOT = 0 +USB_WAIT_CONNECT_DELAY_MS = 100 +USB_WAIT_AFTER_REBOOT_MS = 2000 +USB_WAIT_RETRY_CONNECT_MS = 10 +MAX_RETRY_CONNECT_TIMES = 10 + + +def _normalize_code(code: int) -> int: + # Some legacy paths may return int8-like unsigned values (e.g. 253 for -3). + if code > 127: + return code - 256 + return code + + +def _load_libkplus(dist_root: Path) -> ctypes.CDLL: + lib_dir = dist_root / "kp" / "lib" + dll_path = lib_dir / "libkplus.dll" + if not dll_path.is_file(): + raise RuntimeError(f"libkplus.dll not found: {dll_path}") + + if hasattr(os, "add_dll_directory"): + os.add_dll_directory(str(lib_dir)) + + lib = ctypes.CDLL(str(dll_path)) + lib.kp_connect_devices.argtypes = [ctypes.c_int, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int)] + lib.kp_connect_devices.restype = ctypes.c_void_p + lib.kp_set_timeout.argtypes = [ctypes.c_void_p, ctypes.c_int] + lib.kp_set_timeout.restype = None + lib.kp_reset_device.argtypes = [ctypes.c_void_p, ctypes.c_int] + lib.kp_reset_device.restype = ctypes.c_int + lib.kp_load_firmware_from_file.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_char_p] + lib.kp_load_firmware_from_file.restype = ctypes.c_int + lib.kp_update_kdp_firmware_from_files.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_bool] + lib.kp_update_kdp_firmware_from_files.restype = ctypes.c_int + lib.kp_disconnect_devices.argtypes = [ctypes.c_void_p] + lib.kp_disconnect_devices.restype = ctypes.c_int + lib.kp_scan_devices.argtypes = [] + lib.kp_scan_devices.restype = ctypes.c_void_p + if hasattr(lib, "kp_error_string"): + lib.kp_error_string.argtypes = [ctypes.c_int] + lib.kp_error_string.restype = ctypes.c_char_p + return lib + + +def _errstr(lib: ctypes.CDLL, code: int) -> str: + signed_code = _normalize_code(code) + if hasattr(lib, "kp_error_string"): + try: + msg = lib.kp_error_string(int(code)) + if not msg and signed_code != code: + msg = lib.kp_error_string(int(signed_code)) + if msg: + return msg.decode("utf-8", errors="replace") + except Exception: + pass + return str(code) + + +def _find_port_id_with_kp(dist_root: Path, port_id: int | None, scan_index: int | None) -> int: + if port_id is not None: + return int(port_id) + + sys.path.insert(0, str(dist_root)) + import kp + + device_list = kp.core.scan_devices() + if device_list.device_descriptor_number == 0: + raise RuntimeError("NO_DEVICE: no device found") + + idx = 0 if scan_index is None else int(scan_index) + if idx < 0 or idx >= device_list.device_descriptor_number: + raise RuntimeError(f"INVALID_SCAN_INDEX: {idx}") + return int(device_list.device_descriptor_list[idx].usb_port_id) + + +def _file_diag(path_str: str) -> Dict[str, Any]: + p = Path(path_str) + info: Dict[str, Any] = { + "path": str(p), + "name": p.name, + "exists": p.is_file(), + } + if not p.is_file(): + return info + data = p.read_bytes() + info["size_bytes"] = len(data) + info["sha256"] = hashlib.sha256(data).hexdigest() + return info + + +def _scan_diag_with_kp(dist_root: Path) -> Dict[str, Any]: + sys.path.insert(0, str(dist_root)) + import kp + + scanned = [] + dev_list = kp.core.scan_devices() + num = int(dev_list.device_descriptor_number) + for i in range(num): + d = dev_list.device_descriptor_list[i] + scanned.append( + { + "scan_index": i, + "usb_port_id": int(d.usb_port_id), + "vendor_id": int(d.vendor_id), + "product_id": f"0x{int(d.product_id):04X}", + "link_speed": str(d.link_speed), + "usb_port_path": str(d.usb_port_path), + "is_connectable": bool(d.is_connectable), + "firmware": str(d.firmware), + } + ) + return {"count": num, "devices": scanned} + + +def _firmware_from_scan(scan_diag: Dict[str, Any], port_id: int) -> str: + for d in scan_diag.get("devices", []): + if int(d.get("usb_port_id", -1)) == int(port_id): + return str(d.get("firmware", "")).upper() + return "" + + +def _product_id_from_scan(scan_diag: Dict[str, Any], port_id: int) -> int | None: + for d in scan_diag.get("devices", []): + if int(d.get("usb_port_id", -1)) != int(port_id): + continue + raw = d.get("product_id") + if raw is None: + return None + text = str(raw).strip() + try: + if text.lower().startswith("0x"): + return int(text, 16) + return int(text) + except Exception: + return None + return None + + +def _connect_with_magic(lib: ctypes.CDLL, port_id: int) -> ctypes.c_void_p: + port_ids = (ctypes.c_int * 1)(int(port_id)) + status = ctypes.c_int(KDP_MAGIC_CONNECTION_PASS) + device_group = lib.kp_connect_devices(1, port_ids, ctypes.byref(status)) + if not device_group or status.value != KP_SUCCESS: + signed = _normalize_code(status.value) + raise RuntimeError( + f"CONNECT_FAILED: raw_code={status.value}, signed_code={signed}, msg={_errstr(lib, status.value)}" + ) + return device_group + + +def _reboot_and_reconnect(lib: ctypes.CDLL, device_group: ctypes.c_void_p, port_id: int) -> ctypes.c_void_p: + time.sleep(USB_WAIT_CONNECT_DELAY_MS / 1000.0) + ret = lib.kp_reset_device(device_group, KP_RESET_REBOOT) + if ret != KP_SUCCESS: + raise RuntimeError( + f"RESET_FAILED: raw_code={ret}, signed_code={_normalize_code(ret)}, msg={_errstr(lib, ret)}" + ) + time.sleep(USB_WAIT_AFTER_REBOOT_MS / 1000.0) + lib.kp_disconnect_devices(device_group) + + retries = 0 + while retries <= MAX_RETRY_CONNECT_TIMES: + try: + return _connect_with_magic(lib, port_id) + except RuntimeError: + time.sleep(USB_WAIT_RETRY_CONNECT_MS / 1000.0) + retries += 1 + + raise RuntimeError("RECONNECT_FAILED: max retry exceeded") + + +def main() -> None: + stage = "init" + diag: Dict[str, Any] = {} + try: + if len(sys.argv) != 2: + raise RuntimeError("missing json payload argument") + + req: Dict[str, Any] = json.loads(sys.argv[1]) + dist_root = Path(req["legacy_dist_root"]) + lib = _load_libkplus(dist_root) + + stage = "resolve_port" + port_id = _find_port_id_with_kp(dist_root, req.get("port_id"), req.get("scan_index")) + timeout_ms = req.get("timeout_ms", 5000) + scpu_path = req["scpu_path"] + ncpu_path = req["ncpu_path"] + loader_path = req.get("loader_path") or str(Path(scpu_path).with_name("fw_loader.bin")) + scan_diag = _scan_diag_with_kp(dist_root) + detected_firmware = _firmware_from_scan(scan_diag, int(port_id)) + selected_product_id = _product_id_from_scan(scan_diag, int(port_id)) + diag = { + "selected_port_id": int(port_id), + "selected_product_id": ( + f"0x{int(selected_product_id):04X}" if selected_product_id is not None else None + ), + "timeout_ms": int(timeout_ms) if timeout_ms is not None else None, + "firmware_files": { + "loader": _file_diag(loader_path), + "scpu": _file_diag(scpu_path), + "ncpu": _file_diag(ncpu_path), + }, + "scan": scan_diag, + "detected_firmware": detected_firmware, + } + + stage = "connect" + device_group = _connect_with_magic(lib, port_id) + + stage = "set_timeout" + if timeout_ms is not None: + lib.kp_set_timeout(device_group, int(timeout_ms)) + + method = "" + if detected_firmware == "KDP": + if not Path(loader_path).is_file(): + raise RuntimeError(f"LOADER_NOT_FOUND: {loader_path}") + + stage = "fw_switch_to_usb_boot_loader" + ret = lib.kp_update_kdp_firmware_from_files( + device_group, + loader_path.encode("utf-8"), + None, + True, + ) + method = "kp_update_kdp_firmware_from_files(loader)->kp_load_firmware_from_file" + if ret != KP_SUCCESS: + stage = "disconnect_after_fw_fail" + lib.kp_disconnect_devices(device_group) + raise RuntimeError( + f"FW_LOAD_FAILED: method={method}, raw_code={ret}, msg={_errstr(lib, ret)}" + ) + + stage = "fw_load_kdp2_after_loader" + if timeout_ms is not None: + lib.kp_set_timeout(device_group, int(timeout_ms)) + ret = lib.kp_load_firmware_from_file( + device_group, + scpu_path.encode("utf-8"), + ncpu_path.encode("utf-8"), + ) + else: + stage = "fw_load_kdp2_direct" + method = "kp_load_firmware_from_file_direct" + ret = lib.kp_load_firmware_from_file( + device_group, + scpu_path.encode("utf-8"), + ncpu_path.encode("utf-8"), + ) + + if ret != KP_SUCCESS: + stage = "disconnect_after_fw_fail" + lib.kp_disconnect_devices(device_group) + raise RuntimeError( + f"FW_LOAD_FAILED: method={method}, raw_code={ret}, msg={_errstr(lib, ret)}" + ) + + stage = "disconnect_after_fw_success" + # After firmware update with auto_reboot, disconnect may fail due to USB re-enumeration. + disc = lib.kp_disconnect_devices(device_group) + if disc != KP_SUCCESS: + disc_info = f"disconnect_nonzero_raw={disc},signed={_normalize_code(disc)}" + else: + disc_info = "disconnect_ok" + + print( + json.dumps( + { + "ok": True, + "port_id": int(port_id), + "connect_mode": "kp_connect_devices_with_magic_pass", + "firmware_method": method, + "disconnect_info": disc_info, + "diag": diag, + } + ) + ) + except Exception as exc: + print(json.dumps({"ok": False, "stage": stage, "error": str(exc), "diag": diag})) + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/local_service_win/LocalAPI/main.py b/local_service_win/LocalAPI/main.py index 8b60e8d..a807d11 100644 --- a/local_service_win/LocalAPI/main.py +++ b/local_service_win/LocalAPI/main.py @@ -1,8 +1,13 @@ from __future__ import annotations import base64 +import json +import os +import subprocess +import sys import threading from dataclasses import dataclass +from pathlib import Path from typing import Any, Dict, List, Optional from fastapi import FastAPI, HTTPException, Request @@ -13,6 +18,12 @@ import kp SERVICE_VERSION = "0.1.0" +PROJECT_ROOT = Path(__file__).resolve().parent.parent +DFUT_ROOT = PROJECT_ROOT / "third_party" / "Kneron_DFUT" +DFUT_BIN = DFUT_ROOT / "bin" +DFUT_EXE = DFUT_BIN / "KneronDFUT.exe" +KP121_DIST = PROJECT_ROOT / "third_party" / "kneron_plus_1_2_1" / "dist" +KP121_RUNNER = Path(__file__).resolve().parent / "legacy_plus121_runner.py" @dataclass @@ -45,37 +56,77 @@ def _require_device() -> kp.DeviceGroup: def _image_format_from_str(value: str) -> kp.ImageFormat: value = value.upper() - mapping = { - "RGB565": kp.ImageFormat.KP_IMAGE_FORMAT_RGB565, - "RGBA8888": kp.ImageFormat.KP_IMAGE_FORMAT_RGBA8888, - "RAW8": kp.ImageFormat.KP_IMAGE_FORMAT_RAW8, - "YUYV": kp.ImageFormat.KP_IMAGE_FORMAT_YUYV, - "YUV420": kp.ImageFormat.KP_IMAGE_FORMAT_YUV420, + # Build mapping from symbols that exist in the installed kp version. + candidate_names = { + "RGB565": "KP_IMAGE_FORMAT_RGB565", + "RGBA8888": "KP_IMAGE_FORMAT_RGBA8888", + "RAW8": "KP_IMAGE_FORMAT_RAW8", + "YUYV": "KP_IMAGE_FORMAT_YUYV", + "YUV420": "KP_IMAGE_FORMAT_YUV420", } + mapping: Dict[str, kp.ImageFormat] = {} + for key, attr_name in candidate_names.items(): + enum_value = getattr(kp.ImageFormat, attr_name, None) + if enum_value is not None: + mapping[key] = enum_value if value not in mapping: + supported = ", ".join(sorted(mapping.keys())) raise HTTPException( status_code=400, - detail=_err("INVALID_IMAGE_FORMAT", f"Unsupported image_format: {value}"), + detail=_err( + "INVALID_IMAGE_FORMAT", + f"Unsupported image_format: {value}. supported=[{supported}]", + ), ) return mapping[value] def _channels_ordering_from_str(value: str) -> kp.ChannelOrdering: value = value.upper() - mapping = { - "HCW": kp.ChannelOrdering.KP_CHANNEL_ORDERING_HCW, - "CHW": kp.ChannelOrdering.KP_CHANNEL_ORDERING_CHW, - "HWC": kp.ChannelOrdering.KP_CHANNEL_ORDERING_HWC, - "DEFAULT": kp.ChannelOrdering.KP_CHANNEL_ORDERING_DEFAULT, + candidate_names = { + "HCW": "KP_CHANNEL_ORDERING_HCW", + "CHW": "KP_CHANNEL_ORDERING_CHW", + "HWC": "KP_CHANNEL_ORDERING_HWC", + "DEFAULT": "KP_CHANNEL_ORDERING_DEFAULT", } + mapping: Dict[str, kp.ChannelOrdering] = {} + for key, attr_name in candidate_names.items(): + enum_value = getattr(kp.ChannelOrdering, attr_name, None) + if enum_value is not None: + mapping[key] = enum_value + if "DEFAULT" not in mapping: + if "CHW" in mapping: + mapping["DEFAULT"] = mapping["CHW"] + elif "HCW" in mapping: + mapping["DEFAULT"] = mapping["HCW"] if value not in mapping: + supported = ", ".join(sorted(mapping.keys())) raise HTTPException( status_code=400, - detail=_err("INVALID_CHANNEL_ORDERING", f"Unsupported channels_ordering: {value}"), + detail=_err( + "INVALID_CHANNEL_ORDERING", + f"Unsupported channels_ordering: {value}. supported=[{supported}]", + ), ) return mapping[value] +def _expected_image_size_bytes(image_format: str, width: int, height: int) -> Optional[int]: + fmt = image_format.upper() + if fmt == "RGB565": + return width * height * 2 + if fmt == "RGBA8888": + return width * height * 4 + if fmt == "RAW8": + return width * height + if fmt == "YUYV": + return width * height * 2 + if fmt == "YUV420": + # YUV420 requires even width/height; caller checks exact size only. + return (width * height * 3) // 2 + return None + + def _product_name_from_id(product_id: int) -> str: try: return kp.ProductId(product_id).name.replace("KP_DEVICE_", "") @@ -112,10 +163,24 @@ class FirmwareLoadRequest(BaseModel): ncpu_path: str +class LegacyPlusFirmwareLoadRequest(BaseModel): + port_id: Optional[int] = Field(default=None) + scan_index: Optional[int] = Field(default=None) + timeout_ms: Optional[int] = Field(default=5000) + loader_path: Optional[str] = Field(default=None) + scpu_path: str + ncpu_path: str + + class ModelLoadRequest(BaseModel): nef_path: str +class DriverInstallRequest(BaseModel): + target: str = "ALL" # ALL | KL520 | KL720 | KL630 | KL730 | KL830 + force: bool = False + + class InferenceRunRequest(BaseModel): model_id: int image_format: str @@ -126,6 +191,316 @@ class InferenceRunRequest(BaseModel): output_dtype: str = "float32" +def _resolve_port_id(req: ConnectRequest) -> int: + port_id = req.port_id + if port_id is not None: + return int(port_id) + + device_list = kp.core.scan_devices() + if device_list.device_descriptor_number == 0: + raise HTTPException(status_code=404, detail=_err("NO_DEVICE", "No device found")) + + scan_index = 0 if req.scan_index is None else req.scan_index + if scan_index < 0 or scan_index >= device_list.device_descriptor_number: + raise HTTPException( + status_code=400, + detail=_err("INVALID_SCAN_INDEX", f"Invalid scan_index: {scan_index}"), + ) + return int(device_list.device_descriptor_list[scan_index].usb_port_id) + + +def _scan_devices_snapshot() -> List[Dict[str, Any]]: + device_list = kp.core.scan_devices() + out: List[Dict[str, Any]] = [] + for i in range(int(device_list.device_descriptor_number)): + d = device_list.device_descriptor_list[i] + out.append( + { + "scan_index": i, + "usb_port_id": int(d.usb_port_id), + "product_id": int(d.product_id), + "firmware": str(d.firmware), + "usb_port_path": str(d.usb_port_path), + } + ) + return out + + +def _kl520_kdp_observed_after_timeout(target_port_id: int) -> Dict[str, Any]: + devices = _scan_devices_snapshot() + kl520 = [d for d in devices if int(d["product_id"]) == 0x0100] + exact = [d for d in kl520 if int(d["usb_port_id"]) == int(target_port_id)] + exact_kdp = [d for d in exact if "KDP" in str(d["firmware"]).upper()] + if exact_kdp: + return {"is_success": True, "reason": "exact_port_kdp", "devices": devices} + if not exact: + any_kdp = [d for d in kl520 if "KDP" in str(d["firmware"]).upper()] + if any_kdp: + return {"is_success": True, "reason": "reenumerated_port_kdp", "devices": devices} + return {"is_success": False, "reason": "kdp_not_observed", "devices": devices} + + +def _ensure_file_exists(path: Path, label: str) -> None: + if not path.is_file(): + raise HTTPException( + status_code=500, + detail=_err("FILE_NOT_FOUND", f"{label} not found: {path}"), + ) + + +def _run_dfut_command( + args: List[str], + timeout_sec: int = 180, + echo_console: bool = False, + echo_tag: str = "DFUT", +) -> Dict[str, Any]: + _ensure_file_exists(DFUT_EXE, "DFUT executable") + if echo_console: + print(f"[{echo_tag}] CMD: {' '.join(args)}", flush=True) + + stdout_lines: List[str] = [] + stderr_lines: List[str] = [] + + proc = subprocess.Popen( + args, + cwd=str(DFUT_BIN), + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + encoding="utf-8", + errors="replace", + bufsize=1, + ) + + def _read_stream(stream: Any, collector: List[str], stream_name: str) -> None: + if stream is None: + return + try: + for line in iter(stream.readline, ""): + text = line.rstrip("\r\n") + collector.append(text) + if echo_console: + print(f"[{echo_tag}][{stream_name}] {text}", flush=True) + finally: + try: + stream.close() + except Exception: + pass + + t_out = threading.Thread(target=_read_stream, args=(proc.stdout, stdout_lines, "STDOUT"), daemon=True) + t_err = threading.Thread(target=_read_stream, args=(proc.stderr, stderr_lines, "STDERR"), daemon=True) + t_out.start() + t_err.start() + + try: + proc.wait(timeout=timeout_sec) + except subprocess.TimeoutExpired as exc: + proc.kill() + proc.wait() + t_out.join(timeout=1.0) + t_err.join(timeout=1.0) + stdout_text = "\n".join(stdout_lines).strip() + stderr_text = "\n".join(stderr_lines).strip() + raise HTTPException( + status_code=504, + detail=_err( + "DFUT_TIMEOUT", + ( + f"DFUT timed out after {timeout_sec}s. " + f"stdout={stdout_text} " + f"stderr={stderr_text}" + ), + ), + ) + t_out.join(timeout=1.0) + t_err.join(timeout=1.0) + + stdout_text = "\n".join(stdout_lines).strip() + stderr_text = "\n".join(stderr_lines).strip() + if proc.returncode != 0: + signed_code = proc.returncode + if signed_code > 0x7FFFFFFF: + signed_code -= 0x100000000 + raise HTTPException( + status_code=500, + detail=_err( + "DFUT_FAILED", + ( + f"DFUT failed with return code {proc.returncode} (signed={signed_code}). " + f"command={args}. " + f"stdout={stdout_text} " + f"stderr={stderr_text}" + ), + ), + ) + return { + "return_code": proc.returncode, + "stdout": stdout_text, + "stderr": stderr_text, + "command": args, + } + + +def _run_legacy_plus121_load_firmware(req: LegacyPlusFirmwareLoadRequest) -> Dict[str, Any]: + _ensure_file_exists(KP121_RUNNER, "Legacy 1.2.1 runner") + if not KP121_DIST.is_dir(): + raise HTTPException( + status_code=500, + detail=_err( + "LEGACY_PLUS_NOT_FOUND", + f"Legacy KneronPLUS 1.2.1 package directory not found: {KP121_DIST}", + ), + ) + + payload = { + "port_id": req.port_id, + "scan_index": req.scan_index, + "timeout_ms": req.timeout_ms, + "loader_path": req.loader_path, + "scpu_path": req.scpu_path, + "ncpu_path": req.ncpu_path, + "legacy_dist_root": str(KP121_DIST), + } + + env = os.environ.copy() + existing_pythonpath = env.get("PYTHONPATH", "") + legacy_pythonpath = str(KP121_DIST) + env["PYTHONPATH"] = ( + f"{legacy_pythonpath}{os.pathsep}{existing_pythonpath}" + if existing_pythonpath + else legacy_pythonpath + ) + + proc = subprocess.run( + [sys.executable, str(KP121_RUNNER), json.dumps(payload)], + cwd=str(PROJECT_ROOT), + capture_output=True, + text=True, + encoding="utf-8", + errors="replace", + env=env, + ) + + if proc.returncode != 0: + runner_json = None + if proc.stdout.strip(): + try: + runner_json = json.loads(proc.stdout.strip().splitlines()[-1]) + except json.JSONDecodeError: + runner_json = None + debug_payload = { + "return_code": proc.returncode, + "stdout": proc.stdout.strip(), + "stderr": proc.stderr.strip(), + "runner_json": runner_json, + } + print("[legacy-plus121-runner-failed]", json.dumps(debug_payload, ensure_ascii=False)) + raise HTTPException( + status_code=500, + detail=_err( + "LEGACY_PLUS_FW_LOAD_FAILED", + json.dumps(debug_payload, ensure_ascii=False), + ), + ) + + parsed = {} + if proc.stdout.strip(): + try: + parsed = json.loads(proc.stdout.strip().splitlines()[-1]) + except json.JSONDecodeError: + parsed = {"raw_stdout": proc.stdout.strip()} + + return { + "return_code": proc.returncode, + "result": parsed, + } + + +def _target_product_ids(target: str) -> List[kp.ProductId]: + target = target.upper() + if target == "KL520": + return [kp.ProductId.KP_DEVICE_KL520] + if target == "KL720": + return [kp.ProductId.KP_DEVICE_KL720_LEGACY, kp.ProductId.KP_DEVICE_KL720] + if target == "KL630": + return [kp.ProductId.KP_DEVICE_KL630] + if target == "KL730": + return [kp.ProductId.KP_DEVICE_KL730] + if target == "KL830": + return [kp.ProductId.KP_DEVICE_KL830] + if target == "ALL": + return [ + kp.ProductId.KP_DEVICE_KL520, + kp.ProductId.KP_DEVICE_KL720_LEGACY, + kp.ProductId.KP_DEVICE_KL720, + kp.ProductId.KP_DEVICE_KL630, + kp.ProductId.KP_DEVICE_KL730, + kp.ProductId.KP_DEVICE_KL830, + ] + raise HTTPException(status_code=400, detail=_err("INVALID_TARGET", f"Unsupported target: {target}")) + + +def _pid_to_product_name(pid_value: int) -> str: + try: + return kp.ProductId(pid_value).name.replace("KP_DEVICE_", "") + except ValueError: + return f"UNKNOWN_0x{pid_value:04X}" + + +def _query_windows_driver_status() -> List[Dict[str, Any]]: + # Query current connected Kneron USB devices from Windows PnP layer. + ps = ( + "$items = Get-CimInstance Win32_PnPEntity | " + "Where-Object { $_.PNPDeviceID -like 'USB\\VID_3231&PID_*' } | " + "Select-Object PNPDeviceID,Name,Service,Status; " + "if ($null -eq $items) { '[]' } else { $items | ConvertTo-Json -Depth 3 }" + ) + proc = subprocess.run( + ["powershell", "-NoProfile", "-Command", ps], + capture_output=True, + text=True, + encoding="utf-8", + errors="replace", + ) + if proc.returncode != 0: + raise HTTPException( + status_code=500, + detail=_err("DRIVER_CHECK_FAILED", proc.stderr.strip() or "failed to query Windows PnP devices"), + ) + + out = proc.stdout.strip() + if not out: + return [] + try: + parsed = json.loads(out) + except json.JSONDecodeError: + return [] + if isinstance(parsed, dict): + parsed = [parsed] + + results = [] + for item in parsed: + pnp_id = item.get("PNPDeviceID", "") + pid_hex = "" + if "PID_" in pnp_id: + pid_hex = pnp_id.split("PID_")[1][:4] + pid_val = int(pid_hex, 16) if pid_hex else None + service = item.get("Service") or "" + results.append( + { + "pnp_device_id": pnp_id, + "name": item.get("Name"), + "status": item.get("Status"), + "service": service, + "pid_hex": f"0x{pid_hex}" if pid_hex else None, + "pid_value": pid_val, + "product_name": _pid_to_product_name(pid_val) if pid_val is not None else "UNKNOWN", + "is_winusb": service.lower() == "winusb", + } + ) + return results + + @app.get("/health") def health() -> Dict[str, Any]: return _ok({"status": "up"}) @@ -175,21 +550,7 @@ def connect(req: ConnectRequest) -> Dict[str, Any]: STATE.port_id = None STATE.model_desc = None - port_id = req.port_id - if port_id is None: - device_list = kp.core.scan_devices() - if device_list.device_descriptor_number == 0: - raise HTTPException(status_code=404, detail=_err("NO_DEVICE", "No device found")) - if req.scan_index is None: - scan_index = 0 - else: - scan_index = req.scan_index - if scan_index < 0 or scan_index >= device_list.device_descriptor_number: - raise HTTPException( - status_code=400, - detail=_err("INVALID_SCAN_INDEX", f"Invalid scan_index: {scan_index}"), - ) - port_id = device_list.device_descriptor_list[scan_index].usb_port_id + port_id = _resolve_port_id(req) try: device_group = kp.core.connect_devices([int(port_id)]) @@ -206,6 +567,35 @@ def connect(req: ConnectRequest) -> Dict[str, Any]: return _ok({"connected": True, "port_id": STATE.port_id}) +@app.post("/devices/connect_force") +def connect_force(req: ConnectRequest) -> Dict[str, Any]: + with STATE_LOCK: + if STATE.device_group is not None: + try: + kp.core.disconnect_devices(STATE.device_group) + except kp.ApiKPException: + pass + STATE.device_group = None + STATE.port_id = None + STATE.model_desc = None + + port_id = _resolve_port_id(req) + + try: + device_group = kp.core.connect_devices_without_check([int(port_id)]) + if req.timeout_ms is not None: + kp.core.set_timeout(device_group, int(req.timeout_ms)) + except kp.ApiKPException as exc: + raise HTTPException( + status_code=500, + detail=_err(str(exc.api_return_code), str(exc)), + ) + + STATE.device_group = device_group + STATE.port_id = int(port_id) + return _ok({"connected": True, "port_id": STATE.port_id, "forced": True}) + + @app.post("/devices/disconnect") def disconnect() -> Dict[str, Any]: with STATE_LOCK: @@ -223,6 +613,70 @@ def disconnect() -> Dict[str, Any]: return _ok({"connected": False}) +@app.get("/driver/check") +def driver_check() -> Dict[str, Any]: + entries = _query_windows_driver_status() + all_winusb = all(entry["is_winusb"] for entry in entries) if entries else False + return _ok( + { + "entries": entries, + "all_connected_kneron_are_winusb": all_winusb, + "count": len(entries), + "note": "Run service as Administrator if driver install/update fails.", + } + ) + + +@app.post("/driver/install") +def driver_install(req: DriverInstallRequest) -> Dict[str, Any]: + targets = _target_product_ids(req.target) + results = [] + for product_id in targets: + try: + kp.core.install_driver_for_windows(product_id=product_id) + results.append({"product_id": f"0x{product_id.value:04X}", "product_name": product_id.name, "installed": True}) + except kp.ApiKPException as exc: + results.append( + { + "product_id": f"0x{product_id.value:04X}", + "product_name": product_id.name, + "installed": False, + "error_code": str(exc.api_return_code), + "error_message": str(exc), + } + ) + return _ok({"target": req.target.upper(), "results": results}) + + +@app.post("/driver/ensure") +def driver_ensure(req: DriverInstallRequest) -> Dict[str, Any]: + target = req.target.upper() + target_ids = _target_product_ids(target) + target_pid_values = {pid.value for pid in target_ids} + + entries = _query_windows_driver_status() + needs_install = req.force + for entry in entries: + if entry["pid_value"] in target_pid_values and not entry["is_winusb"]: + needs_install = True + break + + install_result = None + if needs_install: + install_result = driver_install(req) + + after = _query_windows_driver_status() + return _ok( + { + "target": target, + "needed_install": needs_install, + "install_result": install_result["data"] if install_result else None, + "before": entries, + "after": after, + } + ) + + @app.post("/firmware/load") def firmware_load(req: FirmwareLoadRequest) -> Dict[str, Any]: device_group = _require_device() @@ -236,6 +690,145 @@ def firmware_load(req: FirmwareLoadRequest) -> Dict[str, Any]: return _ok({"loaded": True}) +@app.post("/firmware/legacy-plus121/load") +def firmware_legacy_plus121_load(req: LegacyPlusFirmwareLoadRequest) -> Dict[str, Any]: + # Ensure current process does not hold USB handles before legacy subprocess runs. + with STATE_LOCK: + if STATE.device_group is not None: + try: + kp.core.disconnect_devices(STATE.device_group) + except kp.ApiKPException: + pass + STATE.device_group = None + STATE.port_id = None + STATE.model_desc = None + + _ensure_file_exists(Path(req.scpu_path), "Legacy SCPU firmware") + _ensure_file_exists(Path(req.ncpu_path), "Legacy NCPU firmware") + if req.loader_path is not None: + _ensure_file_exists(Path(req.loader_path), "Legacy loader firmware") + result = _run_legacy_plus121_load_firmware(req) + return _ok({"loaded": True, "legacy_plus_version": "1.2.1", "runner": result}) + + +@app.post("/firmware/legacy-upgrade/kl520") +def firmware_legacy_upgrade_kl520(req: ConnectRequest) -> Dict[str, Any]: + print("[DFUT-KL520-UPGRADE] endpoint entered", flush=True) + port_id = _resolve_port_id(req) + print(f"[DFUT-KL520-UPGRADE] resolved port_id={port_id}", flush=True) + fw_scpu = PROJECT_ROOT / "firmware" / "KL520" / "fw_scpu.bin" + fw_ncpu = PROJECT_ROOT / "firmware" / "KL520" / "fw_ncpu.bin" + _ensure_file_exists(fw_scpu, "KL520 SCPU firmware") + _ensure_file_exists(fw_ncpu, "KL520 NCPU firmware") + + args = [ + str(DFUT_EXE), + "--kl520-flash-boot", + "--port", + str(port_id), + "--scpu", + str(fw_scpu), + "--ncpu", + str(fw_ncpu), + "--quiet", + ] + result = _run_dfut_command(args, echo_console=True, echo_tag="DFUT-KL520-UPGRADE") + return _ok( + { + "upgraded": True, + "target": "KL520", + "port_id": port_id, + "dfut": result, + } + ) + + +@app.post("/firmware/legacy-downgrade/kl520") +def firmware_legacy_downgrade_kl520(req: ConnectRequest) -> Dict[str, Any]: + port_id = _resolve_port_id(req) + fw_scpu = PROJECT_ROOT / "firmware" / "KL520_kdp" / "fw_scpu.bin" + fw_ncpu = PROJECT_ROOT / "firmware" / "KL520_kdp" / "fw_ncpu.bin" + _ensure_file_exists(fw_scpu, "KL520 KDP SCPU firmware") + _ensure_file_exists(fw_ncpu, "KL520 KDP NCPU firmware") + + args = [ + str(DFUT_EXE), + "--kl520-update", + "--port", + str(port_id), + "--scpu", + str(fw_scpu), + "--ncpu", + str(fw_ncpu), + ] + timeout_sec = 30 + try: + result = _run_dfut_command( + args, + timeout_sec=timeout_sec, + echo_console=False, + echo_tag="DFUT-KL520-DOWNGRADE", + ) + except HTTPException as exc: + detail = exc.detail if isinstance(exc.detail, dict) else None + err_code = ( + str(detail.get("error", {}).get("code", "")) if isinstance(detail, dict) else "" + ) + if exc.status_code == 504 and err_code == "DFUT_TIMEOUT": + post = _kl520_kdp_observed_after_timeout(port_id) + if post["is_success"]: + return _ok( + { + "downgraded": True, + "target": "KL520", + "port_id": port_id, + "dfut_timeout_but_verified": True, + "verification_reason": post["reason"], + "scan_after_timeout": post["devices"], + "warning": "DFUT timeout but KL520 KDP state observed after timeout.", + } + ) + raise + return _ok( + { + "downgraded": True, + "target": "KL520", + "port_id": port_id, + "dfut": result, + } + ) + + +@app.post("/firmware/legacy-upgrade/kl720") +def firmware_legacy_upgrade_kl720(req: ConnectRequest) -> Dict[str, Any]: + port_id = _resolve_port_id(req) + fw_scpu = PROJECT_ROOT / "firmware" / "KL720" / "fw_scpu.bin" + fw_ncpu = PROJECT_ROOT / "firmware" / "KL720" / "fw_ncpu.bin" + _ensure_file_exists(fw_scpu, "KL720 SCPU firmware") + _ensure_file_exists(fw_ncpu, "KL720 NCPU firmware") + + args = [ + str(DFUT_EXE), + "--kl720-update", + "--port", + str(port_id), + "--scpu", + str(fw_scpu), + "--ncpu", + str(fw_ncpu), + "--quiet", + ] + result = _run_dfut_command(args) + return _ok( + { + "upgraded": True, + "target": "KL720", + "port_id": port_id, + "dfut": result, + } + ) + + @app.post("/models/load") def models_load(req: ModelLoadRequest) -> Dict[str, Any]: device_group = _require_device() @@ -321,14 +914,31 @@ def inference_run(req: InferenceRunRequest) -> Dict[str, Any]: detail=_err(str(exc.api_return_code), str(exc)), ) + b64_text = req.image_base64.strip() + if b64_text.startswith("data:") and "," in b64_text: + b64_text = b64_text.split(",", 1)[1] + try: - image_bytes = base64.b64decode(req.image_base64) + image_bytes = base64.b64decode(b64_text) except (ValueError, TypeError): raise HTTPException( status_code=400, detail=_err("INVALID_BASE64", "image_base64 is not valid base64 data"), ) + expected_size = _expected_image_size_bytes(req.image_format, req.width, req.height) + if expected_size is not None and len(image_bytes) != expected_size: + raise HTTPException( + status_code=400, + detail=_err( + "INVALID_IMAGE_SIZE", + ( + f"image bytes size mismatch: expected={expected_size}, actual={len(image_bytes)}. " + "Send raw pixel bytes for selected image_format (not BMP/JPEG/PNG file bytes)." + ), + ), + ) + input_image = kp.GenericInputNodeImage( image=image_bytes, width=req.width, diff --git a/local_service_win/LocalAPI/win_driver/amd64/WdfCoInstaller01011.dll b/local_service_win/LocalAPI/win_driver/amd64/WdfCoInstaller01011.dll new file mode 100644 index 0000000..d49d291 Binary files /dev/null and b/local_service_win/LocalAPI/win_driver/amd64/WdfCoInstaller01011.dll differ diff --git a/local_service_win/LocalAPI/win_driver/amd64/winusbcoinstaller2.dll b/local_service_win/LocalAPI/win_driver/amd64/winusbcoinstaller2.dll new file mode 100644 index 0000000..30e5502 Binary files /dev/null and b/local_service_win/LocalAPI/win_driver/amd64/winusbcoinstaller2.dll differ diff --git a/local_service_win/LocalAPI/win_driver/installer_x64.exe b/local_service_win/LocalAPI/win_driver/installer_x64.exe new file mode 100644 index 0000000..0373edc Binary files /dev/null and b/local_service_win/LocalAPI/win_driver/installer_x64.exe differ diff --git a/local_service_win/LocalAPI/win_driver/kneron_kl520.inf b/local_service_win/LocalAPI/win_driver/kneron_kl520.inf new file mode 100644 index 0000000..38deac1 Binary files /dev/null and b/local_service_win/LocalAPI/win_driver/kneron_kl520.inf differ diff --git a/local_service_win/STRATEGY.md b/local_service_win/STRATEGY.md index d719a39..50c8bfa 100644 --- a/local_service_win/STRATEGY.md +++ b/local_service_win/STRATEGY.md @@ -28,6 +28,15 @@ cd local_service_win python -m pip install --force-reinstall .\KneronPLUS-3.1.2-py3-none-any.whl ``` +## Dependency Strategy +- Open-source packages installed by pip: + - `fastapi`, `uvicorn`, `numpy`, `PyQt5`, `opencv-python`, `pyinstaller`, `pyarmor` +- Non-pip dependency: + - `KneronPLUS` (installed from local wheel) +- Bundled runtime (not pip): + - `third_party/Kneron_DFUT` is copied into this repo and used by LocalAPI to recover old firmware in one tool. + - `third_party/kneron_plus_1_2_1/dist` is extracted from `KneronPLUS-1.2.1` wheel and used by a subprocess runner for old-device firmware update experiments. + ## Cross-Project Workflow This repo is the main PoC implementation. If additional references are required, we can switch to other repos during the same conversation and return here as needed. This is workable. @@ -124,12 +133,75 @@ Response } ``` +### `POST /devices/connect_force` +Notes +- Force connection without firmware validation. +- Use this when firmware is incompatible and you need to call `/firmware/load` first. +Request +```json +{ "port_id": 32 } +``` +Response +```json +{ + "ok": true, + "data": { + "connected": true, + "port_id": 32, + "forced": true + }, + "error": null +} +``` + ### `POST /devices/disconnect` Response ```json { "ok": true, "data": { "connected": false }, "error": null } ``` +### `GET /driver/check` +Notes +- Query currently connected Kneron USB devices from Windows PnP. +- Reports whether each entry is bound to WinUSB. +Response +```json +{ + "ok": true, + "data": { + "entries": [ + { + "pnp_device_id": "USB\\VID_3231&PID_0720\\...", + "service": "WinUSB", + "pid_hex": "0x0720", + "product_name": "KL720", + "is_winusb": true + } + ], + "all_connected_kneron_are_winusb": true + }, + "error": null +} +``` + +### `POST /driver/install` +Notes +- Install/replace driver using `kp.core.install_driver_for_windows`. +- Requires Administrator privilege on Windows. +Request +```json +{ "target": "KL720", "force": false } +``` + +### `POST /driver/ensure` +Notes +- Check connected device driver binding, auto install if not WinUSB (or `force=true`). +- `target`: `ALL` | `KL520` | `KL720` | `KL630` | `KL730` | `KL830` +Request +```json +{ "target": "ALL", "force": false } +``` + ### `POST /firmware/load` Request ```json @@ -143,6 +215,80 @@ Response { "ok": true, "data": { "loaded": true }, "error": null } ``` +### `POST /firmware/legacy-plus121/load` +Notes +- Experimental endpoint for old hardware/firmware path. +- Independent route from DFUT. +- Runs a subprocess with bundled `KneronPLUS 1.2.1` package and calls `libkplus.dll` directly by `ctypes`. +- Single-endpoint auto flow: + - Scan target device firmware state. + - If firmware is `KDP`: first call loader (`fw_loader.bin`) to switch USB-boot, then call `kp_load_firmware_from_file(scpu,ncpu)`. + - If firmware is not `KDP`: call `kp_load_firmware_from_file(scpu,ncpu)` directly. + - Finally disconnect. +- Diagnostics include selected port, detected firmware, scan snapshot, and firmware file metadata (path/size/sha256). +Request +```json +{ + "port_id": 32, + "loader_path": "C:\\path\\fw_loader.bin", + "scpu_path": "C:\\path\\fw_scpu.bin", + "ncpu_path": "C:\\path\\fw_ncpu.bin" +} +``` +Response +```json +{ + "ok": true, + "data": { + "loaded": true, + "legacy_plus_version": "1.2.1" + }, + "error": null +} +``` + +### `POST /firmware/legacy-upgrade/kl520` +Notes +- Used for old KL520 firmware recovery path. +- Runs bundled DFUT console with `--kl520-update`. +Request +```json +{ "port_id": 32 } +``` +Response +```json +{ + "ok": true, + "data": { + "upgraded": true, + "target": "KL520", + "port_id": 32 + }, + "error": null +} +``` + +### `POST /firmware/legacy-upgrade/kl720` +Notes +- Used for old KL720 / KL720 legacy recovery path. +- Runs bundled DFUT console with `--kl720-update`. +Request +```json +{ "port_id": 32 } +``` +Response +```json +{ + "ok": true, + "data": { + "upgraded": true, + "target": "KL720", + "port_id": 32 + }, + "error": null +} +``` + ### `POST /models/load` Request ```json @@ -246,21 +392,36 @@ Message (server -> client) - Flash model update / flash firmware update may not be exposed in Python. - Use C library or request Kneron to expose in wrapper if required. - Browser security model prevents direct USB access; local service is required. +- Driver install/update on Windows may require Administrator privileges (`install_driver_for_windows` can fail without elevation). + - MEMO: define production approach for privilege handling (installer-time elevation, helper process with UAC prompt, or enterprise pre-install policy) so end-user flow does not get blocked. ## API Test Progress (Windows PoC) +Updated: 2026-03-03 + ### Completed - `GET /health` - `GET /version` - `GET /devices` - `POST /devices/connect` +- `POST /devices/connect_force` - `POST /devices/disconnect` - -### Pending +- `GET /driver/check` +- `POST /driver/install` +- `POST /driver/ensure` - `POST /firmware/load` +- `POST /firmware/legacy-plus121/load` +- `POST /firmware/legacy-upgrade/kl520` +- `POST /firmware/legacy-downgrade/kl520` +- `POST /firmware/legacy-upgrade/kl720` - `POST /models/load` - `POST /models/clear` - `POST /models/reset` - `POST /inference/run` + +### Pending +- None (for currently implemented HTTP endpoints). + +### Not Implemented Yet (API spec) - `WS /ws` - `POST /firmware/update` @@ -296,3 +457,28 @@ Message (server -> client) - Decide service framework (FastAPI/Flask). - Define error model and device state machine. - Plan installer workflow (driver + service). + +## Legacy Firmware Story And Recommended Handling +- Background: + - Many shipped devices are still on old KDP firmware or KL720 legacy states. + - In that state, `kp.core.connect_devices` and even `connect_devices_without_check` may still return `KP_ERROR_INVALID_FIRMWARE_24`. +- Goal: + - Keep user operations in one tool without requiring a separate DFUT install flow. +- Recommended handling: + 1. User scans devices via `GET /devices`. + 2. If normal connect fails with `KP_ERROR_INVALID_FIRMWARE_24`, call: + - `POST /firmware/legacy-upgrade/kl520` or + - `POST /firmware/legacy-upgrade/kl720` + 3. Re-scan and reconnect using `POST /devices/connect`. + 4. Continue with `POST /firmware/load` (if needed), `POST /models/load`, and inference. +- Experimental alternative: + - If DFUT route is blocked on specific old-device states, test `POST /firmware/legacy-plus121/load` as an independent non-DFUT legacy SDK compatibility path. +- Notes: + - Recovery endpoints use bundled `third_party/Kneron_DFUT/bin/KneronDFUT.exe`. + - This keeps firmware recovery and inference service in the same product boundary. + +## Validation Memo (Next) +- Record and verify on newer KneronPLUS versions: + - For KL520 old KDP state, `loader -> load_firmware_from_file(scpu,ncpu)` sequence works in legacy-plus121 path. + - Hypothesis: the same sequence may also work on newer PLUS runtime. + - Action later: add an explicit validation task on current PLUS branch and capture pass/fail matrix by device FW state. diff --git a/local_service_win/TestRes/Images/BmpToRGB565.html b/local_service_win/TestRes/Images/BmpToRGB565.html new file mode 100644 index 0000000..fd0a45f --- /dev/null +++ b/local_service_win/TestRes/Images/BmpToRGB565.html @@ -0,0 +1,271 @@ + + + + + + BMP to RGB565 + + + +
+

BMP to RGB565 (Raw)

+

+ Select a BMP file, convert pixels to RGB565 raw bytes (little-endian), then copy Base64 for + /inference/run. +

+ +
+ + + + + + + + + +
+ + Preview will appear here +
No file loaded.
+ +
+ + +
+ +
+ + + + +
+ +
+ + +
+
+ + + + diff --git a/local_service_win/TestRes/Images/PayloadDetectionView.html b/local_service_win/TestRes/Images/PayloadDetectionView.html new file mode 100644 index 0000000..caf0f0f --- /dev/null +++ b/local_service_win/TestRes/Images/PayloadDetectionView.html @@ -0,0 +1,955 @@ + + + + + + Payload Detection Viewer (YOLO/TinyYOLO/FCOS) + + + +
+

Payload Detection Viewer

+

+ 專為 POC:手動選擇模型 (YOLOv5 / TinyYOLOv3 / FCOS) 後處理,將 payload 推論結果畫成框 + 類別 + 分數。 +

+ +
+
+ + + + + +
+ +
+ + + +
+
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + + +
+ +
+ + + + + + + + +
+ +
+ + + + + + + + + + +
+ +
+ + + + +
+
+ +
+
+
Detection Overlay
+ +
+
+
+
Top Boxes
+
+ + + + + + + +
#clsscorex1y1x2y2
+
+
+
+
+
+
+ + + + diff --git a/local_service_win/TestRes/Images/PayloadTensorView.html b/local_service_win/TestRes/Images/PayloadTensorView.html new file mode 100644 index 0000000..f91959f --- /dev/null +++ b/local_service_win/TestRes/Images/PayloadTensorView.html @@ -0,0 +1,624 @@ + + + + + + Payload Tensor Viewer + + + +
+

Payload Tensor Viewer

+

+ Paste full JSON payload and click Parse & Render. Supports base64 float32 tensors in NCHW shape (e.g. [1,255,7,7]). +

+ + +
+ + +
+ + + +
+

Overlay Viewer

+

+ Upload original image, pick output/channel, then overlay activation heatmap on top. +

+ +
+ + + +
+ +
+ + + + + + + + + + + 0.45 + +
+ +
+
+
Overlay
+ +
+
+
+
Heatmap Only
+ +
+
+
+
+ +
+
+ + + + diff --git a/local_service_win/TestRes/Images/bike_cars_street_224x224.bmp b/local_service_win/TestRes/Images/bike_cars_street_224x224.bmp new file mode 100644 index 0000000..987b217 Binary files /dev/null and b/local_service_win/TestRes/Images/bike_cars_street_224x224.bmp differ diff --git a/local_service_win/TestRes/Images/one_bike_many_cars_800x800.bmp b/local_service_win/TestRes/Images/one_bike_many_cars_800x800.bmp new file mode 100644 index 0000000..2893d85 Binary files /dev/null and b/local_service_win/TestRes/Images/one_bike_many_cars_800x800.bmp differ diff --git a/local_service_win/TestRes/TEST_PAIRS.md b/local_service_win/TestRes/TEST_PAIRS.md index aa03e11..62cebdb 100644 --- a/local_service_win/TestRes/TEST_PAIRS.md +++ b/local_service_win/TestRes/TEST_PAIRS.md @@ -4,26 +4,26 @@ - YOLOv5 (model zoo) - Model: `res/models/KL520/yolov5-noupsample_w640h640_kn-model-zoo/kl520_20005_yolov5-noupsample_w640h640.nef` - Image: `res/images/one_bike_many_cars_800x800.bmp` - - Source: `examples_model_zoo/kl520_kn-model-zoo_generic_image_inference_post_yolov5/kl520_kn-model-zoo_generic_image_inference_post_yolov5.c` + - Source: `examples_model_zoo/kl520_kn-model-zoo_generic_inference_post_yolov5/kl520_kn-model-zoo_generic_inference_post_yolov5.c` - FCOS (model zoo) - Model: `res/models/KL520/fcos-drk53s_w512h512_kn-model-zoo/kl520_20004_fcos-drk53s_w512h512.nef` - Image: `res/images/one_bike_many_cars_800x800.bmp` - - Source: `examples_model_zoo/kl520_kn-model-zoo_generic_image_inference_post_fcos/kl520_kn-model-zoo_generic_image_inference_post_fcos.c` + - Source: `examples_model_zoo/kl520_kn-model-zoo_generic_inference_post_fcos/kl520_kn-model-zoo_generic_inference_post_fcos.c` - Tiny YOLO v3 (generic demo) - Model: `res/models/KL520/tiny_yolo_v3/models_520.nef` - Image: `res/images/bike_cars_street_224x224.bmp` - - Source: `examples/kl520_demo_generic_image_inference_post_yolo/kl520_demo_generic_image_inference_post_yolo.c` + - Source: `examples/kl520_demo_app_yolo_inference/kl520_demo_app_yolo_inference.c` - Tiny YOLO v3 (multithread demo) - Model: `res/models/KL520/tiny_yolo_v3/models_520.nef` - Image: `res/images/bike_cars_street_224x224.bmp` - - Source: `examples/kl520_demo_generic_image_inference_multithread/kl520_demo_generic_image_inference_multithread.c` + - Source: `examples/kl520_demo_app_yolo_inference_multithread/kl520_demo_app_yolo_inference_multithread.c` ## KL720 - YOLOv5 (model zoo) - Model: `res/models/KL720/yolov5-noupsample_w640h640_kn-model-zoo/kl720_20005_yolov5-noupsample_w640h640.nef` - Image: `res/images/one_bike_many_cars_800x800.bmp` - - Source: `examples_model_zoo/kl720_kn-model-zoo_generic_image_inference_post_yolov5/kl720_kn-model-zoo_generic_image_inference_post_yolov5.c` + - Source: `examples_model_zoo/kl720_kn-model-zoo_generic_inference_post_yolov5/kl720_kn-model-zoo_generic_inference_post_yolov5.c` - FCOS (model zoo) - Model: `res/models/KL720/fcos-drk53s_w512h512_kn-model-zoo/kl720_20004_fcos-drk53s_w512h512.nef` - Image: `res/images/one_bike_many_cars_800x800.bmp` - - Source: `examples_model_zoo/kl720_kn-model-zoo_generic_image_inference_post_fcos/kl720_kn-model-zoo_generic_image_inference_post_fcos.c` + - Source: `examples_model_zoo/kl720_kn-model-zoo_generic_inference_post_fcos/kl720_kn-model-zoo_generic_inference_post_fcos.c` diff --git a/local_service_win/firmware/KL520/VERSION b/local_service_win/firmware/KL520/VERSION new file mode 100644 index 0000000..ccbccc3 --- /dev/null +++ b/local_service_win/firmware/KL520/VERSION @@ -0,0 +1 @@ +2.2.0 diff --git a/local_service_win/firmware/KL520/dfw/minions.bin b/local_service_win/firmware/KL520/dfw/minions.bin new file mode 100644 index 0000000..7463ab8 Binary files /dev/null and b/local_service_win/firmware/KL520/dfw/minions.bin differ diff --git a/local_service_win/firmware/KL520/fw_loader.bin b/local_service_win/firmware/KL520/fw_loader.bin new file mode 100644 index 0000000..51ca844 Binary files /dev/null and b/local_service_win/firmware/KL520/fw_loader.bin differ diff --git a/local_service_win/firmware/KL520/fw_ncpu.bin b/local_service_win/firmware/KL520/fw_ncpu.bin new file mode 100644 index 0000000..10cd08b Binary files /dev/null and b/local_service_win/firmware/KL520/fw_ncpu.bin differ diff --git a/local_service_win/firmware/KL520/fw_scpu.bin b/local_service_win/firmware/KL520/fw_scpu.bin new file mode 100644 index 0000000..482315a Binary files /dev/null and b/local_service_win/firmware/KL520/fw_scpu.bin differ diff --git a/local_service_win/firmware/KL520_kdp/fw_ncpu.bin b/local_service_win/firmware/KL520_kdp/fw_ncpu.bin new file mode 100644 index 0000000..0ed154f Binary files /dev/null and b/local_service_win/firmware/KL520_kdp/fw_ncpu.bin differ diff --git a/local_service_win/firmware/KL520_kdp/fw_scpu.bin b/local_service_win/firmware/KL520_kdp/fw_scpu.bin new file mode 100644 index 0000000..5101c06 Binary files /dev/null and b/local_service_win/firmware/KL520_kdp/fw_scpu.bin differ diff --git a/local_service_win/firmware/KL630/VERSION b/local_service_win/firmware/KL630/VERSION new file mode 100644 index 0000000..aefb325 --- /dev/null +++ b/local_service_win/firmware/KL630/VERSION @@ -0,0 +1 @@ +SDK-v2.5.7 diff --git a/local_service_win/firmware/KL630/kp_firmware.tar b/local_service_win/firmware/KL630/kp_firmware.tar new file mode 100644 index 0000000..822b319 Binary files /dev/null and b/local_service_win/firmware/KL630/kp_firmware.tar differ diff --git a/local_service_win/firmware/KL630/kp_loader.tar b/local_service_win/firmware/KL630/kp_loader.tar new file mode 100644 index 0000000..45f6cd4 Binary files /dev/null and b/local_service_win/firmware/KL630/kp_loader.tar differ diff --git a/local_service_win/firmware/KL720/VERSION b/local_service_win/firmware/KL720/VERSION new file mode 100644 index 0000000..ccbccc3 --- /dev/null +++ b/local_service_win/firmware/KL720/VERSION @@ -0,0 +1 @@ +2.2.0 diff --git a/local_service_win/firmware/KL720/fw_ncpu.bin b/local_service_win/firmware/KL720/fw_ncpu.bin new file mode 100644 index 0000000..815530e Binary files /dev/null and b/local_service_win/firmware/KL720/fw_ncpu.bin differ diff --git a/local_service_win/firmware/KL720/fw_scpu.bin b/local_service_win/firmware/KL720/fw_scpu.bin new file mode 100644 index 0000000..82f23e2 Binary files /dev/null and b/local_service_win/firmware/KL720/fw_scpu.bin differ diff --git a/local_service_win/firmware/KL730/VERSION b/local_service_win/firmware/KL730/VERSION new file mode 100644 index 0000000..5332ca0 --- /dev/null +++ b/local_service_win/firmware/KL730/VERSION @@ -0,0 +1 @@ +SDK-v1.3.0 diff --git a/local_service_win/firmware/KL730/kp_firmware.tar b/local_service_win/firmware/KL730/kp_firmware.tar new file mode 100644 index 0000000..a688586 Binary files /dev/null and b/local_service_win/firmware/KL730/kp_firmware.tar differ diff --git a/local_service_win/firmware/KL730/kp_loader.tar b/local_service_win/firmware/KL730/kp_loader.tar new file mode 100644 index 0000000..3e799e2 Binary files /dev/null and b/local_service_win/firmware/KL730/kp_loader.tar differ diff --git a/local_service_win/third_party/Kneron_DFUT/VERSION b/local_service_win/third_party/Kneron_DFUT/VERSION new file mode 100644 index 0000000..56fea8a --- /dev/null +++ b/local_service_win/third_party/Kneron_DFUT/VERSION @@ -0,0 +1 @@ +3.0.0 \ No newline at end of file diff --git a/local_service_win/third_party/Kneron_DFUT/bin/D3Dcompiler_47.dll b/local_service_win/third_party/Kneron_DFUT/bin/D3Dcompiler_47.dll new file mode 100644 index 0000000..56512f5 Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/D3Dcompiler_47.dll differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/KneronDFUT.exe b/local_service_win/third_party/Kneron_DFUT/bin/KneronDFUT.exe new file mode 100644 index 0000000..d1a231d Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/KneronDFUT.exe differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/Qt5Core.dll b/local_service_win/third_party/Kneron_DFUT/bin/Qt5Core.dll new file mode 100644 index 0000000..4e0ee9a Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/Qt5Core.dll differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/Qt5Gui.dll b/local_service_win/third_party/Kneron_DFUT/bin/Qt5Gui.dll new file mode 100644 index 0000000..bba96c8 Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/Qt5Gui.dll differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/Qt5Svg.dll b/local_service_win/third_party/Kneron_DFUT/bin/Qt5Svg.dll new file mode 100644 index 0000000..b006006 Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/Qt5Svg.dll differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/Qt5Widgets.dll b/local_service_win/third_party/Kneron_DFUT/bin/Qt5Widgets.dll new file mode 100644 index 0000000..e6ff156 Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/Qt5Widgets.dll differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/iconengines/qsvgicon.dll b/local_service_win/third_party/Kneron_DFUT/bin/iconengines/qsvgicon.dll new file mode 100644 index 0000000..b10761c Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/iconengines/qsvgicon.dll differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/imageformats/qgif.dll b/local_service_win/third_party/Kneron_DFUT/bin/imageformats/qgif.dll new file mode 100644 index 0000000..97beb57 Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/imageformats/qgif.dll differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/imageformats/qicns.dll b/local_service_win/third_party/Kneron_DFUT/bin/imageformats/qicns.dll new file mode 100644 index 0000000..a64309b Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/imageformats/qicns.dll differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/imageformats/qico.dll b/local_service_win/third_party/Kneron_DFUT/bin/imageformats/qico.dll new file mode 100644 index 0000000..5c744ae Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/imageformats/qico.dll differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/imageformats/qjpeg.dll b/local_service_win/third_party/Kneron_DFUT/bin/imageformats/qjpeg.dll new file mode 100644 index 0000000..f2bb6be Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/imageformats/qjpeg.dll differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/imageformats/qsvg.dll b/local_service_win/third_party/Kneron_DFUT/bin/imageformats/qsvg.dll new file mode 100644 index 0000000..921f25f Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/imageformats/qsvg.dll differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/imageformats/qtga.dll b/local_service_win/third_party/Kneron_DFUT/bin/imageformats/qtga.dll new file mode 100644 index 0000000..b68d35d Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/imageformats/qtga.dll differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/imageformats/qtiff.dll b/local_service_win/third_party/Kneron_DFUT/bin/imageformats/qtiff.dll new file mode 100644 index 0000000..31a8ce3 Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/imageformats/qtiff.dll differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/imageformats/qwbmp.dll b/local_service_win/third_party/Kneron_DFUT/bin/imageformats/qwbmp.dll new file mode 100644 index 0000000..a6751ab Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/imageformats/qwbmp.dll differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/imageformats/qwebp.dll b/local_service_win/third_party/Kneron_DFUT/bin/imageformats/qwebp.dll new file mode 100644 index 0000000..49862fa Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/imageformats/qwebp.dll differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/libEGL.dll b/local_service_win/third_party/Kneron_DFUT/bin/libEGL.dll new file mode 100644 index 0000000..d3247d2 Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/libEGL.dll differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/libGLESV2.dll b/local_service_win/third_party/Kneron_DFUT/bin/libGLESV2.dll new file mode 100644 index 0000000..7825e28 Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/libGLESV2.dll differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/libgcc_s_seh-1.dll b/local_service_win/third_party/Kneron_DFUT/bin/libgcc_s_seh-1.dll new file mode 100644 index 0000000..4ec945b Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/libgcc_s_seh-1.dll differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/libkplus.dll b/local_service_win/third_party/Kneron_DFUT/bin/libkplus.dll new file mode 100644 index 0000000..0a9ff70 Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/libkplus.dll differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/libstdc++-6.dll b/local_service_win/third_party/Kneron_DFUT/bin/libstdc++-6.dll new file mode 100644 index 0000000..8e55acc Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/libstdc++-6.dll differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/libusb-1.0.dll b/local_service_win/third_party/Kneron_DFUT/bin/libusb-1.0.dll new file mode 100644 index 0000000..bec7169 Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/libusb-1.0.dll differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/libwdi.dll b/local_service_win/third_party/Kneron_DFUT/bin/libwdi.dll new file mode 100644 index 0000000..354b339 Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/libwdi.dll differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/libwinpthread-1.dll b/local_service_win/third_party/Kneron_DFUT/bin/libwinpthread-1.dll new file mode 100644 index 0000000..d9f4e1a Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/libwinpthread-1.dll differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/opengl32sw.dll b/local_service_win/third_party/Kneron_DFUT/bin/opengl32sw.dll new file mode 100644 index 0000000..475e82a Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/opengl32sw.dll differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/platforms/qwindows.dll b/local_service_win/third_party/Kneron_DFUT/bin/platforms/qwindows.dll new file mode 100644 index 0000000..f9874fc Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/platforms/qwindows.dll differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/styles/qwindowsvistastyle.dll b/local_service_win/third_party/Kneron_DFUT/bin/styles/qwindowsvistastyle.dll new file mode 100644 index 0000000..a3c0e52 Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/styles/qwindowsvistastyle.dll differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_ar.qm b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_ar.qm new file mode 100644 index 0000000..1e9227a Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_ar.qm differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_bg.qm b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_bg.qm new file mode 100644 index 0000000..dcec255 Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_bg.qm differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_ca.qm b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_ca.qm new file mode 100644 index 0000000..0b798e5 Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_ca.qm differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_cs.qm b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_cs.qm new file mode 100644 index 0000000..3ab5ca7 Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_cs.qm differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_da.qm b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_da.qm new file mode 100644 index 0000000..6756496 Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_da.qm differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_de.qm b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_de.qm new file mode 100644 index 0000000..86ae7fa Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_de.qm differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_en.qm b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_en.qm new file mode 100644 index 0000000..9dad8df Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_en.qm differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_es.qm b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_es.qm new file mode 100644 index 0000000..82012da Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_es.qm differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_fi.qm b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_fi.qm new file mode 100644 index 0000000..2548cca Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_fi.qm differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_fr.qm b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_fr.qm new file mode 100644 index 0000000..8353f0a Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_fr.qm differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_gd.qm b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_gd.qm new file mode 100644 index 0000000..fd7eecd Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_gd.qm differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_he.qm b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_he.qm new file mode 100644 index 0000000..e15d45e Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_he.qm differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_hu.qm b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_hu.qm new file mode 100644 index 0000000..b51bd1a Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_hu.qm differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_it.qm b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_it.qm new file mode 100644 index 0000000..a2433c6 Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_it.qm differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_ja.qm b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_ja.qm new file mode 100644 index 0000000..74409b1 Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_ja.qm differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_ko.qm b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_ko.qm new file mode 100644 index 0000000..a46b8a0 Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_ko.qm differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_lv.qm b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_lv.qm new file mode 100644 index 0000000..c1dbfbd Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_lv.qm differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_pl.qm b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_pl.qm new file mode 100644 index 0000000..0909204 Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_pl.qm differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_ru.qm b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_ru.qm new file mode 100644 index 0000000..b77ce55 Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_ru.qm differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_sk.qm b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_sk.qm new file mode 100644 index 0000000..215d234 Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_sk.qm differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_uk.qm b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_uk.qm new file mode 100644 index 0000000..88c4362 Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_uk.qm differ diff --git a/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_zh_TW.qm b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_zh_TW.qm new file mode 100644 index 0000000..21c4190 Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/bin/translations/qt_zh_TW.qm differ diff --git a/local_service_win/third_party/Kneron_DFUT/resource/firmware/KL520/flash_helper.bin b/local_service_win/third_party/Kneron_DFUT/resource/firmware/KL520/flash_helper.bin new file mode 100644 index 0000000..e746210 Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/resource/firmware/KL520/flash_helper.bin differ diff --git a/local_service_win/third_party/Kneron_DFUT/resource/firmware/KL520/fw_loader.bin b/local_service_win/third_party/Kneron_DFUT/resource/firmware/KL520/fw_loader.bin new file mode 100644 index 0000000..51ca844 Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/resource/firmware/KL520/fw_loader.bin differ diff --git a/local_service_win/third_party/Kneron_DFUT/resource/firmware/KL630/flash_helper.tar b/local_service_win/third_party/Kneron_DFUT/resource/firmware/KL630/flash_helper.tar new file mode 100644 index 0000000..eb94b5a Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/resource/firmware/KL630/flash_helper.tar differ diff --git a/local_service_win/third_party/Kneron_DFUT/resource/firmware/KL730/flash_helper.tar b/local_service_win/third_party/Kneron_DFUT/resource/firmware/KL730/flash_helper.tar new file mode 100644 index 0000000..b042714 Binary files /dev/null and b/local_service_win/third_party/Kneron_DFUT/resource/firmware/KL730/flash_helper.tar differ diff --git a/local_service_win/third_party/kneron_plus_1_2_1/KneronPLUS-1.2.1.zip b/local_service_win/third_party/kneron_plus_1_2_1/KneronPLUS-1.2.1.zip new file mode 100644 index 0000000..e2aee1c Binary files /dev/null and b/local_service_win/third_party/kneron_plus_1_2_1/KneronPLUS-1.2.1.zip differ