namespace YoctoLib 
{/*********************************************************************
 *
 * $Id: yocto_display.cs 75637 2026-08-20 16:54:40Z mvuilleu $
 *
 * Implements yFindDisplay(), the high-level API for Display functions
 *
 * - - - - - - - - - License information: - - - - - - - - -
 *
 *  Copyright (C) 2011 and beyond by Yoctopuce Sarl, Switzerland.
 *
 *  Yoctopuce Sarl (hereafter Licensor) grants to you a perpetual
 *  non-exclusive license to use, modify, copy and integrate this
 *  file into your software for the sole purpose of interfacing
 *  with Yoctopuce products.
 *
 *  You may reproduce and distribute copies of this file in
 *  source or object form, as long as the sole purpose of this
 *  code is to interface with Yoctopuce products. You must retain
 *  this notice in the distributed source file.
 *
 *  You should refer to Yoctopuce General Terms and Conditions
 *  for additional information regarding your rights and
 *  obligations.
 *
 *  THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
 *  WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
 *  WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS
 *  FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO
 *  EVENT SHALL LICENSOR BE LIABLE FOR ANY INCIDENTAL, SPECIAL,
 *  INDIRECT OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA,
 *  COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR
 *  SERVICES, ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT
 *  LIMITED TO ANY DEFENSE THEREOF), ANY CLAIMS FOR INDEMNITY OR
 *  CONTRIBUTION, OR OTHER SIMILAR COSTS, WHETHER ASSERTED ON THE
 *  BASIS OF CONTRACT, TORT (INCLUDING NEGLIGENCE), BREACH OF
 *  WARRANTY, OR OTHERWISE.
 *
 *********************************************************************/


using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Text;
using YDEV_DESCR = System.Int32;
using YFUN_DESCR = System.Int32;

#pragma warning disable 1591
//--- (generated code: YDisplayLayer class start)
/**
 * <summary>
 *   Each <c>DisplayLayer</c> represents an image layer containing objects
 *   to display (bitmaps, text, etc.).
 * <para>
 *   The content is displayed only when
 *   the layer is active on the screen (and not masked by other
 *   overlapping layers).
 * </para>
 * <para>
 * </para>
 * </summary>
 */
public class YDisplayLayer
{
//--- (end of generated code: YDisplayLayer class start)

    private YDisplay _display  = null;
    private int      _id = -1;

    //--- (generated code: YDisplayLayer definitions)

    public enum ALIGN
    {
        TOP_LEFT = 0,
        CENTER_LEFT = 1,
        BASELINE_LEFT = 2,
        BOTTOM_LEFT = 3,
        TOP_CENTER = 4,
        CENTER = 5,
        BASELINE_CENTER = 6,
        BOTTOM_CENTER = 7,
        TOP_DECIMAL = 8,
        CENTER_DECIMAL = 9,
        BASELINE_DECIMAL = 10,
        BOTTOM_DECIMAL = 11,
        TOP_RIGHT = 12,
        CENTER_RIGHT = 13,
        BASELINE_RIGHT = 14,
        BOTTOM_RIGHT = 15
    };
    public const int NO_INK = -1;
    public const int BG_INK = -2;
    public const int FG_INK = -3;
    protected string _cmdbuff = "";
    protected bool _hidden = false;
    protected int _polyPrevX = 0;
    protected int _polyPrevY = 0;
    //--- (end of generated code: YDisplayLayer definitions)

    public YDisplayLayer(YDisplay parent, int id)
    {
        this._display = parent;
        this._id = id;
        //--- (generated code: YDisplayLayer attributes initialization)
        //--- (end of generated code: YDisplayLayer attributes initialization)
    }

    //--- (generated code: YDisplayLayer implementation)



    public virtual bool must_be_flushed()
    {
        return (this._cmdbuff).Length > 0;
    }


    public virtual int resetHiddenFlag()
    {
        this._hidden = false;
        return YAPI.SUCCESS;
    }


    public virtual int flush_now()
    {
        int res;
        res = YAPI.SUCCESS;
        if ((this._cmdbuff).Length > 0) {
            res = this._display.sendCommand(this._cmdbuff);
            this._cmdbuff = "";
        }
        return res;
    }


    public virtual int command_push(string cmd)
    {
        int res;
        res = YAPI.SUCCESS;
        if ((this._cmdbuff).Length + (cmd).Length >= 64) {
            // force flush before, to prevent overflow
            this.flush_now();
        }
        if ((this._cmdbuff).Length == 0) {
            // always prepend layer ID first
            this._cmdbuff = (this._id).ToString();
        }
        this._cmdbuff = this._cmdbuff + cmd;
        return res;
    }


    public virtual int command_flush(string cmd)
    {
        int res;

        res = this.command_push(cmd);
        if (this._hidden) {
            return res;
        }
        if (this._display.isFrozen()) {
            return res;
        }
        return this.flush_now();
    }


    /**
     * <summary>
     *   Reverts the layer to its initial state (fully transparent, default settings).
     * <para>
     *   Reinitializes the drawing pointer to the upper left position,
     *   and selects the most visible pen color. If you only want to erase the layer
     *   content, use the method <c>clear()</c> instead.
     * </para>
     * </summary>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int reset()
    {
        this._hidden = false;
        return this.command_flush("X");
    }


    /**
     * <summary>
     *   Erases the whole content of the layer (makes it fully transparent).
     * <para>
     *   This method does not change any other attribute of the layer.
     *   To reinitialize the layer attributes to defaults settings, use the method
     *   <c>reset()</c> instead.
     * </para>
     * </summary>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int clear()
    {
        return this.command_flush("x");
    }


    /**
     * <summary>
     *   Selects the color to be used for all subsequent drawing functions,
     *   for filling as well as for line and text drawing.
     * <para>
     *   To select a different fill and outline color, use
     *   <c>selectFillColor</c> and <c>selectLineColor</c>.
     *   The pen color is provided as an RGB value.
     *   For grayscale or monochrome displays, the value is
     *   automatically converted to the proper range.
     * </para>
     * </summary>
     * <param name="color">
     *   the desired pen color, as a 24-bit RGB value
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int selectColorPen(int color)
    {
        return this.command_push("c"+String.Format("{0:x06}",color));
    }


    /**
     * <summary>
     *   Selects the pen gray level for all subsequent drawing functions,
     *   for filling as well as for line and text drawing.
     * <para>
     *   To select a different fill and outline color, use
     *   <c>selectFillColor</c> and <c>selectLineColor</c>.
     *   The gray level is provided as a number between
     *   0 (black) and 255 (white, or whichever the lightest color is).
     *   For monochrome displays (without gray levels), any value
     *   lower than 128 is rendered as black, and any value equal
     *   or above to 128 is non-black.
     * </para>
     * </summary>
     * <param name="graylevel">
     *   the desired gray level, from 0 to 255
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int selectGrayPen(int graylevel)
    {
        return this.command_push("g"+Convert.ToString(graylevel));
    }


    /**
     * <summary>
     *   Selects an eraser instead of a pen for all subsequent drawing functions,
     *   except for bitmap copy functions.
     * <para>
     *   Any point drawn using the eraser
     *   becomes transparent (as when the layer is empty), showing the other
     *   layers beneath it.
     * </para>
     * </summary>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int selectEraser()
    {
        return this.command_push("e");
    }


    /**
     * <summary>
     *   Selects the color to be used for filling rectangular bars,
     *   discs and polygons.
     * <para>
     *   The color is provided as an RGB value.
     *   For grayscale or monochrome displays, the value is
     *   automatically converted to the proper range.
     *   You can also use the constants <c>FG_INK</c> to use the
     *   default drawing colour, <c>BG_INK</c> to use the default
     *   background colour, and <c>NO_INK</c> to disable filling.
     * </para>
     * </summary>
     * <param name="color">
     *   the desired drawing color, as a 24-bit RGB value,
     *   or one of the constants <c>NO_INK</c>, <c>FG_INK</c>
     *   or <c>BG_INK</c>
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int selectFillColor(int color)
    {
        int r;
        int g;
        int b;
        if (color==-1) {
            return this.command_push("f_");
        }
        if (color==-2) {
            return this.command_push("f-");
        }
        if (color==-3) {
            return this.command_push("f.");
        }
        r = ((color >> 20) & 15);
        g = ((color >> 12) & 15);
        b = ((color >> 4) & 15);
        return this.command_push("f"+String.Format("{0:x}",r)+""+String.Format("{0:x}",g)+""+String.Format("{0:x}",b));
    }


    /**
     * <summary>
     *   Selects the color to be used for drawing the outline of rectangular
     *   bars, discs and polygons, as well as for drawing lines and text.
     * <para>
     *   The color is provided as an RGB value.
     *   For grayscale or monochrome displays, the value is
     *   automatically converted to the proper range.
     *   You can also use the constants <c>FG_INK</c> to use the
     *   default drawing colour, <c>BG_INK</c> to use the default
     *   background colour, and <c>NO_INK</c> to disable outline drawing.
     * </para>
     * </summary>
     * <param name="color">
     *   the desired drawing color, as a 24-bit RGB value,
     *   or one of the constants <c>NO_INK</c>, <c>FG_INK</c>
     *   or <c>BG_INK</c>
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int selectLineColor(int color)
    {
        int r;
        int g;
        int b;
        if (color==-1) {
            return this.command_push("l_");
        }
        if (color==-2) {
            return this.command_push("l-");
        }
        if (color==-3) {
            return this.command_push("l*");
        }
        r = ((color >> 20) & 15);
        g = ((color >> 12) & 15);
        b = ((color >> 4) & 15);
        return this.command_push("l"+String.Format("{0:x}",r)+""+String.Format("{0:x}",g)+""+String.Format("{0:x}",b));
    }


    /**
     * <summary>
     *   Selects the line width for drawing the outline of rectangular
     *   bars, discs and polygons, as well as for drawing lines.
     * <para>
     * </para>
     * </summary>
     * <param name="width">
     *   the desired line width, in pixels
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int selectLineWidth(int width)
    {
        return this.command_push("t"+Convert.ToString(width));
    }


    public virtual int setAntialiasingMode(bool mode)
    {
        return this.command_push("a"+(mode?"1":"0"));
    }


    /**
     * <summary>
     *   Draws a single pixel at the specified position.
     * <para>
     * </para>
     * </summary>
     * <param name="x">
     *   the distance from left of layer, in pixels
     * </param>
     * <param name="y">
     *   the distance from top of layer, in pixels
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int drawPixel(int x, int y)
    {
        return this.command_flush("P"+Convert.ToString(x)+","+Convert.ToString(y));
    }


    /**
     * <summary>
     *   Draws an empty rectangle at a specified position.
     * <para>
     * </para>
     * </summary>
     * <param name="x1">
     *   the distance from left of layer to the left border of the rectangle, in pixels
     * </param>
     * <param name="y1">
     *   the distance from top of layer to the top border of the rectangle, in pixels
     * </param>
     * <param name="x2">
     *   the distance from left of layer to the right border of the rectangle, in pixels
     * </param>
     * <param name="y2">
     *   the distance from top of layer to the bottom border of the rectangle, in pixels
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int drawRect(int x1, int y1, int x2, int y2)
    {
        return this.command_flush("R"+Convert.ToString(x1)+","+Convert.ToString(y1)+","+Convert.ToString(x2)+","+Convert.ToString(y2));
    }


    /**
     * <summary>
     *   Draws a filled rectangular bar at a specified position.
     * <para>
     * </para>
     * </summary>
     * <param name="x1">
     *   the distance from left of layer to the left border of the rectangle, in pixels
     * </param>
     * <param name="y1">
     *   the distance from top of layer to the top border of the rectangle, in pixels
     * </param>
     * <param name="x2">
     *   the distance from left of layer to the right border of the rectangle, in pixels
     * </param>
     * <param name="y2">
     *   the distance from top of layer to the bottom border of the rectangle, in pixels
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int drawBar(int x1, int y1, int x2, int y2)
    {
        return this.command_flush("B"+Convert.ToString(x1)+","+Convert.ToString(y1)+","+Convert.ToString(x2)+","+Convert.ToString(y2));
    }


    /**
     * <summary>
     *   Draws an empty circle at a specified position.
     * <para>
     * </para>
     * </summary>
     * <param name="x">
     *   the distance from left of layer to the center of the circle, in pixels
     * </param>
     * <param name="y">
     *   the distance from top of layer to the center of the circle, in pixels
     * </param>
     * <param name="r">
     *   the radius of the circle, in pixels
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int drawCircle(int x, int y, int r)
    {
        return this.command_flush("C"+Convert.ToString(x)+","+Convert.ToString(y)+","+Convert.ToString(r));
    }


    /**
     * <summary>
     *   Draws a filled disc at a given position.
     * <para>
     * </para>
     * </summary>
     * <param name="x">
     *   the distance from left of layer to the center of the disc, in pixels
     * </param>
     * <param name="y">
     *   the distance from top of layer to the center of the disc, in pixels
     * </param>
     * <param name="r">
     *   the radius of the disc, in pixels
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int drawDisc(int x, int y, int r)
    {
        return this.command_flush("D"+Convert.ToString(x)+","+Convert.ToString(y)+","+Convert.ToString(r));
    }


    /**
     * <summary>
     *   Selects a font to use for the next text drawing functions, by providing the name of the
     *   font file.
     * <para>
     *   You can use a built-in font as well as a font file that you have previously
     *   uploaded to the device built-in memory. If you experience problems selecting a font
     *   file, check the device logs for any error message such as missing font file or bad font
     *   file format.
     * </para>
     * </summary>
     * <param name="fontname">
     *   the font file name, embedded fonts are 8x8.yfm, Small.yfm, Medium.yfm, Large.yfm (not available on
     *   Yocto-MiniDisplay).
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int selectFont(string fontname)
    {
        return this.command_push("&"+fontname+""+((char)(27)).ToString());
    }


    /**
     * <summary>
     *   Draws a text string at the specified position.
     * <para>
     *   The point of the text that is aligned
     *   to the specified pixel position is called the anchor point, and can be chosen among
     *   several options. Text is rendered from left to right, without implicit wrapping.
     * </para>
     * </summary>
     * <param name="x">
     *   the distance from left of layer to the text anchor point, in pixels
     * </param>
     * <param name="y">
     *   the distance from top of layer to the text anchor point, in pixels
     * </param>
     * <param name="anchor">
     *   the text anchor point, chosen among the <c>YDisplayLayer.ALIGN</c> enumeration:
     *   <c>YDisplayLayer.ALIGN.TOP_LEFT</c>,         <c>YDisplayLayer.ALIGN.CENTER_LEFT</c>,
     *   <c>YDisplayLayer.ALIGN.BASELINE_LEFT</c>,    <c>YDisplayLayer.ALIGN.BOTTOM_LEFT</c>,
     *   <c>YDisplayLayer.ALIGN.TOP_CENTER</c>,       <c>YDisplayLayer.ALIGN.CENTER</c>,
     *   <c>YDisplayLayer.ALIGN.BASELINE_CENTER</c>,  <c>YDisplayLayer.ALIGN.BOTTOM_CENTER</c>,
     *   <c>YDisplayLayer.ALIGN.TOP_DECIMAL</c>,      <c>YDisplayLayer.ALIGN.CENTER_DECIMAL</c>,
     *   <c>YDisplayLayer.ALIGN.BASELINE_DECIMAL</c>, <c>YDisplayLayer.ALIGN.BOTTOM_DECIMAL</c>,
     *   <c>YDisplayLayer.ALIGN.TOP_RIGHT</c>,        <c>YDisplayLayer.ALIGN.CENTER_RIGHT</c>,
     *   <c>YDisplayLayer.ALIGN.BASELINE_RIGHT</c>,   <c>YDisplayLayer.ALIGN.BOTTOM_RIGHT</c>.
     * </param>
     * <param name="text">
     *   the text string to draw
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int drawText(int x, int y, ALIGN anchor, string text)
    {
        int textlen;
        string destname;
        textlen = (text).Length;
        if (textlen > 60) {
            if (textlen > 1000) {
                this._display._throw(YAPI.INVALID_ARGUMENT, "text too large (max 1000 characters)");
                return YAPI.INVALID_ARGUMENT;
            }
            this._display.flushLayers();
            destname = "layer"+Convert.ToString(this._id)+":T"+Convert.ToString(x)+","+Convert.ToString(y)+","+((int)(anchor)).ToString()+",";
            return this._display.upload(destname,YAPI.DefaultEncoding.GetBytes(text));
        }
        return this.command_flush("T"+Convert.ToString(x)+","+Convert.ToString(y)+","+((int)(anchor)).ToString()+","+text+""+((char)(27)).ToString());
    }


    /**
     * <summary>
     *   Draws an image previously uploaded to the device filesystem, at the specified position.
     * <para>
     *   At present time, GIF images are the only supported image format. If you experience
     *   problems using an image file, check the device logs for any error message such as
     *   missing image file or bad image file format.
     * </para>
     * </summary>
     * <param name="x">
     *   the distance from left of layer to the left of the image, in pixels
     * </param>
     * <param name="y">
     *   the distance from top of layer to the top of the image, in pixels
     * </param>
     * <param name="imagename">
     *   the GIF file name
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int drawImage(int x, int y, string imagename)
    {
        return this.command_flush("*"+Convert.ToString(x)+","+Convert.ToString(y)+","+imagename+""+((char)(27)).ToString());
    }


    /**
     * <summary>
     *   Draws a GIF image provided as a binary buffer at the specified position.
     * <para>
     *   If the image drawing must be included in an animation sequence, save it
     *   in the device filesystem first and use <c>drawImage</c> instead.
     * </para>
     * </summary>
     * <param name="x">
     *   the distance from left of layer to the left of the image, in pixels
     * </param>
     * <param name="y">
     *   the distance from top of layer to the top of the image, in pixels
     * </param>
     * <param name="gifimage">
     *   a binary object with the content of a GIF file
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int drawGIF(int x, int y, byte[] gifimage)
    {
        string destname;
        this._display.flushLayers();
        destname = "layer"+Convert.ToString(this._id)+":G,-1@"+Convert.ToString(x)+","+Convert.ToString(y);
        return this._display.upload(destname,gifimage);
    }


    /**
     * <summary>
     *   Draws a bitmap at the specified position.
     * <para>
     *   The bitmap is provided as a binary object,
     *   where each pixel maps to a bit, from left to right and from top to bottom.
     *   The most significant bit of each byte maps to the leftmost pixel, and the least
     *   significant bit maps to the rightmost pixel. Bits set to 1 are drawn using the
     *   layer selected pen color. Bits set to 0 are drawn using the specified background
     *   color, unless <c>NO_INK</c> (-1) is specified, in which case they are not
     *   drawn at all (as if transparent).
     * </para>
     * </summary>
     * <param name="x">
     *   the distance from left of layer to the left of the bitmap, in pixels
     * </param>
     * <param name="y">
     *   the distance from top of layer to the top of the bitmap, in pixels
     * </param>
     * <param name="w">
     *   the width of the bitmap, in pixels
     * </param>
     * <param name="bitmap">
     *   a binary object
     * </param>
     * <param name="bgcol">
     *   the RGB background color to use for zero bits, as a 24-bit RGB value,
     *   or one of the constants <c>NO_INK</c>, <c>FG_INK</c> or <c>BG_INK</c>
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int drawBitmap(int x, int y, int w, byte[] bitmap, int bgcol)
    {
        string destname;
        int r;
        int g;
        int b;
        string rgbcol;
        if ((w < 0) || (w > 512)) {
            this._display._throw(YAPI.INVALID_ARGUMENT, "bitmap width must be in range 1..512");
            return YAPI.INVALID_ARGUMENT;
        }
        this._display.flushLayers();
        if (bgcol <= 255) {
            if (bgcol >= -1) {
                // backward-compatible behaviour (gray level)
                rgbcol = ""+Convert.ToString(bgcol);
            } else {
                // background color or foreground color
                if (bgcol <= -3) {
                    rgbcol = "#.";
                } else {
                    rgbcol = "#-";
                }
            }
        } else {
            // RGB color
            r = ((bgcol >> 20) & 15);
            g = ((bgcol >> 12) & 15);
            b = ((bgcol >> 4) & 15);
            rgbcol = "#"+String.Format("{0:x}",r)+""+String.Format("{0:x}",g)+""+String.Format("{0:x}",b);
        }
        destname = "layer"+Convert.ToString(this._id)+":"+Convert.ToString(w)+","+rgbcol+"@"+Convert.ToString(x)+","+Convert.ToString(y);
        return this._display.upload(destname,bitmap);
    }


    /**
     * <summary>
     *   Draws a color pixmap at the specified position.
     * <para>
     *   The pixmap is provided as a binary
     *   object, where each byte maps to one pixel. The 24 bit RGB value corresponding to each
     *   byte value is defined in the palette provided as extra argument.
     *   The palette maximal size is 8, and it is recommended to use the smallest possible
     *   palette size to optimize the size of data to be sent to the display.
     *   The height of the pixmap is implicitely given by the pixmap buffer size.
     * </para>
     * </summary>
     * <param name="x">
     *   the distance from left of layer to the left of the pixmap, in pixels
     * </param>
     * <param name="y">
     *   the distance from top of layer to the top of the pixmap, in pixels
     * </param>
     * <param name="w">
     *   the width of the pixmap, in pixels
     * </param>
     * <param name="pixmap">
     *   a binary buffer where each byte maps to one pixel
     * </param>
     * <param name="palette">
     *   an array of 24-bit RGB values, defining the color for each byte value in pixmap
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int drawPixmap(int x, int y, int w, byte[] pixmap, List<int> palette)
    {
        byte[] gifimage = new byte[0];
        gifimage = this._display.gifEncode(pixmap, palette, w, false);
        return this.drawGIF(x, y, gifimage);
    }


    /**
     * <summary>
     *   Moves the drawing pointer of this layer to the specified position.
     * <para>
     * </para>
     * </summary>
     * <param name="x">
     *   the distance from left of layer, in pixels
     * </param>
     * <param name="y">
     *   the distance from top of layer, in pixels
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int moveTo(int x, int y)
    {
        return this.command_push("@"+Convert.ToString(x)+","+Convert.ToString(y));
    }


    /**
     * <summary>
     *   Draws a line from current drawing pointer position to the specified position.
     * <para>
     *   The specified destination pixel is included in the line. The pointer position
     *   is then moved to the end point of the line.
     * </para>
     * </summary>
     * <param name="x">
     *   the distance from left of layer to the end point of the line, in pixels
     * </param>
     * <param name="y">
     *   the distance from top of layer to the end point of the line, in pixels
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int lineTo(int x, int y)
    {
        return this.command_flush("-"+Convert.ToString(x)+","+Convert.ToString(y));
    }


    /**
     * <summary>
     *   Starts drawing a polygon with the first corner at the specified position.
     * <para>
     * </para>
     * </summary>
     * <param name="x">
     *   the distance from left of layer, in pixels
     * </param>
     * <param name="y">
     *   the distance from top of layer, in pixels
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int polygonStart(int x, int y)
    {
        this._polyPrevX = x;
        this._polyPrevY = y;
        return this.command_push("["+Convert.ToString(x)+","+Convert.ToString(y));
    }


    /**
     * <summary>
     *   Adds a point to the currently open polygon, previously opened using
     *   <c>polygonStart</c>.
     * <para>
     * </para>
     * </summary>
     * <param name="x">
     *   the distance from left of layer to the new point, in pixels
     * </param>
     * <param name="y">
     *   the distance from top of layer to the new point, in pixels
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int polygonAdd(int x, int y)
    {
        int dx;
        int dy;
        dx = x - this._polyPrevX;
        dy = y - this._polyPrevY;
        this._polyPrevX = x;
        this._polyPrevY = y;
        return this.command_flush(";"+Convert.ToString(dx)+","+Convert.ToString(dy));
    }


    /**
     * <summary>
     *   Closes the currently open polygon, fill its content the fill color currently
     *   selected for the layer, and draw its outline using the selected line color.
     * <para>
     * </para>
     * </summary>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int polygonEnd()
    {
        return this.command_flush("]");
    }


    /**
     * <summary>
     *   Outputs a message in the console area, and advances the console pointer accordingly.
     * <para>
     *   The console pointer position is automatically moved to the beginning
     *   of the next line when a newline character is met, or when the right margin
     *   is hit. When the new text to display extends below the lower margin, the
     *   console area is automatically scrolled up.
     * </para>
     * </summary>
     * <param name="text">
     *   the message to display
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int consoleOut(string text)
    {
        int textlen;
        string destname;
        textlen = (text).Length;
        if (textlen > 60) {
            if (textlen > 1000) {
                this._display._throw(YAPI.INVALID_ARGUMENT, "text too large (max 1000 characters)");
                return YAPI.INVALID_ARGUMENT;
            }
            this._display.flushLayers();
            destname = "layer"+Convert.ToString(this._id)+":!";
            return this._display.upload(destname,YAPI.DefaultEncoding.GetBytes(text));
        }
        return this.command_flush("!"+text+""+((char)(27)).ToString());
    }


    /**
     * <summary>
     *   Sets up display margins for the <c>consoleOut</c> function.
     * <para>
     * </para>
     * </summary>
     * <param name="x1">
     *   the distance from left of layer to the left margin, in pixels
     * </param>
     * <param name="y1">
     *   the distance from top of layer to the top margin, in pixels
     * </param>
     * <param name="x2">
     *   the distance from left of layer to the right margin, in pixels
     * </param>
     * <param name="y2">
     *   the distance from top of layer to the bottom margin, in pixels
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int setConsoleMargins(int x1, int y1, int x2, int y2)
    {
        return this.command_push("m"+Convert.ToString(x1)+","+Convert.ToString(y1)+","+Convert.ToString(x2)+","+Convert.ToString(y2));
    }


    /**
     * <summary>
     *   Sets up the background color used by the <c>clearConsole</c> function and by
     *   the console scrolling feature.
     * <para>
     * </para>
     * </summary>
     * <param name="bgcol">
     *   the background gray level to use when scrolling (0 = black,
     *   255 = white), or -1 for transparent
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int setConsoleBackground(int bgcol)
    {
        return this.command_push("b"+Convert.ToString(bgcol));
    }


    /**
     * <summary>
     *   Sets up the wrapping behavior used by the <c>consoleOut</c> function.
     * <para>
     * </para>
     * </summary>
     * <param name="wordwrap">
     *   <c>true</c> to wrap only between words,
     *   <c>false</c> to wrap on the last column anyway.
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int setConsoleWordWrap(bool wordwrap)
    {
        return this.command_push("w"+(wordwrap?"1":"0"));
    }


    /**
     * <summary>
     *   Blanks the console area within console margins, and resets the console pointer
     *   to the upper left corner of the console.
     * <para>
     * </para>
     * </summary>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int clearConsole()
    {
        return this.command_flush("^");
    }


    /**
     * <summary>
     *   Sets the position of the layer relative to the display upper left corner.
     * <para>
     *   When smooth scrolling is used, the display offset of the layer is
     *   automatically updated during the next milliseconds to animate the move of the layer.
     * </para>
     * </summary>
     * <param name="x">
     *   the distance from left of display to the upper left corner of the layer
     * </param>
     * <param name="y">
     *   the distance from top of display to the upper left corner of the layer
     * </param>
     * <param name="scrollTime">
     *   number of milliseconds to use for smooth scrolling, or
     *   0 if the scrolling should be immediate.
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int setLayerPosition(int x, int y, int scrollTime)
    {
        return this.command_flush("#"+Convert.ToString(x)+","+Convert.ToString(y)+","+Convert.ToString(scrollTime));
    }


    /**
     * <summary>
     *   Hides the layer.
     * <para>
     *   The state of the layer is preserved but the layer is not displayed
     *   on the screen until the next call to <c>unhide()</c>. Hiding the layer can positively
     *   affect the drawing speed, since it postpones the rendering until all operations are
     *   completed (double-buffering).
     * </para>
     * </summary>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int hide()
    {
        this.command_push("h");
        this._hidden = true;
        return this.flush_now();
    }


    /**
     * <summary>
     *   Shows the layer.
     * <para>
     *   Shows the layer again after a hide command.
     * </para>
     * </summary>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int unhide()
    {
        this._hidden = false;
        return this.command_flush("s");
    }


    /**
     * <summary>
     *   Gets parent YDisplay.
     * <para>
     *   Returns the parent YDisplay object of the current YDisplayLayer.
     * </para>
     * </summary>
     * <returns>
     *   an <c>YDisplay</c> object
     * </returns>
     */
    public virtual YDisplay get_display()
    {
        return this._display;
    }


    /**
     * <summary>
     *   Returns the display width, in pixels.
     * <para>
     * </para>
     * </summary>
     * <returns>
     *   an integer corresponding to the display width, in pixels
     * </returns>
     * <para>
     *   On failure, throws an exception or returns YDisplayLayer.DISPLAYWIDTH_INVALID.
     * </para>
     */
    public virtual int get_displayWidth()
    {
        return this._display.get_displayWidth();
    }


    /**
     * <summary>
     *   Returns the display height, in pixels.
     * <para>
     * </para>
     * </summary>
     * <returns>
     *   an integer corresponding to the display height, in pixels
     * </returns>
     * <para>
     *   On failure, throws an exception or returns YDisplayLayer.DISPLAYHEIGHT_INVALID.
     * </para>
     */
    public virtual int get_displayHeight()
    {
        return this._display.get_displayHeight();
    }


    /**
     * <summary>
     *   Returns the width of the layers to draw on, in pixels.
     * <para>
     * </para>
     * </summary>
     * <returns>
     *   an integer corresponding to the width of the layers to draw on, in pixels
     * </returns>
     * <para>
     *   On failure, throws an exception or returns YDisplayLayer.LAYERWIDTH_INVALID.
     * </para>
     */
    public virtual int get_layerWidth()
    {
        return this._display.get_layerWidth();
    }


    /**
     * <summary>
     *   Returns the height of the layers to draw on, in pixels.
     * <para>
     * </para>
     * </summary>
     * <returns>
     *   an integer corresponding to the height of the layers to draw on, in pixels
     * </returns>
     * <para>
     *   On failure, throws an exception or returns YDisplayLayer.LAYERHEIGHT_INVALID.
     * </para>
     */
    public virtual int get_layerHeight()
    {
        return this._display.get_layerHeight();
    }

    //--- (end of generated code: YDisplayLayer implementation)


    //--- (generated code: YDisplayLayer functions)

    //--- (end of generated code: YDisplayLayer functions)
}

//--- (generated code: YDisplay class start)
/**
 * <summary>
 *   The <c>YDisplay</c> class allows to drive Yoctopuce displays.
 * <para>
 *   Yoctopuce display interface has been designed to easily
 *   show information and images. The device provides built-in
 *   multi-layer rendering. Layers can be drawn offline, individually,
 *   and freely moved on the display. It can also replay recorded
 *   sequences (animations).
 * </para>
 * <para>
 *   In order to draw on the screen, you should use the
 *   <c>display.get_displayLayer</c> method to retrieve the layer(s) on
 *   which you want to draw, and then use methods defined in
 *   <c>YDisplayLayer</c> to draw on the layers.
 * </para>
 * <para>
 * </para>
 * </summary>
 */
public class YDisplay : YFunction
{
//--- (end of generated code: YDisplay class start)
    //--- (generated code: YDisplay definitions)
    public new delegate void ValueCallback(YDisplay func, string value);
    public new delegate void TimedReportCallback(YDisplay func, YMeasure measure);

    public enum FASTREFRESH
    {
        WHENEVER_POSSIBLE = 0,
        WHENEVER_SUPPORTED = 1,
        NEVER = 2,
        INVALID = 3
    };
    public enum REGENERATE
    {
        ON_REQUEST_ONLY = 0,
        EVERY_DAY = 1,
        EVERY_12H = 2,
        EVERY_6H = 3,
        EVERY_3H = 4,
        EVERY_2H = 5,
        EVERY_HOUR = 6,
        EVERY_30MIN = 7,
        EVERY_15MIN = 8,
        EVERY_480 = 9,
        EVERY_432 = 10,
        EVERY_360 = 11,
        EVERY_288 = 12,
        EVERY_240 = 13,
        EVERY_192 = 14,
        EVERY_144 = 15,
        EVERY_96 = 16,
        EVERY_48 = 17,
        EVERY_36 = 18,
        EVERY_24 = 19,
        EVERY_12 = 20,
        EVERY_10 = 21,
        EVERY_8 = 22,
        EVERY_6 = 23,
        EVERY_4 = 24,
        ALWAYS = 25,
        INVALID = 26
    };
    public enum DISPLAYSTATE
    {
        FAILURE = 0,
        OFF = 1,
        POWERING = 2,
        IDLE = 3,
        REFRESHING = 4,
        INVALID = 5
    };
    public const int ENABLED_FALSE = 0;
    public const int ENABLED_TRUE = 1;
    public const int ENABLED_INVALID = -1;
    public const string STARTUPSEQ_INVALID = YAPI.INVALID_STRING;
    public const int BRIGHTNESS_INVALID = YAPI.INVALID_UINT;
    public const int AUTOINVERTDELAY_INVALID = YAPI.INVALID_UINT;
    public const int ORIENTATION_LEFT = 0;
    public const int ORIENTATION_UP = 1;
    public const int ORIENTATION_RIGHT = 2;
    public const int ORIENTATION_DOWN = 3;
    public const int ORIENTATION_INVALID = -1;
    public const string DISPLAYPANEL_INVALID = YAPI.INVALID_STRING;
    public const int DISPLAYWIDTH_INVALID = YAPI.INVALID_UINT;
    public const int DISPLAYHEIGHT_INVALID = YAPI.INVALID_UINT;
    public const int DISPLAYTYPE_MONO = 0;
    public const int DISPLAYTYPE_EPAPER_BW = 1;
    public const int DISPLAYTYPE_EPAPER_BWR = 2;
    public const int DISPLAYTYPE_EPAPER_BWRY = 3;
    public const int DISPLAYTYPE_INVALID = -1;
    public const int LAYERWIDTH_INVALID = YAPI.INVALID_UINT;
    public const int LAYERHEIGHT_INVALID = YAPI.INVALID_UINT;
    public const int LAYERCOUNT_INVALID = YAPI.INVALID_UINT;
    public const string COMMAND_INVALID = YAPI.INVALID_STRING;
    protected int _enabled = ENABLED_INVALID;
    protected string _startupSeq = STARTUPSEQ_INVALID;
    protected int _brightness = BRIGHTNESS_INVALID;
    protected int _autoInvertDelay = AUTOINVERTDELAY_INVALID;
    protected int _orientation = ORIENTATION_INVALID;
    protected string _displayPanel = DISPLAYPANEL_INVALID;
    protected int _displayWidth = DISPLAYWIDTH_INVALID;
    protected int _displayHeight = DISPLAYHEIGHT_INVALID;
    protected int _displayType = DISPLAYTYPE_INVALID;
    protected int _layerWidth = LAYERWIDTH_INVALID;
    protected int _layerHeight = LAYERHEIGHT_INVALID;
    protected int _layerCount = LAYERCOUNT_INVALID;
    protected string _command = COMMAND_INVALID;
    protected ValueCallback _valueCallbackDisplay = null;
    protected List<YDisplayLayer> _allDisplayLayers = new List<YDisplayLayer>();
    protected ulong _frozenUntil = 0;
    protected bool _recording;
    protected string _sequence;
    //--- (end of generated code: YDisplay definitions)

    public YDisplay(string func)
        : base(func)
    {
        _className = "Display";
        //--- (generated code: YDisplay attributes initialization)
        //--- (end of generated code: YDisplay attributes initialization)
    }

  //--- (generated code: YDisplay implementation)

    protected override void _parseAttr(YAPI.YJSONObject json_val)
    {
        if (json_val.has("enabled"))
        {
            _enabled = json_val.getInt("enabled") > 0 ? 1 : 0;
        }
        if (json_val.has("startupSeq"))
        {
            _startupSeq = json_val.getString("startupSeq");
        }
        if (json_val.has("brightness"))
        {
            _brightness = json_val.getInt("brightness");
        }
        if (json_val.has("autoInvertDelay"))
        {
            _autoInvertDelay = json_val.getInt("autoInvertDelay");
        }
        if (json_val.has("orientation"))
        {
            _orientation = json_val.getInt("orientation");
        }
        if (json_val.has("displayPanel"))
        {
            _displayPanel = json_val.getString("displayPanel");
        }
        if (json_val.has("displayWidth"))
        {
            _displayWidth = json_val.getInt("displayWidth");
        }
        if (json_val.has("displayHeight"))
        {
            _displayHeight = json_val.getInt("displayHeight");
        }
        if (json_val.has("displayType"))
        {
            _displayType = json_val.getInt("displayType");
        }
        if (json_val.has("layerWidth"))
        {
            _layerWidth = json_val.getInt("layerWidth");
        }
        if (json_val.has("layerHeight"))
        {
            _layerHeight = json_val.getInt("layerHeight");
        }
        if (json_val.has("layerCount"))
        {
            _layerCount = json_val.getInt("layerCount");
        }
        if (json_val.has("command"))
        {
            _command = json_val.getString("command");
        }
        base._parseAttr(json_val);
    }


    /**
     * <summary>
     *   Returns true if the screen is powered, false otherwise.
     * <para>
     * </para>
     * <para>
     * </para>
     * </summary>
     * <returns>
     *   either <c>YDisplay.ENABLED_FALSE</c> or <c>YDisplay.ENABLED_TRUE</c>, according to true if the
     *   screen is powered, false otherwise
     * </returns>
     * <para>
     *   On failure, throws an exception or returns <c>YDisplay.ENABLED_INVALID</c>.
     * </para>
     */
    public int get_enabled()
    {
        int res;
        lock (_thisLock) {
            if (this._cacheExpiration <= YAPI.GetTickCount()) {
                if (this.load(YAPI._yapiContext.GetCacheValidity()) != YAPI.SUCCESS) {
                    return ENABLED_INVALID;
                }
            }
            res = this._enabled;
        }
        return res;
    }

    /**
     * <summary>
     *   Changes the power state of the display.
     * <para>
     * </para>
     * <para>
     * </para>
     * </summary>
     * <param name="newval">
     *   either <c>YDisplay.ENABLED_FALSE</c> or <c>YDisplay.ENABLED_TRUE</c>, according to the power state
     *   of the display
     * </param>
     * <para>
     * </para>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public int set_enabled(int newval)
    {
        string rest_val;
        lock (_thisLock) {
            rest_val = (newval > 0 ? "1" : "0");
            return _setAttr("enabled", rest_val);
        }
    }


    /**
     * <summary>
     *   Returns the name of the sequence to play when the displayed is powered on.
     * <para>
     * </para>
     * <para>
     * </para>
     * </summary>
     * <returns>
     *   a string corresponding to the name of the sequence to play when the displayed is powered on
     * </returns>
     * <para>
     *   On failure, throws an exception or returns <c>YDisplay.STARTUPSEQ_INVALID</c>.
     * </para>
     */
    public string get_startupSeq()
    {
        string res;
        lock (_thisLock) {
            if (this._cacheExpiration <= YAPI.GetTickCount()) {
                if (this.load(YAPI._yapiContext.GetCacheValidity()) != YAPI.SUCCESS) {
                    return STARTUPSEQ_INVALID;
                }
            }
            res = this._startupSeq;
        }
        return res;
    }

    /**
     * <summary>
     *   Changes the name of the sequence to play when the display is powered on.
     * <para>
     *   Remember to call the <c>saveToFlash()</c> method of the module if the
     *   modification must be kept.
     * </para>
     * <para>
     * </para>
     * </summary>
     * <param name="newval">
     *   a string corresponding to the name of the sequence to play when the display is powered on
     * </param>
     * <para>
     * </para>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public int set_startupSeq(string newval)
    {
        string rest_val;
        lock (_thisLock) {
            rest_val = newval;
            return _setAttr("startupSeq", rest_val);
        }
    }


    /**
     * <summary>
     *   Returns the luminosity of the  module informative LEDs (from 0 to 100).
     * <para>
     * </para>
     * <para>
     * </para>
     * </summary>
     * <returns>
     *   an integer corresponding to the luminosity of the  module informative LEDs (from 0 to 100)
     * </returns>
     * <para>
     *   On failure, throws an exception or returns <c>YDisplay.BRIGHTNESS_INVALID</c>.
     * </para>
     */
    public int get_brightness()
    {
        int res;
        lock (_thisLock) {
            if (this._cacheExpiration <= YAPI.GetTickCount()) {
                if (this.load(YAPI._yapiContext.GetCacheValidity()) != YAPI.SUCCESS) {
                    return BRIGHTNESS_INVALID;
                }
            }
            res = this._brightness;
        }
        return res;
    }

    /**
     * <summary>
     *   Changes the brightness of the display.
     * <para>
     *   The parameter is a value between 0 and
     *   100. Remember to call the <c>saveToFlash()</c> method of the module if the
     *   modification must be kept.
     * </para>
     * <para>
     * </para>
     * </summary>
     * <param name="newval">
     *   an integer corresponding to the brightness of the display
     * </param>
     * <para>
     * </para>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public int set_brightness(int newval)
    {
        string rest_val;
        lock (_thisLock) {
            rest_val = (newval).ToString();
            return _setAttr("brightness", rest_val);
        }
    }


    /**
     * <summary>
     *   Returns the interval between automatic display inversions, or 0 if automatic
     *   inversion is disabled.
     * <para>
     *   Using the automatic inversion mechanism reduces the
     *   burn-in that occurs on OLED screens over long periods when the same content
     *   remains displayed on the screen.
     * </para>
     * <para>
     * </para>
     * </summary>
     * <returns>
     *   an integer corresponding to the interval between automatic display inversions, or 0 if automatic
     *   inversion is disabled
     * </returns>
     * <para>
     *   On failure, throws an exception or returns <c>YDisplay.AUTOINVERTDELAY_INVALID</c>.
     * </para>
     */
    public int get_autoInvertDelay()
    {
        int res;
        lock (_thisLock) {
            if (this._cacheExpiration <= YAPI.GetTickCount()) {
                if (this.load(YAPI._yapiContext.GetCacheValidity()) != YAPI.SUCCESS) {
                    return AUTOINVERTDELAY_INVALID;
                }
            }
            res = this._autoInvertDelay;
        }
        return res;
    }

    /**
     * <summary>
     *   Changes the interval between automatic display inversions.
     * <para>
     *   The parameter is the number of seconds, or 0 to disable automatic inversion.
     *   Using the automatic inversion mechanism reduces the burn-in that occurs on OLED
     *   screens over long periods when the same content remains displayed on the screen.
     *   Remember to call the <c>saveToFlash()</c> method of the module if the
     *   modification must be kept.
     * </para>
     * <para>
     * </para>
     * </summary>
     * <param name="newval">
     *   an integer corresponding to the interval between automatic display inversions
     * </param>
     * <para>
     * </para>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public int set_autoInvertDelay(int newval)
    {
        string rest_val;
        lock (_thisLock) {
            rest_val = (newval).ToString();
            return _setAttr("autoInvertDelay", rest_val);
        }
    }


    /**
     * <summary>
     *   Returns the currently selected display orientation.
     * <para>
     *   The orientation is defined as the side of the screen where the
     *   USB connector (for OLED displays) or the ribbon cable (for ePaper panels) is located when the
     *   display is up straight.
     * </para>
     * <para>
     * </para>
     * </summary>
     * <returns>
     *   a value among <c>YDisplay.ORIENTATION_LEFT</c>, <c>YDisplay.ORIENTATION_UP</c>,
     *   <c>YDisplay.ORIENTATION_RIGHT</c> and <c>YDisplay.ORIENTATION_DOWN</c> corresponding to the
     *   currently selected display orientation
     * </returns>
     * <para>
     *   On failure, throws an exception or returns <c>YDisplay.ORIENTATION_INVALID</c>.
     * </para>
     */
    public int get_orientation()
    {
        int res;
        lock (_thisLock) {
            if (this._cacheExpiration <= YAPI.GetTickCount()) {
                if (this.load(YAPI._yapiContext.GetCacheValidity()) != YAPI.SUCCESS) {
                    return ORIENTATION_INVALID;
                }
            }
            res = this._orientation;
        }
        return res;
    }

    /**
     * <summary>
     *   Changes the display orientation.
     * <para>
     *   he orientation is defined as the side of the screen where the
     *   USB connector (for OLED displays) or the ribbon cable (for ePaper panels) is located when the
     *   display is up straight. Remember to call the <c>saveToFlash()</c>
     *   method of the module if the modification must be kept.
     * </para>
     * <para>
     * </para>
     * </summary>
     * <param name="newval">
     *   a value among <c>YDisplay.ORIENTATION_LEFT</c>, <c>YDisplay.ORIENTATION_UP</c>,
     *   <c>YDisplay.ORIENTATION_RIGHT</c> and <c>YDisplay.ORIENTATION_DOWN</c> corresponding to the display orientation
     * </param>
     * <para>
     * </para>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public int set_orientation(int newval)
    {
        string rest_val;
        lock (_thisLock) {
            rest_val = (newval).ToString();
            int res = _setAttr("orientation", rest_val);
            _clearLazyCache();
            return res;
        }
    }


    /**
     * <summary>
     *   Returns the exact model of the display panel.
     * <para>
     * </para>
     * <para>
     * </para>
     * </summary>
     * <returns>
     *   a string corresponding to the exact model of the display panel
     * </returns>
     * <para>
     *   On failure, throws an exception or returns <c>YDisplay.DISPLAYPANEL_INVALID</c>.
     * </para>
     */
    public string get_displayPanel()
    {
        string res;
        lock (_thisLock) {
            if (this._cacheExpiration <= YAPI.GetTickCount()) {
                if (this.load(YAPI._yapiContext.GetCacheValidity()) != YAPI.SUCCESS) {
                    return DISPLAYPANEL_INVALID;
                }
            }
            res = this._displayPanel;
        }
        return res;
    }

