VNC server for eCos

Introduction

VNC stands for Virtual Network Computing. It is in essence, a remote display system which allows you to view a computing 'desktop' environment not only on the machine where it is running, but from anywhere on the Internet and from a wide variety of machine architectures. For full details of VNC, and to get the vncviewer program see: http://www.uk.research.att.com/vnc/.

The VNC server for eCos runs on the target platform and waits for a client (vncviewer program running on a PC) to connect via an ethernet connection (port 5900). Once a client has connected, the target platform has a virtual screen, keyboard and mouse.

 

Limitations

The eCos port of the VNC server has been designed with some limitations in order to keep memory and processor power requirements to a minimum.

  1. The VNC client must accept the settings that the VNC server suggests (bits-per-pixel, number-of-colours and so on as specified at build time with the eCos configuration tool) or the VNC server will just disconnect.
  2. The VNC server only supports CoRRE encoding and RAW encoding for sending display data to the client.
  3. The VNC server does not support password authentication, the client is able to connect without the user typing in a password.
  4. Only one VNC client may connect to the VNC server at a time.

In reality these limitations are not a problem.

 

VNC server API

If the VNC server is to be used with the eCos port of MicroWindows, then VNC server API may be ignored and the application should just use one of the API supplied by MicroWindows.

VNC server display API

To use the VNC server display API the application should include the VNC server header file by adding the following line to their C application:

#include <vnc-server.h>   /* VNC server header file *

This file specifies several function to manipulate the display.

vnc_frame_format_t* VncGetInfo(void)

The VNC get info function returns a pointer to a 'vnc_frame_format_t' type structure and is used to get information about the VNC display. 'vnc_frame_format_t' is defined in the vnc-server.h file as:

typedef struct
{
    cyg_uint16 frame_width;
    cyg_uint16 frame_height;
    void * frame_buffer;
    bool rgb332;
    
bool rgb555;
    bool rgb565;
} vnc_frame_format_t;

The frame_width and frame height fields contain the VNC server display size in pixels.

The * frame_buffer pointer contains the address of the actual frame buffer the VNC server uses, though the application should never write to this buffer directly.

The final 3 (bool) fields specifiy the pixel format - only one of them will be set to true.

 

void VncInit(vnc_colour_t colour)

The VNC initialise function, initialises the VNC server and paints the display with the specified colour. This funcftion must be called before any of the other VNC server display functions are used, except for VncGetInfo() - which may be called at any time.

The type 'vnc_colour_t' is defined in the vnc-server.h file - and is used to represent a colour. If the VNC server is built to support 8-bit pixel data then 'vnc_colour_t' will be type cyg_uint8, but if 16-bit pixel data is being used then 'vnc_colour_t' will be type cyg_uint16.

 

void VncDrawPixel(cyg_uint16 x,
                  cyg_uint16 y,
                  vnc_colour_t colour)

The VNC draw pixel function simply draws a pixel of colour, 'colour', at position ('x', 'y') on the VNC server display. Note that pixel (0, 0) is the top-left pixel in the display.

 

vnc_colour_t VncReadPixel(cyg_uint16 x
                          cyg_uint16 y)

The VNC read pixel function simply returns the colour of the pixel at position ('x', 'y') on the VNC server display. Note that pixel (0, 0) is the top-left pixel in the display.

 

void VncDrawHorzLine(cyg_uint16 x1,
                     cyg_uint16 x2,
                     cyg_uint16 y,
                     vnc_colour_t colour)

The VNC draw horizontal line function simply draws a line of pixels of colour, 'colour', from position ('x1', 'y') to position ('x2', 'y') (inclusive) on the VNC server display. Note that pixel (0, 0) is the top-left pixel in the display.

 

void VncDrawVertLine(cyg_uint16 x,
                     cyg_uint16 y1,
                     cyg_uint16 y2,
                     vnc_colour_t colour)

The VNC draw vertical line function simply draws a line of pixels of colour, 'colour', from position ('x', 'y1') to position ('x', 'y2') (inclusive) on the VNC server display. Note that pixel (0, 0) is the top-left pixel in the display.

 

