From 2f868bc36db7f964410e31c7a1541caf2c63e5bf Mon Sep 17 00:00:00 2001 From: Siyuan Date: Wed, 12 Nov 2025 14:16:53 +0000 Subject: [PATCH] dead simple dual build target POC --- internal/native/cgo/CMakeLists.txt | 14 +- internal/native/cgo/main.c | 227 +++++++++++++++++++++++++++++ internal/native/cgo/main.h | 26 ++++ internal/native/native.go | 10 +- internal/native/proxy.go | 80 +++++++--- internal/native/server.go | 36 ++--- scripts/dev_deploy.sh | 48 ++++-- 7 files changed, 382 insertions(+), 59 deletions(-) create mode 100644 internal/native/cgo/main.c create mode 100644 internal/native/cgo/main.h diff --git a/internal/native/cgo/CMakeLists.txt b/internal/native/cgo/CMakeLists.txt index 739dabe5..c4c01ded 100644 --- a/internal/native/cgo/CMakeLists.txt +++ b/internal/native/cgo/CMakeLists.txt @@ -42,6 +42,8 @@ FetchContent_MakeAvailable(lvgl) # Get source files, excluding CMake generated files file(GLOB_RECURSE sources CONFIGURE_DEPENDS "*.c" "ui/*.c") list(FILTER sources EXCLUDE REGEX "CMakeFiles.*CompilerId.*\\.c$") +# Exclude main.c from library sources (it's used for the binary target) +list(FILTER sources EXCLUDE REGEX "main\\.c$") add_library(jknative STATIC ${sources} ${CMAKE_CURRENT_SOURCE_DIR}/ctrl.h) @@ -68,4 +70,14 @@ target_link_libraries(jknative PRIVATE # libgpiod ) -install(TARGETS jknative DESTINATION lib) \ No newline at end of file +# Binary target using main.c as entry point +add_executable(jknative-bin ${CMAKE_CURRENT_SOURCE_DIR}/main.c) + +# Link the binary to the library (if needed in the future) +target_link_libraries(jknative-bin PRIVATE + jknative + pthread +) + +install(TARGETS jknative DESTINATION lib) +install(TARGETS jknative-bin DESTINATION bin) \ No newline at end of file diff --git a/internal/native/cgo/main.c b/internal/native/cgo/main.c new file mode 100644 index 00000000..a3e0e22f --- /dev/null +++ b/internal/native/cgo/main.c @@ -0,0 +1,227 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ctrl.h" +#include "main.h" + +#define SOCKET_PATH "/tmp/video.sock" +#define BUFFER_SIZE 4096 + +// Global state +static int client_fd = -1; +static pthread_mutex_t client_fd_mutex = PTHREAD_MUTEX_INITIALIZER; + +void jetkvm_c_log_handler(int level, const char *filename, const char *funcname, int line, const char *message) { + // printf("[%s] %s:%d %s: %s\n", filename ? filename : "unknown", funcname ? funcname : "unknown", line, message ? message : ""); + fprintf(stderr, "[%s] %s:%d %s: %s\n", filename ? filename : "unknown", funcname ? funcname : "unknown", line, message ? message : ""); +} + +// Video handler that pipes frames to the Unix socket +// This will be called by the video subsystem via video_send_frame -> jetkvm_set_video_handler's handler +void jetkvm_video_handler(const uint8_t *frame, ssize_t len) { + // pthread_mutex_lock(&client_fd_mutex); + // if (client_fd >= 0 && frame != NULL && len > 0) { + // ssize_t bytes_written = 0; + // while (bytes_written < len) { + // ssize_t n = write(client_fd, frame + bytes_written, len - bytes_written); + // if (n < 0) { + // if (errno == EPIPE || errno == ECONNRESET) { + // // Client disconnected + // close(client_fd); + // client_fd = -1; + // break; + // } + // perror("write"); + // break; + // } + // bytes_written += n; + // } + // } + // pthread_mutex_unlock(&client_fd_mutex); +} + +void jetkvm_video_state_handler(jetkvm_video_state_t *state) { + fprintf(stderr, "Video state: {\n" + "\"ready\": %d,\n" + "\"error\": \"%s\",\n" + "\"width\": %d,\n" + "\"height\": %d,\n" + "\"frame_per_second\": %f\n" + "}\n", state->ready, state->error, state->width, state->height, state->frame_per_second); +} + +void jetkvm_indev_handler(int code) { + fprintf(stderr, "Video indev: %d\n", code); +} + +void jetkvm_rpc_handler(const char *method, const char *params) { + fprintf(stderr, "Video rpc: %s %s\n", method, params); +} + +// Note: jetkvm_set_video_handler, jetkvm_set_indev_handler, jetkvm_set_rpc_handler, +// jetkvm_call_rpc_handler, and jetkvm_set_video_state_handler are implemented in +// the library (ctrl.c) and will be used from there when linking. + +int main(int argc, char *argv[]) { + const char *socket_path = SOCKET_PATH; + + // Allow custom socket path via command line argument + if (argc > 1) { + socket_path = argv[1]; + } + + // Remove existing socket file if it exists + unlink(socket_path); + + // Set handlers + jetkvm_set_log_handler(&jetkvm_c_log_handler); + jetkvm_set_video_handler(&jetkvm_video_handler); + jetkvm_set_video_state_handler(&jetkvm_video_state_handler); + jetkvm_set_indev_handler(&jetkvm_indev_handler); + jetkvm_set_rpc_handler(&jetkvm_rpc_handler); + + // Initialize video first (before accepting connections) + fprintf(stderr, "Initializing video...\n"); + if (jetkvm_video_init(1.0) != 0) { + fprintf(stderr, "Failed to initialize video\n"); + return 1; + } + + // Start video streaming - frames will be sent via video_send_frame + // which calls the video handler we set up + jetkvm_video_start(); + fprintf(stderr, "Video streaming started.\n"); + + // Create Unix domain socket + int server_fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (server_fd < 0) { + perror("socket"); + jetkvm_video_stop(); + jetkvm_video_shutdown(); + return 1; + } + + // Make socket non-blocking + int flags = fcntl(server_fd, F_GETFL, 0); + if (flags < 0 || fcntl(server_fd, F_SETFL, flags | O_NONBLOCK) < 0) { + perror("fcntl"); + close(server_fd); + jetkvm_video_stop(); + jetkvm_video_shutdown(); + return 1; + } + + // Bind socket to path + struct sockaddr_un addr; + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1); + + if (bind(server_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + perror("bind"); + close(server_fd); + jetkvm_video_stop(); + jetkvm_video_shutdown(); + return 1; + } + + // Listen for connections + if (listen(server_fd, 1) < 0) { + perror("listen"); + close(server_fd); + jetkvm_video_stop(); + jetkvm_video_shutdown(); + return 1; + } + + fprintf(stderr, "Listening on Unix socket: %s (non-blocking)\n", socket_path); + fprintf(stderr, "Video frames will be sent to connected clients...\n"); + + // Main loop: check for new connections and handle client disconnections + fd_set read_fds; + struct timeval timeout; + + while (1) { + FD_ZERO(&read_fds); + FD_SET(server_fd, &read_fds); + + pthread_mutex_lock(&client_fd_mutex); + int current_client_fd = client_fd; + if (current_client_fd >= 0) { + FD_SET(current_client_fd, &read_fds); + } + int max_fd = (current_client_fd > server_fd) ? current_client_fd : server_fd; + pthread_mutex_unlock(&client_fd_mutex); + + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + int result = select(max_fd + 1, &read_fds, NULL, NULL, &timeout); + if (result < 0) { + if (errno == EINTR) { + continue; + } + perror("select"); + break; + } + + // Check for new connection + if (FD_ISSET(server_fd, &read_fds)) { + int accepted_fd = accept(server_fd, NULL, NULL); + if (accepted_fd >= 0) { + fprintf(stderr, "Client connected\n"); + pthread_mutex_lock(&client_fd_mutex); + if (client_fd >= 0) { + // Close previous client if any + close(client_fd); + } + client_fd = accepted_fd; + pthread_mutex_unlock(&client_fd_mutex); + } else if (errno != EAGAIN && errno != EWOULDBLOCK) { + perror("accept"); + } + } + + // Check if client disconnected + pthread_mutex_lock(&client_fd_mutex); + current_client_fd = client_fd; + pthread_mutex_unlock(&client_fd_mutex); + + if (current_client_fd >= 0 && FD_ISSET(current_client_fd, &read_fds)) { + // Client sent data or closed connection + char buffer[1]; + if (read(current_client_fd, buffer, 1) <= 0) { + fprintf(stderr, "Client disconnected\n"); + pthread_mutex_lock(&client_fd_mutex); + close(client_fd); + client_fd = -1; + pthread_mutex_unlock(&client_fd_mutex); + } + } + } + + // Stop video streaming + jetkvm_video_stop(); + jetkvm_video_shutdown(); + + // Cleanup + pthread_mutex_lock(&client_fd_mutex); + if (client_fd >= 0) { + close(client_fd); + client_fd = -1; + } + pthread_mutex_unlock(&client_fd_mutex); + + close(server_fd); + unlink(socket_path); + + return 0; +} + diff --git a/internal/native/cgo/main.h b/internal/native/cgo/main.h new file mode 100644 index 00000000..d9cc6c49 --- /dev/null +++ b/internal/native/cgo/main.h @@ -0,0 +1,26 @@ +#ifndef JETKVM_NATIVE_MAIN_H +#define JETKVM_NATIVE_MAIN_H + +#include +#include +#include +#include +#include +#include +#include +#include "ctrl.h" + +void jetkvm_c_log_handler(int level, const char *filename, const char *funcname, int line, const char *message); +void jetkvm_video_handler(const uint8_t *frame, ssize_t len); +void jetkvm_video_state_handler(jetkvm_video_state_t *state); +void jetkvm_indev_handler(int code); +void jetkvm_rpc_handler(const char *method, const char *params); + + +// typedef void (jetkvm_video_state_handler_t)(jetkvm_video_state_t *state); +// typedef void (jetkvm_log_handler_t)(int level, const char *filename, const char *funcname, int line, const char *message); +// typedef void (jetkvm_rpc_handler_t)(const char *method, const char *params); +// typedef void (jetkvm_video_handler_t)(const uint8_t *frame, ssize_t len); +// typedef void (jetkvm_indev_handler_t)(int code); + +#endif \ No newline at end of file diff --git a/internal/native/native.go b/internal/native/native.go index edf5217a..f60573d6 100644 --- a/internal/native/native.go +++ b/internal/native/native.go @@ -28,11 +28,11 @@ type Native struct { } type NativeOptions struct { - Disable bool `env:"JETKVM_NATIVE_DISABLE"` - SystemVersion *semver.Version `env:"JETKVM_NATIVE_SYSTEM_VERSION"` - AppVersion *semver.Version `env:"JETKVM_NATIVE_APP_VERSION"` - DisplayRotation uint16 `env:"JETKVM_NATIVE_DISPLAY_ROTATION"` - DefaultQualityFactor float64 `env:"JETKVM_NATIVE_DEFAULT_QUALITY_FACTOR"` + Disable bool + SystemVersion *semver.Version + AppVersion *semver.Version + DisplayRotation uint16 + DefaultQualityFactor float64 OnVideoStateChange func(state VideoState) OnVideoFrameReceived func(frame []byte, duration time.Duration) OnIndevEvent func(event string) diff --git a/internal/native/proxy.go b/internal/native/proxy.go index b36c82e7..60e3bea2 100644 --- a/internal/native/proxy.go +++ b/internal/native/proxy.go @@ -9,7 +9,8 @@ import ( "syscall" "time" - "github.com/jetkvm/kvm/internal/supervisor" + "github.com/Masterminds/semver/v3" + "github.com/jetkvm/kvm/internal/utils" "github.com/rs/zerolog" ) @@ -17,6 +18,48 @@ const ( maxFrameSize = 1920 * 1080 / 2 ) +type nativeProxyOptions struct { + Disable bool `env:"JETKVM_NATIVE_DISABLE"` + SystemVersion *semver.Version `env:"JETKVM_NATIVE_SYSTEM_VERSION"` + AppVersion *semver.Version `env:"JETKVM_NATIVE_APP_VERSION"` + DisplayRotation uint16 `env:"JETKVM_NATIVE_DISPLAY_ROTATION"` + DefaultQualityFactor float64 `env:"JETKVM_NATIVE_DEFAULT_QUALITY_FACTOR"` + CtrlUnixSocket string `env:"JETKVM_NATIVE_CTRL_UNIX_SOCKET"` + VideoStreamUnixSocket string `env:"JETKVM_NATIVE_VIDEO_STREAM_UNIX_SOCKET"` + BinaryPath string `env:"JETKVM_NATIVE_BINARY_PATH"` + LoggerLevel zerolog.Level `env:"JETKVM_NATIVE_LOGGER_LEVEL"` + HandshakeMessage string `env:"JETKVM_NATIVE_HANDSHAKE_MESSAGE"` + + OnVideoFrameReceived func(frame []byte, duration time.Duration) + OnIndevEvent func(event string) + OnRpcEvent func(event string) + OnVideoStateChange func(state VideoState) +} + +func (n *NativeOptions) toProxyOptions() *nativeProxyOptions { + return &nativeProxyOptions{ + Disable: n.Disable, + SystemVersion: n.SystemVersion, + AppVersion: n.AppVersion, + DisplayRotation: n.DisplayRotation, + DefaultQualityFactor: n.DefaultQualityFactor, + OnVideoFrameReceived: n.OnVideoFrameReceived, + OnIndevEvent: n.OnIndevEvent, + OnRpcEvent: n.OnRpcEvent, + OnVideoStateChange: n.OnVideoStateChange, + } +} + +func (p *nativeProxyOptions) toNativeOptions() *NativeOptions { + return &NativeOptions{ + Disable: p.Disable, + SystemVersion: p.SystemVersion, + AppVersion: p.AppVersion, + DisplayRotation: p.DisplayRotation, + DefaultQualityFactor: p.DefaultQualityFactor, + } +} + // cmdWrapper wraps exec.Cmd to implement processCmd interface type cmdWrapper struct { *exec.Cmd @@ -55,23 +98,17 @@ type NativeProxy struct { cmd *cmdWrapper logger *zerolog.Logger ready chan struct{} - options *NativeOptions + options *nativeProxyOptions restartM sync.Mutex stopped bool processWait chan error } -func ensureDirectoryExists(path string) error { - if _, err := os.Stat(path); os.IsNotExist(err) { - return os.MkdirAll(path, 0600) - } - return nil -} - // NewNativeProxy creates a new NativeProxy that spawns a separate process func NewNativeProxy(opts NativeOptions) (*NativeProxy, error) { - nativeUnixSocket := "jetkvm-native-grpc" - videoStreamUnixSocket := "@jetkvm-native-video-stream" + proxyOptions := opts.toProxyOptions() + proxyOptions.CtrlUnixSocket = "jetkvm-native-grpc" + proxyOptions.VideoStreamUnixSocket = "@jetkvm-native-video-stream" // Get the current executable path to spawn itself exePath, err := os.Executable() @@ -80,12 +117,12 @@ func NewNativeProxy(opts NativeOptions) (*NativeProxy, error) { } proxy := &NativeProxy{ - nativeUnixSocket: nativeUnixSocket, - videoStreamUnixSocket: videoStreamUnixSocket, + nativeUnixSocket: proxyOptions.CtrlUnixSocket, + videoStreamUnixSocket: proxyOptions.VideoStreamUnixSocket, binaryPath: exePath, logger: nativeLogger, ready: make(chan struct{}), - options: &opts, + options: proxyOptions, processWait: make(chan error, 1), } proxy.cmd, err = proxy.spawnProcess() @@ -95,7 +132,7 @@ func NewNativeProxy(opts NativeOptions) (*NativeProxy, error) { } // create unix packet - listener, err := net.Listen("unixpacket", videoStreamUnixSocket) + listener, err := net.Listen("unixpacket", proxyOptions.VideoStreamUnixSocket) if err != nil { nativeLogger.Warn().Err(err).Msg("failed to start server") return nil, fmt.Errorf("failed to start server: %w", err) @@ -116,6 +153,11 @@ func NewNativeProxy(opts NativeOptions) (*NativeProxy, error) { } func (p *NativeProxy) spawnProcess() (*cmdWrapper, error) { + envArgs, err := utils.MarshalEnv(p.options) + if err != nil { + return nil, fmt.Errorf("failed to marshal environment variables: %w", err) + } + cmd := exec.Command( p.binaryPath, "-subcomponent=native", @@ -125,13 +167,7 @@ func (p *NativeProxy) spawnProcess() (*cmdWrapper, error) { // Set environment variable to indicate native process mode cmd.Env = append( os.Environ(), - fmt.Sprintf("%s=native", supervisor.EnvSubcomponent), - fmt.Sprintf("%s=%s", "JETKVM_NATIVE_SOCKET", p.nativeUnixSocket), - fmt.Sprintf("%s=%s", "JETKVM_VIDEO_STREAM_SOCKET", p.videoStreamUnixSocket), - fmt.Sprintf("%s=%s", "JETKVM_NATIVE_SYSTEM_VERSION", p.options.SystemVersion), - fmt.Sprintf("%s=%s", "JETKVM_NATIVE_APP_VERSION", p.options.AppVersion), - fmt.Sprintf("%s=%d", "JETKVM_NATIVE_DISPLAY_ROTATION", p.options.DisplayRotation), - fmt.Sprintf("%s=%f", "JETKVM_NATIVE_DEFAULT_QUALITY_FACTOR", p.options.DefaultQualityFactor), + envArgs..., ) // Wrap cmd to implement processCmd interface wrappedCmd := &cmdWrapper{Cmd: cmd} diff --git a/internal/native/server.go b/internal/native/server.go index cc642381..c278b9ca 100644 --- a/internal/native/server.go +++ b/internal/native/server.go @@ -10,7 +10,6 @@ import ( "github.com/caarlos0/env/v11" "github.com/erikdubbelboer/gspt" - "github.com/rs/zerolog" ) // Native Process @@ -19,31 +18,24 @@ import ( // RunNativeProcess runs the native process mode func RunNativeProcess(binaryName string) { + logger := *nativeLogger // Initialize logger - logger := zerolog.New(os.Stderr).With().Timestamp().Logger() gspt.SetProcTitle(binaryName + " [native]") - // Determine socket path - socketPath := os.Getenv("JETKVM_NATIVE_SOCKET") - videoStreamSocketPath := os.Getenv("JETKVM_VIDEO_STREAM_SOCKET") - - if socketPath == "" || videoStreamSocketPath == "" { - logger.Fatal().Str("socket_path", socketPath).Str("video_stream_socket_path", videoStreamSocketPath).Msg("socket path or video stream socket path is not set") - } - - // connect to video stream socket - conn, err := net.Dial("unixpacket", videoStreamSocketPath) - if err != nil { - logger.Fatal().Err(err).Msg("failed to connect to video stream socket") - } - logger.Info().Str("video_stream_socket_path", videoStreamSocketPath).Msg("connected to video stream socket") - - var nativeOptions NativeOptions - if err := env.Parse(&nativeOptions); err != nil { + var proxyOptions nativeProxyOptions + if err := env.Parse(&proxyOptions); err != nil { logger.Fatal().Err(err).Msg("failed to parse native options") } + // connect to video stream socket + conn, err := net.Dial("unixpacket", proxyOptions.VideoStreamUnixSocket) + if err != nil { + logger.Fatal().Err(err).Msg("failed to connect to video stream socket") + } + logger.Info().Str("video_stream_socket_path", proxyOptions.VideoStreamUnixSocket).Msg("connected to video stream socket") + + nativeOptions := proxyOptions.toNativeOptions() nativeOptions.OnVideoFrameReceived = func(frame []byte, duration time.Duration) { _, err := conn.Write(frame) if err != nil { @@ -52,7 +44,7 @@ func RunNativeProcess(binaryName string) { } // Create native instance - nativeInstance := NewNative(nativeOptions) + nativeInstance := NewNative(*nativeOptions) // Start native instance if err := nativeInstance.Start(); err != nil { @@ -64,14 +56,14 @@ func RunNativeProcess(binaryName string) { logger.Info().Msg("starting gRPC server") // Start gRPC server - server, lis, err := StartGRPCServer(grpcServer, fmt.Sprintf("@%v", socketPath), &logger) + server, lis, err := StartGRPCServer(grpcServer, fmt.Sprintf("@%v", proxyOptions.CtrlUnixSocket), &logger) if err != nil { logger.Fatal().Err(err).Msg("failed to start gRPC server") } gspt.SetProcTitle(binaryName + " [native] ready") // Signal that we're ready by writing socket path to stdout (for parent to read) - fmt.Fprintf(os.Stdout, "%s\n", socketPath) + fmt.Fprintf(os.Stdout, "%s\n", proxyOptions.CtrlUnixSocket) defer os.Stdout.Close() // Set up signal handling diff --git a/scripts/dev_deploy.sh b/scripts/dev_deploy.sh index 6c8b204c..519206ea 100755 --- a/scripts/dev_deploy.sh +++ b/scripts/dev_deploy.sh @@ -18,6 +18,7 @@ show_help() { echo " --skip-native-build Skip native build" echo " --disable-docker Disable docker build" echo " --enable-sync-trace Enable sync trace (do not use in release builds)" + echo " --native-binary Build and deploy the native binary (FOR DEBUGGING ONLY)" echo " -i, --install Build for release and install the app" echo " --help Display this help message" echo @@ -58,6 +59,7 @@ REMOTE_PATH="/userdata/jetkvm/bin" SKIP_UI_BUILD=false SKIP_UI_BUILD_RELEASE=0 SKIP_NATIVE_BUILD=0 +BUILD_NATIVE_BINARY=false ENABLE_SYNC_TRACE=0 RESET_USB_HID_DEVICE=false LOG_TRACE_SCOPES="${LOG_TRACE_SCOPES:-jetkvm,cloud,websocket,native,jsonrpc}" @@ -113,6 +115,10 @@ while [[ $# -gt 0 ]]; do RUN_GO_TESTS=true shift ;; + --native-binary) + BUILD_NATIVE_BINARY=true + shift + ;; -i|--install) INSTALL_APP=true shift @@ -141,6 +147,9 @@ fi # Check device connectivity before proceeding check_ping "${REMOTE_HOST}" check_ssh "${REMOTE_USER}" "${REMOTE_HOST}" +function sshdev() { + ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "${REMOTE_USER}@${REMOTE_HOST}" $@ +} # check if the current CPU architecture is x86_64 if [ "$(uname -m)" != "x86_64" ]; then @@ -152,6 +161,27 @@ if [ "$BUILD_IN_DOCKER" = true ]; then build_docker_image fi +if [ "$BUILD_NATIVE_BINARY" = true ]; then + msg_info "▶ Building native binary" + make build_native + sshdev "killall -9 jetkvm_app jetkvm_app_debug jetkvm_native_debug || true" + sshdev "cat > ${REMOTE_PATH}/jetkvm_native_debug" < internal/native/cgo/build/jknative-bin + sshdev ash << EOF +set -e + +# Set the library path to include the directory where librockit.so is located +export LD_LIBRARY_PATH=/oem/usr/lib:\$LD_LIBRARY_PATH + +cd ${REMOTE_PATH} +killall -9 jetkvm_app jetkvm_app_debug jetkvm_native_debug || true +sleep 5 +echo 'V' > /dev/watchdog +chmod +x jetkvm_native_debug +./jetkvm_native_debug +EOF + exit 0 +fi + # Build the development version on the host # When using `make build_release`, the frontend will be built regardless of the `SKIP_UI_BUILD` flag # check if static/index.html exists @@ -176,10 +206,10 @@ if [ "$RUN_GO_TESTS" = true ]; then make build_dev_test msg_info "▶ Copying device-tests.tar.gz to remote host" - ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "${REMOTE_USER}@${REMOTE_HOST}" "cat > /tmp/device-tests.tar.gz" < device-tests.tar.gz + sshdev "cat > /tmp/device-tests.tar.gz" < device-tests.tar.gz msg_info "▶ Running go tests" - ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "${REMOTE_USER}@${REMOTE_HOST}" ash << 'EOF' + sshdev ash << 'EOF' set -e TMP_DIR=$(mktemp -d) cd ${TMP_DIR} @@ -222,10 +252,10 @@ then ENABLE_SYNC_TRACE=${ENABLE_SYNC_TRACE} # Copy the binary to the remote host as if we were the OTA updater. - ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "${REMOTE_USER}@${REMOTE_HOST}" "cat > /userdata/jetkvm/jetkvm_app.update" < bin/jetkvm_app + sshdev "cat > /userdata/jetkvm/jetkvm_app.update" < bin/jetkvm_app # Reboot the device, the new app will be deployed by the startup process. - ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "${REMOTE_USER}@${REMOTE_HOST}" "reboot" + sshdev "reboot" else msg_info "▶ Building development binary" do_make build_dev \ @@ -234,21 +264,21 @@ else ENABLE_SYNC_TRACE=${ENABLE_SYNC_TRACE} # Kill any existing instances of the application - ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "${REMOTE_USER}@${REMOTE_HOST}" "killall jetkvm_app_debug || true" + sshdev "killall jetkvm_app_debug || true" # Copy the binary to the remote host - ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "${REMOTE_USER}@${REMOTE_HOST}" "cat > ${REMOTE_PATH}/jetkvm_app_debug" < bin/jetkvm_app + sshdev "cat > ${REMOTE_PATH}/jetkvm_app_debug" < bin/jetkvm_app if [ "$RESET_USB_HID_DEVICE" = true ]; then msg_info "▶ Resetting USB HID device" msg_warn "The option has been deprecated and will be removed in a future version, as JetKVM will now reset USB gadget configuration when needed" # Remove the old USB gadget configuration - ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "${REMOTE_USER}@${REMOTE_HOST}" "rm -rf /sys/kernel/config/usb_gadget/jetkvm/configs/c.1/hid.usb*" - ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "${REMOTE_USER}@${REMOTE_HOST}" "ls /sys/class/udc > /sys/kernel/config/usb_gadget/jetkvm/UDC" + sshdev "rm -rf /sys/kernel/config/usb_gadget/jetkvm/configs/c.1/hid.usb*" + sshdev "ls /sys/class/udc > /sys/kernel/config/usb_gadget/jetkvm/UDC" fi # Deploy and run the application on the remote host - ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "${REMOTE_USER}@${REMOTE_HOST}" ash << EOF + sshdev ash << EOF set -e # Set the library path to include the directory where librockit.so is located