    /**
     * <summary>
     *   Changes the model of display to match the connected display panel.
     * <para>
     *   This function has no effect if the module does not support the selected
     *   display panel. Remember to call the <c>saveToFlash()</c>
     *   method of the module if the modification must be kept.
     * </para>
     * <para>
     * </para>
     * </summary>
     * <param name="newval">
     *   a string corresponding to the model of display to match the connected display panel
     * </param>
     * <para>
     * </para>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public int set_displayPanel(string newval)
    {
        string rest_val;
        lock (_thisLock) {
            rest_val = newval;
            int res = _setAttr("displayPanel", rest_val);
            _clearLazyCache();
            return res;
        }
    }


    /**
     * <summary>
     *   Returns the display width, in pixels.
     * <para>
     * </para>
     * <para>
     * </para>
     * </summary>
     * <returns>
     *   an integer corresponding to the display width, in pixels
     * </returns>
     * <para>
     *   On failure, throws an exception or returns <c>YDisplay.DISPLAYWIDTH_INVALID</c>.
     * </para>
     */
    public int get_displayWidth()
    {
        int res;
        lock (_thisLock) {
            if (this._cacheExpiration == 0) {
                if (this.load(YAPI._yapiContext.GetCacheValidity()) != YAPI.SUCCESS) {
                    return DISPLAYWIDTH_INVALID;
                }
            }
            res = this._displayWidth;
        }
        return res;
    }


    /**
     * <summary>
     *   Returns the display height, in pixels.
     * <para>
     * </para>
     * <para>
     * </para>
     * </summary>
     * <returns>
     *   an integer corresponding to the display height, in pixels
     * </returns>
     * <para>
     *   On failure, throws an exception or returns <c>YDisplay.DISPLAYHEIGHT_INVALID</c>.
     * </para>
     */
    public int get_displayHeight()
    {
        int res;
        lock (_thisLock) {
            if (this._cacheExpiration == 0) {
                if (this.load(YAPI._yapiContext.GetCacheValidity()) != YAPI.SUCCESS) {
                    return DISPLAYHEIGHT_INVALID;
                }
            }
            res = this._displayHeight;
        }
        return res;
    }


    /**
     * <summary>
     *   Returns the display type: monochrome OLED, black and white ePaper, color ePaper, and so on.
     * <para>
     * </para>
     * <para>
     * </para>
     * </summary>
     * <returns>
     *   a value among <c>YDisplay.DISPLAYTYPE_MONO</c>, <c>YDisplay.DISPLAYTYPE_EPAPER_BW</c>,
     *   <c>YDisplay.DISPLAYTYPE_EPAPER_BWR</c> and <c>YDisplay.DISPLAYTYPE_EPAPER_BWRY</c> corresponding to
     *   the display type: monochrome OLED, black and white ePaper, color ePaper, and so on
     * </returns>
     * <para>
     *   On failure, throws an exception or returns <c>YDisplay.DISPLAYTYPE_INVALID</c>.
     * </para>
     */
    public int get_displayType()
    {
        int res;
        lock (_thisLock) {
            if (this._cacheExpiration == 0) {
                if (this.load(YAPI._yapiContext.GetCacheValidity()) != YAPI.SUCCESS) {
                    return DISPLAYTYPE_INVALID;
                }
            }
            res = this._displayType;
        }
        return res;
    }


    /**
     * <summary>
     *   Returns the width of the layers to draw on, in pixels.
     * <para>
     * </para>
     * <para>
     * </para>
     * </summary>
     * <returns>
     *   an integer corresponding to the width of the layers to draw on, in pixels
     * </returns>
     * <para>
     *   On failure, throws an exception or returns <c>YDisplay.LAYERWIDTH_INVALID</c>.
     * </para>
     */
    public int get_layerWidth()
    {
        int res;
        lock (_thisLock) {
            if (this._cacheExpiration == 0) {
                if (this.load(YAPI._yapiContext.GetCacheValidity()) != YAPI.SUCCESS) {
                    return LAYERWIDTH_INVALID;
                }
            }
            res = this._layerWidth;
        }
        return res;
    }


    /**
     * <summary>
     *   Returns the height of the layers to draw on, in pixels.
     * <para>
     * </para>
     * <para>
     * </para>
     * </summary>
     * <returns>
     *   an integer corresponding to the height of the layers to draw on, in pixels
     * </returns>
     * <para>
     *   On failure, throws an exception or returns <c>YDisplay.LAYERHEIGHT_INVALID</c>.
     * </para>
     */
    public int get_layerHeight()
    {
        int res;
        lock (_thisLock) {
            if (this._cacheExpiration == 0) {
                if (this.load(YAPI._yapiContext.GetCacheValidity()) != YAPI.SUCCESS) {
                    return LAYERHEIGHT_INVALID;
                }
            }
            res = this._layerHeight;
        }
        return res;
    }


    /**
     * <summary>
     *   Returns the number of available layers to draw on.
     * <para>
     * </para>
     * <para>
     * </para>
     * </summary>
     * <returns>
     *   an integer corresponding to the number of available layers to draw on
     * </returns>
     * <para>
     *   On failure, throws an exception or returns <c>YDisplay.LAYERCOUNT_INVALID</c>.
     * </para>
     */
    public int get_layerCount()
    {
        int res;
        lock (_thisLock) {
            if (this._cacheExpiration == 0) {
                if (this.load(YAPI._yapiContext.GetCacheValidity()) != YAPI.SUCCESS) {
                    return LAYERCOUNT_INVALID;
                }
            }
            res = this._layerCount;
        }
        return res;
    }


    public string get_command()
    {
        string res;
        lock (_thisLock) {
            if (this._cacheExpiration <= YAPI.GetTickCount()) {
                if (this.load(YAPI._yapiContext.GetCacheValidity()) != YAPI.SUCCESS) {
                    return COMMAND_INVALID;
                }
            }
            res = this._command;
        }
        return res;
    }

    public int set_command(string newval)
    {
        string rest_val;
        lock (_thisLock) {
            rest_val = newval;
            return _setAttr("command", rest_val);
        }
    }


    /**
     * <summary>
     *   Retrieves a display for a given identifier.
     * <para>
     *   The identifier can be specified using several formats:
     * </para>
     * <para>
     * </para>
     * <para>
     *   - FunctionLogicalName
     * </para>
     * <para>
     *   - ModuleSerialNumber.FunctionIdentifier
     * </para>
     * <para>
     *   - ModuleSerialNumber.FunctionLogicalName
     * </para>
     * <para>
     *   - ModuleLogicalName.FunctionIdentifier
     * </para>
     * <para>
     *   - ModuleLogicalName.FunctionLogicalName
     * </para>
     * <para>
     * </para>
     * <para>
     *   This function does not require that the display is online at the time
     *   it is invoked. The returned object is nevertheless valid.
     *   Use the method <c>YDisplay.isOnline()</c> to test if the display is
     *   indeed online at a given time. In case of ambiguity when looking for
     *   a display by logical name, no error is notified: the first instance
     *   found is returned. The search is performed first by hardware name,
     *   then by logical name.
     * </para>
     * <para>
     *   If a call to this object's is_online() method returns FALSE although
     *   you are certain that the matching device is plugged, make sure that you did
     *   call registerHub() at application initialization time.
     * </para>
     * <para>
     * </para>
     * </summary>
     * <param name="func">
     *   a string that uniquely characterizes the display, for instance
     *   <c>YD128X32.display</c>.
     * </param>
     * <returns>
     *   a <c>YDisplay</c> object allowing you to drive the display.
     * </returns>
     */
    public static YDisplay FindDisplay(string func)
    {
        YDisplay obj;
        lock (YAPI.globalLock) {
            obj = (YDisplay) YFunction._FindFromCache("Display", func);
            if (obj == null) {
                obj = new YDisplay(func);
                YFunction._AddToCache("Display", func, obj);
            }
        }
        return obj;
    }


    /**
     * <summary>
     *   Registers the callback function that is invoked on every change of advertised value.
     * <para>
     *   The callback is then invoked only during the execution of <c>ySleep</c> or <c>yHandleEvents</c>.
     *   This provides control over the time when the callback is triggered. For good responsiveness,
     *   remember to call one of these two functions periodically. The callback is called once juste after beeing
     *   registered, passing the current advertised value  of the function, provided that it is not an empty string.
     *   To unregister a callback, pass a null pointer as argument.
     * </para>
     * <para>
     * </para>
     * </summary>
     * <param name="callback">
     *   the callback function to call, or a null pointer. The callback function should take two
     *   arguments: the function object of which the value has changed, and the character string describing
     *   the new advertised value.
     * @noreturn
     * </param>
     */
    public int registerValueCallback(ValueCallback callback)
    {
        string val;
        if (callback != null) {
            YFunction._UpdateValueCallbackList(this, true);
        } else {
            YFunction._UpdateValueCallbackList(this, false);
        }
        this._valueCallbackDisplay = callback;
        // Immediately invoke value callback with current value
        if (callback != null && this.isOnline()) {
            val = this._advertisedValue;
            if (!(val == "")) {
                this._invokeValueCallback(val);
            }
        }
        return 0;
    }


    public override int _invokeValueCallback(string value)
    {
        if (this._valueCallbackDisplay != null) {
            this._valueCallbackDisplay(this, value);
        } else {
            base._invokeValueCallback(value);
        }
        return 0;
    }


    public virtual int sendCommand(string cmd)
    {
        if (!(this._recording)) {
            return this.set_command(cmd);
        }
        this._sequence = ""+this._sequence+""+cmd+"\n";
        return YAPI.SUCCESS;
    }


    public virtual int flushLayers()
    {
        for (int ii_0 = 0; ii_0 < this._allDisplayLayers.Count; ii_0++) {
            if (this._allDisplayLayers[ii_0].must_be_flushed()) {
                this._allDisplayLayers[ii_0].flush_now();
            }
        }
        return YAPI.SUCCESS;
    }


    public virtual int resetHiddenLayerFlags()
    {
        for (int ii_0 = 0; ii_0 < this._allDisplayLayers.Count; ii_0++) {
            this._allDisplayLayers[ii_0].resetHiddenFlag();
        }
        return YAPI.SUCCESS;
    }


    public virtual bool isFrozen()
    {
        if (this._frozenUntil == 0) {
            return false;
        }
        if (this._frozenUntil <= YAPI.GetTickCount()) {
            this._frozenUntil = 0;
            return false;
        }
        return true;
    }


    /**
     * <summary>
     *   Returns the fast refresh usage policy in use (ePaper displays only).
     * <para>
     *   This setting is combined with the regenerate policy to determine when the screen
     *   should be updated using a fast update versus or regenerated using a slower,
     *   flickering full refresh.
     * </para>
     * <para>
     * </para>
     * </summary>
     * <returns>
     *   a value among the <c>YDisplay.FASTREFRESH</c> enumeration
     *   (<c>YDisplay.FASTREFRESH_WHENEVER_POSSIBLE</c>,
     *   <c>YDisplay.FASTREFRESH_WHENEVER_SUPPORTED</c>,
     *   <c>YDisplay.FASTREFRESH_NEVER</c>).
     * </returns>
     * <para>
     *   On failure, throws an exception or returns <c>YDisplay.FASTREFRESH_INVALID</c>.
     * </para>
     */
    public virtual FASTREFRESH get_fastRefreshPolicy()
    {
        int combined;
        int fmod;
        combined = this.get_brightness();
        if (combined < 0) {
            return FASTREFRESH.INVALID;
        }
        fmod = (combined / 25);
        if (fmod >= 2) {
            fmod = fmod - 2;
        }
        return (FASTREFRESH) fmod;
    }


    /**
     * <summary>
     *   Returns the display regeneration minimal frequency (ePaper displays only).
     * <para>
     *   This setting is combined with the fast refresh usage policy to determine
     *   when the screen should be updated using a fast update versus or regenerated
     *   using a slower, flickering full refresh. To change the display regeneration minimal
     *   frequency, use methode <c>set_fastRefreshPolicy()</c>.
     * </para>
     * <para>
     * </para>
     * </summary>
     * <returns>
     *   a value among the <c>YDisplay.REGENERATE</c> enumeration
     *   (<c>YDisplay.REGENERATE_ON_REQUEST_ONLY</c>,
     *   <c>YDisplay.REGENERATE_EVERY_DAY</c>, <c>YDisplay.REGENERATE_EVERY_12H</c>,
     *   <c>YDisplay.REGENERATE_EVERY_6H</c>, <c>YDisplay.REGENERATE_EVERY_3H</c>,
     *   <c>YDisplay.REGENERATE_EVERY_2H</c>, <c>YDisplay.REGENERATE_EVERY_HOUR</c>,
     *   <c>YDisplay.REGENERATE_EVERY_30MIN</c>, <c>YDisplay.REGENERATE_EVERY_15MIN</c>,
     *   <c>YDisplay.REGENERATE_EVERY_480</c>, <c>YDisplay.REGENERATE_EVERY_432</c>,
     *   <c>YDisplay.REGENERATE_EVERY_360</c>, <c>YDisplay.REGENERATE_EVERY_288</c>,
     *   <c>YDisplay.REGENERATE_EVERY_240</c>, <c>YDisplay.REGENERATE_EVERY_192</c>,
     *   <c>YDisplay.REGENERATE_EVERY_144</c>, <c>YDisplay.REGENERATE_EVERY_96</c>,
     *   <c>YDisplay.REGENERATE_EVERY_48</c>, <c>YDisplay.REGENERATE_EVERY_36</c>,
     *   <c>YDisplay.REGENERATE_EVERY_24</c>, <c>YDisplay.REGENERATE_EVERY_12</c>,
     *   <c>YDisplay.REGENERATE_EVERY_10</c>, <c>YDisplay.REGENERATE_EVERY_8</c>,
     *   <c>YDisplay.REGENERATE_EVERY_6</c>, <c>YDisplay.REGENERATE_EVERY_4</c>,
     *   <c>YDisplay.REGENERATE_ALWAYS</c>).
     * </returns>
     * <para>
     *   On failure, throws an exception or returns <c>YDisplay.REGENERATE_INVALID</c>.
     * </para>
     */
    public virtual REGENERATE get_regeneratePolicy()
    {
        int combined;
        int fval;
        combined= this.get_brightness();
        if (combined < 0) {
            return REGENERATE.INVALID;
        }
        if (combined >= 100) {
            fval = 25;
        } else {
            fval = (combined % 25);
        }
        return (REGENERATE) fval;
    }


    /**
     * <summary>
     *   Changes the fast refresh usage policy and display regeneration minimal frequency
     *   (ePaper displays only).
     * <para>
     *   These settings jointly determine when the screen should be
     *   updated using a fast update versus or regenerated using a slower, flickering full
     *   refresh.
     * </para>
     * <para>
     * </para>
     * </summary>
     * <param name="fastRefresh">
     *   a value among the <c>YDisplay.FASTREFRESH</c> enumeration
     *   (<c>YDisplay.FASTREFRESH_WHENEVER_POSSIBLE</c>,
     *   <c>YDisplay.FASTREFRESH_WHENEVER_SUPPORTED</c>,
     *   <c>YDisplay.FASTREFRESH_NEVER</c>),
     *   corresponding to the policy for using fast refresh.
     * </param>
     * <param name="regenerate">
     *   a value among the enumeration <c>YRefFrame.REGENERATE</c>
     *   (<c>YDisplay.REGENERATE_ON_REQUEST_ONLY</c>,
     *   <c>YDisplay.REGENERATE_EVERY_DAY</c>, <c>YDisplay.REGENERATE_EVERY_12H</c>,
     *   <c>YDisplay.REGENERATE_EVERY_6H</c>, <c>YDisplay.REGENERATE_EVERY_3H</c>,
     *   <c>YDisplay.REGENERATE_EVERY_2H</c>, <c>YDisplay.REGENERATE_EVERY_HOUR</c>,
     *   <c>YDisplay.REGENERATE_EVERY_30MIN</c>, <c>YDisplay.REGENERATE_EVERY_15MIN</c>,
     *   <c>YDisplay.REGENERATE_EVERY_480</c>, <c>YDisplay.REGENERATE_EVERY_432</c>,
     *   <c>YDisplay.REGENERATE_EVERY_360</c>, <c>YDisplay.REGENERATE_EVERY_288</c>,
     *   <c>YDisplay.REGENERATE_EVERY_240</c>, <c>YDisplay.REGENERATE_EVERY_192</c>,
     *   <c>YDisplay.REGENERATE_EVERY_144</c>, <c>YDisplay.REGENERATE_EVERY_96</c>,
     *   <c>YDisplay.REGENERATE_EVERY_48</c>, <c>YDisplay.REGENERATE_EVERY_36</c>,
     *   <c>YDisplay.REGENERATE_EVERY_24</c>, <c>YDisplay.REGENERATE_EVERY_12</c>,
     *   <c>YDisplay.REGENERATE_EVERY_10</c>, <c>YDisplay.REGENERATE_EVERY_8</c>,
     *   <c>YDisplay.REGENERATE_EVERY_6</c>, <c>YDisplay.REGENERATE_EVERY_4</c>,
     *   <c>YDisplay.REGENERATE_ALWAYS</c>),
     *   corresponding to the display minimal regeneration frequency.
     * </param>
     * <para>
     *   Remember to call the <c>saveToFlash()</c>
     *   method of the module if the modification must be kept.
     * </para>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int set_fastRefreshPolicy(FASTREFRESH fastRefresh, REGENERATE regenerate)
    {
        int combined;
        int fmod;
        int fval;
        fmod = (int)fastRefresh;
        fval = (int)regenerate;
        if ((fval == 25) || (fmod == 2)) {
            combined = 100;
        } else {
            combined = 50 + fmod * 25 + fval;
        }
        return this.set_brightness(combined);
    }


    /**
     * <summary>
     *   Clears the display screen and resets all display layers to their default state.
     * <para>
     *   Using this function in a sequence will kill the sequence play-back. Do not use that
     *   function to reset the display at sequence start-up.
     * </para>
     * <para>
     * </para>
     * </summary>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int resetAll()
    {
        this.flushLayers();
        this.resetHiddenLayerFlags();
        return this.sendCommand("Z");
    }


    /**
     * <summary>
     *   Forces an ePaper screen to perform a regenerative update using the slow
     *   update method.
     * <para>
     *   Periodic use of the slow method (total panel update with
     *   multiple inversions) prevents ghosting effects and improves contrast.
     * </para>
     * <para>
     * </para>
     * </summary>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int regenerateDisplay()
    {
        return this.sendCommand("z");
    }


    /**
     * <summary>
     *   Returns the current state of an ePaper display, specifically to
     *   determine whether an update is in progress or whether a
     *   configuration issue has been detected.
     * <para>
     *   If a display configuration
     *   error has been detected, the error message can be retrieved.
     * </para>
     * <para>
     * </para>
     * </summary>
     * <param name="errmsg">
     *   a string passed by reference to receive the error message.
     * </param>
     * <returns>
     *   a value among the enumeration <c>YDisplay.DISPLAYSTATE</c>
     *   (<c>YDisplay.DISPLAYSTATE.FAILURE</c>, <c>YDisplay.DISPLAYSTATE.OFF</c>,
     *   <c>YDisplay.DISPLAYSTATE.POWERING</c>, <c>YDisplay.DISPLAYSTATE.IDLE</c>,
     *   <c>YDisplay.DISPLAYSTATE.REFRESHING</c>)
     *   corresponding to the current display state.
     * </returns>
     */
    public virtual DISPLAYSTATE get_ePaperState(ref string errmsg)
    {
        byte[] json = new byte[0];
        string dispError;
        int dispState;

        if (this.get_displayType() == DISPLAYTYPE_MONO) {
            errmsg = "Not an ePaper display";
            return (DISPLAYSTATE) 0;
        }
        json = this._download("disp.json");
        if ((json).Length == 0) {
            errmsg = this.get_errorMessage();
            return (DISPLAYSTATE) 0;
        } else {
            dispError = this._json_get_string(this._get_json_path(json, "err"));
            errmsg = dispError;
            if ((dispError).Length > 0) {
                return (DISPLAYSTATE) 0;
            }
            dispState = YAPI._atoi(this._json_get_key(json, "state"));
            if (dispState > 10) {
                return (DISPLAYSTATE) 4;
            }
            if (dispState == 10) {
                return (DISPLAYSTATE) 3;
            }
            if (dispState > 0) {
                return (DISPLAYSTATE) 2;
            }
        }
        return (DISPLAYSTATE) 1;
    }