void VncFillRect(cyg_uint16 x1,
                 cyg_uint16 y1,
                 cyg_uint16 x2,
                 cyg_uint16 y2,
                 vnc_colour_t colour)

The VNC fill rectangle function draws a solid rectangle of colour, 'colour', with top-left corner at ('x1', 'y1') and bottom right corner at ('x2', 'y2') (inclusive) on the VNC server display. Note that pixel (0, 0) is the top-left pixel in the display.

 

void VncCopyRect(cyg_uint16 x1,
                 cyg_uint16 y1,
                 cyg_uint16 width,
                 cyg_uint16 height,
                 cyg_uint16 x2,
                 cyg_uint16 y2)

The VNC copy rectangle function copies a rectangle from one part of the VNC display to another. The source rectangle is of width 'width', and height 'height', with its top-left corner at ('x1', 'y1'). The destination rectangle is the same size with its top-left corner at ('x2', 'y2'). Note that pixel (0, 0) is the top-left pixel in the display.

 

void VncCopyRect2Buffer(cyg_uint16 x,
                        cyg_uint16 y,
                        cyg_uint16 width,
                        cyg_uint16 height,
                        void *buffer,
                        cyg_uint16 buff_w,
                        cyg_uint16 buff_h,
                        cyg_uint16 x_off,
                        cyg_uint16 y_off)

The VNC copy rectangle to buffer function copies a rectangle of the VNC server display to a buffer supplied by the application. This function is useful for saving areas of the display which will need to be restored later, such as the area under a mouse cursor.

The rectangle of the display to be copied is of width 'width' and height 'height' with its top-left corner at position ('x', 'y'). The address of the buffer supplied to copy the image data is specified by '*buffer'. This buffer is of width 'buff_w' and height 'buff_height'. If the buffer width and height is larger than the rectangle being copied from the display, an x and y offset may be supplied ('x_off' and 'y_off' respectively) to offset where the rectangle of display data in the buffer.

For example a buffer of width = 50 and height = 40 could be defined with:

vnc_colour_t my_buffer[40][50];

Then VncCopyRect2Buffer() could be called with:

VncCopyRect2Buffer(10,  /* x-pos on display */
                   10,  /* y-pos on display */

                   30,  /* rectangle width on display */
                   20,  /* rectangle heigth on display */
                   20,  /* rectangle heigth on display */
                                      (void *)my_buffer, /* Address of buffer */
                   50,  /* buffer width */
                   40,  /* buffer height */
                   5,   /* buffer x-offset */
                   6);  /* buffer y-offset */

This would copy a 30 pixel wide, 20 pixel high rectangle from (10, 10) of the VNC server display to the buffer 'my_buffer'. Inside the buffer there would by an x-offset of 5 and a y offset of 6. Thus pixel (10, 10) from the VNC server display would now be copied to my_buffer[6][5] - and so on for the rest of the rectangle.

 

void VncCopyBuffer2Rect(void *buffer,
                        cyg_uint16 buff_w,
                        cyg_uint16 buff_h,
                        cyg_uint16 x_off,
                        cyg_uint16 y_off,
                        cyg_uint16 x,
                        cyg_uint16 y,
                        cyg_uint16 width,
                        cyg_uint16 height)

The VNC copy buffer to rectangle function copies a rectangle from a buffer supplied by the application to the VNC server display. This function is usefull for restoring previously saved areas of the display.

For example, to restore the rectangle saved in the previous example use of the VncCopyRect2Buffer() function above, the VncCopyBuff2Rect() would be called with:

VncCopyBuffer2Rect((void *)my_buffer, /* Address of buffer */
                   50,  /* buffer width */
                   40,  /* buffer height */
                   5,   /* buffer x-offset */
                   6,   /* buffer y-offset */
                   10,  /* x-pos on display */
                   10,  /* y-pos on display */

                   30,  /* rectangle width on display */
                   20); /* rectangle heigth on display */

