mirror of
https://github.com/apache/nuttx-apps.git
synced 2026-08-01 20:29:00 +00:00
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>
177 lines
4.4 KiB
C
177 lines
4.4 KiB
C
/****************************************************************************
|
|
* 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;
|
|
}
|
|
}
|