    /**
     * <summary>
     *   Disables screen refresh for a short period of time.
     * <para>
     *   The combination of
     *   <c>postponeRefresh</c> and <c>triggerRefresh</c> can be used as an
     *   alternative to double-buffering to avoid flickering during display updates.
     * </para>
     * </summary>
     * <param name="duration">
     *   duration of deactivation in milliseconds (max. 30 seconds)
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int postponeRefresh(int duration)
    {
        this._frozenUntil = YAPI.GetTickCount() + (ulong)(duration);
        return this.sendCommand("H"+Convert.ToString(duration));
    }


    /**
     * <summary>
     *   Triggers an immediate screen refresh.
     * <para>
     *   The combination of
     *   <c>postponeRefresh</c> and <c>triggerRefresh</c> can be used as an
     *   alternative to double-buffering to avoid flickering during display updates.
     * </para>
     * </summary>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int triggerRefresh()
    {
        this._frozenUntil = 0;
        this.flushLayers();
        return this.sendCommand("H0");
    }


    /**
     * <summary>
     *   Smoothly changes the brightness of the screen to produce a fade-in or fade-out
     *   effect.
     * <para>
     * </para>
     * </summary>
     * <param name="brightness">
     *   the new screen brightness
     * </param>
     * <param name="duration">
     *   duration of the brightness transition, in milliseconds.
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int fade(int brightness, int duration)
    {
        this.flushLayers();
        return this.sendCommand("+"+Convert.ToString(brightness)+","+Convert.ToString(duration));
    }


    /**
     * <summary>
     *   Starts to record all display commands into a sequence, for later replay.
     * <para>
     *   The name used to store the sequence is specified when calling
     *   <c>saveSequence()</c>, once the recording is complete.
     * </para>
     * </summary>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int newSequence()
    {
        this.flushLayers();
        this._sequence = "";
        this._recording = true;
        return YAPI.SUCCESS;
    }


    /**
     * <summary>
     *   Stops recording display commands and saves the sequence into the specified
     *   file on the display internal memory.
     * <para>
     *   The sequence can be later replayed
     *   using <c>playSequence()</c>.
     * </para>
     * </summary>
     * <param name="sequenceName">
     *   the name of the newly created sequence
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int saveSequence(string sequenceName)
    {
        this.flushLayers();
        this._recording = false;
        this._upload(sequenceName, YAPI.DefaultEncoding.GetBytes(this._sequence));
        //We need to use YPRINTF("") for Objective-C
        this._sequence = "";
        return YAPI.SUCCESS;
    }


    /**
     * <summary>
     *   Replays a display sequence previously recorded using
     *   <c>newSequence()</c> and <c>saveSequence()</c>.
     * <para>
     * </para>
     * </summary>
     * <param name="sequenceName">
     *   the name of the newly created sequence
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int playSequence(string sequenceName)
    {
        this.flushLayers();
        return this.sendCommand("S"+sequenceName);
    }


    /**
     * <summary>
     *   Waits for a specified delay (in milliseconds) before playing next
     *   commands in current sequence.
     * <para>
     *   This method can be used while
     *   recording a display sequence, to insert a timed wait in the sequence
     *   (without any immediate effect). It can also be used dynamically while
     *   playing a pre-recorded sequence, to suspend or resume the execution of
     *   the sequence. To cancel a delay, call the same method with a zero delay.
     * </para>
     * </summary>
     * <param name="delay_ms">
     *   the duration to wait, in milliseconds
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int pauseSequence(int delay_ms)
    {
        this.flushLayers();
        return this.sendCommand("W"+Convert.ToString(delay_ms));
    }


    /**
     * <summary>
     *   Stops immediately any ongoing sequence replay.
     * <para>
     *   The display is left as is.
     * </para>
     * </summary>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int stopSequence()
    {
        this.flushLayers();
        return this.sendCommand("S");
    }


    /**
     * <summary>
     *   Uploads an arbitrary file (for instance a GIF file) to the display, to the
     *   specified full path name.
     * <para>
     *   If a file already exists with the same path name,
     *   its content is overwritten.
     * </para>
     * </summary>
     * <param name="pathname">
     *   path and name of the new file to create
     * </param>
     * <param name="content">
     *   binary buffer with the content to set
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int upload(string pathname, byte[] content)
    {
        this.flushLayers();
        return this._upload(pathname, content);
    }


    /**
     * <summary>
     *   Copies the whole content of a layer to another layer.
     * <para>
     *   The color and transparency
     *   of all the pixels from the destination layer are set to match the source pixels.
     *   This method only affects the displayed content, but does not change any
     *   property of the layer object.
     *   Note that layer 0 has no transparency support (it is always completely opaque).
     * </para>
     * </summary>
     * <param name="srcLayerId">
     *   the identifier of the source layer (a number in range 0..layerCount-1)
     * </param>
     * <param name="dstLayerId">
     *   the identifier of the destination layer (a number in range 0..layerCount-1)
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int copyLayerContent(int srcLayerId, int dstLayerId)
    {
        this.flushLayers();
        return this.sendCommand("o"+Convert.ToString(srcLayerId)+","+Convert.ToString(dstLayerId));
    }


    /**
     * <summary>
     *   Swaps the whole content of two layers.
     * <para>
     *   The color and transparency of all the pixels from
     *   the two layers are swapped. This method only affects the displayed content, but does
     *   not change any property of the layer objects. In particular, the visibility of each
     *   layer stays unchanged. When used between one hidden layer and a visible layer,
     *   this method makes it possible to easily implement double-buffering.
     *   Note that layer 0 has no transparency support (it is always completely opaque).
     * </para>
     * </summary>
     * <param name="layerIdA">
     *   the first layer (a number in range 0..layerCount-1)
     * </param>
     * <param name="layerIdB">
     *   the second layer (a number in range 0..layerCount-1)
     * </param>
     * <returns>
     *   <c>YAPI.SUCCESS</c> if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns a negative error code.
     * </para>
     */
    public virtual int swapLayerContent(int layerIdA, int layerIdB)
    {
        this.flushLayers();
        return this.sendCommand("E"+Convert.ToString(layerIdA)+","+Convert.ToString(layerIdB));
    }


    /**
     * <summary>
     *   Returns a YDisplayLayer object that can be used to draw on the specified
     *   layer.
     * <para>
     *   The content is displayed only when the layer is active on the
     *   screen (and not masked by other overlapping layers).
     * </para>
     * </summary>
     * <param name="layerId">
     *   the identifier of the layer (a number in range 0..layerCount-1)
     * </param>
     * <returns>
     *   an <c>YDisplayLayer</c> object
     * </returns>
     * <para>
     *   On failure, throws an exception or returns <c>null</c>.
     * </para>
     */
    public virtual YDisplayLayer get_displayLayer(int layerId)
    {
        int layercount;
        int idx;
        layercount = this.get_layerCount();
        if (!((layerId >= 0) && (layerId < layercount))) {
            this._throw(YAPI.INVALID_ARGUMENT, "invalid DisplayLayer index");
            return null;
        }
        if (this._allDisplayLayers.Count == 0) {
            idx = 0;
            while (idx < layercount) {
                this._allDisplayLayers.Add(new YDisplayLayer(this, idx));
                idx = idx + 1;
            }
        }
        return this._allDisplayLayers[layerId];
    }


    /**
     * <summary>
     *   Returns a color image with the current content of the display.
     * <para>
     *   The image is returned as a binary object, where each byte represents a pixel,
     *   from left to right and from top to bottom. The palette used to map byte
     *   values to RGB colors is filled into the list provided as argument.
     *   In all cases, the first palette entry (value 0) corresponds to the
     *   screen default background color.
     *   The image dimensions are given by the display width and height.
     * </para>
     * </summary>
     * <param name="palette">
     *   a list to be filled with the image palette
     * </param>
     * <returns>
     *   a binary object if the call succeeds.
     * </returns>
     * <para>
     *   On failure, throws an exception or returns an empty binary object.
     * </para>
     */
    public virtual byte[] readDisplay(List<int> palette)
    {
        byte[] zipmap = new byte[0];
        int zipsize;
        int zipwidth;
        int zipheight;
        int ziprotate;
        int zipcolors;
        int zipcol;
        int zipbits;
        int zipmask;
        int srcpos;
        int endrun;
        int srcpat;
        int srcbit;
        int srcval;
        int srcx;
        int srcy;
        int srci;
        byte[] pixmap = new byte[0];
        int pixcount;
        int pixval;
        int pixpos;
        byte[] rotmap = new byte[0];
        pixmap = new byte[0];
        // Check if the display firmware has autoInvertDelay and pixels.bin support

        if (this.get_autoInvertDelay() < 0) {
            // Old firmware, use uncompressed GIF output to rebuild pixmap
            zipmap = this._download("display.gif");
            zipsize = (zipmap).Length;
            if (zipsize == 0) {
                return pixmap;
            }
            if (!(zipsize >= 32)) {
                this._throw(YAPI.IO_ERROR, "not a GIF image");
                return pixmap;
            }
            if (!((zipmap[0] == 71) && (zipmap[2] == 70))) {
                this._throw(YAPI.INVALID_ARGUMENT, "not a GIF image");
                return pixmap;
            }
            zipwidth = zipmap[6] + 256 * zipmap[7];
            zipheight = zipmap[8] + 256 * zipmap[9];
            palette.Clear();
            zipcol = zipmap[13] * 65536 + zipmap[14] * 256 + zipmap[15];
            palette.Add(zipcol);
            zipcol = zipmap[16] * 65536 + zipmap[17] * 256 + zipmap[18];
            palette.Add(zipcol);
            pixcount = zipwidth * zipheight;
            pixmap = new byte[pixcount];
            pixpos = 0;
            srcpos = 30;
            zipsize = zipsize - 2;
            while (srcpos < zipsize) {
                // load next run size
                endrun = srcpos + 1 + zipmap[srcpos];
                srcpos = srcpos + 1;
                while (srcpos < endrun) {
                    srcval = zipmap[srcpos];
                    srcpos = srcpos + 1;
                    srcbit = 8;
                    while (srcbit != 0) {
                        if (srcbit < 3) {
                            srcval = srcval + (zipmap[srcpos] << srcbit);
                            srcpos = srcpos + 1;
                        }
                        pixval = (srcval & 7);
                        srcval = (srcval >> 3);
                        if (!((pixval > 1) && (pixval != 4))) {
                            this._throw(YAPI.INVALID_ARGUMENT, "unexpected encoding");
                            return pixmap;
                        }
                        pixmap[pixpos] = (byte)(pixval & 0xff);
                        pixpos = pixpos + 1;
                        srcbit = srcbit - 3;
                    }
                }
            }
            return pixmap;
        }
        // New firmware, use compressed pixels.bin
        zipmap = this._download("pixels.bin");
        zipsize = (zipmap).Length;
        if (zipsize == 0) {
            return pixmap;
        }
        if (!(zipsize >= 16)) {
            this._throw(YAPI.IO_ERROR, "not a pixmap");
            return pixmap;
        }
        if (!((zipmap[0] == 80) && (zipmap[2] == 88))) {
            this._throw(YAPI.INVALID_ARGUMENT, "not a pixmap");
            return pixmap;
        }
        zipwidth = zipmap[4] + 256 * zipmap[5];
        zipheight = zipmap[6] + 256 * zipmap[7];
        ziprotate = zipmap[8];
        zipcolors = zipmap[9];
        palette.Clear();
        srcpos = 10;
        srci = 0;
        while (srci < zipcolors) {
            zipcol = zipmap[srcpos] * 65536 + zipmap[srcpos+1] * 256 + zipmap[srcpos+2];
            palette.Add(zipcol);
            srcpos = srcpos + 3;
            srci = srci + 1;
        }
        zipbits = 1;
        while ((1 << zipbits) < zipcolors) {
            zipbits = zipbits + 1;
        }
        zipmask = (1 << zipbits) - 1;
        pixcount = zipwidth * zipheight;
        pixmap = new byte[pixcount];
        srcx = 0;
        srcy = 0;
        srcval = 0;
        while (srcpos < zipsize) {
            // load next compression pattern byte
            srcpat = zipmap[srcpos];
            srcpos = srcpos + 1;
            srcbit = 7;
            while (srcbit >= 0) {
                // get next bitmap byte
                if ((srcpat & 128) != 0) {
                    srcval = zipmap[srcpos];
                    srcpos = srcpos + 1;
                    if (zipbits > 1) {
                        srcval = (srcval << 8) + zipmap[srcpos];
                        srcpos = srcpos + 1;
                    }
                }
                srcpat = (srcpat << 1);
                pixpos = srcy * zipwidth + srcx;
                // produce 8 pixels
                srci = 7 * zipbits;
                while (srci >= 0) {
                    pixval = ((srcval >> srci) & zipmask);
                    pixmap[pixpos] = (byte)(pixval & 0xff);
                    pixpos = pixpos + 1;
                    srci = srci - zipbits;
                }
                srcy = srcy + 1;
                if (srcy >= zipheight) {
                    srcy = 0;
                    srcx = srcx + 8;
                    // drop last bytes if image is not a multiple of 8
                    if (srcx >= zipwidth) {
                        srcbit = 0;
                    }
                }
                srcbit = srcbit - 1;
            }
        }
        // rotate pixmap to match display orientation
        if (ziprotate == 0) {
            return pixmap;
        }
        if ((ziprotate & 2) != 0) {
            // rotate buffer 180 degrees by swapping pixels
            srcpos = 0;
            pixpos = pixcount - 1;
            while (srcpos < pixpos) {
                pixval = pixmap[srcpos];
                pixmap[srcpos] = (byte)(pixmap[pixpos] & 0xff);
                pixmap[pixpos] = (byte)(pixval & 0xff);
                srcpos = srcpos + 1;
                pixpos = pixpos - 1;
            }
        }
        if ((ziprotate & 1) == 0) {
            return pixmap;
        }
        // rotate 90 ccw: first pixel is bottom left
        rotmap = new byte[pixcount];
        srcx = 0;
        srcy = zipwidth - 1;
        srcpos = 0;
        while (srcpos < pixcount) {
            pixval = pixmap[srcpos];
            pixpos = srcy * zipheight + srcx;
            rotmap[pixpos] = (byte)(pixval & 0xff);
            srcy = srcy - 1;
            if (srcy < 0) {
                srcx = srcx + 1;
                srcy = zipwidth - 1;
            }
            srcpos = srcpos + 1;
        }
        return rotmap;
    }


