Compare commits
31 Commits
2d364b01ea
...
ad229726fa
| Author | SHA1 | Date |
|---|---|---|
|
|
ad229726fa | |
|
|
227409e2e8 | |
|
|
8f8a743ee6 | |
|
|
e3512cec36 | |
|
|
882cd9ed19 | |
|
|
dde897699e | |
|
|
4d274b3e3e | |
|
|
7d169e30d6 | |
|
|
e53eb320ee | |
|
|
b0b1341508 | |
|
|
d0aa3f1386 | |
|
|
a5cac6f51b | |
|
|
85b9955cad | |
|
|
3f16c28daf | |
|
|
81063425ac | |
|
|
afec360f65 | |
|
|
2a22f234f8 | |
|
|
462613e129 | |
|
|
23a3aaa61d | |
|
|
358512fa83 | |
|
|
70db172287 | |
|
|
76c4144565 | |
|
|
e9bcdc5f3f | |
|
|
028cb7ddd6 | |
|
|
e930363b24 | |
|
|
f106d308a3 | |
|
|
b042adac67 | |
|
|
703625d59a | |
|
|
e582486bec | |
|
|
cb24ef6d4f | |
|
|
fe77acd5f0 |
|
|
@ -35,4 +35,4 @@
|
|||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,19 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
SUDO_PATH=$(which sudo)
|
||||
function sudo() {
|
||||
if [ "$UID" -eq 0 ]; then
|
||||
"$@"
|
||||
else
|
||||
${SUDO_PATH} "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
sudo apt-get update && sudo apt-get install -y --no-install-recommends \
|
||||
set -ex
|
||||
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
sudo apt-get update && \
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
build-essential \
|
||||
device-tree-compiler \
|
||||
gperf g++-multilib gcc-multilib \
|
||||
|
|
|
|||
|
|
@ -16,13 +16,19 @@ jobs:
|
|||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
- name: Set up build dependencies
|
||||
- name: Set up docker image context
|
||||
run: |
|
||||
apt-get update && apt-get install -y \
|
||||
build-essential \
|
||||
cmake \
|
||||
libusb-1.0-0-dev \
|
||||
libudev-dev
|
||||
./scripts/ci_helper.sh prepare
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Build docker image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: ${{ env.DOCKER_BUILD_CONTEXT_DIR }}
|
||||
file: ${{ env.DOCKER_BUILD_CONTEXT_DIR }}/Dockerfile.build
|
||||
tags: ${{ env.DOCKER_BUILD_TAG }}
|
||||
push: false
|
||||
load: true
|
||||
- name: Set up Cmake cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
|
|
@ -37,21 +43,21 @@ jobs:
|
|||
cache: "npm"
|
||||
cache-dependency-path: "**/package-lock.json"
|
||||
- name: Set up Golang
|
||||
uses: actions/setup-go@v5.5.0
|
||||
uses: actions/setup-go@v6.0.0
|
||||
with:
|
||||
go-version: "1.24.4"
|
||||
go-version: "^1.25.1"
|
||||
- name: Build frontend
|
||||
run: |
|
||||
make frontend
|
||||
- name: Build application
|
||||
- name: Build application inside Docker container
|
||||
run: |
|
||||
make build_dev
|
||||
./scripts/ci_helper.sh make build_dev
|
||||
- name: Run tests
|
||||
run: |
|
||||
go test ./... -json > testreport.json
|
||||
- name: Make test cases
|
||||
run: |
|
||||
make build_dev_test
|
||||
./scripts/ci_helper.sh make build_dev_test
|
||||
- name: Golang Test Report
|
||||
uses: becheran/go-testreport@v0.3.2
|
||||
with:
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@ static/*
|
|||
.idea
|
||||
.DS_Store
|
||||
|
||||
.cache
|
||||
.vite
|
||||
.pnpm-store
|
||||
|
||||
device-tests.tar.gz
|
||||
node_modules
|
||||
|
||||
|
|
|
|||
|
|
@ -3,5 +3,6 @@
|
|||
"cva",
|
||||
"cx"
|
||||
],
|
||||
"cmake.sourceDirectory": "/Users/aveline/Projects/JetKVM/ymjk/internal/native/cgo"
|
||||
"cmake.sourceDirectory": "/Users/aveline/Projects/JetKVM/ymjk/internal/native/cgo",
|
||||
"git.ignoreLimitWarning": true
|
||||
}
|
||||
|
|
@ -361,6 +361,17 @@ The application uses a JSON configuration file stored at `/userdata/kvm_config.j
|
|||
3. **Add migration logic if needed for existing installations**
|
||||
|
||||
|
||||
### LVGL Build
|
||||
|
||||
We modified the LVGL code a little bit to remove unused fonts and examples.
|
||||
The patches are generated by
|
||||
|
||||
```bash
|
||||
git diff --cached --diff-filter=d > ../internal/native/cgo/lvgl-minify.patch && \
|
||||
git diff --name-only --diff-filter=d --cached > ../internal/native/cgo/lvgl-minify.del
|
||||
```
|
||||
|
||||
|
||||
---
|
||||
|
||||
**Happy coding!**
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
# syntax=docker/dockerfile:1
|
||||
FROM golang:1.25.1-trixie
|
||||
FROM --platform=${BUILDPLATFORM} golang:1.25.1-trixie AS builder
|
||||
|
||||
ENV GOTOOLCHAIN=local
|
||||
ENV GOPATH /go
|
||||
ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH
|
||||
ENV GOPATH=/go
|
||||
ENV PATH=$GOPATH/bin:/usr/local/go/bin:$PATH
|
||||
|
||||
ADD .devcontainer/install-deps.sh /install-deps.sh
|
||||
COPY install-deps.sh /install-deps.sh
|
||||
RUN /install-deps.sh
|
||||
|
||||
# Create build directory
|
||||
|
|
@ -16,4 +16,9 @@ COPY go.mod go.sum /build/
|
|||
|
||||
WORKDIR /build
|
||||
|
||||
RUN go mod download && go mod verify
|
||||
RUN go mod download && go mod verify
|
||||
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
ENTRYPOINT [ "/entrypoint.sh" ]
|
||||
47
Makefile
|
|
@ -2,16 +2,16 @@ BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
|
|||
BUILDDATE := $(shell date -u +%FT%T%z)
|
||||
BUILDTS := $(shell date -u +%s)
|
||||
REVISION := $(shell git rev-parse HEAD)
|
||||
VERSION_DEV := 0.4.8-dev$(shell date +%Y%m%d%H%M)
|
||||
VERSION := 0.4.7
|
||||
VERSION_DEV := 0.5.0-dev$(shell date +%Y%m%d%H%M)
|
||||
VERSION := 0.4.9
|
||||
|
||||
PROMETHEUS_TAG := github.com/prometheus/common/version
|
||||
KVM_PKG_NAME := github.com/jetkvm/kvm
|
||||
|
||||
BUILDKIT_FLAVOR := arm-rockchip830-linux-uclibcgnueabihf
|
||||
BUILDKIT_PATH ?= /opt/jetkvm-native-buildkit
|
||||
SKIP_NATIVE_IF_EXISTS ?= 1
|
||||
|
||||
SKIP_NATIVE_IF_EXISTS ?= 0
|
||||
SKIP_UI_BUILD ?= 0
|
||||
|
||||
GO_BUILD_ARGS := -tags netgo -tags timetzdata
|
||||
GO_RELEASE_BUILD_ARGS := -trimpath $(GO_BUILD_ARGS)
|
||||
|
|
@ -45,10 +45,9 @@ build_native:
|
|||
echo "libjknative.a already exists, skipping native build..."; \
|
||||
else \
|
||||
echo "Building native..."; \
|
||||
cd internal/native/cgo && ./ui_index.gen.sh && \
|
||||
CC="$(BUILDKIT_PATH)/bin/$(BUILDKIT_FLAVOR)-gcc" \
|
||||
LD="$(BUILDKIT_PATH)/bin/$(BUILDKIT_FLAVOR)-ld" \
|
||||
./build.sh; \
|
||||
./scripts/build_cgo.sh; \
|
||||
fi
|
||||
|
||||
build_dev: build_native
|
||||
|
|
@ -88,22 +87,24 @@ build_dev_test: build_test2json build_gotestsum
|
|||
tar czfv device-tests.tar.gz -C $(BIN_DIR)/tests .
|
||||
|
||||
frontend:
|
||||
cd ui && npm ci && npm run build:device && \
|
||||
find ../static/ \
|
||||
-type f \
|
||||
\( -name '*.js' \
|
||||
-o -name '*.css' \
|
||||
-o -name '*.html' \
|
||||
-o -name '*.ico' \
|
||||
-o -name '*.png' \
|
||||
-o -name '*.jpg' \
|
||||
-o -name '*.jpeg' \
|
||||
-o -name '*.gif' \
|
||||
-o -name '*.svg' \
|
||||
-o -name '*.webp' \
|
||||
-o -name '*.woff2' \
|
||||
\) \
|
||||
-exec sh -c 'gzip -9 -kfv {}' \;
|
||||
@if [ "$(SKIP_UI_BUILD)" = "1" ] && [ -f "static/index.html" ]; then \
|
||||
echo "Skipping frontend build..."; \
|
||||
else \
|
||||
cd ui && npm ci && npm run build:device && \
|
||||
find ../static/ -type f \
|
||||
\( -name '*.js' \
|
||||
-o -name '*.css' \
|
||||
-o -name '*.html' \
|
||||
-o -name '*.ico' \
|
||||
-o -name '*.png' \
|
||||
-o -name '*.jpg' \
|
||||
-o -name '*.jpeg' \
|
||||
-o -name '*.gif' \
|
||||
-o -name '*.svg' \
|
||||
-o -name '*.webp' \
|
||||
-o -name '*.woff2' \
|
||||
\) -exec sh -c 'gzip -9 -kfv {}' \; ;\
|
||||
fi
|
||||
|
||||
dev_release: frontend build_dev
|
||||
@echo "Uploading release... $(VERSION_DEV)"
|
||||
|
|
@ -111,7 +112,7 @@ dev_release: frontend build_dev
|
|||
rclone copyto bin/jetkvm_app r2://jetkvm-update/app/$(VERSION_DEV)/jetkvm_app
|
||||
rclone copyto bin/jetkvm_app.sha256 r2://jetkvm-update/app/$(VERSION_DEV)/jetkvm_app.sha256
|
||||
|
||||
build_release: frontend
|
||||
build_release: frontend build_native
|
||||
@echo "Building release..."
|
||||
$(GO_CMD) build \
|
||||
-ldflags="$(GO_LDFLAGS) -X $(KVM_PKG_NAME).builtAppVersion=$(VERSION)" \
|
||||
|
|
|
|||
204
dev_deploy.sh
|
|
@ -1,204 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Exit immediately if a command exits with a non-zero status
|
||||
set -e
|
||||
|
||||
C_RST="$(tput sgr0)"
|
||||
C_ERR="$(tput setaf 1)"
|
||||
C_OK="$(tput setaf 2)"
|
||||
C_WARN="$(tput setaf 3)"
|
||||
C_INFO="$(tput setaf 5)"
|
||||
|
||||
msg() { printf '%s%s%s\n' $2 "$1" $C_RST; }
|
||||
|
||||
msg_info() { msg "$1" $C_INFO; }
|
||||
msg_ok() { msg "$1" $C_OK; }
|
||||
msg_err() { msg "$1" $C_ERR; }
|
||||
msg_warn() { msg "$1" $C_WARN; }
|
||||
|
||||
# Function to display help message
|
||||
show_help() {
|
||||
echo "Usage: $0 [options] -r <remote_ip>"
|
||||
echo
|
||||
echo "Required:"
|
||||
echo " -r, --remote <remote_ip> Remote host IP address"
|
||||
echo
|
||||
echo "Optional:"
|
||||
echo " -u, --user <remote_user> Remote username (default: root)"
|
||||
echo " --run-go-tests Run go tests"
|
||||
echo " --run-go-tests-only Run go tests and exit"
|
||||
echo " --skip-ui-build Skip frontend/UI build"
|
||||
echo " --skip-native-build Skip native build"
|
||||
echo " -i, --install Build for release and install the app"
|
||||
echo " --help Display this help message"
|
||||
echo
|
||||
echo "Example:"
|
||||
echo " $0 -r 192.168.0.17"
|
||||
echo " $0 -r 192.168.0.17 -u admin"
|
||||
}
|
||||
|
||||
# Default values
|
||||
REMOTE_USER="root"
|
||||
REMOTE_PATH="/userdata/jetkvm/bin"
|
||||
SKIP_UI_BUILD=false
|
||||
SKIP_NATIVE_BUILD=0
|
||||
RESET_USB_HID_DEVICE=false
|
||||
LOG_TRACE_SCOPES="${LOG_TRACE_SCOPES:-jetkvm,cloud,websocket,native,jsonrpc}"
|
||||
RUN_GO_TESTS=false
|
||||
RUN_GO_TESTS_ONLY=false
|
||||
INSTALL_APP=false
|
||||
|
||||
# Parse command line arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-r|--remote)
|
||||
REMOTE_HOST="$2"
|
||||
shift 2
|
||||
;;
|
||||
-u|--user)
|
||||
REMOTE_USER="$2"
|
||||
shift 2
|
||||
;;
|
||||
--skip-ui-build)
|
||||
SKIP_UI_BUILD=true
|
||||
shift
|
||||
;;
|
||||
--skip-native-build)
|
||||
SKIP_NATIVE_BUILD=1
|
||||
shift
|
||||
;;
|
||||
--reset-usb-hid)
|
||||
RESET_USB_HID_DEVICE=true
|
||||
shift
|
||||
;;
|
||||
--run-go-tests)
|
||||
RUN_GO_TESTS=true
|
||||
shift
|
||||
;;
|
||||
--run-go-tests-only)
|
||||
RUN_GO_TESTS_ONLY=true
|
||||
RUN_GO_TESTS=true
|
||||
shift
|
||||
;;
|
||||
-i|--install)
|
||||
INSTALL_APP=true
|
||||
shift
|
||||
;;
|
||||
--help)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Verify required parameters
|
||||
if [ -z "$REMOTE_HOST" ]; then
|
||||
msg_err "Error: Remote IP is a required parameter"
|
||||
show_help
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Build the development version on the host
|
||||
if [ "$SKIP_UI_BUILD" = false ]; then
|
||||
msg_info "▶ Building frontend"
|
||||
make frontend
|
||||
fi
|
||||
|
||||
if [ "$RUN_GO_TESTS" = true ]; then
|
||||
msg_info "▶ Building go tests"
|
||||
make build_dev_test
|
||||
|
||||
msg_info "▶ Copying device-tests.tar.gz to remote host"
|
||||
ssh "${REMOTE_USER}@${REMOTE_HOST}" "cat > /tmp/device-tests.tar.gz" < device-tests.tar.gz
|
||||
|
||||
msg_info "▶ Running go tests"
|
||||
ssh "${REMOTE_USER}@${REMOTE_HOST}" ash << 'EOF'
|
||||
set -e
|
||||
TMP_DIR=$(mktemp -d)
|
||||
cd ${TMP_DIR}
|
||||
tar zxf /tmp/device-tests.tar.gz
|
||||
./gotestsum --format=testdox \
|
||||
--jsonfile=/tmp/device-tests.json \
|
||||
--post-run-command 'sh -c "echo $TESTS_FAILED > /tmp/device-tests.failed"' \
|
||||
--raw-command -- ./run_all_tests -json
|
||||
|
||||
GOTESTSUM_EXIT_CODE=$?
|
||||
if [ $GOTESTSUM_EXIT_CODE -ne 0 ]; then
|
||||
echo "❌ Tests failed (exit code: $GOTESTSUM_EXIT_CODE)"
|
||||
rm -rf ${TMP_DIR} /tmp/device-tests.tar.gz
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TESTS_FAILED=$(cat /tmp/device-tests.failed)
|
||||
if [ "$TESTS_FAILED" -ne 0 ]; then
|
||||
echo "❌ Tests failed $TESTS_FAILED tests failed"
|
||||
rm -rf ${TMP_DIR} /tmp/device-tests.tar.gz
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ Tests passed"
|
||||
rm -rf ${TMP_DIR} /tmp/device-tests.tar.gz
|
||||
EOF
|
||||
|
||||
if [ "$RUN_GO_TESTS_ONLY" = true ]; then
|
||||
msg_info "▶ Go tests completed"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$INSTALL_APP" = true ]
|
||||
then
|
||||
msg_info "▶ Building release binary"
|
||||
make build_release SKIP_NATIVE_IF_EXISTS=${SKIP_NATIVE_BUILD}
|
||||
|
||||
# Copy the binary to the remote host as if we were the OTA updater.
|
||||
ssh "${REMOTE_USER}@${REMOTE_HOST}" "cat > /userdata/jetkvm/jetkvm_app.update" < bin/jetkvm_app
|
||||
|
||||
# Reboot the device, the new app will be deployed by the startup process.
|
||||
ssh "${REMOTE_USER}@${REMOTE_HOST}" "reboot"
|
||||
else
|
||||
msg_info "▶ Building development binary"
|
||||
make build_dev SKIP_NATIVE_IF_EXISTS=${SKIP_NATIVE_BUILD}
|
||||
|
||||
# Kill any existing instances of the application
|
||||
ssh "${REMOTE_USER}@${REMOTE_HOST}" "killall jetkvm_app_debug || true"
|
||||
|
||||
# Copy the binary to the remote host
|
||||
ssh "${REMOTE_USER}@${REMOTE_HOST}" "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 "${REMOTE_USER}@${REMOTE_HOST}" "rm -rf /sys/kernel/config/usb_gadget/jetkvm/configs/c.1/hid.usb*"
|
||||
ssh "${REMOTE_USER}@${REMOTE_HOST}" "ls /sys/class/udc > /sys/kernel/config/usb_gadget/jetkvm/UDC"
|
||||
fi
|
||||
|
||||
# Deploy and run the application on the remote host
|
||||
ssh "${REMOTE_USER}@${REMOTE_HOST}" 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
|
||||
|
||||
# Kill any existing instances of the application
|
||||
killall jetkvm_app || true
|
||||
killall jetkvm_app_debug || true
|
||||
|
||||
# Navigate to the directory where the binary will be stored
|
||||
cd "${REMOTE_PATH}"
|
||||
|
||||
# Make the new binary executable
|
||||
chmod +x jetkvm_app_debug
|
||||
|
||||
# Run the application in the background
|
||||
PION_LOG_TRACE=${LOG_TRACE_SCOPES} ./jetkvm_app_debug | tee -a /tmp/jetkvm_app_debug.log
|
||||
EOF
|
||||
fi
|
||||
|
||||
echo "Deployment complete."
|
||||
|
|
@ -0,0 +1 @@
|
|||
scripts/dev_deploy.sh
|
||||
29
display.go
|
|
@ -23,7 +23,6 @@ var (
|
|||
)
|
||||
|
||||
const (
|
||||
touchscreenDevice string = "/dev/input/event1"
|
||||
backlightControlClass string = "/sys/class/backlight/backlight/brightness"
|
||||
)
|
||||
|
||||
|
|
@ -38,23 +37,25 @@ func updateDisplay() {
|
|||
|
||||
if usbState == "configured" {
|
||||
nativeInstance.UpdateLabelIfChanged("usb_status_label", "Connected")
|
||||
_, _ = nativeInstance.UIObjSetState("usb_status", "LV_STATE_DEFAULT")
|
||||
_, _ = nativeInstance.UIObjAddState("usb_status_label", "LV_STATE_CHECKED")
|
||||
} else {
|
||||
nativeInstance.UpdateLabelIfChanged("usb_status_label", "Disconnected")
|
||||
_, _ = nativeInstance.UIObjSetState("usb_status", "LV_STATE_DISABLED")
|
||||
_, _ = nativeInstance.UIObjClearState("usb_status_label", "LV_STATE_CHECKED")
|
||||
}
|
||||
if lastVideoState.Ready {
|
||||
nativeInstance.UpdateLabelIfChanged("hdmi_status_label", "Connected")
|
||||
_, _ = nativeInstance.UIObjSetState("hdmi_status", "LV_STATE_DEFAULT")
|
||||
_, _ = nativeInstance.UIObjAddState("hdmi_status_label", "LV_STATE_CHECKED")
|
||||
} else {
|
||||
nativeInstance.UpdateLabelIfChanged("hdmi_status_label", "Disconnected")
|
||||
_, _ = nativeInstance.UIObjSetState("hdmi_status", "LV_STATE_DISABLED")
|
||||
_, _ = nativeInstance.UIObjClearState("hdmi_status_label", "LV_STATE_CHECKED")
|
||||
}
|
||||
nativeInstance.UpdateLabelIfChanged("cloud_status_label", fmt.Sprintf("%d active", actionSessions))
|
||||
|
||||
if networkState.IsUp() {
|
||||
nativeInstance.UISetVar("main_screen", "home_screen")
|
||||
nativeInstance.SwitchToScreenIf("home_screen", []string{"no_network_screen", "boot_screen"})
|
||||
} else {
|
||||
nativeInstance.UISetVar("main_screen", "no_network_screen")
|
||||
nativeInstance.SwitchToScreenIf("no_network_screen", []string{"home_screen", "boot_screen"})
|
||||
}
|
||||
|
||||
|
|
@ -184,19 +185,19 @@ func updateStaticContents() {
|
|||
nativeInstance.UpdateLabelIfChanged("home_info_mac_addr", networkState.MACString())
|
||||
|
||||
// get cpu info
|
||||
cpuInfo, err := os.ReadFile("/proc/cpuinfo")
|
||||
// get the line starting with "Serial"
|
||||
for _, line := range strings.Split(string(cpuInfo), "\n") {
|
||||
if strings.HasPrefix(line, "Serial") {
|
||||
serial := strings.SplitN(line, ":", 2)[1]
|
||||
nativeInstance.UpdateLabelAndChangeVisibility("cpu_serial", strings.TrimSpace(serial))
|
||||
break
|
||||
if cpuInfo, err := os.ReadFile("/proc/cpuinfo"); err == nil {
|
||||
// get the line starting with "Serial"
|
||||
for line := range strings.SplitSeq(string(cpuInfo), "\n") {
|
||||
if strings.HasPrefix(line, "Serial") {
|
||||
serial := strings.SplitN(line, ":", 2)[1]
|
||||
nativeInstance.UpdateLabelAndChangeVisibility("cpu_serial", strings.TrimSpace(serial))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get kernel version
|
||||
kernelVersion, err := os.ReadFile("/proc/version")
|
||||
if err == nil {
|
||||
if kernelVersion, err := os.ReadFile("/proc/version"); err == nil {
|
||||
kernelVersion := strings.TrimPrefix(string(kernelVersion), "Linux version ")
|
||||
kernelVersion = strings.SplitN(kernelVersion, " ", 2)[0]
|
||||
nativeInstance.UpdateLabelAndChangeVisibility("kernel_version", kernelVersion)
|
||||
|
|
|
|||
|
|
@ -1,84 +0,0 @@
|
|||
package lldp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/google/gopacket/afpacket"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
afPacketBufferSize = 2 // in MiB
|
||||
afPacketSnaplen = 9216
|
||||
)
|
||||
|
||||
func afPacketComputeSize(targetSizeMb int, snaplen int, pageSize int) (
|
||||
frameSize int, blockSize int, numBlocks int, err error) {
|
||||
if snaplen < pageSize {
|
||||
frameSize = pageSize / (pageSize / snaplen)
|
||||
} else {
|
||||
frameSize = (snaplen/pageSize + 1) * pageSize
|
||||
}
|
||||
|
||||
// 128 is the default from the gopacket library so just use that
|
||||
blockSize = frameSize * 128
|
||||
numBlocks = (targetSizeMb * 1024 * 1024) / blockSize
|
||||
|
||||
if numBlocks == 0 {
|
||||
return 0, 0, 0, fmt.Errorf("interface buffersize is too small")
|
||||
}
|
||||
|
||||
return frameSize, blockSize, numBlocks, nil
|
||||
}
|
||||
|
||||
func afPacketNewTPacket(ifName string) (*afpacket.TPacket, error) {
|
||||
szFrame, szBlock, numBlocks, err := afPacketComputeSize(
|
||||
afPacketBufferSize,
|
||||
afPacketSnaplen,
|
||||
os.Getpagesize())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return afpacket.NewTPacket(
|
||||
afpacket.OptInterface(ifName),
|
||||
afpacket.OptFrameSize(szFrame),
|
||||
afpacket.OptBlockSize(szBlock),
|
||||
afpacket.OptNumBlocks(numBlocks),
|
||||
afpacket.OptAddVLANHeader(false),
|
||||
afpacket.SocketRaw,
|
||||
afpacket.TPacketVersion3)
|
||||
}
|
||||
|
||||
type ifreq struct {
|
||||
ifrName [IFNAMSIZ]byte
|
||||
ifrHwaddr syscall.RawSockaddr
|
||||
}
|
||||
|
||||
func addMulticastAddr(ifName string, addr net.HardwareAddr) error {
|
||||
fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer syscall.Close(fd)
|
||||
|
||||
var name [IFNAMSIZ]byte
|
||||
copy(name[:], []byte(ifName))
|
||||
|
||||
ifr := &ifreq{
|
||||
ifrName: name,
|
||||
ifrHwaddr: toRawSockaddr(addr),
|
||||
}
|
||||
|
||||
_, _, ep := unix.Syscall(unix.SYS_IOCTL, uintptr(fd),
|
||||
unix.SIOCADDMULTI, uintptr(unsafe.Pointer(ifr)))
|
||||
|
||||
if ep != 0 {
|
||||
return syscall.Errno(ep)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
//go:build arm && linux
|
||||
|
||||
package lldp
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func toRawSockaddr(mac net.HardwareAddr) (sockaddr syscall.RawSockaddr) {
|
||||
for i, n := range mac {
|
||||
sockaddr.Data[i] = uint8(n)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
//go:build !arm && linux
|
||||
|
||||
package lldp
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func toRawSockaddr(mac net.HardwareAddr) (sockaddr syscall.RawSockaddr) {
|
||||
for i, n := range mac {
|
||||
sockaddr.Data[i] = int8(n)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
package lldp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/afpacket"
|
||||
"github.com/jellydator/ttlcache/v3"
|
||||
"github.com/jetkvm/kvm/internal/logging"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
var defaultLogger = logging.GetSubsystemLogger("lldp")
|
||||
|
||||
type LLDP struct {
|
||||
l *zerolog.Logger
|
||||
tPacket *afpacket.TPacket
|
||||
pktSource *gopacket.PacketSource
|
||||
rxCtx context.Context
|
||||
rxCancel context.CancelFunc
|
||||
rxLock sync.Mutex
|
||||
|
||||
enableRx bool
|
||||
enableTx bool
|
||||
|
||||
packets chan gopacket.Packet
|
||||
interfaceName string
|
||||
stop chan struct{}
|
||||
|
||||
neighbors *ttlcache.Cache[string, Neighbor]
|
||||
}
|
||||
|
||||
type LLDPOptions struct {
|
||||
InterfaceName string
|
||||
EnableRx bool
|
||||
EnableTx bool
|
||||
Logger *zerolog.Logger
|
||||
}
|
||||
|
||||
func NewLLDP(opts *LLDPOptions) *LLDP {
|
||||
if opts.Logger == nil {
|
||||
opts.Logger = defaultLogger
|
||||
}
|
||||
|
||||
if opts.InterfaceName == "" {
|
||||
opts.Logger.Fatal().Msg("InterfaceName is required")
|
||||
}
|
||||
|
||||
return &LLDP{
|
||||
interfaceName: opts.InterfaceName,
|
||||
enableRx: opts.EnableRx,
|
||||
enableTx: opts.EnableTx,
|
||||
l: opts.Logger,
|
||||
neighbors: ttlcache.New(ttlcache.WithTTL[string, Neighbor](1 * time.Hour)),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *LLDP) Start() error {
|
||||
l.rxLock.Lock()
|
||||
defer l.rxLock.Unlock()
|
||||
|
||||
if l.rxCtx != nil {
|
||||
l.l.Info().Msg("LLDP already started")
|
||||
return nil
|
||||
}
|
||||
|
||||
l.rxCtx, l.rxCancel = context.WithCancel(context.Background())
|
||||
|
||||
if l.enableRx {
|
||||
l.l.Info().Msg("setting up AF_PACKET")
|
||||
if err := l.setUpCapture(); err != nil {
|
||||
l.l.Error().Err(err).Msg("unable to set up AF_PACKET")
|
||||
return err
|
||||
}
|
||||
if err := l.startCapture(); err != nil {
|
||||
l.l.Error().Err(err).Msg("unable to start capture")
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
go l.neighbors.Start()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *LLDP) Stop() error {
|
||||
l.rxLock.Lock()
|
||||
defer l.rxLock.Unlock()
|
||||
|
||||
if l.rxCancel != nil {
|
||||
l.rxCancel()
|
||||
l.rxCancel = nil
|
||||
l.rxCtx = nil
|
||||
}
|
||||
|
||||
if l.enableRx {
|
||||
_ = l.shutdownCapture()
|
||||
}
|
||||
|
||||
l.neighbors.Stop()
|
||||
l.neighbors.DeleteAll()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
package lldp
|
||||
|
||||
import "time"
|
||||
|
||||
type Neighbor struct {
|
||||
Mac string `json:"mac"`
|
||||
Source string `json:"source"`
|
||||
ChassisID string `json:"chassis_id"`
|
||||
PortID string `json:"port_id"`
|
||||
PortDescription string `json:"port_description"`
|
||||
SystemName string `json:"system_name"`
|
||||
SystemDescription string `json:"system_description"`
|
||||
TTL uint16 `json:"ttl"`
|
||||
ManagementAddress string `json:"management_address"`
|
||||
Values map[string]string `json:"values"`
|
||||
}
|
||||
|
||||
func (l *LLDP) addNeighbor(mac string, neighbor Neighbor, ttl time.Duration) {
|
||||
logger := l.l.With().
|
||||
Str("mac", mac).
|
||||
Interface("neighbor", neighbor).
|
||||
Logger()
|
||||
|
||||
current_neigh := l.neighbors.Get(mac)
|
||||
if current_neigh != nil {
|
||||
current_source := current_neigh.Value().Source
|
||||
if current_source == "lldp" && neighbor.Source != "lldp" {
|
||||
logger.Info().Msg("skip updating neighbor, as LLDP has higher priority")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
logger.Info().Msg("adding neighbor")
|
||||
l.neighbors.Set(mac, neighbor, ttl)
|
||||
}
|
||||
|
||||
func (l *LLDP) deleteNeighbor(mac string) {
|
||||
logger := l.l.With().
|
||||
Str("mac", mac).
|
||||
Logger()
|
||||
|
||||
logger.Info().Msg("deleting neighbor")
|
||||
l.neighbors.Delete(mac)
|
||||
}
|
||||
|
||||
func (l *LLDP) GetNeighbors() []Neighbor {
|
||||
items := l.neighbors.Items()
|
||||
neighbors := make([]Neighbor, 0, len(items))
|
||||
|
||||
for _, item := range items {
|
||||
neighbors = append(neighbors, item.Value())
|
||||
}
|
||||
|
||||
l.l.Info().Interface("neighbors", neighbors).Msg("neighbors")
|
||||
|
||||
return neighbors
|
||||
}
|
||||
|
|
@ -1,264 +0,0 @@
|
|||
package lldp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
"github.com/rs/zerolog"
|
||||
"golang.org/x/net/bpf"
|
||||
)
|
||||
|
||||
const IFNAMSIZ = 16
|
||||
|
||||
var (
|
||||
lldpDefaultTTL = 120 * time.Second
|
||||
cdpDefaultTTL = 180 * time.Second
|
||||
)
|
||||
|
||||
// from lldpd
|
||||
// https://github.com/lldpd/lldpd/blob/9034c9332cca0c8b1a20e1287f0e5fed81f7eb2a/src/daemon/lldpd.h#L246
|
||||
//
|
||||
//nolint:govet
|
||||
var bpfFilter = []bpf.RawInstruction{
|
||||
{0x30, 0, 0, 0x00000000}, {0x54, 0, 0, 0x00000001}, {0x15, 0, 16, 0x00000001},
|
||||
{0x28, 0, 0, 0x0000000c}, {0x15, 0, 6, 0x000088cc},
|
||||
{0x20, 0, 0, 0x00000002}, {0x15, 2, 0, 0xc200000e},
|
||||
{0x15, 1, 0, 0xc2000003}, {0x15, 0, 2, 0xc2000000},
|
||||
{0x28, 0, 0, 0x00000000}, {0x15, 12, 13, 0x00000180},
|
||||
{0x20, 0, 0, 0x00000002}, {0x15, 0, 2, 0x52cccccc},
|
||||
{0x28, 0, 0, 0x00000000}, {0x15, 8, 9, 0x000001e0},
|
||||
{0x15, 1, 0, 0x0ccccccc}, {0x15, 0, 2, 0x81000100},
|
||||
{0x28, 0, 0, 0x00000000}, {0x15, 4, 5, 0x00000100},
|
||||
{0x20, 0, 0, 0x00000002}, {0x15, 0, 3, 0x2b000000},
|
||||
{0x28, 0, 0, 0x00000000}, {0x15, 0, 1, 0x000000e0},
|
||||
{0x6, 0, 0, 0x00040000},
|
||||
{0x6, 0, 0, 0x00000000},
|
||||
}
|
||||
|
||||
var multicastAddrs = []string{
|
||||
// LLDP
|
||||
"01:80:C2:00:00:00",
|
||||
"01:80:C2:00:00:03",
|
||||
"01:80:C2:00:00:0E",
|
||||
// CDP
|
||||
"01:00:0C:CC:CC:CC",
|
||||
}
|
||||
|
||||
func (l *LLDP) setUpCapture() error {
|
||||
logger := l.l.With().Str("interface", l.interfaceName).Logger()
|
||||
tPacket, err := afPacketNewTPacket(l.interfaceName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Info().Msg("created TPacket")
|
||||
|
||||
// set up multicast addresses
|
||||
// otherwise the kernel might discard the packets
|
||||
// another workaround would be to enable promiscuous mode but that's too tricky
|
||||
for _, mac := range multicastAddrs {
|
||||
hwAddr, err := net.ParseMAC(mac)
|
||||
if err != nil {
|
||||
logger.Error().Msgf("unable to parse MAC address %s: %s", mac, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if err := addMulticastAddr(l.interfaceName, hwAddr); err != nil {
|
||||
logger.Error().Msgf("unable to add multicast address %s: %s", mac, err)
|
||||
continue
|
||||
}
|
||||
|
||||
logger.Info().
|
||||
Interface("hwaddr", hwAddr).
|
||||
Msgf("added multicast address")
|
||||
}
|
||||
|
||||
if err = tPacket.SetBPF(bpfFilter); err != nil {
|
||||
logger.Error().Msgf("unable to set BPF filter: %s", err)
|
||||
tPacket.Close()
|
||||
return err
|
||||
}
|
||||
logger.Info().Msg("BPF filter set")
|
||||
|
||||
l.pktSource = gopacket.NewPacketSource(tPacket, layers.LayerTypeEthernet)
|
||||
l.tPacket = tPacket
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *LLDP) startCapture() error {
|
||||
logger := l.l.With().Str("interface", l.interfaceName).Logger()
|
||||
if l.tPacket == nil {
|
||||
return fmt.Errorf("AFPacket not initialized")
|
||||
}
|
||||
|
||||
if l.pktSource == nil {
|
||||
return fmt.Errorf("packet source not initialized")
|
||||
}
|
||||
|
||||
go func() {
|
||||
logger.Info().Msg("starting capture LLDP ethernet frames")
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-l.rxCtx.Done():
|
||||
logger.Info().Msg("shutting down LLDP capture")
|
||||
return
|
||||
case packet := <-l.pktSource.Packets():
|
||||
if err := l.handlePacket(packet, &logger); err != nil {
|
||||
logger.Error().Msgf("error handling packet: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *LLDP) handlePacket(packet gopacket.Packet, logger *zerolog.Logger) error {
|
||||
linkLayer := packet.LinkLayer()
|
||||
if linkLayer == nil {
|
||||
return fmt.Errorf("no link layer")
|
||||
}
|
||||
|
||||
srcMac := linkLayer.LinkFlow().Src().String()
|
||||
dstMac := linkLayer.LinkFlow().Dst().String()
|
||||
|
||||
logger.Trace().
|
||||
Str("src_mac", srcMac).
|
||||
Str("dst_mac", dstMac).
|
||||
Int("length", len(packet.Data())).
|
||||
Hex("data", packet.Data()).
|
||||
Msg("received packet")
|
||||
|
||||
lldpRaw := packet.Layer(layers.LayerTypeLinkLayerDiscovery)
|
||||
if lldpRaw != nil {
|
||||
logger.Trace().Msgf("Found LLDP Frame")
|
||||
|
||||
lldpInfo := packet.Layer(layers.LayerTypeLinkLayerDiscoveryInfo)
|
||||
if lldpInfo == nil {
|
||||
return fmt.Errorf("no LLDP info layer")
|
||||
}
|
||||
|
||||
return l.handlePacketLLDP(
|
||||
srcMac,
|
||||
lldpRaw.(*layers.LinkLayerDiscovery),
|
||||
lldpInfo.(*layers.LinkLayerDiscoveryInfo),
|
||||
)
|
||||
}
|
||||
|
||||
cdpRaw := packet.Layer(layers.LayerTypeCiscoDiscovery)
|
||||
if cdpRaw != nil {
|
||||
logger.Trace().Msgf("Found CDP Frame")
|
||||
|
||||
cdpInfo := packet.Layer(layers.LayerTypeCiscoDiscoveryInfo)
|
||||
if cdpInfo == nil {
|
||||
return fmt.Errorf("no CDP info layer")
|
||||
}
|
||||
|
||||
return l.handlePacketCDP(
|
||||
srcMac,
|
||||
cdpRaw.(*layers.CiscoDiscovery),
|
||||
cdpInfo.(*layers.CiscoDiscoveryInfo),
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *LLDP) handlePacketLLDP(mac string, raw *layers.LinkLayerDiscovery, info *layers.LinkLayerDiscoveryInfo) error {
|
||||
n := &Neighbor{
|
||||
Values: make(map[string]string),
|
||||
Source: "lldp",
|
||||
Mac: mac,
|
||||
}
|
||||
gotEnd := false
|
||||
|
||||
ttl := lldpDefaultTTL
|
||||
|
||||
for _, v := range raw.Values {
|
||||
switch v.Type {
|
||||
case layers.LLDPTLVEnd:
|
||||
gotEnd = true
|
||||
case layers.LLDPTLVChassisID:
|
||||
n.ChassisID = string(raw.ChassisID.ID)
|
||||
n.Values["chassis_id"] = n.ChassisID
|
||||
case layers.LLDPTLVPortID:
|
||||
n.PortID = string(raw.PortID.ID)
|
||||
n.Values["port_id"] = n.PortID
|
||||
case layers.LLDPTLVPortDescription:
|
||||
n.PortDescription = info.PortDescription
|
||||
n.Values["port_description"] = n.PortDescription
|
||||
case layers.LLDPTLVSysName:
|
||||
n.SystemName = info.SysName
|
||||
n.Values["system_name"] = n.SystemName
|
||||
case layers.LLDPTLVSysDescription:
|
||||
n.SystemDescription = info.SysDescription
|
||||
n.Values["system_description"] = n.SystemDescription
|
||||
case layers.LLDPTLVMgmtAddress:
|
||||
// n.ManagementAddress = info.MgmtAddress.Address
|
||||
case layers.LLDPTLVTTL:
|
||||
n.TTL = uint16(raw.TTL)
|
||||
ttl = time.Duration(n.TTL) * time.Second
|
||||
n.Values["ttl"] = fmt.Sprintf("%d", n.TTL)
|
||||
case layers.LLDPTLVOrgSpecific:
|
||||
for _, org := range info.OrgTLVs {
|
||||
n.Values[fmt.Sprintf("org_specific_%d", org.OUI)] = string(org.Info)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if gotEnd || ttl < 1*time.Second {
|
||||
l.deleteNeighbor(mac)
|
||||
} else {
|
||||
l.addNeighbor(mac, *n, ttl)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *LLDP) handlePacketCDP(mac string, raw *layers.CiscoDiscovery, info *layers.CiscoDiscoveryInfo) error {
|
||||
// TODO: implement full CDP parsing
|
||||
n := &Neighbor{
|
||||
Values: make(map[string]string),
|
||||
Source: "cdp",
|
||||
Mac: mac,
|
||||
}
|
||||
|
||||
ttl := cdpDefaultTTL
|
||||
|
||||
n.ChassisID = info.DeviceID
|
||||
n.PortID = info.PortID
|
||||
n.SystemName = info.SysName
|
||||
n.SystemDescription = info.Platform
|
||||
n.TTL = uint16(raw.TTL)
|
||||
|
||||
if n.TTL > 1 {
|
||||
ttl = time.Duration(n.TTL) * time.Second
|
||||
}
|
||||
|
||||
if len(info.MgmtAddresses) > 0 {
|
||||
n.ManagementAddress = string(info.MgmtAddresses[0])
|
||||
}
|
||||
|
||||
l.addNeighbor(mac, *n, ttl)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *LLDP) shutdownCapture() error {
|
||||
if l.tPacket != nil {
|
||||
l.l.Info().Msg("closing TPacket")
|
||||
l.tPacket.Close()
|
||||
l.tPacket = nil
|
||||
}
|
||||
|
||||
if l.pktSource != nil {
|
||||
l.l.Info().Msg("closing packet source")
|
||||
l.pktSource = nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -35,6 +35,7 @@ FetchContent_Declare(
|
|||
GIT_TAG v9.3.0
|
||||
GIT_SHALLOW 1
|
||||
UPDATE_DISCONNECTED 1
|
||||
PATCH_COMMAND patch -p1 -f < ${CMAKE_CURRENT_SOURCE_DIR}/lvgl-minify.patch && cat ${CMAKE_CURRENT_SOURCE_DIR}/lvgl-minify.del | xargs rm -v
|
||||
)
|
||||
FetchContent_MakeAvailable(lvgl)
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
jetkvm_video_state_t state;
|
||||
jetkvm_video_state_handler_t *video_state_handler = NULL;
|
||||
|
||||
jetkvm_rpc_handler_t *rpc_handler = NULL;
|
||||
jetkvm_video_handler_t *video_handler = NULL;
|
||||
|
||||
|
||||
|
|
@ -34,6 +34,16 @@ void jetkvm_set_indev_handler(jetkvm_indev_handler_t *handler) {
|
|||
lvgl_set_indev_handler(handler);
|
||||
}
|
||||
|
||||
void jetkvm_set_rpc_handler(jetkvm_rpc_handler_t *handler) {
|
||||
rpc_handler = handler;
|
||||
}
|
||||
|
||||
void jetkvm_call_rpc_handler(const char *method, const char *params) {
|
||||
if (rpc_handler != NULL) {
|
||||
(*rpc_handler)(method, params);
|
||||
}
|
||||
}
|
||||
|
||||
const char *jetkvm_ui_event_code_to_name(int code) {
|
||||
lv_event_code_t cCode = (lv_event_code_t)code;
|
||||
return lv_event_code_get_name(code);
|
||||
|
|
@ -237,38 +247,52 @@ void jetkvm_ui_set_image(const char *obj_name, const char *image_name) {
|
|||
lv_img_set_src(obj, image_name);
|
||||
}
|
||||
|
||||
void jetkvm_ui_set_state(const char *obj_name, const char *state_name) {
|
||||
lv_state_t str_to_lv_state(const char *state_name) {
|
||||
if (strcmp(state_name, "LV_STATE_USER_1") == 0) {
|
||||
return LV_STATE_USER_1;
|
||||
}
|
||||
else if (strcmp(state_name, "LV_STATE_USER_2") == 0) {
|
||||
return LV_STATE_USER_2;
|
||||
}
|
||||
else if (strcmp(state_name, "LV_STATE_USER_3") == 0) {
|
||||
return LV_STATE_USER_3;
|
||||
}
|
||||
else if (strcmp(state_name, "LV_STATE_USER_4") == 0) {
|
||||
return LV_STATE_USER_4;
|
||||
}
|
||||
else if (strcmp(state_name, "LV_STATE_DISABLED") == 0) {
|
||||
return LV_STATE_DISABLED;
|
||||
}
|
||||
else if (strcmp(state_name, "LV_STATE_DEFAULT") == 0) {
|
||||
return LV_STATE_DEFAULT;
|
||||
}
|
||||
else if (strcmp(state_name, "LV_STATE_CHECKED") == 0) {
|
||||
return LV_STATE_CHECKED;
|
||||
}
|
||||
else if (strcmp(state_name, "LV_STATE_FOCUSED") == 0) {
|
||||
return LV_STATE_FOCUSED;
|
||||
}
|
||||
return LV_STATE_DEFAULT;
|
||||
}
|
||||
|
||||
void jetkvm_ui_add_state(const char *obj_name, const char *state_name) {
|
||||
lv_obj_t *obj = ui_get_obj(obj_name);
|
||||
if (obj == NULL) {
|
||||
return;
|
||||
}
|
||||
lv_obj_add_state(obj, LV_STATE_USER_1);
|
||||
lv_state_t state_val = LV_STATE_DEFAULT;
|
||||
if (strcmp(state_name, "LV_STATE_USER_1") == 0)
|
||||
{
|
||||
state_val = LV_STATE_USER_1;
|
||||
}
|
||||
else if (strcmp(state_name, "LV_STATE_USER_2") == 0)
|
||||
{
|
||||
state_val = LV_STATE_USER_2;
|
||||
}
|
||||
else if (strcmp(state_name, "LV_STATE_USER_3") == 0)
|
||||
{
|
||||
state_val = LV_STATE_USER_3;
|
||||
}
|
||||
else if (strcmp(state_name, "LV_STATE_USER_4") == 0)
|
||||
{
|
||||
state_val = LV_STATE_USER_4;
|
||||
}
|
||||
else if (strcmp(state_name, "LV_STATE_DISABLED") == 0)
|
||||
{
|
||||
state_val = LV_STATE_DISABLED;
|
||||
}
|
||||
// TODO: use LV_STATE_USER_* once eez supports it
|
||||
lv_obj_clear_state(obj, LV_STATE_USER_1 | LV_STATE_USER_2 | LV_STATE_USER_3 | LV_STATE_USER_4 | LV_STATE_DISABLED);
|
||||
lv_state_t state_val = str_to_lv_state(state_name);
|
||||
lv_obj_add_state(obj, state_val);
|
||||
}
|
||||
|
||||
void jetkvm_ui_clear_state(const char *obj_name, const char *state_name) {
|
||||
lv_obj_t *obj = ui_get_obj(obj_name);
|
||||
if (obj == NULL) {
|
||||
return;
|
||||
}
|
||||
lv_state_t state_val = str_to_lv_state(state_name);
|
||||
lv_obj_clear_state(obj, state_val);
|
||||
}
|
||||
|
||||
int jetkvm_ui_add_flag(const char *obj_name, const char *flag_name) {
|
||||
lv_obj_t *obj = ui_get_obj(obj_name);
|
||||
if (obj == NULL) {
|
||||
|
|
@ -369,6 +393,10 @@ jetkvm_video_state_t *jetkvm_video_get_status() {
|
|||
return &state;
|
||||
}
|
||||
|
||||
char *jetkvm_video_log_status() {
|
||||
return videoc_log_status();
|
||||
}
|
||||
|
||||
int jetkvm_video_init() {
|
||||
return video_init();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,12 +16,15 @@ typedef struct
|
|||
|
||||
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);
|
||||
|
||||
void jetkvm_set_log_handler(jetkvm_log_handler_t *handler);
|
||||
void jetkvm_set_video_handler(jetkvm_video_handler_t *handler);
|
||||
void jetkvm_set_indev_handler(jetkvm_indev_handler_t *handler);
|
||||
void jetkvm_set_rpc_handler(jetkvm_rpc_handler_t *handler);
|
||||
void jetkvm_call_rpc_handler(const char *method, const char *params);
|
||||
void jetkvm_set_video_state_handler(jetkvm_video_state_handler_t *handler);
|
||||
|
||||
void jetkvm_ui_set_var(const char *name, const char *value);
|
||||
|
|
@ -36,7 +39,8 @@ const char *jetkvm_ui_get_current_screen();
|
|||
void jetkvm_ui_load_screen(const char *obj_name);
|
||||
int jetkvm_ui_set_text(const char *obj_name, const char *text);
|
||||
void jetkvm_ui_set_image(const char *obj_name, const char *image_name);
|
||||
void jetkvm_ui_set_state(const char *obj_name, const char *state_name);
|
||||
void jetkvm_ui_add_state(const char *obj_name, const char *state_name);
|
||||
void jetkvm_ui_clear_state(const char *obj_name, const char *state_name);
|
||||
void jetkvm_ui_fade_in(const char *obj_name, u_int32_t duration);
|
||||
void jetkvm_ui_fade_out(const char *obj_name, u_int32_t duration);
|
||||
void jetkvm_ui_set_opacity(const char *obj_name, u_int8_t opacity);
|
||||
|
|
@ -55,6 +59,7 @@ int jetkvm_video_set_quality_factor(float quality_factor);
|
|||
float jetkvm_video_get_quality_factor();
|
||||
int jetkvm_video_set_edid(const char *edid_hex);
|
||||
char *jetkvm_video_get_edid_hex();
|
||||
char *jetkvm_video_log_status();
|
||||
jetkvm_video_state_t *jetkvm_video_get_status();
|
||||
|
||||
void video_report_format(bool ready, const char *error, u_int16_t width, u_int16_t height, double frame_per_second);
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ int get_edid(uint8_t *edid, size_t max_size)
|
|||
fd = open(V4L_SUBDEV, O_RDWR);
|
||||
if (fd < 0)
|
||||
{
|
||||
perror("Failed to open device");
|
||||
log_error("Failed to open device");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -48,7 +48,7 @@ int get_edid(uint8_t *edid, size_t max_size)
|
|||
|
||||
if (ioctl(fd, VIDIOC_G_EDID, &v4l2_edid) < 0)
|
||||
{
|
||||
perror("Failed to get EDID");
|
||||
log_error("Failed to get EDID");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -90,7 +90,7 @@ int set_edid(uint8_t *edid, size_t size)
|
|||
fd = open(V4L_SUBDEV, O_RDWR);
|
||||
if (fd < 0)
|
||||
{
|
||||
perror("Failed to open device");
|
||||
log_error("Failed to open device");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -104,7 +104,7 @@ int set_edid(uint8_t *edid, size_t size)
|
|||
|
||||
if (ioctl(fd, VIDIOC_S_EDID, &v4l2_edid) < 0)
|
||||
{
|
||||
perror("Failed to set EDID");
|
||||
log_error("Failed to set EDID");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -123,13 +123,13 @@ const char *videoc_log_status()
|
|||
fd = open(V4L_SUBDEV, O_RDWR);
|
||||
if (fd < 0)
|
||||
{
|
||||
perror("Failed to open device");
|
||||
log_error("Failed to open device");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ioctl(fd, VIDIOC_LOG_STATUS) == -1)
|
||||
{
|
||||
perror("VIDIOC_LOG_STATUS failed");
|
||||
log_error("VIDIOC_LOG_STATUS failed");
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -166,14 +166,14 @@ const char *videoc_log_status()
|
|||
buffer = strdup(p);
|
||||
if (buffer == NULL)
|
||||
{
|
||||
perror("Failed to allocate memory for status");
|
||||
log_error("Failed to allocate memory for status");
|
||||
return NULL;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
log_error("Failed to read kernel log\n");
|
||||
log_error("Failed to read kernel log");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,25 @@
|
|||
#define LOG_HANDLER_H
|
||||
|
||||
typedef void (jetkvm_log_handler_t)(int level, const char *filename, const char *funcname, const int line, const char *message);
|
||||
|
||||
/**
|
||||
* @brief Log a message
|
||||
*
|
||||
* @param level The level of the message
|
||||
* @param filename The filename of the message
|
||||
* @param funcname The function name of the message
|
||||
* @param line The line number of the message
|
||||
* @param message The message to log
|
||||
* @return void
|
||||
*/
|
||||
void log_message(int level, const char *filename, const char *funcname, const int line, const char *message);
|
||||
|
||||
/**
|
||||
* @brief Set the log handler
|
||||
*
|
||||
* @param handler The handler to set
|
||||
* @return void
|
||||
*/
|
||||
void log_set_handler(jetkvm_log_handler_t *handler);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,251 @@
|
|||
diff --git a/env_support/cmake/os_desktop.cmake b/env_support/cmake/os_desktop.cmake
|
||||
index 5c6b05ed8..a18044d64 100644
|
||||
--- a/env_support/cmake/os_desktop.cmake
|
||||
+++ b/env_support/cmake/os_desktop.cmake
|
||||
@@ -60,8 +60,6 @@ get_directory_property(HAS_PARENT_SCOPE PARENT_DIRECTORY)
|
||||
# Set sources used for LVGL components
|
||||
file(GLOB_RECURSE SOURCES ${LVGL_ROOT_DIR}/src/*.c
|
||||
${LVGL_ROOT_DIR}/src/*.S)
|
||||
-file(GLOB_RECURSE EXAMPLE_SOURCES ${LVGL_ROOT_DIR}/examples/*.c)
|
||||
-file(GLOB_RECURSE DEMO_SOURCES ${LVGL_ROOT_DIR}/demos/*.c)
|
||||
file(GLOB_RECURSE THORVG_SOURCES ${LVGL_ROOT_DIR}/src/libs/thorvg/*.cpp
|
||||
${LVGL_ROOT_DIR}/src/others/vg_lite_tvg/*.cpp)
|
||||
|
||||
@@ -229,51 +227,6 @@ if(NOT (CMAKE_C_COMPILER_ID STREQUAL "MSVC"))
|
||||
PROPERTIES COMPILE_FLAGS -Wunused-parameter)
|
||||
endif()
|
||||
|
||||
-# Build LVGL example library
|
||||
-if(CONFIG_LV_BUILD_EXAMPLES)
|
||||
-
|
||||
- message(STATUS "Enabling the building of examples")
|
||||
-
|
||||
- add_library(lvgl_examples ${EXAMPLE_SOURCES})
|
||||
- add_library(lvgl::examples ALIAS lvgl_examples)
|
||||
- target_include_directories(lvgl_examples SYSTEM PUBLIC ${LVGL_ROOT_DIR}/examples)
|
||||
- set_target_properties(lvgl_examples PROPERTIES COMPILE_DEFINITIONS "${COMP_DEF}")
|
||||
-
|
||||
- # This tells cmake to link lvgl with lvgl_examples
|
||||
- # PUBLIC allows code linking with LVGL to also use the library
|
||||
- # The linker will resolve all dependencies when dynamic linking
|
||||
- target_link_libraries(lvgl PUBLIC lvgl_examples)
|
||||
-
|
||||
- # During static linking, we need to create a cyclic dependency as the examples also needs lvgl
|
||||
- if (NOT BUILD_SHARED_LIBS)
|
||||
- target_link_libraries(lvgl_examples PRIVATE lvgl)
|
||||
- endif()
|
||||
-
|
||||
-endif()
|
||||
-
|
||||
-# Build LVGL demos library
|
||||
-if(CONFIG_LV_BUILD_DEMOS)
|
||||
-
|
||||
- message(STATUS "Enabling the building of demos")
|
||||
-
|
||||
- add_library(lvgl_demos ${DEMO_SOURCES})
|
||||
- add_library(lvgl::demos ALIAS lvgl_demos)
|
||||
- target_include_directories(lvgl_demos SYSTEM PUBLIC ${LVGL_ROOT_DIR}/demos)
|
||||
- set_target_properties(lvgl_demos PROPERTIES COMPILE_DEFINITIONS "${COMP_DEF}")
|
||||
-
|
||||
- # This tells cmake to link lvgl with lvgl_examples
|
||||
- # PUBLIC allows code linking with LVGL to also use the library
|
||||
- # The linker will resolve all dependencies when dynamic linking
|
||||
- target_link_libraries(lvgl PUBLIC lvgl_demos)
|
||||
-
|
||||
- # During static linking, we need to create a cyclic dependency as the demos also needs lvgl
|
||||
- if (NOT BUILD_SHARED_LIBS)
|
||||
- # If static linking - demos depends on fonts defined in lvgl
|
||||
- # During dynamic linking, the linker is able to resolve everything
|
||||
- target_link_libraries(lvgl_demos PRIVATE lvgl)
|
||||
- endif()
|
||||
-
|
||||
-endif()
|
||||
|
||||
############################## INSTALLATION ######################################
|
||||
|
||||
@@ -373,58 +326,6 @@ if(CONFIG_LV_USE_THORVG_INTERNAL)
|
||||
|
||||
endif()
|
||||
|
||||
-if(CONFIG_LV_BUILD_DEMOS)
|
||||
-
|
||||
- install(
|
||||
- DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/demos"
|
||||
- DESTINATION "${INC_INSTALL_DIR}"
|
||||
- FILES_MATCHING
|
||||
- PATTERN "*.h")
|
||||
-
|
||||
- set_target_properties(
|
||||
- lvgl_demos
|
||||
- PROPERTIES OUTPUT_NAME lvgl_demos
|
||||
- VERSION ${LVGL_VERSION}
|
||||
- SOVERSION ${LVGL_SOVERSION}
|
||||
- ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib"
|
||||
- LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib"
|
||||
- PUBLIC_HEADER "${LVGL_PUBLIC_HEADERS}")
|
||||
-
|
||||
- install(
|
||||
- TARGETS lvgl_demos
|
||||
- ARCHIVE DESTINATION "${LIB_INSTALL_DIR}"
|
||||
- LIBRARY DESTINATION "${LIB_INSTALL_DIR}"
|
||||
- RUNTIME DESTINATION "${RUNTIME_INSTALL_DIR}"
|
||||
- PUBLIC_HEADER DESTINATION "${INC_INSTALL_DIR}")
|
||||
-
|
||||
-endif()
|
||||
-
|
||||
-if(CONFIG_LV_BUILD_EXAMPLES)
|
||||
-
|
||||
- install(
|
||||
- DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/examples"
|
||||
- DESTINATION "${INC_INSTALL_DIR}"
|
||||
- FILES_MATCHING
|
||||
- PATTERN "*.h")
|
||||
-
|
||||
- set_target_properties(
|
||||
- lvgl_examples
|
||||
- PROPERTIES OUTPUT_NAME lvgl_examples
|
||||
- VERSION ${LVGL_VERSION}
|
||||
- SOVERSION ${LVGL_SOVERSION}
|
||||
- ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib"
|
||||
- LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib"
|
||||
- PUBLIC_HEADER "${LVGL_PUBLIC_HEADERS}")
|
||||
-
|
||||
- install(
|
||||
- TARGETS lvgl_examples
|
||||
- ARCHIVE DESTINATION "${LIB_INSTALL_DIR}"
|
||||
- LIBRARY DESTINATION "${LIB_INSTALL_DIR}"
|
||||
- RUNTIME DESTINATION "${RUNTIME_INSTALL_DIR}"
|
||||
- PUBLIC_HEADER DESTINATION "${INC_INSTALL_DIR}")
|
||||
-
|
||||
-endif()
|
||||
-
|
||||
############################## SET GLOBAL VARIABLES ######################################
|
||||
|
||||
if (HAS_PARENT_SCOPE)
|
||||
diff --git a/src/font/lv_font.h b/src/font/lv_font.h
|
||||
index 180891832..b66c30eaa 100644
|
||||
--- a/src/font/lv_font.h
|
||||
+++ b/src/font/lv_font.h
|
||||
@@ -230,122 +230,10 @@ bool lv_font_has_static_bitmap(const lv_font_t * font);
|
||||
|
||||
#define LV_FONT_DECLARE(font_name) LV_ATTRIBUTE_EXTERN_DATA extern const lv_font_t font_name;
|
||||
|
||||
-#if LV_FONT_MONTSERRAT_8
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_8)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_10
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_10)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_12
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_12)
|
||||
-#endif
|
||||
-
|
||||
#if LV_FONT_MONTSERRAT_14
|
||||
LV_FONT_DECLARE(lv_font_montserrat_14)
|
||||
#endif
|
||||
|
||||
-#if LV_FONT_MONTSERRAT_16
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_16)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_18
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_18)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_20
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_20)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_22
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_22)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_24
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_24)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_26
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_26)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_28
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_28)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_30
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_30)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_32
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_32)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_34
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_34)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_36
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_36)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_38
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_38)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_40
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_40)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_42
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_42)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_44
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_44)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_46
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_46)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_48
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_48)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_28_COMPRESSED
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_28_compressed)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_DEJAVU_16_PERSIAN_HEBREW
|
||||
-LV_FONT_DECLARE(lv_font_dejavu_16_persian_hebrew)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_SIMSUN_14_CJK
|
||||
-LV_FONT_DECLARE(lv_font_simsun_14_cjk)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_SIMSUN_16_CJK
|
||||
-LV_FONT_DECLARE(lv_font_simsun_16_cjk)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_SOURCE_HAN_SANS_SC_14_CJK
|
||||
-LV_FONT_DECLARE(lv_font_source_han_sans_sc_14_cjk)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_SOURCE_HAN_SANS_SC_16_CJK
|
||||
-LV_FONT_DECLARE(lv_font_source_han_sans_sc_16_cjk)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_UNSCII_8
|
||||
-LV_FONT_DECLARE(lv_font_unscii_8)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_UNSCII_16
|
||||
-LV_FONT_DECLARE(lv_font_unscii_16)
|
||||
-#endif
|
||||
-
|
||||
/*Declare the custom (user defined) fonts*/
|
||||
#ifdef LV_FONT_CUSTOM_DECLARE
|
||||
LV_FONT_CUSTOM_DECLARE
|
||||
|
|
@ -1,207 +0,0 @@
|
|||
diff --git a/env_support/cmake/custom.cmake b/env_support/cmake/custom.cmake
|
||||
index 7da68124b..1fbe2d3de 100644
|
||||
--- a/env_support/cmake/custom.cmake
|
||||
+++ b/env_support/cmake/custom.cmake
|
||||
@@ -15,8 +15,6 @@ get_filename_component(LV_CONF_DIR ${LV_CONF_PATH} DIRECTORY)
|
||||
option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
|
||||
|
||||
file(GLOB_RECURSE SOURCES ${LVGL_ROOT_DIR}/src/*.c)
|
||||
-file(GLOB_RECURSE EXAMPLE_SOURCES ${LVGL_ROOT_DIR}/examples/*.c)
|
||||
-file(GLOB_RECURSE DEMO_SOURCES ${LVGL_ROOT_DIR}/demos/*.c)
|
||||
|
||||
if (BUILD_SHARED_LIBS)
|
||||
add_library(lvgl SHARED ${SOURCES})
|
||||
@@ -25,10 +23,6 @@ else()
|
||||
endif()
|
||||
|
||||
add_library(lvgl::lvgl ALIAS lvgl)
|
||||
-add_library(lvgl_examples STATIC ${EXAMPLE_SOURCES})
|
||||
-add_library(lvgl::examples ALIAS lvgl_examples)
|
||||
-add_library(lvgl_demos STATIC ${DEMO_SOURCES})
|
||||
-add_library(lvgl::demos ALIAS lvgl_demos)
|
||||
|
||||
target_compile_definitions(
|
||||
lvgl PUBLIC $<$<BOOL:${LV_LVGL_H_INCLUDE_SIMPLE}>:LV_LVGL_H_INCLUDE_SIMPLE>
|
||||
@@ -37,15 +31,6 @@ target_compile_definitions(
|
||||
# Include root and optional parent path of LV_CONF_PATH
|
||||
target_include_directories(lvgl SYSTEM PUBLIC ${LVGL_ROOT_DIR} ${LV_CONF_DIR})
|
||||
|
||||
-# Include /examples folder
|
||||
-target_include_directories(lvgl_examples SYSTEM
|
||||
- PUBLIC ${LVGL_ROOT_DIR}/examples)
|
||||
-target_include_directories(lvgl_demos SYSTEM
|
||||
- PUBLIC ${LVGL_ROOT_DIR}/demos)
|
||||
-
|
||||
-target_link_libraries(lvgl_examples PUBLIC lvgl)
|
||||
-target_link_libraries(lvgl_demos PUBLIC lvgl)
|
||||
-
|
||||
# Lbrary and headers can be installed to system using make install
|
||||
file(GLOB LVGL_PUBLIC_HEADERS "${CMAKE_SOURCE_DIR}/lv_conf.h"
|
||||
"${CMAKE_SOURCE_DIR}/lvgl.h")
|
||||
diff --git a/lvgl.mk b/lvgl.mk
|
||||
index 0ea126daa..300fb6cbe 100644
|
||||
--- a/lvgl.mk
|
||||
+++ b/lvgl.mk
|
||||
@@ -1,5 +1,3 @@
|
||||
-include $(LVGL_DIR)/$(LVGL_DIR_NAME)/demos/lv_demos.mk
|
||||
-include $(LVGL_DIR)/$(LVGL_DIR_NAME)/examples/lv_examples.mk
|
||||
include $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/core/lv_core.mk
|
||||
include $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/draw/lv_draw.mk
|
||||
include $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/extra/lv_extra.mk
|
||||
diff --git a/src/font/lv_font.h b/src/font/lv_font.h
|
||||
index e3b670c87..4cceffc45 100644
|
||||
--- a/src/font/lv_font.h
|
||||
+++ b/src/font/lv_font.h
|
||||
@@ -132,114 +132,10 @@ static inline lv_coord_t lv_font_get_line_height(const lv_font_t * font_p)
|
||||
|
||||
#define LV_FONT_DECLARE(font_name) extern const lv_font_t font_name;
|
||||
|
||||
-#if LV_FONT_MONTSERRAT_8
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_8)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_10
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_10)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_12
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_12)
|
||||
-#endif
|
||||
-
|
||||
#if LV_FONT_MONTSERRAT_14
|
||||
LV_FONT_DECLARE(lv_font_montserrat_14)
|
||||
#endif
|
||||
|
||||
-#if LV_FONT_MONTSERRAT_16
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_16)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_18
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_18)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_20
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_20)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_22
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_22)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_24
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_24)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_26
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_26)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_28
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_28)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_30
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_30)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_32
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_32)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_34
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_34)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_36
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_36)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_38
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_38)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_40
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_40)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_42
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_42)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_44
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_44)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_46
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_46)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_48
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_48)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_12_SUBPX
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_12_subpx)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_MONTSERRAT_28_COMPRESSED
|
||||
-LV_FONT_DECLARE(lv_font_montserrat_28_compressed)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_DEJAVU_16_PERSIAN_HEBREW
|
||||
-LV_FONT_DECLARE(lv_font_dejavu_16_persian_hebrew)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_SIMSUN_16_CJK
|
||||
-LV_FONT_DECLARE(lv_font_simsun_16_cjk)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_UNSCII_8
|
||||
-LV_FONT_DECLARE(lv_font_unscii_8)
|
||||
-#endif
|
||||
-
|
||||
-#if LV_FONT_UNSCII_16
|
||||
-LV_FONT_DECLARE(lv_font_unscii_16)
|
||||
-#endif
|
||||
-
|
||||
/*Declare the custom (user defined) fonts*/
|
||||
#ifdef LV_FONT_CUSTOM_DECLARE
|
||||
LV_FONT_CUSTOM_DECLARE
|
||||
diff --git a/src/font/lv_font.mk b/src/font/lv_font.mk
|
||||
index 2201b73f2..7b2707da4 100644
|
||||
--- a/src/font/lv_font.mk
|
||||
+++ b/src/font/lv_font.mk
|
||||
@@ -2,33 +2,7 @@ CSRCS += lv_font.c
|
||||
CSRCS += lv_font_fmt_txt.c
|
||||
CSRCS += lv_font_loader.c
|
||||
|
||||
-CSRCS += lv_font_dejavu_16_persian_hebrew.c
|
||||
-CSRCS += lv_font_montserrat_8.c
|
||||
-CSRCS += lv_font_montserrat_10.c
|
||||
-CSRCS += lv_font_montserrat_12.c
|
||||
-CSRCS += lv_font_montserrat_12_subpx.c
|
||||
CSRCS += lv_font_montserrat_14.c
|
||||
-CSRCS += lv_font_montserrat_16.c
|
||||
-CSRCS += lv_font_montserrat_18.c
|
||||
-CSRCS += lv_font_montserrat_20.c
|
||||
-CSRCS += lv_font_montserrat_22.c
|
||||
-CSRCS += lv_font_montserrat_24.c
|
||||
-CSRCS += lv_font_montserrat_26.c
|
||||
-CSRCS += lv_font_montserrat_28.c
|
||||
-CSRCS += lv_font_montserrat_28_compressed.c
|
||||
-CSRCS += lv_font_montserrat_30.c
|
||||
-CSRCS += lv_font_montserrat_32.c
|
||||
-CSRCS += lv_font_montserrat_34.c
|
||||
-CSRCS += lv_font_montserrat_36.c
|
||||
-CSRCS += lv_font_montserrat_38.c
|
||||
-CSRCS += lv_font_montserrat_40.c
|
||||
-CSRCS += lv_font_montserrat_42.c
|
||||
-CSRCS += lv_font_montserrat_44.c
|
||||
-CSRCS += lv_font_montserrat_46.c
|
||||
-CSRCS += lv_font_montserrat_48.c
|
||||
-CSRCS += lv_font_simsun_16_cjk.c
|
||||
-CSRCS += lv_font_unscii_8.c
|
||||
-CSRCS += lv_font_unscii_16.c
|
||||
|
||||
DEPPATH += --dep-path $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/font
|
||||
VPATH += :$(LVGL_DIR)/$(LVGL_DIR_NAME)/src/font
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
// #include "st7789/lcd.h"
|
||||
#include "ui/ui.h"
|
||||
#include "ui_index.h"
|
||||
#include "ctrl.h"
|
||||
|
||||
#define DISP_BUF_SIZE (300 * 240 * 2)
|
||||
static lv_color_t buf[DISP_BUF_SIZE];
|
||||
|
|
@ -32,8 +33,6 @@ void lvgl_init(u_int16_t rotation) {
|
|||
/*LittlevGL init*/
|
||||
lv_init();
|
||||
|
||||
/*Linux frame buffer device init*/
|
||||
|
||||
/*Linux frame buffer device init*/
|
||||
lv_display_t *disp = lv_linux_fbdev_create();
|
||||
// lv_display_set_physical_resolution(disp, 240, 300);
|
||||
|
|
@ -42,29 +41,6 @@ void lvgl_init(u_int16_t rotation) {
|
|||
|
||||
lvgl_set_rotation(disp, rotation);
|
||||
|
||||
// lv_display_t *disp = lv_st7789_create(LCD_H_RES, LCD_V_RES, LV_LCD_FLAG_NONE, lcd_send_cmd, lcd_send_color);
|
||||
// lv_display_set_resolution(disp, 240, 300);
|
||||
// lv_display_set_rotation(disp, LV_DISP_ROTATION_270);
|
||||
|
||||
// lv_color_t * buf1 = NULL;
|
||||
// lv_color_t * buf2 = NULL;
|
||||
|
||||
// uint32_t buf_size = LCD_H_RES * LCD_V_RES / 10 * lv_color_format_get_size(lv_display_get_color_format(disp));
|
||||
|
||||
// buf1 = lv_malloc(buf_size);
|
||||
// if(buf1 == NULL) {
|
||||
// log_error("display draw buffer malloc failed");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// buf2 = lv_malloc(buf_size);
|
||||
// if(buf2 == NULL) {
|
||||
// log_error("display buffer malloc failed");
|
||||
// lv_free(buf1);
|
||||
// return;
|
||||
// }
|
||||
// lv_display_set_buffers(disp, buf1, buf2, buf_size, LV_DISPLAY_RENDER_MODE_PARTIAL);
|
||||
|
||||
/* Linux input device init */
|
||||
lv_indev_t *mouse = lv_evdev_create(LV_INDEV_TYPE_POINTER, "/dev/input/event1");
|
||||
lv_indev_set_group(mouse, lv_group_get_default());
|
||||
|
|
@ -76,10 +52,9 @@ void lvgl_init(u_int16_t rotation) {
|
|||
|
||||
ui_init();
|
||||
|
||||
ui_set_rpc_handler((jetkvm_rpc_handler_t *)jetkvm_call_rpc_handler);
|
||||
|
||||
log_info("ui initalized");
|
||||
// lv_label_set_text(ui_Boot_Screen_Version, "");
|
||||
// lv_label_set_text(ui_Home_Content_Ip, "...");
|
||||
// lv_label_set_text(ui_Home_Header_Cloud_Status_Label, "0 active");
|
||||
}
|
||||
|
||||
void lvgl_tick(void) {
|
||||
|
|
@ -188,7 +163,7 @@ lv_img_dsc_t *ui_get_image(const char *name) {
|
|||
void ui_set_text(const char *name, const char *text) {
|
||||
lv_obj_t *obj = ui_get_obj(name);
|
||||
if(obj == NULL) {
|
||||
log_error("ui_set_text %s %s, obj not found\n", name, text);
|
||||
log_error("ui_set_text %s %s, obj not found", name, text);
|
||||
return;
|
||||
}
|
||||
lv_label_set_text(obj, text);
|
||||
|
|
|
|||
|
|
@ -12,10 +12,37 @@ void lvgl_tick(void);
|
|||
|
||||
void lvgl_set_rotation(lv_display_t *disp, u_int16_t rotation);
|
||||
|
||||
/**
|
||||
* @brief Set the text of an object
|
||||
*
|
||||
* @param name The name of the object
|
||||
* @param text The text to set
|
||||
* @return void
|
||||
*/
|
||||
void ui_set_text(const char *name, const char *text);
|
||||
|
||||
/**
|
||||
* @brief Get the object with the given name
|
||||
*
|
||||
* @param name The name of the object
|
||||
* @return lv_obj_t* The object with the given name
|
||||
*/
|
||||
lv_obj_t *ui_get_obj(const char *name);
|
||||
|
||||
/**
|
||||
* @brief Get the style with the given name
|
||||
*
|
||||
* @param name The name of the style
|
||||
* @return lv_style_t* The style with the given name
|
||||
*/
|
||||
lv_style_t *ui_get_style(const char *name);
|
||||
|
||||
/**
|
||||
* @brief Get the image with the given name
|
||||
*
|
||||
* @param name The name of the image
|
||||
* @return lv_img_dsc_t* The image with the given name
|
||||
*/
|
||||
lv_img_dsc_t *ui_get_image(const char *name);
|
||||
|
||||
#endif // SCREEN_H
|
||||
|
|
|
|||
|
|
@ -268,14 +268,14 @@ static void *venc_read_stream(void *arg)
|
|||
stFrame.pstPack = malloc(sizeof(VENC_PACK_S));
|
||||
while (venc_running)
|
||||
{
|
||||
// printf("RK_MPI_VENC_GetStream\n");
|
||||
log_trace("RK_MPI_VENC_GetStream");
|
||||
s32Ret = RK_MPI_VENC_GetStream(VENC_CHANNEL, &stFrame, 200); // blocks max 200ms
|
||||
if (s32Ret == RK_SUCCESS)
|
||||
{
|
||||
RK_U64 nowUs = get_us();
|
||||
// printf("chn:0, loopCount:%d enc->seq:%d wd:%d pts=%llu delay=%lldus\n",
|
||||
// loopCount, stFrame.u32Seq, stFrame.pstPack->u32Len,
|
||||
// stFrame.pstPack->u64PTS, nowUs - stFrame.pstPack->u64PTS);
|
||||
log_trace("chn:0, loopCount:%d enc->seq:%d wd:%d pts=%llu delay=%lldus",
|
||||
loopCount, stFrame.u32Seq, stFrame.pstPack->u32Len,
|
||||
stFrame.pstPack->u64PTS, nowUs - stFrame.pstPack->u64PTS);
|
||||
pData = RK_MPI_MB_Handle2VirAddr(stFrame.pstPack->pMbBlk);
|
||||
video_send_frame(pData, (ssize_t)stFrame.pstPack->u32Len);
|
||||
s32Ret = RK_MPI_VENC_ReleaseStream(VENC_CHANNEL, &stFrame);
|
||||
|
|
@ -304,6 +304,7 @@ uint32_t detected_width, detected_height;
|
|||
bool detected_signal = false, streaming_flag = false;
|
||||
|
||||
pthread_t *streaming_thread = NULL;
|
||||
pthread_mutex_t streaming_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
void write_buffer_to_file(const uint8_t *buffer, size_t length, const char *filename)
|
||||
{
|
||||
|
|
@ -322,7 +323,7 @@ void *run_video_stream(void *arg)
|
|||
{
|
||||
if (detected_signal == false)
|
||||
{
|
||||
usleep(100000);
|
||||
usleep(10000); // Reduced to 10ms for better responsiveness to streaming_flag changes
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -347,7 +348,7 @@ void *run_video_stream(void *arg)
|
|||
|
||||
if (ioctl(video_dev_fd, VIDIOC_S_FMT, &fmt) < 0)
|
||||
{
|
||||
perror("Set format fail");
|
||||
log_error("Set format fail: %s", strerror(errno));
|
||||
usleep(100000); // Sleep for 100 milliseconds
|
||||
close(video_dev_fd);
|
||||
continue;
|
||||
|
|
@ -362,7 +363,8 @@ void *run_video_stream(void *arg)
|
|||
|
||||
if (ioctl(video_dev_fd, VIDIOC_REQBUFS, &req) < 0)
|
||||
{
|
||||
perror("VIDIOC_REQBUFS failed");
|
||||
log_error("VIDIOC_REQBUFS failed: %s", strerror(errno));
|
||||
close(video_dev_fd);
|
||||
return errno;
|
||||
}
|
||||
log_info("VIDIOC_REQBUFS successful");
|
||||
|
|
@ -384,32 +386,35 @@ void *run_video_stream(void *arg)
|
|||
|
||||
if (-1 == ioctl(video_dev_fd, VIDIOC_QUERYBUF, &buf))
|
||||
{
|
||||
perror("VIDIOC_QUERYBUF failed");
|
||||
log_error("VIDIOC_QUERYBUF failed: %s", strerror(errno));
|
||||
req.count = i;
|
||||
close(video_dev_fd);
|
||||
return errno;
|
||||
}
|
||||
printf("VIDIOC_QUERYBUF successful for buffer %d\n", i);
|
||||
log_info("VIDIOC_QUERYBUF successful for buffer %d", i);
|
||||
|
||||
printf("plane: length = %d\n", planes_buffer->length);
|
||||
printf("plane: offset = %d\n", planes_buffer->m.mem_offset);
|
||||
log_info("plane: length = %d", planes_buffer->length);
|
||||
log_info("plane: offset = %d", planes_buffer->m.mem_offset);
|
||||
|
||||
MB_BLK blk = RK_MPI_MB_GetMB(memPool, (planes_buffer)->length, RK_TRUE);
|
||||
if (blk == NULL)
|
||||
{
|
||||
RK_LOGE("get mb blk failed!");
|
||||
log_error("get mb blk failed!");
|
||||
close(video_dev_fd);
|
||||
return -1;
|
||||
}
|
||||
printf("Got memory block for buffer %d\n", i);
|
||||
log_info("Got memory block for buffer %d", i);
|
||||
|
||||
buffers[i].mb_blk = blk;
|
||||
|
||||
RK_S32 buf_fd = (RK_MPI_MB_Handle2Fd(blk));
|
||||
if (buf_fd < 0)
|
||||
{
|
||||
RK_LOGE("RK_MPI_MB_Handle2Fd failed!");
|
||||
log_error("RK_MPI_MB_Handle2Fd failed!");
|
||||
close(video_dev_fd);
|
||||
return -1;
|
||||
}
|
||||
printf("Converted memory block to file descriptor for buffer %d\n", i);
|
||||
log_info("Converted memory block to file descriptor for buffer %d", i);
|
||||
planes_buffer->m.fd = buf_fd;
|
||||
}
|
||||
|
||||
|
|
@ -424,15 +429,16 @@ void *run_video_stream(void *arg)
|
|||
buf.m.planes = &buffers[i].plane_buffer;
|
||||
if (ioctl(video_dev_fd, VIDIOC_QBUF, &buf) < 0)
|
||||
{
|
||||
perror("VIDIOC_QBUF failed");
|
||||
log_error("VIDIOC_QBUF failed: %s", strerror(errno));
|
||||
close(video_dev_fd);
|
||||
return errno;
|
||||
}
|
||||
printf("VIDIOC_QBUF successful for buffer %d\n", i);
|
||||
log_info("VIDIOC_QBUF successful for buffer %d", i);
|
||||
}
|
||||
|
||||
if (ioctl(video_dev_fd, VIDIOC_STREAMON, &type) < 0)
|
||||
{
|
||||
perror("VIDIOC_STREAMON failed");
|
||||
log_error("VIDIOC_STREAMON failed: %s", strerror(errno));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
|
@ -463,7 +469,7 @@ void *run_video_stream(void *arg)
|
|||
r = select(video_dev_fd + 1, &fds, NULL, NULL, &tv);
|
||||
if (r == 0)
|
||||
{
|
||||
log_info("select timeout \n");
|
||||
log_info("select timeout");
|
||||
break;
|
||||
}
|
||||
if (r == -1)
|
||||
|
|
@ -472,7 +478,7 @@ void *run_video_stream(void *arg)
|
|||
{
|
||||
continue;
|
||||
}
|
||||
perror("select in video streaming");
|
||||
log_error("select in video streaming");
|
||||
break;
|
||||
}
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
|
|
@ -482,10 +488,10 @@ void *run_video_stream(void *arg)
|
|||
buf.length = 1;
|
||||
if (ioctl(video_dev_fd, VIDIOC_DQBUF, &buf) < 0)
|
||||
{
|
||||
perror("VIDIOC_DQBUF failed");
|
||||
log_error("VIDIOC_DQBUF failed: %s", strerror(errno));
|
||||
break;
|
||||
}
|
||||
// printf("got frame, bytesused = %d\n", tmp_plane.bytesused);
|
||||
log_trace("got frame, bytesused = %d", tmp_plane.bytesused);
|
||||
memset(&stFrame, 0, sizeof(VIDEO_FRAME_INFO_S));
|
||||
MB_BLK blk = RK_NULL;
|
||||
blk = RK_MPI_MMZ_Fd2Handle(tmp_plane.m.fd);
|
||||
|
|
@ -503,26 +509,16 @@ void *run_video_stream(void *arg)
|
|||
stFrame.stVFrame.u32FrameFlag |= 0;
|
||||
stFrame.stVFrame.enCompressMode = COMPRESS_MODE_NONE;
|
||||
bool retried = false;
|
||||
// if (num == 100) {
|
||||
// RK_VOID *pData = RK_MPI_MB_Handle2VirAddr(stFrame.stVFrame.pMbBlk);
|
||||
// if (pData) {
|
||||
// size_t frameSize = tmp_plane.bytesused; // Use the actual size reported by the driver
|
||||
// write_buffer_to_file(pData, frameSize, "/userdata/banana.raw");
|
||||
// printf("Frame 100 written to /userdata/banana.raw\n");
|
||||
// } else {
|
||||
// printf("Failed to get virtual address for frame 100\n");
|
||||
// }
|
||||
// }
|
||||
retry_send_frame:
|
||||
if (RK_MPI_VENC_SendFrame(VENC_CHANNEL, &stFrame, 2000) != RK_SUCCESS)
|
||||
{
|
||||
if (retried == true)
|
||||
{
|
||||
RK_LOGE("RK_MPI_VENC_SendFrame retry failed");
|
||||
log_error("RK_MPI_VENC_SendFrame retry failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
RK_LOGE("RK_MPI_VENC_SendFrame failed,retrying");
|
||||
log_error("RK_MPI_VENC_SendFrame failed,retrying");
|
||||
retried = true;
|
||||
usleep(1000llu);
|
||||
goto retry_send_frame;
|
||||
|
|
@ -532,12 +528,13 @@ void *run_video_stream(void *arg)
|
|||
num++;
|
||||
|
||||
if (ioctl(video_dev_fd, VIDIOC_QBUF, &buf) < 0)
|
||||
printf("failture VIDIOC_QBUF\n");
|
||||
log_error("failure VIDIOC_QBUF: %s", strerror(errno));
|
||||
}
|
||||
cleanup:
|
||||
log_info("cleaning up video capture device %s", VIDEO_DEV);
|
||||
if (ioctl(video_dev_fd, VIDIOC_STREAMOFF, &type) < 0)
|
||||
{
|
||||
perror("VIDIOC_STREAMOFF failed");
|
||||
log_error("VIDIOC_STREAMOFF failed: %s", strerror(errno));
|
||||
}
|
||||
|
||||
venc_stop();
|
||||
|
|
@ -550,9 +547,11 @@ void *run_video_stream(void *arg)
|
|||
}
|
||||
}
|
||||
|
||||
log_info("closing video capture device %s", VIDEO_DEV);
|
||||
close(video_dev_fd);
|
||||
}
|
||||
|
||||
log_info("video stream thread exiting");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -560,65 +559,78 @@ void video_shutdown()
|
|||
{
|
||||
if (should_exit == true)
|
||||
{
|
||||
printf("shutting down in progress already\n");
|
||||
log_info("shutting down in progress already");
|
||||
return;
|
||||
}
|
||||
video_stop_streaming();
|
||||
// if (buffers != NULL) {
|
||||
// for (int i = 0; i < input_buffer_count; i++) {
|
||||
// if ((buffers + i)->mb_blk != NULL) {
|
||||
// RK_MPI_MB_ReleaseMB((buffers + i)->mb_blk);
|
||||
// }
|
||||
// free((buffers + i)->planes_buffer);
|
||||
// }
|
||||
// free(buffers);
|
||||
// }
|
||||
|
||||
should_exit = true;
|
||||
if (sub_dev_fd > 0)
|
||||
{
|
||||
shutdown(sub_dev_fd, SHUT_RDWR);
|
||||
// close(sub_dev_fd);
|
||||
printf("Closed sub_dev_fd\n");
|
||||
log_info("Closed sub_dev_fd");
|
||||
}
|
||||
|
||||
if (memPool != MB_INVALID_POOLID)
|
||||
{
|
||||
RK_MPI_MB_DestroyPool(memPool);
|
||||
}
|
||||
printf("Destroyed memory pool\n");
|
||||
// if (format_thread != NULL) {
|
||||
// pthread_join(*format_thread, NULL);
|
||||
// free(format_thread);
|
||||
// format_thread = NULL;
|
||||
// }
|
||||
// printf("Joined format detection thread\n");
|
||||
log_info("Destroyed memory pool");
|
||||
|
||||
pthread_mutex_destroy(&streaming_mutex);
|
||||
log_info("Destroyed streaming mutex");
|
||||
}
|
||||
|
||||
// TODO: mutex?
|
||||
|
||||
void video_start_streaming()
|
||||
{
|
||||
pthread_mutex_lock(&streaming_mutex);
|
||||
if (streaming_thread != NULL)
|
||||
{
|
||||
log_info("video streaming already started");
|
||||
return;
|
||||
log_warn("video streaming already started");
|
||||
goto cleanup;
|
||||
}
|
||||
streaming_thread = malloc(sizeof(pthread_t));
|
||||
assert(streaming_thread != NULL);
|
||||
|
||||
pthread_t *new_thread = malloc(sizeof(pthread_t));
|
||||
if (new_thread == NULL)
|
||||
{
|
||||
log_error("Failed to allocate memory for streaming thread");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
streaming_flag = true;
|
||||
pthread_create(streaming_thread, NULL, run_video_stream, NULL);
|
||||
int result = pthread_create(new_thread, NULL, run_video_stream, NULL);
|
||||
if (result != 0)
|
||||
{
|
||||
log_error("Failed to create streaming thread: %s", strerror(result));
|
||||
streaming_flag = false;
|
||||
free(new_thread);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Only set streaming_thread after successful creation, and before unlocking the mutex
|
||||
streaming_thread = new_thread;
|
||||
cleanup:
|
||||
pthread_mutex_unlock(&streaming_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
void video_stop_streaming()
|
||||
{
|
||||
pthread_mutex_lock(&streaming_mutex);
|
||||
if (streaming_thread != NULL)
|
||||
{
|
||||
streaming_flag = false;
|
||||
log_info("stopping video streaming");
|
||||
// wait 100ms for the thread to exit
|
||||
usleep(1000000);
|
||||
log_info("waiting for video streaming thread to exit");
|
||||
pthread_join(*streaming_thread, NULL);
|
||||
free(streaming_thread);
|
||||
streaming_thread = NULL;
|
||||
log_info("video streaming stopped");
|
||||
}
|
||||
pthread_mutex_unlock(&streaming_mutex);
|
||||
}
|
||||
|
||||
void *run_detect_format(void *arg)
|
||||
|
|
@ -632,7 +644,6 @@ void *run_detect_format(void *arg)
|
|||
if (ioctl(sub_dev_fd, VIDIOC_SUBSCRIBE_EVENT, &sub) == -1)
|
||||
{
|
||||
log_error("cannot subscribe to event");
|
||||
perror("Cannot subscribe to event");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
|
@ -657,12 +668,12 @@ void *run_detect_format(void *arg)
|
|||
else if (errno == ERANGE)
|
||||
{
|
||||
// Timings were found, but they are out of range of the hardware capabilities.
|
||||
printf("HDMI status: out of range\n");
|
||||
log_warn("HDMI status: out of range");
|
||||
video_report_format(false, "out_of_range", 0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
perror("error VIDIOC_QUERY_DV_TIMINGS");
|
||||
log_error("error VIDIOC_QUERY_DV_TIMINGS: %s", strerror(errno));
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -681,19 +692,24 @@ void *run_detect_format(void *arg)
|
|||
detected_height = dv_timings.bt.height;
|
||||
detected_signal = true;
|
||||
video_report_format(true, NULL, detected_width, detected_height, frames_per_second);
|
||||
pthread_mutex_lock(&streaming_mutex);
|
||||
if (streaming_flag == true)
|
||||
{
|
||||
pthread_mutex_unlock(&streaming_mutex);
|
||||
log_info("restarting on going video streaming");
|
||||
video_stop_streaming();
|
||||
video_start_streaming();
|
||||
}
|
||||
else
|
||||
{
|
||||
pthread_mutex_unlock(&streaming_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
if (ioctl(sub_dev_fd, VIDIOC_DQEVENT, &ev) != 0)
|
||||
{
|
||||
log_error("failed to VIDIOC_DQEVENT");
|
||||
perror("failed to VIDIOC_DQEVENT");
|
||||
log_error("failed to VIDIOC_DQEVENT: %s", strerror(errno));
|
||||
break;
|
||||
}
|
||||
log_info("New event of type %u", ev.type);
|
||||
|
|
@ -715,12 +731,18 @@ void video_set_quality_factor(float factor)
|
|||
|
||||
// TODO: update venc bitrate without stopping streaming
|
||||
|
||||
pthread_mutex_lock(&streaming_mutex);
|
||||
if (streaming_flag == true)
|
||||
{
|
||||
pthread_mutex_unlock(&streaming_mutex);
|
||||
log_info("restarting on going video streaming due to quality factor change");
|
||||
video_stop_streaming();
|
||||
video_start_streaming();
|
||||
}
|
||||
else
|
||||
{
|
||||
pthread_mutex_unlock(&streaming_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
float video_get_quality_factor() {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,48 @@
|
|||
#ifndef VIDEO_DAEMON_VIDEO_H
|
||||
#define VIDEO_DAEMON_VIDEO_H
|
||||
|
||||
/**
|
||||
* @brief Initialize the video subsystem
|
||||
*
|
||||
* @return int 0 on success, -1 on failure
|
||||
*/
|
||||
int video_init();
|
||||
|
||||
/**
|
||||
* @brief Shutdown the video subsystem
|
||||
*/
|
||||
void video_shutdown();
|
||||
|
||||
/**
|
||||
* @brief Run the detect format thread
|
||||
*
|
||||
* @param arg The argument to pass to the thread
|
||||
* @return void* The result of the thread
|
||||
*/
|
||||
void *run_detect_format(void *arg);
|
||||
|
||||
/**
|
||||
* @brief Start the video streaming
|
||||
*/
|
||||
void video_start_streaming();
|
||||
|
||||
/**
|
||||
* @brief Stop the video streaming
|
||||
*/
|
||||
void video_stop_streaming();
|
||||
|
||||
/**
|
||||
* @brief Set the quality factor of the video
|
||||
*
|
||||
* @param factor The quality factor to set
|
||||
*/
|
||||
void video_set_quality_factor(float factor);
|
||||
|
||||
/**
|
||||
* @brief Get the quality factor of the video
|
||||
*
|
||||
* @return float The quality factor of the video
|
||||
*/
|
||||
float video_get_quality_factor();
|
||||
|
||||
#endif //VIDEO_DAEMON_VIDEO_H
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ package native
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
|
|
@ -37,9 +38,16 @@ extern void jetkvm_go_indev_handler(int code);
|
|||
static inline void jetkvm_cgo_setup_indev_handler() {
|
||||
jetkvm_set_indev_handler(&jetkvm_go_indev_handler);
|
||||
}
|
||||
|
||||
extern void jetkvm_go_rpc_handler(cchar_t *method, cchar_t *params);
|
||||
static inline void jetkvm_cgo_setup_rpc_handler() {
|
||||
jetkvm_set_rpc_handler(&jetkvm_go_rpc_handler);
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
var cgoLock sync.Mutex
|
||||
|
||||
//export jetkvm_go_video_state_handler
|
||||
func jetkvm_go_video_state_handler(state *C.jetkvm_video_state_t) {
|
||||
videoState := VideoState{
|
||||
|
|
@ -75,6 +83,11 @@ func jetkvm_go_indev_handler(code C.int) {
|
|||
indevEventChan <- int(code)
|
||||
}
|
||||
|
||||
//export jetkvm_go_rpc_handler
|
||||
func jetkvm_go_rpc_handler(method *C.cchar_t, params *C.cchar_t) {
|
||||
rpcEventChan <- C.GoString(method)
|
||||
}
|
||||
|
||||
var eventCodeToNameMap = map[int]string{}
|
||||
|
||||
func uiEventCodeToName(code int) string {
|
||||
|
|
@ -90,13 +103,20 @@ func uiEventCodeToName(code int) string {
|
|||
}
|
||||
|
||||
func setUpNativeHandlers() {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
C.jetkvm_cgo_setup_log_handler()
|
||||
C.jetkvm_cgo_setup_video_state_handler()
|
||||
C.jetkvm_cgo_setup_video_handler()
|
||||
C.jetkvm_cgo_setup_indev_handler()
|
||||
C.jetkvm_cgo_setup_rpc_handler()
|
||||
}
|
||||
|
||||
func uiInit(rotation uint16) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
cRotation := C.u_int16_t(rotation)
|
||||
defer C.free(unsafe.Pointer(&cRotation))
|
||||
|
||||
|
|
@ -104,10 +124,16 @@ func uiInit(rotation uint16) {
|
|||
}
|
||||
|
||||
func uiTick() {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
C.jetkvm_ui_tick()
|
||||
}
|
||||
|
||||
func videoInit() error {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
ret := C.jetkvm_video_init()
|
||||
if ret != 0 {
|
||||
return fmt.Errorf("failed to initialize video: %d", ret)
|
||||
|
|
@ -116,18 +142,40 @@ func videoInit() error {
|
|||
}
|
||||
|
||||
func videoShutdown() {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
C.jetkvm_video_shutdown()
|
||||
}
|
||||
|
||||
func videoStart() {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
C.jetkvm_video_start()
|
||||
}
|
||||
|
||||
func videoStop() {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
C.jetkvm_video_stop()
|
||||
}
|
||||
|
||||
func videoLogStatus() string {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
logStatus := C.jetkvm_video_log_status()
|
||||
defer C.free(unsafe.Pointer(logStatus))
|
||||
|
||||
return C.GoString(logStatus)
|
||||
}
|
||||
|
||||
func uiSetVar(name string, value string) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
nameCStr := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(nameCStr))
|
||||
|
||||
|
|
@ -138,6 +186,9 @@ func uiSetVar(name string, value string) {
|
|||
}
|
||||
|
||||
func uiGetVar(name string) string {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
nameCStr := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(nameCStr))
|
||||
|
||||
|
|
@ -145,31 +196,58 @@ func uiGetVar(name string) string {
|
|||
}
|
||||
|
||||
func uiSwitchToScreen(screen string) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
screenCStr := C.CString(screen)
|
||||
defer C.free(unsafe.Pointer(screenCStr))
|
||||
C.jetkvm_ui_load_screen(screenCStr)
|
||||
}
|
||||
|
||||
func uiGetCurrentScreen() string {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
screenCStr := C.jetkvm_ui_get_current_screen()
|
||||
return C.GoString(screenCStr)
|
||||
}
|
||||
|
||||
func uiObjSetState(objName string, state string) (bool, error) {
|
||||
func uiObjAddState(objName string, state string) (bool, error) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
objNameCStr := C.CString(objName)
|
||||
defer C.free(unsafe.Pointer(objNameCStr))
|
||||
stateCStr := C.CString(state)
|
||||
defer C.free(unsafe.Pointer(stateCStr))
|
||||
C.jetkvm_ui_set_state(objNameCStr, stateCStr)
|
||||
C.jetkvm_ui_add_state(objNameCStr, stateCStr)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func uiObjClearState(objName string, state string) (bool, error) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
objNameCStr := C.CString(objName)
|
||||
defer C.free(unsafe.Pointer(objNameCStr))
|
||||
stateCStr := C.CString(state)
|
||||
defer C.free(unsafe.Pointer(stateCStr))
|
||||
C.jetkvm_ui_clear_state(objNameCStr, stateCStr)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func uiGetLVGLVersion() string {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
return C.GoString(C.jetkvm_ui_get_lvgl_version())
|
||||
}
|
||||
|
||||
// TODO: use Enum instead of string but it's not a hot path and performance is not a concern now
|
||||
func uiObjAddFlag(objName string, flag string) (bool, error) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
objNameCStr := C.CString(objName)
|
||||
defer C.free(unsafe.Pointer(objNameCStr))
|
||||
flagCStr := C.CString(flag)
|
||||
|
|
@ -179,6 +257,9 @@ func uiObjAddFlag(objName string, flag string) (bool, error) {
|
|||
}
|
||||
|
||||
func uiObjClearFlag(objName string, flag string) (bool, error) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
objNameCStr := C.CString(objName)
|
||||
defer C.free(unsafe.Pointer(objNameCStr))
|
||||
flagCStr := C.CString(flag)
|
||||
|
|
@ -196,6 +277,9 @@ func uiObjShow(objName string) (bool, error) {
|
|||
}
|
||||
|
||||
func uiObjSetOpacity(objName string, opacity int) (bool, error) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
objNameCStr := C.CString(objName)
|
||||
defer C.free(unsafe.Pointer(objNameCStr))
|
||||
|
||||
|
|
@ -204,6 +288,9 @@ func uiObjSetOpacity(objName string, opacity int) (bool, error) {
|
|||
}
|
||||
|
||||
func uiObjFadeIn(objName string, duration uint32) (bool, error) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
objNameCStr := C.CString(objName)
|
||||
defer C.free(unsafe.Pointer(objNameCStr))
|
||||
|
||||
|
|
@ -213,6 +300,9 @@ func uiObjFadeIn(objName string, duration uint32) (bool, error) {
|
|||
}
|
||||
|
||||
func uiObjFadeOut(objName string, duration uint32) (bool, error) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
objNameCStr := C.CString(objName)
|
||||
defer C.free(unsafe.Pointer(objNameCStr))
|
||||
|
||||
|
|
@ -222,6 +312,9 @@ func uiObjFadeOut(objName string, duration uint32) (bool, error) {
|
|||
}
|
||||
|
||||
func uiLabelSetText(objName string, text string) (bool, error) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
objNameCStr := C.CString(objName)
|
||||
defer C.free(unsafe.Pointer(objNameCStr))
|
||||
|
||||
|
|
@ -236,6 +329,9 @@ func uiLabelSetText(objName string, text string) (bool, error) {
|
|||
}
|
||||
|
||||
func uiImgSetSrc(objName string, src string) (bool, error) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
objNameCStr := C.CString(objName)
|
||||
defer C.free(unsafe.Pointer(objNameCStr))
|
||||
|
||||
|
|
@ -248,6 +344,9 @@ func uiImgSetSrc(objName string, src string) (bool, error) {
|
|||
}
|
||||
|
||||
func uiDispSetRotation(rotation uint16) (bool, error) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
nativeLogger.Info().Uint16("rotation", rotation).Msg("setting rotation")
|
||||
|
||||
cRotation := C.u_int16_t(rotation)
|
||||
|
|
@ -258,21 +357,33 @@ func uiDispSetRotation(rotation uint16) (bool, error) {
|
|||
}
|
||||
|
||||
func videoGetStreamQualityFactor() (float64, error) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
factor := C.jetkvm_video_get_quality_factor()
|
||||
return float64(factor), nil
|
||||
}
|
||||
|
||||
func videoSetStreamQualityFactor(factor float64) error {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
C.jetkvm_video_set_quality_factor(C.float(factor))
|
||||
return nil
|
||||
}
|
||||
|
||||
func videoGetEDID() (string, error) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
edidCStr := C.jetkvm_video_get_edid_hex()
|
||||
return C.GoString(edidCStr), nil
|
||||
}
|
||||
|
||||
func videoSetEDID(edid string) error {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
edidCStr := C.CString(edid)
|
||||
defer C.free(unsafe.Pointer(edidCStr))
|
||||
C.jetkvm_video_set_edid(edidCStr)
|
||||
|
|
|
|||
|
|
@ -28,7 +28,12 @@ func uiGetCurrentScreen() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func uiObjSetState(objName string, state string) (bool, error) {
|
||||
func uiObjAddState(objName string, state string) (bool, error) {
|
||||
panicPlatformNotSupported()
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func uiObjClearState(objName string, state string) (bool, error) {
|
||||
panicPlatformNotSupported()
|
||||
return false, nil
|
||||
}
|
||||
|
|
@ -103,6 +108,11 @@ func videoSetStreamQualityFactor(factor float64) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func videoLogStatus() string {
|
||||
panicPlatformNotSupported()
|
||||
return ""
|
||||
}
|
||||
|
||||
func videoGetEDID() (string, error) {
|
||||
panicPlatformNotSupported()
|
||||
return "", nil
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ var (
|
|||
videoStateChan chan VideoState = make(chan VideoState)
|
||||
logChan chan nativeLogMessage = make(chan nativeLogMessage)
|
||||
indevEventChan chan int = make(chan int)
|
||||
rpcEventChan chan string = make(chan string)
|
||||
)
|
||||
|
||||
func (n *Native) handleVideoFrameChan() {
|
||||
|
|
@ -70,3 +71,10 @@ func (n *Native) handleIndevEventChan() {
|
|||
n.onIndevEvent(name)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Native) handleRpcEventChan() {
|
||||
for {
|
||||
event := <-rpcEventChan
|
||||
n.onRpcEvent(event)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,9 +37,24 @@ func (n *Native) UIObjShow(objName string) (bool, error) {
|
|||
return uiObjShow(objName)
|
||||
}
|
||||
|
||||
// UIObjSetState clears the state then adds the new state
|
||||
func (n *Native) UIObjSetState(objName string, state string) (bool, error) {
|
||||
return uiObjSetState(objName, state)
|
||||
// UISetVar sets the variable
|
||||
func (n *Native) UISetVar(name string, value string) {
|
||||
uiSetVar(name, value)
|
||||
}
|
||||
|
||||
// UIGetVar gets the variable
|
||||
func (n *Native) UIGetVar(name string) string {
|
||||
return uiGetVar(name)
|
||||
}
|
||||
|
||||
// UIObjAddState adds the state to the object
|
||||
func (n *Native) UIObjAddState(objName string, state string) (bool, error) {
|
||||
return uiObjAddState(objName, state)
|
||||
}
|
||||
|
||||
// UIObjClearState clears the state from the object
|
||||
func (n *Native) UIObjClearState(objName string, state string) (bool, error) {
|
||||
return uiObjClearState(objName, state)
|
||||
}
|
||||
|
||||
// UIObjAddFlag adds the flag to the object
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"navigation": {
|
||||
"selectedUserPageObject": "[jetkvm.eez-project]:/userPages/5",
|
||||
"selectedActionObject": "[jetkvm.eez-project]:/actions/0",
|
||||
"selectedUserPageObject": "[jetkvm.eez-project]:/userPages/8",
|
||||
"selectedActionObject": "[jetkvm.eez-project]:/actions/12",
|
||||
"selectedGlobalVariableObject": "[jetkvm.eez-project]:/variables/globalVariables/1",
|
||||
"selectedStyleObject": "[jetkvm.eez-project]:/lvglStyles/styles/0",
|
||||
"selectedStyleObject": "[jetkvm.eez-project]:/lvglStyles/styles/8",
|
||||
"selectedThemeObject": "[jetkvm.eez-project]:/themes/0",
|
||||
"selectedFontObject": "[jetkvm.eez-project]:/fonts/4",
|
||||
"selectedBitmapObject": "[jetkvm.eez-project]:/bitmaps/11",
|
||||
"selectedBitmapObject": "[jetkvm.eez-project]:/bitmaps/9",
|
||||
"subnavigationSelectedItems": {
|
||||
"variables-tab/sub-navigation/selected-item": "Global"
|
||||
}
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
{
|
||||
"type": "border",
|
||||
"selected": 2,
|
||||
"size": 113.5,
|
||||
"size": 271.5,
|
||||
"location": "right",
|
||||
"children": [
|
||||
{
|
||||
|
|
@ -77,7 +77,7 @@
|
|||
},
|
||||
{
|
||||
"type": "border",
|
||||
"selected": 1,
|
||||
"selected": 0,
|
||||
"location": "bottom",
|
||||
"children": [
|
||||
{
|
||||
|
|
@ -188,38 +188,48 @@
|
|||
"enableClose": false,
|
||||
"icon": "svg:variable"
|
||||
}
|
||||
],
|
||||
"active": true
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "tabset",
|
||||
"id": "EDITORS",
|
||||
"weight": 49.31058517127421,
|
||||
"selected": 4,
|
||||
"weight": 52.479136828866125,
|
||||
"selected": 5,
|
||||
"enableDeleteWhenEmpty": false,
|
||||
"enableClose": false,
|
||||
"children": [
|
||||
{
|
||||
"type": "tab",
|
||||
"id": "#aec56ae8-5b75-4a2f-ad81-f0d7d683c77a",
|
||||
"name": "FontBook24",
|
||||
"id": "#2b774476-9ef3-4363-83f8-8b478f163b02",
|
||||
"name": "MenuAdvancedScreen",
|
||||
"component": "editor",
|
||||
"config": {
|
||||
"objectPath": "[jetkvm.eez-project]:/fonts/4",
|
||||
"objectPath": "[jetkvm.eez-project]:/userPages/4",
|
||||
"permanent": false
|
||||
},
|
||||
"icon": "material:font_download"
|
||||
"icon": "svg:page"
|
||||
},
|
||||
{
|
||||
"type": "tab",
|
||||
"id": "#7bbd8382-ea41-467d-8ad3-4312a2d47266",
|
||||
"name": "ResetConfigScreen",
|
||||
"component": "editor",
|
||||
"config": {
|
||||
"objectPath": "[jetkvm.eez-project]:/userPages/8",
|
||||
"permanent": true
|
||||
},
|
||||
"icon": "svg:page"
|
||||
},
|
||||
{
|
||||
"type": "tab",
|
||||
"id": "#c8dece00-e490-46b8-8a14-5dcfa8bbce36",
|
||||
"name": "AboutScreen",
|
||||
"name": "StatusScreen",
|
||||
"component": "editor",
|
||||
"config": {
|
||||
"objectPath": "[jetkvm.eez-project]:/userPages/5",
|
||||
"permanent": false
|
||||
"objectPath": "[jetkvm.eez-project]:/userPages/7",
|
||||
"permanent": true
|
||||
},
|
||||
"icon": "svg:page"
|
||||
},
|
||||
|
|
@ -237,7 +247,7 @@
|
|||
{
|
||||
"type": "tab",
|
||||
"id": "#f5a057a5-977c-46be-8702-5447d603a34f",
|
||||
"name": "MenuScreen",
|
||||
"name": "HomeScreen",
|
||||
"component": "editor",
|
||||
"config": {
|
||||
"objectPath": "[jetkvm.eez-project]:/userPages/2",
|
||||
|
|
@ -257,12 +267,13 @@
|
|||
},
|
||||
"icon": "material:settings"
|
||||
}
|
||||
]
|
||||
],
|
||||
"active": true
|
||||
},
|
||||
{
|
||||
"type": "row",
|
||||
"id": "#ee319cf9-6145-49e4-b40e-1d999be897c8",
|
||||
"weight": 24.95234430353635,
|
||||
"weight": 21.78379264594443,
|
||||
"children": [
|
||||
{
|
||||
"type": "tabset",
|
||||
|
|
@ -1065,8 +1076,7 @@
|
|||
"0": {
|
||||
"0": {
|
||||
"0": {
|
||||
"1": {},
|
||||
"$selected": true
|
||||
"1": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1086,11 +1096,58 @@
|
|||
}
|
||||
},
|
||||
"[jetkvm.eez-project]:/userPages/1[flow-state]": {
|
||||
"selection": {
|
||||
"0": {
|
||||
"0": {
|
||||
"0": {},
|
||||
"1": {},
|
||||
"$selected": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"transform": {
|
||||
"translate": {
|
||||
"x": -180,
|
||||
"y": -207
|
||||
},
|
||||
"scale": 1
|
||||
},
|
||||
"timeline": {
|
||||
"isEditorActive": false,
|
||||
"position": 0,
|
||||
"secondToPx": 200,
|
||||
"scrollLeft": 0
|
||||
}
|
||||
},
|
||||
"[jetkvm.eez-project]:/lvglStyles/styles[tree-state]": {
|
||||
"0": {},
|
||||
"1": {},
|
||||
"2": {},
|
||||
"3": {},
|
||||
"4": {
|
||||
"$selected": true
|
||||
},
|
||||
"5": {
|
||||
"$selected": true
|
||||
},
|
||||
"6": {
|
||||
"$selected": true
|
||||
},
|
||||
"7": {
|
||||
"$selected": true
|
||||
},
|
||||
"8": {
|
||||
"$selected": true
|
||||
}
|
||||
},
|
||||
"[jetkvm.eez-project]:/userPages/2[flow-state]": {
|
||||
"selection": {
|
||||
"0": {
|
||||
"0": {
|
||||
"0": {
|
||||
"0": {},
|
||||
"0": {
|
||||
"$selected": true
|
||||
},
|
||||
"1": {
|
||||
"0": {}
|
||||
}
|
||||
|
|
@ -1102,9 +1159,7 @@
|
|||
"3": {
|
||||
"0": {
|
||||
"0": {},
|
||||
"1": {
|
||||
"$selected": true
|
||||
}
|
||||
"1": {}
|
||||
},
|
||||
"1": {
|
||||
"0": {},
|
||||
|
|
@ -1128,12 +1183,7 @@
|
|||
"scrollLeft": 0
|
||||
}
|
||||
},
|
||||
"[jetkvm.eez-project]:/lvglStyles/styles[tree-state]": {
|
||||
"0": {
|
||||
"$selected": true
|
||||
}
|
||||
},
|
||||
"[jetkvm.eez-project]:/userPages/2[flow-state]": {
|
||||
"[jetkvm.eez-project]:/userPages/3[flow-state]": {
|
||||
"selection": {
|
||||
"0": {
|
||||
"0": {
|
||||
|
|
@ -1142,13 +1192,14 @@
|
|||
},
|
||||
"1": {
|
||||
"0": {
|
||||
"0": {},
|
||||
"0": {
|
||||
"$selected": true
|
||||
},
|
||||
"1": {},
|
||||
"2": {},
|
||||
"3": {},
|
||||
"4": {
|
||||
"0": {},
|
||||
"$selected": true
|
||||
"0": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1169,19 +1220,15 @@
|
|||
"scrollLeft": 0
|
||||
}
|
||||
},
|
||||
"[jetkvm.eez-project]:/userPages/3[flow-state]": {
|
||||
"[jetkvm.eez-project]:/userPages/4[flow-state]": {
|
||||
"selection": {
|
||||
"0": {
|
||||
"0": {
|
||||
"0": {
|
||||
"0": {},
|
||||
"$selected": true
|
||||
"0": {}
|
||||
},
|
||||
"1": {
|
||||
"0": {
|
||||
"0": {},
|
||||
"1": {},
|
||||
"2": {},
|
||||
"3": {}
|
||||
}
|
||||
}
|
||||
|
|
@ -1190,41 +1237,8 @@
|
|||
},
|
||||
"transform": {
|
||||
"translate": {
|
||||
"x": -150,
|
||||
"y": -120
|
||||
},
|
||||
"scale": 1
|
||||
},
|
||||
"timeline": {
|
||||
"isEditorActive": false,
|
||||
"position": 0,
|
||||
"secondToPx": 200,
|
||||
"scrollLeft": 0
|
||||
}
|
||||
},
|
||||
"[jetkvm.eez-project]:/userPages/4[flow-state]": {
|
||||
"selection": {
|
||||
"0": {
|
||||
"0": {
|
||||
"0": {
|
||||
"0": {
|
||||
"$selected": true
|
||||
}
|
||||
},
|
||||
"1": {
|
||||
"0": {
|
||||
"0": {},
|
||||
"1": {},
|
||||
"2": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"transform": {
|
||||
"translate": {
|
||||
"x": -176,
|
||||
"y": -127
|
||||
"x": -181,
|
||||
"y": -256.3828125
|
||||
},
|
||||
"scale": 1
|
||||
},
|
||||
|
|
@ -1245,19 +1259,8 @@
|
|||
"1": {
|
||||
"0": {
|
||||
"0": {},
|
||||
"1": {
|
||||
"1": {}
|
||||
},
|
||||
"2": {},
|
||||
"3": {},
|
||||
"4": {},
|
||||
"5": {
|
||||
"1": {
|
||||
"$selected": true
|
||||
}
|
||||
},
|
||||
"6": {},
|
||||
"7": {}
|
||||
"1": {},
|
||||
"2": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1300,11 +1303,11 @@
|
|||
"0": {},
|
||||
"1": {
|
||||
"0": {
|
||||
"0": {},
|
||||
"0": {
|
||||
"1": {}
|
||||
},
|
||||
"2": {
|
||||
"1": {
|
||||
"$selected": true
|
||||
}
|
||||
"1": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1313,7 +1316,7 @@
|
|||
},
|
||||
"transform": {
|
||||
"translate": {
|
||||
"x": -138,
|
||||
"x": -10.425644531250029,
|
||||
"y": -122
|
||||
},
|
||||
"scale": 1
|
||||
|
|
@ -1324,6 +1327,67 @@
|
|||
"secondToPx": 200,
|
||||
"scrollLeft": 0
|
||||
}
|
||||
},
|
||||
"[jetkvm.eez-project]:/userPages/7[flow-state]": {
|
||||
"selection": {
|
||||
"0": {
|
||||
"0": {
|
||||
"0": {},
|
||||
"1": {},
|
||||
"$selected": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"transform": {
|
||||
"translate": {
|
||||
"x": -180,
|
||||
"y": -207
|
||||
},
|
||||
"scale": 1
|
||||
},
|
||||
"timeline": {
|
||||
"isEditorActive": false,
|
||||
"position": 0,
|
||||
"secondToPx": 200,
|
||||
"scrollLeft": 0
|
||||
}
|
||||
},
|
||||
"[jetkvm.eez-project]:/userPages/8[flow-state]": {
|
||||
"selection": {
|
||||
"0": {
|
||||
"0": {
|
||||
"0": {
|
||||
"0": {}
|
||||
},
|
||||
"1": {
|
||||
"0": {
|
||||
"0": {
|
||||
"0": {
|
||||
"$selected": true
|
||||
}
|
||||
},
|
||||
"1": {},
|
||||
"2": {
|
||||
"0": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"transform": {
|
||||
"translate": {
|
||||
"x": -194,
|
||||
"y": -37
|
||||
},
|
||||
"scale": 1
|
||||
},
|
||||
"timeline": {
|
||||
"isEditorActive": false,
|
||||
"position": 0,
|
||||
"secondToPx": 200,
|
||||
"scrollLeft": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"activeOutputSection": 0,
|
||||
|
|
@ -1339,10 +1403,10 @@
|
|||
"logsPanelFilter": "all",
|
||||
"selectedStylePropertyName": "",
|
||||
"lvglPart": "MAIN",
|
||||
"lvglState": "DISABLED",
|
||||
"lvglState": "DEFAULT",
|
||||
"lvglExpandedPropertiesGroup": [
|
||||
"MARGIN",
|
||||
"TEXT"
|
||||
"POSITION AND SIZE",
|
||||
"LAYOUT"
|
||||
],
|
||||
"showInactiveFlowsInDebugger": true,
|
||||
"globalFlowZoom": true,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
#include "actions.h"
|
||||
#include "screens.h"
|
||||
#include <stdio.h>
|
||||
#include "ui.h"
|
||||
#include "vars.h"
|
||||
|
||||
int handle_gesture_screen_switch(lv_event_t *e, lv_dir_t direction, int screenId) {
|
||||
lv_event_code_t event_code = lv_event_get_code(e);
|
||||
|
|
@ -15,6 +18,15 @@ int handle_gesture_screen_switch(lv_event_t *e, lv_dir_t direction, int screenId
|
|||
return 1;
|
||||
}
|
||||
|
||||
void handle_gesture_main_screen_switch(lv_event_t *e, lv_dir_t direction) {
|
||||
const char *main_screen = get_var_main_screen();
|
||||
if (strcmp(main_screen, "home_screen") == 0) {
|
||||
loadScreen(SCREEN_ID_HOME_SCREEN);
|
||||
} else if (strcmp(main_screen, "no_network_screen") == 0) {
|
||||
loadScreen(SCREEN_ID_NO_NETWORK_SCREEN);
|
||||
}
|
||||
}
|
||||
|
||||
void action_switch_to_menu(lv_event_t *e) {
|
||||
loadScreen(SCREEN_ID_MENU_SCREEN);
|
||||
}
|
||||
|
|
@ -31,8 +43,16 @@ void action_switch_to_about(lv_event_t *e) {
|
|||
loadScreen(SCREEN_ID_ABOUT_SCREEN);
|
||||
}
|
||||
|
||||
void action_switch_to_reset_config(lv_event_t *e) {
|
||||
loadScreen(SCREEN_ID_RESET_CONFIG_SCREEN);
|
||||
}
|
||||
|
||||
void action_switch_to_reboot(lv_event_t *e) {
|
||||
loadScreen(SCREEN_ID_REBOOT_SCREEN);
|
||||
}
|
||||
|
||||
void action_menu_screen_gesture(lv_event_t * e) {
|
||||
handle_gesture_screen_switch(e, LV_DIR_RIGHT, SCREEN_ID_HOME_SCREEN);
|
||||
handle_gesture_main_screen_switch(e, LV_DIR_RIGHT);
|
||||
}
|
||||
|
||||
void action_menu_advanced_screen_gesture(lv_event_t * e) {
|
||||
|
|
@ -40,7 +60,7 @@ void action_menu_advanced_screen_gesture(lv_event_t * e) {
|
|||
}
|
||||
|
||||
void action_reset_config_screen_gesture(lv_event_t * e) {
|
||||
handle_gesture_screen_switch(e, LV_DIR_RIGHT, SCREEN_ID_MENU_ADVANCED_SCREEN);
|
||||
handle_gesture_screen_switch(e, LV_DIR_RIGHT, SCREEN_ID_MENU_SCREEN);
|
||||
}
|
||||
|
||||
void action_home_screen_gesture(lv_event_t * e) {
|
||||
|
|
@ -49,4 +69,72 @@ void action_home_screen_gesture(lv_event_t * e) {
|
|||
|
||||
void action_about_screen_gesture(lv_event_t * e) {
|
||||
handle_gesture_screen_switch(e, LV_DIR_RIGHT, SCREEN_ID_MENU_SCREEN);
|
||||
}
|
||||
|
||||
// user_data doesn't seem to be working, so we use a global variable here
|
||||
static uint32_t t_reset_config;
|
||||
static uint32_t t_reboot;
|
||||
static bool b_reboot = false;
|
||||
static bool b_reset_config = false;
|
||||
const int RESET_CONFIG_HOLD_TIME = 10;
|
||||
const int REBOOT_HOLD_TIME = 5;
|
||||
|
||||
void action_reset_config(lv_event_t * e) {
|
||||
lv_event_code_t event_code = lv_event_get_code(e);
|
||||
lv_obj_t *obj = lv_event_get_target(e);
|
||||
|
||||
if (event_code == LV_EVENT_PRESSED) {
|
||||
t_reset_config = lv_tick_get();
|
||||
}
|
||||
else if (event_code == LV_EVENT_PRESSING) {
|
||||
int remaining_time = RESET_CONFIG_HOLD_TIME * 1000 - lv_tick_elaps(t_reset_config);
|
||||
if (remaining_time <= 0) {
|
||||
lv_obj_add_flag(objects.reset_config_button, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(objects.reset_config_spinner, LV_OBJ_FLAG_HIDDEN);
|
||||
ui_call_rpc_handler("resetConfig", NULL);
|
||||
b_reset_config = true;
|
||||
} else {
|
||||
b_reset_config = false;
|
||||
char buf[100];
|
||||
int remaining_time_seconds = remaining_time / 1000;
|
||||
if (remaining_time_seconds <= 1) {
|
||||
remaining_time_seconds = 1;
|
||||
}
|
||||
sprintf(buf, "Press and hold for %d seconds", remaining_time_seconds);
|
||||
lv_label_set_text(objects.reset_config_label, buf);
|
||||
}
|
||||
} else if (event_code == LV_EVENT_RELEASED) {
|
||||
if (!b_reset_config) {
|
||||
lv_label_set_text(objects.reset_config_label, "Press and hold for 10 seconds");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void action_reboot(lv_event_t * e) {
|
||||
lv_event_code_t event_code = lv_event_get_code(e);
|
||||
lv_obj_t *obj = lv_event_get_target(e);
|
||||
|
||||
if (event_code == LV_EVENT_PRESSED) {
|
||||
t_reboot = lv_tick_get();
|
||||
}
|
||||
else if (event_code == LV_EVENT_PRESSING) {
|
||||
int remaining_time = REBOOT_HOLD_TIME * 1000 - lv_tick_elaps(t_reboot);
|
||||
if (remaining_time <= 0) {
|
||||
ui_call_rpc_handler("reboot", NULL);
|
||||
b_reboot = false;
|
||||
} else {
|
||||
b_reboot = false;
|
||||
char buf[100];
|
||||
int remaining_time_seconds = remaining_time / 1000;
|
||||
if (remaining_time_seconds <= 1) {
|
||||
remaining_time_seconds = 1;
|
||||
}
|
||||
sprintf(buf, "Press and hold for %d seconds", remaining_time_seconds);
|
||||
lv_label_set_text(objects.reboot_label, buf);
|
||||
}
|
||||
} else if (event_code == LV_EVENT_RELEASED) {
|
||||
if (!b_reboot) {
|
||||
lv_label_set_text(objects.reboot_label, "Press and hold for 5 seconds");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ extern int handle_gesture_screen_switch(lv_event_t *e, lv_dir_t direction, int s
|
|||
|
||||
extern void action_switch_to_menu(lv_event_t * e);
|
||||
extern void action_switch_to_advanced_menu(lv_event_t * e);
|
||||
extern void action_switch_to_reset_config(lv_event_t * e);
|
||||
extern void action_switch_to_about(lv_event_t * e);
|
||||
extern void action_menu_screen_gesture(lv_event_t * e);
|
||||
extern void action_home_screen_gesture(lv_event_t * e);
|
||||
|
|
@ -20,6 +21,9 @@ extern void action_about_screen_gesture(lv_event_t * e);
|
|||
extern void action_switch_to_status(lv_event_t * e);
|
||||
extern void action_common_click_event(lv_event_t * e);
|
||||
extern void action_handle_common_press_event(lv_event_t * e);
|
||||
extern void action_reset_config(lv_event_t * e);
|
||||
extern void action_reboot(lv_event_t * e);
|
||||
extern void action_switch_to_reboot(lv_event_t * e);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
|
|
@ -325,10 +325,11 @@ void create_screen_home_screen() {
|
|||
lv_obj_t *obj = lv_label_create(parent_obj);
|
||||
objects.home_info_ipv6_addr = obj;
|
||||
lv_obj_set_pos(obj, LV_PCT(0), LV_PCT(0));
|
||||
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
|
||||
lv_obj_set_size(obj, LV_PCT(98), 17);
|
||||
lv_label_set_long_mode(obj, LV_LABEL_LONG_DOT);
|
||||
add_style_label_font16(obj);
|
||||
lv_label_set_text(obj, "fe80::ffff:ffff:ffff:ffff:ffff:ffff");
|
||||
lv_obj_set_style_text_align(obj, LV_TEXT_ALIGN_LEFT, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_label_set_text(obj, "fe80::ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
|
||||
}
|
||||
{
|
||||
// HomeInfoMACAddr
|
||||
|
|
@ -431,10 +432,11 @@ void create_screen_home_screen() {
|
|||
objects.usb_status_label = obj;
|
||||
lv_obj_set_pos(obj, LV_PCT(0), LV_PCT(0));
|
||||
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
|
||||
lv_obj_add_flag(obj, LV_OBJ_FLAG_CHECKABLE);
|
||||
add_style_label_font16(obj);
|
||||
lv_obj_set_style_text_color(obj, lv_color_hex(0xff22c55e), LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_text_color(obj, lv_color_hex(0xff808080), LV_PART_MAIN | LV_STATE_DISABLED);
|
||||
lv_label_set_text(obj, "Connected");
|
||||
lv_obj_set_style_text_color(obj, lv_color_hex(0xff808080), LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_text_color(obj, lv_color_hex(0xff22c55e), LV_PART_MAIN | LV_STATE_CHECKED);
|
||||
lv_label_set_text(obj, "Unknown");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -493,11 +495,11 @@ void create_screen_home_screen() {
|
|||
objects.hdmi_status_label = obj;
|
||||
lv_obj_set_pos(obj, LV_PCT(0), LV_PCT(0));
|
||||
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
|
||||
lv_obj_add_state(obj, LV_STATE_DISABLED);
|
||||
lv_obj_add_flag(obj, LV_OBJ_FLAG_CHECKABLE);
|
||||
add_style_label_font16(obj);
|
||||
lv_obj_set_style_text_color(obj, lv_color_hex(0xff22c55e), LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_text_color(obj, lv_color_hex(0xff808080), LV_PART_MAIN | LV_STATE_DISABLED);
|
||||
lv_label_set_text(obj, "Disconnected");
|
||||
lv_obj_set_style_text_color(obj, lv_color_hex(0xff22c55e), LV_PART_MAIN | LV_STATE_CHECKED);
|
||||
lv_obj_set_style_text_color(obj, lv_color_hex(0xff808080), LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_label_set_text(obj, "Unknown");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -829,6 +831,8 @@ void create_screen_menu_advanced_screen() {
|
|||
objects.menu_btn_advanced_developer_mode = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), 50);
|
||||
lv_obj_add_event_cb(obj, action_reset_config, LV_EVENT_PRESSED, (void *)0);
|
||||
lv_obj_add_flag(obj, LV_OBJ_FLAG_HIDDEN);
|
||||
add_style_menu_button(obj);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
|
|
@ -847,6 +851,7 @@ void create_screen_menu_advanced_screen() {
|
|||
objects.menu_btn_advanced_usb_emulation = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), 50);
|
||||
lv_obj_add_flag(obj, LV_OBJ_FLAG_HIDDEN);
|
||||
add_style_menu_button(obj);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
|
|
@ -865,6 +870,7 @@ void create_screen_menu_advanced_screen() {
|
|||
objects.menu_btn_advanced_reboot = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), 50);
|
||||
lv_obj_add_event_cb(obj, action_switch_to_reboot, LV_EVENT_PRESSED, (void *)0);
|
||||
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SNAPPABLE);
|
||||
add_style_menu_button(obj);
|
||||
{
|
||||
|
|
@ -884,6 +890,7 @@ void create_screen_menu_advanced_screen() {
|
|||
objects.menu_btn_advanced_reset_config = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), 50);
|
||||
lv_obj_add_event_cb(obj, action_switch_to_reset_config, LV_EVENT_PRESSED, (void *)0);
|
||||
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SNAPPABLE);
|
||||
add_style_menu_button(obj);
|
||||
lv_obj_set_style_bg_color(obj, lv_color_hex(0xffdc2626), LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
|
|
@ -1719,6 +1726,403 @@ void create_screen_status_screen() {
|
|||
void tick_screen_status_screen() {
|
||||
}
|
||||
|
||||
void create_screen_reset_config_screen() {
|
||||
lv_obj_t *obj = lv_obj_create(0);
|
||||
objects.reset_config_screen = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, 300, 240);
|
||||
lv_obj_add_event_cb(obj, action_about_screen_gesture, LV_EVENT_GESTURE, (void *)0);
|
||||
add_style_flex_screen_menu(obj);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
lv_obj_t *obj = lv_obj_create(parent_obj);
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_PCT(100));
|
||||
lv_obj_set_style_pad_left(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_top(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_right(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_bottom(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_bg_opa(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLLABLE);
|
||||
add_style_flex_start(obj);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
// ResetConfigHeader
|
||||
lv_obj_t *obj = lv_obj_create(parent_obj);
|
||||
objects.reset_config_header = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_pad_left(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_top(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_bottom(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_bg_opa(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
add_style_flow_row_space_between(obj);
|
||||
lv_obj_set_style_pad_right(obj, 4, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
lv_obj_t *obj = lv_button_create(parent_obj);
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, 32, 32);
|
||||
lv_obj_add_event_cb(obj, action_switch_to_menu, LV_EVENT_CLICKED, (void *)0);
|
||||
add_style_back_button(obj);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
lv_obj_t *obj = lv_image_create(parent_obj);
|
||||
lv_obj_set_pos(obj, -1, 2);
|
||||
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
|
||||
lv_image_set_src(obj, &img_back_caret);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
lv_obj_t *obj = lv_label_create(parent_obj);
|
||||
lv_obj_set_pos(obj, LV_PCT(0), LV_PCT(0));
|
||||
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
|
||||
add_style_header_link(obj);
|
||||
lv_label_set_text(obj, "Reset Config");
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
// ResetConfigContainer
|
||||
lv_obj_t *obj = lv_obj_create(parent_obj);
|
||||
objects.reset_config_container = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_PCT(80));
|
||||
lv_obj_set_style_pad_left(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_top(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_bottom(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_bg_opa(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_scrollbar_mode(obj, LV_SCROLLBAR_MODE_AUTO);
|
||||
lv_obj_set_scroll_dir(obj, LV_DIR_VER);
|
||||
lv_obj_set_scroll_snap_x(obj, LV_SCROLL_SNAP_START);
|
||||
add_style_flex_column_start(obj);
|
||||
lv_obj_set_style_pad_right(obj, 4, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
lv_obj_t *obj = lv_obj_create(parent_obj);
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_pad_left(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_top(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_bottom(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_bg_opa(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLLABLE);
|
||||
add_style_flex_column_start(obj);
|
||||
lv_obj_set_style_pad_right(obj, 10, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
// ResetConfigLabelContainer
|
||||
lv_obj_t *obj = lv_obj_create(parent_obj);
|
||||
objects.reset_config_label_container = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_bg_opa(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLLABLE);
|
||||
add_style_flex_column_start(obj);
|
||||
lv_obj_set_style_pad_right(obj, 10, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_left(obj, 10, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_top(obj, 10, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_bottom(obj, 10, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
// ResetConfigLabel
|
||||
lv_obj_t *obj = lv_label_create(parent_obj);
|
||||
objects.reset_config_label = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
add_style_info_content_label(obj);
|
||||
lv_obj_set_style_text_font(obj, &ui_font_font_book20, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_label_set_text(obj, "Press and hold for\n10 seconds");
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
// ResetConfigSpinner
|
||||
lv_obj_t *obj = lv_obj_create(parent_obj);
|
||||
objects.reset_config_spinner = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_pad_left(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_top(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_right(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_bottom(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_bg_opa(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_add_flag(obj, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICKABLE|LV_OBJ_FLAG_SCROLLABLE);
|
||||
add_style_flex_column_start(obj);
|
||||
lv_obj_set_style_flex_main_place(obj, LV_FLEX_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_flex_cross_place(obj, LV_FLEX_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_flex_track_place(obj, LV_FLEX_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
lv_obj_t *obj = lv_spinner_create(parent_obj);
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, 80, 80);
|
||||
lv_spinner_set_anim_params(obj, 1000, 60);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
// ResetConfigButton
|
||||
lv_obj_t *obj = lv_obj_create(parent_obj);
|
||||
objects.reset_config_button = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_pad_left(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_top(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_right(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_bottom(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_bg_opa(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLLABLE);
|
||||
add_style_flex_column_start(obj);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
lv_obj_t *obj = lv_button_create(parent_obj);
|
||||
objects.obj0 = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), 50);
|
||||
lv_obj_add_event_cb(obj, action_reset_config, LV_EVENT_PRESSED, (void *)0);
|
||||
lv_obj_add_event_cb(obj, action_reset_config, LV_EVENT_PRESSING, (void *)0);
|
||||
lv_obj_add_event_cb(obj, action_reset_config, LV_EVENT_RELEASED, (void *)0);
|
||||
lv_obj_set_style_bg_color(obj, lv_color_hex(0xffdc2626), LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_text_align(obj, LV_TEXT_ALIGN_LEFT, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_right(obj, 13, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
lv_obj_t *obj = lv_label_create(parent_obj);
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_align(obj, LV_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_text_align(obj, LV_TEXT_ALIGN_LEFT, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_label_set_text(obj, "Reset configuration");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tick_screen_reset_config_screen();
|
||||
}
|
||||
|
||||
void tick_screen_reset_config_screen() {
|
||||
}
|
||||
|
||||
void create_screen_reboot_screen() {
|
||||
lv_obj_t *obj = lv_obj_create(0);
|
||||
objects.reboot_screen = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, 300, 240);
|
||||
lv_obj_add_event_cb(obj, action_about_screen_gesture, LV_EVENT_GESTURE, (void *)0);
|
||||
add_style_flex_screen_menu(obj);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
lv_obj_t *obj = lv_obj_create(parent_obj);
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_PCT(100));
|
||||
lv_obj_set_style_pad_left(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_top(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_right(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_bottom(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_bg_opa(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLLABLE);
|
||||
add_style_flex_start(obj);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
// RebootHeader
|
||||
lv_obj_t *obj = lv_obj_create(parent_obj);
|
||||
objects.reboot_header = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_pad_left(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_top(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_bottom(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_bg_opa(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
add_style_flow_row_space_between(obj);
|
||||
lv_obj_set_style_pad_right(obj, 4, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
lv_obj_t *obj = lv_button_create(parent_obj);
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, 32, 32);
|
||||
lv_obj_add_event_cb(obj, action_switch_to_menu, LV_EVENT_CLICKED, (void *)0);
|
||||
add_style_back_button(obj);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
lv_obj_t *obj = lv_image_create(parent_obj);
|
||||
lv_obj_set_pos(obj, -1, 2);
|
||||
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
|
||||
lv_image_set_src(obj, &img_back_caret);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
lv_obj_t *obj = lv_label_create(parent_obj);
|
||||
lv_obj_set_pos(obj, LV_PCT(0), LV_PCT(0));
|
||||
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
|
||||
add_style_header_link(obj);
|
||||
lv_label_set_text(obj, "Reboot Device");
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
// RebootContainer
|
||||
lv_obj_t *obj = lv_obj_create(parent_obj);
|
||||
objects.reboot_container = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_PCT(80));
|
||||
lv_obj_set_style_pad_left(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_top(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_bottom(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_bg_opa(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_scrollbar_mode(obj, LV_SCROLLBAR_MODE_AUTO);
|
||||
lv_obj_set_scroll_dir(obj, LV_DIR_VER);
|
||||
lv_obj_set_scroll_snap_x(obj, LV_SCROLL_SNAP_START);
|
||||
add_style_flex_column_start(obj);
|
||||
lv_obj_set_style_pad_right(obj, 4, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
lv_obj_t *obj = lv_obj_create(parent_obj);
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_pad_left(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_top(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_bottom(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_bg_opa(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLLABLE);
|
||||
add_style_flex_column_start(obj);
|
||||
lv_obj_set_style_pad_right(obj, 10, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
// RebootLabelContainer
|
||||
lv_obj_t *obj = lv_obj_create(parent_obj);
|
||||
objects.reboot_label_container = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_bg_opa(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLLABLE);
|
||||
add_style_flex_column_start(obj);
|
||||
lv_obj_set_style_pad_right(obj, 10, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_left(obj, 10, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_top(obj, 10, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_bottom(obj, 10, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
// RebootLabel
|
||||
lv_obj_t *obj = lv_label_create(parent_obj);
|
||||
objects.reboot_label = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
add_style_info_content_label(obj);
|
||||
lv_obj_set_style_text_font(obj, &ui_font_font_book20, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_label_set_text(obj, "Press and hold for\n5 seconds");
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
// RebootConfigButton
|
||||
lv_obj_t *obj = lv_obj_create(parent_obj);
|
||||
objects.reboot_config_button = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_pad_left(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_top(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_right(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_bottom(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_bg_opa(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLLABLE);
|
||||
add_style_flex_column_start(obj);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
lv_obj_t *obj = lv_button_create(parent_obj);
|
||||
objects.obj1 = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), 50);
|
||||
lv_obj_add_event_cb(obj, action_reboot, LV_EVENT_PRESSED, (void *)0);
|
||||
lv_obj_add_event_cb(obj, action_reboot, LV_EVENT_PRESSING, (void *)0);
|
||||
lv_obj_add_event_cb(obj, action_reboot, LV_EVENT_RELEASED, (void *)0);
|
||||
lv_obj_set_style_bg_color(obj, lv_color_hex(0xffdc2626), LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_text_align(obj, LV_TEXT_ALIGN_LEFT, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_right(obj, 13, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
lv_obj_t *obj = lv_label_create(parent_obj);
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_align(obj, LV_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_text_align(obj, LV_TEXT_ALIGN_LEFT, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_label_set_text(obj, "Hold to reboot");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tick_screen_reboot_screen();
|
||||
}
|
||||
|
||||
void tick_screen_reboot_screen() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
typedef void (*tick_screen_func_t)();
|
||||
|
|
@ -1731,6 +2135,8 @@ tick_screen_func_t tick_screen_funcs[] = {
|
|||
tick_screen_menu_network_screen,
|
||||
tick_screen_about_screen,
|
||||
tick_screen_status_screen,
|
||||
tick_screen_reset_config_screen,
|
||||
tick_screen_reboot_screen,
|
||||
};
|
||||
void tick_screen(int screen_index) {
|
||||
tick_screen_funcs[screen_index]();
|
||||
|
|
@ -1752,4 +2158,6 @@ void create_screens() {
|
|||
create_screen_menu_network_screen();
|
||||
create_screen_about_screen();
|
||||
create_screen_status_screen();
|
||||
create_screen_reset_config_screen();
|
||||
create_screen_reboot_screen();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ typedef struct _objects_t {
|
|||
lv_obj_t *menu_network_screen;
|
||||
lv_obj_t *about_screen;
|
||||
lv_obj_t *status_screen;
|
||||
lv_obj_t *reset_config_screen;
|
||||
lv_obj_t *reboot_screen;
|
||||
lv_obj_t *boot_logo;
|
||||
lv_obj_t *boot_screen_version;
|
||||
lv_obj_t *no_network_header_container;
|
||||
|
|
@ -83,6 +85,19 @@ typedef struct _objects_t {
|
|||
lv_obj_t *app_version_1;
|
||||
lv_obj_t *cloud_domain_container;
|
||||
lv_obj_t *cloud_domain;
|
||||
lv_obj_t *reset_config_header;
|
||||
lv_obj_t *reset_config_container;
|
||||
lv_obj_t *reset_config_label_container;
|
||||
lv_obj_t *reset_config_label;
|
||||
lv_obj_t *reset_config_spinner;
|
||||
lv_obj_t *reset_config_button;
|
||||
lv_obj_t *obj0;
|
||||
lv_obj_t *reboot_header;
|
||||
lv_obj_t *reboot_container;
|
||||
lv_obj_t *reboot_label_container;
|
||||
lv_obj_t *reboot_label;
|
||||
lv_obj_t *reboot_config_button;
|
||||
lv_obj_t *obj1;
|
||||
} objects_t;
|
||||
|
||||
extern objects_t objects;
|
||||
|
|
@ -96,6 +111,8 @@ enum ScreensEnum {
|
|||
SCREEN_ID_MENU_NETWORK_SCREEN = 6,
|
||||
SCREEN_ID_ABOUT_SCREEN = 7,
|
||||
SCREEN_ID_STATUS_SCREEN = 8,
|
||||
SCREEN_ID_RESET_CONFIG_SCREEN = 9,
|
||||
SCREEN_ID_REBOOT_SCREEN = 10,
|
||||
};
|
||||
|
||||
void create_screen_boot_screen();
|
||||
|
|
@ -121,6 +138,12 @@ void tick_screen_about_screen();
|
|||
|
||||
void create_screen_status_screen();
|
||||
void tick_screen_status_screen();
|
||||
|
||||
void create_screen_reset_config_screen();
|
||||
void tick_screen_reset_config_screen();
|
||||
|
||||
void create_screen_reboot_screen();
|
||||
void tick_screen_reboot_screen();
|
||||
|
||||
void tick_screen_by_id(enum ScreensEnum screenId);
|
||||
void tick_screen(int screen_index);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,19 @@
|
|||
|
||||
|
||||
|
||||
|
||||
jetkvm_rpc_handler_t *ui_rpc_handler = NULL;
|
||||
|
||||
void ui_set_rpc_handler(jetkvm_rpc_handler_t *handler) {
|
||||
ui_rpc_handler = handler;
|
||||
}
|
||||
|
||||
void ui_call_rpc_handler(const char *method, const char *params) {
|
||||
if (ui_rpc_handler != NULL) {
|
||||
(*ui_rpc_handler)(method, params);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(EEZ_FOR_LVGL)
|
||||
|
||||
void ui_init() {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,13 @@
|
|||
|
||||
#include <lvgl.h>
|
||||
|
||||
typedef void (jetkvm_rpc_handler_t)(const char *method, const char *params);
|
||||
|
||||
void ui_set_rpc_handler(jetkvm_rpc_handler_t *handler);
|
||||
void ui_call_rpc_handler(const char *method, const char *params);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#if defined(EEZ_FOR_LVGL)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
char app_version[100] = { 0 };
|
||||
char system_version[100] = { 0 };
|
||||
char lvgl_version[32] = { 0 };
|
||||
char main_screen[32] = "home_screen";
|
||||
|
||||
const char *get_var_app_version() {
|
||||
return app_version;
|
||||
|
|
@ -36,4 +37,13 @@ void set_var_system_version(const char *value) {
|
|||
system_version[sizeof(system_version) / sizeof(char) - 1] = 0;
|
||||
}
|
||||
|
||||
void set_var_lvgl_version(const char *value) {}
|
||||
void set_var_lvgl_version(const char *value) {}
|
||||
|
||||
void set_var_main_screen(const char *value) {
|
||||
strncpy(main_screen, value, sizeof(main_screen) / sizeof(char));
|
||||
main_screen[sizeof(main_screen) / sizeof(char) - 1] = 0;
|
||||
}
|
||||
|
||||
const char *get_var_main_screen() {
|
||||
return main_screen;
|
||||
}
|
||||
|
|
@ -17,7 +17,8 @@ extern "C" {
|
|||
enum FlowGlobalVariables {
|
||||
FLOW_GLOBAL_VARIABLE_APP_VERSION = 0,
|
||||
FLOW_GLOBAL_VARIABLE_SYSTEM_VERSION = 1,
|
||||
FLOW_GLOBAL_VARIABLE_LVGL_VERSION = 2
|
||||
FLOW_GLOBAL_VARIABLE_LVGL_VERSION = 2,
|
||||
FLOW_GLOBAL_VARIABLE_MAIN_SCREEN = 3
|
||||
};
|
||||
|
||||
// Native global variables
|
||||
|
|
@ -28,6 +29,8 @@ extern const char *get_var_system_version();
|
|||
extern void set_var_system_version(const char *value);
|
||||
extern const char *get_var_lvgl_version();
|
||||
extern void set_var_lvgl_version(const char *value);
|
||||
extern const char *get_var_main_screen();
|
||||
extern void set_var_main_screen(const char *value);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package native
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
|
|
@ -17,6 +18,9 @@ type Native struct {
|
|||
onVideoStateChange func(state VideoState)
|
||||
onVideoFrameReceived func(frame []byte, duration time.Duration)
|
||||
onIndevEvent func(event string)
|
||||
onRpcEvent func(event string)
|
||||
videoLock sync.Mutex
|
||||
screenLock sync.Mutex
|
||||
}
|
||||
|
||||
type NativeOptions struct {
|
||||
|
|
@ -26,20 +30,21 @@ type NativeOptions struct {
|
|||
OnVideoStateChange func(state VideoState)
|
||||
OnVideoFrameReceived func(frame []byte, duration time.Duration)
|
||||
OnIndevEvent func(event string)
|
||||
OnRpcEvent func(event string)
|
||||
}
|
||||
|
||||
func NewNative(opts NativeOptions) *Native {
|
||||
onVideoStateChange := opts.OnVideoStateChange
|
||||
if onVideoStateChange == nil {
|
||||
onVideoStateChange = func(state VideoState) {
|
||||
nativeLogger.Info().Msg("video state changed")
|
||||
nativeLogger.Info().Interface("state", state).Msg("video state changed")
|
||||
}
|
||||
}
|
||||
|
||||
onVideoFrameReceived := opts.OnVideoFrameReceived
|
||||
if onVideoFrameReceived == nil {
|
||||
onVideoFrameReceived = func(frame []byte, duration time.Duration) {
|
||||
nativeLogger.Info().Msg("video frame received")
|
||||
nativeLogger.Info().Interface("frame", frame).Dur("duration", duration).Msg("video frame received")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -50,6 +55,13 @@ func NewNative(opts NativeOptions) *Native {
|
|||
}
|
||||
}
|
||||
|
||||
onRpcEvent := opts.OnRpcEvent
|
||||
if onRpcEvent == nil {
|
||||
onRpcEvent = func(event string) {
|
||||
nativeLogger.Info().Str("event", event).Msg("rpc event")
|
||||
}
|
||||
}
|
||||
|
||||
return &Native{
|
||||
ready: make(chan struct{}),
|
||||
l: nativeLogger,
|
||||
|
|
@ -57,9 +69,12 @@ func NewNative(opts NativeOptions) *Native {
|
|||
systemVersion: opts.SystemVersion,
|
||||
appVersion: opts.AppVersion,
|
||||
displayRotation: opts.DisplayRotation,
|
||||
onVideoStateChange: opts.OnVideoStateChange,
|
||||
onVideoFrameReceived: opts.OnVideoFrameReceived,
|
||||
onIndevEvent: opts.OnIndevEvent,
|
||||
onVideoStateChange: onVideoStateChange,
|
||||
onVideoFrameReceived: onVideoFrameReceived,
|
||||
onIndevEvent: onIndevEvent,
|
||||
onRpcEvent: onRpcEvent,
|
||||
videoLock: sync.Mutex{},
|
||||
screenLock: sync.Mutex{},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -73,11 +88,14 @@ func (n *Native) Start() {
|
|||
go n.handleVideoStateChan()
|
||||
go n.handleVideoFrameChan()
|
||||
go n.handleIndevEventChan()
|
||||
go n.handleRpcEventChan()
|
||||
|
||||
n.initUI()
|
||||
go n.tickUI()
|
||||
|
||||
videoInit()
|
||||
if err := videoInit(); err != nil {
|
||||
n.l.Error().Err(err).Msg("failed to initialize video")
|
||||
}
|
||||
|
||||
close(n.ready)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,27 +9,52 @@ type VideoState struct {
|
|||
}
|
||||
|
||||
func (n *Native) VideoSetQualityFactor(factor float64) error {
|
||||
n.videoLock.Lock()
|
||||
defer n.videoLock.Unlock()
|
||||
|
||||
return videoSetStreamQualityFactor(factor)
|
||||
}
|
||||
|
||||
func (n *Native) VideoGetQualityFactor() (float64, error) {
|
||||
n.videoLock.Lock()
|
||||
defer n.videoLock.Unlock()
|
||||
|
||||
return videoGetStreamQualityFactor()
|
||||
}
|
||||
|
||||
func (n *Native) VideoSetEDID(edid string) error {
|
||||
n.videoLock.Lock()
|
||||
defer n.videoLock.Unlock()
|
||||
|
||||
return videoSetEDID(edid)
|
||||
}
|
||||
|
||||
func (n *Native) VideoGetEDID() (string, error) {
|
||||
n.videoLock.Lock()
|
||||
defer n.videoLock.Unlock()
|
||||
|
||||
return videoGetEDID()
|
||||
}
|
||||
|
||||
func (n *Native) VideoLogStatus() (string, error) {
|
||||
n.videoLock.Lock()
|
||||
defer n.videoLock.Unlock()
|
||||
|
||||
return videoLogStatus(), nil
|
||||
}
|
||||
|
||||
func (n *Native) VideoStop() error {
|
||||
n.videoLock.Lock()
|
||||
defer n.videoLock.Unlock()
|
||||
|
||||
videoStop()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *Native) VideoStart() error {
|
||||
n.videoLock.Lock()
|
||||
defer n.videoLock.Unlock()
|
||||
|
||||
videoStart()
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,46 +0,0 @@
|
|||
package network
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/jetkvm/kvm/internal/lldp"
|
||||
)
|
||||
|
||||
func (s *NetworkInterfaceState) shouldStartLLDP() bool {
|
||||
if s.lldp == nil {
|
||||
s.l.Trace().Msg("LLDP not initialized")
|
||||
return false
|
||||
}
|
||||
|
||||
s.l.Trace().Msgf("LLDP mode: %s", s.config.LLDPMode.String)
|
||||
|
||||
return s.config.LLDPMode.String != "disabled"
|
||||
}
|
||||
|
||||
func (s *NetworkInterfaceState) startLLDP() {
|
||||
if !s.shouldStartLLDP() || s.lldp == nil {
|
||||
return
|
||||
}
|
||||
|
||||
s.l.Trace().Msg("starting LLDP")
|
||||
if err := s.lldp.Start(); err != nil {
|
||||
s.l.Error().Err(err).Msg("unable to start LLDP")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *NetworkInterfaceState) stopLLDP() {
|
||||
if s.lldp == nil {
|
||||
return
|
||||
}
|
||||
s.l.Trace().Msg("stopping LLDP")
|
||||
if err := s.lldp.Stop(); err != nil {
|
||||
s.l.Error().Err(err).Msg("unable to stop LLDP")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *NetworkInterfaceState) GetLLDPNeighbors() ([]lldp.Neighbor, error) {
|
||||
if s.lldp == nil {
|
||||
return nil, errors.New("lldp not initialized")
|
||||
}
|
||||
return s.lldp.GetNeighbors(), nil
|
||||
}
|
||||
|
|
@ -6,7 +6,6 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/jetkvm/kvm/internal/confparser"
|
||||
"github.com/jetkvm/kvm/internal/lldp"
|
||||
"github.com/jetkvm/kvm/internal/logging"
|
||||
"github.com/jetkvm/kvm/internal/udhcpc"
|
||||
"github.com/rs/zerolog"
|
||||
|
|
@ -31,8 +30,6 @@ type NetworkInterfaceState struct {
|
|||
config *NetworkConfig
|
||||
dhcpClient *udhcpc.DHCPClient
|
||||
|
||||
lldp *lldp.LLDP
|
||||
|
||||
defaultHostname string
|
||||
currentHostname string
|
||||
currentFqdn string
|
||||
|
|
@ -101,24 +98,7 @@ func NewNetworkInterfaceState(opts *NetworkInterfaceOptions) (*NetworkInterfaceS
|
|||
},
|
||||
})
|
||||
|
||||
// create the lldp service
|
||||
lldpClient := lldp.NewLLDP(&lldp.LLDPOptions{
|
||||
InterfaceName: opts.InterfaceName,
|
||||
EnableRx: true,
|
||||
EnableTx: true,
|
||||
Logger: l,
|
||||
})
|
||||
|
||||
// create the lldp service
|
||||
lldpClient = lldp.NewLLDP(&lldp.LLDPOptions{
|
||||
InterfaceName: opts.InterfaceName,
|
||||
EnableRx: true,
|
||||
EnableTx: true,
|
||||
Logger: l,
|
||||
})
|
||||
|
||||
s.dhcpClient = dhcpClient
|
||||
s.lldp = lldpClient
|
||||
return s, nil
|
||||
}
|
||||
|
||||
|
|
@ -386,18 +366,12 @@ func (s *NetworkInterfaceState) updateNtpServersFromLease(lease *udhcpc.Lease) e
|
|||
}
|
||||
|
||||
func (s *NetworkInterfaceState) handleInitialCheck() {
|
||||
if s.IsUp() {
|
||||
s.startLLDP()
|
||||
}
|
||||
// if s.IsUp() {}
|
||||
s.onInitialCheck(s)
|
||||
}
|
||||
|
||||
func (s *NetworkInterfaceState) handleStateChange() {
|
||||
if s.IsUp() {
|
||||
s.startLLDP()
|
||||
} else {
|
||||
s.stopLLDP()
|
||||
}
|
||||
// if s.IsUp() {} else {}
|
||||
s.onStateChange(s)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -251,6 +251,10 @@ func rpcSetEDID(edid string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func rpcGetVideoLogStatus() (string, error) {
|
||||
return nativeInstance.VideoLogStatus()
|
||||
}
|
||||
|
||||
func rpcGetDevChannelState() (bool, error) {
|
||||
return config.IncludePreRelease, nil
|
||||
}
|
||||
|
|
@ -1207,6 +1211,7 @@ var rpcHandlers = map[string]RPCHandler{
|
|||
"setAutoUpdateState": {Func: rpcSetAutoUpdateState, Params: []string{"enabled"}},
|
||||
"getEDID": {Func: rpcGetEDID},
|
||||
"setEDID": {Func: rpcSetEDID, Params: []string{"edid"}},
|
||||
"getVideoLogStatus": {Func: rpcGetVideoLogStatus},
|
||||
"getDevChannelState": {Func: rpcGetDevChannelState},
|
||||
"setDevChannelState": {Func: rpcSetDevChannelState, Params: []string{"enabled"}},
|
||||
"getLocalVersion": {Func: rpcGetLocalVersion},
|
||||
|
|
@ -1259,5 +1264,4 @@ var rpcHandlers = map[string]RPCHandler{
|
|||
"setKeyboardMacros": {Func: setKeyboardMacros, Params: []string{"params"}},
|
||||
"getLocalLoopbackOnly": {Func: rpcGetLocalLoopbackOnly},
|
||||
"setLocalLoopbackOnly": {Func: rpcSetLocalLoopbackOnly, Params: []string{"enabled"}},
|
||||
"getLLDPNeighbors": {Func: rpcGetLLDPNeighbors},
|
||||
}
|
||||
|
|
|
|||
15
native.go
|
|
@ -24,6 +24,21 @@ func initNative(systemVersion *semver.Version, appVersion *semver.Version) {
|
|||
nativeLogger.Trace().Str("event", event).Msg("indev event received")
|
||||
wakeDisplay(false, "indev_event")
|
||||
},
|
||||
OnRpcEvent: func(event string) {
|
||||
nativeLogger.Trace().Str("event", event).Msg("rpc event received")
|
||||
switch event {
|
||||
case "resetConfig":
|
||||
err := rpcResetConfig()
|
||||
if err != nil {
|
||||
nativeLogger.Warn().Err(err).Msg("error resetting config")
|
||||
}
|
||||
_ = rpcReboot(true)
|
||||
case "reboot":
|
||||
_ = rpcReboot(true)
|
||||
default:
|
||||
nativeLogger.Warn().Str("event", event).Msg("unknown rpc event received")
|
||||
}
|
||||
},
|
||||
OnVideoFrameReceived: func(frame []byte, duration time.Duration) {
|
||||
if currentSession != nil {
|
||||
err := currentSession.VideoTrack.WriteSample(media.Sample{Data: frame, Duration: duration})
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package kvm
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jetkvm/kvm/internal/lldp"
|
||||
"github.com/jetkvm/kvm/internal/network"
|
||||
"github.com/jetkvm/kvm/internal/udhcpc"
|
||||
)
|
||||
|
|
@ -124,7 +123,3 @@ func rpcSetNetworkSettings(settings network.RpcNetworkSettings) (*network.RpcNet
|
|||
func rpcRenewDHCPLease() error {
|
||||
return networkState.RpcRenewDHCPLease()
|
||||
}
|
||||
|
||||
func rpcGetLLDPNeighbors() ([]lldp.Neighbor, error) {
|
||||
return networkState.GetLLDPNeighbors()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,11 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
C_RST="$(tput sgr0)"
|
||||
C_ERR="$(tput setaf 1)"
|
||||
C_OK="$(tput setaf 2)"
|
||||
C_WARN="$(tput setaf 3)"
|
||||
C_INFO="$(tput setaf 5)"
|
||||
SCRIPT_PATH=$(realpath "$(dirname $(realpath "${BASH_SOURCE[0]}"))")
|
||||
source ${SCRIPT_PATH}/build_utils.sh
|
||||
|
||||
msg() { printf '%s%s%s\n' $2 "$1" $C_RST; }
|
||||
|
||||
msg_info() { msg "$1" $C_INFO; }
|
||||
msg_ok() { msg "$1" $C_OK; }
|
||||
msg_err() { msg "$1" $C_ERR; }
|
||||
msg_warn() { msg "$1" $C_WARN; }
|
||||
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
BUILD_DIR=${SCRIPT_DIR}/build
|
||||
CGO_PATH=$(realpath "${SCRIPT_PATH}/../internal/native/cgo")
|
||||
BUILD_DIR=${CGO_PATH}/build
|
||||
|
||||
CMAKE_TOOLCHAIN_FILE=/opt/jetkvm-native-buildkit/rv1106-jetkvm-v2.cmake
|
||||
CLEAN_ALL=${CLEAN_ALL:-0}
|
||||
|
|
@ -25,7 +15,7 @@ if [ "$CLEAN_ALL" -eq 1 ]; then
|
|||
fi
|
||||
|
||||
TMP_DIR=$(mktemp -d)
|
||||
pushd "${SCRIPT_DIR}" > /dev/null
|
||||
pushd "${CGO_PATH}" > /dev/null
|
||||
|
||||
msg_info "▶ Generating UI index"
|
||||
./ui_index.gen.sh
|
||||
|
|
@ -37,7 +27,7 @@ VERBOSE=1 cmake -B "${BUILD_DIR}" \
|
|||
-DCMAKE_CROSSCOMPILING=1 \
|
||||
-DCMAKE_TOOLCHAIN_FILE=$CMAKE_TOOLCHAIN_FILE \
|
||||
-DLV_BUILD_USE_KCONFIG=ON \
|
||||
-DLV_BUILD_DEFCONFIG_PATH=${SCRIPT_DIR}/lvgl_defconfig \
|
||||
-DLV_BUILD_DEFCONFIG_PATH=${CGO_PATH}/lvgl_defconfig \
|
||||
-DCONFIG_LV_BUILD_EXAMPLES=OFF \
|
||||
-DCONFIG_LV_BUILD_DEMOS=OFF \
|
||||
-DSKIP_GLIBC_NAMES=ON \
|
||||
|
|
@ -46,8 +36,8 @@ VERBOSE=1 cmake -B "${BUILD_DIR}" \
|
|||
|
||||
msg_info "▶ Copying built library and header files"
|
||||
cmake --build "${BUILD_DIR}" --target install
|
||||
cp -r "${TMP_DIR}/include" ../
|
||||
cp -r "${TMP_DIR}/lib" ../
|
||||
cp -r "${TMP_DIR}/include" "${CGO_PATH}"
|
||||
cp -r "${TMP_DIR}/lib" "${CGO_PATH}"
|
||||
rm -rf "${TMP_DIR}"
|
||||
|
||||
popd > /dev/null
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
#!/bin/bash
|
||||
|
||||
# check if TERM is set
|
||||
# though it's not the actual way to detect if TTY is available, it's a good enough approximation for our use case
|
||||
HAS_TTY=true
|
||||
if [ -z "$TERM" ] || [ "$TERM" = "dumb" ]; then
|
||||
HAS_TTY=false
|
||||
fi
|
||||
|
||||
# default colors
|
||||
C_RST=$(echo -e "\e[0m")
|
||||
C_ERR=$(echo -e "\e[31m")
|
||||
C_OK=$(echo -e "\e[32m")
|
||||
C_WARN=$(echo -e "\e[33m")
|
||||
C_INFO=$(echo -e "\e[35m")
|
||||
|
||||
# if TTY is available, use colors
|
||||
if [ "$HAS_TTY" = true ]; then
|
||||
C_RST="$(tput sgr0)"
|
||||
C_ERR="$(tput setaf 1)"
|
||||
C_OK="$(tput setaf 2)"
|
||||
C_WARN="$(tput setaf 3)"
|
||||
C_INFO="$(tput setaf 5)"
|
||||
fi
|
||||
|
||||
msg() { printf '%s%s%s\n' $2 "$1" $C_RST; }
|
||||
|
||||
msg_info() { msg "$1" $C_INFO; }
|
||||
msg_ok() { msg "$1" $C_OK; }
|
||||
msg_err() { msg "$1" $C_ERR; }
|
||||
msg_warn() { msg "$1" $C_WARN; }
|
||||
|
||||
DOCKER_BUILD_TAG=${DOCKER_BUILD_TAG:-ghcr.io/jetkvm/buildkit:latest}
|
||||
DOCKER_BUILD_DEBUG=${DOCKER_BUILD_DEBUG:-false}
|
||||
DOCKER_BUILD_CONTEXT_DIR=${DOCKER_BUILD_CONTEXT_DIR:-$(mktemp -d)}
|
||||
DOCKER_GO_CACHE_DIR=${DOCKER_GO_CACHE_DIR:-$(pwd)/.cache}
|
||||
|
||||
BUILD_IN_DOCKER=${BUILD_IN_DOCKER:-false}
|
||||
|
||||
|
||||
function prepare_docker_build_context() {
|
||||
msg_info "▶ Preparing docker build context ..."
|
||||
cp .devcontainer/install-deps.sh \
|
||||
go.mod \
|
||||
go.sum \
|
||||
Dockerfile.build \
|
||||
"${DOCKER_BUILD_CONTEXT_DIR}"
|
||||
cat > "${DOCKER_BUILD_CONTEXT_DIR}/entrypoint.sh" << 'EOF'
|
||||
#!/bin/bash
|
||||
git config --global --add safe.directory /build
|
||||
exec $@
|
||||
EOF
|
||||
chmod +x "${DOCKER_BUILD_CONTEXT_DIR}/entrypoint.sh"
|
||||
}
|
||||
|
||||
function build_docker_image() {
|
||||
if [ "$JETKVM_INSIDE_DOCKER" = 1 ]; then
|
||||
msg_err "Error: already running inside Docker"
|
||||
exit
|
||||
fi
|
||||
|
||||
BUILD_ARGS="--build-arg BUILDPLATFORM=linux/amd64"
|
||||
if [ "$DOCKER_BUILD_DEBUG" = true ]; then
|
||||
BUILD_ARGS="$BUILD_ARGS --progress=plain --no-cache"
|
||||
fi
|
||||
|
||||
msg_info "Checking if Docker is available ..."
|
||||
if ! command -v docker &> /dev/null; then
|
||||
msg_err "Error: Docker is not installed"
|
||||
exit 1
|
||||
fi
|
||||
prepare_docker_build_context
|
||||
pushd "${DOCKER_BUILD_CONTEXT_DIR}" > /dev/null
|
||||
msg_info "▶ Building docker image ..."
|
||||
docker build $BUILD_ARGS -t ${DOCKER_BUILD_TAG} -f Dockerfile.build .
|
||||
popd > /dev/null
|
||||
}
|
||||
|
||||
function do_make() {
|
||||
DOCKER_BUILD_ARGS="--rm"
|
||||
if [ "$HAS_TTY" = true ]; then
|
||||
DOCKER_BUILD_ARGS="$DOCKER_BUILD_ARGS --interactive --tty"
|
||||
fi
|
||||
if [ "$BUILD_IN_DOCKER" = true ]; then
|
||||
msg_info "▶ Building the project in Docker ..."
|
||||
set -x
|
||||
docker run \
|
||||
--env JETKVM_INSIDE_DOCKER=1 \
|
||||
-v "$(pwd):/build" \
|
||||
-v "${DOCKER_GO_CACHE_DIR}:/root/.cache/go-build" \
|
||||
${DOCKER_BUILD_TAG} make "$@"
|
||||
set +x
|
||||
else
|
||||
msg_info "▶ Building the project in host ..."
|
||||
set -x
|
||||
make "$@"
|
||||
set +x
|
||||
fi
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
#!/bin/bash
|
||||
|
||||
SCRIPT_PATH=$(realpath "$(dirname $(realpath "${BASH_SOURCE[0]}"))")
|
||||
source ${SCRIPT_PATH}/build_utils.sh
|
||||
|
||||
set -e
|
||||
|
||||
# check if GITHUB_ENV is set
|
||||
if [ -z "$GITHUB_ENV" ]; then
|
||||
echo "GITHUB_ENV is not set"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$1" = "prepare" ]; then
|
||||
prepare_docker_build_context
|
||||
echo "DOCKER_BUILD_CONTEXT_DIR=$DOCKER_BUILD_CONTEXT_DIR" >> $GITHUB_ENV
|
||||
echo "DOCKER_BUILD_TAG=$DOCKER_BUILD_TAG" >> $GITHUB_ENV
|
||||
elif [ "$1" = "make" ]; then
|
||||
BUILD_IN_DOCKER=true
|
||||
# check if GO is available
|
||||
if ! command -v go &> /dev/null; then
|
||||
msg_info "Go is not available, will using default cache directory"
|
||||
else
|
||||
DOCKER_GO_CACHE_DIR=$(go env GOCACHE)
|
||||
fi
|
||||
do_make "${@:2}"
|
||||
fi
|
||||
|
||||
|
|
@ -0,0 +1,218 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Exit immediately if a command exits with a non-zero status
|
||||
set -e
|
||||
|
||||
# Function to display help message
|
||||
show_help() {
|
||||
echo "Usage: $0 [options] -r <remote_ip>"
|
||||
echo
|
||||
echo "Required:"
|
||||
echo " -r, --remote <remote_ip> Remote host IP address"
|
||||
echo
|
||||
echo "Optional:"
|
||||
echo " -u, --user <remote_user> Remote username (default: root)"
|
||||
echo " --run-go-tests Run go tests"
|
||||
echo " --run-go-tests-only Run go tests and exit"
|
||||
echo " --skip-ui-build Skip frontend/UI build"
|
||||
echo " --skip-native-build Skip native build"
|
||||
echo " -i, --install Build for release and install the app"
|
||||
echo " --help Display this help message"
|
||||
echo
|
||||
echo "Example:"
|
||||
echo " $0 -r 192.168.0.17"
|
||||
echo " $0 -r 192.168.0.17 -u admin"
|
||||
}
|
||||
|
||||
# Default values
|
||||
SCRIPT_PATH=$(realpath "$(dirname $(realpath "${BASH_SOURCE[0]}"))")
|
||||
REMOTE_USER="root"
|
||||
REMOTE_PATH="/userdata/jetkvm/bin"
|
||||
SKIP_UI_BUILD=false
|
||||
SKIP_UI_BUILD_RELEASE=0
|
||||
SKIP_NATIVE_BUILD=0
|
||||
RESET_USB_HID_DEVICE=false
|
||||
LOG_TRACE_SCOPES="${LOG_TRACE_SCOPES:-jetkvm,cloud,websocket,native,jsonrpc}"
|
||||
RUN_GO_TESTS=false
|
||||
RUN_GO_TESTS_ONLY=false
|
||||
INSTALL_APP=false
|
||||
BUILD_IN_DOCKER=false
|
||||
DOCKER_BUILD_DEBUG=false
|
||||
DOCKER_BUILD_TAG=ghcr.io/jetkvm/buildkit:latest
|
||||
|
||||
# Parse command line arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-r|--remote)
|
||||
REMOTE_HOST="$2"
|
||||
shift 2
|
||||
;;
|
||||
-u|--user)
|
||||
REMOTE_USER="$2"
|
||||
shift 2
|
||||
;;
|
||||
--skip-ui-build)
|
||||
SKIP_UI_BUILD=true
|
||||
shift
|
||||
;;
|
||||
--skip-native-build)
|
||||
SKIP_NATIVE_BUILD=1
|
||||
shift
|
||||
;;
|
||||
--reset-usb-hid)
|
||||
RESET_USB_HID_DEVICE=true
|
||||
shift
|
||||
;;
|
||||
--build-in-docker)
|
||||
BUILD_IN_DOCKER=true
|
||||
shift
|
||||
;;
|
||||
--docker-build-debug)
|
||||
DOCKER_BUILD_DEBUG=true
|
||||
shift
|
||||
;;
|
||||
--run-go-tests)
|
||||
RUN_GO_TESTS=true
|
||||
shift
|
||||
;;
|
||||
--run-go-tests-only)
|
||||
RUN_GO_TESTS_ONLY=true
|
||||
RUN_GO_TESTS=true
|
||||
shift
|
||||
;;
|
||||
-i|--install)
|
||||
INSTALL_APP=true
|
||||
shift
|
||||
;;
|
||||
--help)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
source ${SCRIPT_PATH}/build_utils.sh
|
||||
|
||||
# Verify required parameters
|
||||
if [ -z "$REMOTE_HOST" ]; then
|
||||
msg_err "Error: Remote IP is a required parameter"
|
||||
show_help
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# check if the current CPU architecture is x86_64
|
||||
if [ "$(uname -m)" != "x86_64" ]; then
|
||||
msg_warn "Warning: This script is only supported on x86_64 architecture"
|
||||
BUILD_IN_DOCKER=true
|
||||
fi
|
||||
|
||||
if [ "$BUILD_IN_DOCKER" = true ]; then
|
||||
build_docker_image
|
||||
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
|
||||
if [[ "$SKIP_UI_BUILD" = false && "$JETKVM_INSIDE_DOCKER" != 1 ]]; then
|
||||
msg_info "▶ Building frontend"
|
||||
make frontend SKIP_UI_BUILD=0
|
||||
SKIP_UI_BUILD_RELEASE=1
|
||||
fi
|
||||
|
||||
if [ "$RUN_GO_TESTS" = true ]; then
|
||||
msg_info "▶ Building go tests"
|
||||
make build_dev_test
|
||||
|
||||
msg_info "▶ Copying device-tests.tar.gz to remote host"
|
||||
ssh "${REMOTE_USER}@${REMOTE_HOST}" "cat > /tmp/device-tests.tar.gz" < device-tests.tar.gz
|
||||
|
||||
msg_info "▶ Running go tests"
|
||||
ssh "${REMOTE_USER}@${REMOTE_HOST}" ash << 'EOF'
|
||||
set -e
|
||||
TMP_DIR=$(mktemp -d)
|
||||
cd ${TMP_DIR}
|
||||
tar zxf /tmp/device-tests.tar.gz
|
||||
./gotestsum --format=testdox \
|
||||
--jsonfile=/tmp/device-tests.json \
|
||||
--post-run-command 'sh -c "echo $TESTS_FAILED > /tmp/device-tests.failed"' \
|
||||
--raw-command -- ./run_all_tests -json
|
||||
|
||||
GOTESTSUM_EXIT_CODE=$?
|
||||
if [ $GOTESTSUM_EXIT_CODE -ne 0 ]; then
|
||||
echo "❌ Tests failed (exit code: $GOTESTSUM_EXIT_CODE)"
|
||||
rm -rf ${TMP_DIR} /tmp/device-tests.tar.gz
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TESTS_FAILED=$(cat /tmp/device-tests.failed)
|
||||
if [ "$TESTS_FAILED" -ne 0 ]; then
|
||||
echo "❌ Tests failed $TESTS_FAILED tests failed"
|
||||
rm -rf ${TMP_DIR} /tmp/device-tests.tar.gz
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ Tests passed"
|
||||
rm -rf ${TMP_DIR} /tmp/device-tests.tar.gz
|
||||
EOF
|
||||
|
||||
if [ "$RUN_GO_TESTS_ONLY" = true ]; then
|
||||
msg_info "▶ Go tests completed"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$INSTALL_APP" = true ]
|
||||
then
|
||||
msg_info "▶ Building release binary"
|
||||
do_make build_release SKIP_NATIVE_IF_EXISTS=${SKIP_NATIVE_BUILD} SKIP_UI_BUILD=${SKIP_UI_BUILD_RELEASE}
|
||||
|
||||
# Copy the binary to the remote host as if we were the OTA updater.
|
||||
ssh "${REMOTE_USER}@${REMOTE_HOST}" "cat > /userdata/jetkvm/jetkvm_app.update" < bin/jetkvm_app
|
||||
|
||||
# Reboot the device, the new app will be deployed by the startup process.
|
||||
ssh "${REMOTE_USER}@${REMOTE_HOST}" "reboot"
|
||||
else
|
||||
msg_info "▶ Building development binary"
|
||||
do_make build_dev SKIP_NATIVE_IF_EXISTS=${SKIP_NATIVE_BUILD} SKIP_UI_BUILD=${SKIP_UI_BUILD_RELEASE}
|
||||
|
||||
# Kill any existing instances of the application
|
||||
ssh "${REMOTE_USER}@${REMOTE_HOST}" "killall jetkvm_app_debug || true"
|
||||
|
||||
# Copy the binary to the remote host
|
||||
ssh "${REMOTE_USER}@${REMOTE_HOST}" "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 "${REMOTE_USER}@${REMOTE_HOST}" "rm -rf /sys/kernel/config/usb_gadget/jetkvm/configs/c.1/hid.usb*"
|
||||
ssh "${REMOTE_USER}@${REMOTE_HOST}" "ls /sys/class/udc > /sys/kernel/config/usb_gadget/jetkvm/UDC"
|
||||
fi
|
||||
|
||||
# Deploy and run the application on the remote host
|
||||
ssh "${REMOTE_USER}@${REMOTE_HOST}" 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
|
||||
|
||||
# Kill any existing instances of the application
|
||||
killall jetkvm_app || true
|
||||
killall jetkvm_app_debug || true
|
||||
|
||||
# Navigate to the directory where the binary will be stored
|
||||
cd "${REMOTE_PATH}"
|
||||
|
||||
# Make the new binary executable
|
||||
chmod +x jetkvm_app_debug
|
||||
|
||||
# Run the application in the background
|
||||
PION_LOG_TRACE=${LOG_TRACE_SCOPES} ./jetkvm_app_debug | tee -a /tmp/jetkvm_app_debug.log
|
||||
EOF
|
||||
fi
|
||||
|
||||
echo "Deployment complete."
|
||||
|
|
@ -3,18 +3,8 @@
|
|||
# Exit immediately if a command exits with a non-zero status
|
||||
set -e
|
||||
|
||||
C_RST="$(tput sgr0)"
|
||||
C_ERR="$(tput setaf 1)"
|
||||
C_OK="$(tput setaf 2)"
|
||||
C_WARN="$(tput setaf 3)"
|
||||
C_INFO="$(tput setaf 5)"
|
||||
|
||||
msg() { printf '%s%s%s\n' $2 "$1" $C_RST; }
|
||||
|
||||
msg_info() { msg "$1" $C_INFO; }
|
||||
msg_ok() { msg "$1" $C_OK; }
|
||||
msg_err() { msg "$1" $C_ERR; }
|
||||
msg_warn() { msg "$1" $C_WARN; }
|
||||
SCRIPT_PATH=$(realpath "$(dirname $(realpath "${BASH_SOURCE[0]}"))")
|
||||
source ${SCRIPT_PATH}/build_utils.sh
|
||||
|
||||
# Get the latest release information
|
||||
msg_info "Getting latest release information ..."
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<!-- These are the fonts used in the app -->
|
||||
<link
|
||||
rel="preload"
|
||||
href="./public/fonts/CircularXXWeb-Medium.woff2"
|
||||
|
|
@ -32,6 +31,13 @@
|
|||
type="font/woff2"
|
||||
crossorigin
|
||||
/>
|
||||
<link
|
||||
rel="preload"
|
||||
href="./public/fonts/CircularXXWeb-Bold.woff2"
|
||||
as="font"
|
||||
type="font/woff2"
|
||||
crossorigin
|
||||
/>
|
||||
<title>JetKVM</title>
|
||||
<link rel="stylesheet" href="./public/fonts/fonts.css" />
|
||||
<link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96" />
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "kvm-ui",
|
||||
"private": true,
|
||||
"version": "2025.09.03.2100",
|
||||
"version": "2025.09.23.0000",
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node": "^22.15.0"
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@headlessui/react": "^2.2.7",
|
||||
"@headlessui/react": "^2.2.8",
|
||||
"@headlessui/tailwindcss": "^0.2.2",
|
||||
"@heroicons/react": "^2.2.0",
|
||||
"@vitejs/plugin-basic-ssl": "^2.1.0",
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
"dayjs": "^1.11.18",
|
||||
"eslint-import-resolver-alias": "^1.1.2",
|
||||
"focus-trap-react": "^11.0.4",
|
||||
"framer-motion": "^12.23.12",
|
||||
"framer-motion": "^12.23.18",
|
||||
"lodash.throttle": "^4.1.1",
|
||||
"mini-svg-data-uri": "^1.4.4",
|
||||
"react": "^19.1.1",
|
||||
|
|
@ -41,45 +41,45 @@
|
|||
"react-dom": "^19.1.1",
|
||||
"react-hot-toast": "^2.6.0",
|
||||
"react-icons": "^5.5.0",
|
||||
"react-router": "^7.8.2",
|
||||
"react-simple-keyboard": "^3.8.119",
|
||||
"react-router": "^7.9.1",
|
||||
"react-simple-keyboard": "^3.8.122",
|
||||
"react-use-websocket": "^4.13.0",
|
||||
"react-xtermjs": "^1.0.10",
|
||||
"recharts": "^3.1.2",
|
||||
"recharts": "^3.2.1",
|
||||
"tailwind-merge": "^3.3.1",
|
||||
"usehooks-ts": "^3.1.1",
|
||||
"validator": "^13.15.15",
|
||||
"zustand": "^4.5.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/compat": "^1.3.2",
|
||||
"@eslint/compat": "^1.4.0",
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
"@eslint/js": "^9.34.0",
|
||||
"@eslint/js": "^9.36.0",
|
||||
"@tailwindcss/forms": "^0.5.10",
|
||||
"@tailwindcss/postcss": "^4.1.12",
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
"@tailwindcss/vite": "^4.1.12",
|
||||
"@types/react": "^19.1.12",
|
||||
"@tailwindcss/postcss": "^4.1.13",
|
||||
"@tailwindcss/typography": "^0.5.18",
|
||||
"@tailwindcss/vite": "^4.1.13",
|
||||
"@types/react": "^19.1.13",
|
||||
"@types/react-dom": "^19.1.9",
|
||||
"@types/semver": "^7.7.1",
|
||||
"@types/validator": "^13.15.3",
|
||||
"@typescript-eslint/eslint-plugin": "^8.42.0",
|
||||
"@typescript-eslint/parser": "^8.42.0",
|
||||
"@vitejs/plugin-react-swc": "^4.0.1",
|
||||
"@typescript-eslint/eslint-plugin": "^8.44.1",
|
||||
"@typescript-eslint/parser": "^8.44.1",
|
||||
"@vitejs/plugin-react-swc": "^4.1.0",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"eslint": "^9.34.0",
|
||||
"eslint": "^9.36.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-import": "^2.32.0",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.20",
|
||||
"globals": "^16.3.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.21",
|
||||
"globals": "^16.4.0",
|
||||
"postcss": "^8.5.6",
|
||||
"prettier": "^3.6.2",
|
||||
"prettier-plugin-tailwindcss": "^0.6.14",
|
||||
"tailwindcss": "^4.1.12",
|
||||
"tailwindcss": "^4.1.13",
|
||||
"typescript": "^5.9.2",
|
||||
"vite": "^7.1.5",
|
||||
"vite": "^7.1.7",
|
||||
"vite-tsconfig-paths": "^5.1.4"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#1D4ED8" d="M0 6a6 6 0 0 1 6-6h12a6 6 0 0 1 6 6v12a6 6 0 0 1-6 6H6a6 6 0 0 1-6-6V6Z"/><path fill="#fff" d="M13.885 12a1.895 1.895 0 1 1-3.79 0 1.895 1.895 0 0 1 3.79 0Z"/><path fill="#fff" fill-rule="evenodd" d="M7.59 9.363c.49.182.74.727.558 1.218A4.103 4.103 0 0 0 12 16.105a4.103 4.103 0 0 0 3.852-5.526.947.947 0 0 1 1.777-.658A5.998 5.998 0 0 1 12 18a5.998 5.998 0 0 1-5.628-8.078.947.947 0 0 1 1.218-.56ZM11.993 7.895c-.628 0-1.22.14-1.75.39a.947.947 0 1 1-.808-1.714A5.985 5.985 0 0 1 11.993 6c.913 0 1.78.204 2.557.57a.947.947 0 1 1-.808 1.715 4.09 4.09 0 0 0-1.75-.39Z" clip-rule="evenodd"/><path fill="#1D4ED8" d="M0 6a6 6 0 0 1 6-6h12a6 6 0 0 1 6 6v12a6 6 0 0 1-6 6H6a6 6 0 0 1-6-6V6Z"/><path fill="#fff" d="M13.885 12a1.895 1.895 0 1 1-3.79 0 1.895 1.895 0 0 1 3.79 0Z"/><path fill="#fff" fill-rule="evenodd" d="M7.59 9.363c.49.182.74.727.558 1.218A4.103 4.103 0 0 0 12 16.105a4.103 4.103 0 0 0 3.852-5.526.947.947 0 0 1 1.777-.658A5.998 5.998 0 0 1 12 18a5.998 5.998 0 0 1-5.628-8.078.947.947 0 0 1 1.218-.56ZM11.993 7.895c-.628 0-1.22.14-1.75.39a.947.947 0 1 1-.808-1.714A5.985 5.985 0 0 1 11.993 6c.913 0 1.78.204 2.557.57a.947.947 0 1 1-.808 1.715 4.09 4.09 0 0 0-1.75-.39Z" clip-rule="evenodd"/></svg><style>@media (prefers-color-scheme:light){:root{filter:none}}@media (prefers-color-scheme:dark){:root{filter:none}}</style></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#1D4ED8" d="M0 6a6 6 0 0 1 6-6h12a6 6 0 0 1 6 6v12a6 6 0 0 1-6 6H6a6 6 0 0 1-6-6V6Z"/><path fill="#fff" d="M13.885 12a1.895 1.895 0 1 1-3.79 0 1.895 1.895 0 0 1 3.79 0Z"/><path fill="#fff" fill-rule="evenodd" d="M7.59 9.363c.49.182.74.727.558 1.218A4.103 4.103 0 0 0 12 16.105a4.103 4.103 0 0 0 3.852-5.526.947.947 0 0 1 1.777-.658A5.998 5.998 0 0 1 12 18a5.998 5.998 0 0 1-5.628-8.078.947.947 0 0 1 1.218-.56Zm4.403-1.468c-.628 0-1.22.14-1.75.39a.947.947 0 1 1-.808-1.714A5.985 5.985 0 0 1 11.993 6c.913 0 1.78.204 2.557.57a.947.947 0 1 1-.808 1.715 4.09 4.09 0 0 0-1.75-.39Z" clip-rule="evenodd"/><path fill="#1D4ED8" d="M0 6a6 6 0 0 1 6-6h12a6 6 0 0 1 6 6v12a6 6 0 0 1-6 6H6a6 6 0 0 1-6-6V6Z"/><path fill="#fff" d="M13.885 12a1.895 1.895 0 1 1-3.79 0 1.895 1.895 0 0 1 3.79 0Z"/><path fill="#fff" fill-rule="evenodd" d="M7.59 9.363c.49.182.74.727.558 1.218A4.103 4.103 0 0 0 12 16.105a4.103 4.103 0 0 0 3.852-5.526.947.947 0 0 1 1.777-.658A5.998 5.998 0 0 1 12 18a5.998 5.998 0 0 1-5.628-8.078.947.947 0 0 1 1.218-.56Zm4.403-1.468c-.628 0-1.22.14-1.75.39a.947.947 0 1 1-.808-1.714A5.985 5.985 0 0 1 11.993 6c.913 0 1.78.204 2.557.57a.947.947 0 1 1-.808 1.715 4.09 4.09 0 0 0-1.75-.39Z" clip-rule="evenodd"/></svg><style>@media (prefers-color-scheme:light){:root{filter:none}}@media (prefers-color-scheme:dark){:root{filter:none}}</style></svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
|
@ -1 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#1D4ED8" d="M0 6a6 6 0 0 1 6-6h12a6 6 0 0 1 6 6v12a6 6 0 0 1-6 6H6a6 6 0 0 1-6-6V6Z"/><path fill="#fff" d="M13.885 12a1.895 1.895 0 1 1-3.79 0 1.895 1.895 0 0 1 3.79 0Z"/><path fill="#fff" fill-rule="evenodd" d="M7.59 9.363c.49.182.74.727.558 1.218A4.103 4.103 0 0 0 12 16.105a4.103 4.103 0 0 0 3.852-5.526.947.947 0 0 1 1.777-.658A5.998 5.998 0 0 1 12 18a5.998 5.998 0 0 1-5.628-8.078.947.947 0 0 1 1.218-.56ZM11.993 7.895c-.628 0-1.22.14-1.75.39a.947.947 0 1 1-.808-1.714A5.985 5.985 0 0 1 11.993 6c.913 0 1.78.204 2.557.57a.947.947 0 1 1-.808 1.715 4.09 4.09 0 0 0-1.75-.39Z" clip-rule="evenodd"/><path fill="#1D4ED8" d="M0 6a6 6 0 0 1 6-6h12a6 6 0 0 1 6 6v12a6 6 0 0 1-6 6H6a6 6 0 0 1-6-6V6Z"/><path fill="#fff" d="M13.885 12a1.895 1.895 0 1 1-3.79 0 1.895 1.895 0 0 1 3.79 0Z"/><path fill="#fff" fill-rule="evenodd" d="M7.59 9.363c.49.182.74.727.558 1.218A4.103 4.103 0 0 0 12 16.105a4.103 4.103 0 0 0 3.852-5.526.947.947 0 0 1 1.777-.658A5.998 5.998 0 0 1 12 18a5.998 5.998 0 0 1-5.628-8.078.947.947 0 0 1 1.218-.56ZM11.993 7.895c-.628 0-1.22.14-1.75.39a.947.947 0 1 1-.808-1.714A5.985 5.985 0 0 1 11.993 6c.913 0 1.78.204 2.557.57a.947.947 0 1 1-.808 1.715 4.09 4.09 0 0 0-1.75-.39Z" clip-rule="evenodd"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#1D4ED8" d="M0 6a6 6 0 0 1 6-6h12a6 6 0 0 1 6 6v12a6 6 0 0 1-6 6H6a6 6 0 0 1-6-6V6Z"/><path fill="#fff" d="M13.885 12a1.895 1.895 0 1 1-3.79 0 1.895 1.895 0 0 1 3.79 0Z"/><path fill="#fff" fill-rule="evenodd" d="M7.59 9.363c.49.182.74.727.558 1.218A4.103 4.103 0 0 0 12 16.105a4.103 4.103 0 0 0 3.852-5.526.947.947 0 0 1 1.777-.658A5.998 5.998 0 0 1 12 18a5.998 5.998 0 0 1-5.628-8.078.947.947 0 0 1 1.218-.56Zm4.403-1.468c-.628 0-1.22.14-1.75.39a.947.947 0 1 1-.808-1.714A5.985 5.985 0 0 1 11.993 6c.913 0 1.78.204 2.557.57a.947.947 0 1 1-.808 1.715 4.09 4.09 0 0 0-1.75-.39Z" clip-rule="evenodd"/><path fill="#1D4ED8" d="M0 6a6 6 0 0 1 6-6h12a6 6 0 0 1 6 6v12a6 6 0 0 1-6 6H6a6 6 0 0 1-6-6V6Z"/><path fill="#fff" d="M13.885 12a1.895 1.895 0 1 1-3.79 0 1.895 1.895 0 0 1 3.79 0Z"/><path fill="#fff" fill-rule="evenodd" d="M7.59 9.363c.49.182.74.727.558 1.218A4.103 4.103 0 0 0 12 16.105a4.103 4.103 0 0 0 3.852-5.526.947.947 0 0 1 1.777-.658A5.998 5.998 0 0 1 12 18a5.998 5.998 0 0 1-5.628-8.078.947.947 0 0 1 1.218-.56Zm4.403-1.468c-.628 0-1.22.14-1.75.39a.947.947 0 1 1-.808-1.714A5.985 5.985 0 0 1 11.993 6c.913 0 1.78.204 2.557.57a.947.947 0 1 1-.808 1.715 4.09 4.09 0 0 0-1.75-.39Z" clip-rule="evenodd"/></svg>
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 913 B |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1008 B |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 736 B |
|
|
@ -1,15 +1 @@
|
|||
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M2 7C2 5.89543 2.89543 5 4 5H20C21.1046 5 22 5.89543 22 7V19C22 20.1046 21.1046 21 20 21H4C2.89543 21 2 20.1046 2 19V7Z"
|
||||
fill="transparent" />
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M20 7H4V19H20V7ZM4 5C2.89543 5 2 5.89543 2 7V19C2 20.1046 2.89543 21 4 21H20C21.1046 21 22 20.1046 22 19V7C22 5.89543 21.1046 5 20 5H4Z"
|
||||
fill="currentColor" />
|
||||
<path d="M12 3H24V15H12V3Z" fill="transparent" />
|
||||
<path
|
||||
d="M14 6C14 5.44772 14.4477 5 15 5H21C21.5523 5 22 5.44772 22 6V12C22 12.5523 21.5523 13 21 13H15C14.4477 13 14 12.5523 14 12V6Z"
|
||||
fill="transparent" />
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M16 7V11H20V7H16ZM15 5C14.4477 5 14 5.44772 14 6V12C14 12.5523 14.4477 13 15 13H21C21.5523 13 22 12.5523 22 12V6C22 5.44772 21.5523 5 21 5H15Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="transparent" d="M2 7a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V7Z"/><path fill="currentColor" fill-rule="evenodd" d="M20 7H4v12h16V7ZM4 5a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2H4Z" clip-rule="evenodd"/><path fill="transparent" d="M12 3h12v12H12V3Z"/><path fill="transparent" d="M14 6a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1h-6a1 1 0 0 1-1-1V6Z"/><path fill="currentColor" fill-rule="evenodd" d="M16 7v4h4V7h-4Zm-1-2a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1h-6Z" clip-rule="evenodd"/></svg>
|
||||
|
Before Width: | Height: | Size: 991 B After Width: | Height: | Size: 647 B |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 921 B |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 184 KiB After Width: | Height: | Size: 184 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 2.6 KiB |
|
|
@ -1,12 +1 @@
|
|||
<svg width="89" height="24" viewBox="0 0 89 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="24" height="24" rx="6" fill="#1D4ED8"/>
|
||||
<path d="M0 6C0 2.68629 2.68629 0 6 0H18C21.3137 0 24 2.68629 24 6V18C24 21.3137 21.3137 24 18 24H6C2.68629 24 0 21.3137 0 18V6Z" fill="#1D4ED8"/>
|
||||
<path d="M13.8854 12.0001C13.8854 13.0465 13.037 13.8949 11.9906 13.8949C10.9441 13.8949 10.0957 13.0465 10.0957 12.0001C10.0957 10.9536 10.9441 10.1052 11.9906 10.1052C13.037 10.1052 13.8854 10.9536 13.8854 12.0001Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.58968 9.36279C8.08026 9.54475 8.33045 10.09 8.14849 10.5805C7.9844 11.0229 7.89433 11.5023 7.89433 12.0048C7.89433 14.2684 9.73148 16.1051 11.9998 16.1051C14.268 16.1051 16.1052 14.2684 16.1052 12.0048C16.1052 11.5023 16.0151 11.0229 15.851 10.5805C15.6691 10.09 15.9192 9.54475 16.4098 9.36279C16.9004 9.18083 17.4456 9.43101 17.6276 9.92159C17.8687 10.5717 18 11.274 18 12.0048C18 15.3167 15.3127 17.9999 11.9998 17.9999C8.68682 17.9999 5.99951 15.3167 5.99951 12.0048C5.99951 11.274 6.13081 10.5717 6.37194 9.92159C6.5539 9.43101 7.09911 9.18083 7.58968 9.36279Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.9927 7.89481C11.3649 7.89481 10.7726 8.03489 10.243 8.28454C9.7697 8.50765 9.20516 8.30483 8.98206 7.83154C8.75895 7.35825 8.96177 6.79371 9.43506 6.57061C10.2121 6.20432 11.0799 6 11.9927 6C12.9056 6 13.7733 6.20432 14.5504 6.57061C15.0237 6.79371 15.2265 7.35825 15.0034 7.83154C14.7803 8.30483 14.2157 8.50765 13.7424 8.28454C13.2128 8.03489 12.6205 7.89481 11.9927 7.89481Z" fill="white"/>
|
||||
<path d="M0 6C0 2.68629 2.68629 0 6 0H18C21.3137 0 24 2.68629 24 6V18C24 21.3137 21.3137 24 18 24H6C2.68629 24 0 21.3137 0 18V6Z" fill="#1D4ED8"/>
|
||||
<path d="M13.8854 12.0001C13.8854 13.0465 13.037 13.8949 11.9906 13.8949C10.9441 13.8949 10.0957 13.0465 10.0957 12.0001C10.0957 10.9536 10.9441 10.1052 11.9906 10.1052C13.037 10.1052 13.8854 10.9536 13.8854 12.0001Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.58968 9.36279C8.08026 9.54475 8.33045 10.09 8.14849 10.5805C7.9844 11.0229 7.89433 11.5023 7.89433 12.0048C7.89433 14.2684 9.73148 16.1051 11.9998 16.1051C14.268 16.1051 16.1052 14.2684 16.1052 12.0048C16.1052 11.5023 16.0151 11.0229 15.851 10.5805C15.6691 10.09 15.9192 9.54475 16.4098 9.36279C16.9004 9.18083 17.4456 9.43101 17.6276 9.92159C17.8687 10.5717 18 11.274 18 12.0048C18 15.3167 15.3127 17.9999 11.9998 17.9999C8.68682 17.9999 5.99951 15.3167 5.99951 12.0048C5.99951 11.274 6.13081 10.5717 6.37194 9.92159C6.5539 9.43101 7.09911 9.18083 7.58968 9.36279Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.9927 7.89481C11.3649 7.89481 10.7726 8.03489 10.243 8.28454C9.7697 8.50765 9.20516 8.30483 8.98206 7.83154C8.75895 7.35825 8.96177 6.79371 9.43506 6.57061C10.2121 6.20432 11.0799 6 11.9927 6C12.9056 6 13.7733 6.20432 14.5504 6.57061C15.0237 6.79371 15.2265 7.35825 15.0034 7.83154C14.7803 8.30483 14.2157 8.50765 13.7424 8.28454C13.2128 8.03489 12.6205 7.89481 11.9927 7.89481Z" fill="white"/>
|
||||
<path d="M28.32 13.84L30.192 13.456V14.512C30.192 15.184 30.3573 15.6747 30.688 15.984C31.0187 16.2827 31.4347 16.432 31.936 16.432C32.448 16.432 32.8533 16.272 33.152 15.952C33.4507 15.6213 33.6 15.168 33.6 14.592V6.656H35.52V14.544C35.52 15.0453 35.4347 15.52 35.264 15.968C35.0933 16.416 34.8533 16.8107 34.544 17.152C34.2347 17.4827 33.8613 17.7493 33.424 17.952C32.9867 18.144 32.496 18.24 31.952 18.24C31.3973 18.24 30.896 18.1547 30.448 17.984C30 17.8027 29.616 17.552 29.296 17.232C28.9867 16.912 28.7467 16.528 28.576 16.08C28.4053 15.632 28.32 15.1307 28.32 14.576V13.84ZM42.9919 13.248C42.9812 13.024 42.9332 12.8107 42.8479 12.608C42.7732 12.3947 42.6559 12.208 42.4959 12.048C42.3359 11.888 42.1385 11.76 41.9039 11.664C41.6692 11.568 41.3919 11.52 41.0719 11.52C40.7839 11.52 40.5225 11.5733 40.2879 11.68C40.0639 11.776 39.8719 11.9093 39.7119 12.08C39.5519 12.24 39.4239 12.4267 39.3279 12.64C39.2319 12.8427 39.1785 13.0453 39.1679 13.248H42.9919ZM44.7679 15.776C44.6612 16.1173 44.5065 16.4373 44.3039 16.736C44.1012 17.0347 43.8505 17.296 43.5519 17.52C43.2532 17.744 42.9119 17.92 42.5279 18.048C42.1439 18.176 41.7172 18.24 41.2479 18.24C40.7145 18.24 40.2079 18.1493 39.7279 17.968C39.2479 17.776 38.8265 17.504 38.4639 17.152C38.1012 16.7893 37.8079 16.352 37.5839 15.84C37.3705 15.3173 37.2639 14.7253 37.2639 14.064C37.2639 13.4453 37.3652 12.8853 37.5679 12.384C37.7812 11.8827 38.0639 11.456 38.4159 11.104C38.7679 10.7413 39.1732 10.464 39.6319 10.272C40.0905 10.0693 40.5652 9.968 41.0559 9.968C41.6532 9.968 42.1865 10.064 42.6559 10.256C43.1359 10.448 43.5359 10.72 43.8559 11.072C44.1865 11.424 44.4372 11.8507 44.6079 12.352C44.7785 12.8427 44.8639 13.3973 44.8639 14.016C44.8639 14.1653 44.8585 14.2987 44.8479 14.416C44.8372 14.5227 44.8265 14.5867 44.8159 14.608H39.1199C39.1305 14.9067 39.1945 15.1787 39.3119 15.424C39.4292 15.6693 39.5839 15.8827 39.7759 16.064C39.9679 16.2453 40.1865 16.3893 40.4319 16.496C40.6879 16.592 40.9599 16.64 41.2479 16.64C41.8132 16.64 42.2452 16.512 42.5439 16.256C42.8532 15.9893 43.0719 15.664 43.1999 15.28L44.7679 15.776ZM48.9895 10.208H50.6055V11.856H48.9895V15.472C48.9895 15.8133 49.0695 16.064 49.2295 16.224C49.3895 16.3733 49.6402 16.448 49.9815 16.448C50.1095 16.448 50.2375 16.4427 50.3655 16.432C50.4935 16.4107 50.5788 16.3947 50.6215 16.384V17.92C50.5682 17.9413 50.4508 17.9733 50.2695 18.016C50.0882 18.0693 49.8268 18.096 49.4855 18.096C48.7602 18.096 48.1895 17.8933 47.7735 17.488C47.3575 17.0827 47.1495 16.512 47.1495 15.776V11.856H45.7095V10.208H46.1095C46.5255 10.208 46.8295 10.0907 47.0215 9.856C47.2135 9.62133 47.3095 9.33333 47.3095 8.992V7.824H48.9895V10.208ZM56.0653 13.088L54.5613 14.736V18H52.6413V6.656H54.5613V12.096L59.4413 6.656H61.9693L57.3773 11.664L62.0173 18H59.6013L56.0653 13.088ZM70.6701 6.656H72.7021L68.4141 18H66.4621L62.2381 6.656H64.3181L67.4861 15.488L70.6701 6.656ZM84.7954 18V9.648L81.2594 18H79.5954L76.0914 9.68V18H74.2194V6.656H76.7794L80.4594 15.312L84.0914 6.656H86.6994V18H84.7954Z" fill="#1D4ED8"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="89" height="24" fill="none"><rect width="24" height="24" fill="#1D4ED8" rx="6"/><path fill="#1D4ED8" d="M0 6a6 6 0 0 1 6-6h12a6 6 0 0 1 6 6v12a6 6 0 0 1-6 6H6a6 6 0 0 1-6-6V6Z"/><path fill="#fff" d="M13.885 12a1.895 1.895 0 1 1-3.79 0 1.895 1.895 0 0 1 3.79 0Z"/><path fill="#fff" fill-rule="evenodd" d="M7.59 9.363c.49.182.74.727.558 1.218A4.103 4.103 0 0 0 12 16.105a4.103 4.103 0 0 0 3.852-5.526.947.947 0 0 1 1.777-.658A5.998 5.998 0 0 1 12 18a5.998 5.998 0 0 1-5.628-8.078.947.947 0 0 1 1.218-.56ZM11.993 7.895c-.628 0-1.22.14-1.75.39a.947.947 0 1 1-.808-1.714A5.985 5.985 0 0 1 11.993 6c.913 0 1.78.204 2.557.57a.947.947 0 1 1-.808 1.715 4.09 4.09 0 0 0-1.75-.39Z" clip-rule="evenodd"/><path fill="#1D4ED8" d="M0 6a6 6 0 0 1 6-6h12a6 6 0 0 1 6 6v12a6 6 0 0 1-6 6H6a6 6 0 0 1-6-6V6Z"/><path fill="#fff" d="M13.885 12a1.895 1.895 0 1 1-3.79 0 1.895 1.895 0 0 1 3.79 0Z"/><path fill="#fff" fill-rule="evenodd" d="M7.59 9.363c.49.182.74.727.558 1.218A4.103 4.103 0 0 0 12 16.105a4.103 4.103 0 0 0 3.852-5.526.947.947 0 0 1 1.777-.658A5.998 5.998 0 0 1 12 18a5.998 5.998 0 0 1-5.628-8.078.947.947 0 0 1 1.218-.56ZM11.993 7.895c-.628 0-1.22.14-1.75.39a.947.947 0 1 1-.808-1.714A5.985 5.985 0 0 1 11.993 6c.913 0 1.78.204 2.557.57a.947.947 0 1 1-.808 1.715 4.09 4.09 0 0 0-1.75-.39Z" clip-rule="evenodd"/><path fill="#1D4ED8" d="m28.32 13.84 1.872-.384v1.056c0 .672.165 1.163.496 1.472.33.299.747.448 1.248.448.512 0 .917-.16 1.216-.48.299-.33.448-.784.448-1.36V6.656h1.92v7.888c0 .501-.085.976-.256 1.424-.17.448-.41.843-.72 1.184a3.57 3.57 0 0 1-1.12.8 3.625 3.625 0 0 1-1.472.288 4.196 4.196 0 0 1-1.504-.256 3.424 3.424 0 0 1-1.152-.752c-.31-.32-.55-.704-.72-1.152a4.196 4.196 0 0 1-.256-1.504v-.736Zm14.672-.592a1.866 1.866 0 0 0-.144-.64 1.469 1.469 0 0 0-.352-.56 1.776 1.776 0 0 0-.592-.384 2.19 2.19 0 0 0-.832-.144c-.288 0-.55.053-.784.16-.224.096-.416.23-.576.4-.16.16-.288.347-.384.56a1.61 1.61 0 0 0-.16.608h3.824Zm1.776 2.528a3.633 3.633 0 0 1-.464.96c-.203.299-.454.56-.752.784-.299.224-.64.4-1.024.528s-.81.192-1.28.192c-.533 0-1.04-.09-1.52-.272a3.846 3.846 0 0 1-1.264-.816 4.23 4.23 0 0 1-.88-1.312c-.214-.523-.32-1.115-.32-1.776 0-.619.101-1.179.304-1.68.213-.501.496-.928.848-1.28.352-.363.757-.64 1.216-.832a3.487 3.487 0 0 1 1.424-.304c.597 0 1.13.096 1.6.288.48.192.88.464 1.2.816.33.352.581.779.752 1.28.17.49.256 1.045.256 1.664 0 .15-.005.283-.016.4a.814.814 0 0 1-.032.192H39.12c.01.299.075.57.192.816.117.245.272.459.464.64s.41.325.656.432c.256.096.528.144.816.144.565 0 .997-.128 1.296-.384.31-.267.528-.592.656-.976l1.568.496Zm4.221-5.568h1.617v1.648h-1.617v3.616c0 .341.08.592.24.752.16.15.411.224.752.224.128 0 .256-.005.384-.016.128-.021.214-.037.256-.048v1.536c-.053.021-.17.053-.352.096-.18.053-.442.08-.783.08-.726 0-1.296-.203-1.712-.608-.416-.405-.624-.976-.624-1.712v-3.92h-1.44v-1.648h.4c.416 0 .72-.117.912-.352a1.32 1.32 0 0 0 .288-.864V7.824h1.68v2.384Zm7.076 2.88-1.504 1.648V18h-1.92V6.656h1.92v5.44l4.88-5.44h2.528l-4.592 5.008L62.017 18h-2.416l-3.536-4.912ZM70.67 6.656h2.032L68.414 18h-1.952L62.238 6.656h2.08l3.168 8.832 3.184-8.832ZM84.795 18V9.648L81.26 18h-1.664l-3.504-8.32V18H74.22V6.656h2.56l3.68 8.656 3.632-8.656H86.7V18h-1.904Z"/></svg>
|
||||
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 1.2 KiB |
|
|
@ -1,30 +1 @@
|
|||
<svg viewBox="0 0 89 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="24" height="24" rx="6" fill="#1D4ED8" />
|
||||
<path
|
||||
d="M0 6C0 2.68629 2.68629 0 6 0H18C21.3137 0 24 2.68629 24 6V18C24 21.3137 21.3137 24 18 24H6C2.68629 24 0 21.3137 0 18V6Z"
|
||||
fill="#1D4ED8" />
|
||||
<path
|
||||
d="M13.8854 12.0001C13.8854 13.0465 13.037 13.8949 11.9906 13.8949C10.9441 13.8949 10.0957 13.0465 10.0957 12.0001C10.0957 10.9536 10.9441 10.1052 11.9906 10.1052C13.037 10.1052 13.8854 10.9536 13.8854 12.0001Z"
|
||||
fill="white" />
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M7.58968 9.36279C8.08026 9.54475 8.33045 10.09 8.14849 10.5805C7.9844 11.0229 7.89433 11.5023 7.89433 12.0048C7.89433 14.2684 9.73148 16.1051 11.9998 16.1051C14.268 16.1051 16.1052 14.2684 16.1052 12.0048C16.1052 11.5023 16.0151 11.0229 15.851 10.5805C15.6691 10.09 15.9192 9.54475 16.4098 9.36279C16.9004 9.18083 17.4456 9.43101 17.6276 9.92159C17.8687 10.5717 18 11.274 18 12.0048C18 15.3167 15.3127 17.9999 11.9998 17.9999C8.68682 17.9999 5.99951 15.3167 5.99951 12.0048C5.99951 11.274 6.13081 10.5717 6.37194 9.92159C6.5539 9.43101 7.09911 9.18083 7.58968 9.36279Z"
|
||||
fill="white" />
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M11.9927 7.89481C11.3649 7.89481 10.7726 8.03489 10.243 8.28454C9.7697 8.50765 9.20516 8.30483 8.98206 7.83154C8.75895 7.35825 8.96177 6.79371 9.43506 6.57061C10.2121 6.20432 11.0799 6 11.9927 6C12.9056 6 13.7733 6.20432 14.5504 6.57061C15.0237 6.79371 15.2265 7.35825 15.0034 7.83154C14.7803 8.30483 14.2157 8.50765 13.7424 8.28454C13.2128 8.03489 12.6205 7.89481 11.9927 7.89481Z"
|
||||
fill="white" />
|
||||
<path
|
||||
d="M0 6C0 2.68629 2.68629 0 6 0H18C21.3137 0 24 2.68629 24 6V18C24 21.3137 21.3137 24 18 24H6C2.68629 24 0 21.3137 0 18V6Z"
|
||||
fill="#1D4ED8" />
|
||||
<path
|
||||
d="M13.8854 12.0001C13.8854 13.0465 13.037 13.8949 11.9906 13.8949C10.9441 13.8949 10.0957 13.0465 10.0957 12.0001C10.0957 10.9536 10.9441 10.1052 11.9906 10.1052C13.037 10.1052 13.8854 10.9536 13.8854 12.0001Z"
|
||||
fill="white" />
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M7.58968 9.36279C8.08026 9.54475 8.33045 10.09 8.14849 10.5805C7.9844 11.0229 7.89433 11.5023 7.89433 12.0048C7.89433 14.2684 9.73148 16.1051 11.9998 16.1051C14.268 16.1051 16.1052 14.2684 16.1052 12.0048C16.1052 11.5023 16.0151 11.0229 15.851 10.5805C15.6691 10.09 15.9192 9.54475 16.4098 9.36279C16.9004 9.18083 17.4456 9.43101 17.6276 9.92159C17.8687 10.5717 18 11.274 18 12.0048C18 15.3167 15.3127 17.9999 11.9998 17.9999C8.68682 17.9999 5.99951 15.3167 5.99951 12.0048C5.99951 11.274 6.13081 10.5717 6.37194 9.92159C6.5539 9.43101 7.09911 9.18083 7.58968 9.36279Z"
|
||||
fill="white" />
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M11.9927 7.89481C11.3649 7.89481 10.7726 8.03489 10.243 8.28454C9.7697 8.50765 9.20516 8.30483 8.98206 7.83154C8.75895 7.35825 8.96177 6.79371 9.43506 6.57061C10.2121 6.20432 11.0799 6 11.9927 6C12.9056 6 13.7733 6.20432 14.5504 6.57061C15.0237 6.79371 15.2265 7.35825 15.0034 7.83154C14.7803 8.30483 14.2157 8.50765 13.7424 8.28454C13.2128 8.03489 12.6205 7.89481 11.9927 7.89481Z"
|
||||
fill="white" />
|
||||
<path
|
||||
d="M28.32 13.84L30.192 13.456V14.512C30.192 15.184 30.3573 15.6747 30.688 15.984C31.0187 16.2827 31.4347 16.432 31.936 16.432C32.448 16.432 32.8533 16.272 33.152 15.952C33.4507 15.6213 33.6 15.168 33.6 14.592V6.656H35.52V14.544C35.52 15.0453 35.4347 15.52 35.264 15.968C35.0933 16.416 34.8533 16.8107 34.544 17.152C34.2347 17.4827 33.8613 17.7493 33.424 17.952C32.9867 18.144 32.496 18.24 31.952 18.24C31.3973 18.24 30.896 18.1547 30.448 17.984C30 17.8027 29.616 17.552 29.296 17.232C28.9867 16.912 28.7467 16.528 28.576 16.08C28.4053 15.632 28.32 15.1307 28.32 14.576V13.84ZM42.9919 13.248C42.9812 13.024 42.9332 12.8107 42.8479 12.608C42.7732 12.3947 42.6559 12.208 42.4959 12.048C42.3359 11.888 42.1385 11.76 41.9039 11.664C41.6692 11.568 41.3919 11.52 41.0719 11.52C40.7839 11.52 40.5225 11.5733 40.2879 11.68C40.0639 11.776 39.8719 11.9093 39.7119 12.08C39.5519 12.24 39.4239 12.4267 39.3279 12.64C39.2319 12.8427 39.1785 13.0453 39.1679 13.248H42.9919ZM44.7679 15.776C44.6612 16.1173 44.5065 16.4373 44.3039 16.736C44.1012 17.0347 43.8505 17.296 43.5519 17.52C43.2532 17.744 42.9119 17.92 42.5279 18.048C42.1439 18.176 41.7172 18.24 41.2479 18.24C40.7145 18.24 40.2079 18.1493 39.7279 17.968C39.2479 17.776 38.8265 17.504 38.4639 17.152C38.1012 16.7893 37.8079 16.352 37.5839 15.84C37.3705 15.3173 37.2639 14.7253 37.2639 14.064C37.2639 13.4453 37.3652 12.8853 37.5679 12.384C37.7812 11.8827 38.0639 11.456 38.4159 11.104C38.7679 10.7413 39.1732 10.464 39.6319 10.272C40.0905 10.0693 40.5652 9.968 41.0559 9.968C41.6532 9.968 42.1865 10.064 42.6559 10.256C43.1359 10.448 43.5359 10.72 43.8559 11.072C44.1865 11.424 44.4372 11.8507 44.6079 12.352C44.7785 12.8427 44.8639 13.3973 44.8639 14.016C44.8639 14.1653 44.8585 14.2987 44.8479 14.416C44.8372 14.5227 44.8265 14.5867 44.8159 14.608H39.1199C39.1305 14.9067 39.1945 15.1787 39.3119 15.424C39.4292 15.6693 39.5839 15.8827 39.7759 16.064C39.9679 16.2453 40.1865 16.3893 40.4319 16.496C40.6879 16.592 40.9599 16.64 41.2479 16.64C41.8132 16.64 42.2452 16.512 42.5439 16.256C42.8532 15.9893 43.0719 15.664 43.1999 15.28L44.7679 15.776ZM48.9895 10.208H50.6055V11.856H48.9895V15.472C48.9895 15.8133 49.0695 16.064 49.2295 16.224C49.3895 16.3733 49.6402 16.448 49.9815 16.448C50.1095 16.448 50.2375 16.4427 50.3655 16.432C50.4935 16.4107 50.5788 16.3947 50.6215 16.384V17.92C50.5682 17.9413 50.4508 17.9733 50.2695 18.016C50.0882 18.0693 49.8268 18.096 49.4855 18.096C48.7602 18.096 48.1895 17.8933 47.7735 17.488C47.3575 17.0827 47.1495 16.512 47.1495 15.776V11.856H45.7095V10.208H46.1095C46.5255 10.208 46.8295 10.0907 47.0215 9.856C47.2135 9.62133 47.3095 9.33333 47.3095 8.992V7.824H48.9895V10.208ZM56.0653 13.088L54.5613 14.736V18H52.6413V6.656H54.5613V12.096L59.4413 6.656H61.9693L57.3773 11.664L62.0173 18H59.6013L56.0653 13.088ZM70.6701 6.656H72.7021L68.4141 18H66.4621L62.2381 6.656H64.3181L67.4861 15.488L70.6701 6.656ZM84.7954 18V9.648L81.2594 18H79.5954L76.0914 9.68V18H74.2194V6.656H76.7794L80.4594 15.312L84.0914 6.656H86.6994V18H84.7954Z"
|
||||
fill="white" />
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 89 24"><rect width="24" height="24" fill="#1D4ED8" rx="6"/><path fill="#1D4ED8" d="M0 6a6 6 0 0 1 6-6h12a6 6 0 0 1 6 6v12a6 6 0 0 1-6 6H6a6 6 0 0 1-6-6V6Z"/><path fill="#fff" d="M13.885 12a1.895 1.895 0 1 1-3.79 0 1.895 1.895 0 0 1 3.79 0Z"/><path fill="#fff" fill-rule="evenodd" d="M7.59 9.363c.49.182.74.727.558 1.218A4.103 4.103 0 0 0 12 16.105a4.103 4.103 0 0 0 3.852-5.526.947.947 0 0 1 1.777-.658A5.998 5.998 0 0 1 12 18a5.998 5.998 0 0 1-5.628-8.078.947.947 0 0 1 1.218-.56ZM11.993 7.895c-.628 0-1.22.14-1.75.39a.947.947 0 1 1-.808-1.714A5.985 5.985 0 0 1 11.993 6c.913 0 1.78.204 2.557.57a.947.947 0 1 1-.808 1.715 4.09 4.09 0 0 0-1.75-.39Z" clip-rule="evenodd"/><path fill="#1D4ED8" d="M0 6a6 6 0 0 1 6-6h12a6 6 0 0 1 6 6v12a6 6 0 0 1-6 6H6a6 6 0 0 1-6-6V6Z"/><path fill="#fff" d="M13.885 12a1.895 1.895 0 1 1-3.79 0 1.895 1.895 0 0 1 3.79 0Z"/><path fill="#fff" fill-rule="evenodd" d="M7.59 9.363c.49.182.74.727.558 1.218A4.103 4.103 0 0 0 12 16.105a4.103 4.103 0 0 0 3.852-5.526.947.947 0 0 1 1.777-.658A5.998 5.998 0 0 1 12 18a5.998 5.998 0 0 1-5.628-8.078.947.947 0 0 1 1.218-.56ZM11.993 7.895c-.628 0-1.22.14-1.75.39a.947.947 0 1 1-.808-1.714A5.985 5.985 0 0 1 11.993 6c.913 0 1.78.204 2.557.57a.947.947 0 1 1-.808 1.715 4.09 4.09 0 0 0-1.75-.39Z" clip-rule="evenodd"/><path fill="#fff" d="m28.32 13.84 1.872-.384v1.056c0 .672.165 1.163.496 1.472.33.299.747.448 1.248.448.512 0 .917-.16 1.216-.48.299-.33.448-.784.448-1.36V6.656h1.92v7.888c0 .501-.085.976-.256 1.424-.17.448-.41.843-.72 1.184a3.57 3.57 0 0 1-1.12.8 3.625 3.625 0 0 1-1.472.288 4.196 4.196 0 0 1-1.504-.256 3.424 3.424 0 0 1-1.152-.752c-.31-.32-.55-.704-.72-1.152a4.196 4.196 0 0 1-.256-1.504v-.736Zm14.672-.592a1.866 1.866 0 0 0-.144-.64 1.469 1.469 0 0 0-.352-.56 1.776 1.776 0 0 0-.592-.384 2.19 2.19 0 0 0-.832-.144c-.288 0-.55.053-.784.16-.224.096-.416.23-.576.4-.16.16-.288.347-.384.56a1.61 1.61 0 0 0-.16.608h3.824Zm1.776 2.528a3.633 3.633 0 0 1-.464.96c-.203.299-.454.56-.752.784-.299.224-.64.4-1.024.528s-.81.192-1.28.192c-.533 0-1.04-.09-1.52-.272a3.846 3.846 0 0 1-1.264-.816 4.23 4.23 0 0 1-.88-1.312c-.214-.523-.32-1.115-.32-1.776 0-.619.101-1.179.304-1.68.213-.501.496-.928.848-1.28.352-.363.757-.64 1.216-.832a3.487 3.487 0 0 1 1.424-.304c.597 0 1.13.096 1.6.288.48.192.88.464 1.2.816.33.352.581.779.752 1.28.17.49.256 1.045.256 1.664 0 .15-.005.283-.016.4a.814.814 0 0 1-.032.192H39.12c.01.299.075.57.192.816.117.245.272.459.464.64s.41.325.656.432c.256.096.528.144.816.144.565 0 .997-.128 1.296-.384.31-.267.528-.592.656-.976l1.568.496Zm4.221-5.568h1.617v1.648h-1.617v3.616c0 .341.08.592.24.752.16.15.411.224.752.224.128 0 .256-.005.384-.016.128-.021.214-.037.256-.048v1.536c-.053.021-.17.053-.352.096-.18.053-.442.08-.783.08-.726 0-1.296-.203-1.712-.608-.416-.405-.624-.976-.624-1.712v-3.92h-1.44v-1.648h.4c.416 0 .72-.117.912-.352a1.32 1.32 0 0 0 .288-.864V7.824h1.68v2.384Zm7.076 2.88-1.504 1.648V18h-1.92V6.656h1.92v5.44l4.88-5.44h2.528l-4.592 5.008L62.017 18h-2.416l-3.536-4.912ZM70.67 6.656h2.032L68.414 18h-1.952L62.238 6.656h2.08l3.168 8.832 3.184-8.832ZM84.795 18V9.648L81.26 18h-1.664l-3.504-8.32V18H74.22V6.656h2.56l3.68 8.656 3.632-8.656H86.7V18h-1.904Z"/></svg>
|
||||
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 2.6 KiB |
|
|
@ -1,11 +1 @@
|
|||
<svg viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_3161_210)">
|
||||
<path d="M11.5 1V7.60833H17.3333C17.3333 4.20833 14.7917 1.40833 11.5 1ZM4 12.6083C4 16.2917 6.98333 19.275 10.6667 19.275C14.35 19.275 17.3333 16.2917 17.3333 12.6083V9.275H4V12.6083ZM9.83333 1C6.54167 1.40833 4 4.20833 4 7.60833H9.83333V1Z"
|
||||
fill="black"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_3161_210">
|
||||
<rect width="20" height="20" fill="white" transform="translate(0.5)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 21 20"><g clip-path="url(#a)"><path fill="#000" d="M11.5 1v6.608h5.833c0-3.4-2.541-6.2-5.833-6.608ZM4 12.608a6.665 6.665 0 0 0 6.667 6.667 6.665 6.665 0 0 0 6.666-6.667V9.275H4v3.333ZM9.833 1A6.657 6.657 0 0 0 4 7.608h5.833V1Z"/></g><defs><clipPath id="a"><path fill="#fff" d="M.5 0h20v20H.5z"/></clipPath></defs></svg>
|
||||
|
Before Width: | Height: | Size: 575 B After Width: | Height: | Size: 384 B |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 2.5 KiB |
|
|
@ -1,11 +1 @@
|
|||
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_3161_200)">
|
||||
<path d="M7.49967 9.36667V6.25C7.49967 5.69747 7.71917 5.16756 8.10987 4.77686C8.50057 4.38616 9.03047 4.16667 9.58301 4.16667C10.1355 4.16667 10.6654 4.38616 11.0561 4.77686C11.4468 5.16756 11.6663 5.69747 11.6663 6.25V9.36667C12.6747 8.69167 13.333 7.55 13.333 6.25C13.333 4.175 11.658 2.5 9.58301 2.5C7.50801 2.5 5.83301 4.175 5.83301 6.25C5.83301 7.55 6.49134 8.69167 7.49967 9.36667ZM15.6997 13.225L11.9163 11.3417C11.7747 11.2833 11.6247 11.25 11.4663 11.25H10.833V6.25C10.833 5.55833 10.2747 5 9.58301 5C8.89134 5 8.33301 5.55833 8.33301 6.25V15.2C5.33301 14.5667 5.38301 14.575 5.27467 14.575C5.01634 14.575 4.78301 14.6833 4.61634 14.85L3.95801 15.5167L8.07467 19.6333C8.29967 19.8583 8.61634 20 8.95801 20H14.6163C15.2413 20 15.7247 19.5417 15.8163 18.9333L16.4413 14.5417C16.4497 14.4833 16.458 14.425 16.458 14.375C16.458 13.8583 16.1413 13.4083 15.6997 13.225Z"
|
||||
fill="black"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_3161_200">
|
||||
<rect width="20" height="20" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 20 20"><g clip-path="url(#a)"><path fill="#000" d="M7.5 9.367V6.25a2.083 2.083 0 0 1 4.166 0v3.117a3.738 3.738 0 0 0 1.667-3.117 3.745 3.745 0 0 0-3.75-3.75 3.745 3.745 0 0 0-3.75 3.75c0 1.3.658 2.442 1.667 3.117Zm8.2 3.858-3.784-1.883a1.172 1.172 0 0 0-.45-.092h-.633v-5c0-.692-.558-1.25-1.25-1.25s-1.25.558-1.25 1.25v8.95c-3-.633-2.95-.625-3.058-.625a.932.932 0 0 0-.659.275l-.658.667 4.117 4.116c.225.225.541.367.883.367h5.658c.625 0 1.109-.458 1.2-1.067l.625-4.391c.009-.059.017-.117.017-.167 0-.517-.317-.967-.758-1.15Z"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h20v20H0z"/></clipPath></defs></svg>
|
||||
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 680 B |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1005 B After Width: | Height: | Size: 857 B |
|
|
@ -207,8 +207,8 @@ export function MacroStepCard({
|
|||
)}
|
||||
<div className="relative w-full">
|
||||
<Combobox
|
||||
onChange={(value: { value: string; label: string }) => {
|
||||
onKeySelect(value);
|
||||
onChange={(value) => {
|
||||
onKeySelect({ value: value as string | null });
|
||||
onKeyQueryChange('');
|
||||
}}
|
||||
displayValue={() => keyQuery}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import { TextAreaWithLabel } from "@components/TextArea";
|
|||
|
||||
// uint32 max value / 4
|
||||
const pasteMaxLength = 1073741824;
|
||||
const defaultDelay = 20;
|
||||
|
||||
export default function PasteModal() {
|
||||
const TextAreaRef = useRef<HTMLTextAreaElement>(null);
|
||||
|
|
@ -27,10 +28,10 @@ export default function PasteModal() {
|
|||
const { executeMacro, cancelExecuteMacro } = useKeyboard();
|
||||
|
||||
const [invalidChars, setInvalidChars] = useState<string[]>([]);
|
||||
const [delayValue, setDelayValue] = useState(100);
|
||||
const [delayValue, setDelayValue] = useState(defaultDelay);
|
||||
const delay = useMemo(() => {
|
||||
if (delayValue < 50 || delayValue > 65534) {
|
||||
return 100;
|
||||
if (delayValue < 0 || delayValue > 65534) {
|
||||
return defaultDelay;
|
||||
}
|
||||
return delayValue;
|
||||
}, [delayValue]);
|
||||
|
|
@ -40,7 +41,7 @@ export default function PasteModal() {
|
|||
const delayClassName = useMemo(() => debugMode ? "" : "hidden", [debugMode]);
|
||||
|
||||
const { setKeyboardLayout } = useSettingsStore();
|
||||
const { selectedKeyboard } = useKeyboardLayout();
|
||||
const { selectedKeyboard } = useKeyboardLayout();
|
||||
|
||||
useEffect(() => {
|
||||
send("getKeyboardLayout", {}, (resp: JsonRpcResponse) => {
|
||||
|
|
@ -136,7 +137,8 @@ export default function PasteModal() {
|
|||
<div
|
||||
className="w-full"
|
||||
onKeyUp={e => e.stopPropagation()}
|
||||
onKeyDown={e => e.stopPropagation()} onKeyDownCapture={e => e.stopPropagation()}
|
||||
onKeyDown={e => e.stopPropagation()}
|
||||
onKeyDownCapture={e => e.stopPropagation()}
|
||||
onKeyUpCapture={e => e.stopPropagation()}
|
||||
>
|
||||
<TextAreaWithLabel
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useEffect, useState } from "react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
import { Button } from "@/components/Button";
|
||||
import { TextAreaWithLabel } from "@/components/TextArea";
|
||||
|
|
@ -52,7 +52,7 @@ export default function SettingsVideoRoute() {
|
|||
const [customEdidValue, setCustomEdidValue] = useState<string | null>(null);
|
||||
const [edid, setEdid] = useState<string | null>(null);
|
||||
const [edidLoading, setEdidLoading] = useState(false);
|
||||
|
||||
const { debugMode } = useSettingsStore();
|
||||
// Video enhancement settings from store
|
||||
const {
|
||||
videoSaturation,
|
||||
|
|
@ -132,6 +132,26 @@ export default function SettingsVideoRoute() {
|
|||
});
|
||||
};
|
||||
|
||||
const [debugInfo, setDebugInfo] = useState<string | null>(null);
|
||||
const [debugInfoLoading, setDebugInfoLoading] = useState(false);
|
||||
const getDebugInfo = useCallback(() => {
|
||||
setDebugInfoLoading(true);
|
||||
send("getVideoLogStatus", {}, (resp: JsonRpcResponse) => {
|
||||
if ("error" in resp) {
|
||||
notifications.error(`Failed to get debug info: ${resp.error.data || "Unknown error"}`);
|
||||
setDebugInfoLoading(false);
|
||||
return;
|
||||
}
|
||||
const data = resp.result as string;
|
||||
setDebugInfo(data
|
||||
.split("\n")
|
||||
.map(line => line.trim().replace(/^\[\s*\d+\.\d+\]\s*/, ""))
|
||||
.join("\n")
|
||||
);
|
||||
setDebugInfoLoading(false);
|
||||
});
|
||||
}, [send]);
|
||||
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
<div className="space-y-4">
|
||||
|
|
@ -279,6 +299,30 @@ export default function SettingsVideoRoute() {
|
|||
)}
|
||||
</Fieldset>
|
||||
</div>
|
||||
|
||||
|
||||
{debugMode && (
|
||||
<div className="space-y-4">
|
||||
<SettingsItem
|
||||
title="Debugging Info"
|
||||
description="Debugging information for video"
|
||||
>
|
||||
<Button size="SM" theme="primary" text="Get Debugging Info"
|
||||
loading={debugInfoLoading}
|
||||
disabled={debugInfoLoading}
|
||||
onClick={() => {
|
||||
getDebugInfo();
|
||||
}} />
|
||||
</SettingsItem>
|
||||
{debugInfo && (
|
||||
<div className="font-mono bg-gray-100 dark:bg-gray-800 p-2 rounded-md text-xs max-h-64 overflow-y-auto">
|
||||
<pre className="whitespace-pre-wrap">
|
||||
{debugInfo}
|
||||
</pre>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
25
video.go
|
|
@ -1,13 +1,8 @@
|
|||
package kvm
|
||||
|
||||
import "github.com/jetkvm/kvm/internal/native"
|
||||
|
||||
// max frame size for 1080p video, specified in mpp venc setting
|
||||
const maxFrameSize = 1920 * 1080 / 2
|
||||
|
||||
func writeCtrlAction(action string) error {
|
||||
return nil
|
||||
}
|
||||
import (
|
||||
"github.com/jetkvm/kvm/internal/native"
|
||||
)
|
||||
|
||||
var lastVideoState native.VideoState
|
||||
|
||||
|
|
@ -15,19 +10,9 @@ func triggerVideoStateUpdate() {
|
|||
go func() {
|
||||
writeJSONRPCEvent("videoInputState", lastVideoState, currentSession)
|
||||
}()
|
||||
}
|
||||
|
||||
// func HandleVideoStateMessage(event CtrlResponse) {
|
||||
// videoState := VideoInputState{}
|
||||
// err := json.Unmarshal(event.Data, &videoState)
|
||||
// if err != nil {
|
||||
// logger.Warn().Err(err).Msg("Error parsing video state json")
|
||||
// return
|
||||
// }
|
||||
// lastVideoState = videoState
|
||||
// triggerVideoStateUpdate()
|
||||
// requestDisplayUpdate(true)
|
||||
// }
|
||||
nativeLogger.Info().Interface("state", lastVideoState).Msg("video state updated")
|
||||
}
|
||||
|
||||
func rpcGetVideoState() (native.VideoState, error) {
|
||||
return lastVideoState, nil
|
||||
|
|
|
|||