mirror of
https://github.com/apache/nuttx.git
synced 2025-12-10 20:24:51 +08:00
grahpics: Move VNC server to drivers/video
and remove the empty VNC client Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
This commit is contained in:
@@ -523,6 +523,5 @@ config NXSTART_DEVNO
|
||||
---help---
|
||||
LCD device number (in case there are more than one LCDs connected).
|
||||
Default: 0
|
||||
source "graphics/vnc/Kconfig"
|
||||
|
||||
endif # NX
|
||||
|
||||
@@ -24,7 +24,6 @@ include nxglib/Make.defs
|
||||
include nxbe/Make.defs
|
||||
include nxmu/Make.defs
|
||||
include nxterm/Make.defs
|
||||
include vnc/Make.defs
|
||||
|
||||
CFLAGS += ${shell $(INCDIR) "$(CC)" $(TOPDIR)$(DELIM)graphics}
|
||||
|
||||
|
||||
@@ -98,10 +98,6 @@ apps/grahpics/nxwidgets
|
||||
The NxWidgets code is provided as a separate package located outside of the
|
||||
NuttX source tree (probably at this location).
|
||||
|
||||
graphics/vnc
|
||||
The future home of the VNC Remote Frame Buffer (RFB) server and client
|
||||
implementations.
|
||||
|
||||
Installing New Fonts
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#
|
||||
# For a description of the syntax of this configuration file,
|
||||
# see the file kconfig-language.txt in the NuttX tools repository.
|
||||
#
|
||||
|
||||
source "graphics/vnc/server/Kconfig"
|
||||
source "graphics/vnc/client/Kconfig"
|
||||
@@ -1,22 +0,0 @@
|
||||
############################################################################
|
||||
# graphics/vnc/Make.defs
|
||||
#
|
||||
# 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 vnc/server/Make.defs
|
||||
include vnc/client/Make.defs
|
||||
@@ -1,15 +0,0 @@
|
||||
#
|
||||
# For a description of the syntax of this configuration file,
|
||||
# see the file kconfig-language.txt in the NuttX tools repository.
|
||||
#
|
||||
|
||||
menuconfig VNCCLIENT
|
||||
bool "VNC client"
|
||||
default n
|
||||
depends on NET_TCP && !VNC_SERVER && EXPERIMENTAL
|
||||
---help---
|
||||
Enable support for a VNC Remote Frame Buffer (RFB) client
|
||||
|
||||
if VNCCLIENT
|
||||
|
||||
endif # VNCCLIENT
|
||||
@@ -1,27 +0,0 @@
|
||||
############################################################################
|
||||
# graphics/vnc/client/Make.defs
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
ifeq ($(CONFIG_VNCCLIENT),y)
|
||||
|
||||
DEPPATH += --dep-path vnc/client
|
||||
CFLAGS += ${shell $(INCDIR) "$(CC)" $(TOPDIR)/graphics/vnc/client}
|
||||
VPATH += :vnc/client
|
||||
|
||||
endif
|
||||
@@ -1,162 +0,0 @@
|
||||
#
|
||||
# For a description of the syntax of this configuration file,
|
||||
# see the file kconfig-language.txt in the NuttX tools repository.
|
||||
#
|
||||
|
||||
menuconfig VNCSERVER
|
||||
bool "VNC server"
|
||||
default n
|
||||
depends on NET_TCP
|
||||
select FB_UPDATE
|
||||
---help---
|
||||
Enable support for a VNC Remote Frame Buffer (RFB) server.
|
||||
|
||||
if VNCSERVER
|
||||
|
||||
choice
|
||||
prompt "VNC server protocol"
|
||||
default VNCSERVER_PROTO3p8
|
||||
|
||||
config VNCSERVER_PROTO3p3
|
||||
bool "Version 3.3"
|
||||
depends on EXPERIMENTAL
|
||||
|
||||
config VNCSERVER_PROTO3p8
|
||||
bool "Version 3.8"
|
||||
|
||||
endchoice # VNC server protocol
|
||||
|
||||
config VNCSERVER_NDISPLAYS
|
||||
int "Number of displays"
|
||||
default 1
|
||||
range 1 99
|
||||
---help---
|
||||
Specifies the number of RFB displays supported by the server.
|
||||
Normally this should be one.
|
||||
|
||||
config VNCSERVER_NAME
|
||||
string "VNC display name"
|
||||
default "NuttX"
|
||||
|
||||
config VNCSERVER_PRIO
|
||||
int "VNC server task priority"
|
||||
default 100
|
||||
|
||||
config VNCSERVER_STACKSIZE
|
||||
int "VNC server stack size"
|
||||
default DEFAULT_TASK_STACKSIZE
|
||||
|
||||
config VNCSERVER_UPDATER_PRIO
|
||||
int "VNC updater thread priority"
|
||||
default 100
|
||||
|
||||
config VNCSERVER_UPDATER_STACKSIZE
|
||||
int "VNC updater thread stack size"
|
||||
default DEFAULT_TASK_STACKSIZE
|
||||
|
||||
choice
|
||||
prompt "VNC color format"
|
||||
default VNCSERVER_COLORFMT_RGB16
|
||||
|
||||
config VNCSERVER_COLORFMT_RGB8
|
||||
bool "RGB8 3:3:2"
|
||||
|
||||
config VNCSERVER_COLORFMT_RGB16
|
||||
bool "RGB16 5:6:5"
|
||||
|
||||
config VNCSERVER_COLORFMT_RGB32
|
||||
bool "RGB32 8:8:8"
|
||||
|
||||
endchoice # VNC color format
|
||||
|
||||
config VNCSERVER_SCREENWIDTH
|
||||
int "Framebuffer width (pixels)"
|
||||
default 320
|
||||
---help---
|
||||
This setting defines the width in pixels of the local framebuffer.
|
||||
|
||||
Memory usage: PixelWidth * ScreenWidth * ScreenHeight
|
||||
|
||||
So, for example, a 320x240 screen with RGB16 pixels would require
|
||||
2x320x240 = 150 KB of RAM.
|
||||
|
||||
config VNCSERVER_SCREENHEIGHT
|
||||
int "Framebuffer height (rows)"
|
||||
default 240
|
||||
---help---
|
||||
This setting defines the height in rows of the local framebuffer.
|
||||
|
||||
Memory usage: PixelWidth * ScreenWidth * ScreenHeight
|
||||
|
||||
So, for example, a 320x240 screen with RGB16 pixels would require
|
||||
2x320x240 = 150 KB of RAM.
|
||||
|
||||
config VNCSERVER_NUPDATES
|
||||
int "Number of pre-allocate update structures"
|
||||
default 48
|
||||
---help---
|
||||
This setting provides the number of pre-allocated update structures
|
||||
that will be used. Dynamic memory allocations are never made. In
|
||||
the likely event that we run out of update structures, the graphics
|
||||
subsystem will pause and wait for the next structures to be released.
|
||||
|
||||
Overhead is 12-bytes per update structure.
|
||||
|
||||
config VNCSERVER_UPDATE_BUFSIZE
|
||||
int "Max update buffer size (bytes)"
|
||||
default 1024
|
||||
---help---
|
||||
A single buffer is pre-allocated for rendering updates. This
|
||||
setting specifies the maximum in bytes of that update buffer. For
|
||||
example, an update buffers of 32 pixels at 8-bits per pixel and
|
||||
32-rows would yield a buffer size of 1024!
|
||||
|
||||
There is a very strong interaction with this setting and the network MTU.
|
||||
Ideally, this buffer should fit in one network packet to avoid accessive
|
||||
re-assembly of partial TCP packets.
|
||||
|
||||
REVISIT: In fact, if the buffer does not fit in one network packet,
|
||||
then there appears to be reliability issues in the connection. I am
|
||||
not sure why that is; TCP is a stream so it should not matter how
|
||||
many packets are in a transfer.
|
||||
|
||||
Example: Negotiated pixel depth = 8 BPP, window width = 800 pixels.
|
||||
CONFIG_VNCSERVER_UPDATE_BUFSIZE needs to be the payload size (MSS)
|
||||
of the transfer or 800 bytes. The MTU is then:
|
||||
|
||||
MSS = MTU - sizeof(IP Header) - sizeof(VNC FramebufferUpdate Header)
|
||||
|
||||
For IPv4, the IP Header is 20 bytes; 40 bytes for IPv6. The
|
||||
FramebufferUpdate header is 16 bytes so. The desired MSS is 800 bytes
|
||||
so MTU = 836 or 856. For Ethernet, this is a total packet size of 870
|
||||
bytes.
|
||||
|
||||
config VNCSERVER_KBDENCODE
|
||||
bool "Encode keyboard input"
|
||||
default n
|
||||
depends on LIBC_KBDCODEC
|
||||
---help---
|
||||
Use a special encoding of keyboard characters as defined in
|
||||
include/nuttx/input/kbd_coded.h.
|
||||
|
||||
config VNCSERVER_INBUFFER_SIZE
|
||||
int "Input buffer size"
|
||||
default 80
|
||||
|
||||
config VNCSERVER_DEBUG
|
||||
bool "VNC Server debug"
|
||||
default n
|
||||
depends on DEBUG_FEATURES && !DEBUG_GRAPHICS
|
||||
---help---
|
||||
Normally VNC debug output is selected with DEBUG_GRAPHICS. The
|
||||
VNC server support this special option to enable GRAPHICS debug
|
||||
output for the VNC server while GRAPHICS debug is disabled. This
|
||||
provides an cleaner, less cluttered output when you only wish to
|
||||
debug the VNC server versus enabling DEBUG_GRAPHICS globally.
|
||||
|
||||
config VNCSERVER_UPDATE_DEBUG
|
||||
bool "Detailed updater debug"
|
||||
default n
|
||||
depends on DEBUG_GRAPHICS || VNCSERVER_DEBUG
|
||||
|
||||
endif # VNCSERVER
|
||||
@@ -1,30 +0,0 @@
|
||||
############################################################################
|
||||
# graphics/vnc/server/Make.defs
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
ifeq ($(CONFIG_VNCSERVER),y)
|
||||
|
||||
CSRCS += vnc_server.c vnc_negotiate.c vnc_updater.c vnc_receiver.c
|
||||
CSRCS += vnc_raw.c vnc_rre.c vnc_color.c vnc_fbdev.c vnc_keymap.c
|
||||
|
||||
DEPPATH += --dep-path vnc/server
|
||||
CFLAGS += ${shell $(INCDIR) "$(CC)" $(TOPDIR)/graphics/vnc/server}
|
||||
VPATH += :vnc/server
|
||||
|
||||
endif
|
||||
@@ -1,411 +0,0 @@
|
||||
/****************************************************************************
|
||||
* graphics/vnc/server/vnc_color.c
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "vnc_server.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_convert_rgbNN
|
||||
*
|
||||
* Description:
|
||||
* Convert the native framebuffer color format (either RGB8 3:3:2,
|
||||
* RGB16 5:6:5, or RGB32 8:8:8) to the remote framebuffer color format
|
||||
* (either RGB8 2:2:2, RGB8 3:3:2, RGB16 5:5:5, RGB16 5:6:5, or RGB32
|
||||
* 8:8:8)
|
||||
*
|
||||
* Input Parameters:
|
||||
* pixel - The src color in local framebuffer format.
|
||||
*
|
||||
* Returned Value:
|
||||
* The pixel in the remote framebuffer color format.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(CONFIG_VNCSERVER_COLORFMT_RGB8)
|
||||
|
||||
uint8_t vnc_convert_rgb8_222(lfb_color_t rgb)
|
||||
{
|
||||
/* 76543210
|
||||
* --------
|
||||
* RRRGGGBB
|
||||
* ..RRGGBB
|
||||
*/
|
||||
|
||||
return (uint8_t)(((rgb >> 2) & 0x30) |
|
||||
((rgb >> 1) & 0x0c) |
|
||||
(rgb & 0x03));
|
||||
}
|
||||
|
||||
uint8_t vnc_convert_rgb8_332(lfb_color_t rgb)
|
||||
{
|
||||
/* Identity mapping */
|
||||
|
||||
return (uint8_t)rgb;
|
||||
}
|
||||
|
||||
uint16_t vnc_convert_rgb16_555(lfb_color_t rgb)
|
||||
{
|
||||
/* 111111
|
||||
* 54321098 76543210
|
||||
* -----------------
|
||||
* RRRGGGBB
|
||||
* .RRR..GG G..BB...
|
||||
*/
|
||||
|
||||
return (uint8_t)((((uint16_t)rgb << 8) & 0x7000) |
|
||||
(((uint16_t)rgb << 5) & 0x0380) |
|
||||
(((uint16_t)rgb << 3) & 0x0018));
|
||||
}
|
||||
|
||||
uint16_t vnc_convert_rgb16_565(lfb_color_t rgb)
|
||||
{
|
||||
/* 111111
|
||||
* 54321098 76543210
|
||||
* -----------------
|
||||
* RRRGGGBB
|
||||
* RRR..GGG ...BB...
|
||||
*/
|
||||
|
||||
return (uint8_t)((((uint16_t)rgb << 8) & 0xe000) |
|
||||
(((uint16_t)rgb << 6) & 0x0700) |
|
||||
(((uint16_t)rgb << 3) & 0x0018));
|
||||
}
|
||||
|
||||
uint32_t vnc_convert_rgb32_888(lfb_color_t rgb)
|
||||
{
|
||||
/* 33222222 22221111 111111
|
||||
* 10987654 32109876 54321098 76543210
|
||||
* ----------------------------------
|
||||
* RRRGGGBB
|
||||
* RRR..... GGG..... BB......
|
||||
*/
|
||||
|
||||
return (((uint32_t)rgb << 16) & 0x00e00000) |
|
||||
(((uint32_t)rgb << 11) & 0x0000e000) |
|
||||
(((uint32_t)rgb << 6) & 0x000000c0);
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_VNCSERVER_COLORFMT_RGB16)
|
||||
|
||||
uint8_t vnc_convert_rgb8_222(lfb_color_t rgb)
|
||||
{
|
||||
/* 111111
|
||||
* 54321098 76543210
|
||||
* -----------------
|
||||
* RRRRRGGG GGGBBBBB
|
||||
* ..RRGGBB
|
||||
*/
|
||||
|
||||
return (uint8_t)(((rgb >> 10) & 0x0030) |
|
||||
((rgb >> 7) & 0x000c) |
|
||||
((rgb >> 3) & 0x0003));
|
||||
}
|
||||
|
||||
uint8_t vnc_convert_rgb8_332(lfb_color_t rgb)
|
||||
{
|
||||
/* 111111
|
||||
* 54321098 76543210
|
||||
* -----------------
|
||||
* RRRRRGGG GGGBBBBB
|
||||
* RRRGGGBB
|
||||
*/
|
||||
|
||||
return (uint8_t)(((rgb >> 8) & 0x00e0) |
|
||||
((rgb >> 6) & 0x001c) |
|
||||
((rgb >> 3) & 0x0003));
|
||||
}
|
||||
|
||||
uint16_t vnc_convert_rgb16_555(lfb_color_t rgb)
|
||||
{
|
||||
/* 111111
|
||||
* 54321098 76543210
|
||||
* -----------------
|
||||
* RRRRRGGG GGGBBBBB
|
||||
* .RRRRRGG GGGBBBBB
|
||||
*/
|
||||
|
||||
return (((rgb >> 1) & ~0x001f) | (rgb & 0x001f));
|
||||
}
|
||||
|
||||
uint16_t vnc_convert_rgb16_565(lfb_color_t rgb)
|
||||
{
|
||||
/* Identity mapping */
|
||||
|
||||
return (uint32_t)rgb;
|
||||
}
|
||||
|
||||
uint32_t vnc_convert_rgb32_888(lfb_color_t rgb)
|
||||
{
|
||||
/* 33222222 22221111 111111
|
||||
* 10987654 32109876 54321098 76543210
|
||||
* ----------------------------------
|
||||
* RRRRRGGG GGGBBBBB
|
||||
* RRRRR... GGGGGG.. BBBBB...
|
||||
*/
|
||||
|
||||
return (((uint32_t)rgb << 8) & 0x00f80000) |
|
||||
(((uint32_t)rgb << 6) & 0x0000fc00) |
|
||||
(((uint32_t)rgb << 3) & 0x000000f8);
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_VNCSERVER_COLORFMT_RGB32)
|
||||
|
||||
uint8_t vnc_convert_rgb8_222(lfb_color_t rgb)
|
||||
{
|
||||
/* 33222222 22221111 111111
|
||||
* 10987654 32109876 54321098 76543210
|
||||
* -----------------------------------
|
||||
* RRRRRRRR GGGGGGGG BBBBBBBB
|
||||
* ..RRGGBB
|
||||
*/
|
||||
|
||||
return (uint8_t)(((rgb >> 18) & 0x00000030) |
|
||||
((rgb >> 12) & 0x0000000c) |
|
||||
((rgb >> 6) & 0x00000003));
|
||||
}
|
||||
|
||||
uint8_t vnc_convert_rgb8_332(lfb_color_t rgb)
|
||||
{
|
||||
/* 33222222 22221111 111111
|
||||
* 10987654 32109876 54321098 76543210
|
||||
* -----------------------------------
|
||||
* RRRRRRRR GGGGGGGG BBBBBBBB
|
||||
* RRRGGGBB
|
||||
*/
|
||||
|
||||
return (uint8_t)(((rgb >> 16) & 0x00000070) |
|
||||
((rgb >> 11) & 0x0000001c) |
|
||||
((rgb >> 6) & 0x00000003));
|
||||
}
|
||||
|
||||
uint16_t vnc_convert_rgb16_555(lfb_color_t rgb)
|
||||
{
|
||||
/* 33222222 22221111 111111
|
||||
* 10987654 32109876 54321098 76543210
|
||||
* -----------------------------------
|
||||
* RRRRRRRR GGGGGGGG BBBBBBBB
|
||||
* .RRRRRGG GGGBBBBB
|
||||
*/
|
||||
|
||||
return (uint16_t)(((rgb >> 9) & 0x00007c00) |
|
||||
((rgb >> 6) & 0x000003e0) |
|
||||
((rgb >> 3) & 0x0000001f));
|
||||
}
|
||||
|
||||
uint16_t vnc_convert_rgb16_565(lfb_color_t rgb)
|
||||
{
|
||||
/* 33222222 22221111 111111
|
||||
* 10987654 32109876 54321098 76543210
|
||||
* -----------------------------------
|
||||
* RRRRRRRR GGGGGGGG BBBBBBBB
|
||||
* RRRRRGGG GGGBBBBB
|
||||
*/
|
||||
|
||||
return (uint16_t)(((rgb >> 8) & 0x0000f800) |
|
||||
((rgb >> 5) & 0x000007e0) |
|
||||
((rgb >> 3) & 0x0000001f));
|
||||
}
|
||||
|
||||
uint32_t vnc_convert_rgb32_888(lfb_color_t rgb)
|
||||
{
|
||||
/* Identity mapping */
|
||||
|
||||
return rgb;
|
||||
}
|
||||
#else
|
||||
# error Unspecified/unsupported color format
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_colors
|
||||
*
|
||||
* Description:
|
||||
* Test the update rectangle to see if it contains complex colors. If it
|
||||
* contains only a few colors, then it may be a candidate for some type
|
||||
* run-length encoding.
|
||||
*
|
||||
* REVISIT: This function is imperfect: It will fail if there are more
|
||||
* than 8 colors in the region. For small colors, we can keep a local
|
||||
* array for all color formats and always return the exact result, no
|
||||
* matter now many colors.
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - An instance of the session structure.
|
||||
* rect - The update region in the local frame buffer.
|
||||
* maxcolors - The maximum number of colors that should be returned. This
|
||||
* currently cannot exceed eight.
|
||||
* colors - The top 'maxcolors' most frequency colors are returned.
|
||||
*
|
||||
* Returned Value:
|
||||
* The number of valid colors in the colors[] array are returned, the
|
||||
* first entry being the most frequent. A negated errno value is returned
|
||||
* if the colors cannot be determined. This would be the case if the color
|
||||
* there are more than 'maxcolors' colors in the update rectangle.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int vnc_colors(FAR struct vnc_session_s *session,
|
||||
FAR struct fb_area_s *rect,
|
||||
unsigned int maxcolors,
|
||||
FAR lfb_color_t *colors)
|
||||
{
|
||||
FAR const lfb_color_t *rowstart;
|
||||
FAR const lfb_color_t *pixptr;
|
||||
lfb_color_t pixel;
|
||||
fb_coord_t x;
|
||||
fb_coord_t y;
|
||||
int ncolors = 0;
|
||||
int pixndx;
|
||||
int maxndx;
|
||||
int cmpndx;
|
||||
unsigned int counts[8] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
DEBUGASSERT(session != NULL && rect != NULL &&
|
||||
maxcolors <= 8 && colors != NULL);
|
||||
|
||||
/* Pointer to the first pixel in the first row in the local framebuffer */
|
||||
|
||||
rowstart = (FAR lfb_color_t *)
|
||||
(session->fb + RFB_STRIDE * rect->y +
|
||||
RFB_BYTESPERPIXEL * rect->x);
|
||||
|
||||
/* Loop for each row in the rectangle */
|
||||
|
||||
for (y = 0; y < rect->h; y++)
|
||||
{
|
||||
/* Loop for each column in the row */
|
||||
|
||||
pixptr = rowstart;
|
||||
for (x = 0; x < rect->w; x++)
|
||||
{
|
||||
/* Compare this pix to all of the others we have seen */
|
||||
|
||||
pixel = *pixptr++;
|
||||
for (pixndx = 0; pixndx < ncolors; pixndx++)
|
||||
{
|
||||
if (colors[pixndx] == pixel)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Have we seen this color before? */
|
||||
|
||||
if (pixndx < ncolors)
|
||||
{
|
||||
/* Yes.. just increment the count of the number of times we
|
||||
* have seen it.
|
||||
*/
|
||||
|
||||
counts[pixndx]++;
|
||||
}
|
||||
|
||||
/* Do we have space for another color? */
|
||||
|
||||
else if (ncolors >= maxcolors)
|
||||
{
|
||||
/* No, then bail. We don't have enough memory to deal with
|
||||
* large number of colors.
|
||||
*/
|
||||
|
||||
return -E2BIG;
|
||||
}
|
||||
|
||||
/* Add the new color to the list of colors that we have found */
|
||||
|
||||
else
|
||||
{
|
||||
colors[ncolors] = pixel;
|
||||
counts[ncolors] = 1;
|
||||
ncolors++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the point to the start of the next row */
|
||||
|
||||
rowstart = (FAR lfb_color_t *)((uintptr_t)rowstart + RFB_STRIDE);
|
||||
}
|
||||
|
||||
/* Now sort the colors by how often we saw them with the most frequent
|
||||
* color in the first position.
|
||||
*/
|
||||
|
||||
/* Loop for colors N={0..(ncolors-1)} */
|
||||
|
||||
for (pixndx = 0; pixndx < ncolors - 1; pixndx++)
|
||||
{
|
||||
/* Compare color N with colors M={(N_1)..ncolors} */
|
||||
|
||||
maxndx = pixndx;
|
||||
for (cmpndx = maxndx + 1; cmpndx < ncolors; cmpndx++)
|
||||
{
|
||||
/* Have we seen color M more often that color N? */
|
||||
|
||||
if (counts[cmpndx] > counts[maxndx])
|
||||
{
|
||||
/* Yes.. then color M has been seen more frequently */
|
||||
|
||||
maxndx = cmpndx;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do nothing if color N is the most often seen */
|
||||
|
||||
if (maxndx != pixndx)
|
||||
{
|
||||
/* Otherwise swap color N and color M */
|
||||
|
||||
/* Remember color N */
|
||||
|
||||
lfb_color_t tmpcolor = colors[pixndx];
|
||||
int tmpcount = counts[pixndx];
|
||||
|
||||
/* Set color N to color M */
|
||||
|
||||
colors[pixndx] = colors[maxndx];
|
||||
counts[pixndx] = counts[maxndx];
|
||||
|
||||
/* Set color M to color N */
|
||||
|
||||
colors[maxndx] = tmpcolor;
|
||||
counts[maxndx] = tmpcount;
|
||||
}
|
||||
}
|
||||
|
||||
/* And return the number of colors that we found */
|
||||
|
||||
return ncolors;
|
||||
}
|
||||
@@ -1,892 +0,0 @@
|
||||
/****************************************************************************
|
||||
* graphics/vnc/server/vnc_fbdev.c
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if defined(CONFIG_VNCSERVER_DEBUG) && !defined(CONFIG_DEBUG_GRAPHICS)
|
||||
# undef CONFIG_DEBUG_ERROR
|
||||
# undef CONFIG_DEBUG_WARN
|
||||
# undef CONFIG_DEBUG_INFO
|
||||
# undef CONFIG_DEBUG_GRAPHICS_ERROR
|
||||
# undef CONFIG_DEBUG_GRAPHICS_WARN
|
||||
# undef CONFIG_DEBUG_GRAPHICS_INFO
|
||||
# define CONFIG_DEBUG_ERROR 1
|
||||
# define CONFIG_DEBUG_WARN 1
|
||||
# define CONFIG_DEBUG_INFO 1
|
||||
# define CONFIG_DEBUG_GRAPHICS 1
|
||||
# define CONFIG_DEBUG_GRAPHICS_ERROR 1
|
||||
# define CONFIG_DEBUG_GRAPHICS_WARN 1
|
||||
# define CONFIG_DEBUG_GRAPHICS_INFO 1
|
||||
#endif
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/kthread.h>
|
||||
#include <nuttx/video/fb.h>
|
||||
#include <nuttx/video/vnc.h>
|
||||
|
||||
#include "vnc_server.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/* This structure provides the frame buffer interface and also incapulates
|
||||
* information about the frame buffer instances for each display.
|
||||
*/
|
||||
|
||||
struct vnc_fbinfo_s
|
||||
{
|
||||
/* The publicly visible frame buffer interface. This must appear first
|
||||
* so that struct vnc_fbinfo_s is cast compatible with struct fb_vtable_s.
|
||||
*/
|
||||
|
||||
struct fb_vtable_s vtable;
|
||||
|
||||
/* Our private per-display information */
|
||||
|
||||
bool initialized; /* True: This instance has been initialized */
|
||||
uint8_t display; /* Display number */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/* Get information about the video controller configuration and the
|
||||
* configuration of each color plane.
|
||||
*/
|
||||
|
||||
static int up_getvideoinfo(FAR struct fb_vtable_s *vtable,
|
||||
FAR struct fb_videoinfo_s *vinfo);
|
||||
static int up_getplaneinfo(FAR struct fb_vtable_s *vtable, int planeno,
|
||||
FAR struct fb_planeinfo_s *pinfo);
|
||||
|
||||
/* The following are provided only if the video hardware supports RGB color
|
||||
* mapping.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_FB_CMAP
|
||||
static int up_getcmap(FAR struct fb_vtable_s *vtable,
|
||||
FAR struct fb_cmap_s *cmap);
|
||||
static int up_putcmap(FAR struct fb_vtable_s *vtable,
|
||||
FAR const struct fb_cmap_s *cmap);
|
||||
#endif
|
||||
|
||||
/* The following are provided only if the video hardware supports a hardware
|
||||
* cursor.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_FB_HWCURSOR
|
||||
static int up_getcursor(FAR struct fb_vtable_s *vtable,
|
||||
FAR struct fb_cursorattrib_s *attrib);
|
||||
static int up_setcursor(FAR struct fb_vtable_s *vtable,
|
||||
FAR struct fb_setcursor_s *settings);
|
||||
#endif
|
||||
|
||||
/* Update the host window when there is a change to the framebuffer */
|
||||
|
||||
static int up_updateearea(FAR struct fb_vtable_s *vtable,
|
||||
FAR const struct fb_area_s *area);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/* Current cursor position */
|
||||
|
||||
#ifdef CONFIG_FB_HWCURSOR
|
||||
static struct fb_cursorpos_s g_cpos;
|
||||
|
||||
/* Current cursor size */
|
||||
|
||||
#ifdef CONFIG_FB_HWCURSORSIZE
|
||||
static struct fb_cursorsize_s g_csize;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* The framebuffer objects, one for each configured display. */
|
||||
|
||||
static struct vnc_fbinfo_s g_fbinfo[RFB_MAX_DISPLAYS];
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
/* Used to synchronize the server thread with the framebuffer driver.
|
||||
* NOTE: This depends on the fact that all zero is correct initial state
|
||||
* for the semaphores.
|
||||
*/
|
||||
|
||||
struct fb_startup_s g_fbstartup[RFB_MAX_DISPLAYS];
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_getvideoinfo
|
||||
****************************************************************************/
|
||||
|
||||
static int up_getvideoinfo(FAR struct fb_vtable_s *vtable,
|
||||
FAR struct fb_videoinfo_s *vinfo)
|
||||
{
|
||||
FAR struct vnc_fbinfo_s *fbinfo = (FAR struct vnc_fbinfo_s *)vtable;
|
||||
FAR struct vnc_session_s *session;
|
||||
|
||||
ginfo("vtable=%p vinfo=%p\n", vtable, vinfo);
|
||||
|
||||
DEBUGASSERT(fbinfo != NULL && vinfo != NULL);
|
||||
if (fbinfo != NULL && vinfo != NULL)
|
||||
{
|
||||
DEBUGASSERT(fbinfo->display >= 0 &&
|
||||
fbinfo->display < RFB_MAX_DISPLAYS);
|
||||
session = g_vnc_sessions[fbinfo->display];
|
||||
|
||||
if (session == NULL || session->state != VNCSERVER_RUNNING)
|
||||
{
|
||||
gerr("ERROR: session is not connected\n");
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
/* Return the requested video info. We are committed to using the
|
||||
* configured color format in the framebuffer, but performing color
|
||||
* conversions on the fly for the remote framebuffer as necessary.
|
||||
*/
|
||||
|
||||
vinfo->fmt = RFB_COLORFMT;
|
||||
vinfo->xres = CONFIG_VNCSERVER_SCREENWIDTH;
|
||||
vinfo->yres = CONFIG_VNCSERVER_SCREENHEIGHT;
|
||||
vinfo->nplanes = 1;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
gerr("ERROR: Invalid arguments\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_getplaneinfo
|
||||
****************************************************************************/
|
||||
|
||||
static int up_getplaneinfo(FAR struct fb_vtable_s *vtable, int planeno,
|
||||
FAR struct fb_planeinfo_s *pinfo)
|
||||
{
|
||||
FAR struct vnc_fbinfo_s *fbinfo = (FAR struct vnc_fbinfo_s *)vtable;
|
||||
FAR struct vnc_session_s *session;
|
||||
|
||||
ginfo("vtable=%p planeno=%d pinfo=%p\n", vtable, planeno, pinfo);
|
||||
|
||||
DEBUGASSERT(fbinfo != NULL && pinfo != NULL && planeno == 0);
|
||||
if (fbinfo != NULL && pinfo != NULL && planeno == 0)
|
||||
{
|
||||
DEBUGASSERT(fbinfo->display >= 0 &&
|
||||
fbinfo->display < RFB_MAX_DISPLAYS);
|
||||
session = g_vnc_sessions[fbinfo->display];
|
||||
|
||||
if (session == NULL || session->state != VNCSERVER_RUNNING)
|
||||
{
|
||||
gerr("ERROR: session is not connected\n");
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
DEBUGASSERT(session->fb != NULL);
|
||||
|
||||
/* Return the requested plane info. We are committed to using the
|
||||
* configured bits-per-pixels in the framebuffer, but performing color
|
||||
* conversions on the fly for the remote framebuffer as necessary.
|
||||
*/
|
||||
|
||||
pinfo->fbmem = (FAR void *)session->fb;
|
||||
pinfo->fblen = RFB_SIZE;
|
||||
pinfo->stride = RFB_STRIDE;
|
||||
pinfo->display = fbinfo->display;
|
||||
pinfo->bpp = RFB_BITSPERPIXEL;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
gerr("ERROR: Returning EINVAL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_getcmap
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_FB_CMAP
|
||||
static int up_getcmap(FAR struct fb_vtable_s *vtable,
|
||||
FAR struct fb_cmap_s *cmap)
|
||||
{
|
||||
FAR struct vnc_fbinfo_s *fbinfo = (FAR struct vnc_fbinfo_s *)vtable;
|
||||
FAR struct vnc_session_s *session;
|
||||
int i;
|
||||
|
||||
ginfo("vtable=%p cmap=%p\n", vtable, cmap);
|
||||
|
||||
DEBUGASSERT(fbinfo != NULL && cmap != NULL);
|
||||
|
||||
if (fbinfo != NULL && cmap != NULL)
|
||||
{
|
||||
DEBUGASSERT(fbinfo->display >= 0 &&
|
||||
fbinfo->display < RFB_MAX_DISPLAYS);
|
||||
session = g_vnc_sessions[fbinfo->display];
|
||||
|
||||
if (session == NULL || session->state != VNCSERVER_RUNNING)
|
||||
{
|
||||
gerr("ERROR: session is not connected\n");
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
ginfo("first=%d len=%d\n", vcmap->first, cmap->len);
|
||||
#warning Missing logic
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
gerr("ERROR: Returning EINVAL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_putcmap
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_FB_CMAP
|
||||
static int up_putcmap(FAR struct fb_vtable_s *vtable,
|
||||
FAR const struct fb_cmap_s *cmap)
|
||||
{
|
||||
FAR struct vnc_fbinfo_s *fbinfo = (FAR struct vnc_fbinfo_s *)vtable;
|
||||
FAR struct vnc_session_s *session;
|
||||
int i;
|
||||
|
||||
ginfo("vtable=%p cmap=%p\n", vtable, cmap);
|
||||
|
||||
DEBUGASSERT(fbinfo != NULL && cmap != NULL);
|
||||
|
||||
if (fbinfo != NULL && cmap != NULL)
|
||||
{
|
||||
DEBUGASSERT(fbinfo->display >= 0 &&
|
||||
fbinfo->display < RFB_MAX_DISPLAYS);
|
||||
session = g_vnc_sessions[fbinfo->display];
|
||||
|
||||
if (session == NULL || session->state != VNCSERVER_RUNNING)
|
||||
{
|
||||
gerr("ERROR: session is not connected\n");
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
ginfo("first=%d len=%d\n", vcmap->first, cmap->len);
|
||||
#warning Missing logic
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
gerr("ERROR: Returning EINVAL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_getcursor
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_FB_HWCURSOR
|
||||
static int up_getcursor(FAR struct fb_vtable_s *vtable,
|
||||
FAR struct fb_cursorattrib_s *attrib)
|
||||
{
|
||||
FAR struct vnc_fbinfo_s *fbinfo = (FAR struct vnc_fbinfo_s *)vtable;
|
||||
FAR struct vnc_session_s *session;
|
||||
int i;
|
||||
|
||||
ginfo("vtable=%p attrib=%p\n", vtable, attrib);
|
||||
|
||||
DEBUGASSERT(fbinfo != NULL && attrib != NULL);
|
||||
|
||||
if (fbinfo != NULL && attrib != NULL)
|
||||
{
|
||||
DEBUGASSERT(fbinfo->display >= 0 &&
|
||||
fbinfo->display < RFB_MAX_DISPLAYS);
|
||||
session = g_vnc_sessions[fbinfo->display];
|
||||
|
||||
if (session == NULL || session->state != VNCSERVER_RUNNING)
|
||||
{
|
||||
gerr("ERROR: session is not connected\n");
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
#warning Missing logic
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
gerr("ERROR: Returning EINVAL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_setcursor
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_FB_HWCURSOR
|
||||
static int up_setcursor(FAR struct fb_vtable_s *vtable,
|
||||
FAR struct fb_setcursor_s *settings)
|
||||
{
|
||||
FAR struct vnc_fbinfo_s *fbinfo = (FAR struct vnc_fbinfo_s *)vtable;
|
||||
FAR struct vnc_session_s *session;
|
||||
int i;
|
||||
|
||||
ginfo("vtable=%p settings=%p\n", vtable, settings);
|
||||
|
||||
DEBUGASSERT(fbinfo != NULL && settings != NULL);
|
||||
|
||||
if (fbinfo != NULL && settings != NULL)
|
||||
{
|
||||
DEBUGASSERT(fbinfo->display >= 0 &&
|
||||
fbinfo->display < RFB_MAX_DISPLAYS);
|
||||
session = g_vnc_sessions[fbinfo->display];
|
||||
|
||||
if (session == NULL || session->state != VNCSERVER_RUNNING)
|
||||
{
|
||||
gerr("ERROR: session is not connected\n");
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
ginfo("flags: %02x\n", settings->flags);
|
||||
if ((settings->flags & FB_CUR_SETPOSITION) != 0)
|
||||
{
|
||||
#warning Missing logic
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FB_HWCURSORSIZE
|
||||
if ((settings->flags & FB_CUR_SETSIZE) != 0)
|
||||
{
|
||||
#warning Missing logic
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FB_HWCURSORIMAGE
|
||||
if ((settings->flags & FB_CUR_SETIMAGE) != 0)
|
||||
{
|
||||
#warning Missing logic
|
||||
}
|
||||
#endif
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
gerr("ERROR: Returning EINVAL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_updateearea
|
||||
****************************************************************************/
|
||||
|
||||
static int up_updateearea(FAR struct fb_vtable_s *vtable,
|
||||
FAR const struct fb_area_s *area)
|
||||
{
|
||||
FAR struct vnc_fbinfo_s *fbinfo = (FAR struct vnc_fbinfo_s *)vtable;
|
||||
FAR struct vnc_session_s *session;
|
||||
int ret = OK;
|
||||
|
||||
DEBUGASSERT(fbinfo != NULL && area != NULL);
|
||||
|
||||
/* Recover the session information from the display number in the planeinfo
|
||||
* structure.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(fbinfo->display >= 0 && fbinfo->display < RFB_MAX_DISPLAYS);
|
||||
session = g_vnc_sessions[fbinfo->display];
|
||||
|
||||
/* Verify that the session is still valid */
|
||||
|
||||
if (session != NULL && session->state == VNCSERVER_RUNNING)
|
||||
{
|
||||
/* Queue the rectangular update */
|
||||
|
||||
ret = vnc_update_rectangle(session, area, true);
|
||||
if (ret < 0)
|
||||
{
|
||||
gerr("ERROR: vnc_update_rectangle failed: %d\n", ret);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FB_SYNC
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_waitforsync
|
||||
****************************************************************************/
|
||||
|
||||
static int up_waitforsync(FAR struct fb_vtable_s *vtable)
|
||||
{
|
||||
FAR struct vnc_fbinfo_s *fbinfo = (FAR struct vnc_fbinfo_s *)vtable;
|
||||
FAR struct vnc_session_s *session;
|
||||
|
||||
DEBUGASSERT(fbinfo);
|
||||
DEBUGASSERT(fbinfo->display >= 0 && fbinfo->display < RFB_MAX_DISPLAYS);
|
||||
|
||||
session = g_vnc_sessions[fbinfo->display];
|
||||
|
||||
if (session && session->state == VNCSERVER_RUNNING)
|
||||
{
|
||||
return nxsem_wait(&session->vsyncsem);
|
||||
}
|
||||
|
||||
return ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_start_server
|
||||
*
|
||||
* Description:
|
||||
* Start the VNC server.
|
||||
*
|
||||
* Input Parameters:
|
||||
* display - In the case of hardware with multiple displays, this
|
||||
* specifies the display. Normally this is zero.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero is returned on success; a negated errno value is returned on any
|
||||
* failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int vnc_start_server(int display)
|
||||
{
|
||||
FAR char *argv[2];
|
||||
char str[8];
|
||||
pid_t pid;
|
||||
|
||||
DEBUGASSERT(display >= 0 && display < RFB_MAX_DISPLAYS);
|
||||
|
||||
/* Check if the server is already running */
|
||||
|
||||
if (g_vnc_sessions[display] != NULL)
|
||||
{
|
||||
DEBUGASSERT(g_vnc_sessions[display]->state >= VNCSERVER_INITIALIZED);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Start the VNC server kernel thread. */
|
||||
|
||||
ginfo("Starting the VNC server for display %d\n", display);
|
||||
|
||||
g_fbstartup[display].result = -EBUSY;
|
||||
nxsem_reset(&g_fbstartup[display].fbinit, 0);
|
||||
nxsem_reset(&g_fbstartup[display].fbconnect, 0);
|
||||
|
||||
/* Format the kernel thread arguments (ASCII.. yech) */
|
||||
|
||||
itoa(display, str, 10);
|
||||
argv[0] = str;
|
||||
argv[1] = NULL;
|
||||
|
||||
pid = kthread_create("vnc_server", CONFIG_VNCSERVER_PRIO,
|
||||
CONFIG_VNCSERVER_STACKSIZE,
|
||||
(main_t)vnc_server, argv);
|
||||
if (pid < 0)
|
||||
{
|
||||
gerr("ERROR: Failed to start the VNC server: %d\n", (int)pid);
|
||||
return (int)pid;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_wait_start
|
||||
*
|
||||
* Description:
|
||||
* Wait for the server to be started.
|
||||
*
|
||||
* Input Parameters:
|
||||
* display - In the case of hardware with multiple displays, this
|
||||
* specifies the display. Normally this is zero.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero is returned on success; a negated errno value is returned on any
|
||||
* failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline int vnc_wait_start(int display)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Check if there has been a session allocated yet. This is one of the
|
||||
* first things that the VNC server will do with the kernel thread is
|
||||
* started. But we might be here before the thread has gotten that far.
|
||||
*
|
||||
* If it has been allocated, then wait until it is in the INIITIALIZED
|
||||
* state. The INITIAILIZED states indicates that the session structure
|
||||
* has been allocated and fully initialized.
|
||||
*/
|
||||
|
||||
while (g_vnc_sessions[display] == NULL ||
|
||||
g_vnc_sessions[display]->state == VNCSERVER_UNINITIALIZED)
|
||||
{
|
||||
/* The server is not yet running. Wait for the server to post the FB
|
||||
* semaphore. In certain error situations, the server may post the
|
||||
* semaphore, then reset it to zero. There are are certainly race
|
||||
* conditions here, but I think none that are fatal.
|
||||
*/
|
||||
|
||||
ret = nxsem_wait_uninterruptible(&g_fbstartup[display].fbinit);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_wait_connect
|
||||
*
|
||||
* Description:
|
||||
* Wait for the server to be connected to the VNC client. We can do
|
||||
* nothing until that connection is established.
|
||||
*
|
||||
* Input Parameters:
|
||||
* display - In the case of hardware with multiple displays, this
|
||||
* specifies the display. Normally this is zero.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero is returned on success; a negated errno value is returned on any
|
||||
* failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline int vnc_wait_connect(int display)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Check if there has been a session allocated yet. This is one of the
|
||||
* first things that the VNC server will do with the kernel thread is
|
||||
* started. But we might be here before the thread has gotten that far.
|
||||
*
|
||||
* If it has been allocated, then wait until it is in the RUNNING state.
|
||||
* The RUNNING state indicates that the server has started, it has
|
||||
* established a connection with the VNC client, it is negotiated
|
||||
* encodings and framebuffer characteristics, and it has started the
|
||||
* updater thread. The server is now ready to receive Client-to-Server
|
||||
* messages and to perform remote framebuffer updates.
|
||||
*/
|
||||
|
||||
while (g_vnc_sessions[display] == NULL ||
|
||||
g_vnc_sessions[display]->state != VNCSERVER_RUNNING)
|
||||
{
|
||||
/* The server is not yet running. Wait for the server to post the FB
|
||||
* semaphore. In certain error situations, the server may post the
|
||||
* semaphore, then reset it to zero. There are are certainly race
|
||||
* conditions here, but I think none that are fatal.
|
||||
*/
|
||||
|
||||
ret = nxsem_wait_uninterruptible(&g_fbstartup[display].fbconnect);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* We were awakened. A result of -EBUSY means that the negotiation
|
||||
* is not complete. Why would we be awakened in that case? Some
|
||||
* counting semaphore screw-up?
|
||||
*/
|
||||
|
||||
ret = g_fbstartup[display].result;
|
||||
if (ret != -EBUSY)
|
||||
{
|
||||
#ifdef CONFIG_DEBUG_FEATURES
|
||||
if (ret < 0)
|
||||
{
|
||||
DEBUGASSERT(g_vnc_sessions[display] == NULL);
|
||||
gerr("ERROR: VNC server startup failed: %d\n", ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUGASSERT(g_vnc_sessions[display] != NULL &&
|
||||
g_vnc_sessions[display]->state ==
|
||||
VNCSERVER_RUNNING);
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_fbinitialize
|
||||
*
|
||||
* Description:
|
||||
* Initialize the framebuffer video hardware associated with the display.
|
||||
*
|
||||
* Input Parameters:
|
||||
* display - In the case of hardware with multiple displays, this
|
||||
* specifies the display. Normally this is zero.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero is returned on success; a negated errno value is returned on any
|
||||
* failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int up_fbinitialize(int display)
|
||||
{
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(display >= 0 && display < RFB_MAX_DISPLAYS);
|
||||
|
||||
/* Start the VNC server kernel thread. */
|
||||
|
||||
ret = vnc_start_server(display);
|
||||
if (ret < 0)
|
||||
{
|
||||
gerr("ERROR: vnc_start_server() failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Wait for the VNC client to connect and for the RFB to be ready */
|
||||
|
||||
ret = vnc_wait_connect(display);
|
||||
if (ret < 0)
|
||||
{
|
||||
gerr("ERROR: vnc_wait_connect() failed: %d\n", ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_fbinitialize
|
||||
*
|
||||
* Description:
|
||||
* Initialize the VNC frame buffer driver. The VNC frame buffer driver
|
||||
* supports two initialization interfaces: The standard up_fbinitialize()
|
||||
* that will be called from the graphics layer and this special
|
||||
* initialization function that can be used only by VNC aware OS logic.
|
||||
*
|
||||
* The two initialization functions may be called separated or together in
|
||||
* either order. The difference is that standard up_fbinitialize(), if
|
||||
* used by itself, will not have any remote mouse or keyboard inputs that
|
||||
* are reported to the VNC framebuffer driver from the remote VNC client.
|
||||
*
|
||||
* In the standard graphics architecture, the keyboard/mouse inputs are
|
||||
* received by some application/board specific logic at the highest level
|
||||
* in the architecture via input drivers. The received keyboard/mouse
|
||||
* input data must then be "injected" into NX where it can they can be
|
||||
* assigned to the window that has focus. They will eventually be
|
||||
* received by the Window instances via NX callback methods.
|
||||
*
|
||||
* NX is a middleware layer in the architecture, below the
|
||||
* application/board specific logic but above the driver level logic. The
|
||||
* frame buffer driver, on the other hand lies at the very lowest level in
|
||||
* the graphics architecture. It cannot call upward into the application
|
||||
* nor can it call upward into NX. So, some other logic.
|
||||
*
|
||||
* vnc_fbinitialize() provides an optional, alternative initialization
|
||||
* function. It is optional because it need not be called. If it is not
|
||||
* called, however, keyboard/mouse inputs from the remote VNC client will
|
||||
* be lost. By calling vnc_fbinitialize(), you can provide callout
|
||||
* functions that can be received by logic higher in the architecture.
|
||||
*
|
||||
* Input Parameters:
|
||||
* display - In the case of hardware with multiple displays, this
|
||||
* specifies the display. Normally this is zero.
|
||||
* kbdout - If non-NULL, then the pointed-to function will be called to
|
||||
* handle all keyboard input as it is received. This may be either raw,
|
||||
* ASCII keypress input or encoded keyboard input as determined by
|
||||
* CONFIG_VNCSERVER_KBDENCODE. See include/nuttx/input/kbd_codec.h.
|
||||
* mouseout - If non-NULL, then the pointed-to function will be called to
|
||||
* handle all mouse input as it is received.
|
||||
* arg - An opaque user provided argument that will be provided when the
|
||||
* callouts are performed.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success. Otherwise, a negated errno value is
|
||||
* returned to indicate the nature of the failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int vnc_fbinitialize(int display, vnc_kbdout_t kbdout,
|
||||
vnc_mouseout_t mouseout, FAR void *arg)
|
||||
{
|
||||
FAR struct vnc_session_s *session;
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(display >= 0 && display < RFB_MAX_DISPLAYS);
|
||||
|
||||
/* Start the VNC server kernel thread. */
|
||||
|
||||
ret = vnc_start_server(display);
|
||||
if (ret < 0)
|
||||
{
|
||||
gerr("ERROR: vnc_start_server() failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Wait for the VNC server to start and complete initialization. */
|
||||
|
||||
ret = vnc_wait_start(display);
|
||||
if (ret < 0)
|
||||
{
|
||||
gerr("ERROR: vnc_wait_start() failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Save the input callout function information in the session structure. */
|
||||
|
||||
session = g_vnc_sessions[display];
|
||||
DEBUGASSERT(session != NULL);
|
||||
|
||||
session->kbdout = kbdout;
|
||||
session->mouseout = mouseout;
|
||||
session->arg = arg;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_fbgetvplane
|
||||
*
|
||||
* Description:
|
||||
* Return a a reference to the framebuffer object for the specified video
|
||||
* plane of the specified plane. Many OSDs support multiple planes of
|
||||
* video.
|
||||
*
|
||||
* Input Parameters:
|
||||
* display - In the case of hardware with multiple displays, this
|
||||
* specifies the display. Normally this is zero.
|
||||
* vplane - Identifies the plane being queried.
|
||||
*
|
||||
* Returned Value:
|
||||
* A non-NULL pointer to the frame buffer access structure is returned on
|
||||
* success; NULL is returned on any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct fb_vtable_s *up_fbgetvplane(int display, int vplane)
|
||||
{
|
||||
FAR struct vnc_session_s *session;
|
||||
FAR struct vnc_fbinfo_s *fbinfo;
|
||||
|
||||
DEBUGASSERT(display >= 0 && display < RFB_MAX_DISPLAYS);
|
||||
session = g_vnc_sessions[display];
|
||||
|
||||
/* Verify that the session is still valid */
|
||||
|
||||
if (session == NULL || session->state != VNCSERVER_RUNNING)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (vplane == 0)
|
||||
{
|
||||
/* Has the framebuffer information been initialized for this display? */
|
||||
|
||||
fbinfo = &g_fbinfo[display];
|
||||
if (!fbinfo->initialized)
|
||||
{
|
||||
fbinfo->vtable.getvideoinfo = up_getvideoinfo,
|
||||
fbinfo->vtable.getplaneinfo = up_getplaneinfo,
|
||||
#ifdef CONFIG_FB_CMAP
|
||||
fbinfo->vtable.getcmap = up_getcmap,
|
||||
fbinfo->vtable.putcmap = up_putcmap,
|
||||
#endif
|
||||
#ifdef CONFIG_FB_HWCURSOR
|
||||
fbinfo->vtable.getcursor = up_getcursor,
|
||||
fbinfo->vtable.setcursor = up_setcursor,
|
||||
#endif
|
||||
#ifdef CONFIG_FB_SYNC
|
||||
fbinfo->vtable.waitforvsync = up_waitforsync;
|
||||
#endif
|
||||
fbinfo->vtable.updatearea = up_updateearea,
|
||||
fbinfo->display = display;
|
||||
fbinfo->initialized = true;
|
||||
}
|
||||
|
||||
return &fbinfo->vtable;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_fbuninitialize
|
||||
*
|
||||
* Description:
|
||||
* Uninitialize the framebuffer support for the specified display.
|
||||
*
|
||||
* Input Parameters:
|
||||
* display - In the case of hardware with multiple displays, this
|
||||
* specifies the display. Normally this is zero.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void up_fbuninitialize(int display)
|
||||
{
|
||||
#if 0 /* Do nothing */
|
||||
FAR struct vnc_session_s *session;
|
||||
FAR struct vnc_fbinfo_s *fbinfo;
|
||||
|
||||
DEBUGASSERT(display >= 0 && display < RFB_MAX_DISPLAYS);
|
||||
session = g_vnc_sessions[display];
|
||||
|
||||
/* Verify that the session is still valid */
|
||||
|
||||
if (session != NULL)
|
||||
{
|
||||
fbinfo = &g_fbinfo[display];
|
||||
#warning Missing logic
|
||||
UNUSED(session);
|
||||
UNUSED(fbinfo);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1,610 +0,0 @@
|
||||
/****************************************************************************
|
||||
* graphics/vnc/server/vnc_keymap.c
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <nuttx/ascii.h>
|
||||
|
||||
#define XK_MISCELLANY 1 /* Select X11 character set */
|
||||
#define XK_LATIN1 1
|
||||
#define XK_XKB_KEYS 1
|
||||
|
||||
#include <nuttx/video/vnc.h>
|
||||
#include <nuttx/input/x11_keysymdef.h>
|
||||
#include <nuttx/input/kbd_codec.h>
|
||||
|
||||
#include "vnc_server.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define FIRST_PRTCHAR ASCII_SPACE
|
||||
#define LAST_PRTCHAR ASCII_TILDE
|
||||
#define NPRTCHARS (ASCII_TILDE + ASCII_SPACE - 1)
|
||||
|
||||
#define ISPRINTABLE(c) ((c) >= FIRST_PRTCHAR && (c) <= LAST_PRTCHAR)
|
||||
#define ISLOWERCASE(c) ((c) >= ASCII_a && (c) <= ASCII_z)
|
||||
#define ISUPPERCASE(c) ((c) >= ASCII_A && (c) <= ASCII_Z)
|
||||
#define ISALPHABETIC(c) (ISLOWERCASE(c) || ISUPPERCASE(c))
|
||||
|
||||
/****************************************************************************
|
||||
* Private types
|
||||
****************************************************************************/
|
||||
|
||||
enum vnc_modifier_e
|
||||
{
|
||||
MOD_SHIFT = 0, /* Left or right shift key */
|
||||
MOD_CONTROL, /* Left or right control key */
|
||||
MOD_ALT, /* Alt key */
|
||||
MOD_CAPSLOCK, /* Caps lock */
|
||||
MOD_SHIFTLOCK, /* Shift lock */
|
||||
#ifdef CONFIG_VNCSERVER_KBDENCODE
|
||||
MOD_SCROLLLOCK, /* Scroll lock */
|
||||
MOD_NUMLOCK, /* Num lock */
|
||||
#endif
|
||||
NMODIFIERS
|
||||
};
|
||||
|
||||
struct vnc_keymap_s
|
||||
{
|
||||
uint16_t nxcode;
|
||||
uint16_t x11code;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/* Special key modifiers */
|
||||
|
||||
static const struct vnc_keymap_s g_modifiers[] =
|
||||
{
|
||||
{MOD_SHIFT, XK_Shift_L},
|
||||
{MOD_SHIFT, XK_Shift_R},
|
||||
{MOD_CONTROL, XK_Control_L},
|
||||
{MOD_CONTROL, XK_Control_R},
|
||||
{MOD_ALT, XK_Alt_L},
|
||||
{MOD_ALT, XK_Alt_R},
|
||||
{MOD_CAPSLOCK, XK_Caps_Lock},
|
||||
{MOD_SHIFTLOCK, XK_Shift_Lock},
|
||||
#ifdef CONFIG_VNCSERVER_KBDENCODE
|
||||
{MOD_SCROLLLOCK, XK_Scroll_Lock},
|
||||
{MOD_NUMLOCK, XK_Num_Lock},
|
||||
#endif
|
||||
};
|
||||
|
||||
#define G_MODIFIERS_NELEM (sizeof(g_modifiers) / sizeof(struct vnc_keymap_s))
|
||||
|
||||
/* Map special mappings for X11 codes to ASCII characters */
|
||||
|
||||
static const struct vnc_keymap_s g_asciimap[] =
|
||||
{
|
||||
/* Control characters */
|
||||
|
||||
#ifdef CONFIG_VNCSERVER_KBDENCODE
|
||||
{ASCII_BS, XK_BackSpace},
|
||||
#endif
|
||||
{ASCII_TAB, XK_Tab},
|
||||
{ASCII_LF, XK_Linefeed},
|
||||
{ASCII_CR, XK_Return},
|
||||
{ASCII_ESC, XK_Escape},
|
||||
#ifdef CONFIG_VNCSERVER_KBDENCODE
|
||||
{ASCII_DEL, XK_Delete},
|
||||
#endif
|
||||
|
||||
/* Alternative encodings */
|
||||
|
||||
{'`', XK_dead_grave},
|
||||
{'<EFBFBD>', XK_dead_acute},
|
||||
{ASCII_TILDE, XK_dead_tilde},
|
||||
{ASCII_CARET, XK_dead_circumflex},
|
||||
|
||||
/* Keypad aliases */
|
||||
|
||||
{ASCII_0, XK_KP_0},
|
||||
{ASCII_1, XK_KP_1},
|
||||
{ASCII_2, XK_KP_2},
|
||||
{ASCII_3, XK_KP_3},
|
||||
{ASCII_4, XK_KP_4},
|
||||
{ASCII_5, XK_KP_5},
|
||||
{ASCII_6, XK_KP_6},
|
||||
{ASCII_7, XK_KP_7},
|
||||
{ASCII_8, XK_KP_8},
|
||||
{ASCII_9, XK_KP_9},
|
||||
{ASCII_ASTERISK, XK_KP_Multiply},
|
||||
{ASCII_PLUS, XK_KP_Add},
|
||||
{ASCII_COMMA, XK_KP_Separator},
|
||||
{ASCII_HYPHEN, XK_KP_Subtract},
|
||||
{ASCII_PERIOD, XK_KP_Decimal},
|
||||
{ASCII_DIVIDE, XK_KP_Divide},
|
||||
{ASCII_SPACE, XK_KP_Space},
|
||||
{ASCII_TAB, XK_KP_Tab},
|
||||
{ASCII_CR, XK_KP_Enter},
|
||||
#ifdef CONFIG_VNCSERVER_KBDENCODE
|
||||
{ASCII_DEL, XK_KP_Delete},
|
||||
#endif
|
||||
};
|
||||
|
||||
#define G_ASCIIMAP_NELEM (sizeof(g_asciimap) / sizeof(struct vnc_keymap_s))
|
||||
|
||||
#ifdef CONFIG_VNCSERVER_KBDENCODE
|
||||
static const struct vnc_keymap_s g_cursor[] =
|
||||
{
|
||||
{KEYCODE_BACKDEL, XK_BackSpace},
|
||||
{KEYCODE_FWDDEL, XK_Delete},
|
||||
{KEYCODE_FWDDEL, XK_KP_Delete},
|
||||
{KEYCODE_HOME, XK_Home},
|
||||
{KEYCODE_HOME, XK_KP_Home},
|
||||
{KEYCODE_END, XK_End},
|
||||
{KEYCODE_END, XK_KP_End},
|
||||
{KEYCODE_LEFT, XK_Left},
|
||||
{KEYCODE_LEFT, XK_KP_Left},
|
||||
{KEYCODE_RIGHT, XK_Right},
|
||||
{KEYCODE_RIGHT, XK_KP_Right},
|
||||
{KEYCODE_UP, XK_Up},
|
||||
{KEYCODE_UP, XK_KP_Up},
|
||||
{KEYCODE_DOWN, XK_Down},
|
||||
{KEYCODE_DOWN, XK_KP_Down},
|
||||
{KEYCODE_PAGEUP, XK_Page_Up},
|
||||
{KEYCODE_PAGEUP, XK_KP_Prior},
|
||||
{KEYCODE_PAGEUP, XK_KP_Page_Up},
|
||||
{KEYCODE_PAGEDOWN, XK_Page_Down},
|
||||
{KEYCODE_PAGEDOWN, XK_KP_Next},
|
||||
{KEYCODE_PAGEDOWN, XK_KP_Page_Down},
|
||||
{KEYCODE_INSERT, XK_Insert},
|
||||
{KEYCODE_INSERT, XK_KP_Insert},
|
||||
{KEYCODE_SELECT, XK_Select},
|
||||
{KEYCODE_EXECUTE, XK_Execute},
|
||||
{KEYCODE_HELP, XK_Help},
|
||||
{KEYCODE_MENU, XK_Alt_L},
|
||||
{KEYCODE_MENU, XK_Alt_R},
|
||||
{KEYCODE_PAUSE, XK_Pause},
|
||||
{KEYCODE_PRTSCRN, XK_Print},
|
||||
{KEYCODE_CLEAR, XK_Clear},
|
||||
{MOD_SCROLLLOCK, XK_Scroll_Lock},
|
||||
{MOD_NUMLOCK, XK_Num_Lock},
|
||||
{KEYCODE_F1, XK_KP_F1},
|
||||
{KEYCODE_F1, XK_F1},
|
||||
{KEYCODE_F2, XK_KP_F2},
|
||||
{KEYCODE_F2, XK_F2},
|
||||
{KEYCODE_F3, XK_KP_F3},
|
||||
{KEYCODE_F3, XK_F3},
|
||||
{KEYCODE_F4, XK_KP_F4},
|
||||
{KEYCODE_F4, XK_F4},
|
||||
{KEYCODE_F5, XK_F5},
|
||||
{KEYCODE_F6, XK_F6},
|
||||
{KEYCODE_F7, XK_F7},
|
||||
{KEYCODE_F8, XK_F8},
|
||||
{KEYCODE_F9, XK_F9},
|
||||
{KEYCODE_F10, XK_F10},
|
||||
{KEYCODE_F11, XK_F11},
|
||||
{KEYCODE_F12, XK_F12},
|
||||
{KEYCODE_F13, XK_F13},
|
||||
{KEYCODE_F14, XK_F14},
|
||||
{KEYCODE_F15, XK_F15},
|
||||
{KEYCODE_F16, XK_F16},
|
||||
{KEYCODE_F17, XK_F17},
|
||||
{KEYCODE_F18, XK_F18},
|
||||
{KEYCODE_F19, XK_F19},
|
||||
{KEYCODE_F20, XK_F20},
|
||||
{KEYCODE_F21, XK_F21},
|
||||
{KEYCODE_F22, XK_F22},
|
||||
{KEYCODE_F23, XK_F23},
|
||||
{KEYCODE_F24, XK_F24},
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Changes the case of a character. Based on US keyboard layout */
|
||||
|
||||
static const uint8_t g_caseswap[NPRTCHARS] =
|
||||
{
|
||||
ASCII_SPACE, ASCII_1, ASCII_RSQUOTE, ASCII_3, /* ! " # */
|
||||
ASCII_4, ASCII_5, ASCII_7, ASCII_QUOTE, /* $ % & ' */
|
||||
ASCII_9, ASCII_0, ASCII_8, ASCII_EQUAL, /* ( ) * + */
|
||||
ASCII_LT, ASCII_UNDERSCORE, ASCII_GT, ASCII_QUESTION, /* , - . / */
|
||||
ASCII_RPAREN, ASCII_EXCLAM, ASCII_AT, ASCII_NUMBER, /* 0 1 2 3 */
|
||||
ASCII_DOLLAR, ASCII_PERCENT, ASCII_CIRCUMFLEX, ASCII_AMPERSAND, /* 4 5 6 7 */
|
||||
ASCII_ASTERISK, ASCII_LPAREN, ASCII_SEMICOLON, ASCII_COLON, /* 8 9 : ; */
|
||||
ASCII_COMMA, ASCII_PLUS, ASCII_PERIOD, ASCII_SLASH, /* < = > ? */
|
||||
ASCII_2, ASCII_a, ASCII_b, ASCII_c, /* @ A B C */
|
||||
ASCII_d, ASCII_e, ASCII_f, ASCII_g, /* D E F G */
|
||||
ASCII_h, ASCII_i, ASCII_j, ASCII_k, /* H I J K */
|
||||
ASCII_l, ASCII_m, ASCII_n, ASCII_o, /* L M N O */
|
||||
ASCII_p, ASCII_q, ASCII_r, ASCII_s, /* P Q R S */
|
||||
ASCII_t, ASCII_u, ASCII_v, ASCII_v, /* T U V W */
|
||||
ASCII_x, ASCII_y, ASCII_z, ASCII_LBRACE, /* X Y Z [ */
|
||||
ASCII_VERTBAR, ASCII_RBRACE, ASCII_6, ASCII_HYPHEN, /* \ ] ^ _ */
|
||||
ASCII_TILDE, ASCII_A, ASCII_B, ASCII_C, /* ' a b c */
|
||||
ASCII_D, ASCII_E, ASCII_F, ASCII_G, /* c e f g */
|
||||
ASCII_H, ASCII_I, ASCII_J, ASCII_K, /* h i j k */
|
||||
ASCII_L, ASCII_M, ASCII_N, ASCII_O, /* l m n o */
|
||||
ASCII_P, ASCII_Q, ASCII_R, ASCII_S, /* p q r s */
|
||||
ASCII_T, ASCII_U, ASCII_V, ASCII_W, /* t u v w */
|
||||
ASCII_X, ASCII_Y, ASCII_Z, ASCII_LBRACKET, /* x y z { */
|
||||
ASCII_BACKSLASH, ASCII_RBRACKET, ASCII_RSQUOTE, /* | } ~ */
|
||||
};
|
||||
|
||||
/* State of each modifier */
|
||||
|
||||
static bool g_modstate[NMODIFIERS];
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_kbd_encode
|
||||
*
|
||||
* Description:
|
||||
* Encode one escape sequence command into the proivded buffer.
|
||||
*
|
||||
* Input Parameters:
|
||||
* buffer - The location to write the sequence
|
||||
* keycode - The command to be added to the output stream.
|
||||
* terminator - Escape sequence terminating character.
|
||||
*
|
||||
* Returned Value:
|
||||
* Number of bytes written
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_VNCSERVER_KBDENCODE
|
||||
static inline int vnc_kbd_encode(FAR uint8_t *buffer, uint8_t keycode,
|
||||
uint8_t terminator)
|
||||
{
|
||||
*buffer++ = ASCII_ESC;
|
||||
*buffer++ = ASCII_LBRACKET;
|
||||
*buffer++ = keycode;
|
||||
*buffer = terminator;
|
||||
return 4;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_kbd_press
|
||||
*
|
||||
* Description:
|
||||
* Indicates a normal key press event. Put one byte of normal keyboard
|
||||
* data into the user provided buffer.
|
||||
*
|
||||
* Input Parameters:
|
||||
* buffer - The location to write the sequence
|
||||
* ch - The character to be added to the output stream.
|
||||
*
|
||||
* Returned Value:
|
||||
* Number of bytes written
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_VNCSERVER_KBDENCODE
|
||||
static inline void vnc_kbd_press(FAR uint8_t *buffer, uint8_t ch)
|
||||
{
|
||||
*buffer = ch;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_kbd_release
|
||||
*
|
||||
* Description:
|
||||
* Encode the release of a normal key.
|
||||
*
|
||||
* Input Parameters:
|
||||
* buffer - The location to write the sequence
|
||||
* ch - The character associated with the key that was releared.
|
||||
*
|
||||
* Returned Value:
|
||||
* Number of bytes written
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_VNCSERVER_KBDENCODE
|
||||
static inline void vnc_kbd_release(FAR uint8_t *buffer, uint8_t ch)
|
||||
{
|
||||
return vnc_kbd_encode(buffer, ch, ('a' + KBD_RELEASE));
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_kbd_specpress
|
||||
*
|
||||
* Description:
|
||||
* Denotes a special key press event. Put one special keyboard command
|
||||
* into the user provided buffer.
|
||||
*
|
||||
* Input Parameters:
|
||||
* buffer - The location to write the sequence
|
||||
* keycode - The command to be added to the output stream.
|
||||
*
|
||||
* Returned Value:
|
||||
* Number of bytes written
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_VNCSERVER_KBDENCODE
|
||||
static inline void vnc_kbd_specpress(FAR uint8_t *buffer, uint8_t keycode)
|
||||
{
|
||||
return vnc_kbd_encode(buffer, keycode, stream, ('a' + KBD_SPECPRESS));
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_kbd_specrel
|
||||
*
|
||||
* Description:
|
||||
* Denotes a special key release event. Put one special keyboard
|
||||
* command into the user provided buffer.
|
||||
*
|
||||
* Input Parameters:
|
||||
* buffer - The location to write the sequence
|
||||
* keycode - The command to be added to the output stream.
|
||||
*
|
||||
* Returned Value:
|
||||
* Number of bytes written
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_VNCSERVER_KBDENCODE
|
||||
static inline void vnc_kbd_specrel(FAR uint8_t *buffer, uint8_t keycode)
|
||||
{
|
||||
return vnc_kbd_encode(buffer, keycode, stream, ('a' + KBD_SPECREL));
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_kbd_lookup
|
||||
*
|
||||
* Description:
|
||||
* Attempt to map the X11 keycode by searching in a lookup table.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int vnc_kbd_lookup(FAR const struct vnc_keymap_s *table,
|
||||
unsigned int nelem, uint16_t keysym)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* First just try to map the virtual keycode using our lookup-table */
|
||||
|
||||
for (i = 0; i < nelem; i++)
|
||||
{
|
||||
if (table[i].x11code == keysym)
|
||||
{
|
||||
/* We have a match */
|
||||
|
||||
return (int)table[i].nxcode;
|
||||
}
|
||||
}
|
||||
|
||||
/* No match */
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_kbd_ascii
|
||||
*
|
||||
* Description:
|
||||
* Attempt to map the X11 keycode into the corresponding ASCII code.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int vnc_kbd_ascii(uint16_t keysym)
|
||||
{
|
||||
/* ISO/IEC 8859-1 Latin1 matches C ASCII in this range: */
|
||||
|
||||
#ifdef CONFIG_VNCSERVER_KBDENCODE
|
||||
if (keysym >= ASCII_SPACE && keysym < ASCII_DEL)
|
||||
#else
|
||||
if (keysym >= ASCII_SPACE && keysym <= ASCII_DEL)
|
||||
#endif
|
||||
{
|
||||
return (int)keysym;
|
||||
}
|
||||
|
||||
/* Perform a lookup to handler some special cases */
|
||||
|
||||
return vnc_kbd_lookup(g_asciimap, G_ASCIIMAP_NELEM, keysym);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_key_map
|
||||
*
|
||||
* Description:
|
||||
* Map the receive X11 keysym into something understood by NuttX and route
|
||||
* that through NX to the appropriate window.
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - An instance of the session structure allocated by
|
||||
* vnc_create_session().
|
||||
* keysym - The X11 keysym value (see include/nuttx/inputx11_keysymdef)
|
||||
* keydown - True: Key pressed; False: Key released
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void vnc_key_map(FAR struct vnc_session_s *session, uint16_t keysym,
|
||||
bool keydown)
|
||||
{
|
||||
#ifdef CONFIG_VNCSERVER_KBDENCODE
|
||||
uint8_t buffer[4]
|
||||
int nch;
|
||||
#else
|
||||
uint8_t buffer;
|
||||
#endif
|
||||
int16_t keych;
|
||||
|
||||
/* Check for modifier keys */
|
||||
|
||||
keych = vnc_kbd_lookup(g_modifiers, G_MODIFIERS_NELEM, keysym);
|
||||
if (keych >= 0)
|
||||
{
|
||||
g_modstate[keych] = keydown;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_VNCSERVER_KBDENCODE
|
||||
/* If we are not encoding key presses, then we have to ignore key release
|
||||
* events.
|
||||
*/
|
||||
|
||||
if (!keydown)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If no external keyboard input handler has been provided,
|
||||
* then we have to drop the keyboard input.
|
||||
*/
|
||||
|
||||
if (session->kbdout == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Try to convert the keycode to an ASCII value */
|
||||
|
||||
keych = vnc_kbd_ascii((char)(keysym & 255));
|
||||
if (keych >= 0)
|
||||
{
|
||||
/* It is a simple ASCII-mappable LATIN1 character. Now we need
|
||||
* to apply any modifiers.
|
||||
*/
|
||||
|
||||
if (g_modstate[MOD_CONTROL])
|
||||
{
|
||||
/* Make into a control character */
|
||||
|
||||
keych &= 0x1f;
|
||||
}
|
||||
|
||||
/* Other modifiers apply only to printable characters */
|
||||
|
||||
else if (ISPRINTABLE(keych))
|
||||
{
|
||||
/* If Shift Lock is selected, then the case of all printable
|
||||
* characters should be reversed (unless the Shift key is also
|
||||
* pressed)
|
||||
*/
|
||||
|
||||
if (g_modstate[MOD_SHIFTLOCK])
|
||||
{
|
||||
if (g_modstate[MOD_SHIFT])
|
||||
{
|
||||
/* Swap case */
|
||||
|
||||
keych = g_caseswap[keych];
|
||||
}
|
||||
}
|
||||
|
||||
/* If Caps Lock is selected, then the case of alphabetic
|
||||
* characters should be reversed (unless the Shift key is also
|
||||
* pressed)
|
||||
*/
|
||||
|
||||
else if (g_modstate[MOD_CAPSLOCK] && ISALPHABETIC(keych))
|
||||
{
|
||||
if (g_modstate[MOD_SHIFT])
|
||||
{
|
||||
/* Swap case */
|
||||
|
||||
keych = g_caseswap[keych];
|
||||
}
|
||||
}
|
||||
|
||||
/* If (1) only the Shift Key is pressed or (2) the Shift key is
|
||||
* pressed with Caps Lock, but the character is not alphabetic,
|
||||
* then the case of all printable characters should be reversed.
|
||||
*/
|
||||
|
||||
else if (g_modstate[MOD_SHIFT])
|
||||
{
|
||||
keych = g_caseswap[keych];
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VNCSERVER_KBDENCODE
|
||||
/* Encode the normal character */
|
||||
|
||||
if (keydown)
|
||||
{
|
||||
nch = vnc_kbd_press(buffer, keych);
|
||||
}
|
||||
else
|
||||
{
|
||||
nch = vnc_kbd_release(buffer, keych);
|
||||
}
|
||||
|
||||
/* Inject the normal character sequence into NX */
|
||||
|
||||
session->kbdout(session->arg, nch, buffer);
|
||||
#else
|
||||
/* Inject the single key press into NX */
|
||||
|
||||
buffer = (uint8_t)keych;
|
||||
session->kbdout(session->arg, 1, &buffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Not mappable to an ASCII LATIN1 character */
|
||||
|
||||
#ifdef CONFIG_VNCSERVER_KBDENCODE
|
||||
else
|
||||
{
|
||||
/* Lookup cursor movement/screen control keysyms */
|
||||
|
||||
keych = vnc_kbd_lookup(g_modifiers, G_MODIFIERS_NELEM, keysym);
|
||||
if (keych >= 0)
|
||||
{
|
||||
/* Encode the speical character */
|
||||
|
||||
if (keydown)
|
||||
{
|
||||
nch = vnc_kbd_specpress(buffer, keych);
|
||||
}
|
||||
else
|
||||
{
|
||||
nch = vnc_kbd_specrel(buffer, keych);
|
||||
}
|
||||
|
||||
/* Inject the special character sequence into NX */
|
||||
|
||||
session->kbdout(session->arg, nch, buffer);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1,521 +0,0 @@
|
||||
/****************************************************************************
|
||||
* graphics/vnc/server/vnc_negotiate.c
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#if defined(CONFIG_VNCSERVER_DEBUG) && !defined(CONFIG_DEBUG_GRAPHICS)
|
||||
# undef CONFIG_DEBUG_ERROR
|
||||
# undef CONFIG_DEBUG_WARN
|
||||
# undef CONFIG_DEBUG_INFO
|
||||
# undef CONFIG_DEBUG_GRAPHICS_ERROR
|
||||
# undef CONFIG_DEBUG_GRAPHICS_WARN
|
||||
# undef CONFIG_DEBUG_GRAPHICS_INFO
|
||||
# define CONFIG_DEBUG_ERROR 1
|
||||
# define CONFIG_DEBUG_WARN 1
|
||||
# define CONFIG_DEBUG_INFO 1
|
||||
# define CONFIG_DEBUG_GRAPHICS 1
|
||||
# define CONFIG_DEBUG_GRAPHICS_ERROR 1
|
||||
# define CONFIG_DEBUG_GRAPHICS_WARN 1
|
||||
# define CONFIG_DEBUG_GRAPHICS_INFO 1
|
||||
#endif
|
||||
#include <debug.h>
|
||||
|
||||
#ifdef CONFIG_NET_SOCKOPTS
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include <nuttx/video/fb.h>
|
||||
#include <nuttx/video/rfb.h>
|
||||
|
||||
#include "vnc_server.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(CONFIG_VNCSERVER_PROTO3p3)
|
||||
static const char g_vncproto[] = RFB_PROTOCOL_VERSION_3p3;
|
||||
#elif defined(CONFIG_VNCSERVER_PROTO3p8)
|
||||
static const char g_vncproto[] = RFB_PROTOCOL_VERSION_3p8;
|
||||
static const char g_nosecurity[] = "No security types are supported";
|
||||
#endif
|
||||
static const char g_vncname[] = CONFIG_VNCSERVER_NAME;
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_negotiate
|
||||
*
|
||||
* Description:
|
||||
* Perform the VNC initialization sequence after the client has successfully
|
||||
* connected to the server. Negotiate security, framebuffer and color
|
||||
* properties.
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - An instance of the session structure.
|
||||
*
|
||||
* Returned Value:
|
||||
* Returns zero (OK) on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int vnc_negotiate(FAR struct vnc_session_s *session)
|
||||
{
|
||||
#ifdef CONFIG_VNCSERVER_PROTO3p3
|
||||
FAR struct rfb_sectype_s *sectype;
|
||||
#else /* ifdef CONFIG_VNCSERVER_PROTO3p8 */
|
||||
FAR struct rfb_supported_sectypes_s *sectypes;
|
||||
FAR struct rfb_selected_sectype_s *sectype;
|
||||
FAR struct rfb_sectype_result_s *secresult;
|
||||
FAR struct rfb_sectype_fail_s *secfail;
|
||||
#endif
|
||||
FAR struct rfb_serverinit_s *serverinit;
|
||||
FAR struct rfb_pixelfmt_s *pixelfmt;
|
||||
FAR struct rfb_setpixelformat_s *setformat;
|
||||
FAR struct rfb_setencodings_s *encodings;
|
||||
ssize_t nsent;
|
||||
ssize_t nrecvd;
|
||||
size_t len;
|
||||
|
||||
#ifdef CONFIG_NET_SOCKOPTS
|
||||
struct timeval tv;
|
||||
int ret;
|
||||
|
||||
/* Set a receive timeout so that we don't hang if the client does not
|
||||
* respond according to RFB 3.3 protocol.
|
||||
*/
|
||||
|
||||
tv.tv_sec = 5;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
ret = psock_setsockopt(&session->connect, SOL_SOCKET, SO_RCVTIMEO,
|
||||
&tv, sizeof(struct timeval));
|
||||
if (ret < 0)
|
||||
{
|
||||
gerr("ERROR: Failed to set receive timeout: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Inform the client of the VNC protocol version */
|
||||
|
||||
ginfo("Send protocol version: %s\n", g_vncproto);
|
||||
|
||||
len = strlen(g_vncproto);
|
||||
nsent = psock_send(&session->connect, g_vncproto, len, 0);
|
||||
if (nsent < 0)
|
||||
{
|
||||
gerr("ERROR: Send ProtocolVersion failed: %d\n", (int)nsent);
|
||||
return (int)nsent;
|
||||
}
|
||||
|
||||
DEBUGASSERT(nsent == len);
|
||||
|
||||
/* Receive the echo of the protocol string */
|
||||
|
||||
ginfo("Receive echo from VNC client\n");
|
||||
|
||||
nrecvd = psock_recv(&session->connect, session->inbuf, len, 0);
|
||||
if (nrecvd < 0)
|
||||
{
|
||||
gerr("ERROR: Receive protocol confirmation failed: %d\n", (int)nrecvd);
|
||||
return (int)nrecvd;
|
||||
}
|
||||
else if (nrecvd == 0)
|
||||
{
|
||||
gwarn("WARNING: Connection closed\n");
|
||||
return -ECONNABORTED;
|
||||
}
|
||||
|
||||
DEBUGASSERT(nrecvd == len);
|
||||
|
||||
#ifdef CONFIG_VNCSERVER_PROTO3p3
|
||||
/* Version 3.3: The server decides the security type and sends a single
|
||||
* word containing the security type: Tell the client that we won't use
|
||||
* any stinkin' security.
|
||||
*/
|
||||
|
||||
ginfo("Send SecurityType\n");
|
||||
|
||||
sectype = (FAR struct rfb_sectype_s *)session->outbuf;
|
||||
rfb_putbe32(sectype->type, RFB_SECTYPE_NONE);
|
||||
|
||||
nsent = psock_send(&session->connect, sectype,
|
||||
sizeof(struct rfb_sectype_s), 0);
|
||||
if (nsent < 0)
|
||||
{
|
||||
gerr("ERROR: Send Security failed: %d\n", (int)nsent);
|
||||
return (int)nsent;
|
||||
}
|
||||
|
||||
DEBUGASSERT(nsent == sizeof(struct rfb_sectype_s));
|
||||
|
||||
#else /* ifdef CONFIG_VNCSERVER_PROTO3p8 */
|
||||
/* Version 3.8: Offer the client a choice of security -- where None is the
|
||||
* only option offered.
|
||||
*/
|
||||
|
||||
ginfo("Send SupportedSecurityTypes\n");
|
||||
|
||||
sectypes = (FAR struct rfb_supported_sectypes_s *)session->outbuf;
|
||||
sectypes->ntypes = 1;
|
||||
sectypes->type[0] = RFB_SECTYPE_NONE;
|
||||
|
||||
nsent = psock_send(&session->connect, sectypes,
|
||||
SIZEOF_RFB_SUPPORTED_SECTYPES_S(1), 0);
|
||||
if (nsent < 0)
|
||||
{
|
||||
gerr("ERROR: Send SupportedSecurityTypes failed: %d\n", (int)nsent);
|
||||
return (int)nsent;
|
||||
}
|
||||
|
||||
DEBUGASSERT(nsent == SIZEOF_RFB_SUPPORTED_SECTYPES_S(1));
|
||||
|
||||
/* If the server listed at least one valid security type supported by the
|
||||
* client, the client sends back a single byte indicating which security
|
||||
* type is to be used on the connection.
|
||||
*/
|
||||
|
||||
ginfo("Receive SecurityType\n");
|
||||
|
||||
sectype = (FAR struct rfb_selected_sectype_s *)session->inbuf;
|
||||
|
||||
nrecvd = psock_recv(&session->connect, sectype,
|
||||
sizeof(struct rfb_selected_sectype_s), 0);
|
||||
if (nrecvd < 0)
|
||||
{
|
||||
gerr("ERROR: Receive SecurityType failed: %d\n", (int)nrecvd);
|
||||
return (int)nrecvd;
|
||||
}
|
||||
else if (nrecvd == 0)
|
||||
{
|
||||
gwarn("WARNING: Connection closed\n");
|
||||
return -ECONNABORTED;
|
||||
}
|
||||
|
||||
DEBUGASSERT(nrecvd == sizeof(struct rfb_selected_sectype_s));
|
||||
|
||||
ginfo("Send SecurityResult\n");
|
||||
|
||||
secresult = (FAR struct rfb_sectype_result_s *)session->outbuf;
|
||||
|
||||
if (sectype->type != RFB_SECTYPE_NONE)
|
||||
{
|
||||
gerr("ERROR: Received unsupported SecurityType: %d\n", sectype->type);
|
||||
|
||||
/* REVISIT: Should send the reason string here */
|
||||
|
||||
rfb_putbe32(secresult->result, RFB_SECTYPE_FAIL);
|
||||
|
||||
nsent = psock_send(&session->connect, secresult,
|
||||
sizeof(struct rfb_sectype_result_s), 0);
|
||||
if (nsent < 0)
|
||||
{
|
||||
gerr("ERROR: Send SecurityResult failed: %d\n", (int)nsent);
|
||||
return (int)nsent;
|
||||
}
|
||||
|
||||
DEBUGASSERT(nsent == sizeof(struct rfb_sectype_result_s));
|
||||
|
||||
ginfo("Send failure reason\n");
|
||||
|
||||
secfail = (FAR struct rfb_sectype_fail_s *)session->outbuf;
|
||||
len = strlen(g_nosecurity);
|
||||
rfb_putbe32(secfail->len, len);
|
||||
memcpy(secfail->str, g_nosecurity, len);
|
||||
|
||||
nsent = psock_send(&session->connect, secfail,
|
||||
SIZEOF_RFB_SECTYPE_FAIL_S(len), 0);
|
||||
if (nsent < 0)
|
||||
{
|
||||
gerr("ERROR: Send failure reason failed: %d\n", (int)nsent);
|
||||
return (int)nsent;
|
||||
}
|
||||
|
||||
DEBUGASSERT(nsent == SIZEOF_RFB_SECTYPE_FAIL_S(len));
|
||||
return -EPROTONOSUPPORT;
|
||||
}
|
||||
|
||||
rfb_putbe32(secresult->result, RFB_SECTYPE_SUCCESS);
|
||||
|
||||
nsent = psock_send(&session->connect, secresult,
|
||||
sizeof(struct rfb_sectype_result_s), 0);
|
||||
if (nsent < 0)
|
||||
{
|
||||
gerr("ERROR: Send SecurityResult failed: %d\n", (int)nsent);
|
||||
return (int)nsent;
|
||||
}
|
||||
|
||||
DEBUGASSERT(nsent == sizeof(struct rfb_sectype_result_s));
|
||||
#endif
|
||||
|
||||
/* Receive the ClientInit message
|
||||
*
|
||||
* "Once the client and server are sure that they’re happy to talk to one
|
||||
* another using the agreed security type, the protocol passes to the
|
||||
* initialization phase. The client sends a ClientInit message followed
|
||||
* by the server sending a ServerInit message."
|
||||
*
|
||||
* In this implementation, the sharing flag is ignored.
|
||||
*/
|
||||
|
||||
ginfo("Receive ClientInit\n");
|
||||
|
||||
nrecvd = psock_recv(&session->connect, session->inbuf,
|
||||
sizeof(struct rfb_clientinit_s), 0);
|
||||
if (nrecvd < 0)
|
||||
{
|
||||
gerr("ERROR: Receive ClientInit failed: %d\n", (int)nrecvd);
|
||||
return (int)nrecvd;
|
||||
}
|
||||
else if (nrecvd == 0)
|
||||
{
|
||||
gwarn("WARNING: Connection closed\n");
|
||||
return -ECONNABORTED;
|
||||
}
|
||||
|
||||
DEBUGASSERT(nrecvd == sizeof(struct rfb_clientinit_s));
|
||||
|
||||
/* Send the ServerInit message
|
||||
*
|
||||
* "After receiving the ClientInit message, the server sends a ServerInit
|
||||
* message. This tells the client the width and height of the server’s
|
||||
* framebuffer, its pixel format and the name associated with the
|
||||
* desktop:"
|
||||
*
|
||||
* RealVNC client supports this resolutions:
|
||||
* Full (all available colors) - Max resolution of the platform
|
||||
* (TrueColor)
|
||||
* Medium (256 colors) - 256 colors (Paletted)
|
||||
* Low (64 colors) - RGB8 2:2:2 (default, TrueColor)
|
||||
* Very Low (8 colors) - RGB3 1:1:1 (TrueColor)
|
||||
*/
|
||||
|
||||
ginfo("Send ServerInit\n");
|
||||
|
||||
serverinit = (FAR struct rfb_serverinit_s *)session->outbuf;
|
||||
|
||||
rfb_putbe16(serverinit->width, CONFIG_VNCSERVER_SCREENWIDTH);
|
||||
rfb_putbe16(serverinit->height, CONFIG_VNCSERVER_SCREENHEIGHT);
|
||||
|
||||
pixelfmt = &serverinit->format;
|
||||
|
||||
pixelfmt->bpp = RFB_BITSPERPIXEL;
|
||||
pixelfmt->depth = RFB_PIXELDEPTH;
|
||||
pixelfmt->bigendian = 0;
|
||||
pixelfmt->truecolor = RFB_TRUECOLOR;
|
||||
|
||||
rfb_putbe16(pixelfmt->rmax, RFB_RMAX);
|
||||
rfb_putbe16(pixelfmt->gmax, RFB_GMAX);
|
||||
rfb_putbe16(pixelfmt->bmax, RFB_BMAX);
|
||||
|
||||
pixelfmt->rshift = RFB_RSHIFT;
|
||||
pixelfmt->gshift = RFB_GSHIFT;
|
||||
pixelfmt->bshift = RFB_BSHIFT;
|
||||
|
||||
len = strlen(g_vncname);
|
||||
rfb_putbe32(serverinit->namelen, len);
|
||||
memcpy(serverinit->name, g_vncname, len);
|
||||
|
||||
nsent = psock_send(&session->connect, serverinit,
|
||||
SIZEOF_RFB_SERVERINIT_S(len), 0);
|
||||
if (nsent < 0)
|
||||
{
|
||||
gerr("ERROR: Send ServerInit failed: %d\n", (int)nsent);
|
||||
return (int)nsent;
|
||||
}
|
||||
|
||||
DEBUGASSERT(nsent == SIZEOF_RFB_SERVERINIT_S(len));
|
||||
|
||||
/* We now expect to receive the SetPixelFormat message from the client.
|
||||
* This may override some of our framebuffer settings.
|
||||
*/
|
||||
|
||||
ginfo("Receive SetPixelFormat\n");
|
||||
|
||||
setformat = (FAR struct rfb_setpixelformat_s *)session->inbuf;
|
||||
|
||||
nrecvd = psock_recv(&session->connect, setformat,
|
||||
sizeof(struct rfb_setpixelformat_s), 0);
|
||||
if (nrecvd < 0)
|
||||
{
|
||||
gerr("ERROR: Receive SetPixelFormat failed: %d\n", (int)nrecvd);
|
||||
return (int)nrecvd;
|
||||
}
|
||||
else if (nrecvd == 0)
|
||||
{
|
||||
gwarn("WARNING: Connection closed\n");
|
||||
return -ECONNABORTED;
|
||||
}
|
||||
else if (nrecvd != sizeof(struct rfb_setpixelformat_s))
|
||||
{
|
||||
/* Must not be a SetPixelFormat message? */
|
||||
|
||||
gerr("ERROR: SetFormat wrong size: %d\n", (int)nrecvd);
|
||||
return -EPROTO;
|
||||
}
|
||||
else if (setformat->msgtype != RFB_SETPIXELFMT_MSG)
|
||||
{
|
||||
gerr("ERROR: Not a SetPixelFormat message: %d\n",
|
||||
(int)setformat->msgtype);
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
/* Instantiate the client pixel format, verifying that the client request
|
||||
* format is one that we can handle.
|
||||
*/
|
||||
|
||||
ret = vnc_client_pixelformat(session, &setformat->format);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* We do not support this pixel format */
|
||||
|
||||
gerr("ERROR: PixelFormat not supported\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Receive supported encoding types from client. */
|
||||
|
||||
ginfo("Receive encoding types\n");
|
||||
|
||||
encodings = (FAR struct rfb_setencodings_s *)session->inbuf;
|
||||
|
||||
nrecvd = psock_recv(&session->connect, encodings,
|
||||
CONFIG_VNCSERVER_INBUFFER_SIZE, 0);
|
||||
if (nrecvd < 0)
|
||||
{
|
||||
gerr("ERROR: Receive SetEncodings failed: %d\n", (int)nrecvd);
|
||||
return (int)nrecvd;
|
||||
}
|
||||
else if (nrecvd == 0)
|
||||
{
|
||||
gwarn("WARNING: Connection closed\n");
|
||||
return -ECONNABORTED;
|
||||
}
|
||||
|
||||
if (encodings->msgtype == RFB_SETENCODINGS_MSG)
|
||||
{
|
||||
DEBUGASSERT(nrecvd >= SIZEOF_RFB_SETENCODINGS_S(0));
|
||||
|
||||
/* Pick out any mutually supported encodings */
|
||||
|
||||
ret = vnc_client_encodings(session, encodings);
|
||||
if (ret < 0)
|
||||
{
|
||||
gerr("ERROR: vnc_set_encodings failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
session->state = VNCSERVER_CONFIGURED;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_client_pixelformat
|
||||
*
|
||||
* Description:
|
||||
* A Client-to-Sever SetPixelFormat message has been received. We need to
|
||||
* immediately switch the output color format that we generate.
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - An instance of the session structure.
|
||||
* pixelfmt - The pixel from the received SetPixelFormat message
|
||||
*
|
||||
* Returned Value:
|
||||
* Returns zero (OK) on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int vnc_client_pixelformat(FAR struct vnc_session_s *session,
|
||||
FAR struct rfb_pixelfmt_s *pixelfmt)
|
||||
{
|
||||
if (pixelfmt->truecolor == 0)
|
||||
{
|
||||
/* At present, we support only TrueColor formats */
|
||||
|
||||
gerr("ERROR: No support for palette colors\n");
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
if (pixelfmt->bpp == 8 && pixelfmt->depth == 6)
|
||||
{
|
||||
ginfo("Client pixel format: RGB8 2:2:2\n");
|
||||
session->colorfmt = FB_FMT_RGB8_222;
|
||||
session->bpp = 8;
|
||||
session->bigendian = false;
|
||||
}
|
||||
else if (pixelfmt->bpp == 8 && pixelfmt->depth == 8)
|
||||
{
|
||||
ginfo("Client pixel format: RGB8 3:3:2\n");
|
||||
session->colorfmt = FB_FMT_RGB8_332;
|
||||
session->bpp = 8;
|
||||
session->bigendian = false;
|
||||
}
|
||||
else if (pixelfmt->bpp == 16 && pixelfmt->depth == 15)
|
||||
{
|
||||
ginfo("Client pixel format: RGB16 5:5:5\n");
|
||||
session->colorfmt = FB_FMT_RGB16_555;
|
||||
session->bpp = 16;
|
||||
session->bigendian = (pixelfmt->bigendian != 0) ? true : false;
|
||||
}
|
||||
else if (pixelfmt->bpp == 16 && pixelfmt->depth == 16)
|
||||
{
|
||||
ginfo("Client pixel format: RGB16 5:6:5\n");
|
||||
session->colorfmt = FB_FMT_RGB16_565;
|
||||
session->bpp = 16;
|
||||
session->bigendian = (pixelfmt->bigendian != 0) ? true : false;
|
||||
}
|
||||
else if (pixelfmt->bpp == 32 && pixelfmt->depth == 24)
|
||||
{
|
||||
ginfo("Client pixel format: RGB32 8:8:8\n");
|
||||
session->colorfmt = FB_FMT_RGB32;
|
||||
session->bpp = 32;
|
||||
session->bigendian = (pixelfmt->bigendian != 0) ? true : false;
|
||||
}
|
||||
else if (pixelfmt->bpp == 32 && pixelfmt->depth == 32)
|
||||
{
|
||||
session->colorfmt = FB_FMT_RGB32;
|
||||
session->bpp = 32;
|
||||
session->bigendian = (pixelfmt->bigendian != 0) ? true : false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We do not support any other conversions */
|
||||
|
||||
gerr("ERROR: No support for this BPP=%d and depth=%d\n",
|
||||
pixelfmt->bpp, pixelfmt->depth);
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
session->change = true;
|
||||
return OK;
|
||||
}
|
||||
@@ -1,500 +0,0 @@
|
||||
/****************************************************************************
|
||||
* graphics/vnc/server/vnc_raw.c
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if defined(CONFIG_VNCSERVER_DEBUG) && !defined(CONFIG_DEBUG_GRAPHICS)
|
||||
# undef CONFIG_DEBUG_ERROR
|
||||
# undef CONFIG_DEBUG_WARN
|
||||
# undef CONFIG_DEBUG_INFO
|
||||
# undef CONFIG_DEBUG_GRAPHICS_ERROR
|
||||
# undef CONFIG_DEBUG_GRAPHICS_WARN
|
||||
# undef CONFIG_DEBUG_GRAPHICS_INFO
|
||||
# define CONFIG_DEBUG_ERROR 1
|
||||
# define CONFIG_DEBUG_WARN 1
|
||||
# define CONFIG_DEBUG_INFO 1
|
||||
# define CONFIG_DEBUG_GRAPHICS 1
|
||||
# define CONFIG_DEBUG_GRAPHICS_ERROR 1
|
||||
# define CONFIG_DEBUG_GRAPHICS_WARN 1
|
||||
# define CONFIG_DEBUG_GRAPHICS_INFO 1
|
||||
#endif
|
||||
#include <debug.h>
|
||||
|
||||
#include "vnc_server.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_copy8
|
||||
*
|
||||
* Description:
|
||||
* Copy a 16/32-bit pixels from the source rectangle to a 8-bit pixel
|
||||
* destination rectangle.
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - A reference to the VNC session structure.
|
||||
* row,col - The upper left X/Y (pixel/row) position of the rectangle
|
||||
* width,height - The width (pixels) and height (rows of the rectangle)
|
||||
* convert - The function to use to convert from the local framebuffer
|
||||
* color format to the remote framebuffer color format.
|
||||
*
|
||||
* Returned Value:
|
||||
* The size of the transfer in bytes.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static size_t vnc_copy8(FAR struct vnc_session_s *session,
|
||||
fb_coord_t row, fb_coord_t col,
|
||||
fb_coord_t height, fb_coord_t width,
|
||||
vnc_convert8_t convert)
|
||||
{
|
||||
FAR struct rfb_framebufferupdate_s *update;
|
||||
FAR const lfb_color_t *srcleft;
|
||||
FAR const lfb_color_t *src;
|
||||
FAR uint8_t *dest;
|
||||
fb_coord_t x;
|
||||
fb_coord_t y;
|
||||
|
||||
/* Destination rectangle start address */
|
||||
|
||||
update = (FAR struct rfb_framebufferupdate_s *)session->outbuf;
|
||||
dest = (FAR uint8_t *)update->rect[0].data;
|
||||
|
||||
/* Source rectangle start address (left/top) */
|
||||
|
||||
srcleft = (FAR lfb_color_t *)
|
||||
(session->fb + RFB_STRIDE * row + RFB_BYTESPERPIXEL * col);
|
||||
|
||||
/* Transfer each row from the source buffer into the update buffer */
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
src = srcleft;
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
*dest++ = convert(*src);
|
||||
src++;
|
||||
}
|
||||
|
||||
srcleft = (FAR lfb_color_t *)((uintptr_t)srcleft + RFB_STRIDE);
|
||||
}
|
||||
|
||||
return (size_t)((uintptr_t)dest - (uintptr_t)update->rect[0].data);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_copy16
|
||||
*
|
||||
* Description:
|
||||
* Copy a 16/32-bit pixels from the source rectangle to a 16-bit pixel
|
||||
* destination rectangle.
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - A reference to the VNC session structure.
|
||||
* row,col - The upper left X/Y (pixel/row) position of the rectangle
|
||||
* width,height - The width (pixels) and height (rows of the rectangle)
|
||||
* convert - The function to use to convert from the local framebuffer
|
||||
* color format to the remote framebuffer color format.
|
||||
*
|
||||
* Returned Value:
|
||||
* The size of the transfer in bytes.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static size_t vnc_copy16(FAR struct vnc_session_s *session,
|
||||
fb_coord_t row, fb_coord_t col,
|
||||
fb_coord_t height, fb_coord_t width,
|
||||
vnc_convert16_t convert)
|
||||
{
|
||||
FAR struct rfb_framebufferupdate_s *update;
|
||||
FAR const lfb_color_t *srcleft;
|
||||
FAR const lfb_color_t *src;
|
||||
FAR uint8_t *dest;
|
||||
uint16_t pixel;
|
||||
fb_coord_t x;
|
||||
fb_coord_t y;
|
||||
bool bigendian;
|
||||
|
||||
/* Destination rectangle start address */
|
||||
|
||||
update = (FAR struct rfb_framebufferupdate_s *)session->outbuf;
|
||||
dest = (FAR uint8_t *)update->rect[0].data;
|
||||
|
||||
/* Source rectangle start address (left/top) */
|
||||
|
||||
srcleft = (FAR lfb_color_t *)
|
||||
(session->fb + RFB_STRIDE * row + RFB_BYTESPERPIXEL * col);
|
||||
|
||||
/* Transfer each row from the source buffer into the update buffer */
|
||||
|
||||
bigendian = session->bigendian;
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
src = srcleft;
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
pixel = convert(*src);
|
||||
|
||||
if (bigendian)
|
||||
{
|
||||
rfb_putbe16(dest, pixel);
|
||||
}
|
||||
else
|
||||
{
|
||||
rfb_putle16(dest, pixel);
|
||||
}
|
||||
|
||||
dest += sizeof(uint16_t);
|
||||
src++;
|
||||
}
|
||||
|
||||
srcleft = (FAR lfb_color_t *)((uintptr_t)srcleft + RFB_STRIDE);
|
||||
}
|
||||
|
||||
return (size_t)((uintptr_t)dest - (uintptr_t)update->rect[0].data);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_copy32
|
||||
*
|
||||
* Description:
|
||||
* Copy a 16/32-bit pixels from the source rectangle to a 32-bit pixel
|
||||
* destination rectangle.
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - A reference to the VNC session structure.
|
||||
* row,col - The upper left X/Y (pixel/row) position of the rectangle
|
||||
* width,height - The width (pixels) and height (rows of the rectangle)
|
||||
* convert - The function to use to convert from the local framebuffer
|
||||
* color format to the remote framebuffer color format.
|
||||
*
|
||||
* Returned Value:
|
||||
* The size of the transfer in bytes.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static size_t vnc_copy32(FAR struct vnc_session_s *session,
|
||||
fb_coord_t row, fb_coord_t col,
|
||||
fb_coord_t height, fb_coord_t width,
|
||||
vnc_convert32_t convert)
|
||||
{
|
||||
FAR struct rfb_framebufferupdate_s *update;
|
||||
FAR const lfb_color_t *srcleft;
|
||||
FAR const lfb_color_t *src;
|
||||
FAR uint8_t *dest;
|
||||
fb_coord_t x;
|
||||
fb_coord_t y;
|
||||
uint32_t pixel;
|
||||
bool bigendian;
|
||||
|
||||
/* Destination rectangle start address */
|
||||
|
||||
update = (FAR struct rfb_framebufferupdate_s *)session->outbuf;
|
||||
dest = (FAR uint8_t *)update->rect[0].data;
|
||||
|
||||
/* Source rectangle start address (left/top) */
|
||||
|
||||
srcleft = (FAR lfb_color_t *)
|
||||
(session->fb + RFB_STRIDE * row + RFB_BYTESPERPIXEL * col);
|
||||
|
||||
/* Transfer each row from the source buffer into the update buffer */
|
||||
|
||||
bigendian = session->bigendian;
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
src = srcleft;
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
pixel = convert(*src);
|
||||
|
||||
if (bigendian)
|
||||
{
|
||||
rfb_putbe32(dest, pixel);
|
||||
}
|
||||
else
|
||||
{
|
||||
rfb_putle32(dest, pixel);
|
||||
}
|
||||
|
||||
dest += sizeof(uint32_t);
|
||||
src++;
|
||||
}
|
||||
|
||||
srcleft = (FAR lfb_color_t *)((uintptr_t)srcleft + RFB_STRIDE);
|
||||
}
|
||||
|
||||
return (size_t)((uintptr_t)dest - (uintptr_t)update->rect[0].data);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_raw
|
||||
*
|
||||
* Description:
|
||||
* As a fallback, send the framebuffer update using the RAW encoding which
|
||||
* must be supported by all VNC clients.
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - An instance of the session structure.
|
||||
* rect - Describes the rectangle in the local framebuffer.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; A negated errno value is returned on failure that
|
||||
* indicates the nature of the failure. A failure is only returned
|
||||
* in cases of a network failure and unexpected internal failures.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int vnc_raw(FAR struct vnc_session_s *session, FAR struct fb_area_s *rect)
|
||||
{
|
||||
FAR struct rfb_framebufferupdate_s *update;
|
||||
FAR const uint8_t *src;
|
||||
fb_coord_t srcwidth;
|
||||
fb_coord_t srcheight;
|
||||
fb_coord_t destwidth;
|
||||
fb_coord_t destheight;
|
||||
fb_coord_t deststride;
|
||||
fb_coord_t updwidth;
|
||||
fb_coord_t updheight;
|
||||
fb_coord_t width;
|
||||
fb_coord_t x;
|
||||
fb_coord_t y;
|
||||
unsigned int bytesperpixel;
|
||||
unsigned int maxwidth;
|
||||
size_t size;
|
||||
ssize_t nsent;
|
||||
uint8_t colorfmt;
|
||||
|
||||
union
|
||||
{
|
||||
vnc_convert8_t bpp8;
|
||||
vnc_convert16_t bpp16;
|
||||
vnc_convert32_t bpp32;
|
||||
} convert;
|
||||
|
||||
/* Set up characteristics of the client pixel format to use on this
|
||||
* update. These can change at any time if a SetPixelFormat is
|
||||
* received asynchronously.
|
||||
*/
|
||||
|
||||
bytesperpixel = (session->bpp + 7) >> 3;
|
||||
maxwidth = CONFIG_VNCSERVER_UPDATE_BUFSIZE / bytesperpixel;
|
||||
|
||||
/* Set up the color conversion */
|
||||
|
||||
colorfmt = session->colorfmt;
|
||||
switch (colorfmt)
|
||||
{
|
||||
case FB_FMT_RGB8_222:
|
||||
convert.bpp8 = vnc_convert_rgb8_222;
|
||||
break;
|
||||
|
||||
case FB_FMT_RGB8_332:
|
||||
convert.bpp8 = vnc_convert_rgb8_332;
|
||||
break;
|
||||
|
||||
case FB_FMT_RGB16_555:
|
||||
convert.bpp16 = vnc_convert_rgb16_555;
|
||||
break;
|
||||
|
||||
case FB_FMT_RGB16_565:
|
||||
convert.bpp16 = vnc_convert_rgb16_565;
|
||||
break;
|
||||
|
||||
case FB_FMT_RGB32:
|
||||
convert.bpp32 = vnc_convert_rgb32_888;
|
||||
break;
|
||||
|
||||
default:
|
||||
gerr("ERROR: Unrecognized color format: %d\n", session->colorfmt);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Get with width and height of the source and destination rectangles.
|
||||
* The source rectangle many be larger than the destination rectangle.
|
||||
* In that case, we will have to emit multiple rectangles.
|
||||
*/
|
||||
|
||||
srcwidth = rect->w;
|
||||
srcheight = rect->h;
|
||||
|
||||
deststride = srcwidth * bytesperpixel;
|
||||
if (deststride > maxwidth)
|
||||
{
|
||||
deststride = maxwidth;
|
||||
}
|
||||
|
||||
DEBUGASSERT(CONFIG_VNCSERVER_UPDATE_BUFSIZE >
|
||||
SIZEOF_RFB_FRAMEBUFFERUPDATE_S(SIZEOF_RFB_RECTANGE_S(0)));
|
||||
|
||||
destwidth = deststride / bytesperpixel;
|
||||
|
||||
/* Reserve some space for message header */
|
||||
|
||||
destheight = (CONFIG_VNCSERVER_UPDATE_BUFSIZE -
|
||||
SIZEOF_RFB_FRAMEBUFFERUPDATE_S(SIZEOF_RFB_RECTANGE_S(0))) /
|
||||
deststride;
|
||||
|
||||
if (destheight > srcheight)
|
||||
{
|
||||
destheight = srcheight;
|
||||
}
|
||||
|
||||
/* Format the rectangle header. We may have to send several update
|
||||
* messages if the pre-allocated outbuf is smaller than the rectangle.
|
||||
* Each update contains a small "sub-rectangle" of the origin update.
|
||||
*
|
||||
* Loop until all sub-rectangles have been output. Start with the
|
||||
* top row and transfer rectangles horizontally across each swath.
|
||||
* The height of the swath is destwidth (the last may be shorter).
|
||||
*
|
||||
* NOTE that the loop also terminates of the color format changes
|
||||
* asynchronously.
|
||||
*/
|
||||
|
||||
for (y = rect->y;
|
||||
srcheight > 0 && colorfmt == session->colorfmt;
|
||||
srcheight -= updheight, y += updheight)
|
||||
{
|
||||
/* updheight = Height to update on this pass through the loop.
|
||||
* This will be destheight unless fewer than that number of rows
|
||||
* remain.
|
||||
*/
|
||||
|
||||
updheight = destheight;
|
||||
if (updheight > srcheight)
|
||||
{
|
||||
updheight = srcheight;
|
||||
}
|
||||
|
||||
/* Loop until this horizontal swath has been sent to the VNC client.
|
||||
* Start with the leftmost pixel and transfer rectangles
|
||||
* horizontally with width of destwidth until all srcwidth
|
||||
* columns have been transferred (the last rectangle may be
|
||||
* narrower).
|
||||
*
|
||||
* NOTE that the loop also terminates of the color format
|
||||
* changes asynchronously.
|
||||
*/
|
||||
|
||||
for (width = srcwidth, x = rect->x;
|
||||
width > 0 && colorfmt == session->colorfmt;
|
||||
width -= updwidth, x += updwidth)
|
||||
{
|
||||
/* updwidth = Width to update on this pass through the loop.
|
||||
* This will be destwidth unless fewer than that number of
|
||||
* columns remain.
|
||||
*/
|
||||
|
||||
updwidth = destwidth;
|
||||
if (updwidth > width)
|
||||
{
|
||||
updwidth = width;
|
||||
}
|
||||
|
||||
/* Transfer the frame buffer data into the rectangle,
|
||||
* performing the necessary color conversions.
|
||||
*/
|
||||
|
||||
if (bytesperpixel == 1)
|
||||
{
|
||||
size = vnc_copy8(session, y, x, updheight, updwidth,
|
||||
convert.bpp8);
|
||||
}
|
||||
else if (bytesperpixel == 2)
|
||||
{
|
||||
size = vnc_copy16(session, y, x, updheight, updwidth,
|
||||
convert.bpp16);
|
||||
}
|
||||
else /* bytesperpixel == 4 */
|
||||
{
|
||||
size = vnc_copy32(session, y, x, updheight, updwidth,
|
||||
convert.bpp32);
|
||||
}
|
||||
|
||||
/* Format the FramebufferUpdate message */
|
||||
|
||||
update = (FAR struct rfb_framebufferupdate_s *)session->outbuf;
|
||||
|
||||
update->msgtype = RFB_FBUPDATE_MSG;
|
||||
update->padding = 0;
|
||||
rfb_putbe16(update->nrect, 1);
|
||||
|
||||
rfb_putbe16(update->rect[0].xpos, x);
|
||||
rfb_putbe16(update->rect[0].ypos, y);
|
||||
rfb_putbe16(update->rect[0].width, updwidth);
|
||||
rfb_putbe16(update->rect[0].height, updheight);
|
||||
rfb_putbe32(update->rect[0].encoding, RFB_ENCODING_RAW);
|
||||
|
||||
DEBUGASSERT(size <= CONFIG_VNCSERVER_UPDATE_BUFSIZE);
|
||||
|
||||
/* We are ready to send the update packet to the VNC client */
|
||||
|
||||
size += SIZEOF_RFB_FRAMEBUFFERUPDATE_S(SIZEOF_RFB_RECTANGE_S(0));
|
||||
src = session->outbuf;
|
||||
|
||||
/* At the very last most, make certain that the color format
|
||||
* has not changed asynchronously.
|
||||
*/
|
||||
|
||||
if (colorfmt == session->colorfmt)
|
||||
{
|
||||
/* Okay send until all of the bytes are out. This may
|
||||
* loop for the case where TCP write buffering is enabled
|
||||
* and there are a limited number of IOBs available.
|
||||
*/
|
||||
|
||||
do
|
||||
{
|
||||
nsent = psock_send(&session->connect, src, size, 0);
|
||||
if (nsent < 0)
|
||||
{
|
||||
gerr("ERROR: Send FrameBufferUpdate failed: %d\n",
|
||||
(int)nsent);
|
||||
return (int)nsent;
|
||||
}
|
||||
|
||||
DEBUGASSERT(nsent <= size);
|
||||
src += nsent;
|
||||
size -= nsent;
|
||||
}
|
||||
while (size > 0);
|
||||
|
||||
updinfo("Sent {(%d, %d),(%d, %d)}\n",
|
||||
x, y, x + updwidth -1, y + updheight - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
@@ -1,478 +0,0 @@
|
||||
/****************************************************************************
|
||||
* graphics/vnc/server/vnc_receiver.c
|
||||
*
|
||||
* 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 <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if defined(CONFIG_VNCSERVER_DEBUG) && !defined(CONFIG_DEBUG_GRAPHICS)
|
||||
# undef CONFIG_DEBUG_ERROR
|
||||
# undef CONFIG_DEBUG_WARN
|
||||
# undef CONFIG_DEBUG_INFO
|
||||
# undef CONFIG_DEBUG_GRAPHICS_ERROR
|
||||
# undef CONFIG_DEBUG_GRAPHICS_WARN
|
||||
# undef CONFIG_DEBUG_GRAPHICS_INFO
|
||||
# define CONFIG_DEBUG_ERROR 1
|
||||
# define CONFIG_DEBUG_WARN 1
|
||||
# define CONFIG_DEBUG_INFO 1
|
||||
# define CONFIG_DEBUG_GRAPHICS 1
|
||||
# define CONFIG_DEBUG_GRAPHICS_ERROR 1
|
||||
# define CONFIG_DEBUG_GRAPHICS_WARN 1
|
||||
# define CONFIG_DEBUG_GRAPHICS_INFO 1
|
||||
#endif
|
||||
#include <debug.h>
|
||||
|
||||
#ifdef CONFIG_NET_SOCKOPTS
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include <nuttx/net/net.h>
|
||||
#include <nuttx/video/rfb.h>
|
||||
#include <nuttx/video/vnc.h>
|
||||
#include <nuttx/input/mouse.h>
|
||||
|
||||
#include "vnc_server.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_read_remainder
|
||||
*
|
||||
* Description:
|
||||
* After receiving the first byte of a client-to-server message, this
|
||||
* reads in the remainder of the message.
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - An instance of the session structure.
|
||||
* msglen - The full length of the message
|
||||
*
|
||||
* Returned Value:
|
||||
* At present, always returns OK
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int vnc_read_remainder(FAR struct vnc_session_s *session, size_t msglen,
|
||||
size_t offset)
|
||||
{
|
||||
ssize_t nrecvd;
|
||||
size_t ntotal;
|
||||
|
||||
/* Loop until the rest of the message is received. */
|
||||
|
||||
for (ntotal = 0; ntotal < msglen; offset += nrecvd, ntotal += nrecvd)
|
||||
{
|
||||
/* Receive more of the message */
|
||||
|
||||
nrecvd = psock_recv(&session->connect, &session->inbuf[offset],
|
||||
msglen - ntotal, 0);
|
||||
if (nrecvd < 0)
|
||||
{
|
||||
gerr("ERROR: Receive message failed: %d\n", (int)nrecvd);
|
||||
return (int)nrecvd;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_receiver
|
||||
*
|
||||
* Description:
|
||||
* This function handles all Client-to-Server messages.
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - An instance of the session structure.
|
||||
*
|
||||
* Returned Value:
|
||||
* At present, always returns OK
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int vnc_receiver(FAR struct vnc_session_s *session)
|
||||
{
|
||||
#ifdef CONFIG_NET_SOCKOPTS
|
||||
struct timeval tv;
|
||||
#endif
|
||||
ssize_t nrecvd;
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(session);
|
||||
ginfo("Receiver running for Display %d\n", session->display);
|
||||
|
||||
#ifdef CONFIG_NET_SOCKOPTS
|
||||
/* Disable the receive timeout so that we will wait indefinitely for the
|
||||
* next Client-to-Server message.
|
||||
*/
|
||||
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
ret = psock_setsockopt(&session->connect, SOL_SOCKET, SO_RCVTIMEO,
|
||||
&tv, sizeof(struct timeval));
|
||||
if (ret < 0)
|
||||
{
|
||||
gerr("ERROR: Failed to disable receive timeout: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Loop until the client disconnects or an unhandled error occurs */
|
||||
|
||||
for (; ; )
|
||||
{
|
||||
/* Set up to read one byte which should be the message type of the
|
||||
* next Client-to-Server message. We will block here until the message
|
||||
* is received.
|
||||
*/
|
||||
|
||||
nrecvd = psock_recv(&session->connect, session->inbuf, 1, 0);
|
||||
if (nrecvd < 0)
|
||||
{
|
||||
gerr("ERROR: Receive byte failed: %d\n", (int)nrecvd);
|
||||
return (int)nrecvd;
|
||||
}
|
||||
|
||||
/* A return value of zero means that the connection was gracefully
|
||||
* closed by the VNC client.
|
||||
*/
|
||||
|
||||
else if (nrecvd == 0)
|
||||
{
|
||||
gwarn("WARNING: Connection closed\n");
|
||||
return OK;
|
||||
}
|
||||
|
||||
DEBUGASSERT(nrecvd == 1);
|
||||
|
||||
/* The single byte received should be the message type. Handle the
|
||||
* message according to this message type.
|
||||
*/
|
||||
|
||||
switch (session->inbuf[0])
|
||||
{
|
||||
case RFB_SETPIXELFMT_MSG: /* SetPixelFormat */
|
||||
{
|
||||
ginfo("Received SetPixelFormat\n");
|
||||
|
||||
/* Read the rest of the SetPixelFormat message */
|
||||
|
||||
ret = vnc_read_remainder(session,
|
||||
sizeof(struct rfb_setpixelformat_s) - 1,
|
||||
1);
|
||||
if (ret < 0)
|
||||
{
|
||||
gerr("ERROR: Failed to read SetPixelFormat message: %d\n",
|
||||
ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
FAR struct rfb_setpixelformat_s *setformat =
|
||||
(FAR struct rfb_setpixelformat_s *)session->inbuf;
|
||||
|
||||
ret = vnc_client_pixelformat(session, &setformat->format);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* We do not support this pixel format */
|
||||
|
||||
/* REVISIT:
|
||||
* We are going to be putting garbage on the RFB
|
||||
*/
|
||||
|
||||
gerr("ERROR: PixelFormat not supported\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RFB_SETENCODINGS_MSG: /* SetEncodings */
|
||||
{
|
||||
FAR struct rfb_setencodings_s *encodings;
|
||||
unsigned int nencodings;
|
||||
|
||||
ginfo("Received SetEncodings\n");
|
||||
|
||||
/* Read the SetEncodings message without the following
|
||||
* encodings.
|
||||
*/
|
||||
|
||||
ret = vnc_read_remainder(session,
|
||||
SIZEOF_RFB_SERVERINIT_S(0) - 1,
|
||||
1);
|
||||
if (ret < 0)
|
||||
{
|
||||
gerr("ERROR: Failed to read SetEncodings message: %d\n",
|
||||
ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Read the following encodings */
|
||||
|
||||
encodings = (FAR struct rfb_setencodings_s *)
|
||||
session->inbuf;
|
||||
|
||||
nencodings = rfb_getbe16(encodings->nencodings);
|
||||
|
||||
ret = vnc_read_remainder(session,
|
||||
nencodings * sizeof(uint32_t),
|
||||
SIZEOF_RFB_SERVERINIT_S(0));
|
||||
if (ret < 0)
|
||||
{
|
||||
gerr("ERROR: Failed to read encodings: %d\n",
|
||||
ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Pick out any mutually supported encodings */
|
||||
|
||||
ret = vnc_client_encodings(session, encodings);
|
||||
if (ret < 0)
|
||||
{
|
||||
gerr("ERROR: vnc_set_encodings failed: %d\n", ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RFB_FBUPDATEREQ_MSG: /* FramebufferUpdateRequest */
|
||||
{
|
||||
FAR struct rfb_fbupdatereq_s *update;
|
||||
struct fb_area_s rect;
|
||||
|
||||
ginfo("Received FramebufferUpdateRequest\n");
|
||||
|
||||
/* Read the rest of the FramebufferUpdateRequest message */
|
||||
|
||||
ret = vnc_read_remainder(session,
|
||||
sizeof(struct rfb_fbupdatereq_s) - 1,
|
||||
1);
|
||||
if (ret < 0)
|
||||
{
|
||||
gerr("ERROR: "
|
||||
"Failed to read FramebufferUpdateRequest message: %d\n",
|
||||
ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Enqueue the update */
|
||||
|
||||
update = (FAR struct rfb_fbupdatereq_s *)session->inbuf;
|
||||
|
||||
rect.x = rfb_getbe16(update->xpos);
|
||||
rect.y = rfb_getbe16(update->ypos);
|
||||
rect.w = rfb_getbe16(update->width);
|
||||
rect.h = rfb_getbe16(update->height);
|
||||
|
||||
ret = vnc_update_rectangle(session, &rect, false);
|
||||
if (ret < 0)
|
||||
{
|
||||
gerr("ERROR: Failed to queue update: %d\n", ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RFB_KEYEVENT_MSG: /* KeyEvent */
|
||||
{
|
||||
FAR struct rfb_keyevent_s *keyevent;
|
||||
|
||||
ginfo("Received KeyEvent\n");
|
||||
|
||||
/* Read the rest of the KeyEvent message */
|
||||
|
||||
ret = vnc_read_remainder(session,
|
||||
sizeof(struct rfb_keyevent_s) - 1,
|
||||
1);
|
||||
if (ret < 0)
|
||||
{
|
||||
gerr("ERROR: Failed to read KeyEvent message: %d\n",
|
||||
ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Inject the key press/release event into NX */
|
||||
|
||||
keyevent = (FAR struct rfb_keyevent_s *)session->inbuf;
|
||||
vnc_key_map(session, rfb_getbe16(keyevent->key),
|
||||
(bool)keyevent->down);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RFB_POINTEREVENT_MSG: /* PointerEvent */
|
||||
{
|
||||
FAR struct rfb_pointerevent_s *event;
|
||||
uint8_t buttons;
|
||||
|
||||
ginfo("Received PointerEvent\n");
|
||||
|
||||
/* Read the rest of the PointerEvent message */
|
||||
|
||||
ret = vnc_read_remainder(session,
|
||||
sizeof(struct rfb_pointerevent_s) - 1,
|
||||
1);
|
||||
if (ret < 0)
|
||||
{
|
||||
gerr("ERROR: Failed to read PointerEvent message: %d\n",
|
||||
ret);
|
||||
}
|
||||
else if (session->mouseout != NULL)
|
||||
{
|
||||
event = (FAR struct rfb_pointerevent_s *)session->inbuf;
|
||||
|
||||
/* Map buttons bitmap. Bits 0-7 are buttons 1-8, 0=up,
|
||||
* 1=down. By convention Bit 0 = left button, Bit 1 =
|
||||
* middle button, and Bit 2 = right button.
|
||||
*/
|
||||
|
||||
buttons = 0;
|
||||
if ((event->buttons & (1 << 0)) != 0)
|
||||
{
|
||||
buttons |= MOUSE_BUTTON_1;
|
||||
}
|
||||
|
||||
if ((event->buttons & (1 << 1)) != 0)
|
||||
{
|
||||
buttons |= MOUSE_BUTTON_2;
|
||||
}
|
||||
|
||||
if ((event->buttons & (1 << 2)) != 0)
|
||||
{
|
||||
buttons |= MOUSE_BUTTON_3;
|
||||
}
|
||||
|
||||
session->mouseout(session->arg,
|
||||
(fb_coord_t)rfb_getbe16(event->xpos),
|
||||
(fb_coord_t)rfb_getbe16(event->ypos),
|
||||
buttons);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RFB_CLIENTCUTTEXT_MSG: /* ClientCutText */
|
||||
{
|
||||
FAR struct rfb_clientcuttext_s *cuttext;
|
||||
uint32_t length;
|
||||
|
||||
ginfo("Received ClientCutText\n");
|
||||
|
||||
/* Read the ClientCutText message without the following
|
||||
* text.
|
||||
*/
|
||||
|
||||
ret = vnc_read_remainder(session,
|
||||
SIZEOF_RFB_CLIENTCUTTEXT_S(0) - 1,
|
||||
1);
|
||||
if (ret < 0)
|
||||
{
|
||||
gerr("ERROR: Failed to read ClientCutText message: %d\n",
|
||||
ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Read the following text */
|
||||
|
||||
cuttext = (FAR struct rfb_clientcuttext_s *)session->inbuf;
|
||||
length = rfb_getbe32(cuttext->length);
|
||||
|
||||
ret = vnc_read_remainder(session, length,
|
||||
SIZEOF_RFB_CLIENTCUTTEXT_S(0));
|
||||
if (ret < 0)
|
||||
{
|
||||
gerr("ERROR: Failed to read text: %d\n",
|
||||
ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* REVISIT: ClientCutText is currently ignored */
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
gerr("ERROR: Unsynchronized, msgtype=%d\n", session->inbuf[0]);
|
||||
return -EPROTO;
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_client_encodings
|
||||
*
|
||||
* Description:
|
||||
* Pick out any mutually supported encodings from the Client-to-Server
|
||||
* SetEncodings message
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - An instance of the session structure.
|
||||
* encodings - The received SetEncodings message
|
||||
*
|
||||
* Returned Value:
|
||||
* At present, always returns OK
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int vnc_client_encodings(FAR struct vnc_session_s *session,
|
||||
FAR struct rfb_setencodings_s *encodings)
|
||||
{
|
||||
uint32_t encoding;
|
||||
unsigned int nencodings;
|
||||
unsigned int i;
|
||||
|
||||
DEBUGASSERT(session != NULL && encodings != NULL);
|
||||
|
||||
/* Assume that there are no common encodings (other than RAW) */
|
||||
|
||||
session->rre = false;
|
||||
|
||||
/* Loop for each client supported encoding */
|
||||
|
||||
nencodings = rfb_getbe16(encodings->nencodings);
|
||||
for (i = 0; i < nencodings; i++)
|
||||
{
|
||||
/* Get the next encoding */
|
||||
|
||||
encoding = rfb_getbe32(&encodings->encodings[i << 2]);
|
||||
|
||||
/* Only a limited support for of RRE is available now. */
|
||||
|
||||
if (encoding == RFB_ENCODING_RRE)
|
||||
{
|
||||
session->rre = true;
|
||||
}
|
||||
}
|
||||
|
||||
session->change = true;
|
||||
return OK;
|
||||
}
|
||||
@@ -1,273 +0,0 @@
|
||||
/****************************************************************************
|
||||
* graphics/vnc/server/vnc_rre.c
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if defined(CONFIG_VNCSERVER_DEBUG) && !defined(CONFIG_DEBUG_GRAPHICS)
|
||||
# undef CONFIG_DEBUG_ERROR
|
||||
# undef CONFIG_DEBUG_WARN
|
||||
# undef CONFIG_DEBUG_INFO
|
||||
# undef CONFIG_DEBUG_GRAPHICS_ERROR
|
||||
# undef CONFIG_DEBUG_GRAPHICS_WARN
|
||||
# undef CONFIG_DEBUG_GRAPHICS_INFO
|
||||
# define CONFIG_DEBUG_ERROR 1
|
||||
# define CONFIG_DEBUG_WARN 1
|
||||
# define CONFIG_DEBUG_INFO 1
|
||||
# define CONFIG_DEBUG_GRAPHICS 1
|
||||
# define CONFIG_DEBUG_GRAPHICS_ERROR 1
|
||||
# define CONFIG_DEBUG_GRAPHICS_WARN 1
|
||||
# define CONFIG_DEBUG_GRAPHICS_INFO 1
|
||||
#endif
|
||||
#include <debug.h>
|
||||
|
||||
#include "vnc_server.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct rre_encode8_s
|
||||
{
|
||||
struct rfb_rrehdr8_s hdr;
|
||||
struct rfb_rrerect8_s rect;
|
||||
};
|
||||
|
||||
struct rre_encode16_s
|
||||
{
|
||||
struct rfb_rrehdr16_s hdr;
|
||||
struct rfb_rrerect16_s rect;
|
||||
};
|
||||
|
||||
struct rre_encode32_s
|
||||
{
|
||||
struct rfb_rrehdr32_s hdr;
|
||||
struct rfb_rrerect32_s rect;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_rreNN
|
||||
*
|
||||
* Description:
|
||||
* Encode a single RRE sub-rectangle, NN=bits-per-pixel
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - An instance of the session structure.
|
||||
* dest - The locate to save the RRE encoded data
|
||||
* rect - Describes the rectangle in the local framebuffer.
|
||||
* bgcolor - The local color of the pixel data
|
||||
*
|
||||
* Returned Value:
|
||||
* The size of the framebuffer update message is returned..
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
ssize_t vnc_rre8(FAR struct vnc_session_s *session,
|
||||
FAR struct rre_encode8_s *dest,
|
||||
FAR struct fb_area_s *rect,
|
||||
uint8_t bgcolor)
|
||||
{
|
||||
rfb_putbe32(dest->hdr.nsubrects, 1);
|
||||
dest->hdr.pixel = bgcolor;
|
||||
dest->rect.pixel = bgcolor;
|
||||
rfb_putbe16(dest->rect.xpos, rect->x);
|
||||
rfb_putbe16(dest->rect.ypos, rect->y);
|
||||
rfb_putbe16(dest->rect.width, rect->w);
|
||||
rfb_putbe16(dest->rect.height, rect->h);
|
||||
|
||||
return sizeof(struct rre_encode8_s);
|
||||
}
|
||||
|
||||
ssize_t vnc_rre16(FAR struct vnc_session_s *session,
|
||||
FAR struct rre_encode16_s *dest,
|
||||
FAR struct fb_area_s *rect,
|
||||
uint16_t bgcolor)
|
||||
{
|
||||
rfb_putbe32(dest->hdr.nsubrects, 1);
|
||||
rfb_putbe16(dest->hdr.pixel, bgcolor);
|
||||
rfb_putbe16(dest->rect.pixel, bgcolor);
|
||||
rfb_putbe16(dest->rect.xpos, rect->x);
|
||||
rfb_putbe16(dest->rect.ypos, rect->y);
|
||||
rfb_putbe16(dest->rect.width, rect->w);
|
||||
rfb_putbe16(dest->rect.height, rect->h);
|
||||
|
||||
return sizeof(struct rre_encode16_s);
|
||||
}
|
||||
|
||||
ssize_t vnc_rre32(FAR struct vnc_session_s *session,
|
||||
FAR struct rre_encode32_s *dest,
|
||||
FAR struct fb_area_s *rect,
|
||||
uint32_t bgcolor)
|
||||
{
|
||||
rfb_putbe32(dest->hdr.nsubrects, 1);
|
||||
rfb_putbe32(dest->hdr.pixel, bgcolor);
|
||||
rfb_putbe32(dest->rect.pixel, bgcolor);
|
||||
rfb_putbe16(dest->rect.xpos, rect->x);
|
||||
rfb_putbe16(dest->rect.ypos, rect->y);
|
||||
rfb_putbe16(dest->rect.width, rect->w);
|
||||
rfb_putbe16(dest->rect.height, rect->h);
|
||||
|
||||
return sizeof(struct rre_encode32_s);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_rre
|
||||
*
|
||||
* Description:
|
||||
* This function does not really do RRE encoding. It just checks if the
|
||||
* update region is one color then uses the RRE encoding format to send
|
||||
* the constant color rectangle.
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - An instance of the session structure.
|
||||
* rect - Describes the rectangle in the local framebuffer.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero is returned if RRE coding was not performed (but no error was
|
||||
* encountered). Otherwise, the size of the framebuffer update message
|
||||
* is returned on success or a negated errno value is returned on failure
|
||||
* that indicates the nature of the failure. A failure is only
|
||||
* returned in cases of a network failure and unexpected internal failures.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int vnc_rre(FAR struct vnc_session_s *session, FAR struct fb_area_s *rect)
|
||||
{
|
||||
FAR struct rfb_framebufferupdate_s *rre;
|
||||
FAR struct rfb_rectangle_s *rrect;
|
||||
lfb_color_t bgcolor;
|
||||
size_t nbytes;
|
||||
ssize_t nsent;
|
||||
int ret;
|
||||
|
||||
/* Check if the client supports the RRE encoding */
|
||||
|
||||
if (session->rre)
|
||||
{
|
||||
/* Check if the update region contains only a single color */
|
||||
|
||||
ret = vnc_colors(session, rect, 1, &bgcolor);
|
||||
if (ret == 1)
|
||||
{
|
||||
/* Format the FrameBuffer Update with a single RRE encoded
|
||||
* rectangle.
|
||||
*/
|
||||
|
||||
rre = (FAR struct rfb_framebufferupdate_s *)session->outbuf;
|
||||
|
||||
rre->msgtype = RFB_FBUPDATE_MSG;
|
||||
rre->padding = 0;
|
||||
rfb_putbe16(rre->nrect, 1);
|
||||
|
||||
rrect = (FAR struct rfb_rectangle_s *)&rre->rect;
|
||||
rfb_putbe16(rrect->xpos, rect->x);
|
||||
rfb_putbe16(rrect->ypos, rect->y);
|
||||
rfb_putbe16(rrect->width, rect->w);
|
||||
rfb_putbe16(rrect->height, rect->h);
|
||||
rfb_putbe32(rrect->encoding, RFB_ENCODING_RRE);
|
||||
|
||||
/* The sub-rectangle encoding depends of the remote pixel width */
|
||||
|
||||
nbytes = SIZEOF_RFB_FRAMEBUFFERUPDATE_S(SIZEOF_RFB_RECTANGE_S(0));
|
||||
|
||||
switch (session->colorfmt)
|
||||
{
|
||||
case FB_FMT_RGB8_222:
|
||||
nbytes += vnc_rre8(session,
|
||||
(FAR struct rre_encode8_s *)rrect->data,
|
||||
rect, vnc_convert_rgb8_222(bgcolor));
|
||||
break;
|
||||
|
||||
case FB_FMT_RGB8_332:
|
||||
nbytes += vnc_rre8(session,
|
||||
(FAR struct rre_encode8_s *)rrect->data,
|
||||
rect, vnc_convert_rgb8_332(bgcolor));
|
||||
break;
|
||||
|
||||
case FB_FMT_RGB16_555:
|
||||
nbytes += vnc_rre16(session,
|
||||
(FAR struct rre_encode16_s *)rrect->data,
|
||||
rect, vnc_convert_rgb16_555(bgcolor));
|
||||
break;
|
||||
|
||||
case FB_FMT_RGB16_565:
|
||||
nbytes += vnc_rre16(session,
|
||||
(FAR struct rre_encode16_s *)rrect->data,
|
||||
rect, vnc_convert_rgb16_565(bgcolor));
|
||||
break;
|
||||
|
||||
case FB_FMT_RGB32:
|
||||
nbytes += vnc_rre32(session,
|
||||
(FAR struct rre_encode32_s *)rrect->data,
|
||||
rect, vnc_convert_rgb32_888(bgcolor));
|
||||
break;
|
||||
|
||||
default:
|
||||
gerr("ERROR: Unrecognized color format: %d\n",
|
||||
session->colorfmt);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* At the very last most, make certain that the supported encoding
|
||||
* has not changed asynchronously.
|
||||
*/
|
||||
|
||||
if (session->rre)
|
||||
{
|
||||
/* Okay send until all of the bytes are out. This may
|
||||
* loop for the case where TCP write buffering is enabled
|
||||
* and there are a limited number of IOBs available.
|
||||
*/
|
||||
|
||||
nsent = psock_send(&session->connect, rre, nbytes, 0);
|
||||
if (nsent < 0)
|
||||
{
|
||||
gerr("ERROR: Send RRE FrameBufferUpdate failed: %d\n",
|
||||
(int)nsent);
|
||||
return (int)nsent;
|
||||
}
|
||||
|
||||
DEBUGASSERT(nsent == nbytes);
|
||||
updinfo("Sent {(%d, %d),(%d, %d)}\n",
|
||||
rect->x, rect->y, rect->w, rect->h);
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,373 +0,0 @@
|
||||
/****************************************************************************
|
||||
* graphics/vnc/server/vnc_server.c
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <queue.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if defined(CONFIG_VNCSERVER_DEBUG) && !defined(CONFIG_DEBUG_GRAPHICS)
|
||||
# undef CONFIG_DEBUG_ERROR
|
||||
# undef CONFIG_DEBUG_WARN
|
||||
# undef CONFIG_DEBUG_INFO
|
||||
# undef CONFIG_DEBUG_GRAPHICS_ERROR
|
||||
# undef CONFIG_DEBUG_GRAPHICS_WARN
|
||||
# undef CONFIG_DEBUG_GRAPHICS_INFO
|
||||
# define CONFIG_DEBUG_ERROR 1
|
||||
# define CONFIG_DEBUG_WARN 1
|
||||
# define CONFIG_DEBUG_INFO 1
|
||||
# define CONFIG_DEBUG_GRAPHICS 1
|
||||
# define CONFIG_DEBUG_GRAPHICS_ERROR 1
|
||||
# define CONFIG_DEBUG_GRAPHICS_WARN 1
|
||||
# define CONFIG_DEBUG_GRAPHICS_INFO 1
|
||||
#endif
|
||||
#include <debug.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/net/net.h>
|
||||
|
||||
#include "vnc_server.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
/* Given a display number as an index, the following array can be used to
|
||||
* look-up the session structure for that display.
|
||||
*/
|
||||
|
||||
FAR struct vnc_session_s *g_vnc_sessions[RFB_MAX_DISPLAYS];
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_reset_session
|
||||
*
|
||||
* Description:
|
||||
* Conclude the current VNC session. This function re-initializes the
|
||||
* session structure; it does not free either the session structure nor
|
||||
* the framebuffer so that they may be re-used.
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - An instance of the session structure.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void vnc_reset_session(FAR struct vnc_session_s *session,
|
||||
FAR uint8_t *fb, int display)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Close any open sockets */
|
||||
|
||||
if (session->state >= VNCSERVER_CONNECTED)
|
||||
{
|
||||
psock_close(&session->connect);
|
||||
psock_close(&session->listen);
|
||||
}
|
||||
|
||||
/* [Re-]initialize the session. */
|
||||
|
||||
memset(&session->connect, 0, sizeof(struct socket));
|
||||
memset(&session->listen, 0, sizeof(struct socket));
|
||||
|
||||
/* Put all of the pre-allocated update structures into the freelist */
|
||||
|
||||
sq_init(&session->updqueue);
|
||||
sq_init(&session->updfree);
|
||||
|
||||
for (i = 0; i < CONFIG_VNCSERVER_NUPDATES; i++)
|
||||
{
|
||||
sq_addlast((FAR sq_entry_t *)&session->updpool[i], &session->updfree);
|
||||
}
|
||||
|
||||
/* Set the INITIALIZED state */
|
||||
|
||||
nxsem_reset(&session->freesem, CONFIG_VNCSERVER_NUPDATES);
|
||||
nxsem_reset(&session->queuesem, 0);
|
||||
|
||||
session->fb = fb;
|
||||
session->display = display;
|
||||
session->state = VNCSERVER_INITIALIZED;
|
||||
session->nwhupd = 0;
|
||||
session->change = true;
|
||||
|
||||
/* Careful not to disturb the keyboard/mouse callouts set by
|
||||
* vnc_fbinitialize(). Client related data left in garbage state.
|
||||
*/
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_connect
|
||||
*
|
||||
* Description:
|
||||
* Wait for a connection from the VNC client
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - An instance of the session structure.
|
||||
* port - The listen port to use
|
||||
*
|
||||
* Returned Value:
|
||||
* Returns zero (OK) on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int vnc_connect(FAR struct vnc_session_s *session, int port)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
int ret;
|
||||
|
||||
ginfo("Connecting display %d\n", session->display);
|
||||
|
||||
/* Create a listening socket */
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
ret = psock_socket(AF_INET, SOCK_STREAM, 0, &session->listen);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Bind the listening socket to a local address */
|
||||
|
||||
ret = psock_bind(&session->listen, (struct sockaddr *)&addr,
|
||||
sizeof(struct sockaddr_in));
|
||||
if (ret < 0)
|
||||
{
|
||||
goto errout_with_listener;
|
||||
}
|
||||
|
||||
/* Listen for a connection */
|
||||
|
||||
ret = psock_listen(&session->listen, 5);
|
||||
if (ret < 0)
|
||||
{
|
||||
goto errout_with_listener;
|
||||
}
|
||||
|
||||
/* Connect to the client */
|
||||
|
||||
ginfo("Accepting connection for Display %d\n", session->display);
|
||||
|
||||
ret = psock_accept(&session->listen, NULL, NULL, &session->connect);
|
||||
if (ret < 0)
|
||||
{
|
||||
goto errout_with_listener;
|
||||
}
|
||||
|
||||
ginfo("Display %d connected\n", session->display);
|
||||
session->state = VNCSERVER_CONNECTED;
|
||||
return OK;
|
||||
|
||||
errout_with_listener:
|
||||
psock_close(&session->listen);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Pubic Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_server
|
||||
*
|
||||
* Description:
|
||||
* The VNC server daemon. This daemon is implemented as a kernel thread.
|
||||
*
|
||||
* Input Parameters:
|
||||
* Standard kernel thread arguments (all ignored)
|
||||
*
|
||||
* Returned Value:
|
||||
* This function does not return.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int vnc_server(int argc, FAR char *argv[])
|
||||
{
|
||||
FAR struct vnc_session_s *session;
|
||||
FAR uint8_t *fb;
|
||||
int display;
|
||||
int ret;
|
||||
|
||||
/* A single argument is expected: A display port number in ASCII form */
|
||||
|
||||
if (argc != 2)
|
||||
{
|
||||
/* In this case the start-up logic will probably hang, waiting for the
|
||||
* display-related semaphore to be set.
|
||||
*/
|
||||
|
||||
gerr("ERROR: Unexpected number of arguments: %d\n", argc);
|
||||
ret = -EINVAL;
|
||||
goto errout_with_hang;
|
||||
}
|
||||
|
||||
display = atoi(argv[1]);
|
||||
if (display < 0 || display >= RFB_MAX_DISPLAYS)
|
||||
{
|
||||
/* In this case the start-up logic will probably hang, waiting for the
|
||||
* display-related semaphore to be set.
|
||||
*/
|
||||
|
||||
gerr("ERROR: Invalid display number: %d\n", display);
|
||||
ret = -EINVAL;
|
||||
goto errout_with_hang;
|
||||
}
|
||||
|
||||
ginfo("Server started for Display %d\n", display);
|
||||
|
||||
/* Allocate the framebuffer memory. We rely on the fact that
|
||||
* the KMM allocator will align memory to 32-bits or better.
|
||||
*/
|
||||
|
||||
fb = (FAR uint8_t *)kmm_zalloc(RFB_SIZE);
|
||||
if (fb == NULL)
|
||||
{
|
||||
gerr("ERROR: Failed to allocate framebuffer memory: %lu KB\n",
|
||||
(unsigned long)(RFB_SIZE / 1024));
|
||||
ret = -ENOMEM;
|
||||
goto errout_with_post;
|
||||
}
|
||||
|
||||
/* Allocate a session structure for this display */
|
||||
|
||||
session = kmm_zalloc(sizeof(struct vnc_session_s));
|
||||
if (session == NULL)
|
||||
{
|
||||
gerr("ERROR: Failed to allocate session\n");
|
||||
ret = -ENOMEM;
|
||||
goto errout_with_fb;
|
||||
}
|
||||
|
||||
g_vnc_sessions[display] = session;
|
||||
nxsem_init(&session->freesem, 0, CONFIG_VNCSERVER_NUPDATES);
|
||||
nxsem_init(&session->queuesem, 0, 0);
|
||||
|
||||
#ifdef CONFIG_FB_SYNC
|
||||
nxsem_init(&session->vsyncsem, 0, 0);
|
||||
nxsem_set_protocol(&session->vsyncsem, SEM_PRIO_NONE);
|
||||
#endif
|
||||
|
||||
/* Inform any waiter that we have started */
|
||||
|
||||
vnc_reset_session(session, fb, display);
|
||||
nxsem_post(&g_fbstartup[display].fbinit);
|
||||
|
||||
/* Loop... handling each each VNC client connection to this display. Only
|
||||
* a single client is allowed for each display.
|
||||
*/
|
||||
|
||||
for (; ; )
|
||||
{
|
||||
/* Release the last session and [Re-]initialize the session structure
|
||||
* for the next connection.
|
||||
*/
|
||||
|
||||
vnc_reset_session(session, fb, display);
|
||||
g_fbstartup[display].result = -EBUSY;
|
||||
nxsem_reset(&g_fbstartup[display].fbconnect, 0);
|
||||
|
||||
/* Establish a connection with the VNC client */
|
||||
|
||||
ret = vnc_connect(session, RFB_DISPLAY_PORT(display));
|
||||
if (ret >= 0)
|
||||
{
|
||||
ginfo("New VNC connection\n");
|
||||
|
||||
/* Perform the VNC initialization sequence after the client has
|
||||
* successfully connected to the server. Negotiate security,
|
||||
* framebuffer and color properties.
|
||||
*/
|
||||
|
||||
ret = vnc_negotiate(session);
|
||||
if (ret < 0)
|
||||
{
|
||||
gerr("ERROR: Failed to negotiate security/framebuffer: %d\n",
|
||||
ret);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Start the VNC updater thread that sends all Server-to-Client
|
||||
* messages.
|
||||
*/
|
||||
|
||||
ret = vnc_start_updater(session);
|
||||
if (ret < 0)
|
||||
{
|
||||
gerr("ERROR: Failed to start updater thread: %d\n", ret);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Let the framebuffer driver know that we are ready to perform
|
||||
* updates.
|
||||
*/
|
||||
|
||||
g_fbstartup[display].result = OK;
|
||||
nxsem_post(&g_fbstartup[display].fbconnect);
|
||||
|
||||
/* Run the VNC receiver on this trhead. The VNC receiver handles
|
||||
* all Client-to-Server messages. The VNC receiver function does
|
||||
* not return until the session has been terminated (or an error
|
||||
* occurs).
|
||||
*/
|
||||
|
||||
ret = vnc_receiver(session);
|
||||
ginfo("Session terminated with %d\n", ret);
|
||||
UNUSED(ret);
|
||||
|
||||
/* Stop the VNC updater thread. */
|
||||
|
||||
ret = vnc_stop_updater(session);
|
||||
if (ret < 0)
|
||||
{
|
||||
gerr("ERROR: Failed to stop updater thread: %d\n", ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
errout_with_fb:
|
||||
kmm_free(fb);
|
||||
|
||||
errout_with_post:
|
||||
g_fbstartup[display].result = ret;
|
||||
nxsem_post(&g_fbstartup[display].fbconnect);
|
||||
|
||||
errout_with_hang:
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
@@ -1,563 +0,0 @@
|
||||
/****************************************************************************
|
||||
* graphics/vnc/server/vnc_server.h
|
||||
*
|
||||
* 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 __GRAPHICS_VNC_SERVER_VNC_SERVER_H
|
||||
#define __GRAPHICS_VNC_SERVER_VNC_SERVER_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <pthread.h>
|
||||
#include <queue.h>
|
||||
|
||||
#include <nuttx/video/fb.h>
|
||||
#include <nuttx/video/rfb.h>
|
||||
#include <nuttx/video/vnc.h>
|
||||
#include <nuttx/net/net.h>
|
||||
#include <nuttx/semaphore.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Configuration */
|
||||
|
||||
#if !defined(CONFIG_VNCSERVER_PROTO3p3) && !defined(CONFIG_VNCSERVER_PROTO3p8)
|
||||
# error No VNC protocol selected
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_VNCSERVER_PROTO3p3) && defined(CONFIG_VNCSERVER_PROTO3p8)
|
||||
# error Too many VNC protocols selected
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_VNCSERVER_NDISPLAYS
|
||||
# define CONFIG_VNCSERVER_NDISPLAYS 1
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_VNCSERVER_COLORFMT_RGB8)
|
||||
# define RFB_COLORFMT FB_FMT_RGB8_332
|
||||
# define RFB_BITSPERPIXEL 8
|
||||
# define RFB_PIXELDEPTH 8
|
||||
# define RFB_TRUECOLOR 1
|
||||
# define RFB_RMAX 0x07
|
||||
# define RFB_GMAX 0x07
|
||||
# define RFB_BMAX 0x03
|
||||
# define RFB_RSHIFT 5
|
||||
# define RFB_GSHIFT 2
|
||||
# define RFB_BSHIFT 0
|
||||
#elif defined(CONFIG_VNCSERVER_COLORFMT_RGB16)
|
||||
# define RFB_COLORFMT FB_FMT_RGB16_565
|
||||
# define RFB_BITSPERPIXEL 16
|
||||
# define RFB_PIXELDEPTH 16
|
||||
# define RFB_TRUECOLOR 1
|
||||
# define RFB_RMAX 0x001f
|
||||
# define RFB_GMAX 0x003f
|
||||
# define RFB_BMAX 0x001f
|
||||
# define RFB_RSHIFT 11
|
||||
# define RFB_GSHIFT 5
|
||||
# define RFB_BSHIFT 0
|
||||
#elif defined(CONFIG_VNCSERVER_COLORFMT_RGB32)
|
||||
# define RFB_COLORFMT FB_FMT_RGB32
|
||||
# define RFB_BITSPERPIXEL 32
|
||||
# define RFB_PIXELDEPTH 24
|
||||
# define RFB_TRUECOLOR 1
|
||||
# define RFB_RMAX 0x000000ff
|
||||
# define RFB_GMAX 0x000000ff
|
||||
# define RFB_BMAX 0x000000ff
|
||||
# define RFB_RSHIFT 16
|
||||
# define RFB_GSHIFT 8
|
||||
# define RFB_BSHIFT 0
|
||||
#else
|
||||
# error Unspecified/unsupported color format
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_VNCSERVER_SCREENWIDTH
|
||||
# define CONFIG_VNCSERVER_SCREENWIDTH 320
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_VNCSERVER_SCREENHEIGHT
|
||||
# define CONFIG_VNCSERVER_SCREENHEIGHT 240
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_VNCSERVER_NAME
|
||||
# define CONFIG_VNCSERVER_NAME "NuttX"
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_VNCSERVER_PRIO
|
||||
# define CONFIG_VNCSERVER_PRIO 100
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_VNCSERVER_STACKSIZE
|
||||
# define CONFIG_VNCSERVER_STACKSIZE 2048
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_VNCSERVER_UPDATER_PRIO
|
||||
# define CONFIG_VNCSERVER_UPDATER_PRIO 100
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_VNCSERVER_UPDATER_STACKSIZE
|
||||
# define CONFIG_VNCSERVER_UPDATER_STACKSIZE 2048
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_VNCSERVER_INBUFFER_SIZE
|
||||
# define CONFIG_VNCSERVER_INBUFFER_SIZE 80
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_VNCSERVER_NUPDATES
|
||||
# define CONFIG_VNCSERVER_NUPDATES 48
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_VNCSERVER_UPDATE_BUFSIZE
|
||||
# define CONFIG_VNCSERVER_UPDATE_BUFSIZE 4096
|
||||
#endif
|
||||
|
||||
#define VNCSERVER_UPDATE_BUFSIZE \
|
||||
(CONFIG_VNCSERVER_UPDATE_BUFSIZE + SIZEOF_RFB_FRAMEBUFFERUPDATE_S(0))
|
||||
|
||||
/* Local framebuffer characteristics in bytes */
|
||||
|
||||
#define RFB_BYTESPERPIXEL ((RFB_BITSPERPIXEL + 7) >> 3)
|
||||
#define RFB_STRIDE (RFB_BYTESPERPIXEL * CONFIG_VNCSERVER_SCREENWIDTH)
|
||||
#define RFB_SIZE (RFB_STRIDE * CONFIG_VNCSERVER_SCREENHEIGHT)
|
||||
|
||||
/* RFB Port Number */
|
||||
|
||||
#define RFB_PORT_BASE 5900
|
||||
#define RFB_MAX_DISPLAYS CONFIG_VNCSERVER_NDISPLAYS
|
||||
#define RFB_DISPLAY_PORT(d) (RFB_PORT_BASE + (d))
|
||||
|
||||
/* Miscellaneous */
|
||||
|
||||
#ifndef MIN
|
||||
# define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
# define MAX(a,b) (((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
/* Debug */
|
||||
|
||||
#ifdef CONFIG_VNCSERVER_UPDATE_DEBUG
|
||||
# define upderr _err
|
||||
# define updwarn _warn
|
||||
# define updinfo _info
|
||||
#else
|
||||
# define upderr _none
|
||||
# define updwarn _none
|
||||
# define updinfo _none
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
/* This enumeration indicates the state of the VNC server */
|
||||
|
||||
enum vnc_server_e
|
||||
{
|
||||
VNCSERVER_UNINITIALIZED = 0, /* Initial state */
|
||||
VNCSERVER_INITIALIZED, /* State structured initialized, but not connected */
|
||||
VNCSERVER_CONNECTED, /* Connect to a client, but not yet configured */
|
||||
VNCSERVER_CONFIGURED, /* Configured and ready to transfer graphics */
|
||||
VNCSERVER_RUNNING, /* Running and actively transferring graphics */
|
||||
VNCSERVER_STOPPING, /* The updater has been asked to stop */
|
||||
VNCSERVER_STOPPED /* The updater has stopped */
|
||||
};
|
||||
|
||||
/* This structure is used to queue FrameBufferUpdate event. It includes a
|
||||
* pointer to support singly linked list.
|
||||
*/
|
||||
|
||||
struct vnc_fbupdate_s
|
||||
{
|
||||
FAR struct vnc_fbupdate_s *flink;
|
||||
bool whupd; /* True: whole screen update */
|
||||
struct fb_area_s rect; /* The enqueued update rectangle */
|
||||
};
|
||||
|
||||
struct vnc_session_s
|
||||
{
|
||||
/* Connection data */
|
||||
|
||||
struct socket listen; /* Listen socket */
|
||||
struct socket connect; /* Connected socket */
|
||||
volatile uint8_t state; /* See enum vnc_server_e */
|
||||
volatile uint8_t nwhupd; /* Number of whole screen updates queued */
|
||||
volatile bool change; /* True: Frambebuffer data change since last whole screen update */
|
||||
|
||||
/* Display geometry and color characteristics */
|
||||
|
||||
uint8_t display; /* Display number (for debug) */
|
||||
volatile uint8_t colorfmt; /* Remote color format (See include/nuttx/fb.h) */
|
||||
volatile uint8_t bpp; /* Remote bits per pixel */
|
||||
volatile bool bigendian; /* True: Remote expect data in big-endian format */
|
||||
volatile bool rre; /* True: Remote supports RRE encoding */
|
||||
FAR uint8_t *fb; /* Allocated local frame buffer */
|
||||
|
||||
/* VNC client input support */
|
||||
|
||||
vnc_kbdout_t kbdout; /* Callout when keyboard input is received */
|
||||
vnc_mouseout_t mouseout; /* Callout when keyboard input is received */
|
||||
FAR void *arg; /* Argument that accompanies the callouts */
|
||||
|
||||
/* Updater information */
|
||||
|
||||
pthread_t updater; /* Updater thread ID */
|
||||
|
||||
/* Update list information */
|
||||
|
||||
struct vnc_fbupdate_s updpool[CONFIG_VNCSERVER_NUPDATES];
|
||||
sq_queue_t updfree;
|
||||
sq_queue_t updqueue;
|
||||
sem_t freesem;
|
||||
sem_t queuesem;
|
||||
#ifdef CONFIG_FB_SYNC
|
||||
sem_t vsyncsem;
|
||||
#endif
|
||||
|
||||
/* I/O buffers for misc network send/receive */
|
||||
|
||||
uint8_t inbuf[CONFIG_VNCSERVER_INBUFFER_SIZE];
|
||||
uint8_t outbuf[VNCSERVER_UPDATE_BUFSIZE];
|
||||
};
|
||||
|
||||
/* This structure is used to communicate start-up status between the server
|
||||
* the framebuffer driver.
|
||||
*/
|
||||
|
||||
struct fb_startup_s
|
||||
{
|
||||
sem_t fbinit; /* Wait for session creation */
|
||||
sem_t fbconnect; /* Wait for client connection */
|
||||
int16_t result; /* OK: successfully initialized */
|
||||
};
|
||||
|
||||
/* The size of the color type in the local framebuffer */
|
||||
|
||||
#if defined(CONFIG_VNCSERVER_COLORFMT_RGB8)
|
||||
typedef uint8_t lfb_color_t;
|
||||
#elif defined(CONFIG_VNCSERVER_COLORFMT_RGB16)
|
||||
typedef uint16_t lfb_color_t;
|
||||
#elif defined(CONFIG_VNCSERVER_COLORFMT_RGB32)
|
||||
typedef uint32_t lfb_color_t;
|
||||
#else
|
||||
# error Unspecified/unsupported color format
|
||||
#endif
|
||||
|
||||
/* Color conversion function pointer types */
|
||||
|
||||
typedef CODE uint8_t (*vnc_convert8_t) (lfb_color_t rgb);
|
||||
typedef CODE uint16_t (*vnc_convert16_t)(lfb_color_t rgb);
|
||||
typedef CODE uint32_t (*vnc_convert32_t)(lfb_color_t rgb);
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/* Given a display number as an index, the following array can be used to
|
||||
* look-up the session structure for that display.
|
||||
*/
|
||||
|
||||
EXTERN FAR struct vnc_session_s *g_vnc_sessions[RFB_MAX_DISPLAYS];
|
||||
|
||||
/* Used to synchronize the server thread with the framebuffer driver. */
|
||||
|
||||
EXTERN struct fb_startup_s g_fbstartup[RFB_MAX_DISPLAYS];
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_server
|
||||
*
|
||||
* Description:
|
||||
* The VNC server daemon. This daemon is implemented as a kernel thread.
|
||||
*
|
||||
* Input Parameters:
|
||||
* Standard kernel thread arguments (all ignored)
|
||||
*
|
||||
* Returned Value:
|
||||
* This function does not return.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int vnc_server(int argc, FAR char *argv[]);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_negotiate
|
||||
*
|
||||
* Description:
|
||||
* Perform the VNC initialization sequence after the client has successfully
|
||||
* connected to the server. Negotiate security, framebuffer and color
|
||||
* properties.
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - An instance of the session structure.
|
||||
*
|
||||
* Returned Value:
|
||||
* Returns zero (OK) on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int vnc_negotiate(FAR struct vnc_session_s *session);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_client_pixelformat
|
||||
*
|
||||
* Description:
|
||||
* A Client-to-Sever SetPixelFormat message has been received. We need to
|
||||
* immediately switch the output color format that we generate.
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - An instance of the session structure.
|
||||
* pixelfmt - The pixel from the received SetPixelFormat message
|
||||
*
|
||||
* Returned Value:
|
||||
* Returns zero (OK) on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int vnc_client_pixelformat(FAR struct vnc_session_s *session,
|
||||
FAR struct rfb_pixelfmt_s *pixelfmt);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_client_encodings
|
||||
*
|
||||
* Description:
|
||||
* Pick out any mutually supported encodings from the Client-to-Server
|
||||
* SetEncodings message
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - An instance of the session structure.
|
||||
* encodings - The received SetEncodings message
|
||||
*
|
||||
* Returned Value:
|
||||
* At present, always returns OK
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int vnc_client_encodings(FAR struct vnc_session_s *session,
|
||||
FAR struct rfb_setencodings_s *encodings);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_start_updater
|
||||
*
|
||||
* Description:
|
||||
* Start the updater thread
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - An instance of the session structure.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success; a negated errno value is returned on
|
||||
* any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int vnc_start_updater(FAR struct vnc_session_s *session);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_stop_updater
|
||||
*
|
||||
* Description:
|
||||
* Stop the updater thread
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - An instance of the session structure.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success; a negated errno value is returned on
|
||||
* any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int vnc_stop_updater(FAR struct vnc_session_s *session);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_update_rectangle
|
||||
*
|
||||
* Description:
|
||||
* Queue an update of the specified rectangular region on the display.
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - An instance of the session structure.
|
||||
* rect - The rectanglular region to be updated.
|
||||
* change - True: Frame buffer data has changed
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success; a negated errno value is returned on
|
||||
* any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int vnc_update_rectangle(FAR struct vnc_session_s *session,
|
||||
FAR const struct fb_area_s *rect,
|
||||
bool change);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_receiver
|
||||
*
|
||||
* Description:
|
||||
* This function handles all Client-to-Server messages.
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - An instance of the session structure.
|
||||
*
|
||||
* Returned Value:
|
||||
* At present, always returns OK
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int vnc_receiver(FAR struct vnc_session_s *session);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_rre
|
||||
*
|
||||
* Description:
|
||||
* This function does not really do RRE encoding. It just checks if the
|
||||
* update region is one color then uses the RRE encoding format to send
|
||||
* the constant color rectangle.
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - An instance of the session structure.
|
||||
* rect - Describes the rectangle in the local framebuffer.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero is returned if RRE coding was not performed (but not error was)
|
||||
* encountered. Otherwise, the size of the framebuffer update message
|
||||
* is returned on success or a negated errno value is returned on failure
|
||||
* that indicates the nature of the failure. A failure is only
|
||||
* returned in cases of a network failure and unexpected internal failures.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int vnc_rre(FAR struct vnc_session_s *session, FAR struct fb_area_s *rect);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_raw
|
||||
*
|
||||
* Description:
|
||||
* As a fallback, send the framebuffer update using the RAW encoding which
|
||||
* must be supported by all VNC clients.
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - An instance of the session structure.
|
||||
* rect - Describes the rectangle in the local framebuffer.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; A negated errno value is returned on failure that
|
||||
* indicates the nature of the failure. A failure is only returned
|
||||
* in cases of a network failure and unexpected internal failures.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int vnc_raw(FAR struct vnc_session_s *session, FAR struct fb_area_s *rect);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_key_map
|
||||
*
|
||||
* Description:
|
||||
* Map the receive X11 keysym into something understood by NuttX and route
|
||||
* that through NX to the appropriate window.
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - An instance of the session structure.
|
||||
* keysym - The X11 keysym value (see include/nuttx/inputx11_keysymdef)
|
||||
* keydown - True: Key pressed; False: Key released
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void vnc_key_map(FAR struct vnc_session_s *session, uint16_t keysym,
|
||||
bool keydown);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_convert_rgbNN
|
||||
*
|
||||
* Description:
|
||||
* Convert the native framebuffer color format (either RGB8 3:3:2,
|
||||
* RGB16 5:6:5, or RGB32 8:8:8) to the remote framebuffer color format
|
||||
* (either RGB8 2:2:2, RGB8 3:3:2, RGB16 5:5:5, RGB16 5:6:5, or RGB32
|
||||
* 8:8:8)
|
||||
*
|
||||
* Input Parameters:
|
||||
* pixel - The src color in local framebuffer format.
|
||||
*
|
||||
* Returned Value:
|
||||
* The pixel in the remote framebuffer color format.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uint8_t vnc_convert_rgb8_222(lfb_color_t rgb);
|
||||
uint8_t vnc_convert_rgb8_332(lfb_color_t rgb);
|
||||
uint16_t vnc_convert_rgb16_555(lfb_color_t rgb);
|
||||
uint16_t vnc_convert_rgb16_565(lfb_color_t rgb);
|
||||
uint32_t vnc_convert_rgb32_888(lfb_color_t rgb);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_colors
|
||||
*
|
||||
* Description:
|
||||
* Test the update rectangle to see if it contains complex colors. If it
|
||||
* contains only a few colors, then it may be a candidate for some type
|
||||
* run-length encoding.
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - An instance of the session structure.
|
||||
* rect - The update region in the local frame buffer.
|
||||
* maxcolors - The maximum number of colors that should be returned. This
|
||||
* currently cannot exceed eight.
|
||||
* colors - The top 'maxcolors' most frequency colors are returned.
|
||||
*
|
||||
* Returned Value:
|
||||
* The number of valid colors in the colors[] array are returned, the
|
||||
* first entry being the most frequent. A negated errno value is returned
|
||||
* if the colors cannot be determined. This would be the case if the color
|
||||
* depth is > 8 and there are more than 'maxcolors' colors in the update
|
||||
* rectangle.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int vnc_colors(FAR struct vnc_session_s *session,
|
||||
FAR struct fb_area_s *rect,
|
||||
unsigned int maxcolors, FAR lfb_color_t *colors);
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __GRAPHICS_VNC_SERVER_VNC_SERVER_H */
|
||||
@@ -1,655 +0,0 @@
|
||||
/****************************************************************************
|
||||
* graphics/vnc/server/vnc_updater.c
|
||||
*
|
||||
* 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 <string.h>
|
||||
#include <sched.h>
|
||||
#include <pthread.h>
|
||||
#include <queue.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if defined(CONFIG_VNCSERVER_DEBUG) && !defined(CONFIG_DEBUG_GRAPHICS)
|
||||
# undef CONFIG_DEBUG_ERROR
|
||||
# undef CONFIG_DEBUG_WARN
|
||||
# undef CONFIG_DEBUG_INFO
|
||||
# undef CONFIG_DEBUG_GRAPHICS_ERROR
|
||||
# undef CONFIG_DEBUG_GRAPHICS_WARN
|
||||
# undef CONFIG_DEBUG_GRAPHICS_INFO
|
||||
# define CONFIG_DEBUG_ERROR 1
|
||||
# define CONFIG_DEBUG_WARN 1
|
||||
# define CONFIG_DEBUG_INFO 1
|
||||
# define CONFIG_DEBUG_GRAPHICS 1
|
||||
# define CONFIG_DEBUG_GRAPHICS_ERROR 1
|
||||
# define CONFIG_DEBUG_GRAPHICS_WARN 1
|
||||
# define CONFIG_DEBUG_GRAPHICS_INFO 1
|
||||
#endif
|
||||
#include <debug.h>
|
||||
|
||||
#include "vnc_server.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#undef VNCSERVER_SEM_DEBUG /* Define to dump queue/semaphore state */
|
||||
#undef VNCSERVER_SEM_DEBUG_SILENT /* Define to dump only suspicious conditions */
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef VNCSERVER_SEM_DEBUG
|
||||
static sem_t g_errsem = SEM_INITIALIZER(1);
|
||||
#endif
|
||||
|
||||
/* A rectangle represent the entire local framebuffer */
|
||||
|
||||
static const struct fb_area_s g_wholescreen =
|
||||
{
|
||||
0, 0, CONFIG_VNCSERVER_SCREENWIDTH, CONFIG_VNCSERVER_SCREENHEIGHT
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_sem_debug
|
||||
*
|
||||
* Description:
|
||||
* Dump information about the freesem to verify that it is sync.
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - A reference to the VNC session structure.
|
||||
*
|
||||
* Returned Value:
|
||||
* A non-NULL structure pointer should always be returned. This function
|
||||
* will wait if no structure is available.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef VNCSERVER_SEM_DEBUG
|
||||
static void vnc_sem_debug(FAR struct vnc_session_s *session,
|
||||
FAR const char *msg, unsigned int unattached)
|
||||
{
|
||||
FAR struct vnc_fbupdate_s *update;
|
||||
int nqueued;
|
||||
int nfree;
|
||||
int freesem;
|
||||
int queuesem;
|
||||
int freecount;
|
||||
int queuecount;
|
||||
int freewaiting;
|
||||
int queuewaiting;
|
||||
int ret;
|
||||
|
||||
ret = nxsem_wait_uninterruptible(&g_errsem);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* Should happen only on task cancellation */
|
||||
|
||||
DEBUGASSERT(ret == -ECANCELED);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Count structures in the list */
|
||||
|
||||
nqueued = sq_count(&session->updqueue);
|
||||
nfree = sq_count(&session->updfree);
|
||||
|
||||
freesem = session->freesem.semcount;
|
||||
queuesem = session->queuesem.semcount;
|
||||
|
||||
freecount = freesem > 0 ? freesem : 0;
|
||||
queuecount = queuesem > 0 ? queuesem : 0;
|
||||
|
||||
freewaiting = freesem < 0 ? -freesem : 0;
|
||||
queuewaiting = queuesem < 0 ? -queuesem : 0;
|
||||
|
||||
#ifdef VNCSERVER_SEM_DEBUG_SILENT
|
||||
/* This dumps most false alarms in the case where:
|
||||
*
|
||||
* - Updater was waiting on a semaphore (count is -1)
|
||||
* - New update added to the queue (queue count is 1)
|
||||
* - queuesem posted. Wakes up Updater and the count is 0.
|
||||
*/
|
||||
|
||||
if ((nqueued + nfree) != (freecount + queuecount))
|
||||
#endif
|
||||
{
|
||||
syslog(LOG_INFO, "FREESEM DEBUG: %s\n", msg);
|
||||
syslog(LOG_INFO, " Free list:\n");
|
||||
syslog(LOG_INFO, " semcount: %d\n", freecount);
|
||||
syslog(LOG_INFO, " queued nodes: %u\n", nfree);
|
||||
syslog(LOG_INFO, " waiting: %u\n", freewaiting);
|
||||
syslog(LOG_INFO, " Qeued Updates:\n");
|
||||
syslog(LOG_INFO, " semcount: %d\n", queuecount);
|
||||
syslog(LOG_INFO, " queued nodes: %u\n", nqueued);
|
||||
syslog(LOG_INFO, " waiting: %u\n", queuewaiting);
|
||||
syslog(LOG_INFO, " Unqueued: %u\n", unattached);
|
||||
}
|
||||
|
||||
nxsem_post(&g_errsem);
|
||||
}
|
||||
#else
|
||||
# define vnc_sem_debug(s,m,u)
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_alloc_update
|
||||
*
|
||||
* Description:
|
||||
* Allocate one update structure by taking it from the freelist.
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - A reference to the VNC session structure.
|
||||
*
|
||||
* Returned Value:
|
||||
* A non-NULL structure pointer should always be returned. This function
|
||||
* will wait if no structure is available.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static FAR struct vnc_fbupdate_s *
|
||||
vnc_alloc_update(FAR struct vnc_session_s *session)
|
||||
{
|
||||
FAR struct vnc_fbupdate_s *update;
|
||||
|
||||
/* Reserve one element from the free list. Lock the scheduler to assure
|
||||
* that the sq_remfirst() and the successful return from nxsem_wait are
|
||||
* atomic. Of course, the scheduler will be unlocked while we wait.
|
||||
*/
|
||||
|
||||
sched_lock();
|
||||
vnc_sem_debug(session, "Before alloc", 0);
|
||||
|
||||
nxsem_wait_uninterruptible(&session->freesem);
|
||||
|
||||
/* It is reserved.. go get it */
|
||||
|
||||
update = (FAR struct vnc_fbupdate_s *)sq_remfirst(&session->updfree);
|
||||
|
||||
vnc_sem_debug(session, "After alloc", 1);
|
||||
sched_unlock();
|
||||
|
||||
DEBUGASSERT(update != NULL);
|
||||
return update;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_free_update
|
||||
*
|
||||
* Description:
|
||||
* Free one update structure by returning it from the freelist.
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - A reference to the VNC session structure.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void vnc_free_update(FAR struct vnc_session_s *session,
|
||||
FAR struct vnc_fbupdate_s *update)
|
||||
{
|
||||
/* Reserve one element from the free list. Lock the scheduler to assure
|
||||
* that the sq_addlast() and the nxsem_post() are atomic.
|
||||
*/
|
||||
|
||||
sched_lock();
|
||||
vnc_sem_debug(session, "Before free", 1);
|
||||
|
||||
/* Put the entry into the free list */
|
||||
|
||||
sq_addlast((FAR sq_entry_t *)update, &session->updfree);
|
||||
|
||||
/* Post the semaphore to indicate the availability of one more update */
|
||||
|
||||
nxsem_post(&session->freesem);
|
||||
|
||||
vnc_sem_debug(session, "After free", 0);
|
||||
DEBUGASSERT(session->freesem.semcount <= CONFIG_VNCSERVER_NUPDATES);
|
||||
|
||||
sched_unlock();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_remove_queue
|
||||
*
|
||||
* Description:
|
||||
* Remove one entry from the list of queued rectangles, waiting if
|
||||
* necessary if the queue is empty.
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - A reference to the VNC session structure.
|
||||
*
|
||||
* Returned Value:
|
||||
* A non-NULL structure pointer should always be returned. This function
|
||||
* will wait if no structure is available.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static FAR struct vnc_fbupdate_s *
|
||||
vnc_remove_queue(FAR struct vnc_session_s *session)
|
||||
{
|
||||
FAR struct vnc_fbupdate_s *rect;
|
||||
|
||||
/* Reserve one element from the list of queued rectangle. Lock the
|
||||
* scheduler to assure that the sq_remfirst() and the successful return
|
||||
* from nxsem_wait are atomic. Of course, the scheduler will be unlocked
|
||||
* while we wait.
|
||||
*/
|
||||
|
||||
sched_lock();
|
||||
vnc_sem_debug(session, "Before remove", 0);
|
||||
|
||||
nxsem_wait_uninterruptible(&session->queuesem);
|
||||
|
||||
/* It is reserved.. go get it */
|
||||
|
||||
rect = (FAR struct vnc_fbupdate_s *)sq_remfirst(&session->updqueue);
|
||||
|
||||
vnc_sem_debug(session, "After remove", 0);
|
||||
DEBUGASSERT(rect != NULL);
|
||||
|
||||
/* Check if we just removed the whole screen update from the queue */
|
||||
|
||||
if (session->nwhupd > 0 && rect->whupd)
|
||||
{
|
||||
session->nwhupd--;
|
||||
updinfo("Whole screen update: nwhupd=%d\n", session->nwhupd);
|
||||
}
|
||||
|
||||
sched_unlock();
|
||||
return rect;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_add_queue
|
||||
*
|
||||
* Description:
|
||||
* Add one rectangle entry to the list of queued rectangles to be updated.
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - A reference to the VNC session structure.
|
||||
* rect - The rectangle to be added to the queue.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void vnc_add_queue(FAR struct vnc_session_s *session,
|
||||
FAR struct vnc_fbupdate_s *rect)
|
||||
{
|
||||
/* Lock the scheduler to assure that the sq_addlast() and the nxsem_post()
|
||||
* are atomic.
|
||||
*/
|
||||
|
||||
sched_lock();
|
||||
vnc_sem_debug(session, "Before add", 1);
|
||||
|
||||
/* Put the entry into the list of queued rectangles. */
|
||||
|
||||
sq_addlast((FAR sq_entry_t *)rect, &session->updqueue);
|
||||
|
||||
/* Post the semaphore to indicate the availability of one more rectangle
|
||||
* in the queue. This may wakeup the updater.
|
||||
*/
|
||||
|
||||
nxsem_post(&session->queuesem);
|
||||
|
||||
vnc_sem_debug(session, "After add", 0);
|
||||
DEBUGASSERT(session->queuesem.semcount <= CONFIG_VNCSERVER_NUPDATES);
|
||||
|
||||
sched_unlock();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_updater
|
||||
*
|
||||
* Description:
|
||||
* This is the "updater" thread. It is the sender of all Server-to-Client
|
||||
* messages
|
||||
*
|
||||
* Input Parameters:
|
||||
* Standard pthread arguments.
|
||||
*
|
||||
* Returned Value:
|
||||
* NULL is always returned.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static FAR void *vnc_updater(FAR void *arg)
|
||||
{
|
||||
FAR struct vnc_session_s *session = (FAR struct vnc_session_s *)arg;
|
||||
FAR struct vnc_fbupdate_s *srcrect;
|
||||
int ret;
|
||||
#ifdef CONFIG_FB_SYNC
|
||||
int val;
|
||||
#endif
|
||||
|
||||
DEBUGASSERT(session != NULL);
|
||||
ginfo("Updater running for Display %d\n", session->display);
|
||||
|
||||
/* Loop, processing updates until we are asked to stop.
|
||||
* REVISIT: Probably need some kind of signal mechanism to wake up
|
||||
* vnc_remove_queue() in order to stop. Or perhaps a special STOP
|
||||
* message in the queue?
|
||||
*/
|
||||
|
||||
while (session->state == VNCSERVER_RUNNING)
|
||||
{
|
||||
/* Get the next queued rectangle update. This call will block until an
|
||||
* update is available for the case where the update queue is empty.
|
||||
*/
|
||||
|
||||
srcrect = vnc_remove_queue(session);
|
||||
DEBUGASSERT(srcrect != NULL);
|
||||
|
||||
updinfo("Dequeued {(%d, %d),(%d, %d)}\n",
|
||||
srcrect->rect.x, srcrect->rect.y,
|
||||
srcrect->rect.w, srcrect->rect.h);
|
||||
|
||||
/* Attempt to use RRE encoding */
|
||||
|
||||
ret = vnc_rre(session, &srcrect->rect);
|
||||
if (ret == 0)
|
||||
{
|
||||
/* Perform the framebuffer update using the default RAW encoding */
|
||||
|
||||
ret = vnc_raw(session, &srcrect->rect);
|
||||
}
|
||||
|
||||
/* Release the update structure */
|
||||
|
||||
vnc_free_update(session, srcrect);
|
||||
|
||||
#ifdef CONFIG_FB_SYNC
|
||||
ret = nxsem_get_value(&session->vsyncsem, &val);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
gerr("ERROR: Get vsync sem failed: %d\n", ret);
|
||||
break;
|
||||
}
|
||||
|
||||
if (sq_count(&session->updqueue) == 0 && val <= 0)
|
||||
{
|
||||
nxsem_post(&session->vsyncsem);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Break out and terminate the server if the encoding failed */
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
gerr("ERROR: Encoding failed: %d\n", ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
session->state = VNCSERVER_STOPPED;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_start_updater
|
||||
*
|
||||
* Description:
|
||||
* Start the updater thread
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - An instance of the session structure.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success; a negated errno value is returned on
|
||||
* any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int vnc_start_updater(FAR struct vnc_session_s *session)
|
||||
{
|
||||
pthread_attr_t attr;
|
||||
struct sched_param param;
|
||||
int status;
|
||||
|
||||
ginfo("Starting updater for Display %d\n", session->display);
|
||||
|
||||
/* Create thread that is gonna send rectangles to the client */
|
||||
|
||||
session->state = VNCSERVER_RUNNING;
|
||||
|
||||
DEBUGVERIFY(pthread_attr_init(&attr));
|
||||
DEBUGVERIFY(pthread_attr_setstacksize(&attr,
|
||||
CONFIG_VNCSERVER_UPDATER_STACKSIZE));
|
||||
|
||||
param.sched_priority = CONFIG_VNCSERVER_UPDATER_PRIO;
|
||||
DEBUGVERIFY(pthread_attr_setschedparam(&attr, ¶m));
|
||||
|
||||
status = pthread_create(&session->updater, &attr, vnc_updater,
|
||||
(pthread_addr_t)session);
|
||||
if (status != 0)
|
||||
{
|
||||
return -status;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_stop_updater
|
||||
*
|
||||
* Description:
|
||||
* Stop the updater thread
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - An instance of the session structure.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success; a negated errno value is returned on
|
||||
* any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int vnc_stop_updater(FAR struct vnc_session_s *session)
|
||||
{
|
||||
pthread_addr_t result;
|
||||
int status;
|
||||
|
||||
/* Is the update thread running? */
|
||||
|
||||
if (session->state == VNCSERVER_RUNNING)
|
||||
{
|
||||
/* Yes.. ask it to please stop */
|
||||
|
||||
session->state = VNCSERVER_STOPPING;
|
||||
|
||||
/* Wait for the thread to comply with our request */
|
||||
|
||||
status = pthread_join(session->updater, &result);
|
||||
if (status != 0)
|
||||
{
|
||||
return -status;
|
||||
}
|
||||
|
||||
/* Return what the thread returned */
|
||||
|
||||
return (int)((intptr_t)result);
|
||||
}
|
||||
|
||||
/* Not running? Just say we stopped the thread successfully. */
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: vnc_update_rectangle
|
||||
*
|
||||
* Description:
|
||||
* Queue an update of the specified rectangular region on the display.
|
||||
*
|
||||
* Input Parameters:
|
||||
* session - An instance of the session structure.
|
||||
* rect - The rectanglular region to be updated.
|
||||
* change - True: Frame buffer data has changed
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success; a negated errno value is returned on
|
||||
* any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int vnc_update_rectangle(FAR struct vnc_session_s *session,
|
||||
FAR const struct fb_area_s *rect, bool change)
|
||||
{
|
||||
FAR struct vnc_fbupdate_s *update;
|
||||
struct fb_area_s intersection;
|
||||
bool whupd;
|
||||
|
||||
intersection.x = rect->x;
|
||||
intersection.y = rect->y;
|
||||
|
||||
/* Clip rectangle to the screen dimensions */
|
||||
|
||||
if (rect->w < g_wholescreen.w)
|
||||
{
|
||||
intersection.w = rect->w;
|
||||
}
|
||||
else
|
||||
{
|
||||
intersection.w = g_wholescreen.w;
|
||||
}
|
||||
|
||||
if (rect->h < g_wholescreen.h)
|
||||
{
|
||||
intersection.h = rect->h;
|
||||
}
|
||||
else
|
||||
{
|
||||
intersection.h = g_wholescreen.h;
|
||||
}
|
||||
|
||||
/* Make sure that the clipped rectangle has an area */
|
||||
|
||||
if (intersection.w && intersection.h)
|
||||
{
|
||||
/* Check for a whole screen update. The RealVNC client sends a lot
|
||||
* of these (especially when it is confused)
|
||||
*/
|
||||
|
||||
whupd = (memcmp(&intersection, &g_wholescreen,
|
||||
sizeof(struct fb_area_s)) == 0);
|
||||
|
||||
/* Ignore any client update requests if there have been no changes to
|
||||
* the framebuffer since the last whole screen update.
|
||||
*/
|
||||
|
||||
sched_lock();
|
||||
if (!change && !session->change)
|
||||
{
|
||||
/* No.. ignore the client update. We have nothing new to report. */
|
||||
|
||||
sched_unlock();
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Ignore all updates if there is a queued whole screen update */
|
||||
|
||||
if (session->nwhupd == 0)
|
||||
{
|
||||
/* No whole screen updates in the queue. Is this a new whole
|
||||
* screen update?
|
||||
*/
|
||||
|
||||
if (whupd)
|
||||
{
|
||||
/* Yes.. Discard all of the previously queued updates */
|
||||
|
||||
FAR struct vnc_fbupdate_s *curr;
|
||||
FAR struct vnc_fbupdate_s *next;
|
||||
|
||||
updinfo("New whole screen update...\n");
|
||||
|
||||
curr = (FAR struct vnc_fbupdate_s *)session->updqueue.head;
|
||||
sq_init(&session->updqueue);
|
||||
nxsem_reset(&session->queuesem, 0);
|
||||
|
||||
for (; curr != NULL; curr = next)
|
||||
{
|
||||
next = curr->flink;
|
||||
vnc_free_update(session, curr);
|
||||
}
|
||||
|
||||
/* One whole screen update will be queued. There have been
|
||||
* no frame buffer data changes since this update was queued.
|
||||
*/
|
||||
|
||||
session->nwhupd = 1;
|
||||
session->change = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We are not updating the whole screen. Remember if this
|
||||
* update (OR a preceding update) was due to a data change.
|
||||
*/
|
||||
|
||||
session->change |= change;
|
||||
}
|
||||
|
||||
/* Allocate an update structure... waiting if necessary */
|
||||
|
||||
update = vnc_alloc_update(session);
|
||||
DEBUGASSERT(update != NULL);
|
||||
|
||||
/* Copy the clipped rectangle into the update structure */
|
||||
|
||||
update->whupd = whupd;
|
||||
memcpy(&update->rect, &intersection, sizeof(intersection));
|
||||
|
||||
/* Add the update to the end of the update queue. */
|
||||
|
||||
vnc_add_queue(session, update);
|
||||
|
||||
updinfo("Queued {(%d, %d),(%d, %d)}\n",
|
||||
intersection.x, intersection.y,
|
||||
intersection.w, intersection.h);
|
||||
}
|
||||
|
||||
sched_unlock();
|
||||
}
|
||||
|
||||
/* Since we ignore bad rectangles and wait for update structures, there is
|
||||
* really no way a failure can occur.
|
||||
*/
|
||||
|
||||
return OK;
|
||||
}
|
||||
Reference in New Issue
Block a user