    public virtual byte[] gifEncode(byte[] pixmap, List<int> palette, int w, bool shortHdr)
    {
        int minCodeSize;
        int LZW_CLRCODE;
        int LZW_ENDCODE;
        int LZW_1STCODE;
        int codeSize;
        int maxCode;
        List<int> codes = new List<int>();
        int nCodes;
        int pixmapSize;
        byte[] dataStream = new byte[0];
        int blockStart;
        int blockEnd;
        int prevCode;
        int pixPos;
        int wrBits;
        int wrBitCnt;
        int outPos;
        int nextVal;
        int i;
        int hdrSize;
        byte[] res = new byte[0];
        int h;

        if (palette.Count > 8) {
            this._throw(YAPI.INVALID_ARGUMENT, "Palette should have no more than 8 colors");
            res = new byte[0];
            return res;
        }
        if (palette.Count <= 4) {
            minCodeSize = 2;
        } else {
            minCodeSize = 3;
        }
        LZW_CLRCODE = (1 << minCodeSize);
        LZW_ENDCODE = LZW_CLRCODE + 1;
        LZW_1STCODE = LZW_ENDCODE + 1;
        codeSize = minCodeSize + 1;
        maxCode = (1 << codeSize) - 1 - LZW_1STCODE;
        codes.Clear();
        nCodes = 0;
        pixmapSize = (pixmap).Length;
        dataStream = new byte[((2 * pixmapSize) / 3) + 8];
        outPos = 0;
        wrBits = LZW_CLRCODE;
        wrBitCnt = 3;
        // prefetch first byte
        prevCode = pixmap[0];
        pixPos = 1;
        while (pixPos < pixmapSize + 3) {
            blockStart = outPos;
            outPos = blockStart + 1;
            blockEnd = blockStart + 256;
            // flush any carry-over output byte from previous data sub-block
            while (wrBitCnt >= 8) {
                dataStream[outPos] = (byte)((wrBits & 0xff) & 0xff);
                outPos = outPos + 1;
                wrBits = (wrBits >> 8);
                wrBitCnt = wrBitCnt - 8;
            }
            while ((outPos < blockEnd) && (pixPos < pixmapSize)) {
                // search for an existing code matching the running input segment
                // printf("[%d] ", rdBits >> 12);
                nextVal = (prevCode | (pixmap[pixPos] << 12));
                pixPos = pixPos + 1;
                if (prevCode < LZW_1STCODE) {
                    i = 0;
                } else {
                    i = prevCode - LZW_ENDCODE;
                }
                while ((i < nCodes) && (codes[i] != nextVal)) {
                    i = i + 1;
                }
                if (i >= nCodes) {
                    // not found, emit prevCode and create new code
                    wrBits = (wrBits | (prevCode << wrBitCnt));
                    wrBitCnt = wrBitCnt + codeSize;
                    if (nCodes <= maxCode) {
                        //fprintf(stderr, "#%d: #%d + %d\n", nextCode, nextVal & 63, nextVal >> 6);
                        codes.Add(nextVal);
                        nCodes = nCodes + 1;
                    } else {
                        codeSize = codeSize + 1;
                        if (codeSize <= 12) {
                            //fprintf(stderr, "#%d: #%d + %d\n", nextCode, nextVal & 63, nextVal >> 6);
                            codes.Add(nextVal);
                            nCodes = nCodes + 1;
                        } else {
                            wrBits = (wrBits | (LZW_CLRCODE << wrBitCnt));
                            wrBitCnt = wrBitCnt + codeSize;
                            codes.Clear();
                            nCodes = 0;
                            codeSize = minCodeSize + 1;
                        }
                        maxCode = (1 << codeSize) - 1 - LZW_1STCODE;
                    }
                    // flush one (or two) codes to output stream
                    while ((wrBitCnt >= 8) && (outPos < blockEnd)) {
                        dataStream[outPos] = (byte)((wrBits & 0xff) & 0xff);
                        outPos = outPos + 1;
                        wrBits = (wrBits >> 8);
                        wrBitCnt = wrBitCnt - 8;
                    }
                    prevCode = (nextVal >> 12);
                } else {
                    prevCode = i + LZW_1STCODE;
                }
            }
            if (pixPos >= pixmapSize) {
                if ((outPos < blockEnd) && (pixPos == pixmapSize)) {
                    // append code for last run
                    wrBits = (wrBits | (prevCode << wrBitCnt));
                    wrBitCnt = wrBitCnt + codeSize;
                    while ((wrBitCnt >= 8) && (outPos < blockEnd)) {
                        dataStream[outPos] = (byte)((wrBits & 0xff) & 0xff);
                        outPos = outPos + 1;
                        wrBits = (wrBits >> 8);
                        wrBitCnt = wrBitCnt - 8;
                    }
                    pixPos = pixPos + 1;
                }
                if ((outPos < blockEnd) && (pixPos == pixmapSize + 1)) {
                    // append end code
                    wrBits = (wrBits | (LZW_ENDCODE << wrBitCnt));
                    wrBitCnt = wrBitCnt + codeSize;
                    while ((wrBitCnt >= 8) && (outPos < blockEnd)) {
                        dataStream[outPos] = (byte)((wrBits & 0xff) & 0xff);
                        outPos = outPos + 1;
                        wrBits = (wrBits >> 8);
                        wrBitCnt = wrBitCnt - 8;
                    }
                    pixPos = pixPos + 1;
                }
                if ((outPos < blockEnd) && (pixPos == pixmapSize + 2)) {
                    // flush last 0-7 bits
                    if (wrBitCnt > 0) {
                        dataStream[outPos] = (byte)((wrBits & 0xff) & 0xff);
                        outPos = outPos + 1;
                        wrBitCnt = 0;
                    }
                    pixPos = pixPos + 1;
                }
            }
            dataStream[blockStart] = (byte)(outPos - (blockStart + 1) & 0xff);
        }
        blockEnd = outPos;
        // Now write final buffer
        hdrSize = 24 + LZW_CLRCODE * 3;
        res = new byte[hdrSize + outPos + 2];
        // GIF89a header
        res[0x00] = (byte)(0x47 & 0xff);
        res[0x01] = (byte)(0x49 & 0xff);
        res[0x02] = (byte)(0x46 & 0xff);
        res[0x03] = (byte)(0x38 & 0xff);
        res[0x04] = (byte)(0x39 & 0xff);
        res[0x05] = (byte)(0x61 & 0xff);
        // Logical screen descriptor
        h = (((pixmap).Length) / w);
        res[0x06] = (byte)((w & 0xff) & 0xff);
        res[0x07] = (byte)((w >> 8) & 0xff);
        res[0x08] = (byte)((h & 0xff) & 0xff);
        res[0x09] = (byte)((h >> 8) & 0xff);
        res[0x0a] = (byte)(0xf0 + minCodeSize - 1 & 0xff);
        res[0x0b] = (byte)(0 & 0xff);
        res[0x0c] = (byte)(0 & 0xff);
        // Palette
        outPos = 0x0d;
        i = 0;
        while (i < LZW_CLRCODE) {
            if (i < palette.Count) {
                wrBits = palette[i];
                res[outPos] = (byte)(((wrBits >> 16) & 0xff) & 0xff);
                res[outPos + 1] = (byte)(((wrBits >> 8) & 0xff) & 0xff);
                res[outPos + 2] = (byte)((wrBits & 0xff) & 0xff);
            }
            outPos = outPos + 3;
            i = i + 1;
        }
        // Image descriptor
        res[outPos] = (byte)(0x2c & 0xff);
        res[outPos + 5] = (byte)((w & 0xff) & 0xff);
        res[outPos + 6] = (byte)((w >> 8) & 0xff);
        res[outPos + 7] = (byte)((h & 0xff) & 0xff);
        res[outPos + 8] = (byte)((h >> 8) & 0xff);
        outPos = outPos + 10;
        // Prepare to append Image data
        res[outPos] = (byte)(minCodeSize & 0xff);
        i = 0;
        while (i < blockEnd) {
            outPos = outPos + 1;
            res[outPos] = (byte)(dataStream[i] & 0xff);
            i = i + 1;
        }
        // Append zero-block and trailer
        outPos = outPos + 1;
        res[outPos] = (byte)(0 & 0xff);
        outPos = outPos + 1;
        res[outPos] = (byte)(0x3b & 0xff);
        return res;
    }

    /**
     * <summary>
     *   Continues the enumeration of displays started using <c>yFirstDisplay()</c>.
     * <para>
     *   Caution: You can't make any assumption about the returned displays order.
     *   If you want to find a specific a display, use <c>Display.findDisplay()</c>
     *   and a hardwareID or a logical name.
     * </para>
     * </summary>
     * <returns>
     *   a pointer to a <c>YDisplay</c> object, corresponding to
     *   a display currently online, or a <c>null</c> pointer
     *   if there are no more displays to enumerate.
     * </returns>
     */
    public YDisplay nextDisplay()
    {
        string hwid = "";
        if (YAPI.YISERR(_nextFunction(ref hwid)))
            return null;
        if (hwid == "")
            return null;
        return FindDisplay(hwid);
    }

    //--- (end of generated code: YDisplay implementation)

    //--- (generated code: YDisplay functions)

    /**
     * <summary>
     *   Starts the enumeration of displays currently accessible.
     * <para>
     *   Use the method <c>YDisplay.nextDisplay()</c> to iterate on
     *   next displays.
     * </para>
     * </summary>
     * <returns>
     *   a pointer to a <c>YDisplay</c> object, corresponding to
     *   the first display currently online, or a <c>null</c> pointer
     *   if there are none.
     * </returns>
     */
    public static YDisplay FirstDisplay()
    {
        YFUN_DESCR[] v_fundescr = new YFUN_DESCR[1];
        YDEV_DESCR dev = default(YDEV_DESCR);
        int neededsize = 0;
        int err = 0;
        string serial = null;
        string funcId = null;
        string funcName = null;
        string funcVal = null;
        string errmsg = "";
        int size = Marshal.SizeOf(v_fundescr[0]);
        IntPtr p = Marshal.AllocHGlobal(Marshal.SizeOf(v_fundescr[0]));
        err = YAPI.apiGetFunctionsByClass("Display", 0, p, size, ref neededsize, ref errmsg);
        Marshal.Copy(p, v_fundescr, 0, 1);
        Marshal.FreeHGlobal(p);
        if ((YAPI.YISERR(err) | (neededsize == 0)))
            return null;
        serial = "";
        funcId = "";
        funcName = "";
        funcVal = "";
        errmsg = "";
        if ((YAPI.YISERR(YAPI.yapiGetFunctionInfo(v_fundescr[0], ref dev, ref serial, ref funcId, ref funcName, ref funcVal, ref errmsg))))
            return null;
        return FindDisplay(serial + "." + funcId);
    }

    //--- (end of generated code: YDisplay functions)
}
#pragma warning restore 1591

}
