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
|
||||
|
||||
set -e
|
||||
SUDO_PATH=$(which sudo)
|
||||
function sudo() {
|
||||
if [ "$UID" -eq 0 ]; then
|
||||
"$@"
|
||||
else
|
||||
${SUDO_PATH} "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
sudo apt-get update && sudo apt-get install -y --no-install-recommends \
|
||||
set -ex
|
||||
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
sudo apt-get update && \
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
build-essential \
|
||||
device-tree-compiler \
|
||||
gperf g++-multilib gcc-multilib \
|
||||
|
|
|
|||
|
|
@ -3,5 +3,6 @@
|
|||
"cva",
|
||||
"cx"
|
||||
],
|
||||
"cmake.sourceDirectory": "/Users/aveline/Projects/JetKVM/ymjk/internal/native/cgo"
|
||||
"cmake.sourceDirectory": "/Users/aveline/Projects/JetKVM/ymjk/internal/native/cgo",
|
||||
"git.ignoreLimitWarning": true
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
# syntax=docker/dockerfile:1
|
||||
FROM golang:1.25.1-trixie
|
||||
FROM --platform=${BUILDPLATFORM} golang:1.25.1-trixie AS builder
|
||||
|
||||
ENV GOTOOLCHAIN=local
|
||||
ENV GOPATH /go
|
||||
ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH
|
||||
ENV GOPATH=/go
|
||||
ENV PATH=$GOPATH/bin:/usr/local/go/bin:$PATH
|
||||
|
||||
ADD .devcontainer/install-deps.sh /install-deps.sh
|
||||
COPY .devcontainer/install-deps.sh /install-deps.sh
|
||||
RUN /install-deps.sh
|
||||
|
||||
# Create build directory
|
||||
|
|
|
|||
16
Makefile
16
Makefile
|
|
@ -3,15 +3,15 @@ BUILDDATE := $(shell date -u +%FT%T%z)
|
|||
BUILDTS := $(shell date -u +%s)
|
||||
REVISION := $(shell git rev-parse HEAD)
|
||||
VERSION_DEV := 0.4.8-dev$(shell date +%Y%m%d%H%M)
|
||||
VERSION := 0.4.7
|
||||
VERSION := 0.4.9
|
||||
|
||||
PROMETHEUS_TAG := github.com/prometheus/common/version
|
||||
KVM_PKG_NAME := github.com/jetkvm/kvm
|
||||
|
||||
BUILDKIT_FLAVOR := arm-rockchip830-linux-uclibcgnueabihf
|
||||
BUILDKIT_PATH ?= /opt/jetkvm-native-buildkit
|
||||
SKIP_NATIVE_IF_EXISTS ?= 1
|
||||
|
||||
SKIP_NATIVE_IF_EXISTS ?= 0
|
||||
SKIP_UI_BUILD ?= 0
|
||||
|
||||
GO_BUILD_ARGS := -tags netgo -tags timetzdata
|
||||
GO_RELEASE_BUILD_ARGS := -trimpath $(GO_BUILD_ARGS)
|
||||
|
|
@ -88,6 +88,9 @@ build_dev_test: build_test2json build_gotestsum
|
|||
tar czfv device-tests.tar.gz -C $(BIN_DIR)/tests .
|
||||
|
||||
frontend:
|
||||
@if [ "$(SKIP_UI_BUILD)" = "1" ]; then \
|
||||
echo "Skipping frontend build..."; \
|
||||
else \
|
||||
cd ui && npm ci && npm run build:device && \
|
||||
find ../static/ \
|
||||
-type f \
|
||||
|
|
@ -102,8 +105,9 @@ frontend:
|
|||
-o -name '*.svg' \
|
||||
-o -name '*.webp' \
|
||||
-o -name '*.woff2' \
|
||||
\) \
|
||||
-exec sh -c 'gzip -9 -kfv {}' \;
|
||||
\) \
|
||||
-exec sh -c 'gzip -9 -kfv {}' \; \
|
||||
fi
|
||||
|
||||
dev_release: frontend build_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.sha256 r2://jetkvm-update/app/$(VERSION_DEV)/jetkvm_app.sha256
|
||||
|
||||
build_release: frontend
|
||||
build_release: frontend build_native
|
||||
@echo "Building release..."
|
||||
$(GO_CMD) build \
|
||||
-ldflags="$(GO_LDFLAGS) -X $(KVM_PKG_NAME).builtAppVersion=$(VERSION)" \
|
||||
|
|
|
|||
|
|
@ -41,12 +41,16 @@ show_help() {
|
|||
REMOTE_USER="root"
|
||||
REMOTE_PATH="/userdata/jetkvm/bin"
|
||||
SKIP_UI_BUILD=false
|
||||
SKIP_UI_BUILD_RELEASE=0
|
||||
SKIP_NATIVE_BUILD=0
|
||||
RESET_USB_HID_DEVICE=false
|
||||
LOG_TRACE_SCOPES="${LOG_TRACE_SCOPES:-jetkvm,cloud,websocket,native,jsonrpc}"
|
||||
RUN_GO_TESTS=false
|
||||
RUN_GO_TESTS_ONLY=false
|
||||
INSTALL_APP=false
|
||||
BUILD_IN_DOCKER=false
|
||||
DOCKER_BUILD_DEBUG=false
|
||||
DOCKER_BUILD_TAG=ghcr.io/jetkvm/buildkit:latest
|
||||
|
||||
# Parse command line arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
|
|
@ -71,6 +75,14 @@ while [[ $# -gt 0 ]]; do
|
|||
RESET_USB_HID_DEVICE=true
|
||||
shift
|
||||
;;
|
||||
--build-in-docker)
|
||||
BUILD_IN_DOCKER=true
|
||||
shift
|
||||
;;
|
||||
--docker-build-debug)
|
||||
DOCKER_BUILD_DEBUG=true
|
||||
shift
|
||||
;;
|
||||
--run-go-tests)
|
||||
RUN_GO_TESTS=true
|
||||
shift
|
||||
|
|
@ -103,10 +115,59 @@ if [ -z "$REMOTE_HOST" ]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
# check if the current CPU architecture is x86_64
|
||||
if [ "$(uname -m)" != "x86_64" ]; then
|
||||
msg_warn "Warning: This script is only supported on x86_64 architecture"
|
||||
BUILD_IN_DOCKER=true
|
||||
fi
|
||||
|
||||
if [ "$BUILD_IN_DOCKER" = true ]; then
|
||||
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
|
||||
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"
|
||||
make frontend
|
||||
make frontend SKIP_UI_BUILD=0
|
||||
SKIP_UI_BUILD_RELEASE=1
|
||||
fi
|
||||
|
||||
if [ "$RUN_GO_TESTS" = true ]; then
|
||||
|
|
@ -154,7 +215,7 @@ fi
|
|||
if [ "$INSTALL_APP" = true ]
|
||||
then
|
||||
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.
|
||||
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"
|
||||
else
|
||||
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
|
||||
ssh "${REMOTE_USER}@${REMOTE_HOST}" "killall jetkvm_app_debug || true"
|
||||
|
|
|
|||
11
display.go
11
display.go
|
|
@ -23,7 +23,6 @@ var (
|
|||
)
|
||||
|
||||
const (
|
||||
touchscreenDevice string = "/dev/input/event1"
|
||||
backlightControlClass string = "/sys/class/backlight/backlight/brightness"
|
||||
)
|
||||
|
||||
|
|
@ -38,23 +37,25 @@ func updateDisplay() {
|
|||
|
||||
if usbState == "configured" {
|
||||
nativeInstance.UpdateLabelIfChanged("usb_status_label", "Connected")
|
||||
_, _ = nativeInstance.UIObjSetState("usb_status", "LV_STATE_DEFAULT")
|
||||
_, _ = nativeInstance.UIObjAddState("usb_status_label", "LV_STATE_CHECKED")
|
||||
} else {
|
||||
nativeInstance.UpdateLabelIfChanged("usb_status_label", "Disconnected")
|
||||
_, _ = nativeInstance.UIObjSetState("usb_status", "LV_STATE_DISABLED")
|
||||
_, _ = nativeInstance.UIObjClearState("usb_status_label", "LV_STATE_CHECKED")
|
||||
}
|
||||
if lastVideoState.Ready {
|
||||
nativeInstance.UpdateLabelIfChanged("hdmi_status_label", "Connected")
|
||||
_, _ = nativeInstance.UIObjSetState("hdmi_status", "LV_STATE_DEFAULT")
|
||||
_, _ = nativeInstance.UIObjAddState("hdmi_status_label", "LV_STATE_CHECKED")
|
||||
} else {
|
||||
nativeInstance.UpdateLabelIfChanged("hdmi_status_label", "Disconnected")
|
||||
_, _ = nativeInstance.UIObjSetState("hdmi_status", "LV_STATE_DISABLED")
|
||||
_, _ = nativeInstance.UIObjClearState("hdmi_status_label", "LV_STATE_CHECKED")
|
||||
}
|
||||
nativeInstance.UpdateLabelIfChanged("cloud_status_label", fmt.Sprintf("%d active", actionSessions))
|
||||
|
||||
if networkState.IsUp() {
|
||||
nativeInstance.UISetVar("main_screen", "home_screen")
|
||||
nativeInstance.SwitchToScreenIf("home_screen", []string{"no_network_screen", "boot_screen"})
|
||||
} else {
|
||||
nativeInstance.UISetVar("main_screen", "no_network_screen")
|
||||
nativeInstance.SwitchToScreenIf("no_network_screen", []string{"home_screen", "boot_screen"})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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_handler_t *video_state_handler = NULL;
|
||||
|
||||
jetkvm_rpc_handler_t *rpc_handler = NULL;
|
||||
jetkvm_video_handler_t *video_handler = NULL;
|
||||
|
||||
|
||||
|
|
@ -34,6 +34,16 @@ void jetkvm_set_indev_handler(jetkvm_indev_handler_t *handler) {
|
|||
lvgl_set_indev_handler(handler);
|
||||
}
|
||||
|
||||
void jetkvm_set_rpc_handler(jetkvm_rpc_handler_t *handler) {
|
||||
rpc_handler = handler;
|
||||
}
|
||||
|
||||
void jetkvm_call_rpc_handler(const char *method, const char *params) {
|
||||
if (rpc_handler != NULL) {
|
||||
(*rpc_handler)(method, params);
|
||||
}
|
||||
}
|
||||
|
||||
const char *jetkvm_ui_event_code_to_name(int code) {
|
||||
lv_event_code_t cCode = (lv_event_code_t)code;
|
||||
return lv_event_code_get_name(code);
|
||||
|
|
@ -237,38 +247,52 @@ void jetkvm_ui_set_image(const char *obj_name, const char *image_name) {
|
|||
lv_img_set_src(obj, image_name);
|
||||
}
|
||||
|
||||
void jetkvm_ui_set_state(const char *obj_name, const char *state_name) {
|
||||
lv_state_t str_to_lv_state(const char *state_name) {
|
||||
if (strcmp(state_name, "LV_STATE_USER_1") == 0) {
|
||||
return LV_STATE_USER_1;
|
||||
}
|
||||
else if (strcmp(state_name, "LV_STATE_USER_2") == 0) {
|
||||
return LV_STATE_USER_2;
|
||||
}
|
||||
else if (strcmp(state_name, "LV_STATE_USER_3") == 0) {
|
||||
return LV_STATE_USER_3;
|
||||
}
|
||||
else if (strcmp(state_name, "LV_STATE_USER_4") == 0) {
|
||||
return LV_STATE_USER_4;
|
||||
}
|
||||
else if (strcmp(state_name, "LV_STATE_DISABLED") == 0) {
|
||||
return LV_STATE_DISABLED;
|
||||
}
|
||||
else if (strcmp(state_name, "LV_STATE_DEFAULT") == 0) {
|
||||
return LV_STATE_DEFAULT;
|
||||
}
|
||||
else if (strcmp(state_name, "LV_STATE_CHECKED") == 0) {
|
||||
return LV_STATE_CHECKED;
|
||||
}
|
||||
else if (strcmp(state_name, "LV_STATE_FOCUSED") == 0) {
|
||||
return LV_STATE_FOCUSED;
|
||||
}
|
||||
return LV_STATE_DEFAULT;
|
||||
}
|
||||
|
||||
void jetkvm_ui_add_state(const char *obj_name, const char *state_name) {
|
||||
lv_obj_t *obj = ui_get_obj(obj_name);
|
||||
if (obj == NULL) {
|
||||
return;
|
||||
}
|
||||
lv_obj_add_state(obj, LV_STATE_USER_1);
|
||||
lv_state_t state_val = LV_STATE_DEFAULT;
|
||||
if (strcmp(state_name, "LV_STATE_USER_1") == 0)
|
||||
{
|
||||
state_val = LV_STATE_USER_1;
|
||||
}
|
||||
else if (strcmp(state_name, "LV_STATE_USER_2") == 0)
|
||||
{
|
||||
state_val = LV_STATE_USER_2;
|
||||
}
|
||||
else if (strcmp(state_name, "LV_STATE_USER_3") == 0)
|
||||
{
|
||||
state_val = LV_STATE_USER_3;
|
||||
}
|
||||
else if (strcmp(state_name, "LV_STATE_USER_4") == 0)
|
||||
{
|
||||
state_val = LV_STATE_USER_4;
|
||||
}
|
||||
else if (strcmp(state_name, "LV_STATE_DISABLED") == 0)
|
||||
{
|
||||
state_val = LV_STATE_DISABLED;
|
||||
}
|
||||
// TODO: use LV_STATE_USER_* once eez supports it
|
||||
lv_obj_clear_state(obj, LV_STATE_USER_1 | LV_STATE_USER_2 | LV_STATE_USER_3 | LV_STATE_USER_4 | LV_STATE_DISABLED);
|
||||
lv_state_t state_val = str_to_lv_state(state_name);
|
||||
lv_obj_add_state(obj, state_val);
|
||||
}
|
||||
|
||||
void jetkvm_ui_clear_state(const char *obj_name, const char *state_name) {
|
||||
lv_obj_t *obj = ui_get_obj(obj_name);
|
||||
if (obj == NULL) {
|
||||
return;
|
||||
}
|
||||
lv_state_t state_val = str_to_lv_state(state_name);
|
||||
lv_obj_clear_state(obj, state_val);
|
||||
}
|
||||
|
||||
int jetkvm_ui_add_flag(const char *obj_name, const char *flag_name) {
|
||||
lv_obj_t *obj = ui_get_obj(obj_name);
|
||||
if (obj == NULL) {
|
||||
|
|
|
|||
|
|
@ -16,12 +16,15 @@ typedef struct
|
|||
|
||||
typedef void (jetkvm_video_state_handler_t)(jetkvm_video_state_t *state);
|
||||
typedef void (jetkvm_log_handler_t)(int level, const char *filename, const char *funcname, int line, const char *message);
|
||||
typedef void (jetkvm_rpc_handler_t)(const char *method, const char *params);
|
||||
typedef void (jetkvm_video_handler_t)(const uint8_t *frame, ssize_t len);
|
||||
typedef void (jetkvm_indev_handler_t)(int code);
|
||||
|
||||
void jetkvm_set_log_handler(jetkvm_log_handler_t *handler);
|
||||
void jetkvm_set_video_handler(jetkvm_video_handler_t *handler);
|
||||
void jetkvm_set_indev_handler(jetkvm_indev_handler_t *handler);
|
||||
void jetkvm_set_rpc_handler(jetkvm_rpc_handler_t *handler);
|
||||
void jetkvm_call_rpc_handler(const char *method, const char *params);
|
||||
void jetkvm_set_video_state_handler(jetkvm_video_state_handler_t *handler);
|
||||
|
||||
void jetkvm_ui_set_var(const char *name, const char *value);
|
||||
|
|
@ -36,7 +39,8 @@ const char *jetkvm_ui_get_current_screen();
|
|||
void jetkvm_ui_load_screen(const char *obj_name);
|
||||
int jetkvm_ui_set_text(const char *obj_name, const char *text);
|
||||
void jetkvm_ui_set_image(const char *obj_name, const char *image_name);
|
||||
void jetkvm_ui_set_state(const char *obj_name, const char *state_name);
|
||||
void jetkvm_ui_add_state(const char *obj_name, const char *state_name);
|
||||
void jetkvm_ui_clear_state(const char *obj_name, const char *state_name);
|
||||
void jetkvm_ui_fade_in(const char *obj_name, u_int32_t duration);
|
||||
void jetkvm_ui_fade_out(const char *obj_name, u_int32_t duration);
|
||||
void jetkvm_ui_set_opacity(const char *obj_name, u_int8_t opacity);
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ int get_edid(uint8_t *edid, size_t max_size)
|
|||
fd = open(V4L_SUBDEV, O_RDWR);
|
||||
if (fd < 0)
|
||||
{
|
||||
perror("Failed to open device");
|
||||
log_error("Failed to open device");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -48,7 +48,7 @@ int get_edid(uint8_t *edid, size_t max_size)
|
|||
|
||||
if (ioctl(fd, VIDIOC_G_EDID, &v4l2_edid) < 0)
|
||||
{
|
||||
perror("Failed to get EDID");
|
||||
log_error("Failed to get EDID");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -90,7 +90,7 @@ int set_edid(uint8_t *edid, size_t size)
|
|||
fd = open(V4L_SUBDEV, O_RDWR);
|
||||
if (fd < 0)
|
||||
{
|
||||
perror("Failed to open device");
|
||||
log_error("Failed to open device");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -104,7 +104,7 @@ int set_edid(uint8_t *edid, size_t size)
|
|||
|
||||
if (ioctl(fd, VIDIOC_S_EDID, &v4l2_edid) < 0)
|
||||
{
|
||||
perror("Failed to set EDID");
|
||||
log_error("Failed to set EDID");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -123,13 +123,13 @@ const char *videoc_log_status()
|
|||
fd = open(V4L_SUBDEV, O_RDWR);
|
||||
if (fd < 0)
|
||||
{
|
||||
perror("Failed to open device");
|
||||
log_error("Failed to open device");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ioctl(fd, VIDIOC_LOG_STATUS) == -1)
|
||||
{
|
||||
perror("VIDIOC_LOG_STATUS failed");
|
||||
log_error("VIDIOC_LOG_STATUS failed");
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -166,14 +166,14 @@ const char *videoc_log_status()
|
|||
buffer = strdup(p);
|
||||
if (buffer == NULL)
|
||||
{
|
||||
perror("Failed to allocate memory for status");
|
||||
log_error("Failed to allocate memory for status");
|
||||
return NULL;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
log_error("Failed to read kernel log\n");
|
||||
log_error("Failed to read kernel log");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,25 @@
|
|||
#define LOG_HANDLER_H
|
||||
|
||||
typedef void (jetkvm_log_handler_t)(int level, const char *filename, const char *funcname, const int line, const char *message);
|
||||
|
||||
/**
|
||||
* @brief Log a message
|
||||
*
|
||||
* @param level The level of the message
|
||||
* @param filename The filename of the message
|
||||
* @param funcname The function name of the message
|
||||
* @param line The line number of the message
|
||||
* @param message The message to log
|
||||
* @return void
|
||||
*/
|
||||
void log_message(int level, const char *filename, const char *funcname, const int line, const char *message);
|
||||
|
||||
/**
|
||||
* @brief Set the log handler
|
||||
*
|
||||
* @param handler The handler to set
|
||||
* @return void
|
||||
*/
|
||||
void log_set_handler(jetkvm_log_handler_t *handler);
|
||||
|
||||
#endif
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
// #include "st7789/lcd.h"
|
||||
#include "ui/ui.h"
|
||||
#include "ui_index.h"
|
||||
#include "ctrl.h"
|
||||
|
||||
#define DISP_BUF_SIZE (300 * 240 * 2)
|
||||
static lv_color_t buf[DISP_BUF_SIZE];
|
||||
|
|
@ -32,8 +33,6 @@ void lvgl_init(u_int16_t rotation) {
|
|||
/*LittlevGL init*/
|
||||
lv_init();
|
||||
|
||||
/*Linux frame buffer device init*/
|
||||
|
||||
/*Linux frame buffer device init*/
|
||||
lv_display_t *disp = lv_linux_fbdev_create();
|
||||
// lv_display_set_physical_resolution(disp, 240, 300);
|
||||
|
|
@ -42,29 +41,6 @@ void lvgl_init(u_int16_t rotation) {
|
|||
|
||||
lvgl_set_rotation(disp, rotation);
|
||||
|
||||
// lv_display_t *disp = lv_st7789_create(LCD_H_RES, LCD_V_RES, LV_LCD_FLAG_NONE, lcd_send_cmd, lcd_send_color);
|
||||
// lv_display_set_resolution(disp, 240, 300);
|
||||
// lv_display_set_rotation(disp, LV_DISP_ROTATION_270);
|
||||
|
||||
// lv_color_t * buf1 = NULL;
|
||||
// lv_color_t * buf2 = NULL;
|
||||
|
||||
// uint32_t buf_size = LCD_H_RES * LCD_V_RES / 10 * lv_color_format_get_size(lv_display_get_color_format(disp));
|
||||
|
||||
// buf1 = lv_malloc(buf_size);
|
||||
// if(buf1 == NULL) {
|
||||
// log_error("display draw buffer malloc failed");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// buf2 = lv_malloc(buf_size);
|
||||
// if(buf2 == NULL) {
|
||||
// log_error("display buffer malloc failed");
|
||||
// lv_free(buf1);
|
||||
// return;
|
||||
// }
|
||||
// lv_display_set_buffers(disp, buf1, buf2, buf_size, LV_DISPLAY_RENDER_MODE_PARTIAL);
|
||||
|
||||
/* Linux input device init */
|
||||
lv_indev_t *mouse = lv_evdev_create(LV_INDEV_TYPE_POINTER, "/dev/input/event1");
|
||||
lv_indev_set_group(mouse, lv_group_get_default());
|
||||
|
|
@ -76,10 +52,9 @@ void lvgl_init(u_int16_t rotation) {
|
|||
|
||||
ui_init();
|
||||
|
||||
ui_set_rpc_handler((jetkvm_rpc_handler_t *)jetkvm_call_rpc_handler);
|
||||
|
||||
log_info("ui initalized");
|
||||
// lv_label_set_text(ui_Boot_Screen_Version, "");
|
||||
// lv_label_set_text(ui_Home_Content_Ip, "...");
|
||||
// lv_label_set_text(ui_Home_Header_Cloud_Status_Label, "0 active");
|
||||
}
|
||||
|
||||
void lvgl_tick(void) {
|
||||
|
|
@ -188,7 +163,7 @@ lv_img_dsc_t *ui_get_image(const char *name) {
|
|||
void ui_set_text(const char *name, const char *text) {
|
||||
lv_obj_t *obj = ui_get_obj(name);
|
||||
if(obj == NULL) {
|
||||
log_error("ui_set_text %s %s, obj not found\n", name, text);
|
||||
log_error("ui_set_text %s %s, obj not found", name, text);
|
||||
return;
|
||||
}
|
||||
lv_label_set_text(obj, text);
|
||||
|
|
|
|||
|
|
@ -12,10 +12,37 @@ void lvgl_tick(void);
|
|||
|
||||
void lvgl_set_rotation(lv_display_t *disp, u_int16_t rotation);
|
||||
|
||||
/**
|
||||
* @brief Set the text of an object
|
||||
*
|
||||
* @param name The name of the object
|
||||
* @param text The text to set
|
||||
* @return void
|
||||
*/
|
||||
void ui_set_text(const char *name, const char *text);
|
||||
|
||||
/**
|
||||
* @brief Get the object with the given name
|
||||
*
|
||||
* @param name The name of the object
|
||||
* @return lv_obj_t* The object with the given name
|
||||
*/
|
||||
lv_obj_t *ui_get_obj(const char *name);
|
||||
|
||||
/**
|
||||
* @brief Get the style with the given name
|
||||
*
|
||||
* @param name The name of the style
|
||||
* @return lv_style_t* The style with the given name
|
||||
*/
|
||||
lv_style_t *ui_get_style(const char *name);
|
||||
|
||||
/**
|
||||
* @brief Get the image with the given name
|
||||
*
|
||||
* @param name The name of the image
|
||||
* @return lv_img_dsc_t* The image with the given name
|
||||
*/
|
||||
lv_img_dsc_t *ui_get_image(const char *name);
|
||||
|
||||
#endif // SCREEN_H
|
||||
|
|
|
|||
|
|
@ -268,14 +268,14 @@ static void *venc_read_stream(void *arg)
|
|||
stFrame.pstPack = malloc(sizeof(VENC_PACK_S));
|
||||
while (venc_running)
|
||||
{
|
||||
// printf("RK_MPI_VENC_GetStream\n");
|
||||
log_trace("RK_MPI_VENC_GetStream");
|
||||
s32Ret = RK_MPI_VENC_GetStream(VENC_CHANNEL, &stFrame, 200); // blocks max 200ms
|
||||
if (s32Ret == RK_SUCCESS)
|
||||
{
|
||||
RK_U64 nowUs = get_us();
|
||||
// printf("chn:0, loopCount:%d enc->seq:%d wd:%d pts=%llu delay=%lldus\n",
|
||||
// loopCount, stFrame.u32Seq, stFrame.pstPack->u32Len,
|
||||
// stFrame.pstPack->u64PTS, nowUs - stFrame.pstPack->u64PTS);
|
||||
log_trace("chn:0, loopCount:%d enc->seq:%d wd:%d pts=%llu delay=%lldus",
|
||||
loopCount, stFrame.u32Seq, stFrame.pstPack->u32Len,
|
||||
stFrame.pstPack->u64PTS, nowUs - stFrame.pstPack->u64PTS);
|
||||
pData = RK_MPI_MB_Handle2VirAddr(stFrame.pstPack->pMbBlk);
|
||||
video_send_frame(pData, (ssize_t)stFrame.pstPack->u32Len);
|
||||
s32Ret = RK_MPI_VENC_ReleaseStream(VENC_CHANNEL, &stFrame);
|
||||
|
|
@ -304,6 +304,7 @@ uint32_t detected_width, detected_height;
|
|||
bool detected_signal = false, streaming_flag = false;
|
||||
|
||||
pthread_t *streaming_thread = NULL;
|
||||
pthread_mutex_t streaming_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
void write_buffer_to_file(const uint8_t *buffer, size_t length, const char *filename)
|
||||
{
|
||||
|
|
@ -322,7 +323,7 @@ void *run_video_stream(void *arg)
|
|||
{
|
||||
if (detected_signal == false)
|
||||
{
|
||||
usleep(100000);
|
||||
usleep(10000); // Reduced to 10ms for better responsiveness to streaming_flag changes
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -347,7 +348,7 @@ void *run_video_stream(void *arg)
|
|||
|
||||
if (ioctl(video_dev_fd, VIDIOC_S_FMT, &fmt) < 0)
|
||||
{
|
||||
perror("Set format fail");
|
||||
log_error("Set format fail: %s", strerror(errno));
|
||||
usleep(100000); // Sleep for 100 milliseconds
|
||||
close(video_dev_fd);
|
||||
continue;
|
||||
|
|
@ -362,7 +363,8 @@ void *run_video_stream(void *arg)
|
|||
|
||||
if (ioctl(video_dev_fd, VIDIOC_REQBUFS, &req) < 0)
|
||||
{
|
||||
perror("VIDIOC_REQBUFS failed");
|
||||
log_error("VIDIOC_REQBUFS failed: %s", strerror(errno));
|
||||
close(video_dev_fd);
|
||||
return errno;
|
||||
}
|
||||
log_info("VIDIOC_REQBUFS successful");
|
||||
|
|
@ -384,32 +386,35 @@ void *run_video_stream(void *arg)
|
|||
|
||||
if (-1 == ioctl(video_dev_fd, VIDIOC_QUERYBUF, &buf))
|
||||
{
|
||||
perror("VIDIOC_QUERYBUF failed");
|
||||
log_error("VIDIOC_QUERYBUF failed: %s", strerror(errno));
|
||||
req.count = i;
|
||||
close(video_dev_fd);
|
||||
return errno;
|
||||
}
|
||||
printf("VIDIOC_QUERYBUF successful for buffer %d\n", i);
|
||||
log_info("VIDIOC_QUERYBUF successful for buffer %d", i);
|
||||
|
||||
printf("plane: length = %d\n", planes_buffer->length);
|
||||
printf("plane: offset = %d\n", planes_buffer->m.mem_offset);
|
||||
log_info("plane: length = %d", planes_buffer->length);
|
||||
log_info("plane: offset = %d", planes_buffer->m.mem_offset);
|
||||
|
||||
MB_BLK blk = RK_MPI_MB_GetMB(memPool, (planes_buffer)->length, RK_TRUE);
|
||||
if (blk == NULL)
|
||||
{
|
||||
RK_LOGE("get mb blk failed!");
|
||||
log_error("get mb blk failed!");
|
||||
close(video_dev_fd);
|
||||
return -1;
|
||||
}
|
||||
printf("Got memory block for buffer %d\n", i);
|
||||
log_info("Got memory block for buffer %d", i);
|
||||
|
||||
buffers[i].mb_blk = blk;
|
||||
|
||||
RK_S32 buf_fd = (RK_MPI_MB_Handle2Fd(blk));
|
||||
if (buf_fd < 0)
|
||||
{
|
||||
RK_LOGE("RK_MPI_MB_Handle2Fd failed!");
|
||||
log_error("RK_MPI_MB_Handle2Fd failed!");
|
||||
close(video_dev_fd);
|
||||
return -1;
|
||||
}
|
||||
printf("Converted memory block to file descriptor for buffer %d\n", i);
|
||||
log_info("Converted memory block to file descriptor for buffer %d", i);
|
||||
planes_buffer->m.fd = buf_fd;
|
||||
}
|
||||
|
||||
|
|
@ -424,15 +429,16 @@ void *run_video_stream(void *arg)
|
|||
buf.m.planes = &buffers[i].plane_buffer;
|
||||
if (ioctl(video_dev_fd, VIDIOC_QBUF, &buf) < 0)
|
||||
{
|
||||
perror("VIDIOC_QBUF failed");
|
||||
log_error("VIDIOC_QBUF failed: %s", strerror(errno));
|
||||
close(video_dev_fd);
|
||||
return errno;
|
||||
}
|
||||
printf("VIDIOC_QBUF successful for buffer %d\n", i);
|
||||
log_info("VIDIOC_QBUF successful for buffer %d", i);
|
||||
}
|
||||
|
||||
if (ioctl(video_dev_fd, VIDIOC_STREAMON, &type) < 0)
|
||||
{
|
||||
perror("VIDIOC_STREAMON failed");
|
||||
log_error("VIDIOC_STREAMON failed: %s", strerror(errno));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
|
@ -463,7 +469,7 @@ void *run_video_stream(void *arg)
|
|||
r = select(video_dev_fd + 1, &fds, NULL, NULL, &tv);
|
||||
if (r == 0)
|
||||
{
|
||||
log_info("select timeout \n");
|
||||
log_info("select timeout");
|
||||
break;
|
||||
}
|
||||
if (r == -1)
|
||||
|
|
@ -472,7 +478,7 @@ void *run_video_stream(void *arg)
|
|||
{
|
||||
continue;
|
||||
}
|
||||
perror("select in video streaming");
|
||||
log_error("select in video streaming");
|
||||
break;
|
||||
}
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
|
|
@ -482,10 +488,10 @@ void *run_video_stream(void *arg)
|
|||
buf.length = 1;
|
||||
if (ioctl(video_dev_fd, VIDIOC_DQBUF, &buf) < 0)
|
||||
{
|
||||
perror("VIDIOC_DQBUF failed");
|
||||
log_error("VIDIOC_DQBUF failed: %s", strerror(errno));
|
||||
break;
|
||||
}
|
||||
// printf("got frame, bytesused = %d\n", tmp_plane.bytesused);
|
||||
log_trace("got frame, bytesused = %d", tmp_plane.bytesused);
|
||||
memset(&stFrame, 0, sizeof(VIDEO_FRAME_INFO_S));
|
||||
MB_BLK blk = RK_NULL;
|
||||
blk = RK_MPI_MMZ_Fd2Handle(tmp_plane.m.fd);
|
||||
|
|
@ -503,26 +509,16 @@ void *run_video_stream(void *arg)
|
|||
stFrame.stVFrame.u32FrameFlag |= 0;
|
||||
stFrame.stVFrame.enCompressMode = COMPRESS_MODE_NONE;
|
||||
bool retried = false;
|
||||
// if (num == 100) {
|
||||
// RK_VOID *pData = RK_MPI_MB_Handle2VirAddr(stFrame.stVFrame.pMbBlk);
|
||||
// if (pData) {
|
||||
// size_t frameSize = tmp_plane.bytesused; // Use the actual size reported by the driver
|
||||
// write_buffer_to_file(pData, frameSize, "/userdata/banana.raw");
|
||||
// printf("Frame 100 written to /userdata/banana.raw\n");
|
||||
// } else {
|
||||
// printf("Failed to get virtual address for frame 100\n");
|
||||
// }
|
||||
// }
|
||||
retry_send_frame:
|
||||
if (RK_MPI_VENC_SendFrame(VENC_CHANNEL, &stFrame, 2000) != RK_SUCCESS)
|
||||
{
|
||||
if (retried == true)
|
||||
{
|
||||
RK_LOGE("RK_MPI_VENC_SendFrame retry failed");
|
||||
log_error("RK_MPI_VENC_SendFrame retry failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
RK_LOGE("RK_MPI_VENC_SendFrame failed,retrying");
|
||||
log_error("RK_MPI_VENC_SendFrame failed,retrying");
|
||||
retried = true;
|
||||
usleep(1000llu);
|
||||
goto retry_send_frame;
|
||||
|
|
@ -532,12 +528,13 @@ void *run_video_stream(void *arg)
|
|||
num++;
|
||||
|
||||
if (ioctl(video_dev_fd, VIDIOC_QBUF, &buf) < 0)
|
||||
printf("failture VIDIOC_QBUF\n");
|
||||
log_error("failure VIDIOC_QBUF: %s", strerror(errno));
|
||||
}
|
||||
cleanup:
|
||||
log_info("cleaning up video capture device %s", VIDEO_DEV);
|
||||
if (ioctl(video_dev_fd, VIDIOC_STREAMOFF, &type) < 0)
|
||||
{
|
||||
perror("VIDIOC_STREAMOFF failed");
|
||||
log_error("VIDIOC_STREAMOFF failed: %s", strerror(errno));
|
||||
}
|
||||
|
||||
venc_stop();
|
||||
|
|
@ -550,9 +547,11 @@ void *run_video_stream(void *arg)
|
|||
}
|
||||
}
|
||||
|
||||
log_info("closing video capture device %s", VIDEO_DEV);
|
||||
close(video_dev_fd);
|
||||
}
|
||||
|
||||
log_info("video stream thread exiting");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -560,65 +559,78 @@ void video_shutdown()
|
|||
{
|
||||
if (should_exit == true)
|
||||
{
|
||||
printf("shutting down in progress already\n");
|
||||
log_info("shutting down in progress already");
|
||||
return;
|
||||
}
|
||||
video_stop_streaming();
|
||||
// if (buffers != NULL) {
|
||||
// for (int i = 0; i < input_buffer_count; i++) {
|
||||
// if ((buffers + i)->mb_blk != NULL) {
|
||||
// RK_MPI_MB_ReleaseMB((buffers + i)->mb_blk);
|
||||
// }
|
||||
// free((buffers + i)->planes_buffer);
|
||||
// }
|
||||
// free(buffers);
|
||||
// }
|
||||
|
||||
should_exit = true;
|
||||
if (sub_dev_fd > 0)
|
||||
{
|
||||
shutdown(sub_dev_fd, SHUT_RDWR);
|
||||
// close(sub_dev_fd);
|
||||
printf("Closed sub_dev_fd\n");
|
||||
log_info("Closed sub_dev_fd");
|
||||
}
|
||||
|
||||
if (memPool != MB_INVALID_POOLID)
|
||||
{
|
||||
RK_MPI_MB_DestroyPool(memPool);
|
||||
}
|
||||
printf("Destroyed memory pool\n");
|
||||
// if (format_thread != NULL) {
|
||||
// pthread_join(*format_thread, NULL);
|
||||
// free(format_thread);
|
||||
// format_thread = NULL;
|
||||
// }
|
||||
// printf("Joined format detection thread\n");
|
||||
log_info("Destroyed memory pool");
|
||||
|
||||
pthread_mutex_destroy(&streaming_mutex);
|
||||
log_info("Destroyed streaming mutex");
|
||||
}
|
||||
|
||||
// TODO: mutex?
|
||||
|
||||
void video_start_streaming()
|
||||
{
|
||||
pthread_mutex_lock(&streaming_mutex);
|
||||
if (streaming_thread != NULL)
|
||||
{
|
||||
log_info("video streaming already started");
|
||||
return;
|
||||
log_warn("video streaming already started");
|
||||
goto cleanup;
|
||||
}
|
||||
streaming_thread = malloc(sizeof(pthread_t));
|
||||
assert(streaming_thread != NULL);
|
||||
|
||||
pthread_t *new_thread = malloc(sizeof(pthread_t));
|
||||
if (new_thread == NULL)
|
||||
{
|
||||
log_error("Failed to allocate memory for streaming thread");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
streaming_flag = true;
|
||||
pthread_create(streaming_thread, NULL, run_video_stream, NULL);
|
||||
int result = pthread_create(new_thread, NULL, run_video_stream, NULL);
|
||||
if (result != 0)
|
||||
{
|
||||
log_error("Failed to create streaming thread: %s", strerror(result));
|
||||
streaming_flag = false;
|
||||
free(new_thread);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Only set streaming_thread after successful creation, and before unlocking the mutex
|
||||
streaming_thread = new_thread;
|
||||
cleanup:
|
||||
pthread_mutex_unlock(&streaming_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
void video_stop_streaming()
|
||||
{
|
||||
pthread_mutex_lock(&streaming_mutex);
|
||||
if (streaming_thread != NULL)
|
||||
{
|
||||
streaming_flag = false;
|
||||
log_info("stopping video streaming");
|
||||
// wait 100ms for the thread to exit
|
||||
usleep(1000000);
|
||||
log_info("waiting for video streaming thread to exit");
|
||||
pthread_join(*streaming_thread, NULL);
|
||||
free(streaming_thread);
|
||||
streaming_thread = NULL;
|
||||
log_info("video streaming stopped");
|
||||
}
|
||||
pthread_mutex_unlock(&streaming_mutex);
|
||||
}
|
||||
|
||||
void *run_detect_format(void *arg)
|
||||
|
|
@ -632,7 +644,6 @@ void *run_detect_format(void *arg)
|
|||
if (ioctl(sub_dev_fd, VIDIOC_SUBSCRIBE_EVENT, &sub) == -1)
|
||||
{
|
||||
log_error("cannot subscribe to event");
|
||||
perror("Cannot subscribe to event");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
|
@ -657,12 +668,12 @@ void *run_detect_format(void *arg)
|
|||
else if (errno == ERANGE)
|
||||
{
|
||||
// Timings were found, but they are out of range of the hardware capabilities.
|
||||
printf("HDMI status: out of range\n");
|
||||
log_warn("HDMI status: out of range");
|
||||
video_report_format(false, "out_of_range", 0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
perror("error VIDIOC_QUERY_DV_TIMINGS");
|
||||
log_error("error VIDIOC_QUERY_DV_TIMINGS: %s", strerror(errno));
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -681,19 +692,24 @@ void *run_detect_format(void *arg)
|
|||
detected_height = dv_timings.bt.height;
|
||||
detected_signal = true;
|
||||
video_report_format(true, NULL, detected_width, detected_height, frames_per_second);
|
||||
pthread_mutex_lock(&streaming_mutex);
|
||||
if (streaming_flag == true)
|
||||
{
|
||||
pthread_mutex_unlock(&streaming_mutex);
|
||||
log_info("restarting on going video streaming");
|
||||
video_stop_streaming();
|
||||
video_start_streaming();
|
||||
}
|
||||
else
|
||||
{
|
||||
pthread_mutex_unlock(&streaming_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
if (ioctl(sub_dev_fd, VIDIOC_DQEVENT, &ev) != 0)
|
||||
{
|
||||
log_error("failed to VIDIOC_DQEVENT");
|
||||
perror("failed to VIDIOC_DQEVENT");
|
||||
log_error("failed to VIDIOC_DQEVENT: %s", strerror(errno));
|
||||
break;
|
||||
}
|
||||
log_info("New event of type %u", ev.type);
|
||||
|
|
@ -715,12 +731,18 @@ void video_set_quality_factor(float factor)
|
|||
|
||||
// TODO: update venc bitrate without stopping streaming
|
||||
|
||||
pthread_mutex_lock(&streaming_mutex);
|
||||
if (streaming_flag == true)
|
||||
{
|
||||
pthread_mutex_unlock(&streaming_mutex);
|
||||
log_info("restarting on going video streaming due to quality factor change");
|
||||
video_stop_streaming();
|
||||
video_start_streaming();
|
||||
}
|
||||
else
|
||||
{
|
||||
pthread_mutex_unlock(&streaming_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
float video_get_quality_factor() {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,48 @@
|
|||
#ifndef VIDEO_DAEMON_VIDEO_H
|
||||
#define VIDEO_DAEMON_VIDEO_H
|
||||
|
||||
/**
|
||||
* @brief Initialize the video subsystem
|
||||
*
|
||||
* @return int 0 on success, -1 on failure
|
||||
*/
|
||||
int video_init();
|
||||
|
||||
/**
|
||||
* @brief Shutdown the video subsystem
|
||||
*/
|
||||
void video_shutdown();
|
||||
|
||||
/**
|
||||
* @brief Run the detect format thread
|
||||
*
|
||||
* @param arg The argument to pass to the thread
|
||||
* @return void* The result of the thread
|
||||
*/
|
||||
void *run_detect_format(void *arg);
|
||||
|
||||
/**
|
||||
* @brief Start the video streaming
|
||||
*/
|
||||
void video_start_streaming();
|
||||
|
||||
/**
|
||||
* @brief Stop the video streaming
|
||||
*/
|
||||
void video_stop_streaming();
|
||||
|
||||
/**
|
||||
* @brief Set the quality factor of the video
|
||||
*
|
||||
* @param factor The quality factor to set
|
||||
*/
|
||||
void video_set_quality_factor(float factor);
|
||||
|
||||
/**
|
||||
* @brief Get the quality factor of the video
|
||||
*
|
||||
* @return float The quality factor of the video
|
||||
*/
|
||||
float video_get_quality_factor();
|
||||
|
||||
#endif //VIDEO_DAEMON_VIDEO_H
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ package native
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
|
|
@ -37,9 +38,16 @@ extern void jetkvm_go_indev_handler(int code);
|
|||
static inline void jetkvm_cgo_setup_indev_handler() {
|
||||
jetkvm_set_indev_handler(&jetkvm_go_indev_handler);
|
||||
}
|
||||
|
||||
extern void jetkvm_go_rpc_handler(cchar_t *method, cchar_t *params);
|
||||
static inline void jetkvm_cgo_setup_rpc_handler() {
|
||||
jetkvm_set_rpc_handler(&jetkvm_go_rpc_handler);
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
var cgoLock sync.Mutex
|
||||
|
||||
//export jetkvm_go_video_state_handler
|
||||
func jetkvm_go_video_state_handler(state *C.jetkvm_video_state_t) {
|
||||
videoState := VideoState{
|
||||
|
|
@ -75,6 +83,11 @@ func jetkvm_go_indev_handler(code C.int) {
|
|||
indevEventChan <- int(code)
|
||||
}
|
||||
|
||||
//export jetkvm_go_rpc_handler
|
||||
func jetkvm_go_rpc_handler(method *C.cchar_t, params *C.cchar_t) {
|
||||
rpcEventChan <- C.GoString(method)
|
||||
}
|
||||
|
||||
var eventCodeToNameMap = map[int]string{}
|
||||
|
||||
func uiEventCodeToName(code int) string {
|
||||
|
|
@ -90,13 +103,20 @@ func uiEventCodeToName(code int) string {
|
|||
}
|
||||
|
||||
func setUpNativeHandlers() {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
C.jetkvm_cgo_setup_log_handler()
|
||||
C.jetkvm_cgo_setup_video_state_handler()
|
||||
C.jetkvm_cgo_setup_video_handler()
|
||||
C.jetkvm_cgo_setup_indev_handler()
|
||||
C.jetkvm_cgo_setup_rpc_handler()
|
||||
}
|
||||
|
||||
func uiInit(rotation uint16) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
cRotation := C.u_int16_t(rotation)
|
||||
defer C.free(unsafe.Pointer(&cRotation))
|
||||
|
||||
|
|
@ -104,10 +124,16 @@ func uiInit(rotation uint16) {
|
|||
}
|
||||
|
||||
func uiTick() {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
C.jetkvm_ui_tick()
|
||||
}
|
||||
|
||||
func videoInit() error {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
ret := C.jetkvm_video_init()
|
||||
if ret != 0 {
|
||||
return fmt.Errorf("failed to initialize video: %d", ret)
|
||||
|
|
@ -116,18 +142,30 @@ func videoInit() error {
|
|||
}
|
||||
|
||||
func videoShutdown() {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
C.jetkvm_video_shutdown()
|
||||
}
|
||||
|
||||
func videoStart() {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
C.jetkvm_video_start()
|
||||
}
|
||||
|
||||
func videoStop() {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
C.jetkvm_video_stop()
|
||||
}
|
||||
|
||||
func uiSetVar(name string, value string) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
nameCStr := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(nameCStr))
|
||||
|
||||
|
|
@ -138,6 +176,9 @@ func uiSetVar(name string, value string) {
|
|||
}
|
||||
|
||||
func uiGetVar(name string) string {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
nameCStr := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(nameCStr))
|
||||
|
||||
|
|
@ -145,31 +186,58 @@ func uiGetVar(name string) string {
|
|||
}
|
||||
|
||||
func uiSwitchToScreen(screen string) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
screenCStr := C.CString(screen)
|
||||
defer C.free(unsafe.Pointer(screenCStr))
|
||||
C.jetkvm_ui_load_screen(screenCStr)
|
||||
}
|
||||
|
||||
func uiGetCurrentScreen() string {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
screenCStr := C.jetkvm_ui_get_current_screen()
|
||||
return C.GoString(screenCStr)
|
||||
}
|
||||
|
||||
func uiObjSetState(objName string, state string) (bool, error) {
|
||||
func uiObjAddState(objName string, state string) (bool, error) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
objNameCStr := C.CString(objName)
|
||||
defer C.free(unsafe.Pointer(objNameCStr))
|
||||
stateCStr := C.CString(state)
|
||||
defer C.free(unsafe.Pointer(stateCStr))
|
||||
C.jetkvm_ui_set_state(objNameCStr, stateCStr)
|
||||
C.jetkvm_ui_add_state(objNameCStr, stateCStr)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func uiObjClearState(objName string, state string) (bool, error) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
objNameCStr := C.CString(objName)
|
||||
defer C.free(unsafe.Pointer(objNameCStr))
|
||||
stateCStr := C.CString(state)
|
||||
defer C.free(unsafe.Pointer(stateCStr))
|
||||
C.jetkvm_ui_clear_state(objNameCStr, stateCStr)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func uiGetLVGLVersion() string {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
return C.GoString(C.jetkvm_ui_get_lvgl_version())
|
||||
}
|
||||
|
||||
// TODO: use Enum instead of string but it's not a hot path and performance is not a concern now
|
||||
func uiObjAddFlag(objName string, flag string) (bool, error) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
objNameCStr := C.CString(objName)
|
||||
defer C.free(unsafe.Pointer(objNameCStr))
|
||||
flagCStr := C.CString(flag)
|
||||
|
|
@ -179,6 +247,9 @@ func uiObjAddFlag(objName string, flag string) (bool, error) {
|
|||
}
|
||||
|
||||
func uiObjClearFlag(objName string, flag string) (bool, error) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
objNameCStr := C.CString(objName)
|
||||
defer C.free(unsafe.Pointer(objNameCStr))
|
||||
flagCStr := C.CString(flag)
|
||||
|
|
@ -196,6 +267,9 @@ func uiObjShow(objName string) (bool, error) {
|
|||
}
|
||||
|
||||
func uiObjSetOpacity(objName string, opacity int) (bool, error) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
objNameCStr := C.CString(objName)
|
||||
defer C.free(unsafe.Pointer(objNameCStr))
|
||||
|
||||
|
|
@ -204,6 +278,9 @@ func uiObjSetOpacity(objName string, opacity int) (bool, error) {
|
|||
}
|
||||
|
||||
func uiObjFadeIn(objName string, duration uint32) (bool, error) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
objNameCStr := C.CString(objName)
|
||||
defer C.free(unsafe.Pointer(objNameCStr))
|
||||
|
||||
|
|
@ -213,6 +290,9 @@ func uiObjFadeIn(objName string, duration uint32) (bool, error) {
|
|||
}
|
||||
|
||||
func uiObjFadeOut(objName string, duration uint32) (bool, error) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
objNameCStr := C.CString(objName)
|
||||
defer C.free(unsafe.Pointer(objNameCStr))
|
||||
|
||||
|
|
@ -222,6 +302,9 @@ func uiObjFadeOut(objName string, duration uint32) (bool, error) {
|
|||
}
|
||||
|
||||
func uiLabelSetText(objName string, text string) (bool, error) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
objNameCStr := C.CString(objName)
|
||||
defer C.free(unsafe.Pointer(objNameCStr))
|
||||
|
||||
|
|
@ -236,6 +319,9 @@ func uiLabelSetText(objName string, text string) (bool, error) {
|
|||
}
|
||||
|
||||
func uiImgSetSrc(objName string, src string) (bool, error) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
objNameCStr := C.CString(objName)
|
||||
defer C.free(unsafe.Pointer(objNameCStr))
|
||||
|
||||
|
|
@ -248,6 +334,9 @@ func uiImgSetSrc(objName string, src string) (bool, error) {
|
|||
}
|
||||
|
||||
func uiDispSetRotation(rotation uint16) (bool, error) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
nativeLogger.Info().Uint16("rotation", rotation).Msg("setting rotation")
|
||||
|
||||
cRotation := C.u_int16_t(rotation)
|
||||
|
|
@ -258,21 +347,33 @@ func uiDispSetRotation(rotation uint16) (bool, error) {
|
|||
}
|
||||
|
||||
func videoGetStreamQualityFactor() (float64, error) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
factor := C.jetkvm_video_get_quality_factor()
|
||||
return float64(factor), nil
|
||||
}
|
||||
|
||||
func videoSetStreamQualityFactor(factor float64) error {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
C.jetkvm_video_set_quality_factor(C.float(factor))
|
||||
return nil
|
||||
}
|
||||
|
||||
func videoGetEDID() (string, error) {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
edidCStr := C.jetkvm_video_get_edid_hex()
|
||||
return C.GoString(edidCStr), nil
|
||||
}
|
||||
|
||||
func videoSetEDID(edid string) error {
|
||||
cgoLock.Lock()
|
||||
defer cgoLock.Unlock()
|
||||
|
||||
edidCStr := C.CString(edid)
|
||||
defer C.free(unsafe.Pointer(edidCStr))
|
||||
C.jetkvm_video_set_edid(edidCStr)
|
||||
|
|
|
|||
|
|
@ -28,7 +28,12 @@ func uiGetCurrentScreen() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func uiObjSetState(objName string, state string) (bool, error) {
|
||||
func uiObjAddState(objName string, state string) (bool, error) {
|
||||
panicPlatformNotSupported()
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func uiObjClearState(objName string, state string) (bool, error) {
|
||||
panicPlatformNotSupported()
|
||||
return false, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ var (
|
|||
videoStateChan chan VideoState = make(chan VideoState)
|
||||
logChan chan nativeLogMessage = make(chan nativeLogMessage)
|
||||
indevEventChan chan int = make(chan int)
|
||||
rpcEventChan chan string = make(chan string)
|
||||
)
|
||||
|
||||
func (n *Native) handleVideoFrameChan() {
|
||||
|
|
@ -70,3 +71,10 @@ func (n *Native) handleIndevEventChan() {
|
|||
n.onIndevEvent(name)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Native) handleRpcEventChan() {
|
||||
for {
|
||||
event := <-rpcEventChan
|
||||
n.onRpcEvent(event)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,9 +37,24 @@ func (n *Native) UIObjShow(objName string) (bool, error) {
|
|||
return uiObjShow(objName)
|
||||
}
|
||||
|
||||
// UIObjSetState clears the state then adds the new state
|
||||
func (n *Native) UIObjSetState(objName string, state string) (bool, error) {
|
||||
return uiObjSetState(objName, state)
|
||||
// UISetVar sets the variable
|
||||
func (n *Native) UISetVar(name string, value string) {
|
||||
uiSetVar(name, value)
|
||||
}
|
||||
|
||||
// UIGetVar gets the variable
|
||||
func (n *Native) UIGetVar(name string) string {
|
||||
return uiGetVar(name)
|
||||
}
|
||||
|
||||
// UIObjAddState adds the state to the object
|
||||
func (n *Native) UIObjAddState(objName string, state string) (bool, error) {
|
||||
return uiObjAddState(objName, state)
|
||||
}
|
||||
|
||||
// UIObjClearState clears the state from the object
|
||||
func (n *Native) UIObjClearState(objName string, state string) (bool, error) {
|
||||
return uiObjClearState(objName, state)
|
||||
}
|
||||
|
||||
// UIObjAddFlag adds the flag to the object
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"navigation": {
|
||||
"selectedUserPageObject": "[jetkvm.eez-project]:/userPages/5",
|
||||
"selectedActionObject": "[jetkvm.eez-project]:/actions/0",
|
||||
"selectedUserPageObject": "[jetkvm.eez-project]:/userPages/8",
|
||||
"selectedActionObject": "[jetkvm.eez-project]:/actions/12",
|
||||
"selectedGlobalVariableObject": "[jetkvm.eez-project]:/variables/globalVariables/1",
|
||||
"selectedStyleObject": "[jetkvm.eez-project]:/lvglStyles/styles/0",
|
||||
"selectedStyleObject": "[jetkvm.eez-project]:/lvglStyles/styles/8",
|
||||
"selectedThemeObject": "[jetkvm.eez-project]:/themes/0",
|
||||
"selectedFontObject": "[jetkvm.eez-project]:/fonts/4",
|
||||
"selectedBitmapObject": "[jetkvm.eez-project]:/bitmaps/11",
|
||||
"selectedBitmapObject": "[jetkvm.eez-project]:/bitmaps/9",
|
||||
"subnavigationSelectedItems": {
|
||||
"variables-tab/sub-navigation/selected-item": "Global"
|
||||
}
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
{
|
||||
"type": "border",
|
||||
"selected": 2,
|
||||
"size": 113.5,
|
||||
"size": 271.5,
|
||||
"location": "right",
|
||||
"children": [
|
||||
{
|
||||
|
|
@ -77,7 +77,7 @@
|
|||
},
|
||||
{
|
||||
"type": "border",
|
||||
"selected": 1,
|
||||
"selected": 0,
|
||||
"location": "bottom",
|
||||
"children": [
|
||||
{
|
||||
|
|
@ -188,38 +188,48 @@
|
|||
"enableClose": false,
|
||||
"icon": "svg:variable"
|
||||
}
|
||||
],
|
||||
"active": true
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "tabset",
|
||||
"id": "EDITORS",
|
||||
"weight": 49.31058517127421,
|
||||
"selected": 4,
|
||||
"weight": 52.479136828866125,
|
||||
"selected": 5,
|
||||
"enableDeleteWhenEmpty": false,
|
||||
"enableClose": false,
|
||||
"children": [
|
||||
{
|
||||
"type": "tab",
|
||||
"id": "#aec56ae8-5b75-4a2f-ad81-f0d7d683c77a",
|
||||
"name": "FontBook24",
|
||||
"id": "#2b774476-9ef3-4363-83f8-8b478f163b02",
|
||||
"name": "MenuAdvancedScreen",
|
||||
"component": "editor",
|
||||
"config": {
|
||||
"objectPath": "[jetkvm.eez-project]:/fonts/4",
|
||||
"objectPath": "[jetkvm.eez-project]:/userPages/4",
|
||||
"permanent": false
|
||||
},
|
||||
"icon": "material:font_download"
|
||||
"icon": "svg:page"
|
||||
},
|
||||
{
|
||||
"type": "tab",
|
||||
"id": "#7bbd8382-ea41-467d-8ad3-4312a2d47266",
|
||||
"name": "ResetConfigScreen",
|
||||
"component": "editor",
|
||||
"config": {
|
||||
"objectPath": "[jetkvm.eez-project]:/userPages/8",
|
||||
"permanent": true
|
||||
},
|
||||
"icon": "svg:page"
|
||||
},
|
||||
{
|
||||
"type": "tab",
|
||||
"id": "#c8dece00-e490-46b8-8a14-5dcfa8bbce36",
|
||||
"name": "AboutScreen",
|
||||
"name": "StatusScreen",
|
||||
"component": "editor",
|
||||
"config": {
|
||||
"objectPath": "[jetkvm.eez-project]:/userPages/5",
|
||||
"permanent": false
|
||||
"objectPath": "[jetkvm.eez-project]:/userPages/7",
|
||||
"permanent": true
|
||||
},
|
||||
"icon": "svg:page"
|
||||
},
|
||||
|
|
@ -237,7 +247,7 @@
|
|||
{
|
||||
"type": "tab",
|
||||
"id": "#f5a057a5-977c-46be-8702-5447d603a34f",
|
||||
"name": "MenuScreen",
|
||||
"name": "HomeScreen",
|
||||
"component": "editor",
|
||||
"config": {
|
||||
"objectPath": "[jetkvm.eez-project]:/userPages/2",
|
||||
|
|
@ -257,12 +267,13 @@
|
|||
},
|
||||
"icon": "material:settings"
|
||||
}
|
||||
]
|
||||
],
|
||||
"active": true
|
||||
},
|
||||
{
|
||||
"type": "row",
|
||||
"id": "#ee319cf9-6145-49e4-b40e-1d999be897c8",
|
||||
"weight": 24.95234430353635,
|
||||
"weight": 21.78379264594443,
|
||||
"children": [
|
||||
{
|
||||
"type": "tabset",
|
||||
|
|
@ -1065,8 +1076,7 @@
|
|||
"0": {
|
||||
"0": {
|
||||
"0": {
|
||||
"1": {},
|
||||
"$selected": true
|
||||
"1": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1086,11 +1096,58 @@
|
|||
}
|
||||
},
|
||||
"[jetkvm.eez-project]:/userPages/1[flow-state]": {
|
||||
"selection": {
|
||||
"0": {
|
||||
"0": {
|
||||
"0": {},
|
||||
"1": {},
|
||||
"$selected": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"transform": {
|
||||
"translate": {
|
||||
"x": -180,
|
||||
"y": -207
|
||||
},
|
||||
"scale": 1
|
||||
},
|
||||
"timeline": {
|
||||
"isEditorActive": false,
|
||||
"position": 0,
|
||||
"secondToPx": 200,
|
||||
"scrollLeft": 0
|
||||
}
|
||||
},
|
||||
"[jetkvm.eez-project]:/lvglStyles/styles[tree-state]": {
|
||||
"0": {},
|
||||
"1": {},
|
||||
"2": {},
|
||||
"3": {},
|
||||
"4": {
|
||||
"$selected": true
|
||||
},
|
||||
"5": {
|
||||
"$selected": true
|
||||
},
|
||||
"6": {
|
||||
"$selected": true
|
||||
},
|
||||
"7": {
|
||||
"$selected": true
|
||||
},
|
||||
"8": {
|
||||
"$selected": true
|
||||
}
|
||||
},
|
||||
"[jetkvm.eez-project]:/userPages/2[flow-state]": {
|
||||
"selection": {
|
||||
"0": {
|
||||
"0": {
|
||||
"0": {
|
||||
"0": {},
|
||||
"0": {
|
||||
"$selected": true
|
||||
},
|
||||
"1": {
|
||||
"0": {}
|
||||
}
|
||||
|
|
@ -1102,9 +1159,7 @@
|
|||
"3": {
|
||||
"0": {
|
||||
"0": {},
|
||||
"1": {
|
||||
"$selected": true
|
||||
}
|
||||
"1": {}
|
||||
},
|
||||
"1": {
|
||||
"0": {},
|
||||
|
|
@ -1128,12 +1183,7 @@
|
|||
"scrollLeft": 0
|
||||
}
|
||||
},
|
||||
"[jetkvm.eez-project]:/lvglStyles/styles[tree-state]": {
|
||||
"0": {
|
||||
"$selected": true
|
||||
}
|
||||
},
|
||||
"[jetkvm.eez-project]:/userPages/2[flow-state]": {
|
||||
"[jetkvm.eez-project]:/userPages/3[flow-state]": {
|
||||
"selection": {
|
||||
"0": {
|
||||
"0": {
|
||||
|
|
@ -1142,13 +1192,14 @@
|
|||
},
|
||||
"1": {
|
||||
"0": {
|
||||
"0": {},
|
||||
"0": {
|
||||
"$selected": true
|
||||
},
|
||||
"1": {},
|
||||
"2": {},
|
||||
"3": {},
|
||||
"4": {
|
||||
"0": {},
|
||||
"$selected": true
|
||||
"0": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1169,19 +1220,15 @@
|
|||
"scrollLeft": 0
|
||||
}
|
||||
},
|
||||
"[jetkvm.eez-project]:/userPages/3[flow-state]": {
|
||||
"[jetkvm.eez-project]:/userPages/4[flow-state]": {
|
||||
"selection": {
|
||||
"0": {
|
||||
"0": {
|
||||
"0": {
|
||||
"0": {},
|
||||
"$selected": true
|
||||
"0": {}
|
||||
},
|
||||
"1": {
|
||||
"0": {
|
||||
"0": {},
|
||||
"1": {},
|
||||
"2": {},
|
||||
"3": {}
|
||||
}
|
||||
}
|
||||
|
|
@ -1190,41 +1237,8 @@
|
|||
},
|
||||
"transform": {
|
||||
"translate": {
|
||||
"x": -150,
|
||||
"y": -120
|
||||
},
|
||||
"scale": 1
|
||||
},
|
||||
"timeline": {
|
||||
"isEditorActive": false,
|
||||
"position": 0,
|
||||
"secondToPx": 200,
|
||||
"scrollLeft": 0
|
||||
}
|
||||
},
|
||||
"[jetkvm.eez-project]:/userPages/4[flow-state]": {
|
||||
"selection": {
|
||||
"0": {
|
||||
"0": {
|
||||
"0": {
|
||||
"0": {
|
||||
"$selected": true
|
||||
}
|
||||
},
|
||||
"1": {
|
||||
"0": {
|
||||
"0": {},
|
||||
"1": {},
|
||||
"2": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"transform": {
|
||||
"translate": {
|
||||
"x": -176,
|
||||
"y": -127
|
||||
"x": -181,
|
||||
"y": -256.3828125
|
||||
},
|
||||
"scale": 1
|
||||
},
|
||||
|
|
@ -1245,19 +1259,8 @@
|
|||
"1": {
|
||||
"0": {
|
||||
"0": {},
|
||||
"1": {
|
||||
"1": {}
|
||||
},
|
||||
"2": {},
|
||||
"3": {},
|
||||
"4": {},
|
||||
"5": {
|
||||
"1": {
|
||||
"$selected": true
|
||||
}
|
||||
},
|
||||
"6": {},
|
||||
"7": {}
|
||||
"1": {},
|
||||
"2": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1300,11 +1303,11 @@
|
|||
"0": {},
|
||||
"1": {
|
||||
"0": {
|
||||
"0": {},
|
||||
"0": {
|
||||
"1": {}
|
||||
},
|
||||
"2": {
|
||||
"1": {
|
||||
"$selected": true
|
||||
}
|
||||
"1": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1313,7 +1316,7 @@
|
|||
},
|
||||
"transform": {
|
||||
"translate": {
|
||||
"x": -138,
|
||||
"x": -10.425644531250029,
|
||||
"y": -122
|
||||
},
|
||||
"scale": 1
|
||||
|
|
@ -1324,6 +1327,67 @@
|
|||
"secondToPx": 200,
|
||||
"scrollLeft": 0
|
||||
}
|
||||
},
|
||||
"[jetkvm.eez-project]:/userPages/7[flow-state]": {
|
||||
"selection": {
|
||||
"0": {
|
||||
"0": {
|
||||
"0": {},
|
||||
"1": {},
|
||||
"$selected": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"transform": {
|
||||
"translate": {
|
||||
"x": -180,
|
||||
"y": -207
|
||||
},
|
||||
"scale": 1
|
||||
},
|
||||
"timeline": {
|
||||
"isEditorActive": false,
|
||||
"position": 0,
|
||||
"secondToPx": 200,
|
||||
"scrollLeft": 0
|
||||
}
|
||||
},
|
||||
"[jetkvm.eez-project]:/userPages/8[flow-state]": {
|
||||
"selection": {
|
||||
"0": {
|
||||
"0": {
|
||||
"0": {
|
||||
"0": {}
|
||||
},
|
||||
"1": {
|
||||
"0": {
|
||||
"0": {
|
||||
"0": {
|
||||
"$selected": true
|
||||
}
|
||||
},
|
||||
"1": {},
|
||||
"2": {
|
||||
"0": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"transform": {
|
||||
"translate": {
|
||||
"x": -194,
|
||||
"y": -37
|
||||
},
|
||||
"scale": 1
|
||||
},
|
||||
"timeline": {
|
||||
"isEditorActive": false,
|
||||
"position": 0,
|
||||
"secondToPx": 200,
|
||||
"scrollLeft": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"activeOutputSection": 0,
|
||||
|
|
@ -1339,10 +1403,10 @@
|
|||
"logsPanelFilter": "all",
|
||||
"selectedStylePropertyName": "",
|
||||
"lvglPart": "MAIN",
|
||||
"lvglState": "DISABLED",
|
||||
"lvglState": "DEFAULT",
|
||||
"lvglExpandedPropertiesGroup": [
|
||||
"MARGIN",
|
||||
"TEXT"
|
||||
"POSITION AND SIZE",
|
||||
"LAYOUT"
|
||||
],
|
||||
"showInactiveFlowsInDebugger": true,
|
||||
"globalFlowZoom": true,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
#include "actions.h"
|
||||
#include "screens.h"
|
||||
#include <stdio.h>
|
||||
#include "ui.h"
|
||||
#include "vars.h"
|
||||
|
||||
int handle_gesture_screen_switch(lv_event_t *e, lv_dir_t direction, int screenId) {
|
||||
lv_event_code_t event_code = lv_event_get_code(e);
|
||||
|
|
@ -15,6 +18,15 @@ int handle_gesture_screen_switch(lv_event_t *e, lv_dir_t direction, int screenId
|
|||
return 1;
|
||||
}
|
||||
|
||||
void handle_gesture_main_screen_switch(lv_event_t *e, lv_dir_t direction) {
|
||||
const char *main_screen = get_var_main_screen();
|
||||
if (strcmp(main_screen, "home_screen") == 0) {
|
||||
loadScreen(SCREEN_ID_HOME_SCREEN);
|
||||
} else if (strcmp(main_screen, "no_network_screen") == 0) {
|
||||
loadScreen(SCREEN_ID_NO_NETWORK_SCREEN);
|
||||
}
|
||||
}
|
||||
|
||||
void action_switch_to_menu(lv_event_t *e) {
|
||||
loadScreen(SCREEN_ID_MENU_SCREEN);
|
||||
}
|
||||
|
|
@ -31,8 +43,16 @@ void action_switch_to_about(lv_event_t *e) {
|
|||
loadScreen(SCREEN_ID_ABOUT_SCREEN);
|
||||
}
|
||||
|
||||
void action_switch_to_reset_config(lv_event_t *e) {
|
||||
loadScreen(SCREEN_ID_RESET_CONFIG_SCREEN);
|
||||
}
|
||||
|
||||
void action_switch_to_reboot(lv_event_t *e) {
|
||||
loadScreen(SCREEN_ID_REBOOT_SCREEN);
|
||||
}
|
||||
|
||||
void action_menu_screen_gesture(lv_event_t * e) {
|
||||
handle_gesture_screen_switch(e, LV_DIR_RIGHT, SCREEN_ID_HOME_SCREEN);
|
||||
handle_gesture_main_screen_switch(e, LV_DIR_RIGHT);
|
||||
}
|
||||
|
||||
void action_menu_advanced_screen_gesture(lv_event_t * e) {
|
||||
|
|
@ -40,7 +60,7 @@ void action_menu_advanced_screen_gesture(lv_event_t * e) {
|
|||
}
|
||||
|
||||
void action_reset_config_screen_gesture(lv_event_t * e) {
|
||||
handle_gesture_screen_switch(e, LV_DIR_RIGHT, SCREEN_ID_MENU_ADVANCED_SCREEN);
|
||||
handle_gesture_screen_switch(e, LV_DIR_RIGHT, SCREEN_ID_MENU_SCREEN);
|
||||
}
|
||||
|
||||
void action_home_screen_gesture(lv_event_t * e) {
|
||||
|
|
@ -50,3 +70,71 @@ void action_home_screen_gesture(lv_event_t * e) {
|
|||
void action_about_screen_gesture(lv_event_t * e) {
|
||||
handle_gesture_screen_switch(e, LV_DIR_RIGHT, SCREEN_ID_MENU_SCREEN);
|
||||
}
|
||||
|
||||
// user_data doesn't seem to be working, so we use a global variable here
|
||||
static uint32_t t_reset_config;
|
||||
static uint32_t t_reboot;
|
||||
static bool b_reboot = false;
|
||||
static bool b_reset_config = false;
|
||||
const int RESET_CONFIG_HOLD_TIME = 10;
|
||||
const int REBOOT_HOLD_TIME = 5;
|
||||
|
||||
void action_reset_config(lv_event_t * e) {
|
||||
lv_event_code_t event_code = lv_event_get_code(e);
|
||||
lv_obj_t *obj = lv_event_get_target(e);
|
||||
|
||||
if (event_code == LV_EVENT_PRESSED) {
|
||||
t_reset_config = lv_tick_get();
|
||||
}
|
||||
else if (event_code == LV_EVENT_PRESSING) {
|
||||
int remaining_time = RESET_CONFIG_HOLD_TIME * 1000 - lv_tick_elaps(t_reset_config);
|
||||
if (remaining_time <= 0) {
|
||||
lv_obj_add_flag(objects.reset_config_button, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(objects.reset_config_spinner, LV_OBJ_FLAG_HIDDEN);
|
||||
ui_call_rpc_handler("resetConfig", NULL);
|
||||
b_reset_config = true;
|
||||
} else {
|
||||
b_reset_config = false;
|
||||
char buf[100];
|
||||
int remaining_time_seconds = remaining_time / 1000;
|
||||
if (remaining_time_seconds <= 1) {
|
||||
remaining_time_seconds = 1;
|
||||
}
|
||||
sprintf(buf, "Press and hold for %d seconds", remaining_time_seconds);
|
||||
lv_label_set_text(objects.reset_config_label, buf);
|
||||
}
|
||||
} else if (event_code == LV_EVENT_RELEASED) {
|
||||
if (!b_reset_config) {
|
||||
lv_label_set_text(objects.reset_config_label, "Press and hold for 10 seconds");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void action_reboot(lv_event_t * e) {
|
||||
lv_event_code_t event_code = lv_event_get_code(e);
|
||||
lv_obj_t *obj = lv_event_get_target(e);
|
||||
|
||||
if (event_code == LV_EVENT_PRESSED) {
|
||||
t_reboot = lv_tick_get();
|
||||
}
|
||||
else if (event_code == LV_EVENT_PRESSING) {
|
||||
int remaining_time = REBOOT_HOLD_TIME * 1000 - lv_tick_elaps(t_reboot);
|
||||
if (remaining_time <= 0) {
|
||||
ui_call_rpc_handler("reboot", NULL);
|
||||
b_reboot = false;
|
||||
} else {
|
||||
b_reboot = false;
|
||||
char buf[100];
|
||||
int remaining_time_seconds = remaining_time / 1000;
|
||||
if (remaining_time_seconds <= 1) {
|
||||
remaining_time_seconds = 1;
|
||||
}
|
||||
sprintf(buf, "Press and hold for %d seconds", remaining_time_seconds);
|
||||
lv_label_set_text(objects.reboot_label, buf);
|
||||
}
|
||||
} else if (event_code == LV_EVENT_RELEASED) {
|
||||
if (!b_reboot) {
|
||||
lv_label_set_text(objects.reboot_label, "Press and hold for 5 seconds");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ extern int handle_gesture_screen_switch(lv_event_t *e, lv_dir_t direction, int s
|
|||
|
||||
extern void action_switch_to_menu(lv_event_t * e);
|
||||
extern void action_switch_to_advanced_menu(lv_event_t * e);
|
||||
extern void action_switch_to_reset_config(lv_event_t * e);
|
||||
extern void action_switch_to_about(lv_event_t * e);
|
||||
extern void action_menu_screen_gesture(lv_event_t * e);
|
||||
extern void action_home_screen_gesture(lv_event_t * e);
|
||||
|
|
@ -20,6 +21,9 @@ extern void action_about_screen_gesture(lv_event_t * e);
|
|||
extern void action_switch_to_status(lv_event_t * e);
|
||||
extern void action_common_click_event(lv_event_t * e);
|
||||
extern void action_handle_common_press_event(lv_event_t * e);
|
||||
extern void action_reset_config(lv_event_t * e);
|
||||
extern void action_reboot(lv_event_t * e);
|
||||
extern void action_switch_to_reboot(lv_event_t * e);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
|
|
@ -325,10 +325,11 @@ void create_screen_home_screen() {
|
|||
lv_obj_t *obj = lv_label_create(parent_obj);
|
||||
objects.home_info_ipv6_addr = obj;
|
||||
lv_obj_set_pos(obj, LV_PCT(0), LV_PCT(0));
|
||||
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
|
||||
lv_obj_set_size(obj, LV_PCT(98), 17);
|
||||
lv_label_set_long_mode(obj, LV_LABEL_LONG_DOT);
|
||||
add_style_label_font16(obj);
|
||||
lv_label_set_text(obj, "fe80::ffff:ffff:ffff:ffff:ffff:ffff");
|
||||
lv_obj_set_style_text_align(obj, LV_TEXT_ALIGN_LEFT, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_label_set_text(obj, "fe80::ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
|
||||
}
|
||||
{
|
||||
// HomeInfoMACAddr
|
||||
|
|
@ -431,10 +432,11 @@ void create_screen_home_screen() {
|
|||
objects.usb_status_label = obj;
|
||||
lv_obj_set_pos(obj, LV_PCT(0), LV_PCT(0));
|
||||
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
|
||||
lv_obj_add_flag(obj, LV_OBJ_FLAG_CHECKABLE);
|
||||
add_style_label_font16(obj);
|
||||
lv_obj_set_style_text_color(obj, lv_color_hex(0xff22c55e), LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_text_color(obj, lv_color_hex(0xff808080), LV_PART_MAIN | LV_STATE_DISABLED);
|
||||
lv_label_set_text(obj, "Connected");
|
||||
lv_obj_set_style_text_color(obj, lv_color_hex(0xff808080), LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_text_color(obj, lv_color_hex(0xff22c55e), LV_PART_MAIN | LV_STATE_CHECKED);
|
||||
lv_label_set_text(obj, "Unknown");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -493,11 +495,11 @@ void create_screen_home_screen() {
|
|||
objects.hdmi_status_label = obj;
|
||||
lv_obj_set_pos(obj, LV_PCT(0), LV_PCT(0));
|
||||
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
|
||||
lv_obj_add_state(obj, LV_STATE_DISABLED);
|
||||
lv_obj_add_flag(obj, LV_OBJ_FLAG_CHECKABLE);
|
||||
add_style_label_font16(obj);
|
||||
lv_obj_set_style_text_color(obj, lv_color_hex(0xff22c55e), LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_text_color(obj, lv_color_hex(0xff808080), LV_PART_MAIN | LV_STATE_DISABLED);
|
||||
lv_label_set_text(obj, "Disconnected");
|
||||
lv_obj_set_style_text_color(obj, lv_color_hex(0xff22c55e), LV_PART_MAIN | LV_STATE_CHECKED);
|
||||
lv_obj_set_style_text_color(obj, lv_color_hex(0xff808080), LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_label_set_text(obj, "Unknown");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -829,6 +831,8 @@ void create_screen_menu_advanced_screen() {
|
|||
objects.menu_btn_advanced_developer_mode = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), 50);
|
||||
lv_obj_add_event_cb(obj, action_reset_config, LV_EVENT_PRESSED, (void *)0);
|
||||
lv_obj_add_flag(obj, LV_OBJ_FLAG_HIDDEN);
|
||||
add_style_menu_button(obj);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
|
|
@ -847,6 +851,7 @@ void create_screen_menu_advanced_screen() {
|
|||
objects.menu_btn_advanced_usb_emulation = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), 50);
|
||||
lv_obj_add_flag(obj, LV_OBJ_FLAG_HIDDEN);
|
||||
add_style_menu_button(obj);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
|
|
@ -865,6 +870,7 @@ void create_screen_menu_advanced_screen() {
|
|||
objects.menu_btn_advanced_reboot = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), 50);
|
||||
lv_obj_add_event_cb(obj, action_switch_to_reboot, LV_EVENT_PRESSED, (void *)0);
|
||||
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SNAPPABLE);
|
||||
add_style_menu_button(obj);
|
||||
{
|
||||
|
|
@ -884,6 +890,7 @@ void create_screen_menu_advanced_screen() {
|
|||
objects.menu_btn_advanced_reset_config = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), 50);
|
||||
lv_obj_add_event_cb(obj, action_switch_to_reset_config, LV_EVENT_PRESSED, (void *)0);
|
||||
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SNAPPABLE);
|
||||
add_style_menu_button(obj);
|
||||
lv_obj_set_style_bg_color(obj, lv_color_hex(0xffdc2626), LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
|
|
@ -1719,6 +1726,403 @@ void create_screen_status_screen() {
|
|||
void tick_screen_status_screen() {
|
||||
}
|
||||
|
||||
void create_screen_reset_config_screen() {
|
||||
lv_obj_t *obj = lv_obj_create(0);
|
||||
objects.reset_config_screen = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, 300, 240);
|
||||
lv_obj_add_event_cb(obj, action_about_screen_gesture, LV_EVENT_GESTURE, (void *)0);
|
||||
add_style_flex_screen_menu(obj);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
lv_obj_t *obj = lv_obj_create(parent_obj);
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_PCT(100));
|
||||
lv_obj_set_style_pad_left(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_top(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_right(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_bottom(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_bg_opa(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLLABLE);
|
||||
add_style_flex_start(obj);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
// ResetConfigHeader
|
||||
lv_obj_t *obj = lv_obj_create(parent_obj);
|
||||
objects.reset_config_header = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_pad_left(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_top(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_bottom(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_bg_opa(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
add_style_flow_row_space_between(obj);
|
||||
lv_obj_set_style_pad_right(obj, 4, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
lv_obj_t *obj = lv_button_create(parent_obj);
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, 32, 32);
|
||||
lv_obj_add_event_cb(obj, action_switch_to_menu, LV_EVENT_CLICKED, (void *)0);
|
||||
add_style_back_button(obj);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
lv_obj_t *obj = lv_image_create(parent_obj);
|
||||
lv_obj_set_pos(obj, -1, 2);
|
||||
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
|
||||
lv_image_set_src(obj, &img_back_caret);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
lv_obj_t *obj = lv_label_create(parent_obj);
|
||||
lv_obj_set_pos(obj, LV_PCT(0), LV_PCT(0));
|
||||
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
|
||||
add_style_header_link(obj);
|
||||
lv_label_set_text(obj, "Reset Config");
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
// ResetConfigContainer
|
||||
lv_obj_t *obj = lv_obj_create(parent_obj);
|
||||
objects.reset_config_container = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_PCT(80));
|
||||
lv_obj_set_style_pad_left(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_top(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_bottom(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_bg_opa(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_scrollbar_mode(obj, LV_SCROLLBAR_MODE_AUTO);
|
||||
lv_obj_set_scroll_dir(obj, LV_DIR_VER);
|
||||
lv_obj_set_scroll_snap_x(obj, LV_SCROLL_SNAP_START);
|
||||
add_style_flex_column_start(obj);
|
||||
lv_obj_set_style_pad_right(obj, 4, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
lv_obj_t *obj = lv_obj_create(parent_obj);
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_pad_left(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_top(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_bottom(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_bg_opa(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLLABLE);
|
||||
add_style_flex_column_start(obj);
|
||||
lv_obj_set_style_pad_right(obj, 10, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
// ResetConfigLabelContainer
|
||||
lv_obj_t *obj = lv_obj_create(parent_obj);
|
||||
objects.reset_config_label_container = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_bg_opa(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLLABLE);
|
||||
add_style_flex_column_start(obj);
|
||||
lv_obj_set_style_pad_right(obj, 10, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_left(obj, 10, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_top(obj, 10, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_bottom(obj, 10, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
// ResetConfigLabel
|
||||
lv_obj_t *obj = lv_label_create(parent_obj);
|
||||
objects.reset_config_label = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
add_style_info_content_label(obj);
|
||||
lv_obj_set_style_text_font(obj, &ui_font_font_book20, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_label_set_text(obj, "Press and hold for\n10 seconds");
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
// ResetConfigSpinner
|
||||
lv_obj_t *obj = lv_obj_create(parent_obj);
|
||||
objects.reset_config_spinner = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_pad_left(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_top(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_right(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_bottom(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_bg_opa(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_add_flag(obj, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICKABLE|LV_OBJ_FLAG_SCROLLABLE);
|
||||
add_style_flex_column_start(obj);
|
||||
lv_obj_set_style_flex_main_place(obj, LV_FLEX_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_flex_cross_place(obj, LV_FLEX_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_flex_track_place(obj, LV_FLEX_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
lv_obj_t *obj = lv_spinner_create(parent_obj);
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, 80, 80);
|
||||
lv_spinner_set_anim_params(obj, 1000, 60);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
// ResetConfigButton
|
||||
lv_obj_t *obj = lv_obj_create(parent_obj);
|
||||
objects.reset_config_button = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_pad_left(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_top(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_right(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_bottom(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_bg_opa(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLLABLE);
|
||||
add_style_flex_column_start(obj);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
lv_obj_t *obj = lv_button_create(parent_obj);
|
||||
objects.obj0 = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), 50);
|
||||
lv_obj_add_event_cb(obj, action_reset_config, LV_EVENT_PRESSED, (void *)0);
|
||||
lv_obj_add_event_cb(obj, action_reset_config, LV_EVENT_PRESSING, (void *)0);
|
||||
lv_obj_add_event_cb(obj, action_reset_config, LV_EVENT_RELEASED, (void *)0);
|
||||
lv_obj_set_style_bg_color(obj, lv_color_hex(0xffdc2626), LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_text_align(obj, LV_TEXT_ALIGN_LEFT, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_right(obj, 13, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
lv_obj_t *obj = lv_label_create(parent_obj);
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_align(obj, LV_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_text_align(obj, LV_TEXT_ALIGN_LEFT, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_label_set_text(obj, "Reset configuration");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tick_screen_reset_config_screen();
|
||||
}
|
||||
|
||||
void tick_screen_reset_config_screen() {
|
||||
}
|
||||
|
||||
void create_screen_reboot_screen() {
|
||||
lv_obj_t *obj = lv_obj_create(0);
|
||||
objects.reboot_screen = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, 300, 240);
|
||||
lv_obj_add_event_cb(obj, action_about_screen_gesture, LV_EVENT_GESTURE, (void *)0);
|
||||
add_style_flex_screen_menu(obj);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
lv_obj_t *obj = lv_obj_create(parent_obj);
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_PCT(100));
|
||||
lv_obj_set_style_pad_left(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_top(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_right(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_bottom(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_bg_opa(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLLABLE);
|
||||
add_style_flex_start(obj);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
// RebootHeader
|
||||
lv_obj_t *obj = lv_obj_create(parent_obj);
|
||||
objects.reboot_header = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_pad_left(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_top(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_bottom(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_bg_opa(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
add_style_flow_row_space_between(obj);
|
||||
lv_obj_set_style_pad_right(obj, 4, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
lv_obj_t *obj = lv_button_create(parent_obj);
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, 32, 32);
|
||||
lv_obj_add_event_cb(obj, action_switch_to_menu, LV_EVENT_CLICKED, (void *)0);
|
||||
add_style_back_button(obj);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
lv_obj_t *obj = lv_image_create(parent_obj);
|
||||
lv_obj_set_pos(obj, -1, 2);
|
||||
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
|
||||
lv_image_set_src(obj, &img_back_caret);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
lv_obj_t *obj = lv_label_create(parent_obj);
|
||||
lv_obj_set_pos(obj, LV_PCT(0), LV_PCT(0));
|
||||
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
|
||||
add_style_header_link(obj);
|
||||
lv_label_set_text(obj, "Reboot Device");
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
// RebootContainer
|
||||
lv_obj_t *obj = lv_obj_create(parent_obj);
|
||||
objects.reboot_container = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_PCT(80));
|
||||
lv_obj_set_style_pad_left(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_top(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_bottom(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_bg_opa(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_scrollbar_mode(obj, LV_SCROLLBAR_MODE_AUTO);
|
||||
lv_obj_set_scroll_dir(obj, LV_DIR_VER);
|
||||
lv_obj_set_scroll_snap_x(obj, LV_SCROLL_SNAP_START);
|
||||
add_style_flex_column_start(obj);
|
||||
lv_obj_set_style_pad_right(obj, 4, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
lv_obj_t *obj = lv_obj_create(parent_obj);
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_pad_left(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_top(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_bottom(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_bg_opa(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLLABLE);
|
||||
add_style_flex_column_start(obj);
|
||||
lv_obj_set_style_pad_right(obj, 10, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
// RebootLabelContainer
|
||||
lv_obj_t *obj = lv_obj_create(parent_obj);
|
||||
objects.reboot_label_container = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_bg_opa(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLLABLE);
|
||||
add_style_flex_column_start(obj);
|
||||
lv_obj_set_style_pad_right(obj, 10, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_left(obj, 10, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_top(obj, 10, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_bottom(obj, 10, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
// RebootLabel
|
||||
lv_obj_t *obj = lv_label_create(parent_obj);
|
||||
objects.reboot_label = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
add_style_info_content_label(obj);
|
||||
lv_obj_set_style_text_font(obj, &ui_font_font_book20, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_label_set_text(obj, "Press and hold for\n5 seconds");
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
// RebootConfigButton
|
||||
lv_obj_t *obj = lv_obj_create(parent_obj);
|
||||
objects.reboot_config_button = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_pad_left(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_top(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_right(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_bottom(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_bg_opa(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLLABLE);
|
||||
add_style_flex_column_start(obj);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
lv_obj_t *obj = lv_button_create(parent_obj);
|
||||
objects.obj1 = obj;
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_PCT(100), 50);
|
||||
lv_obj_add_event_cb(obj, action_reboot, LV_EVENT_PRESSED, (void *)0);
|
||||
lv_obj_add_event_cb(obj, action_reboot, LV_EVENT_PRESSING, (void *)0);
|
||||
lv_obj_add_event_cb(obj, action_reboot, LV_EVENT_RELEASED, (void *)0);
|
||||
lv_obj_set_style_bg_color(obj, lv_color_hex(0xffdc2626), LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_text_align(obj, LV_TEXT_ALIGN_LEFT, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_right(obj, 13, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
{
|
||||
lv_obj_t *parent_obj = obj;
|
||||
{
|
||||
lv_obj_t *obj = lv_label_create(parent_obj);
|
||||
lv_obj_set_pos(obj, 0, 0);
|
||||
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_align(obj, LV_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_text_align(obj, LV_TEXT_ALIGN_LEFT, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_label_set_text(obj, "Hold to reboot");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tick_screen_reboot_screen();
|
||||
}
|
||||
|
||||
void tick_screen_reboot_screen() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
typedef void (*tick_screen_func_t)();
|
||||
|
|
@ -1731,6 +2135,8 @@ tick_screen_func_t tick_screen_funcs[] = {
|
|||
tick_screen_menu_network_screen,
|
||||
tick_screen_about_screen,
|
||||
tick_screen_status_screen,
|
||||
tick_screen_reset_config_screen,
|
||||
tick_screen_reboot_screen,
|
||||
};
|
||||
void tick_screen(int screen_index) {
|
||||
tick_screen_funcs[screen_index]();
|
||||
|
|
@ -1752,4 +2158,6 @@ void create_screens() {
|
|||
create_screen_menu_network_screen();
|
||||
create_screen_about_screen();
|
||||
create_screen_status_screen();
|
||||
create_screen_reset_config_screen();
|
||||
create_screen_reboot_screen();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ typedef struct _objects_t {
|
|||
lv_obj_t *menu_network_screen;
|
||||
lv_obj_t *about_screen;
|
||||
lv_obj_t *status_screen;
|
||||
lv_obj_t *reset_config_screen;
|
||||
lv_obj_t *reboot_screen;
|
||||
lv_obj_t *boot_logo;
|
||||
lv_obj_t *boot_screen_version;
|
||||
lv_obj_t *no_network_header_container;
|
||||
|
|
@ -83,6 +85,19 @@ typedef struct _objects_t {
|
|||
lv_obj_t *app_version_1;
|
||||
lv_obj_t *cloud_domain_container;
|
||||
lv_obj_t *cloud_domain;
|
||||
lv_obj_t *reset_config_header;
|
||||
lv_obj_t *reset_config_container;
|
||||
lv_obj_t *reset_config_label_container;
|
||||
lv_obj_t *reset_config_label;
|
||||
lv_obj_t *reset_config_spinner;
|
||||
lv_obj_t *reset_config_button;
|
||||
lv_obj_t *obj0;
|
||||
lv_obj_t *reboot_header;
|
||||
lv_obj_t *reboot_container;
|
||||
lv_obj_t *reboot_label_container;
|
||||
lv_obj_t *reboot_label;
|
||||
lv_obj_t *reboot_config_button;
|
||||
lv_obj_t *obj1;
|
||||
} objects_t;
|
||||
|
||||
extern objects_t objects;
|
||||
|
|
@ -96,6 +111,8 @@ enum ScreensEnum {
|
|||
SCREEN_ID_MENU_NETWORK_SCREEN = 6,
|
||||
SCREEN_ID_ABOUT_SCREEN = 7,
|
||||
SCREEN_ID_STATUS_SCREEN = 8,
|
||||
SCREEN_ID_RESET_CONFIG_SCREEN = 9,
|
||||
SCREEN_ID_REBOOT_SCREEN = 10,
|
||||
};
|
||||
|
||||
void create_screen_boot_screen();
|
||||
|
|
@ -122,6 +139,12 @@ void tick_screen_about_screen();
|
|||
void create_screen_status_screen();
|
||||
void tick_screen_status_screen();
|
||||
|
||||
void create_screen_reset_config_screen();
|
||||
void tick_screen_reset_config_screen();
|
||||
|
||||
void create_screen_reboot_screen();
|
||||
void tick_screen_reboot_screen();
|
||||
|
||||
void tick_screen_by_id(enum ScreensEnum screenId);
|
||||
void tick_screen(int screen_index);
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,19 @@
|
|||
|
||||
|
||||
|
||||
|
||||
jetkvm_rpc_handler_t *ui_rpc_handler = NULL;
|
||||
|
||||
void ui_set_rpc_handler(jetkvm_rpc_handler_t *handler) {
|
||||
ui_rpc_handler = handler;
|
||||
}
|
||||
|
||||
void ui_call_rpc_handler(const char *method, const char *params) {
|
||||
if (ui_rpc_handler != NULL) {
|
||||
(*ui_rpc_handler)(method, params);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(EEZ_FOR_LVGL)
|
||||
|
||||
void ui_init() {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,13 @@
|
|||
|
||||
#include <lvgl.h>
|
||||
|
||||
typedef void (jetkvm_rpc_handler_t)(const char *method, const char *params);
|
||||
|
||||
void ui_set_rpc_handler(jetkvm_rpc_handler_t *handler);
|
||||
void ui_call_rpc_handler(const char *method, const char *params);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#if defined(EEZ_FOR_LVGL)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
char app_version[100] = { 0 };
|
||||
char system_version[100] = { 0 };
|
||||
char lvgl_version[32] = { 0 };
|
||||
char main_screen[32] = "home_screen";
|
||||
|
||||
const char *get_var_app_version() {
|
||||
return app_version;
|
||||
|
|
@ -37,3 +38,12 @@ void set_var_system_version(const char *value) {
|
|||
}
|
||||
|
||||
void set_var_lvgl_version(const char *value) {}
|
||||
|
||||
void set_var_main_screen(const char *value) {
|
||||
strncpy(main_screen, value, sizeof(main_screen) / sizeof(char));
|
||||
main_screen[sizeof(main_screen) / sizeof(char) - 1] = 0;
|
||||
}
|
||||
|
||||
const char *get_var_main_screen() {
|
||||
return main_screen;
|
||||
}
|
||||
|
|
@ -17,7 +17,8 @@ extern "C" {
|
|||
enum FlowGlobalVariables {
|
||||
FLOW_GLOBAL_VARIABLE_APP_VERSION = 0,
|
||||
FLOW_GLOBAL_VARIABLE_SYSTEM_VERSION = 1,
|
||||
FLOW_GLOBAL_VARIABLE_LVGL_VERSION = 2
|
||||
FLOW_GLOBAL_VARIABLE_LVGL_VERSION = 2,
|
||||
FLOW_GLOBAL_VARIABLE_MAIN_SCREEN = 3
|
||||
};
|
||||
|
||||
// Native global variables
|
||||
|
|
@ -28,6 +29,8 @@ extern const char *get_var_system_version();
|
|||
extern void set_var_system_version(const char *value);
|
||||
extern const char *get_var_lvgl_version();
|
||||
extern void set_var_lvgl_version(const char *value);
|
||||
extern const char *get_var_main_screen();
|
||||
extern void set_var_main_screen(const char *value);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,6 +1,7 @@
|
|||
package native
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
|
|
@ -17,6 +18,9 @@ type Native struct {
|
|||
onVideoStateChange func(state VideoState)
|
||||
onVideoFrameReceived func(frame []byte, duration time.Duration)
|
||||
onIndevEvent func(event string)
|
||||
onRpcEvent func(event string)
|
||||
videoLock sync.Mutex
|
||||
screenLock sync.Mutex
|
||||
}
|
||||
|
||||
type NativeOptions struct {
|
||||
|
|
@ -26,6 +30,7 @@ type NativeOptions struct {
|
|||
OnVideoStateChange func(state VideoState)
|
||||
OnVideoFrameReceived func(frame []byte, duration time.Duration)
|
||||
OnIndevEvent func(event string)
|
||||
OnRpcEvent func(event string)
|
||||
}
|
||||
|
||||
func NewNative(opts NativeOptions) *Native {
|
||||
|
|
@ -50,6 +55,13 @@ func NewNative(opts NativeOptions) *Native {
|
|||
}
|
||||
}
|
||||
|
||||
onRpcEvent := opts.OnRpcEvent
|
||||
if onRpcEvent == nil {
|
||||
onRpcEvent = func(event string) {
|
||||
nativeLogger.Info().Str("event", event).Msg("rpc event")
|
||||
}
|
||||
}
|
||||
|
||||
return &Native{
|
||||
ready: make(chan struct{}),
|
||||
l: nativeLogger,
|
||||
|
|
@ -60,6 +72,9 @@ func NewNative(opts NativeOptions) *Native {
|
|||
onVideoStateChange: opts.OnVideoStateChange,
|
||||
onVideoFrameReceived: opts.OnVideoFrameReceived,
|
||||
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.handleVideoFrameChan()
|
||||
go n.handleIndevEventChan()
|
||||
go n.handleRpcEventChan()
|
||||
|
||||
n.initUI()
|
||||
go n.tickUI()
|
||||
|
|
|
|||
|
|
@ -9,27 +9,45 @@ type VideoState struct {
|
|||
}
|
||||
|
||||
func (n *Native) VideoSetQualityFactor(factor float64) error {
|
||||
n.videoLock.Lock()
|
||||
defer n.videoLock.Unlock()
|
||||
|
||||
return videoSetStreamQualityFactor(factor)
|
||||
}
|
||||
|
||||
func (n *Native) VideoGetQualityFactor() (float64, error) {
|
||||
n.videoLock.Lock()
|
||||
defer n.videoLock.Unlock()
|
||||
|
||||
return videoGetStreamQualityFactor()
|
||||
}
|
||||
|
||||
func (n *Native) VideoSetEDID(edid string) error {
|
||||
n.videoLock.Lock()
|
||||
defer n.videoLock.Unlock()
|
||||
|
||||
return videoSetEDID(edid)
|
||||
}
|
||||
|
||||
func (n *Native) VideoGetEDID() (string, error) {
|
||||
n.videoLock.Lock()
|
||||
defer n.videoLock.Unlock()
|
||||
|
||||
return videoGetEDID()
|
||||
}
|
||||
|
||||
func (n *Native) VideoStop() error {
|
||||
n.videoLock.Lock()
|
||||
defer n.videoLock.Unlock()
|
||||
|
||||
videoStop()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *Native) VideoStart() error {
|
||||
n.videoLock.Lock()
|
||||
defer n.videoLock.Unlock()
|
||||
|
||||
videoStart()
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,46 +0,0 @@
|
|||
package network
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/jetkvm/kvm/internal/lldp"
|
||||
)
|
||||
|
||||
func (s *NetworkInterfaceState) shouldStartLLDP() bool {
|
||||
if s.lldp == nil {
|
||||
s.l.Trace().Msg("LLDP not initialized")
|
||||
return false
|
||||
}
|
||||
|
||||
s.l.Trace().Msgf("LLDP mode: %s", s.config.LLDPMode.String)
|
||||
|
||||
return s.config.LLDPMode.String != "disabled"
|
||||
}
|
||||
|
||||
func (s *NetworkInterfaceState) startLLDP() {
|
||||
if !s.shouldStartLLDP() || s.lldp == nil {
|
||||
return
|
||||
}
|
||||
|
||||
s.l.Trace().Msg("starting LLDP")
|
||||
if err := s.lldp.Start(); err != nil {
|
||||
s.l.Error().Err(err).Msg("unable to start LLDP")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *NetworkInterfaceState) stopLLDP() {
|
||||
if s.lldp == nil {
|
||||
return
|
||||
}
|
||||
s.l.Trace().Msg("stopping LLDP")
|
||||
if err := s.lldp.Stop(); err != nil {
|
||||
s.l.Error().Err(err).Msg("unable to stop LLDP")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *NetworkInterfaceState) GetLLDPNeighbors() ([]lldp.Neighbor, error) {
|
||||
if s.lldp == nil {
|
||||
return nil, errors.New("lldp not initialized")
|
||||
}
|
||||
return s.lldp.GetNeighbors(), nil
|
||||
}
|
||||
|
|
@ -6,7 +6,6 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/jetkvm/kvm/internal/confparser"
|
||||
"github.com/jetkvm/kvm/internal/lldp"
|
||||
"github.com/jetkvm/kvm/internal/logging"
|
||||
"github.com/jetkvm/kvm/internal/udhcpc"
|
||||
"github.com/rs/zerolog"
|
||||
|
|
@ -31,8 +30,6 @@ type NetworkInterfaceState struct {
|
|||
config *NetworkConfig
|
||||
dhcpClient *udhcpc.DHCPClient
|
||||
|
||||
lldp *lldp.LLDP
|
||||
|
||||
defaultHostname string
|
||||
currentHostname string
|
||||
currentFqdn string
|
||||
|
|
@ -101,24 +98,7 @@ func NewNetworkInterfaceState(opts *NetworkInterfaceOptions) (*NetworkInterfaceS
|
|||
},
|
||||
})
|
||||
|
||||
// create the lldp service
|
||||
lldpClient := lldp.NewLLDP(&lldp.LLDPOptions{
|
||||
InterfaceName: opts.InterfaceName,
|
||||
EnableRx: true,
|
||||
EnableTx: true,
|
||||
Logger: l,
|
||||
})
|
||||
|
||||
// create the lldp service
|
||||
lldpClient = lldp.NewLLDP(&lldp.LLDPOptions{
|
||||
InterfaceName: opts.InterfaceName,
|
||||
EnableRx: true,
|
||||
EnableTx: true,
|
||||
Logger: l,
|
||||
})
|
||||
|
||||
s.dhcpClient = dhcpClient
|
||||
s.lldp = lldpClient
|
||||
return s, nil
|
||||
}
|
||||
|
||||
|
|
@ -387,16 +367,13 @@ func (s *NetworkInterfaceState) updateNtpServersFromLease(lease *udhcpc.Lease) e
|
|||
|
||||
func (s *NetworkInterfaceState) handleInitialCheck() {
|
||||
if s.IsUp() {
|
||||
s.startLLDP()
|
||||
}
|
||||
s.onInitialCheck(s)
|
||||
}
|
||||
|
||||
func (s *NetworkInterfaceState) handleStateChange() {
|
||||
if s.IsUp() {
|
||||
s.startLLDP()
|
||||
} else {
|
||||
s.stopLLDP()
|
||||
}
|
||||
s.onStateChange(s)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1259,5 +1259,4 @@ var rpcHandlers = map[string]RPCHandler{
|
|||
"setKeyboardMacros": {Func: setKeyboardMacros, Params: []string{"params"}},
|
||||
"getLocalLoopbackOnly": {Func: rpcGetLocalLoopbackOnly},
|
||||
"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")
|
||||
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) {
|
||||
if currentSession != nil {
|
||||
err := currentSession.VideoTrack.WriteSample(media.Sample{Data: frame, Duration: duration})
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package kvm
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jetkvm/kvm/internal/lldp"
|
||||
"github.com/jetkvm/kvm/internal/network"
|
||||
"github.com/jetkvm/kvm/internal/udhcpc"
|
||||
)
|
||||
|
|
@ -124,7 +123,3 @@ func rpcSetNetworkSettings(settings network.RpcNetworkSettings) (*network.RpcNet
|
|||
func rpcRenewDHCPLease() error {
|
||||
return networkState.RpcRenewDHCPLease()
|
||||
}
|
||||
|
||||
func rpcGetLLDPNeighbors() ([]lldp.Neighbor, error) {
|
||||
return networkState.GetLLDPNeighbors()
|
||||
}
|
||||
|
|
|
|||
25
video.go
25
video.go
|
|
@ -1,13 +1,8 @@
|
|||
package kvm
|
||||
|
||||
import "github.com/jetkvm/kvm/internal/native"
|
||||
|
||||
// max frame size for 1080p video, specified in mpp venc setting
|
||||
const maxFrameSize = 1920 * 1080 / 2
|
||||
|
||||
func writeCtrlAction(action string) error {
|
||||
return nil
|
||||
}
|
||||
import (
|
||||
"github.com/jetkvm/kvm/internal/native"
|
||||
)
|
||||
|
||||
var lastVideoState native.VideoState
|
||||
|
||||
|
|
@ -15,19 +10,9 @@ func triggerVideoStateUpdate() {
|
|||
go func() {
|
||||
writeJSONRPCEvent("videoInputState", lastVideoState, currentSession)
|
||||
}()
|
||||
}
|
||||
|
||||
// func HandleVideoStateMessage(event CtrlResponse) {
|
||||
// videoState := VideoInputState{}
|
||||
// err := json.Unmarshal(event.Data, &videoState)
|
||||
// if err != nil {
|
||||
// logger.Warn().Err(err).Msg("Error parsing video state json")
|
||||
// return
|
||||
// }
|
||||
// lastVideoState = videoState
|
||||
// triggerVideoStateUpdate()
|
||||
// requestDisplayUpdate(true)
|
||||
// }
|
||||
nativeLogger.Info().Interface("state", lastVideoState).Msg("video state updated")
|
||||
}
|
||||
|
||||
func rpcGetVideoState() (native.VideoState, error) {
|
||||
return lastVideoState, nil
|
||||
|
|
|
|||
Loading…
Reference in New Issue