mirror of
https://github.com/apache/nuttx-apps.git
synced 2026-08-01 20:29:00 +00:00
examples/vncviewer: add VNC viewer for LCD display
Add a minimal VNC viewer application that connects to a VNC server and renders the remote desktop on a local LCD. Features: - RFB 3.8 protocol with VNC Authentication (DES, pure software) - Raw encoding with pixel format auto-detected from LCD driver - Row-by-row rendering via LCDDEVIO_PUTAREA (minimal RAM usage) - LCD resolution and format queried at runtime via LCDDEVIO_GETVIDEOINFO - Auto-reconnect on connection loss with 2-second retry Usage: vncviewer <host> [port] vncviewer -p <password> <host> [port] vncviewer -p <password> -d <lcd_devno> <host> [port] Assisted-by: GitHubCopilot:claude-4.6-opus Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
This commit is contained in:
parent
6379e531de
commit
62f3d37041
9 changed files with 1989 additions and 0 deletions
35
system/vncviewer/CMakeLists.txt
Normal file
35
system/vncviewer/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# ##############################################################################
|
||||
# apps/system/vncviewer/CMakeLists.txt
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more contributor
|
||||
# license agreements. See the NOTICE file distributed with this work for
|
||||
# additional information regarding copyright ownership. The ASF licenses this
|
||||
# file to you under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy of
|
||||
# the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations under
|
||||
# the License.
|
||||
#
|
||||
# ##############################################################################
|
||||
|
||||
if(CONFIG_SYSTEM_VNCVIEWER)
|
||||
nuttx_add_application(
|
||||
NAME
|
||||
${CONFIG_SYSTEM_VNCVIEWER_PROGNAME}
|
||||
SRCS
|
||||
vncviewer_main.c
|
||||
rfb_protocol.c
|
||||
lcd_render.c
|
||||
STACKSIZE
|
||||
${CONFIG_SYSTEM_VNCVIEWER_STACKSIZE}
|
||||
PRIORITY
|
||||
${CONFIG_SYSTEM_VNCVIEWER_PRIORITY})
|
||||
endif()
|
||||
32
system/vncviewer/Kconfig
Normal file
32
system/vncviewer/Kconfig
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#
|
||||
# For a description of the syntax of this configuration file,
|
||||
# see the file kconfig-language.txt in the NuttX tools repository.
|
||||
#
|
||||
|
||||
config SYSTEM_VNCVIEWER
|
||||
tristate "VNC Viewer"
|
||||
default n
|
||||
depends on NET_TCP && LCD
|
||||
---help---
|
||||
Enable the VNC Viewer example application.
|
||||
Connects to a VNC server and displays the remote
|
||||
framebuffer on a local LCD.
|
||||
|
||||
if SYSTEM_VNCVIEWER
|
||||
|
||||
config SYSTEM_VNCVIEWER_PROGNAME
|
||||
string "Program name"
|
||||
default "vncviewer"
|
||||
---help---
|
||||
This is the name of the program that will be used when the
|
||||
NSH ELF program is installed.
|
||||
|
||||
config SYSTEM_VNCVIEWER_PRIORITY
|
||||
int "VNC Viewer task priority"
|
||||
default 100
|
||||
|
||||
config SYSTEM_VNCVIEWER_STACKSIZE
|
||||
int "VNC Viewer stack size"
|
||||
default 4096
|
||||
|
||||
endif
|
||||
25
system/vncviewer/Make.defs
Normal file
25
system/vncviewer/Make.defs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
############################################################################
|
||||
# apps/system/vncviewer/Make.defs
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership. The
|
||||
# ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance with the
|
||||
# License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
ifneq ($(CONFIG_SYSTEM_VNCVIEWER),)
|
||||
CONFIGURED_APPS += $(APPDIR)/system/vncviewer
|
||||
endif
|
||||
37
system/vncviewer/Makefile
Normal file
37
system/vncviewer/Makefile
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
############################################################################
|
||||
# apps/system/vncviewer/Makefile
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership. The
|
||||
# ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance with the
|
||||
# License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
include $(APPDIR)/Make.defs
|
||||
|
||||
# VNC Viewer built-in application info
|
||||
|
||||
PROGNAME = $(CONFIG_SYSTEM_VNCVIEWER_PROGNAME)
|
||||
PRIORITY = $(CONFIG_SYSTEM_VNCVIEWER_PRIORITY)
|
||||
STACKSIZE = $(CONFIG_SYSTEM_VNCVIEWER_STACKSIZE)
|
||||
MODULE = $(CONFIG_SYSTEM_VNCVIEWER)
|
||||
|
||||
# VNC Viewer sources
|
||||
|
||||
MAINSRC = vncviewer_main.c
|
||||
CSRCS = rfb_protocol.c lcd_render.c
|
||||
|
||||
include $(APPDIR)/Application.mk
|
||||
177
system/vncviewer/lcd_render.c
Normal file
177
system/vncviewer/lcd_render.c
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
/****************************************************************************
|
||||
* apps/system/vncviewer/lcd_render.c
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <nuttx/video/fb.h>
|
||||
#include <nuttx/lcd/lcd_dev.h>
|
||||
|
||||
#include "lcd_render.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lcd_init
|
||||
****************************************************************************/
|
||||
|
||||
int lcd_init(struct lcd_ctx_s *ctx, int devno)
|
||||
{
|
||||
char devpath[16];
|
||||
int ret;
|
||||
|
||||
snprintf(devpath, sizeof(devpath), "/dev/lcd%d", devno);
|
||||
|
||||
ctx->fd = open(devpath, O_RDWR);
|
||||
if (ctx->fd < 0)
|
||||
{
|
||||
printf("vncviewer: failed to open %s: %d\n", devpath, errno);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* Query LCD resolution */
|
||||
|
||||
struct fb_videoinfo_s vinfo;
|
||||
ret = ioctl(ctx->fd, LCDDEVIO_GETVIDEOINFO,
|
||||
(unsigned long)(uintptr_t)&vinfo);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("vncviewer: GETVIDEOINFO failed: %d\n", errno);
|
||||
close(ctx->fd);
|
||||
ctx->fd = -1;
|
||||
return -errno;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->xres = vinfo.xres;
|
||||
ctx->yres = vinfo.yres;
|
||||
ctx->fmt = vinfo.fmt;
|
||||
}
|
||||
|
||||
printf("vncviewer: LCD %s opened (%ux%u)\n",
|
||||
devpath, ctx->xres, ctx->yres);
|
||||
|
||||
/* Set power on */
|
||||
|
||||
ret = ioctl(ctx->fd, LCDDEVIO_SETPOWER, 1);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("vncviewer: WARNING: SETPOWER failed: %d\n", errno);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lcd_put_row
|
||||
****************************************************************************/
|
||||
|
||||
int lcd_put_row(struct lcd_ctx_s *ctx, uint16_t x, uint16_t y,
|
||||
uint16_t w, const uint16_t *pixels)
|
||||
{
|
||||
struct lcddev_area_s area;
|
||||
int ret;
|
||||
|
||||
/* Clip to LCD bounds */
|
||||
|
||||
if (x >= ctx->xres || y >= ctx->yres)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
|
||||
if (x + w > ctx->xres)
|
||||
{
|
||||
w = ctx->xres - x;
|
||||
}
|
||||
|
||||
area.row_start = y;
|
||||
area.row_end = y;
|
||||
area.col_start = x;
|
||||
area.col_end = x + w - 1;
|
||||
area.data = (uint8_t *)pixels;
|
||||
|
||||
ret = ioctl(ctx->fd, LCDDEVIO_PUTAREA, (unsigned long)(uintptr_t)&area);
|
||||
if (ret < 0)
|
||||
{
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lcd_fill
|
||||
****************************************************************************/
|
||||
|
||||
int lcd_fill(struct lcd_ctx_s *ctx, uint16_t color)
|
||||
{
|
||||
uint16_t y;
|
||||
uint16_t i;
|
||||
uint16_t w = ctx->xres;
|
||||
FAR uint16_t *rowbuf;
|
||||
|
||||
rowbuf = (FAR uint16_t *)malloc(w * sizeof(uint16_t));
|
||||
if (rowbuf == NULL)
|
||||
{
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (i = 0; i < w; i++)
|
||||
{
|
||||
rowbuf[i] = color;
|
||||
}
|
||||
|
||||
for (y = 0; y < ctx->yres; y++)
|
||||
{
|
||||
lcd_put_row(ctx, 0, y, w, rowbuf);
|
||||
}
|
||||
|
||||
free(rowbuf);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lcd_uninit
|
||||
****************************************************************************/
|
||||
|
||||
void lcd_uninit(struct lcd_ctx_s *ctx)
|
||||
{
|
||||
if (ctx->fd >= 0)
|
||||
{
|
||||
close(ctx->fd);
|
||||
ctx->fd = -1;
|
||||
}
|
||||
}
|
||||
106
system/vncviewer/lcd_render.h
Normal file
106
system/vncviewer/lcd_render.h
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/****************************************************************************
|
||||
* apps/system/vncviewer/lcd_render.h
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __APPS_SYSTEM_VNCVIEWER_LCD_RENDER_H
|
||||
#define __APPS_SYSTEM_VNCVIEWER_LCD_RENDER_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
struct lcd_ctx_s
|
||||
{
|
||||
int fd; /* File descriptor for /dev/lcdN */
|
||||
uint16_t xres; /* LCD horizontal resolution */
|
||||
uint16_t yres; /* LCD vertical resolution */
|
||||
uint8_t fmt; /* Pixel format (FB_FMT_*) */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lcd_init
|
||||
*
|
||||
* Description:
|
||||
* Open and initialize the LCD device.
|
||||
*
|
||||
* Input Parameters:
|
||||
* ctx - LCD context to initialize
|
||||
* devno - LCD device number (0 for /dev/lcd0)
|
||||
*
|
||||
* Returned Value:
|
||||
* OK on success, negative errno on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int lcd_init(struct lcd_ctx_s *ctx, int devno);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lcd_put_row
|
||||
*
|
||||
* Description:
|
||||
* Write a single row of pixels to the LCD.
|
||||
*
|
||||
* Input Parameters:
|
||||
* ctx - LCD context
|
||||
* x - Starting X coordinate
|
||||
* y - Y coordinate (row)
|
||||
* w - Width in pixels
|
||||
* pixels - Pixel data matching LCD native format
|
||||
*
|
||||
* Returned Value:
|
||||
* OK on success, negative errno on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int lcd_put_row(struct lcd_ctx_s *ctx, uint16_t x, uint16_t y,
|
||||
uint16_t w, const uint16_t *pixels);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lcd_fill
|
||||
*
|
||||
* Description:
|
||||
* Fill the entire LCD with a solid color.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int lcd_fill(struct lcd_ctx_s *ctx, uint16_t color);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lcd_uninit
|
||||
*
|
||||
* Description:
|
||||
* Close the LCD device.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void lcd_uninit(struct lcd_ctx_s *ctx);
|
||||
|
||||
#endif /* __APPS_SYSTEM_VNCVIEWER_LCD_RENDER_H */
|
||||
1051
system/vncviewer/rfb_protocol.c
Normal file
1051
system/vncviewer/rfb_protocol.c
Normal file
File diff suppressed because it is too large
Load diff
220
system/vncviewer/rfb_protocol.h
Normal file
220
system/vncviewer/rfb_protocol.h
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
/****************************************************************************
|
||||
* apps/system/vncviewer/rfb_protocol.h
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __APPS_SYSTEM_VNCVIEWER_RFB_PROTOCOL_H
|
||||
#define __APPS_SYSTEM_VNCVIEWER_RFB_PROTOCOL_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* RFB Protocol Version */
|
||||
|
||||
#define RFB_VERSION_STRING "RFB 003.008\n"
|
||||
#define RFB_VERSION_LEN 12
|
||||
|
||||
/* Security Types */
|
||||
|
||||
#define RFB_SEC_INVALID 0
|
||||
#define RFB_SEC_NONE 1
|
||||
#define RFB_SEC_VNC_AUTH 2
|
||||
|
||||
/* Client-to-Server Message Types */
|
||||
|
||||
#define RFB_SET_PIXEL_FORMAT 0
|
||||
#define RFB_SET_ENCODINGS 2
|
||||
#define RFB_FB_UPDATE_REQUEST 3
|
||||
#define RFB_KEY_EVENT 4
|
||||
#define RFB_POINTER_EVENT 5
|
||||
#define RFB_CLIENT_CUT_TEXT 6
|
||||
|
||||
/* Server-to-Client Message Types */
|
||||
|
||||
#define RFB_FB_UPDATE 0
|
||||
#define RFB_SET_COLORMAP 1
|
||||
#define RFB_BELL 2
|
||||
#define RFB_SERVER_CUT_TEXT 3
|
||||
|
||||
/* Encoding Types */
|
||||
|
||||
#define RFB_ENCODING_RAW 0
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
/* Pixel format (negotiated with server based on LCD) */
|
||||
|
||||
struct rfb_pixel_format_s
|
||||
{
|
||||
uint8_t bits_per_pixel; /* 16 */
|
||||
uint8_t depth; /* 16 */
|
||||
uint8_t big_endian; /* 0 = little-endian */
|
||||
uint8_t true_color; /* 1 */
|
||||
uint16_t red_max; /* 31 (5 bits) */
|
||||
uint16_t green_max; /* 63 (6 bits) */
|
||||
uint16_t blue_max; /* 31 (5 bits) */
|
||||
uint8_t red_shift; /* 11 */
|
||||
uint8_t green_shift; /* 5 */
|
||||
uint8_t blue_shift; /* 0 */
|
||||
uint8_t padding[3];
|
||||
};
|
||||
|
||||
/* Server init message (parsed) */
|
||||
|
||||
struct rfb_server_init_s
|
||||
{
|
||||
uint16_t fb_width;
|
||||
uint16_t fb_height;
|
||||
struct rfb_pixel_format_s pixel_format;
|
||||
char name[256];
|
||||
};
|
||||
|
||||
/* Framebuffer update rectangle header */
|
||||
|
||||
struct rfb_rect_hdr_s
|
||||
{
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
uint16_t w;
|
||||
uint16_t h;
|
||||
int32_t encoding;
|
||||
};
|
||||
|
||||
/* RFB connection context */
|
||||
|
||||
struct rfb_conn_s
|
||||
{
|
||||
int sockfd;
|
||||
uint16_t fb_width;
|
||||
uint16_t fb_height;
|
||||
uint16_t view_width;
|
||||
uint16_t view_height;
|
||||
uint8_t bpp; /* Bytes per pixel */
|
||||
char name[256];
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rfb_connect
|
||||
*
|
||||
* Description:
|
||||
* Establish TCP connection to VNC server.
|
||||
*
|
||||
* Input Parameters:
|
||||
* host - Server IP address string
|
||||
* port - Server port number
|
||||
*
|
||||
* Returned Value:
|
||||
* Socket fd on success, negative errno on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int rfb_connect(const char *host, uint16_t port);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rfb_handshake
|
||||
*
|
||||
* Description:
|
||||
* Perform RFB protocol handshake: version, security, init.
|
||||
*
|
||||
* Input Parameters:
|
||||
* conn - RFB connection context (sockfd must be set)
|
||||
* password - VNC password (NULL or empty for no auth)
|
||||
*
|
||||
* Returned Value:
|
||||
* OK on success, negative errno on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int rfb_handshake(struct rfb_conn_s *conn, const char *password);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rfb_set_pixel_format
|
||||
*
|
||||
* Description:
|
||||
* Send SetPixelFormat message based on LCD pixel format.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int rfb_set_pixel_format(struct rfb_conn_s *conn, uint8_t fmt);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rfb_set_encodings
|
||||
*
|
||||
* Description:
|
||||
* Send SetEncodings message (Raw only).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int rfb_set_encodings(struct rfb_conn_s *conn);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rfb_request_update
|
||||
*
|
||||
* Description:
|
||||
* Send FramebufferUpdateRequest.
|
||||
*
|
||||
* Input Parameters:
|
||||
* conn - RFB connection
|
||||
* incremental - true for incremental update
|
||||
* x, y, w, h - Region to request
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int rfb_request_update(struct rfb_conn_s *conn, bool incremental,
|
||||
uint16_t x, uint16_t y, uint16_t w, uint16_t h);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rfb_recv_update
|
||||
*
|
||||
* Description:
|
||||
* Receive and process one server message. For FramebufferUpdate,
|
||||
* calls the provided callback for each rectangle.
|
||||
*
|
||||
* Input Parameters:
|
||||
* conn - RFB connection
|
||||
* rect_cb - Callback for each received rectangle
|
||||
* arg - User argument passed to callback
|
||||
*
|
||||
* Returned Value:
|
||||
* OK on success, negative errno on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
typedef void (*rfb_rect_cb_t)(const struct rfb_rect_hdr_s *rect,
|
||||
const uint8_t *pixels, void *arg);
|
||||
|
||||
int rfb_recv_update(struct rfb_conn_s *conn, rfb_rect_cb_t rect_cb,
|
||||
void *arg);
|
||||
|
||||
#endif /* __APPS_SYSTEM_VNCVIEWER_RFB_PROTOCOL_H */
|
||||
306
system/vncviewer/vncviewer_main.c
Normal file
306
system/vncviewer/vncviewer_main.c
Normal file
|
|
@ -0,0 +1,306 @@
|
|||
/****************************************************************************
|
||||
* apps/system/vncviewer/vncviewer_main.c
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <nuttx/video/fb.h>
|
||||
|
||||
#include "rfb_protocol.h"
|
||||
#include "lcd_render.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define VNCVIEWER_DEFAULT_PORT 5900
|
||||
#define VNCVIEWER_DEFAULT_LCD 0
|
||||
|
||||
#define COLOR_BLACK 0x0000
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static struct lcd_ctx_s g_lcd;
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rect_callback
|
||||
*
|
||||
* Description:
|
||||
* Called for each row of pixel data received from VNC server.
|
||||
* Writes directly to LCD, clipping to screen bounds.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void rect_callback(const struct rfb_rect_hdr_s *rect,
|
||||
const uint8_t *pixels, void *arg)
|
||||
{
|
||||
/* rect->h is always 1 (row-by-row from rfb_recv_update) */
|
||||
|
||||
if (rect->y < g_lcd.yres && rect->x < g_lcd.xres)
|
||||
{
|
||||
uint16_t w = rect->w;
|
||||
|
||||
if (rect->x + w > g_lcd.xres)
|
||||
{
|
||||
w = g_lcd.xres - rect->x;
|
||||
}
|
||||
|
||||
lcd_put_row(&g_lcd, rect->x, rect->y, w, (const uint16_t *)pixels);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: show_usage
|
||||
****************************************************************************/
|
||||
|
||||
static void show_usage(const char *progname)
|
||||
{
|
||||
printf("Usage: %s [options] <host> [port]\n", progname);
|
||||
printf("Options:\n");
|
||||
printf(" -p <password> VNC password\n");
|
||||
printf(" -d <devno> LCD device number (default: %d)\n",
|
||||
VNCVIEWER_DEFAULT_LCD);
|
||||
printf(" -h Show this help\n");
|
||||
printf("Default port: %d\n", VNCVIEWER_DEFAULT_PORT);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vncviewer_main
|
||||
*
|
||||
* Description:
|
||||
* VNC Viewer entry point. Connects to a VNC server and displays
|
||||
* the remote framebuffer on the local LCD.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const char *host = NULL;
|
||||
const char *password = "";
|
||||
uint16_t port = VNCVIEWER_DEFAULT_PORT;
|
||||
int lcd_devno = VNCVIEWER_DEFAULT_LCD;
|
||||
struct rfb_conn_s conn;
|
||||
int opt;
|
||||
int ret;
|
||||
|
||||
/* Parse command line arguments */
|
||||
|
||||
while ((opt = getopt(argc, argv, "p:d:h")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'p':
|
||||
password = optarg;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
lcd_devno = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
show_usage(argv[0]);
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
default:
|
||||
show_usage(argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc)
|
||||
{
|
||||
host = argv[optind++];
|
||||
}
|
||||
|
||||
if (optind < argc)
|
||||
{
|
||||
port = atoi(argv[optind]);
|
||||
}
|
||||
|
||||
if (host == NULL)
|
||||
{
|
||||
printf("vncviewer: host is required\n");
|
||||
show_usage(argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* Initialize LCD */
|
||||
|
||||
printf("vncviewer: initializing LCD...\n");
|
||||
|
||||
ret = lcd_init(&g_lcd, lcd_devno);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("vncviewer: LCD init failed: %d\n", ret);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* Fill screen black */
|
||||
|
||||
lcd_fill(&g_lcd, COLOR_BLACK);
|
||||
|
||||
/* Connect to VNC server */
|
||||
|
||||
memset(&conn, 0, sizeof(conn));
|
||||
|
||||
/* Connection loop with retry */
|
||||
|
||||
for (; ; )
|
||||
{
|
||||
int rcvbuf;
|
||||
|
||||
conn.sockfd = rfb_connect(host, port);
|
||||
if (conn.sockfd < 0)
|
||||
{
|
||||
printf("vncviewer: connection failed: %d, retrying...\n",
|
||||
conn.sockfd);
|
||||
sleep(2);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Increase TCP receive buffer to handle bursts */
|
||||
|
||||
rcvbuf = 32768;
|
||||
setsockopt(conn.sockfd, SOL_SOCKET, SO_RCVBUF,
|
||||
&rcvbuf, sizeof(rcvbuf));
|
||||
|
||||
/* RFB handshake */
|
||||
|
||||
ret = rfb_handshake(&conn, password);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("vncviewer: handshake failed: %d, retrying...\n", ret);
|
||||
close(conn.sockfd);
|
||||
sleep(2);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Configure pixel format based on LCD */
|
||||
|
||||
ret = rfb_set_pixel_format(&conn, g_lcd.fmt);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("vncviewer: set pixel format failed: %d, retrying...\n",
|
||||
ret);
|
||||
close(conn.sockfd);
|
||||
sleep(2);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Set encodings: Raw only */
|
||||
|
||||
ret = rfb_set_encodings(&conn);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("vncviewer: set encodings failed: %d, retrying...\n", ret);
|
||||
close(conn.sockfd);
|
||||
sleep(2);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Determine view size: min of server desktop and LCD */
|
||||
|
||||
conn.view_width = conn.fb_width < g_lcd.xres
|
||||
? conn.fb_width : g_lcd.xres;
|
||||
conn.view_height = conn.fb_height < g_lcd.yres
|
||||
? conn.fb_height : g_lcd.yres;
|
||||
|
||||
printf("vncviewer: view area: %ux%u (server: %ux%u, lcd: %ux%u)\n",
|
||||
conn.view_width, conn.view_height,
|
||||
conn.fb_width, conn.fb_height,
|
||||
g_lcd.xres, g_lcd.yres);
|
||||
|
||||
/* Request initial full framebuffer update */
|
||||
|
||||
ret = rfb_request_update(&conn, false,
|
||||
0, 0, conn.view_width, conn.view_height);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("vncviewer: initial update request failed: %d, "
|
||||
"retrying...\n", ret);
|
||||
close(conn.sockfd);
|
||||
sleep(2);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Main loop: receive updates and render to LCD */
|
||||
|
||||
printf("vncviewer: entering main loop\n");
|
||||
|
||||
while (true)
|
||||
{
|
||||
/* Receive and process server message */
|
||||
|
||||
ret = rfb_recv_update(&conn, rect_callback, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("vncviewer: recv error: %d\n", ret);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Request next incremental update */
|
||||
|
||||
ret = rfb_request_update(&conn, true,
|
||||
0, 0,
|
||||
conn.view_width, conn.view_height);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("vncviewer: update request failed: %d\n", ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Connection lost - retry */
|
||||
|
||||
printf("vncviewer: reconnecting in 2 seconds...\n");
|
||||
close(conn.sockfd);
|
||||
sleep(2);
|
||||
}
|
||||
|
||||
/* Cleanup */
|
||||
|
||||
printf("vncviewer: disconnecting\n");
|
||||
close(conn.sockfd);
|
||||
lcd_uninit(&g_lcd);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue