Working on GP1212A02 support.
authorsl
Mon, 25 Aug 2014 00:07:01 +0200
changeset 101c3a4964a5bd
parent 9 6b08e3e81cf3
child 11 2d749a2bea34
Working on GP1212A02 support.
Display.h
FutabaGP1212A01.cpp
FutabaGP1212A01.h
FutabaGP1212A02.cpp
FutabaGP1212A02.h
FutabaVfd.h
MiniDisplay.cpp
     1.1 --- a/Display.h	Thu Aug 21 21:53:35 2014 +0200
     1.2 +++ b/Display.h	Mon Aug 25 00:07:01 2014 +0200
     1.3 @@ -11,6 +11,8 @@
     1.4  class DisplayBase
     1.5  	{
     1.6  public:
     1.7 +	virtual ~DisplayBase(){};
     1.8 +	//
     1.9  	virtual int Open()=0;
    1.10  	virtual void Close()=0;
    1.11  	//
    1.12 @@ -18,6 +20,9 @@
    1.13  	virtual int MaxBrightness() const=0;
    1.14  	virtual void SetBrightness(int aBrightness)=0;
    1.15  	virtual void Clear()=0;
    1.16 +	virtual void Fill()=0;
    1.17 +	//
    1.18 +	virtual void SwapBuffers()=0;
    1.19  	};
    1.20  
    1.21  
     2.1 --- a/FutabaGP1212A01.cpp	Thu Aug 21 21:53:35 2014 +0200
     2.2 +++ b/FutabaGP1212A01.cpp	Mon Aug 25 00:07:01 2014 +0200
     2.3 @@ -144,6 +144,15 @@
     2.4      }
     2.5  
     2.6  /**
     2.7 +Turn on all pixels.
     2.8 +Must be followed by a SwapBuffers call.
     2.9 +*/
    2.10 +void GP1212A01A::Fill()
    2.11 +	{
    2.12 +	SetAllPixels(0xFF);
    2.13 +	}
    2.14 +
    2.15 +/**
    2.16  Set all pixels on our screen to the desired value.
    2.17  This operation is performed off screen to avoid tearing.
    2.18  @param 8 pixels pattern
     3.1 --- a/FutabaGP1212A01.h	Thu Aug 21 21:53:35 2014 +0200
     3.2 +++ b/FutabaGP1212A01.h	Mon Aug 25 00:07:01 2014 +0200
     3.3 @@ -32,6 +32,7 @@
     3.4  	//From FutabaVfd
     3.5  	virtual void SetBrightness(int aBrightness);
     3.6  	virtual void Clear();
     3.7 +	virtual void Fill();
     3.8  
     3.9  	//Specific to GP1212A01A
    3.10  	void SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char aValue);
     4.1 --- a/FutabaGP1212A02.cpp	Thu Aug 21 21:53:35 2014 +0200
     4.2 +++ b/FutabaGP1212A02.cpp	Mon Aug 25 00:07:01 2014 +0200
     4.3 @@ -2,4 +2,677 @@
     4.4  //
     4.5  //
     4.6  
     4.7 -#include "FutabaGP1212A02.h"
     4.8 \ No newline at end of file
     4.9 +#include "FutabaGP1212A02.h"
    4.10 +
    4.11 +
    4.12 +const int KNumberOfFrameBeforeDiffAlgo = 3;
    4.13 +
    4.14 +//
    4.15 +// class GP1212A02A
    4.16 +//
    4.17 +
    4.18 +GP1212A02A::GP1212A02A():
    4.19 +	iDisplayPositionX(0),iDisplayPositionY(0),
    4.20 +    iOffScreenMode(true),
    4.21 +    iUseFrameDifferencing(true),
    4.22 +    iFrameNext(NULL),
    4.23 +    iFrameCurrent(NULL),
    4.24 +    iFramePrevious(NULL),
    4.25 +    iFrameAlpha(NULL),
    4.26 +    iFrameBeta(NULL),
    4.27 +    iFrameGamma(NULL),
    4.28 +    iNeedFullFrameUpdate(0),
    4.29 +    iRequest(EMiniDisplayRequestNone),iPowerOn(false)
    4.30 +	{
    4.31 +	iDeviceId[0]=0;
    4.32 +	iFirmwareRevision[0]=0;
    4.33 +	//ResetBuffers();
    4.34 +	}
    4.35 +
    4.36 +/**
    4.37 +*/
    4.38 +GP1212A02A::~GP1212A02A()
    4.39 +	{
    4.40 +    delete iFrameAlpha;
    4.41 +    iFrameAlpha=NULL;
    4.42 +    //
    4.43 +    delete iFrameBeta;
    4.44 +    iFrameBeta=NULL;
    4.45 +    //
    4.46 +    delete iFrameGamma;
    4.47 +    iFrameGamma=NULL;
    4.48 +    //
    4.49 +    iFrameNext=NULL;
    4.50 +    iFrameCurrent=NULL;
    4.51 +    iFramePrevious=NULL;
    4.52 +    //
    4.53 +    iNeedFullFrameUpdate=0;
    4.54 +	}
    4.55 +
    4.56 +/**
    4.57 +*/
    4.58 +int GP1212A02A::Open()
    4.59 +	{
    4.60 +	int success = HidDevice::Open(KFutabaVendorId,KFutabaProductIdGP1212A02A,NULL);
    4.61 +	if (success)
    4.62 +		{
    4.63 +        //Allocate both frames
    4.64 +        delete iFrameAlpha;
    4.65 +        iFrameAlpha=NULL;
    4.66 +        iFrameAlpha=new BitArray(KGP12xFrameBufferPixelCount);
    4.67 +        //
    4.68 +        delete iFrameBeta;
    4.69 +        iFrameBeta=NULL;
    4.70 +        iFrameBeta=new BitArray(KGP12xFrameBufferPixelCount);
    4.71 +        //
    4.72 +        delete iFrameGamma;
    4.73 +        iFrameGamma=NULL;
    4.74 +        iFrameGamma=new BitArray(KGP12xFrameBufferPixelCount);
    4.75 +        //
    4.76 +        iFrameNext=iFrameAlpha;
    4.77 +        iFrameCurrent=iFrameBeta;
    4.78 +        iFramePrevious=iFrameGamma;
    4.79 +
    4.80 +
    4.81 +        //To make sure it is synced properly
    4.82 +        iNeedFullFrameUpdate=0;
    4.83 +        //
    4.84 +		SetNonBlocking(1);
    4.85 +        //Since we can't get our display position we force it to our default
    4.86 +		//This makes sure frames are in sync from the start
    4.87 +        //Clever clients will have taken care of putting back frame (0,0) before closing
    4.88 +		SetDisplayPosition(iDisplayPositionX,iDisplayPositionY);
    4.89 +		}
    4.90 +	return success;
    4.91 +	}
    4.92 +
    4.93 +/**
    4.94 +*/
    4.95 +void GP1212A02A::SetPixel(unsigned char aX, unsigned char aY, bool aOn)
    4.96 +	{
    4.97 +	//
    4.98 +	//int byteOffset=(aX*HeightInPixels()+aY)/8;
    4.99 +	//int bitOffset=(aX*HeightInPixels()+aY)%8;
   4.100 +    //iNextFrame[byteOffset] |= ( (aOn?0x01:0x00) << bitOffset );
   4.101 +
   4.102 +    if (iOffScreenMode)
   4.103 +        {
   4.104 +        if (aOn)
   4.105 +            {
   4.106 +            iFrameNext->SetBit(aX*HeightInPixels()+aY);
   4.107 +            }
   4.108 +        else
   4.109 +            {
   4.110 +            iFrameNext->ClearBit(aX*HeightInPixels()+aY);
   4.111 +            }
   4.112 +        }
   4.113 +    else
   4.114 +        {
   4.115 +        //Just specify a one pixel block
   4.116 +        SetPixelBlock(aX,aY,0x00,0x01,aOn);
   4.117 +        }
   4.118 +	}
   4.119 +
   4.120 +/**
   4.121 +*/
   4.122 +void GP1212A02A::BitBlit(const BitArray& aBitmap, int aSrcWidth, int aSrcHeight, int aTargetX, int aTargetY) const
   4.123 +	{
   4.124 +	//TODO: amend loop values so that we don't keep on looping past our frame buffer dimensions.
   4.125 +	for (int i=0;i<aSrcWidth;i++)
   4.126 +		{
   4.127 +		for (int j=0;j<aSrcHeight;j++)
   4.128 +			{
   4.129 +            iFrameNext->SetBitValue((aTargetX+i)*HeightInPixels()+aTargetY+j,aBitmap[+i*aSrcHeight+j]);
   4.130 +			}
   4.131 +		}
   4.132 +	}
   4.133 +
   4.134 +/**
   4.135 +Clear our client side back buffer.
   4.136 +Call to SwapBuffers must follow to actually clear the display.
   4.137 +*/
   4.138 +void GP1212A02A::Clear()
   4.139 +    {
   4.140 +    //memset(iNextFrame->Ptr(),0x00,FrameBufferSizeInBytes());
   4.141 +    if (iOffScreenMode)
   4.142 +        {
   4.143 +        iFrameNext->ClearAll();
   4.144 +        }
   4.145 +    else
   4.146 +        {
   4.147 +        SendClearCommand();
   4.148 +        }
   4.149 +    }
   4.150 +
   4.151 +/**
   4.152 +Turn on all pixels.
   4.153 +Must be followed by a SwapBuffers call.
   4.154 +*/
   4.155 +void GP1212A02A::Fill()
   4.156 +	{
   4.157 +	SetAllPixels(0xFF);
   4.158 +	}
   4.159 +
   4.160 +/**
   4.161 +Set all pixels on our screen to the desired value.
   4.162 +This operation is performed off screen to avoid tearing.
   4.163 +@param 8 pixels pattern
   4.164 +*/
   4.165 +void GP1212A02A::SetAllPixels(unsigned char aPattern)
   4.166 +	{
   4.167 +	//With a single buffer
   4.168 +	//unsigned char screen[2048]; //One screen worth of pixels
   4.169 +	//memset(screen,0xFF,sizeof(screen));
   4.170 +	//SetPixelBlock(0,0,63,sizeof(screen),screen);
   4.171 +
   4.172 +
   4.173 +    if (iOffScreenMode)
   4.174 +        {
   4.175 +        memset(iFrameNext->Ptr(),aPattern,FrameBufferSizeInBytes());
   4.176 +        }
   4.177 +    else
   4.178 +        {
   4.179 +        //Using pattern SetPixelBlock variant.
   4.180 +        SetPixelBlock(0,0,63,FrameBufferSizeInBytes(),aPattern);
   4.181 +        }
   4.182 +	//
   4.183 +	}
   4.184 +
   4.185 +
   4.186 +/**
   4.187 +Set the defined pixel block to the given value.
   4.188 +@param X coordinate of our pixel block starting point.
   4.189 +@param Y coordinate of our pixel block starting point.
   4.190 +@param The height of our pixel block.
   4.191 +@param The size of our pixel data. Number of pixels divided by 8.
   4.192 +@param The value set to 8 pixels used as a pattern.
   4.193 +*/
   4.194 +void GP1212A02A::SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char aValue)
   4.195 +	{
   4.196 +	OffScreenTranslation(aX,aY);
   4.197 +    FutabaVfdReport report;
   4.198 +    report[0]=0x00; //Report ID
   4.199 +    report[1]=(aSize<=report.Size()-10?aSize+0x08:64); //Report length. -10 is for our header first 10 bytes. +8 is for our Futaba header size
   4.200 +    report[2]=0x1B; //Command ID
   4.201 +    report[3]=0x5B; //Command ID
   4.202 +    report[4]=0xF0; //Command ID
   4.203 +    report[5]=aX;   //X
   4.204 +    report[6]=aY;   //Y
   4.205 +    report[7]=aHeight; //Y length before return. Though outside the specs, setting this to zero apparently allows us to modify a single pixel without touching any other.
   4.206 +	report[8]=aSize>>8; //Size of pixel data in bytes (MSB)
   4.207 +	report[9]=aSize;	//Size of pixel data in bytes (LSB)
   4.208 +    int sizeWritten=MIN(aSize,report.Size()-10);
   4.209 +    memset(report.Buffer()+10, aValue, sizeWritten);
   4.210 +    Write(report);
   4.211 +
   4.212 +    int remainingSize=aSize;
   4.213 +    //We need to keep on sending our pixel data until we are done
   4.214 +    while (report[1]==64)
   4.215 +        {
   4.216 +        report.Reset();
   4.217 +        remainingSize-=sizeWritten;
   4.218 +        report[0]=0x00; //Report ID
   4.219 +        report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
   4.220 +        sizeWritten=(report[1]==64?63:report[1]);
   4.221 +        memset(report.Buffer()+2, aValue, sizeWritten);
   4.222 +        Write(report);
   4.223 +        }
   4.224 +	}
   4.225 +
   4.226 +/**
   4.227 +Set the defined pixel block to the given value.
   4.228 +@param X coordinate of our pixel block starting point.
   4.229 +@param Y coordinate of our pixel block starting point.
   4.230 +@param The height of our pixel block.
   4.231 +@param The size of our pixel data. Number of pixels divided by 8.
   4.232 +@param Pointer to our pixel data.
   4.233 +*/
   4.234 +void GP1212A02A::SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char* aPixels)
   4.235 +    {
   4.236 +	OffScreenTranslation(aX,aY);
   4.237 +    FutabaVfdReport report;
   4.238 +    report[0]=0x00; //Report ID
   4.239 +    report[1]=(aSize<=report.Size()-10?aSize+0x08:64); //Report length. -10 is for our header first 10 bytes. +8 is for our Futaba header size
   4.240 +    report[2]=0x1B; //Command ID
   4.241 +    report[3]=0x5B; //Command ID
   4.242 +    report[4]=0xF0; //Command ID
   4.243 +    report[5]=aX;   //X
   4.244 +    report[6]=aY;   //Y
   4.245 +    report[7]=aHeight; //Y length before return. Though outside the specs, setting this to zero apparently allows us to modify a single pixel without touching any other.
   4.246 +	report[8]=aSize>>8; //Size of pixel data in bytes (MSB)
   4.247 +	report[9]=aSize;	//Size of pixel data in bytes (LSB)
   4.248 +    int sizeWritten=MIN(aSize,report.Size()-10);
   4.249 +    memcpy(report.Buffer()+10, aPixels, sizeWritten);
   4.250 +    Write(report);
   4.251 +
   4.252 +    int remainingSize=aSize;
   4.253 +    //We need to keep on sending our pixel data until we are done
   4.254 +    while (report[1]==64)
   4.255 +        {
   4.256 +        report.Reset();
   4.257 +        remainingSize-=sizeWritten;
   4.258 +        report[0]=0x00; //Report ID
   4.259 +        report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
   4.260 +        sizeWritten=(report[1]==64?63:report[1]);
   4.261 +        memcpy(report.Buffer()+2, aPixels+(aSize-remainingSize), sizeWritten);
   4.262 +        Write(report);
   4.263 +        }
   4.264 +    }
   4.265 +
   4.266 +/**
   4.267 +Using this function is advised against as is causes tearing.
   4.268 +Use Clear instead.
   4.269 +*/
   4.270 +void GP1212A02A::SendClearCommand()
   4.271 +	{
   4.272 +    //1BH,5BH,32H,4AH
   4.273 +    //Send Clear Display Command
   4.274 +	FutabaVfdReport report;
   4.275 +	report[0]=0x00; //Report ID
   4.276 +	report[1]=0x04; //Report length
   4.277 +	report[2]=0x1B; //Command ID
   4.278 +	report[3]=0x5B; //Command ID
   4.279 +	report[4]=0x32; //Command ID
   4.280 +	report[5]=0x4A; //Command ID
   4.281 +	Write(report);
   4.282 +	}
   4.283 +
   4.284 +/**
   4.285 +Change our display position within our buffer.
   4.286 +*/
   4.287 +void GP1212A02A::SetDisplayPosition(DW aDw,unsigned char aX, unsigned char aY)
   4.288 +    {
   4.289 +    //1BH,5BH,Dw,Px,Py
   4.290 +    //Send Display Position Settings Command
   4.291 +    FutabaVfdReport report;
   4.292 +    report[0]=0x00; //Report ID
   4.293 +    report[1]=0x05; //Report length
   4.294 +    report[2]=0x1B; //Command ID
   4.295 +    report[3]=0x5B; //Command ID
   4.296 +    report[4]=aDw;  //Specify our DW
   4.297 +    report[5]=aX;   //X coordinate of our DW top-left corner
   4.298 +    report[6]=aY;   //Y coordinate of our DW top-left corner
   4.299 +    Write(report);
   4.300 +    }
   4.301 +
   4.302 +/**
   4.303 +Change our display position within our buffer.
   4.304 +*/
   4.305 +void GP1212A02A::SetDisplayPosition(unsigned char aX, unsigned char aY)
   4.306 +	{
   4.307 +	//Specs apparently says both DW should remain the same
   4.308 +	//Just don't ask
   4.309 +    SetDisplayPosition(GP1212A02A::DW1,aX,aY);
   4.310 +    SetDisplayPosition(GP1212A02A::DW2,aX,aY);
   4.311 +	iDisplayPositionX=aX;
   4.312 +	iDisplayPositionY=aY;
   4.313 +	}
   4.314 +
   4.315 +/**
   4.316 +Provide Y coordinate of our off screen buffer.
   4.317 +*/
   4.318 +unsigned char GP1212A02A::OffScreenY() const
   4.319 +	{
   4.320 +	//Overflowing is fine this is just what we want
   4.321 +	return iDisplayPositionY+HeightInPixels();
   4.322 +	}
   4.323 +
   4.324 +/**
   4.325 +Put our off screen buffer on screen.
   4.326 +On screen buffer goes off screen.
   4.327 +*/
   4.328 +void GP1212A02A::SwapBuffers()
   4.329 +	{
   4.330 +	//Only perform buffer swapping if off screen mode is enabled
   4.331 +	if (OffScreenMode())
   4.332 +		{
   4.333 +		//Send host back buffer to device back buffer
   4.334 +        if (!iUseFrameDifferencing || iNeedFullFrameUpdate<KNumberOfFrameBeforeDiffAlgo)
   4.335 +            {
   4.336 +            iNeedFullFrameUpdate++;
   4.337 +            SetPixelBlock(0,0,63,FrameBufferSizeInBytes(),iFrameNext->Ptr());
   4.338 +            }
   4.339 +        else
   4.340 +            {
   4.341 +            //Frame diff algo is enabled
   4.342 +            //We are going to send to our device only the differences between next frame and previous frame
   4.343 +            SendModifiedPixelBlocks();
   4.344 +            }
   4.345 +		//Swap device front and back buffer
   4.346 +		SetDisplayPosition(iDisplayPositionX,OffScreenY());
   4.347 +
   4.348 +        //Cycle through our frame buffers
   4.349 +        //We keep track of previous frame which is in fact our device back buffer.
   4.350 +        //We can then compare previous and next frame and send only the differences to our device.
   4.351 +        //This mechanism allows us to reduce traffic over our USB bus thus improving our frame rate from 14 FPS to 30 FPS.
   4.352 +        //Keep our previous frame pointer
   4.353 +        BitArray* previousFrame=iFramePrevious;
   4.354 +        //Current frame becomes the previous one
   4.355 +        iFramePrevious = iFrameCurrent;
   4.356 +        //Next frame becomes the current one
   4.357 +        iFrameCurrent = iFrameNext;
   4.358 +        //Next frame is now our former previous
   4.359 +        iFrameNext = previousFrame;
   4.360 +		}
   4.361 +	}
   4.362 +
   4.363 +
   4.364 +//Define the edge of our pixel block
   4.365 +//Pixel blocks of 32x32 seems to run almost as fast as full screen update in worse case scenarii.
   4.366 +//Though I wonder if in some situations 16 could be better. Make this an attribute at some point if need be.
   4.367 +const int KPixelBlockEdge = 32;
   4.368 +const int KPixelBlockSizeInBits = KPixelBlockEdge*KPixelBlockEdge;
   4.369 +const int KPixelBlockSizeInBytes = KPixelBlockSizeInBits/8;
   4.370 +
   4.371 +
   4.372 +/**
   4.373 + * @brief GP1212A02A::SendModifiedPixelBlocks
   4.374 + * Compare our back and front buffer and send to the device only the modified pixels.
   4.375 + */
   4.376 +void GP1212A02A::SendModifiedPixelBlocks()
   4.377 +    {
   4.378 +    int w=WidthInPixels();
   4.379 +    int h=HeightInPixels();
   4.380 +
   4.381 +
   4.382 +    //TODO: optimize with memcmp and 16 inc
   4.383 +    /*
   4.384 +
   4.385 +    for (int i=0;i<w;i++)
   4.386 +        {
   4.387 +        for (int j=0;j<h;j++)
   4.388 +            {
   4.389 +            //aX*HeightInPixels()+aY
   4.390 +            if ((*iFrameNext)[i*h+j]!=(*iFramePrevious)[i*h+j])
   4.391 +                {
   4.392 +                //We need to update that pixel
   4.393 +                SetPixelBlock(i,j,0,1,((*iFrameNext)[i*h+j]?0x01:0x00));
   4.394 +                //SetDisplayPosition(iDisplayPositionX,OffScreenY());
   4.395 +                //SetDisplayPosition(iDisplayPositionX,OffScreenY());
   4.396 +
   4.397 +                //SetPixelBlock(i,j,15,32,iNextFrame->Ptr()+offset);
   4.398 +                }
   4.399 +            }
   4.400 +        }
   4.401 +    */
   4.402 +
   4.403 +    BitArray nextBlock(KPixelBlockSizeInBits);
   4.404 +    BitArray previousBlock(KPixelBlockSizeInBits);
   4.405 +
   4.406 +    for (int i=0;i<w;i+=KPixelBlockEdge)
   4.407 +        {
   4.408 +        for (int j=0;j<h;j+=KPixelBlockEdge)
   4.409 +            {
   4.410 +            //aX*HeightInPixels()+aY
   4.411 +            //int offset=(i*w/8)+(j/8);
   4.412 +
   4.413 +#ifdef DEBUG_FRAME_DIFF
   4.414 +            QImage imagePrevious(KPixelBlockEdge,KPixelBlockEdge,QImage::Format_RGB32);
   4.415 +            QImage imageNext(KPixelBlockEdge,KPixelBlockEdge,QImage::Format_RGB32);
   4.416 +#endif
   4.417 +
   4.418 +            //Get both our blocks from our buffers
   4.419 +            for (int x=i;x<i+KPixelBlockEdge;x++)
   4.420 +                {
   4.421 +                for (int y=j;y<j+KPixelBlockEdge;y++)
   4.422 +                    {
   4.423 +                    int blockOffset=(x-i)*KPixelBlockEdge+(y-j);
   4.424 +                    int frameOffset=x*h+y;
   4.425 +                    nextBlock.SetBitValue(blockOffset,(*iFrameNext)[frameOffset]);
   4.426 +                    previousBlock.SetBitValue(blockOffset,(*iFramePrevious)[frameOffset]);
   4.427 +
   4.428 +#ifdef DEBUG_FRAME_DIFF
   4.429 +                    imageNext.setPixel(x-i,y-j,(nextBlock[blockOffset]?0xFFFFFFFF:0x00000000));
   4.430 +                    imagePrevious.setPixel(x-i,y-j,(previousBlock[blockOffset]?0xFFFFFFFF:0x00000000));
   4.431 +#endif
   4.432 +                    }
   4.433 +                }
   4.434 +
   4.435 +#ifdef DEBUG_FRAME_DIFF
   4.436 +            QString previousName;
   4.437 +            QString nextName;
   4.438 +            QTextStream(&previousName) << "p" << i << "x" << j << ".png";
   4.439 +            QTextStream(&nextName) << "n" << i << "x" << j << ".png";
   4.440 +            imagePrevious.save(previousName);
   4.441 +            imageNext.save(nextName);
   4.442 +#endif
   4.443 +
   4.444 +
   4.445 +            //if (memcmp(iFrameNext->Ptr()+offset,iFramePrevious->Ptr()+offset,32 )) //32=(16*16/8)
   4.446 +            if (memcmp(nextBlock.Ptr(),previousBlock.Ptr(),KPixelBlockSizeInBytes)!=0)
   4.447 +                {
   4.448 +                //We need to update that block
   4.449 +                SetPixelBlock(i,j,KPixelBlockEdge-1,KPixelBlockSizeInBytes,nextBlock.Ptr());
   4.450 +                //SetPixelBlock(i,j,15,32,0xFF/*nextBlock.Ptr()*/);
   4.451 +                //SetDisplayPosition(iDisplayPositionX,OffScreenY());
   4.452 +                //SetDisplayPosition(iDisplayPositionX,OffScreenY());
   4.453 +
   4.454 +                //SetPixelBlock(i,j,15,32,iFrameNext->Ptr()+offset);
   4.455 +                }
   4.456 +            }
   4.457 +        }
   4.458 +
   4.459 +    }
   4.460 +
   4.461 +/**
   4.462 +Translate the given pixel coordinate according to our off screen mode.
   4.463 +*/
   4.464 +void GP1212A02A::OffScreenTranslation(unsigned char& aX, unsigned char& aY)
   4.465 +	{
   4.466 +	if (OffScreenMode())
   4.467 +		{
   4.468 +		aX+=WidthInPixels()-iDisplayPositionX;
   4.469 +		aY+=HeightInPixels()-iDisplayPositionY;
   4.470 +		}
   4.471 +	}
   4.472 +
   4.473 +
   4.474 +/**
   4.475 +*/
   4.476 +void GP1212A02A::ResetBuffers()
   4.477 +	{
   4.478 +    //iNextFrame->ClearAll();
   4.479 +    //memset(iFrameAlpha,0x00,sizeof(iFrameAlpha));
   4.480 +	//memset(iFrameBeta,0x00,sizeof(iFrameBeta));
   4.481 +	}
   4.482 +
   4.483 +/**
   4.484 +*/
   4.485 +void GP1212A02A::RequestDeviceId()
   4.486 +    {
   4.487 +    if (RequestPending())
   4.488 +        {
   4.489 +        //Abort silently for now
   4.490 +        return;
   4.491 +        }
   4.492 +
   4.493 +    //1BH,5BH,63H,49H,44H
   4.494 +    //Send Read ID command
   4.495 +    FutabaVfdReport report;
   4.496 +    report[0]=0x00; //Report ID
   4.497 +    report[1]=0x05; //Report length
   4.498 +    report[2]=0x1B; //Command ID
   4.499 +    report[3]=0x5B; //Command ID
   4.500 +    report[4]=0x63; //Command ID
   4.501 +    report[5]=0x49; //Command ID
   4.502 +    report[6]=0x44; //Command ID
   4.503 +    if (Write(report)==report.Size())
   4.504 +        {
   4.505 +        iRequest=EMiniDisplayRequestDeviceId;
   4.506 +        }
   4.507 +    }
   4.508 +
   4.509 +/**
   4.510 +*/
   4.511 +void GP1212A02A::RequestFirmwareRevision()
   4.512 +    {
   4.513 +    if (RequestPending())
   4.514 +        {
   4.515 +        //Abort silently for now
   4.516 +        return;
   4.517 +        }
   4.518 +
   4.519 +    //1BH,5BH,63H,46H,52H
   4.520 +    //Send Software Revision Read Command
   4.521 +    FutabaVfdReport report;
   4.522 +    report[0]=0x00; //Report ID
   4.523 +    report[1]=0x05; //Report length
   4.524 +    report[2]=0x1B; //Command ID
   4.525 +    report[3]=0x5B; //Command ID
   4.526 +    report[4]=0x63; //Command ID
   4.527 +    report[5]=0x46; //Command ID
   4.528 +    report[6]=0x52; //Command ID
   4.529 +    if (Write(report)==report.Size())
   4.530 +        {
   4.531 +        iRequest=EMiniDisplayRequestFirmwareRevision;
   4.532 +        }
   4.533 +    }
   4.534 +
   4.535 +/**
   4.536 +*/
   4.537 +void GP1212A02A::RequestPowerSupplyStatus()
   4.538 +    {
   4.539 +    if (RequestPending())
   4.540 +        {
   4.541 +        //Abort silently for now
   4.542 +        return;
   4.543 +        }
   4.544 +    //1BH,5BH,63H,50H,4DH
   4.545 +    //Send Power Suppply Monitor Command
   4.546 +    FutabaVfdReport report;
   4.547 +    report[0]=0x00; //Report ID
   4.548 +    report[1]=0x05; //Report length
   4.549 +    report[2]=0x1B; //Command ID
   4.550 +    report[3]=0x5B; //Command ID
   4.551 +    report[4]=0x63; //Command ID
   4.552 +    report[5]=0x50; //Command ID
   4.553 +    report[6]=0x4D; //Command ID
   4.554 +    if (Write(report)==report.Size())
   4.555 +        {
   4.556 +        iRequest=EMiniDisplayRequestPowerSupplyStatus;
   4.557 +        }
   4.558 +    }
   4.559 +
   4.560 +
   4.561 +/**
   4.562 +This is for development purposes only.
   4.563 +Production application should stick to off-screen mode to avoid tearing.
   4.564 +*/
   4.565 +void GP1212A02A::ToggleOffScreenMode()
   4.566 +	{
   4.567 +    SetOffScreenMode(!iOffScreenMode);
   4.568 +	}
   4.569 +
   4.570 +/**
   4.571 + * @brief GP1212A02A::SetOffScreenMode
   4.572 + * @param aOn
   4.573 + * @return
   4.574 + */
   4.575 +void GP1212A02A::SetOffScreenMode(bool aOn)
   4.576 +    {
   4.577 +    if (aOn==iOffScreenMode)
   4.578 +    {
   4.579 +        //Nothing to do here
   4.580 +        return;
   4.581 +    }
   4.582 +
   4.583 +    iOffScreenMode=aOn;
   4.584 +
   4.585 +    //Clean up our buffers upon switching modes
   4.586 +    SetDisplayPosition(0,0);
   4.587 +    Clear();
   4.588 +    SwapBuffers();
   4.589 +    Clear();
   4.590 +    }
   4.591 +
   4.592 +/**
   4.593 +Tries to complete our current request if we have one pending.
   4.594 + */
   4.595 +TMiniDisplayRequest GP1212A02A::AttemptRequestCompletion()
   4.596 +    {
   4.597 +    if (!RequestPending())
   4.598 +        {
   4.599 +        return EMiniDisplayRequestNone;
   4.600 +        }
   4.601 +
   4.602 +    int res=Read(iInputReport);
   4.603 +
   4.604 +    if (!res)
   4.605 +        {
   4.606 +        return EMiniDisplayRequestNone;
   4.607 +        }
   4.608 +
   4.609 +    //Process our request
   4.610 +    if (CurrentRequest()==EMiniDisplayRequestPowerSupplyStatus)
   4.611 +        {
   4.612 +        if (iInputReport[1]==0x4F && iInputReport[2]==0x4E)
   4.613 +            {
   4.614 +            iPowerOn = true;
   4.615 +            }
   4.616 +        else if (iInputReport[1]==0x4F && iInputReport[2]==0x46 && iInputReport[3]==0x46)
   4.617 +            {
   4.618 +            iPowerOn = false;
   4.619 +            }
   4.620 +        }
   4.621 +	else if (CurrentRequest()==EMiniDisplayRequestDeviceId)
   4.622 +		{
   4.623 +			unsigned char* ptr=&iInputReport[1];
   4.624 +			strcpy(iDeviceId,(const char*)ptr);
   4.625 +		}
   4.626 +	else if (CurrentRequest()==EMiniDisplayRequestFirmwareRevision)
   4.627 +		{
   4.628 +			unsigned char* ptr=&iInputReport[1];
   4.629 +			strcpy(iFirmwareRevision,(const char*)ptr);
   4.630 +		}
   4.631 +
   4.632 +    TMiniDisplayRequest completed=iRequest;
   4.633 +    //Our request was completed
   4.634 +    iRequest=EMiniDisplayRequestNone;
   4.635 +
   4.636 +    return completed;
   4.637 +    }
   4.638 +
   4.639 +
   4.640 +/**
   4.641 +Set our screen brightness.
   4.642 +@param The desired brightness level. Must be between MinBrightness and MaxBrightness.
   4.643 +*/
   4.644 +void GP1212A02A::SetBrightness(int aBrightness)
   4.645 +    {
   4.646 +    if (aBrightness<MinBrightness()||aBrightness>MaxBrightness())
   4.647 +        {
   4.648 +        //Brightness out of range.
   4.649 +        //Just ignore that request.
   4.650 +        return;
   4.651 +        }
   4.652 +
   4.653 +    FutabaVfdReport report;
   4.654 +    report[0]=0x00; //Report ID
   4.655 +    report[1]=0x04; //Report size
   4.656 +    report[2]=0x1B; //Command ID
   4.657 +    report[3]=0x4A; //Command ID
   4.658 +    report[4]=0x44; //Command ID
   4.659 +    report[7]=0x30+aBrightness; //Brightness level
   4.660 +    Write(report);
   4.661 +    }
   4.662 +
   4.663 +/**
   4.664 +*/
   4.665 +bool GP1212A02A::PowerOn()
   4.666 +	{
   4.667 +	return iPowerOn;
   4.668 +	}
   4.669 +
   4.670 +/**
   4.671 +*/
   4.672 +char* GP1212A02A::DeviceId()
   4.673 +	{
   4.674 +	return iDeviceId;
   4.675 +	}
   4.676 +
   4.677 +/**
   4.678 +*/
   4.679 +char* GP1212A02A::FirmwareRevision()
   4.680 +	{
   4.681 +	return iFirmwareRevision;
   4.682 +	}
     5.1 --- a/FutabaGP1212A02.h	Thu Aug 21 21:53:35 2014 +0200
     5.2 +++ b/FutabaGP1212A02.h	Mon Aug 25 00:07:01 2014 +0200
     5.3 @@ -7,6 +7,109 @@
     5.4  
     5.5  #include "FutabaGP1212.h"
     5.6  
     5.7 +#include "FutabaGP1212.h"
     5.8 +#include "FutabaVfd.h"
     5.9 +
    5.10 +/**
    5.11 +GP1212A01A is a graphic display module using a FUTABA 256x64dots VFD.
    5.12 +The module do not include character ROM, the customer will compile the character
    5.13 +by themselves (from main system).
    5.14 +*/
    5.15 +class GP1212A02A : public GP1212XXXX
    5.16 +	{
    5.17 +public:
    5.18 +
    5.19 +    GP1212A02A();
    5.20 +    ~GP1212A02A();
    5.21 +
    5.22 +	//From DisplayBase
    5.23 +	int Open();
    5.24 +	virtual void SwapBuffers();
    5.25 +
    5.26 +	//From GraphicDisplay
    5.27 +	virtual void SetPixel(unsigned char aX, unsigned char aY, bool aOn);
    5.28 +	virtual void SetAllPixels(unsigned char aPattern);
    5.29 +    virtual int FrameBufferSizeInBytes() const {return KGP12xFrameBufferSizeInBytes;}
    5.30 +    virtual void BitBlit(const BitArray& aBitmap, int aSrcWidth, int aSrcHeight, int aTargetX, int aTargetY) const;
    5.31 +	virtual void SetBrightness(int aBrightness);
    5.32 +	virtual void Clear();
    5.33 +	virtual void Fill();
    5.34 +
    5.35 +	//Specific to GP1212A01A
    5.36 +	void SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char aValue);
    5.37 +    void SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char* aPixels);
    5.38 +    //Define display position within our display RAM
    5.39 +	void SetDisplayPosition(unsigned char aX, unsigned char aY);
    5.40 +    unsigned char DisplayPositionX() const {return iDisplayPositionX;}
    5.41 +    unsigned char DisplayPositionY() const {return iDisplayPositionY;}
    5.42 +	
    5.43 +    //
    5.44 +    void RequestDeviceId();
    5.45 +    void RequestFirmwareRevision();
    5.46 +    void RequestPowerSupplyStatus();
    5.47 +	//
    5.48 +	void ToggleOffScreenMode();
    5.49 +    void SetOffScreenMode(bool aOn);
    5.50 +    bool OffScreenMode() const {return iOffScreenMode;}
    5.51 +    //
    5.52 +    void SetFrameDifferencing(bool aOn){iUseFrameDifferencing=aOn;}
    5.53 +    bool FrameDifferencing() const {return iUseFrameDifferencing;}
    5.54 +    //
    5.55 +    bool RequestPending(){return iRequest!=EMiniDisplayRequestNone;}
    5.56 +    TMiniDisplayRequest CurrentRequest(){return iRequest;}
    5.57 +    void CancelRequest(){iRequest=EMiniDisplayRequestNone;}
    5.58 +    TMiniDisplayRequest AttemptRequestCompletion();
    5.59 +    FutabaVfdReport& InputReport() {return iInputReport;}
    5.60 +    bool PowerOn();
    5.61 +	char* DeviceId();
    5.62 +	char* FirmwareRevision();
    5.63 +
    5.64 +private:
    5.65 +	enum DW
    5.66 +		{
    5.67 +        DW1=0xC0,
    5.68 +        DW2=0xD0
    5.69 +		};
    5.70 +
    5.71 +	void SetDisplayPosition(DW aDw,unsigned char aX, unsigned char aY);
    5.72 +	unsigned char OffScreenY() const;
    5.73 +	void SendClearCommand();
    5.74 +	void OffScreenTranslation(unsigned char& aX, unsigned char& aY);
    5.75 +	void ResetBuffers();
    5.76 +    void SendModifiedPixelBlocks();
    5.77 +
    5.78 +private:
    5.79 +	unsigned char iDisplayPositionX;
    5.80 +	unsigned char iDisplayPositionY;
    5.81 +	///Off screen mode is the recommended default settings to avoid tearing.
    5.82 +	///Though turning it off can be useful for debugging
    5.83 +	bool iOffScreenMode;
    5.84 +    ///Frame differences algo is used to reduce USB bus traffic and improve frame rate in typical use case
    5.85 +    bool iUseFrameDifferencing;
    5.86 +	///
    5.87 +	//FutabaVfdReport iReport;
    5.88 +	///
    5.89 +	//unsigned char iFrameBuffer[256*64];
    5.90 +    BitArray* iFrameNext;
    5.91 +    BitArray* iFrameCurrent;
    5.92 +    BitArray* iFramePrevious;
    5.93 +    //
    5.94 +    BitArray* iFrameAlpha;
    5.95 +    BitArray* iFrameBeta;
    5.96 +    BitArray* iFrameGamma;
    5.97 +    //
    5.98 +    int iNeedFullFrameUpdate;
    5.99 +	//unsigned char iFrameBeta[256*64];
   5.100 +	//unsigned char *iFrontBuffer;
   5.101 +	//unsigned char *iBackBuffer;
   5.102 +    TMiniDisplayRequest iRequest;
   5.103 +    FutabaVfdReport iInputReport;
   5.104 +	//
   5.105 +	char iDeviceId[KFutabaMaxHidReportSize];
   5.106 +	char iFirmwareRevision[KFutabaMaxHidReportSize];
   5.107 +    bool iPowerOn;
   5.108 +	};
   5.109 +
   5.110  
   5.111  
   5.112  #endif
     6.1 --- a/FutabaVfd.h	Thu Aug 21 21:53:35 2014 +0200
     6.2 +++ b/FutabaVfd.h	Mon Aug 25 00:07:01 2014 +0200
     6.3 @@ -31,7 +31,7 @@
     6.4  //Define Futaba vendor ID to filter our list of device
     6.5  const unsigned short KFutabaVendorId = 0x1008;
     6.6  const unsigned short KFutabaProductIdGP1212A01A = 0x100C;
     6.7 -const unsigned short KFutabaProductIdGP1212A02A = 0x1013; //Or is it 0x1015
     6.8 +const unsigned short KFutabaProductIdGP1212A02A = 0x1015;
     6.9  
    6.10  //typedef struct hid_device_info HidDeviceInfo;
    6.11  
     7.1 --- a/MiniDisplay.cpp	Thu Aug 21 21:53:35 2014 +0200
     7.2 +++ b/MiniDisplay.cpp	Mon Aug 25 00:07:01 2014 +0200
     7.3 @@ -1,29 +1,46 @@
     7.4  
     7.5  #include "MiniDisplay.h"
     7.6  #include "FutabaGP1212A01.h"
     7.7 -
     7.8 -
     7.9 +#include "FutabaGP1212A02.h"
    7.10  
    7.11  
    7.12  
    7.13  //Open & Close functions
    7.14  MiniDisplayDevice MiniDisplayOpen(TMiniDisplayType aType)
    7.15  	{
    7.16 -	GP1212A01A* device=NULL;
    7.17 -	device=new GP1212A01A();
    7.18 +	GraphicDisplay* device=NULL;
    7.19 +
    7.20 +	switch (aType)
    7.21 +		{
    7.22 +	case EMiniDisplayAutoDetect:
    7.23 +		//TODO
    7.24 +		device=new GP1212A01A();
    7.25 +		break;
    7.26 +
    7.27 +	case EMiniDisplayFutabaGP1212A01:
    7.28 +		device=new GP1212A01A();
    7.29 +		break;
    7.30 +		
    7.31 +	case EMiniDisplayFutabaGP1212A02:
    7.32 +		device=new GP1212A02A();
    7.33 +		break;
    7.34 +		};
    7.35 +
    7.36  	int success = device->Open();
    7.37  	if (!success)
    7.38  		{
    7.39  		delete device;
    7.40 -		return NULL;
    7.41 +		device=NULL;
    7.42  		}
    7.43  
    7.44  	return device;
    7.45  	}
    7.46  
    7.47 +//
    7.48 +
    7.49  void MiniDisplayClose(MiniDisplayDevice aDevice)
    7.50  	{
    7.51 -	delete ((GP1212A01A*)aDevice);
    7.52 +	delete ((GraphicDisplay*)aDevice);
    7.53  	}
    7.54  
    7.55  
    7.56 @@ -34,7 +51,7 @@
    7.57  		return;
    7.58  		}
    7.59  
    7.60 -	((GP1212A01A*)aDevice)->SetAllPixels(0x00);
    7.61 +	((GraphicDisplay*)aDevice)->Clear();
    7.62  	}
    7.63  
    7.64  
    7.65 @@ -45,7 +62,7 @@
    7.66  		return;
    7.67  		}
    7.68  
    7.69 -	((GP1212A01A*)aDevice)->SetAllPixels(0xFF);
    7.70 +	((GraphicDisplay*)aDevice)->Fill();
    7.71  	}
    7.72  
    7.73  
    7.74 @@ -56,7 +73,7 @@
    7.75  		return;
    7.76  		}
    7.77  
    7.78 -	((GP1212A01A*)aDevice)->SwapBuffers();
    7.79 +	((GraphicDisplay*)aDevice)->SwapBuffers();
    7.80  	}
    7.81  
    7.82  //-------------------------------------------------------------
    7.83 @@ -67,7 +84,7 @@
    7.84  		return 0;
    7.85  		}
    7.86  
    7.87 -	return ((GP1212A01A*)aDevice)->MaxBrightness();
    7.88 +	return ((GraphicDisplay*)aDevice)->MaxBrightness();
    7.89  	}
    7.90  
    7.91  //-------------------------------------------------------------
    7.92 @@ -78,7 +95,7 @@
    7.93  		return 0;
    7.94  		}
    7.95  
    7.96 -	return ((GP1212A01A*)aDevice)->MinBrightness();
    7.97 +	return ((GraphicDisplay*)aDevice)->MinBrightness();
    7.98  	}
    7.99  
   7.100  //-------------------------------------------------------------
   7.101 @@ -89,7 +106,7 @@
   7.102  		return;
   7.103  		}
   7.104  
   7.105 -	((GP1212A01A*)aDevice)->SetBrightness(aBrightness);
   7.106 +	((GraphicDisplay*)aDevice)->SetBrightness(aBrightness);
   7.107  	}
   7.108  
   7.109  //-------------------------------------------------------------
   7.110 @@ -100,7 +117,7 @@
   7.111  		return 0;
   7.112  		}
   7.113  
   7.114 -	return ((GP1212A01A*)aDevice)->WidthInPixels();
   7.115 +	return ((GraphicDisplay*)aDevice)->WidthInPixels();
   7.116  	}
   7.117  
   7.118  //-------------------------------------------------------------
   7.119 @@ -111,14 +128,14 @@
   7.120  		return 0;
   7.121  		}
   7.122  
   7.123 -	return ((GP1212A01A*)aDevice)->HeightInPixels();
   7.124 +	return ((GraphicDisplay*)aDevice)->HeightInPixels();
   7.125  	}
   7.126  
   7.127  //-------------------------------------------------------------
   7.128  void MiniDisplaySetPixel(MiniDisplayDevice aDevice, int aX, int aY, int aValue)
   7.129  	{
   7.130  	//aValue&=0x00FFFFFF; //Filter out alpha component
   7.131 -	return ((GP1212A01A*)aDevice)->SetPixel(aX,aY,aValue);
   7.132 +	return ((GraphicDisplay*)aDevice)->SetPixel(aX,aY,aValue);
   7.133  	}
   7.134  
   7.135  //-------------------------------------------------------------