Note that in most uses of the VncCopyBuff2Rect() and VncCopyRect2Buffer() functions would be called with:
    width = buff_w
    heigth = buff_h
    x_off = 0
    y_off = 0.

In this case there is no offset into the buffer and the buffer is used 100% to store the rectangle from the display.

 

vnc_printf_return_t VncPrintf(MWCFONT* font,
                              int do_print,
                              vnc_colour_t colour,
                              int x,
                              int y,
                              const char *fmt, ... );)

The VNC printf function writes test to a specified position in the VNC frame buffer, using the specified font and colour.

The '* font' argument is a pointer to a MWCFONT font structure. This is the same font structure as used by MicroWindows, though the VNC server has its own copy of the font description files. The available fonts are:

    font_rom8x16
    font_rom8x8
    font_winFreeSansSerif11x13
    font_winFreeSystem14x16
    font_helvB10
    font_helvB12
    font_helvR10
    font_X5x7
    font_X6x13

If the font argument is set to '0', then the default font (winFreeSystem14x16) is used.

The 'do_print' argument is used to specify whether the function should actually write the text to the frame buffer. If do_print is non-zero, then the text will be written to the frame buffer. If do_print is zero, then no text will be written, but the return value from the function will sill be valid.

The 'colour' argument specifies the colour to use to write the text.

The 'x' and 'y' arguments specify the pixel position (x, y) in the frame buffer of the top left pixel of the first character to be printed.

The 'const char *fmt, ...' argumets are used as in a normal printf statement.

The function returns a data structure of type vnc_printf_return_t, this is defined as:

    typedef struct
    {
        int chars;
        cyg_uint16 width;
        cyg_uint16 height;
    } vnc_printf_return_t;

The 'chars' values is exactly as would have been returned by the printf() function.

The width and height attributes specify the width and height of a rectangle surrounding the text written to the screen. This data can be used to know how much of the frame buffer needs to be painted to delete the text, or (used together with the 'do_print' argument set to 0) to calculate how much of the screen should be saved before printing to it so that it may be restored later.

An example of writing some text to position (250, 200) of the frame buffer, using the colout cyan and the font, winFreeSansSerif11x13:

vnc_printf_return_t print_area;

print_area = VncPrintf(&font_winFreeSansSerif11x13,
                       1,
                       VNC_CYAN,
                       250,
                       200,
                      
"Hello World!\nUsing winFreeSansSerif11x13 font");

Note: 'print_area.width' and 'print_area.height' will be set to indicate how much of the frame buffer was used to print this text.

Another example, using the default font this time:

print_area = VncPrintf(0,
                       1,
                       VNC_BLACK,
                       250,
                       200,
                       
"50 * 34 = %d", 50*34);

Also included in the vnc-server.h header file are 16 predefined colours:

VNC_BLACK
VNC_BLUE
VNC_GREEN
VNC_CYAN
VNC_RED
VNC_MAGENTA
VNC_BROWN
VNC_LTGRAY
VNC_LTGREY  /* Same as VNC_LTGRAY */
VNC_GRAY
VNC_GREY  /* Same as VNC_GRAY */
VNC_LTBLUE
VNC_LTGREEN
VNC_LTCYAN
VNC_LTRED
VNC_LTMAGENTA
VNC_YELLOW
VNC_WHITE

These colours are all of type vnc_colour_t and are always correct for the selected pixel type.

Also contained in the vnc-server.h header file is a macro to convert from a full RGB colour value to the nearest colour that the type vnc_colour_t can represent. This macro is:

VNC_RGB2COL(red, green, blue)

The arguments red, green and blue each have a value from 0 to 255.

For example, to initialise the VNC server display with a colour as close to a very specific shade of green [red=156, green=229, blue=91] - the VncInit() function could be called as follows:

VncInit( VNC_RGB2COL(156, 229, 91) );

Obviously the colour match will be better if the VNC server had been built with 16 bits per pixel rather than with 8 bits per pixel, but in each case the best available colour will be used.

Though not strictly a display function, a function to sound a bell on the client is available.

void VncSoundBell(void)

The VNC Sound Bell function simply sounds a bell on the client - if the client supports this.

 

VNC server mouse API

The VNC server mouse device driver is a standard eCos IO device driver. The device name is "/dev/vnc_mouse" by default, but this may be modified with the configuration tool. The first step in using the mouse device driver is to use the cyg_io_lookup() function:

Cyg_ErrNo mouse_err;
cyg_io_handle_t mouse_handle;
cyg_uint8 mouse_data[8];
cyg_uint32 mouse_len;


mouse_err = cyg_io_lookup("/dev/vnc_mouse", &mouse_handle); /* Open mouse device */ if (mouse_err == -ENOENT)
{
    diag_printf("Could not open mouse device\n");
}

Once the cyg_io_lookup() function has found the mouse device driver, the driver is active and should be read regularly to prevent the receive buffer from overflowing with data. Data is read using the cyg_io_read() function:

mouse_len = 8;  /* Try to read 8 bytes from mouse */
cyg_io_read(mouse_handle, mouse_data, &mouse_len );
if (mouse_len == 0)
{
    diag_printf("Mouse has no new data\n");
}
else
{
    diag_printf("Have New mouse data:\n");

    diag_printf("  Mouse button data: 0x%x\n", mouse_data[1]);
        diag_printf("  Mouse x-coord: %d\n", mouse_data[2]*256 + mouse_data[3]);
        diag_printf("  Mouse y-coord: %d\n", mouse_data[4]*256 + mouse_data[5]);
}

The cyg_io_read() function is a non-blocking function and each mouse event generates 8 bytes of data:

Byte 0: Padding - always zero
Byte 1: Button data (bit 0 = 1 if the left button is pressed, bit 2 = 1 if the right button is pressed)
Byte 2: Mose position x-coord MSB
Byte 3: Mose position x-coord LSB
Byte 4: Mose position y-coord MSB
Byte 5: Mose position y-coord LSB
Byte 6: Padding - always zero
Byte 7: Padding - always zero

 

VNC server keyboard API

The VNC server keyboard device driver is a standard eCos IO device driver. The device name is "/dev/vnc_kbd" by default, but this may be modified with the configuration tool. The first step in using the keyboard device driver is to use the cyg_io_lookup() function:

Cyg_ErrNo kdb_err;
cyg_io_handle_t kbd_handle;
cyg_uint8 kbd_data[8];
cyg_uint32 kbd_len;


kbd_err = cyg_io_lookup("/dev/vnc_kbd", &kbd_handle); /* Open kbd device */
if (kbd_err == -ENOENT)
{
    diag_printf("Could not open kbd device\n");
}

Once the cyg_io_lookup() function has found the keyboard device driver, the driver is active and should be read regularly to prevent the receive buffer from overflowing with data. Data is read using the cyg_io_read() function:

kbd_len = 4;  /* Try to read 4 bytes from keyboard */
cyg_io_read(kbd_handle, kbd_data, &kbd_len );
if (kbd_len == 0)
{
    diag_printf("Keyboard has no new data\n");
}
else
{
    diag_printf("Have New keyboard data:\n");
    if (kbd_data[1])
    {

        diag_printf("  Keysym value 0x%x pressed\n",
                     kbd_data[2]*256 + kbd_data[3]
);
    }
    else
    {
        diag_printf("  Keysym value 0x%x released\n",
                     kbd_data[2]*256 + kbd_data[3]
);
    }

}

The cyg_io_read() function is a non-blocking function and each keystroke event generates 4bytes of data:

Byte 0: Padding - always zero
Byte 1: Key pressed/released (1 when key pressed)
Byte 2: Keysym value for key MSB
Byte 3: Keysym value for key LSB

The actual key values are specified using the "keysym" values defined by the X Window System. For most ordinary keys the keysym value is the same as the corresponding ASCII value. For full details see either the Xlib Reference Manual, published by O'Reilly & Associates or see the header file <X11/keysymdef.h> from any X Window System installation (a google search for 'keysymdef.h' should find it).