mirror of https://github.com/jetkvm/kvm.git
Compare commits
10 Commits
358981128b
...
23a3aaa61d
| Author | SHA1 | Date |
|---|---|---|
|
|
23a3aaa61d | |
|
|
358512fa83 | |
|
|
70db172287 | |
|
|
76c4144565 | |
|
|
e9bcdc5f3f | |
|
|
028cb7ddd6 | |
|
|
e930363b24 | |
|
|
f106d308a3 | |
|
|
b042adac67 | |
|
|
e582486bec |
|
|
@ -1,8 +1,19 @@
|
||||||
#!/bin/bash
|
#!/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 \
|
build-essential \
|
||||||
device-tree-compiler \
|
device-tree-compiler \
|
||||||
gperf g++-multilib gcc-multilib \
|
gperf g++-multilib gcc-multilib \
|
||||||
|
|
|
||||||
|
|
@ -3,5 +3,6 @@
|
||||||
"cva",
|
"cva",
|
||||||
"cx"
|
"cx"
|
||||||
],
|
],
|
||||||
"cmake.sourceDirectory": "/Users/aveline/Projects/JetKVM/ymjk/internal/native/cgo"
|
"cmake.sourceDirectory": "/Users/aveline/Projects/JetKVM/ymjk/internal/native/cgo",
|
||||||
|
"git.ignoreLimitWarning": true
|
||||||
}
|
}
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
# syntax=docker/dockerfile:1
|
# syntax=docker/dockerfile:1
|
||||||
FROM golang:1.25.1-trixie
|
FROM --platform=${BUILDPLATFORM} golang:1.25.1-trixie AS builder
|
||||||
|
|
||||||
ENV GOTOOLCHAIN=local
|
ENV GOTOOLCHAIN=local
|
||||||
ENV GOPATH /go
|
ENV GOPATH=/go
|
||||||
ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH
|
ENV PATH=$GOPATH/bin:/usr/local/go/bin:$PATH
|
||||||
|
|
||||||
ADD .devcontainer/install-deps.sh /install-deps.sh
|
COPY .devcontainer/install-deps.sh /install-deps.sh
|
||||||
RUN /install-deps.sh
|
RUN /install-deps.sh
|
||||||
|
|
||||||
# Create build directory
|
# Create build directory
|
||||||
|
|
|
||||||
16
Makefile
16
Makefile
|
|
@ -3,15 +3,15 @@ BUILDDATE := $(shell date -u +%FT%T%z)
|
||||||
BUILDTS := $(shell date -u +%s)
|
BUILDTS := $(shell date -u +%s)
|
||||||
REVISION := $(shell git rev-parse HEAD)
|
REVISION := $(shell git rev-parse HEAD)
|
||||||
VERSION_DEV := 0.4.8-dev$(shell date +%Y%m%d%H%M)
|
VERSION_DEV := 0.4.8-dev$(shell date +%Y%m%d%H%M)
|
||||||
VERSION := 0.4.7
|
VERSION := 0.4.9
|
||||||
|
|
||||||
PROMETHEUS_TAG := github.com/prometheus/common/version
|
PROMETHEUS_TAG := github.com/prometheus/common/version
|
||||||
KVM_PKG_NAME := github.com/jetkvm/kvm
|
KVM_PKG_NAME := github.com/jetkvm/kvm
|
||||||
|
|
||||||
BUILDKIT_FLAVOR := arm-rockchip830-linux-uclibcgnueabihf
|
BUILDKIT_FLAVOR := arm-rockchip830-linux-uclibcgnueabihf
|
||||||
BUILDKIT_PATH ?= /opt/jetkvm-native-buildkit
|
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_BUILD_ARGS := -tags netgo -tags timetzdata
|
||||||
GO_RELEASE_BUILD_ARGS := -trimpath $(GO_BUILD_ARGS)
|
GO_RELEASE_BUILD_ARGS := -trimpath $(GO_BUILD_ARGS)
|
||||||
|
|
@ -88,6 +88,9 @@ build_dev_test: build_test2json build_gotestsum
|
||||||
tar czfv device-tests.tar.gz -C $(BIN_DIR)/tests .
|
tar czfv device-tests.tar.gz -C $(BIN_DIR)/tests .
|
||||||
|
|
||||||
frontend:
|
frontend:
|
||||||
|
@if [ "$(SKIP_UI_BUILD)" = "1" ]; then \
|
||||||
|
echo "Skipping frontend build..."; \
|
||||||
|
else \
|
||||||
cd ui && npm ci && npm run build:device && \
|
cd ui && npm ci && npm run build:device && \
|
||||||
find ../static/ \
|
find ../static/ \
|
||||||
-type f \
|
-type f \
|
||||||
|
|
@ -102,8 +105,9 @@ frontend:
|
||||||
-o -name '*.svg' \
|
-o -name '*.svg' \
|
||||||
-o -name '*.webp' \
|
-o -name '*.webp' \
|
||||||
-o -name '*.woff2' \
|
-o -name '*.woff2' \
|
||||||
\) \
|
\) \
|
||||||
-exec sh -c 'gzip -9 -kfv {}' \;
|
-exec sh -c 'gzip -9 -kfv {}' \; \
|
||||||
|
fi
|
||||||
|
|
||||||
dev_release: frontend build_dev
|
dev_release: frontend build_dev
|
||||||
@echo "Uploading release... $(VERSION_DEV)"
|
@echo "Uploading release... $(VERSION_DEV)"
|
||||||
|
|
@ -111,7 +115,7 @@ dev_release: frontend build_dev
|
||||||
rclone copyto bin/jetkvm_app r2://jetkvm-update/app/$(VERSION_DEV)/jetkvm_app
|
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
|
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..."
|
@echo "Building release..."
|
||||||
$(GO_CMD) build \
|
$(GO_CMD) build \
|
||||||
-ldflags="$(GO_LDFLAGS) -X $(KVM_PKG_NAME).builtAppVersion=$(VERSION)" \
|
-ldflags="$(GO_LDFLAGS) -X $(KVM_PKG_NAME).builtAppVersion=$(VERSION)" \
|
||||||
|
|
|
||||||
|
|
@ -41,12 +41,16 @@ show_help() {
|
||||||
REMOTE_USER="root"
|
REMOTE_USER="root"
|
||||||
REMOTE_PATH="/userdata/jetkvm/bin"
|
REMOTE_PATH="/userdata/jetkvm/bin"
|
||||||
SKIP_UI_BUILD=false
|
SKIP_UI_BUILD=false
|
||||||
|
SKIP_UI_BUILD_RELEASE=0
|
||||||
SKIP_NATIVE_BUILD=0
|
SKIP_NATIVE_BUILD=0
|
||||||
RESET_USB_HID_DEVICE=false
|
RESET_USB_HID_DEVICE=false
|
||||||
LOG_TRACE_SCOPES="${LOG_TRACE_SCOPES:-jetkvm,cloud,websocket,native,jsonrpc}"
|
LOG_TRACE_SCOPES="${LOG_TRACE_SCOPES:-jetkvm,cloud,websocket,native,jsonrpc}"
|
||||||
RUN_GO_TESTS=false
|
RUN_GO_TESTS=false
|
||||||
RUN_GO_TESTS_ONLY=false
|
RUN_GO_TESTS_ONLY=false
|
||||||
INSTALL_APP=false
|
INSTALL_APP=false
|
||||||
|
BUILD_IN_DOCKER=false
|
||||||
|
DOCKER_BUILD_DEBUG=false
|
||||||
|
DOCKER_BUILD_TAG=ghcr.io/jetkvm/buildkit:latest
|
||||||
|
|
||||||
# Parse command line arguments
|
# Parse command line arguments
|
||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
|
|
@ -71,6 +75,14 @@ while [[ $# -gt 0 ]]; do
|
||||||
RESET_USB_HID_DEVICE=true
|
RESET_USB_HID_DEVICE=true
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
|
--build-in-docker)
|
||||||
|
BUILD_IN_DOCKER=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--docker-build-debug)
|
||||||
|
DOCKER_BUILD_DEBUG=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
--run-go-tests)
|
--run-go-tests)
|
||||||
RUN_GO_TESTS=true
|
RUN_GO_TESTS=true
|
||||||
shift
|
shift
|
||||||
|
|
@ -103,10 +115,59 @@ if [ -z "$REMOTE_HOST" ]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
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
|
||||||
|
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
|
||||||
|
msg_info "▶ Building build environment ..."
|
||||||
|
TMP_DIR=$(mktemp -d)
|
||||||
|
cp -r .devcontainer "${TMP_DIR}"
|
||||||
|
cp go.mod go.sum Dockerfile.build "${TMP_DIR}"
|
||||||
|
pushd "${TMP_DIR}" > /dev/null
|
||||||
|
docker build $BUILD_ARGS -t ${DOCKER_BUILD_TAG} -f Dockerfile.build .
|
||||||
|
popd > /dev/null
|
||||||
|
rm -rf "${TMP_DIR}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
do_make() {
|
||||||
|
if [ "$BUILD_IN_DOCKER" = true ]; then
|
||||||
|
msg_info "▶ Building the project in Docker ..."
|
||||||
|
docker run \
|
||||||
|
--interactive \
|
||||||
|
--tty \
|
||||||
|
--rm \
|
||||||
|
--env JETKVM_INSIDE_DOCKER=1 \
|
||||||
|
-v "$(pwd):/build" \
|
||||||
|
${DOCKER_BUILD_TAG} make "$@"
|
||||||
|
else
|
||||||
|
make "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# Build the development version on the host
|
# Build the development version on the host
|
||||||
if [ "$SKIP_UI_BUILD" = false ]; then
|
# 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"
|
msg_info "▶ Building frontend"
|
||||||
make frontend
|
make frontend SKIP_UI_BUILD=0
|
||||||
|
SKIP_UI_BUILD_RELEASE=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$RUN_GO_TESTS" = true ]; then
|
if [ "$RUN_GO_TESTS" = true ]; then
|
||||||
|
|
@ -154,7 +215,7 @@ fi
|
||||||
if [ "$INSTALL_APP" = true ]
|
if [ "$INSTALL_APP" = true ]
|
||||||
then
|
then
|
||||||
msg_info "▶ Building release binary"
|
msg_info "▶ Building release binary"
|
||||||
make build_release SKIP_NATIVE_IF_EXISTS=${SKIP_NATIVE_BUILD}
|
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.
|
# 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
|
ssh "${REMOTE_USER}@${REMOTE_HOST}" "cat > /userdata/jetkvm/jetkvm_app.update" < bin/jetkvm_app
|
||||||
|
|
@ -163,7 +224,7 @@ then
|
||||||
ssh "${REMOTE_USER}@${REMOTE_HOST}" "reboot"
|
ssh "${REMOTE_USER}@${REMOTE_HOST}" "reboot"
|
||||||
else
|
else
|
||||||
msg_info "▶ Building development binary"
|
msg_info "▶ Building development binary"
|
||||||
make build_dev SKIP_NATIVE_IF_EXISTS=${SKIP_NATIVE_BUILD}
|
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
|
# Kill any existing instances of the application
|
||||||
ssh "${REMOTE_USER}@${REMOTE_HOST}" "killall jetkvm_app_debug || true"
|
ssh "${REMOTE_USER}@${REMOTE_HOST}" "killall jetkvm_app_debug || true"
|
||||||
|
|
|
||||||
11
display.go
11
display.go
|
|
@ -23,7 +23,6 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
touchscreenDevice string = "/dev/input/event1"
|
|
||||||
backlightControlClass string = "/sys/class/backlight/backlight/brightness"
|
backlightControlClass string = "/sys/class/backlight/backlight/brightness"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -38,23 +37,25 @@ func updateDisplay() {
|
||||||
|
|
||||||
if usbState == "configured" {
|
if usbState == "configured" {
|
||||||
nativeInstance.UpdateLabelIfChanged("usb_status_label", "Connected")
|
nativeInstance.UpdateLabelIfChanged("usb_status_label", "Connected")
|
||||||
_, _ = nativeInstance.UIObjSetState("usb_status", "LV_STATE_DEFAULT")
|
_, _ = nativeInstance.UIObjAddState("usb_status_label", "LV_STATE_CHECKED")
|
||||||
} else {
|
} else {
|
||||||
nativeInstance.UpdateLabelIfChanged("usb_status_label", "Disconnected")
|
nativeInstance.UpdateLabelIfChanged("usb_status_label", "Disconnected")
|
||||||
_, _ = nativeInstance.UIObjSetState("usb_status", "LV_STATE_DISABLED")
|
_, _ = nativeInstance.UIObjClearState("usb_status_label", "LV_STATE_CHECKED")
|
||||||
}
|
}
|
||||||
if lastVideoState.Ready {
|
if lastVideoState.Ready {
|
||||||
nativeInstance.UpdateLabelIfChanged("hdmi_status_label", "Connected")
|
nativeInstance.UpdateLabelIfChanged("hdmi_status_label", "Connected")
|
||||||
_, _ = nativeInstance.UIObjSetState("hdmi_status", "LV_STATE_DEFAULT")
|
_, _ = nativeInstance.UIObjAddState("hdmi_status_label", "LV_STATE_CHECKED")
|
||||||
} else {
|
} else {
|
||||||
nativeInstance.UpdateLabelIfChanged("hdmi_status_label", "Disconnected")
|
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))
|
nativeInstance.UpdateLabelIfChanged("cloud_status_label", fmt.Sprintf("%d active", actionSessions))
|
||||||
|
|
||||||
if networkState.IsUp() {
|
if networkState.IsUp() {
|
||||||
|
nativeInstance.UISetVar("main_screen", "home_screen")
|
||||||
nativeInstance.SwitchToScreenIf("home_screen", []string{"no_network_screen", "boot_screen"})
|
nativeInstance.SwitchToScreenIf("home_screen", []string{"no_network_screen", "boot_screen"})
|
||||||
} else {
|
} else {
|
||||||
|
nativeInstance.UISetVar("main_screen", "no_network_screen")
|
||||||
nativeInstance.SwitchToScreenIf("no_network_screen", []string{"home_screen", "boot_screen"})
|
nativeInstance.SwitchToScreenIf("no_network_screen", []string{"home_screen", "boot_screen"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
jetkvm_video_state_t state;
|
jetkvm_video_state_t state;
|
||||||
jetkvm_video_state_handler_t *video_state_handler = NULL;
|
jetkvm_video_state_handler_t *video_state_handler = NULL;
|
||||||
|
jetkvm_rpc_handler_t *rpc_handler = NULL;
|
||||||
jetkvm_video_handler_t *video_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);
|
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) {
|
const char *jetkvm_ui_event_code_to_name(int code) {
|
||||||
lv_event_code_t cCode = (lv_event_code_t)code;
|
lv_event_code_t cCode = (lv_event_code_t)code;
|
||||||
return lv_event_code_get_name(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);
|
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);
|
lv_obj_t *obj = ui_get_obj(obj_name);
|
||||||
if (obj == NULL) {
|
if (obj == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lv_obj_add_state(obj, LV_STATE_USER_1);
|
lv_state_t state_val = str_to_lv_state(state_name);
|
||||||
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_obj_add_state(obj, state_val);
|
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) {
|
int jetkvm_ui_add_flag(const char *obj_name, const char *flag_name) {
|
||||||
lv_obj_t *obj = ui_get_obj(obj_name);
|
lv_obj_t *obj = ui_get_obj(obj_name);
|
||||||
if (obj == NULL) {
|
if (obj == NULL) {
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,15 @@ typedef struct
|
||||||
|
|
||||||
typedef void (jetkvm_video_state_handler_t)(jetkvm_video_state_t *state);
|
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_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_video_handler_t)(const uint8_t *frame, ssize_t len);
|
||||||
typedef void (jetkvm_indev_handler_t)(int code);
|
typedef void (jetkvm_indev_handler_t)(int code);
|
||||||
|
|
||||||
void jetkvm_set_log_handler(jetkvm_log_handler_t *handler);
|
void jetkvm_set_log_handler(jetkvm_log_handler_t *handler);
|
||||||
void jetkvm_set_video_handler(jetkvm_video_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_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_set_video_state_handler(jetkvm_video_state_handler_t *handler);
|
||||||
|
|
||||||
void jetkvm_ui_set_var(const char *name, const char *value);
|
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);
|
void jetkvm_ui_load_screen(const char *obj_name);
|
||||||
int jetkvm_ui_set_text(const char *obj_name, const char *text);
|
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_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_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_fade_out(const char *obj_name, u_int32_t duration);
|
||||||
void jetkvm_ui_set_opacity(const char *obj_name, u_int8_t opacity);
|
void jetkvm_ui_set_opacity(const char *obj_name, u_int8_t opacity);
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ int get_edid(uint8_t *edid, size_t max_size)
|
||||||
fd = open(V4L_SUBDEV, O_RDWR);
|
fd = open(V4L_SUBDEV, O_RDWR);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
{
|
{
|
||||||
perror("Failed to open device");
|
log_error("Failed to open device");
|
||||||
return -1;
|
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)
|
if (ioctl(fd, VIDIOC_G_EDID, &v4l2_edid) < 0)
|
||||||
{
|
{
|
||||||
perror("Failed to get EDID");
|
log_error("Failed to get EDID");
|
||||||
close(fd);
|
close(fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -90,7 +90,7 @@ int set_edid(uint8_t *edid, size_t size)
|
||||||
fd = open(V4L_SUBDEV, O_RDWR);
|
fd = open(V4L_SUBDEV, O_RDWR);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
{
|
{
|
||||||
perror("Failed to open device");
|
log_error("Failed to open device");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -104,7 +104,7 @@ int set_edid(uint8_t *edid, size_t size)
|
||||||
|
|
||||||
if (ioctl(fd, VIDIOC_S_EDID, &v4l2_edid) < 0)
|
if (ioctl(fd, VIDIOC_S_EDID, &v4l2_edid) < 0)
|
||||||
{
|
{
|
||||||
perror("Failed to set EDID");
|
log_error("Failed to set EDID");
|
||||||
close(fd);
|
close(fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -123,13 +123,13 @@ const char *videoc_log_status()
|
||||||
fd = open(V4L_SUBDEV, O_RDWR);
|
fd = open(V4L_SUBDEV, O_RDWR);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
{
|
{
|
||||||
perror("Failed to open device");
|
log_error("Failed to open device");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ioctl(fd, VIDIOC_LOG_STATUS) == -1)
|
if (ioctl(fd, VIDIOC_LOG_STATUS) == -1)
|
||||||
{
|
{
|
||||||
perror("VIDIOC_LOG_STATUS failed");
|
log_error("VIDIOC_LOG_STATUS failed");
|
||||||
close(fd);
|
close(fd);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -166,14 +166,14 @@ const char *videoc_log_status()
|
||||||
buffer = strdup(p);
|
buffer = strdup(p);
|
||||||
if (buffer == NULL)
|
if (buffer == NULL)
|
||||||
{
|
{
|
||||||
perror("Failed to allocate memory for status");
|
log_error("Failed to allocate memory for status");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
log_error("Failed to read kernel log\n");
|
log_error("Failed to read kernel log");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,25 @@
|
||||||
#define LOG_HANDLER_H
|
#define LOG_HANDLER_H
|
||||||
|
|
||||||
typedef void (jetkvm_log_handler_t)(int level, const char *filename, const char *funcname, const int line, const char *message);
|
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);
|
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);
|
void log_set_handler(jetkvm_log_handler_t *handler);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
// #include "st7789/lcd.h"
|
// #include "st7789/lcd.h"
|
||||||
#include "ui/ui.h"
|
#include "ui/ui.h"
|
||||||
#include "ui_index.h"
|
#include "ui_index.h"
|
||||||
|
#include "ctrl.h"
|
||||||
|
|
||||||
#define DISP_BUF_SIZE (300 * 240 * 2)
|
#define DISP_BUF_SIZE (300 * 240 * 2)
|
||||||
static lv_color_t buf[DISP_BUF_SIZE];
|
static lv_color_t buf[DISP_BUF_SIZE];
|
||||||
|
|
@ -32,8 +33,6 @@ void lvgl_init(u_int16_t rotation) {
|
||||||
/*LittlevGL init*/
|
/*LittlevGL init*/
|
||||||
lv_init();
|
lv_init();
|
||||||
|
|
||||||
/*Linux frame buffer device init*/
|
|
||||||
|
|
||||||
/*Linux frame buffer device init*/
|
/*Linux frame buffer device init*/
|
||||||
lv_display_t *disp = lv_linux_fbdev_create();
|
lv_display_t *disp = lv_linux_fbdev_create();
|
||||||
// lv_display_set_physical_resolution(disp, 240, 300);
|
// lv_display_set_physical_resolution(disp, 240, 300);
|
||||||
|
|
@ -42,29 +41,6 @@ void lvgl_init(u_int16_t rotation) {
|
||||||
|
|
||||||
lvgl_set_rotation(disp, 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 */
|
/* Linux input device init */
|
||||||
lv_indev_t *mouse = lv_evdev_create(LV_INDEV_TYPE_POINTER, "/dev/input/event1");
|
lv_indev_t *mouse = lv_evdev_create(LV_INDEV_TYPE_POINTER, "/dev/input/event1");
|
||||||
lv_indev_set_group(mouse, lv_group_get_default());
|
lv_indev_set_group(mouse, lv_group_get_default());
|
||||||
|
|
@ -76,10 +52,9 @@ void lvgl_init(u_int16_t rotation) {
|
||||||
|
|
||||||
ui_init();
|
ui_init();
|
||||||
|
|
||||||
|
ui_set_rpc_handler((jetkvm_rpc_handler_t *)jetkvm_call_rpc_handler);
|
||||||
|
|
||||||
log_info("ui initalized");
|
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) {
|
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) {
|
void ui_set_text(const char *name, const char *text) {
|
||||||
lv_obj_t *obj = ui_get_obj(name);
|
lv_obj_t *obj = ui_get_obj(name);
|
||||||
if(obj == NULL) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
lv_label_set_text(obj, text);
|
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);
|
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);
|
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);
|
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);
|
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);
|
lv_img_dsc_t *ui_get_image(const char *name);
|
||||||
|
|
||||||
#endif // SCREEN_H
|
#endif // SCREEN_H
|
||||||
|
|
|
||||||
|
|
@ -268,14 +268,14 @@ static void *venc_read_stream(void *arg)
|
||||||
stFrame.pstPack = malloc(sizeof(VENC_PACK_S));
|
stFrame.pstPack = malloc(sizeof(VENC_PACK_S));
|
||||||
while (venc_running)
|
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
|
s32Ret = RK_MPI_VENC_GetStream(VENC_CHANNEL, &stFrame, 200); // blocks max 200ms
|
||||||
if (s32Ret == RK_SUCCESS)
|
if (s32Ret == RK_SUCCESS)
|
||||||
{
|
{
|
||||||
RK_U64 nowUs = get_us();
|
RK_U64 nowUs = get_us();
|
||||||
// printf("chn:0, loopCount:%d enc->seq:%d wd:%d pts=%llu delay=%lldus\n",
|
log_trace("chn:0, loopCount:%d enc->seq:%d wd:%d pts=%llu delay=%lldus",
|
||||||
// loopCount, stFrame.u32Seq, stFrame.pstPack->u32Len,
|
loopCount, stFrame.u32Seq, stFrame.pstPack->u32Len,
|
||||||
// stFrame.pstPack->u64PTS, nowUs - stFrame.pstPack->u64PTS);
|
stFrame.pstPack->u64PTS, nowUs - stFrame.pstPack->u64PTS);
|
||||||
pData = RK_MPI_MB_Handle2VirAddr(stFrame.pstPack->pMbBlk);
|
pData = RK_MPI_MB_Handle2VirAddr(stFrame.pstPack->pMbBlk);
|
||||||
video_send_frame(pData, (ssize_t)stFrame.pstPack->u32Len);
|
video_send_frame(pData, (ssize_t)stFrame.pstPack->u32Len);
|
||||||
s32Ret = RK_MPI_VENC_ReleaseStream(VENC_CHANNEL, &stFrame);
|
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;
|
bool detected_signal = false, streaming_flag = false;
|
||||||
|
|
||||||
pthread_t *streaming_thread = NULL;
|
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)
|
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)
|
if (detected_signal == false)
|
||||||
{
|
{
|
||||||
usleep(100000);
|
usleep(10000); // Reduced to 10ms for better responsiveness to streaming_flag changes
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -347,7 +348,7 @@ void *run_video_stream(void *arg)
|
||||||
|
|
||||||
if (ioctl(video_dev_fd, VIDIOC_S_FMT, &fmt) < 0)
|
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
|
usleep(100000); // Sleep for 100 milliseconds
|
||||||
close(video_dev_fd);
|
close(video_dev_fd);
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -362,7 +363,8 @@ void *run_video_stream(void *arg)
|
||||||
|
|
||||||
if (ioctl(video_dev_fd, VIDIOC_REQBUFS, &req) < 0)
|
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;
|
return errno;
|
||||||
}
|
}
|
||||||
log_info("VIDIOC_REQBUFS successful");
|
log_info("VIDIOC_REQBUFS successful");
|
||||||
|
|
@ -384,32 +386,35 @@ void *run_video_stream(void *arg)
|
||||||
|
|
||||||
if (-1 == ioctl(video_dev_fd, VIDIOC_QUERYBUF, &buf))
|
if (-1 == ioctl(video_dev_fd, VIDIOC_QUERYBUF, &buf))
|
||||||
{
|
{
|
||||||
perror("VIDIOC_QUERYBUF failed");
|
log_error("VIDIOC_QUERYBUF failed: %s", strerror(errno));
|
||||||
req.count = i;
|
req.count = i;
|
||||||
|
close(video_dev_fd);
|
||||||
return errno;
|
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);
|
log_info("plane: length = %d", planes_buffer->length);
|
||||||
printf("plane: offset = %d\n", planes_buffer->m.mem_offset);
|
log_info("plane: offset = %d", planes_buffer->m.mem_offset);
|
||||||
|
|
||||||
MB_BLK blk = RK_MPI_MB_GetMB(memPool, (planes_buffer)->length, RK_TRUE);
|
MB_BLK blk = RK_MPI_MB_GetMB(memPool, (planes_buffer)->length, RK_TRUE);
|
||||||
if (blk == NULL)
|
if (blk == NULL)
|
||||||
{
|
{
|
||||||
RK_LOGE("get mb blk failed!");
|
log_error("get mb blk failed!");
|
||||||
|
close(video_dev_fd);
|
||||||
return -1;
|
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;
|
buffers[i].mb_blk = blk;
|
||||||
|
|
||||||
RK_S32 buf_fd = (RK_MPI_MB_Handle2Fd(blk));
|
RK_S32 buf_fd = (RK_MPI_MB_Handle2Fd(blk));
|
||||||
if (buf_fd < 0)
|
if (buf_fd < 0)
|
||||||
{
|
{
|
||||||
RK_LOGE("RK_MPI_MB_Handle2Fd failed!");
|
log_error("RK_MPI_MB_Handle2Fd failed!");
|
||||||
|
close(video_dev_fd);
|
||||||
return -1;
|
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;
|
planes_buffer->m.fd = buf_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -424,15 +429,16 @@ void *run_video_stream(void *arg)
|
||||||
buf.m.planes = &buffers[i].plane_buffer;
|
buf.m.planes = &buffers[i].plane_buffer;
|
||||||
if (ioctl(video_dev_fd, VIDIOC_QBUF, &buf) < 0)
|
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;
|
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)
|
if (ioctl(video_dev_fd, VIDIOC_STREAMON, &type) < 0)
|
||||||
{
|
{
|
||||||
perror("VIDIOC_STREAMON failed");
|
log_error("VIDIOC_STREAMON failed: %s", strerror(errno));
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -463,7 +469,7 @@ void *run_video_stream(void *arg)
|
||||||
r = select(video_dev_fd + 1, &fds, NULL, NULL, &tv);
|
r = select(video_dev_fd + 1, &fds, NULL, NULL, &tv);
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
{
|
{
|
||||||
log_info("select timeout \n");
|
log_info("select timeout");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (r == -1)
|
if (r == -1)
|
||||||
|
|
@ -472,7 +478,7 @@ void *run_video_stream(void *arg)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
perror("select in video streaming");
|
log_error("select in video streaming");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
memset(&buf, 0, sizeof(buf));
|
memset(&buf, 0, sizeof(buf));
|
||||||
|
|
@ -482,10 +488,10 @@ void *run_video_stream(void *arg)
|
||||||
buf.length = 1;
|
buf.length = 1;
|
||||||
if (ioctl(video_dev_fd, VIDIOC_DQBUF, &buf) < 0)
|
if (ioctl(video_dev_fd, VIDIOC_DQBUF, &buf) < 0)
|
||||||
{
|
{
|
||||||
perror("VIDIOC_DQBUF failed");
|
log_error("VIDIOC_DQBUF failed: %s", strerror(errno));
|
||||||
break;
|
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));
|
memset(&stFrame, 0, sizeof(VIDEO_FRAME_INFO_S));
|
||||||
MB_BLK blk = RK_NULL;
|
MB_BLK blk = RK_NULL;
|
||||||
blk = RK_MPI_MMZ_Fd2Handle(tmp_plane.m.fd);
|
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.u32FrameFlag |= 0;
|
||||||
stFrame.stVFrame.enCompressMode = COMPRESS_MODE_NONE;
|
stFrame.stVFrame.enCompressMode = COMPRESS_MODE_NONE;
|
||||||
bool retried = false;
|
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:
|
retry_send_frame:
|
||||||
if (RK_MPI_VENC_SendFrame(VENC_CHANNEL, &stFrame, 2000) != RK_SUCCESS)
|
if (RK_MPI_VENC_SendFrame(VENC_CHANNEL, &stFrame, 2000) != RK_SUCCESS)
|
||||||
{
|
{
|
||||||
if (retried == true)
|
if (retried == true)
|
||||||
{
|
{
|
||||||
RK_LOGE("RK_MPI_VENC_SendFrame retry failed");
|
log_error("RK_MPI_VENC_SendFrame retry failed");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
RK_LOGE("RK_MPI_VENC_SendFrame failed,retrying");
|
log_error("RK_MPI_VENC_SendFrame failed,retrying");
|
||||||
retried = true;
|
retried = true;
|
||||||
usleep(1000llu);
|
usleep(1000llu);
|
||||||
goto retry_send_frame;
|
goto retry_send_frame;
|
||||||
|
|
@ -532,12 +528,13 @@ void *run_video_stream(void *arg)
|
||||||
num++;
|
num++;
|
||||||
|
|
||||||
if (ioctl(video_dev_fd, VIDIOC_QBUF, &buf) < 0)
|
if (ioctl(video_dev_fd, VIDIOC_QBUF, &buf) < 0)
|
||||||
printf("failture VIDIOC_QBUF\n");
|
log_error("failure VIDIOC_QBUF: %s", strerror(errno));
|
||||||
}
|
}
|
||||||
cleanup:
|
cleanup:
|
||||||
|
log_info("cleaning up video capture device %s", VIDEO_DEV);
|
||||||
if (ioctl(video_dev_fd, VIDIOC_STREAMOFF, &type) < 0)
|
if (ioctl(video_dev_fd, VIDIOC_STREAMOFF, &type) < 0)
|
||||||
{
|
{
|
||||||
perror("VIDIOC_STREAMOFF failed");
|
log_error("VIDIOC_STREAMOFF failed: %s", strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
venc_stop();
|
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);
|
close(video_dev_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_info("video stream thread exiting");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -560,65 +559,78 @@ void video_shutdown()
|
||||||
{
|
{
|
||||||
if (should_exit == true)
|
if (should_exit == true)
|
||||||
{
|
{
|
||||||
printf("shutting down in progress already\n");
|
log_info("shutting down in progress already");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
video_stop_streaming();
|
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;
|
should_exit = true;
|
||||||
if (sub_dev_fd > 0)
|
if (sub_dev_fd > 0)
|
||||||
{
|
{
|
||||||
shutdown(sub_dev_fd, SHUT_RDWR);
|
shutdown(sub_dev_fd, SHUT_RDWR);
|
||||||
// close(sub_dev_fd);
|
log_info("Closed sub_dev_fd");
|
||||||
printf("Closed sub_dev_fd\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memPool != MB_INVALID_POOLID)
|
if (memPool != MB_INVALID_POOLID)
|
||||||
{
|
{
|
||||||
RK_MPI_MB_DestroyPool(memPool);
|
RK_MPI_MB_DestroyPool(memPool);
|
||||||
}
|
}
|
||||||
printf("Destroyed memory pool\n");
|
log_info("Destroyed memory pool");
|
||||||
// if (format_thread != NULL) {
|
|
||||||
// pthread_join(*format_thread, NULL);
|
pthread_mutex_destroy(&streaming_mutex);
|
||||||
// free(format_thread);
|
log_info("Destroyed streaming mutex");
|
||||||
// format_thread = NULL;
|
|
||||||
// }
|
|
||||||
// printf("Joined format detection thread\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: mutex?
|
|
||||||
|
|
||||||
void video_start_streaming()
|
void video_start_streaming()
|
||||||
{
|
{
|
||||||
|
pthread_mutex_lock(&streaming_mutex);
|
||||||
if (streaming_thread != NULL)
|
if (streaming_thread != NULL)
|
||||||
{
|
{
|
||||||
log_info("video streaming already started");
|
log_warn("video streaming already started");
|
||||||
return;
|
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;
|
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()
|
void video_stop_streaming()
|
||||||
{
|
{
|
||||||
|
pthread_mutex_lock(&streaming_mutex);
|
||||||
if (streaming_thread != NULL)
|
if (streaming_thread != NULL)
|
||||||
{
|
{
|
||||||
streaming_flag = false;
|
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);
|
pthread_join(*streaming_thread, NULL);
|
||||||
free(streaming_thread);
|
free(streaming_thread);
|
||||||
streaming_thread = NULL;
|
streaming_thread = NULL;
|
||||||
log_info("video streaming stopped");
|
log_info("video streaming stopped");
|
||||||
}
|
}
|
||||||
|
pthread_mutex_unlock(&streaming_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *run_detect_format(void *arg)
|
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)
|
if (ioctl(sub_dev_fd, VIDIOC_SUBSCRIBE_EVENT, &sub) == -1)
|
||||||
{
|
{
|
||||||
log_error("cannot subscribe to event");
|
log_error("cannot subscribe to event");
|
||||||
perror("Cannot subscribe to event");
|
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -657,12 +668,12 @@ void *run_detect_format(void *arg)
|
||||||
else if (errno == ERANGE)
|
else if (errno == ERANGE)
|
||||||
{
|
{
|
||||||
// Timings were found, but they are out of range of the hardware capabilities.
|
// 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);
|
video_report_format(false, "out_of_range", 0, 0, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
perror("error VIDIOC_QUERY_DV_TIMINGS");
|
log_error("error VIDIOC_QUERY_DV_TIMINGS: %s", strerror(errno));
|
||||||
sleep(1);
|
sleep(1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -681,19 +692,24 @@ void *run_detect_format(void *arg)
|
||||||
detected_height = dv_timings.bt.height;
|
detected_height = dv_timings.bt.height;
|
||||||
detected_signal = true;
|
detected_signal = true;
|
||||||
video_report_format(true, NULL, detected_width, detected_height, frames_per_second);
|
video_report_format(true, NULL, detected_width, detected_height, frames_per_second);
|
||||||
|
pthread_mutex_lock(&streaming_mutex);
|
||||||
if (streaming_flag == true)
|
if (streaming_flag == true)
|
||||||
{
|
{
|
||||||
|
pthread_mutex_unlock(&streaming_mutex);
|
||||||
log_info("restarting on going video streaming");
|
log_info("restarting on going video streaming");
|
||||||
video_stop_streaming();
|
video_stop_streaming();
|
||||||
video_start_streaming();
|
video_start_streaming();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock(&streaming_mutex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&ev, 0, sizeof(ev));
|
memset(&ev, 0, sizeof(ev));
|
||||||
if (ioctl(sub_dev_fd, VIDIOC_DQEVENT, &ev) != 0)
|
if (ioctl(sub_dev_fd, VIDIOC_DQEVENT, &ev) != 0)
|
||||||
{
|
{
|
||||||
log_error("failed to VIDIOC_DQEVENT");
|
log_error("failed to VIDIOC_DQEVENT: %s", strerror(errno));
|
||||||
perror("failed to VIDIOC_DQEVENT");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
log_info("New event of type %u", ev.type);
|
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
|
// TODO: update venc bitrate without stopping streaming
|
||||||
|
|
||||||
|
pthread_mutex_lock(&streaming_mutex);
|
||||||
if (streaming_flag == true)
|
if (streaming_flag == true)
|
||||||
{
|
{
|
||||||
|
pthread_mutex_unlock(&streaming_mutex);
|
||||||
log_info("restarting on going video streaming due to quality factor change");
|
log_info("restarting on going video streaming due to quality factor change");
|
||||||
video_stop_streaming();
|
video_stop_streaming();
|
||||||
video_start_streaming();
|
video_start_streaming();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock(&streaming_mutex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float video_get_quality_factor() {
|
float video_get_quality_factor() {
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,48 @@
|
||||||
#ifndef VIDEO_DAEMON_VIDEO_H
|
#ifndef VIDEO_DAEMON_VIDEO_H
|
||||||
#define 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();
|
int video_init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Shutdown the video subsystem
|
||||||
|
*/
|
||||||
void video_shutdown();
|
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);
|
void *run_detect_format(void *arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Start the video streaming
|
||||||
|
*/
|
||||||
void video_start_streaming();
|
void video_start_streaming();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stop the video streaming
|
||||||
|
*/
|
||||||
void video_stop_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);
|
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();
|
float video_get_quality_factor();
|
||||||
|
|
||||||
#endif //VIDEO_DAEMON_VIDEO_H
|
#endif //VIDEO_DAEMON_VIDEO_H
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ package native
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sync"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
|
|
@ -37,9 +38,16 @@ extern void jetkvm_go_indev_handler(int code);
|
||||||
static inline void jetkvm_cgo_setup_indev_handler() {
|
static inline void jetkvm_cgo_setup_indev_handler() {
|
||||||
jetkvm_set_indev_handler(&jetkvm_go_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"
|
import "C"
|
||||||
|
|
||||||
|
var cgoLock sync.Mutex
|
||||||
|
|
||||||
//export jetkvm_go_video_state_handler
|
//export jetkvm_go_video_state_handler
|
||||||
func jetkvm_go_video_state_handler(state *C.jetkvm_video_state_t) {
|
func jetkvm_go_video_state_handler(state *C.jetkvm_video_state_t) {
|
||||||
videoState := VideoState{
|
videoState := VideoState{
|
||||||
|
|
@ -75,6 +83,11 @@ func jetkvm_go_indev_handler(code C.int) {
|
||||||
indevEventChan <- int(code)
|
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{}
|
var eventCodeToNameMap = map[int]string{}
|
||||||
|
|
||||||
func uiEventCodeToName(code int) string {
|
func uiEventCodeToName(code int) string {
|
||||||
|
|
@ -90,13 +103,20 @@ func uiEventCodeToName(code int) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func setUpNativeHandlers() {
|
func setUpNativeHandlers() {
|
||||||
|
cgoLock.Lock()
|
||||||
|
defer cgoLock.Unlock()
|
||||||
|
|
||||||
C.jetkvm_cgo_setup_log_handler()
|
C.jetkvm_cgo_setup_log_handler()
|
||||||
C.jetkvm_cgo_setup_video_state_handler()
|
C.jetkvm_cgo_setup_video_state_handler()
|
||||||
C.jetkvm_cgo_setup_video_handler()
|
C.jetkvm_cgo_setup_video_handler()
|
||||||
C.jetkvm_cgo_setup_indev_handler()
|
C.jetkvm_cgo_setup_indev_handler()
|
||||||
|
C.jetkvm_cgo_setup_rpc_handler()
|
||||||
}
|
}
|
||||||
|
|
||||||
func uiInit(rotation uint16) {
|
func uiInit(rotation uint16) {
|
||||||
|
cgoLock.Lock()
|
||||||
|
defer cgoLock.Unlock()
|
||||||
|
|
||||||
cRotation := C.u_int16_t(rotation)
|
cRotation := C.u_int16_t(rotation)
|
||||||
defer C.free(unsafe.Pointer(&cRotation))
|
defer C.free(unsafe.Pointer(&cRotation))
|
||||||
|
|
||||||
|
|
@ -104,10 +124,16 @@ func uiInit(rotation uint16) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func uiTick() {
|
func uiTick() {
|
||||||
|
cgoLock.Lock()
|
||||||
|
defer cgoLock.Unlock()
|
||||||
|
|
||||||
C.jetkvm_ui_tick()
|
C.jetkvm_ui_tick()
|
||||||
}
|
}
|
||||||
|
|
||||||
func videoInit() error {
|
func videoInit() error {
|
||||||
|
cgoLock.Lock()
|
||||||
|
defer cgoLock.Unlock()
|
||||||
|
|
||||||
ret := C.jetkvm_video_init()
|
ret := C.jetkvm_video_init()
|
||||||
if ret != 0 {
|
if ret != 0 {
|
||||||
return fmt.Errorf("failed to initialize video: %d", ret)
|
return fmt.Errorf("failed to initialize video: %d", ret)
|
||||||
|
|
@ -116,18 +142,30 @@ func videoInit() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func videoShutdown() {
|
func videoShutdown() {
|
||||||
|
cgoLock.Lock()
|
||||||
|
defer cgoLock.Unlock()
|
||||||
|
|
||||||
C.jetkvm_video_shutdown()
|
C.jetkvm_video_shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
func videoStart() {
|
func videoStart() {
|
||||||
|
cgoLock.Lock()
|
||||||
|
defer cgoLock.Unlock()
|
||||||
|
|
||||||
C.jetkvm_video_start()
|
C.jetkvm_video_start()
|
||||||
}
|
}
|
||||||
|
|
||||||
func videoStop() {
|
func videoStop() {
|
||||||
|
cgoLock.Lock()
|
||||||
|
defer cgoLock.Unlock()
|
||||||
|
|
||||||
C.jetkvm_video_stop()
|
C.jetkvm_video_stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
func uiSetVar(name string, value string) {
|
func uiSetVar(name string, value string) {
|
||||||
|
cgoLock.Lock()
|
||||||
|
defer cgoLock.Unlock()
|
||||||
|
|
||||||
nameCStr := C.CString(name)
|
nameCStr := C.CString(name)
|
||||||
defer C.free(unsafe.Pointer(nameCStr))
|
defer C.free(unsafe.Pointer(nameCStr))
|
||||||
|
|
||||||
|
|
@ -138,6 +176,9 @@ func uiSetVar(name string, value string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func uiGetVar(name string) string {
|
func uiGetVar(name string) string {
|
||||||
|
cgoLock.Lock()
|
||||||
|
defer cgoLock.Unlock()
|
||||||
|
|
||||||
nameCStr := C.CString(name)
|
nameCStr := C.CString(name)
|
||||||
defer C.free(unsafe.Pointer(nameCStr))
|
defer C.free(unsafe.Pointer(nameCStr))
|
||||||
|
|
||||||
|
|
@ -145,31 +186,58 @@ func uiGetVar(name string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func uiSwitchToScreen(screen string) {
|
func uiSwitchToScreen(screen string) {
|
||||||
|
cgoLock.Lock()
|
||||||
|
defer cgoLock.Unlock()
|
||||||
|
|
||||||
screenCStr := C.CString(screen)
|
screenCStr := C.CString(screen)
|
||||||
defer C.free(unsafe.Pointer(screenCStr))
|
defer C.free(unsafe.Pointer(screenCStr))
|
||||||
C.jetkvm_ui_load_screen(screenCStr)
|
C.jetkvm_ui_load_screen(screenCStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func uiGetCurrentScreen() string {
|
func uiGetCurrentScreen() string {
|
||||||
|
cgoLock.Lock()
|
||||||
|
defer cgoLock.Unlock()
|
||||||
|
|
||||||
screenCStr := C.jetkvm_ui_get_current_screen()
|
screenCStr := C.jetkvm_ui_get_current_screen()
|
||||||
return C.GoString(screenCStr)
|
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)
|
objNameCStr := C.CString(objName)
|
||||||
defer C.free(unsafe.Pointer(objNameCStr))
|
defer C.free(unsafe.Pointer(objNameCStr))
|
||||||
stateCStr := C.CString(state)
|
stateCStr := C.CString(state)
|
||||||
defer C.free(unsafe.Pointer(stateCStr))
|
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
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func uiGetLVGLVersion() string {
|
func uiGetLVGLVersion() string {
|
||||||
|
cgoLock.Lock()
|
||||||
|
defer cgoLock.Unlock()
|
||||||
|
|
||||||
return C.GoString(C.jetkvm_ui_get_lvgl_version())
|
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
|
// 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) {
|
func uiObjAddFlag(objName string, flag string) (bool, error) {
|
||||||
|
cgoLock.Lock()
|
||||||
|
defer cgoLock.Unlock()
|
||||||
|
|
||||||
objNameCStr := C.CString(objName)
|
objNameCStr := C.CString(objName)
|
||||||
defer C.free(unsafe.Pointer(objNameCStr))
|
defer C.free(unsafe.Pointer(objNameCStr))
|
||||||
flagCStr := C.CString(flag)
|
flagCStr := C.CString(flag)
|
||||||
|
|
@ -179,6 +247,9 @@ func uiObjAddFlag(objName string, flag string) (bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func uiObjClearFlag(objName string, flag string) (bool, error) {
|
func uiObjClearFlag(objName string, flag string) (bool, error) {
|
||||||
|
cgoLock.Lock()
|
||||||
|
defer cgoLock.Unlock()
|
||||||
|
|
||||||
objNameCStr := C.CString(objName)
|
objNameCStr := C.CString(objName)
|
||||||
defer C.free(unsafe.Pointer(objNameCStr))
|
defer C.free(unsafe.Pointer(objNameCStr))
|
||||||
flagCStr := C.CString(flag)
|
flagCStr := C.CString(flag)
|
||||||
|
|
@ -196,6 +267,9 @@ func uiObjShow(objName string) (bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func uiObjSetOpacity(objName string, opacity int) (bool, error) {
|
func uiObjSetOpacity(objName string, opacity int) (bool, error) {
|
||||||
|
cgoLock.Lock()
|
||||||
|
defer cgoLock.Unlock()
|
||||||
|
|
||||||
objNameCStr := C.CString(objName)
|
objNameCStr := C.CString(objName)
|
||||||
defer C.free(unsafe.Pointer(objNameCStr))
|
defer C.free(unsafe.Pointer(objNameCStr))
|
||||||
|
|
||||||
|
|
@ -204,6 +278,9 @@ func uiObjSetOpacity(objName string, opacity int) (bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func uiObjFadeIn(objName string, duration uint32) (bool, error) {
|
func uiObjFadeIn(objName string, duration uint32) (bool, error) {
|
||||||
|
cgoLock.Lock()
|
||||||
|
defer cgoLock.Unlock()
|
||||||
|
|
||||||
objNameCStr := C.CString(objName)
|
objNameCStr := C.CString(objName)
|
||||||
defer C.free(unsafe.Pointer(objNameCStr))
|
defer C.free(unsafe.Pointer(objNameCStr))
|
||||||
|
|
||||||
|
|
@ -213,6 +290,9 @@ func uiObjFadeIn(objName string, duration uint32) (bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func uiObjFadeOut(objName string, duration uint32) (bool, error) {
|
func uiObjFadeOut(objName string, duration uint32) (bool, error) {
|
||||||
|
cgoLock.Lock()
|
||||||
|
defer cgoLock.Unlock()
|
||||||
|
|
||||||
objNameCStr := C.CString(objName)
|
objNameCStr := C.CString(objName)
|
||||||
defer C.free(unsafe.Pointer(objNameCStr))
|
defer C.free(unsafe.Pointer(objNameCStr))
|
||||||
|
|
||||||
|
|
@ -222,6 +302,9 @@ func uiObjFadeOut(objName string, duration uint32) (bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func uiLabelSetText(objName string, text string) (bool, error) {
|
func uiLabelSetText(objName string, text string) (bool, error) {
|
||||||
|
cgoLock.Lock()
|
||||||
|
defer cgoLock.Unlock()
|
||||||
|
|
||||||
objNameCStr := C.CString(objName)
|
objNameCStr := C.CString(objName)
|
||||||
defer C.free(unsafe.Pointer(objNameCStr))
|
defer C.free(unsafe.Pointer(objNameCStr))
|
||||||
|
|
||||||
|
|
@ -236,6 +319,9 @@ func uiLabelSetText(objName string, text string) (bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func uiImgSetSrc(objName string, src string) (bool, error) {
|
func uiImgSetSrc(objName string, src string) (bool, error) {
|
||||||
|
cgoLock.Lock()
|
||||||
|
defer cgoLock.Unlock()
|
||||||
|
|
||||||
objNameCStr := C.CString(objName)
|
objNameCStr := C.CString(objName)
|
||||||
defer C.free(unsafe.Pointer(objNameCStr))
|
defer C.free(unsafe.Pointer(objNameCStr))
|
||||||
|
|
||||||
|
|
@ -248,6 +334,9 @@ func uiImgSetSrc(objName string, src string) (bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func uiDispSetRotation(rotation uint16) (bool, error) {
|
func uiDispSetRotation(rotation uint16) (bool, error) {
|
||||||
|
cgoLock.Lock()
|
||||||
|
defer cgoLock.Unlock()
|
||||||
|
|
||||||
nativeLogger.Info().Uint16("rotation", rotation).Msg("setting rotation")
|
nativeLogger.Info().Uint16("rotation", rotation).Msg("setting rotation")
|
||||||
|
|
||||||
cRotation := C.u_int16_t(rotation)
|
cRotation := C.u_int16_t(rotation)
|
||||||
|
|
@ -258,21 +347,33 @@ func uiDispSetRotation(rotation uint16) (bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func videoGetStreamQualityFactor() (float64, error) {
|
func videoGetStreamQualityFactor() (float64, error) {
|
||||||
|
cgoLock.Lock()
|
||||||
|
defer cgoLock.Unlock()
|
||||||
|
|
||||||
factor := C.jetkvm_video_get_quality_factor()
|
factor := C.jetkvm_video_get_quality_factor()
|
||||||
return float64(factor), nil
|
return float64(factor), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func videoSetStreamQualityFactor(factor float64) error {
|
func videoSetStreamQualityFactor(factor float64) error {
|
||||||
|
cgoLock.Lock()
|
||||||
|
defer cgoLock.Unlock()
|
||||||
|
|
||||||
C.jetkvm_video_set_quality_factor(C.float(factor))
|
C.jetkvm_video_set_quality_factor(C.float(factor))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func videoGetEDID() (string, error) {
|
func videoGetEDID() (string, error) {
|
||||||
|
cgoLock.Lock()
|
||||||
|
defer cgoLock.Unlock()
|
||||||
|
|
||||||
edidCStr := C.jetkvm_video_get_edid_hex()
|
edidCStr := C.jetkvm_video_get_edid_hex()
|
||||||
return C.GoString(edidCStr), nil
|
return C.GoString(edidCStr), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func videoSetEDID(edid string) error {
|
func videoSetEDID(edid string) error {
|
||||||
|
cgoLock.Lock()
|
||||||
|
defer cgoLock.Unlock()
|
||||||
|
|
||||||
edidCStr := C.CString(edid)
|
edidCStr := C.CString(edid)
|
||||||
defer C.free(unsafe.Pointer(edidCStr))
|
defer C.free(unsafe.Pointer(edidCStr))
|
||||||
C.jetkvm_video_set_edid(edidCStr)
|
C.jetkvm_video_set_edid(edidCStr)
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,12 @@ func uiGetCurrentScreen() string {
|
||||||
return ""
|
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()
|
panicPlatformNotSupported()
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ var (
|
||||||
videoStateChan chan VideoState = make(chan VideoState)
|
videoStateChan chan VideoState = make(chan VideoState)
|
||||||
logChan chan nativeLogMessage = make(chan nativeLogMessage)
|
logChan chan nativeLogMessage = make(chan nativeLogMessage)
|
||||||
indevEventChan chan int = make(chan int)
|
indevEventChan chan int = make(chan int)
|
||||||
|
rpcEventChan chan string = make(chan string)
|
||||||
)
|
)
|
||||||
|
|
||||||
func (n *Native) handleVideoFrameChan() {
|
func (n *Native) handleVideoFrameChan() {
|
||||||
|
|
@ -70,3 +71,10 @@ func (n *Native) handleIndevEventChan() {
|
||||||
n.onIndevEvent(name)
|
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)
|
return uiObjShow(objName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UIObjSetState clears the state then adds the new state
|
// UISetVar sets the variable
|
||||||
func (n *Native) UIObjSetState(objName string, state string) (bool, error) {
|
func (n *Native) UISetVar(name string, value string) {
|
||||||
return uiObjSetState(objName, state)
|
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
|
// UIObjAddFlag adds the flag to the object
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"navigation": {
|
"navigation": {
|
||||||
"selectedUserPageObject": "[jetkvm.eez-project]:/userPages/5",
|
"selectedUserPageObject": "[jetkvm.eez-project]:/userPages/8",
|
||||||
"selectedActionObject": "[jetkvm.eez-project]:/actions/0",
|
"selectedActionObject": "[jetkvm.eez-project]:/actions/12",
|
||||||
"selectedGlobalVariableObject": "[jetkvm.eez-project]:/variables/globalVariables/1",
|
"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",
|
"selectedThemeObject": "[jetkvm.eez-project]:/themes/0",
|
||||||
"selectedFontObject": "[jetkvm.eez-project]:/fonts/4",
|
"selectedFontObject": "[jetkvm.eez-project]:/fonts/4",
|
||||||
"selectedBitmapObject": "[jetkvm.eez-project]:/bitmaps/11",
|
"selectedBitmapObject": "[jetkvm.eez-project]:/bitmaps/9",
|
||||||
"subnavigationSelectedItems": {
|
"subnavigationSelectedItems": {
|
||||||
"variables-tab/sub-navigation/selected-item": "Global"
|
"variables-tab/sub-navigation/selected-item": "Global"
|
||||||
}
|
}
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
{
|
{
|
||||||
"type": "border",
|
"type": "border",
|
||||||
"selected": 2,
|
"selected": 2,
|
||||||
"size": 113.5,
|
"size": 271.5,
|
||||||
"location": "right",
|
"location": "right",
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
|
|
@ -77,7 +77,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "border",
|
"type": "border",
|
||||||
"selected": 1,
|
"selected": 0,
|
||||||
"location": "bottom",
|
"location": "bottom",
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
|
|
@ -188,38 +188,48 @@
|
||||||
"enableClose": false,
|
"enableClose": false,
|
||||||
"icon": "svg:variable"
|
"icon": "svg:variable"
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"active": true
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "tabset",
|
"type": "tabset",
|
||||||
"id": "EDITORS",
|
"id": "EDITORS",
|
||||||
"weight": 49.31058517127421,
|
"weight": 52.479136828866125,
|
||||||
"selected": 4,
|
"selected": 5,
|
||||||
"enableDeleteWhenEmpty": false,
|
"enableDeleteWhenEmpty": false,
|
||||||
"enableClose": false,
|
"enableClose": false,
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"type": "tab",
|
"type": "tab",
|
||||||
"id": "#aec56ae8-5b75-4a2f-ad81-f0d7d683c77a",
|
"id": "#2b774476-9ef3-4363-83f8-8b478f163b02",
|
||||||
"name": "FontBook24",
|
"name": "MenuAdvancedScreen",
|
||||||
"component": "editor",
|
"component": "editor",
|
||||||
"config": {
|
"config": {
|
||||||
"objectPath": "[jetkvm.eez-project]:/fonts/4",
|
"objectPath": "[jetkvm.eez-project]:/userPages/4",
|
||||||
"permanent": false
|
"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",
|
"type": "tab",
|
||||||
"id": "#c8dece00-e490-46b8-8a14-5dcfa8bbce36",
|
"id": "#c8dece00-e490-46b8-8a14-5dcfa8bbce36",
|
||||||
"name": "AboutScreen",
|
"name": "StatusScreen",
|
||||||
"component": "editor",
|
"component": "editor",
|
||||||
"config": {
|
"config": {
|
||||||
"objectPath": "[jetkvm.eez-project]:/userPages/5",
|
"objectPath": "[jetkvm.eez-project]:/userPages/7",
|
||||||
"permanent": false
|
"permanent": true
|
||||||
},
|
},
|
||||||
"icon": "svg:page"
|
"icon": "svg:page"
|
||||||
},
|
},
|
||||||
|
|
@ -237,7 +247,7 @@
|
||||||
{
|
{
|
||||||
"type": "tab",
|
"type": "tab",
|
||||||
"id": "#f5a057a5-977c-46be-8702-5447d603a34f",
|
"id": "#f5a057a5-977c-46be-8702-5447d603a34f",
|
||||||
"name": "MenuScreen",
|
"name": "HomeScreen",
|
||||||
"component": "editor",
|
"component": "editor",
|
||||||
"config": {
|
"config": {
|
||||||
"objectPath": "[jetkvm.eez-project]:/userPages/2",
|
"objectPath": "[jetkvm.eez-project]:/userPages/2",
|
||||||
|
|
@ -257,12 +267,13 @@
|
||||||
},
|
},
|
||||||
"icon": "material:settings"
|
"icon": "material:settings"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"active": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "row",
|
"type": "row",
|
||||||
"id": "#ee319cf9-6145-49e4-b40e-1d999be897c8",
|
"id": "#ee319cf9-6145-49e4-b40e-1d999be897c8",
|
||||||
"weight": 24.95234430353635,
|
"weight": 21.78379264594443,
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"type": "tabset",
|
"type": "tabset",
|
||||||
|
|
@ -1065,8 +1076,7 @@
|
||||||
"0": {
|
"0": {
|
||||||
"0": {
|
"0": {
|
||||||
"0": {
|
"0": {
|
||||||
"1": {},
|
"1": {}
|
||||||
"$selected": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1086,11 +1096,58 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"[jetkvm.eez-project]:/userPages/1[flow-state]": {
|
"[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": {
|
"selection": {
|
||||||
"0": {
|
"0": {
|
||||||
"0": {
|
"0": {
|
||||||
"0": {
|
"0": {
|
||||||
"0": {},
|
"0": {
|
||||||
|
"$selected": true
|
||||||
|
},
|
||||||
"1": {
|
"1": {
|
||||||
"0": {}
|
"0": {}
|
||||||
}
|
}
|
||||||
|
|
@ -1102,9 +1159,7 @@
|
||||||
"3": {
|
"3": {
|
||||||
"0": {
|
"0": {
|
||||||
"0": {},
|
"0": {},
|
||||||
"1": {
|
"1": {}
|
||||||
"$selected": true
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"1": {
|
"1": {
|
||||||
"0": {},
|
"0": {},
|
||||||
|
|
@ -1128,12 +1183,7 @@
|
||||||
"scrollLeft": 0
|
"scrollLeft": 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"[jetkvm.eez-project]:/lvglStyles/styles[tree-state]": {
|
"[jetkvm.eez-project]:/userPages/3[flow-state]": {
|
||||||
"0": {
|
|
||||||
"$selected": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"[jetkvm.eez-project]:/userPages/2[flow-state]": {
|
|
||||||
"selection": {
|
"selection": {
|
||||||
"0": {
|
"0": {
|
||||||
"0": {
|
"0": {
|
||||||
|
|
@ -1142,13 +1192,14 @@
|
||||||
},
|
},
|
||||||
"1": {
|
"1": {
|
||||||
"0": {
|
"0": {
|
||||||
"0": {},
|
"0": {
|
||||||
|
"$selected": true
|
||||||
|
},
|
||||||
"1": {},
|
"1": {},
|
||||||
"2": {},
|
"2": {},
|
||||||
"3": {},
|
"3": {},
|
||||||
"4": {
|
"4": {
|
||||||
"0": {},
|
"0": {}
|
||||||
"$selected": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1169,19 +1220,15 @@
|
||||||
"scrollLeft": 0
|
"scrollLeft": 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"[jetkvm.eez-project]:/userPages/3[flow-state]": {
|
"[jetkvm.eez-project]:/userPages/4[flow-state]": {
|
||||||
"selection": {
|
"selection": {
|
||||||
"0": {
|
"0": {
|
||||||
"0": {
|
"0": {
|
||||||
"0": {
|
"0": {
|
||||||
"0": {},
|
"0": {}
|
||||||
"$selected": true
|
|
||||||
},
|
},
|
||||||
"1": {
|
"1": {
|
||||||
"0": {
|
"0": {
|
||||||
"0": {},
|
|
||||||
"1": {},
|
|
||||||
"2": {},
|
|
||||||
"3": {}
|
"3": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1190,41 +1237,8 @@
|
||||||
},
|
},
|
||||||
"transform": {
|
"transform": {
|
||||||
"translate": {
|
"translate": {
|
||||||
"x": -150,
|
"x": -181,
|
||||||
"y": -120
|
"y": -256.3828125
|
||||||
},
|
|
||||||
"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
|
|
||||||
},
|
},
|
||||||
"scale": 1
|
"scale": 1
|
||||||
},
|
},
|
||||||
|
|
@ -1245,19 +1259,8 @@
|
||||||
"1": {
|
"1": {
|
||||||
"0": {
|
"0": {
|
||||||
"0": {},
|
"0": {},
|
||||||
"1": {
|
"1": {},
|
||||||
"1": {}
|
"2": {}
|
||||||
},
|
|
||||||
"2": {},
|
|
||||||
"3": {},
|
|
||||||
"4": {},
|
|
||||||
"5": {
|
|
||||||
"1": {
|
|
||||||
"$selected": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"6": {},
|
|
||||||
"7": {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1300,11 +1303,11 @@
|
||||||
"0": {},
|
"0": {},
|
||||||
"1": {
|
"1": {
|
||||||
"0": {
|
"0": {
|
||||||
"0": {},
|
"0": {
|
||||||
|
"1": {}
|
||||||
|
},
|
||||||
"2": {
|
"2": {
|
||||||
"1": {
|
"1": {}
|
||||||
"$selected": true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1313,7 +1316,7 @@
|
||||||
},
|
},
|
||||||
"transform": {
|
"transform": {
|
||||||
"translate": {
|
"translate": {
|
||||||
"x": -138,
|
"x": -10.425644531250029,
|
||||||
"y": -122
|
"y": -122
|
||||||
},
|
},
|
||||||
"scale": 1
|
"scale": 1
|
||||||
|
|
@ -1324,6 +1327,67 @@
|
||||||
"secondToPx": 200,
|
"secondToPx": 200,
|
||||||
"scrollLeft": 0
|
"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,
|
"activeOutputSection": 0,
|
||||||
|
|
@ -1339,10 +1403,10 @@
|
||||||
"logsPanelFilter": "all",
|
"logsPanelFilter": "all",
|
||||||
"selectedStylePropertyName": "",
|
"selectedStylePropertyName": "",
|
||||||
"lvglPart": "MAIN",
|
"lvglPart": "MAIN",
|
||||||
"lvglState": "DISABLED",
|
"lvglState": "DEFAULT",
|
||||||
"lvglExpandedPropertiesGroup": [
|
"lvglExpandedPropertiesGroup": [
|
||||||
"MARGIN",
|
"POSITION AND SIZE",
|
||||||
"TEXT"
|
"LAYOUT"
|
||||||
],
|
],
|
||||||
"showInactiveFlowsInDebugger": true,
|
"showInactiveFlowsInDebugger": true,
|
||||||
"globalFlowZoom": true,
|
"globalFlowZoom": true,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
#include "actions.h"
|
#include "actions.h"
|
||||||
#include "screens.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) {
|
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);
|
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;
|
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) {
|
void action_switch_to_menu(lv_event_t *e) {
|
||||||
loadScreen(SCREEN_ID_MENU_SCREEN);
|
loadScreen(SCREEN_ID_MENU_SCREEN);
|
||||||
}
|
}
|
||||||
|
|
@ -31,8 +43,16 @@ void action_switch_to_about(lv_event_t *e) {
|
||||||
loadScreen(SCREEN_ID_ABOUT_SCREEN);
|
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) {
|
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) {
|
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) {
|
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) {
|
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) {
|
void action_about_screen_gesture(lv_event_t * e) {
|
||||||
handle_gesture_screen_switch(e, LV_DIR_RIGHT, SCREEN_ID_MENU_SCREEN);
|
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_menu(lv_event_t * e);
|
||||||
extern void action_switch_to_advanced_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_switch_to_about(lv_event_t * e);
|
||||||
extern void action_menu_screen_gesture(lv_event_t * e);
|
extern void action_menu_screen_gesture(lv_event_t * e);
|
||||||
extern void action_home_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_switch_to_status(lv_event_t * e);
|
||||||
extern void action_common_click_event(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_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
|
#ifdef __cplusplus
|
||||||
|
|
|
||||||
|
|
@ -325,10 +325,11 @@ void create_screen_home_screen() {
|
||||||
lv_obj_t *obj = lv_label_create(parent_obj);
|
lv_obj_t *obj = lv_label_create(parent_obj);
|
||||||
objects.home_info_ipv6_addr = obj;
|
objects.home_info_ipv6_addr = obj;
|
||||||
lv_obj_set_pos(obj, LV_PCT(0), LV_PCT(0));
|
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);
|
lv_label_set_long_mode(obj, LV_LABEL_LONG_DOT);
|
||||||
add_style_label_font16(obj);
|
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
|
// HomeInfoMACAddr
|
||||||
|
|
@ -431,10 +432,11 @@ void create_screen_home_screen() {
|
||||||
objects.usb_status_label = obj;
|
objects.usb_status_label = obj;
|
||||||
lv_obj_set_pos(obj, LV_PCT(0), LV_PCT(0));
|
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_SIZE_CONTENT, LV_SIZE_CONTENT);
|
||||||
|
lv_obj_add_flag(obj, LV_OBJ_FLAG_CHECKABLE);
|
||||||
add_style_label_font16(obj);
|
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_DEFAULT);
|
||||||
lv_obj_set_style_text_color(obj, lv_color_hex(0xff808080), LV_PART_MAIN | LV_STATE_DISABLED);
|
lv_obj_set_style_text_color(obj, lv_color_hex(0xff22c55e), LV_PART_MAIN | LV_STATE_CHECKED);
|
||||||
lv_label_set_text(obj, "Connected");
|
lv_label_set_text(obj, "Unknown");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -493,11 +495,11 @@ void create_screen_home_screen() {
|
||||||
objects.hdmi_status_label = obj;
|
objects.hdmi_status_label = obj;
|
||||||
lv_obj_set_pos(obj, LV_PCT(0), LV_PCT(0));
|
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_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);
|
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(0xff22c55e), LV_PART_MAIN | LV_STATE_CHECKED);
|
||||||
lv_obj_set_style_text_color(obj, lv_color_hex(0xff808080), LV_PART_MAIN | LV_STATE_DISABLED);
|
lv_obj_set_style_text_color(obj, lv_color_hex(0xff808080), LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||||
lv_label_set_text(obj, "Disconnected");
|
lv_label_set_text(obj, "Unknown");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -829,6 +831,8 @@ void create_screen_menu_advanced_screen() {
|
||||||
objects.menu_btn_advanced_developer_mode = obj;
|
objects.menu_btn_advanced_developer_mode = obj;
|
||||||
lv_obj_set_pos(obj, 0, 0);
|
lv_obj_set_pos(obj, 0, 0);
|
||||||
lv_obj_set_size(obj, LV_PCT(100), 50);
|
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);
|
add_style_menu_button(obj);
|
||||||
{
|
{
|
||||||
lv_obj_t *parent_obj = obj;
|
lv_obj_t *parent_obj = obj;
|
||||||
|
|
@ -847,6 +851,7 @@ void create_screen_menu_advanced_screen() {
|
||||||
objects.menu_btn_advanced_usb_emulation = obj;
|
objects.menu_btn_advanced_usb_emulation = obj;
|
||||||
lv_obj_set_pos(obj, 0, 0);
|
lv_obj_set_pos(obj, 0, 0);
|
||||||
lv_obj_set_size(obj, LV_PCT(100), 50);
|
lv_obj_set_size(obj, LV_PCT(100), 50);
|
||||||
|
lv_obj_add_flag(obj, LV_OBJ_FLAG_HIDDEN);
|
||||||
add_style_menu_button(obj);
|
add_style_menu_button(obj);
|
||||||
{
|
{
|
||||||
lv_obj_t *parent_obj = obj;
|
lv_obj_t *parent_obj = obj;
|
||||||
|
|
@ -865,6 +870,7 @@ void create_screen_menu_advanced_screen() {
|
||||||
objects.menu_btn_advanced_reboot = obj;
|
objects.menu_btn_advanced_reboot = obj;
|
||||||
lv_obj_set_pos(obj, 0, 0);
|
lv_obj_set_pos(obj, 0, 0);
|
||||||
lv_obj_set_size(obj, LV_PCT(100), 50);
|
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);
|
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SNAPPABLE);
|
||||||
add_style_menu_button(obj);
|
add_style_menu_button(obj);
|
||||||
{
|
{
|
||||||
|
|
@ -884,6 +890,7 @@ void create_screen_menu_advanced_screen() {
|
||||||
objects.menu_btn_advanced_reset_config = obj;
|
objects.menu_btn_advanced_reset_config = obj;
|
||||||
lv_obj_set_pos(obj, 0, 0);
|
lv_obj_set_pos(obj, 0, 0);
|
||||||
lv_obj_set_size(obj, LV_PCT(100), 50);
|
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);
|
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SNAPPABLE);
|
||||||
add_style_menu_button(obj);
|
add_style_menu_button(obj);
|
||||||
lv_obj_set_style_bg_color(obj, lv_color_hex(0xffdc2626), LV_PART_MAIN | LV_STATE_DEFAULT);
|
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 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)();
|
typedef void (*tick_screen_func_t)();
|
||||||
|
|
@ -1731,6 +2135,8 @@ tick_screen_func_t tick_screen_funcs[] = {
|
||||||
tick_screen_menu_network_screen,
|
tick_screen_menu_network_screen,
|
||||||
tick_screen_about_screen,
|
tick_screen_about_screen,
|
||||||
tick_screen_status_screen,
|
tick_screen_status_screen,
|
||||||
|
tick_screen_reset_config_screen,
|
||||||
|
tick_screen_reboot_screen,
|
||||||
};
|
};
|
||||||
void tick_screen(int screen_index) {
|
void tick_screen(int screen_index) {
|
||||||
tick_screen_funcs[screen_index]();
|
tick_screen_funcs[screen_index]();
|
||||||
|
|
@ -1752,4 +2158,6 @@ void create_screens() {
|
||||||
create_screen_menu_network_screen();
|
create_screen_menu_network_screen();
|
||||||
create_screen_about_screen();
|
create_screen_about_screen();
|
||||||
create_screen_status_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 *menu_network_screen;
|
||||||
lv_obj_t *about_screen;
|
lv_obj_t *about_screen;
|
||||||
lv_obj_t *status_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_logo;
|
||||||
lv_obj_t *boot_screen_version;
|
lv_obj_t *boot_screen_version;
|
||||||
lv_obj_t *no_network_header_container;
|
lv_obj_t *no_network_header_container;
|
||||||
|
|
@ -83,6 +85,19 @@ typedef struct _objects_t {
|
||||||
lv_obj_t *app_version_1;
|
lv_obj_t *app_version_1;
|
||||||
lv_obj_t *cloud_domain_container;
|
lv_obj_t *cloud_domain_container;
|
||||||
lv_obj_t *cloud_domain;
|
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;
|
} objects_t;
|
||||||
|
|
||||||
extern objects_t objects;
|
extern objects_t objects;
|
||||||
|
|
@ -96,6 +111,8 @@ enum ScreensEnum {
|
||||||
SCREEN_ID_MENU_NETWORK_SCREEN = 6,
|
SCREEN_ID_MENU_NETWORK_SCREEN = 6,
|
||||||
SCREEN_ID_ABOUT_SCREEN = 7,
|
SCREEN_ID_ABOUT_SCREEN = 7,
|
||||||
SCREEN_ID_STATUS_SCREEN = 8,
|
SCREEN_ID_STATUS_SCREEN = 8,
|
||||||
|
SCREEN_ID_RESET_CONFIG_SCREEN = 9,
|
||||||
|
SCREEN_ID_REBOOT_SCREEN = 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
void create_screen_boot_screen();
|
void create_screen_boot_screen();
|
||||||
|
|
@ -121,6 +138,12 @@ void tick_screen_about_screen();
|
||||||
|
|
||||||
void create_screen_status_screen();
|
void create_screen_status_screen();
|
||||||
void tick_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_by_id(enum ScreensEnum screenId);
|
||||||
void tick_screen(int screen_index);
|
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)
|
#if defined(EEZ_FOR_LVGL)
|
||||||
|
|
||||||
void ui_init() {
|
void ui_init() {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,13 @@
|
||||||
|
|
||||||
#include <lvgl.h>
|
#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)
|
#if defined(EEZ_FOR_LVGL)
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
char app_version[100] = { 0 };
|
char app_version[100] = { 0 };
|
||||||
char system_version[100] = { 0 };
|
char system_version[100] = { 0 };
|
||||||
char lvgl_version[32] = { 0 };
|
char lvgl_version[32] = { 0 };
|
||||||
|
char main_screen[32] = "home_screen";
|
||||||
|
|
||||||
const char *get_var_app_version() {
|
const char *get_var_app_version() {
|
||||||
return 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;
|
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 {
|
enum FlowGlobalVariables {
|
||||||
FLOW_GLOBAL_VARIABLE_APP_VERSION = 0,
|
FLOW_GLOBAL_VARIABLE_APP_VERSION = 0,
|
||||||
FLOW_GLOBAL_VARIABLE_SYSTEM_VERSION = 1,
|
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
|
// Native global variables
|
||||||
|
|
@ -28,6 +29,8 @@ extern const char *get_var_system_version();
|
||||||
extern void set_var_system_version(const char *value);
|
extern void set_var_system_version(const char *value);
|
||||||
extern const char *get_var_lvgl_version();
|
extern const char *get_var_lvgl_version();
|
||||||
extern void set_var_lvgl_version(const char *value);
|
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
|
#ifdef __cplusplus
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1,6 +1,7 @@
|
||||||
package native
|
package native
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Masterminds/semver/v3"
|
"github.com/Masterminds/semver/v3"
|
||||||
|
|
@ -17,6 +18,9 @@ type Native struct {
|
||||||
onVideoStateChange func(state VideoState)
|
onVideoStateChange func(state VideoState)
|
||||||
onVideoFrameReceived func(frame []byte, duration time.Duration)
|
onVideoFrameReceived func(frame []byte, duration time.Duration)
|
||||||
onIndevEvent func(event string)
|
onIndevEvent func(event string)
|
||||||
|
onRpcEvent func(event string)
|
||||||
|
videoLock sync.Mutex
|
||||||
|
screenLock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
type NativeOptions struct {
|
type NativeOptions struct {
|
||||||
|
|
@ -26,6 +30,7 @@ type NativeOptions struct {
|
||||||
OnVideoStateChange func(state VideoState)
|
OnVideoStateChange func(state VideoState)
|
||||||
OnVideoFrameReceived func(frame []byte, duration time.Duration)
|
OnVideoFrameReceived func(frame []byte, duration time.Duration)
|
||||||
OnIndevEvent func(event string)
|
OnIndevEvent func(event string)
|
||||||
|
OnRpcEvent func(event string)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNative(opts NativeOptions) *Native {
|
func NewNative(opts NativeOptions) *Native {
|
||||||
|
|
@ -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{
|
return &Native{
|
||||||
ready: make(chan struct{}),
|
ready: make(chan struct{}),
|
||||||
l: nativeLogger,
|
l: nativeLogger,
|
||||||
|
|
@ -60,6 +72,9 @@ func NewNative(opts NativeOptions) *Native {
|
||||||
onVideoStateChange: opts.OnVideoStateChange,
|
onVideoStateChange: opts.OnVideoStateChange,
|
||||||
onVideoFrameReceived: opts.OnVideoFrameReceived,
|
onVideoFrameReceived: opts.OnVideoFrameReceived,
|
||||||
onIndevEvent: opts.OnIndevEvent,
|
onIndevEvent: opts.OnIndevEvent,
|
||||||
|
onRpcEvent: opts.OnRpcEvent,
|
||||||
|
videoLock: sync.Mutex{},
|
||||||
|
screenLock: sync.Mutex{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -73,6 +88,7 @@ func (n *Native) Start() {
|
||||||
go n.handleVideoStateChan()
|
go n.handleVideoStateChan()
|
||||||
go n.handleVideoFrameChan()
|
go n.handleVideoFrameChan()
|
||||||
go n.handleIndevEventChan()
|
go n.handleIndevEventChan()
|
||||||
|
go n.handleRpcEventChan()
|
||||||
|
|
||||||
n.initUI()
|
n.initUI()
|
||||||
go n.tickUI()
|
go n.tickUI()
|
||||||
|
|
|
||||||
|
|
@ -9,27 +9,45 @@ type VideoState struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Native) VideoSetQualityFactor(factor float64) error {
|
func (n *Native) VideoSetQualityFactor(factor float64) error {
|
||||||
|
n.videoLock.Lock()
|
||||||
|
defer n.videoLock.Unlock()
|
||||||
|
|
||||||
return videoSetStreamQualityFactor(factor)
|
return videoSetStreamQualityFactor(factor)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Native) VideoGetQualityFactor() (float64, error) {
|
func (n *Native) VideoGetQualityFactor() (float64, error) {
|
||||||
|
n.videoLock.Lock()
|
||||||
|
defer n.videoLock.Unlock()
|
||||||
|
|
||||||
return videoGetStreamQualityFactor()
|
return videoGetStreamQualityFactor()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Native) VideoSetEDID(edid string) error {
|
func (n *Native) VideoSetEDID(edid string) error {
|
||||||
|
n.videoLock.Lock()
|
||||||
|
defer n.videoLock.Unlock()
|
||||||
|
|
||||||
return videoSetEDID(edid)
|
return videoSetEDID(edid)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Native) VideoGetEDID() (string, error) {
|
func (n *Native) VideoGetEDID() (string, error) {
|
||||||
|
n.videoLock.Lock()
|
||||||
|
defer n.videoLock.Unlock()
|
||||||
|
|
||||||
return videoGetEDID()
|
return videoGetEDID()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Native) VideoStop() error {
|
func (n *Native) VideoStop() error {
|
||||||
|
n.videoLock.Lock()
|
||||||
|
defer n.videoLock.Unlock()
|
||||||
|
|
||||||
videoStop()
|
videoStop()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Native) VideoStart() error {
|
func (n *Native) VideoStart() error {
|
||||||
|
n.videoLock.Lock()
|
||||||
|
defer n.videoLock.Unlock()
|
||||||
|
|
||||||
videoStart()
|
videoStart()
|
||||||
return nil
|
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"
|
"sync"
|
||||||
|
|
||||||
"github.com/jetkvm/kvm/internal/confparser"
|
"github.com/jetkvm/kvm/internal/confparser"
|
||||||
"github.com/jetkvm/kvm/internal/lldp"
|
|
||||||
"github.com/jetkvm/kvm/internal/logging"
|
"github.com/jetkvm/kvm/internal/logging"
|
||||||
"github.com/jetkvm/kvm/internal/udhcpc"
|
"github.com/jetkvm/kvm/internal/udhcpc"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
|
|
@ -31,8 +30,6 @@ type NetworkInterfaceState struct {
|
||||||
config *NetworkConfig
|
config *NetworkConfig
|
||||||
dhcpClient *udhcpc.DHCPClient
|
dhcpClient *udhcpc.DHCPClient
|
||||||
|
|
||||||
lldp *lldp.LLDP
|
|
||||||
|
|
||||||
defaultHostname string
|
defaultHostname string
|
||||||
currentHostname string
|
currentHostname string
|
||||||
currentFqdn 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.dhcpClient = dhcpClient
|
||||||
s.lldp = lldpClient
|
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -387,16 +367,13 @@ func (s *NetworkInterfaceState) updateNtpServersFromLease(lease *udhcpc.Lease) e
|
||||||
|
|
||||||
func (s *NetworkInterfaceState) handleInitialCheck() {
|
func (s *NetworkInterfaceState) handleInitialCheck() {
|
||||||
if s.IsUp() {
|
if s.IsUp() {
|
||||||
s.startLLDP()
|
|
||||||
}
|
}
|
||||||
s.onInitialCheck(s)
|
s.onInitialCheck(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NetworkInterfaceState) handleStateChange() {
|
func (s *NetworkInterfaceState) handleStateChange() {
|
||||||
if s.IsUp() {
|
if s.IsUp() {
|
||||||
s.startLLDP()
|
|
||||||
} else {
|
} else {
|
||||||
s.stopLLDP()
|
|
||||||
}
|
}
|
||||||
s.onStateChange(s)
|
s.onStateChange(s)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1259,5 +1259,4 @@ var rpcHandlers = map[string]RPCHandler{
|
||||||
"setKeyboardMacros": {Func: setKeyboardMacros, Params: []string{"params"}},
|
"setKeyboardMacros": {Func: setKeyboardMacros, Params: []string{"params"}},
|
||||||
"getLocalLoopbackOnly": {Func: rpcGetLocalLoopbackOnly},
|
"getLocalLoopbackOnly": {Func: rpcGetLocalLoopbackOnly},
|
||||||
"setLocalLoopbackOnly": {Func: rpcSetLocalLoopbackOnly, Params: []string{"enabled"}},
|
"setLocalLoopbackOnly": {Func: rpcSetLocalLoopbackOnly, Params: []string{"enabled"}},
|
||||||
"getLLDPNeighbors": {Func: rpcGetLLDPNeighbors},
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
12
native.go
12
native.go
|
|
@ -24,6 +24,18 @@ func initNative(systemVersion *semver.Version, appVersion *semver.Version) {
|
||||||
nativeLogger.Trace().Str("event", event).Msg("indev event received")
|
nativeLogger.Trace().Str("event", event).Msg("indev event received")
|
||||||
wakeDisplay(false, "indev_event")
|
wakeDisplay(false, "indev_event")
|
||||||
},
|
},
|
||||||
|
OnRpcEvent: func(event string) {
|
||||||
|
nativeLogger.Trace().Str("event", event).Msg("rpc event received")
|
||||||
|
switch event {
|
||||||
|
case "resetConfig":
|
||||||
|
rpcResetConfig()
|
||||||
|
rpcReboot(true)
|
||||||
|
case "reboot":
|
||||||
|
rpcReboot(true)
|
||||||
|
default:
|
||||||
|
nativeLogger.Warn().Str("event", event).Msg("unknown rpc event received")
|
||||||
|
}
|
||||||
|
},
|
||||||
OnVideoFrameReceived: func(frame []byte, duration time.Duration) {
|
OnVideoFrameReceived: func(frame []byte, duration time.Duration) {
|
||||||
if currentSession != nil {
|
if currentSession != nil {
|
||||||
err := currentSession.VideoTrack.WriteSample(media.Sample{Data: frame, Duration: duration})
|
err := currentSession.VideoTrack.WriteSample(media.Sample{Data: frame, Duration: duration})
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package kvm
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/jetkvm/kvm/internal/lldp"
|
|
||||||
"github.com/jetkvm/kvm/internal/network"
|
"github.com/jetkvm/kvm/internal/network"
|
||||||
"github.com/jetkvm/kvm/internal/udhcpc"
|
"github.com/jetkvm/kvm/internal/udhcpc"
|
||||||
)
|
)
|
||||||
|
|
@ -124,7 +123,3 @@ func rpcSetNetworkSettings(settings network.RpcNetworkSettings) (*network.RpcNet
|
||||||
func rpcRenewDHCPLease() error {
|
func rpcRenewDHCPLease() error {
|
||||||
return networkState.RpcRenewDHCPLease()
|
return networkState.RpcRenewDHCPLease()
|
||||||
}
|
}
|
||||||
|
|
||||||
func rpcGetLLDPNeighbors() ([]lldp.Neighbor, error) {
|
|
||||||
return networkState.GetLLDPNeighbors()
|
|
||||||
}
|
|
||||||
|
|
|
||||||
25
video.go
25
video.go
|
|
@ -1,13 +1,8 @@
|
||||||
package kvm
|
package kvm
|
||||||
|
|
||||||
import "github.com/jetkvm/kvm/internal/native"
|
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
|
|
||||||
}
|
|
||||||
|
|
||||||
var lastVideoState native.VideoState
|
var lastVideoState native.VideoState
|
||||||
|
|
||||||
|
|
@ -15,19 +10,9 @@ func triggerVideoStateUpdate() {
|
||||||
go func() {
|
go func() {
|
||||||
writeJSONRPCEvent("videoInputState", lastVideoState, currentSession)
|
writeJSONRPCEvent("videoInputState", lastVideoState, currentSession)
|
||||||
}()
|
}()
|
||||||
}
|
|
||||||
|
|
||||||
// func HandleVideoStateMessage(event CtrlResponse) {
|
nativeLogger.Info().Interface("state", lastVideoState).Msg("video state updated")
|
||||||
// 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)
|
|
||||||
// }
|
|
||||||
|
|
||||||
func rpcGetVideoState() (native.VideoState, error) {
|
func rpcGetVideoState() (native.VideoState, error) {
|
||||||
return lastVideoState, nil
|
return lastVideoState, nil
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue