FutabaGP1212A01.cpp
author StephaneLenclud
Tue, 10 Feb 2015 17:14:09 +0100
changeset 35 638eb0763e20
parent 22 ea9ccfdb5563
permissions -rw-r--r--
Liscense and Copyright fix.
sl@8
     1
//
StephaneLenclud@35
     2
// Copyright (C) 2014-2015 Stéphane Lenclud.
sl@8
     3
//
StephaneLenclud@35
     4
// This file is part of MiniDisplay.
StephaneLenclud@35
     5
//
StephaneLenclud@35
     6
// MiniDisplay is free software: you can redistribute it and/or modify
StephaneLenclud@35
     7
// it under the terms of the GNU General Public License as published by
StephaneLenclud@35
     8
// the Free Software Foundation, either version 3 of the License, or
StephaneLenclud@35
     9
// (at your option) any later version.
StephaneLenclud@35
    10
//
StephaneLenclud@35
    11
// MiniDisplay is distributed in the hope that it will be useful,
StephaneLenclud@35
    12
// but WITHOUT ANY WARRANTY; without even the implied warranty of
StephaneLenclud@35
    13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
StephaneLenclud@35
    14
// GNU General Public License for more details.
StephaneLenclud@35
    15
//
StephaneLenclud@35
    16
// You should have received a copy of the GNU General Public License
StephaneLenclud@35
    17
// along with MiniDisplay.  If not, see <http://www.gnu.org/licenses/>.
sl@8
    18
//
sl@8
    19
sl@8
    20
#include "FutabaGP1212A01.h"
sl@8
    21
sl@8
    22
const int KNumberOfFrameBeforeDiffAlgo = 3;
sl@8
    23
sl@8
    24
//
sl@8
    25
// class GP1212A01A
sl@8
    26
//
sl@8
    27
sl@8
    28
GP1212A01A::GP1212A01A():
sl@8
    29
	iDisplayPositionX(0),iDisplayPositionY(0),
sl@8
    30
    iOffScreenMode(true),
sl@8
    31
    iUseFrameDifferencing(true),
sl@8
    32
    iFrameNext(NULL),
sl@8
    33
    iFrameCurrent(NULL),
sl@8
    34
    iFramePrevious(NULL),
sl@8
    35
    iFrameAlpha(NULL),
sl@8
    36
    iFrameBeta(NULL),
sl@8
    37
    iFrameGamma(NULL),
sl@12
    38
    iNeedFullFrameUpdate(0)
sl@8
    39
	{
sl@8
    40
	//ResetBuffers();
sl@8
    41
	}
sl@8
    42
sl@8
    43
/**
sl@8
    44
*/
sl@8
    45
GP1212A01A::~GP1212A01A()
sl@8
    46
	{
sl@8
    47
    delete iFrameAlpha;
sl@8
    48
    iFrameAlpha=NULL;
sl@8
    49
    //
sl@8
    50
    delete iFrameBeta;
sl@8
    51
    iFrameBeta=NULL;
sl@8
    52
    //
sl@8
    53
    delete iFrameGamma;
sl@8
    54
    iFrameGamma=NULL;
sl@8
    55
    //
sl@8
    56
    iFrameNext=NULL;
sl@8
    57
    iFrameCurrent=NULL;
sl@8
    58
    iFramePrevious=NULL;
sl@8
    59
    //
sl@8
    60
    iNeedFullFrameUpdate=0;
sl@8
    61
	}
sl@8
    62
sl@8
    63
/**
sl@8
    64
*/
sl@8
    65
int GP1212A01A::Open()
sl@8
    66
	{
sl@8
    67
	int success = HidDevice::Open(KFutabaVendorId,KFutabaProductIdGP1212A01A,NULL);
sl@8
    68
	if (success)
sl@8
    69
		{
sl@8
    70
        //Allocate both frames
sl@8
    71
        delete iFrameAlpha;
sl@8
    72
        iFrameAlpha=NULL;
sl@13
    73
        iFrameAlpha=new BitArrayHigh(KGP12xFrameBufferPixelCount);
sl@8
    74
        //
sl@8
    75
        delete iFrameBeta;
sl@8
    76
        iFrameBeta=NULL;
sl@13
    77
        iFrameBeta=new BitArrayHigh(KGP12xFrameBufferPixelCount);
sl@8
    78
        //
sl@8
    79
        delete iFrameGamma;
sl@8
    80
        iFrameGamma=NULL;
sl@13
    81
        iFrameGamma=new BitArrayHigh(KGP12xFrameBufferPixelCount);
sl@8
    82
        //
sl@8
    83
        iFrameNext=iFrameAlpha;
sl@8
    84
        iFrameCurrent=iFrameBeta;
sl@8
    85
        iFramePrevious=iFrameGamma;
sl@8
    86
sl@8
    87
sl@8
    88
        //To make sure it is synced properly
sl@8
    89
        iNeedFullFrameUpdate=0;
sl@8
    90
        //
sl@8
    91
		SetNonBlocking(1);
sl@8
    92
        //Since we can't get our display position we force it to our default
sl@8
    93
		//This makes sure frames are in sync from the start
sl@8
    94
        //Clever clients will have taken care of putting back frame (0,0) before closing
sl@8
    95
		SetDisplayPosition(iDisplayPositionX,iDisplayPositionY);
sl@8
    96
		}
sl@8
    97
	return success;
sl@8
    98
	}
sl@8
    99
sl@8
   100
/**
sl@8
   101
*/
sl@22
   102
void GP1212A01A::SetPixel(unsigned char aX, unsigned char aY, unsigned int aPixel)
sl@8
   103
	{
sl@8
   104
	//
sl@8
   105
	//int byteOffset=(aX*HeightInPixels()+aY)/8;
sl@8
   106
	//int bitOffset=(aX*HeightInPixels()+aY)%8;
sl@8
   107
    //iNextFrame[byteOffset] |= ( (aOn?0x01:0x00) << bitOffset );
sl@8
   108
sl@22
   109
	//Pixel is on if any of the non-alpha component is not null
sl@22
   110
	bool on = (aPixel&0x00FFFFFF)!=0x00000000;
sl@22
   111
sl@8
   112
    if (iOffScreenMode)
sl@8
   113
        {
sl@22
   114
        if (on)
sl@8
   115
            {
sl@8
   116
            iFrameNext->SetBit(aX*HeightInPixels()+aY);
sl@8
   117
            }
sl@8
   118
        else
sl@8
   119
            {
sl@8
   120
            iFrameNext->ClearBit(aX*HeightInPixels()+aY);
sl@8
   121
            }
sl@8
   122
        }
sl@8
   123
    else
sl@8
   124
        {
sl@8
   125
        //Just specify a one pixel block
sl@22
   126
        SetPixelBlock(aX,aY,0x00,0x01,on);
sl@8
   127
        }
sl@8
   128
	}
sl@8
   129
sl@8
   130
/**
sl@8
   131
*/
sl@13
   132
/*
sl@8
   133
void GP1212A01A::BitBlit(const BitArray& aBitmap, int aSrcWidth, int aSrcHeight, int aTargetX, int aTargetY) const
sl@8
   134
	{
sl@8
   135
	//TODO: amend loop values so that we don't keep on looping past our frame buffer dimensions.
sl@8
   136
	for (int i=0;i<aSrcWidth;i++)
sl@8
   137
		{
sl@8
   138
		for (int j=0;j<aSrcHeight;j++)
sl@8
   139
			{
sl@8
   140
            iFrameNext->SetBitValue((aTargetX+i)*HeightInPixels()+aTargetY+j,aBitmap[+i*aSrcHeight+j]);
sl@8
   141
			}
sl@8
   142
		}
sl@8
   143
	}
sl@13
   144
*/
sl@8
   145
sl@8
   146
/**
sl@8
   147
Clear our client side back buffer.
sl@8
   148
Call to SwapBuffers must follow to actually clear the display.
sl@8
   149
*/
sl@8
   150
void GP1212A01A::Clear()
sl@8
   151
    {
sl@8
   152
    //memset(iNextFrame->Ptr(),0x00,FrameBufferSizeInBytes());
sl@8
   153
    if (iOffScreenMode)
sl@8
   154
        {
sl@8
   155
        iFrameNext->ClearAll();
sl@8
   156
        }
sl@8
   157
    else
sl@8
   158
        {
sl@8
   159
        SendClearCommand();
sl@8
   160
        }
sl@8
   161
    }
sl@8
   162
sl@8
   163
/**
sl@10
   164
Turn on all pixels.
sl@10
   165
Must be followed by a SwapBuffers call.
sl@10
   166
*/
sl@10
   167
void GP1212A01A::Fill()
sl@10
   168
	{
sl@10
   169
	SetAllPixels(0xFF);
sl@10
   170
	}
sl@10
   171
sl@10
   172
/**
sl@8
   173
Set all pixels on our screen to the desired value.
sl@8
   174
This operation is performed off screen to avoid tearing.
sl@8
   175
@param 8 pixels pattern
sl@8
   176
*/
sl@8
   177
void GP1212A01A::SetAllPixels(unsigned char aPattern)
sl@8
   178
	{
sl@8
   179
	//With a single buffer
sl@8
   180
	//unsigned char screen[2048]; //One screen worth of pixels
sl@8
   181
	//memset(screen,0xFF,sizeof(screen));
sl@8
   182
	//SetPixelBlock(0,0,63,sizeof(screen),screen);
sl@8
   183
sl@8
   184
sl@8
   185
    if (iOffScreenMode)
sl@8
   186
        {
sl@8
   187
        memset(iFrameNext->Ptr(),aPattern,FrameBufferSizeInBytes());
sl@8
   188
        }
sl@8
   189
    else
sl@8
   190
        {
sl@8
   191
        //Using pattern SetPixelBlock variant.
sl@8
   192
        SetPixelBlock(0,0,63,FrameBufferSizeInBytes(),aPattern);
sl@8
   193
        }
sl@8
   194
	//
sl@8
   195
	}
sl@8
   196
sl@8
   197
sl@8
   198
/**
sl@8
   199
Set the defined pixel block to the given value.
sl@8
   200
@param X coordinate of our pixel block starting point.
sl@8
   201
@param Y coordinate of our pixel block starting point.
sl@8
   202
@param The height of our pixel block.
sl@8
   203
@param The size of our pixel data. Number of pixels divided by 8.
sl@8
   204
@param The value set to 8 pixels used as a pattern.
sl@8
   205
*/
sl@8
   206
void GP1212A01A::SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char aValue)
sl@8
   207
	{
sl@8
   208
	OffScreenTranslation(aX,aY);
sl@8
   209
    FutabaVfdReport report;
sl@8
   210
    report[0]=0x00; //Report ID
sl@8
   211
    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
sl@8
   212
    report[2]=0x1B; //Command ID
sl@8
   213
    report[3]=0x5B; //Command ID
sl@8
   214
    report[4]=0xF0; //Command ID
sl@8
   215
    report[5]=aX;   //X
sl@8
   216
    report[6]=aY;   //Y
sl@8
   217
    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.
sl@8
   218
	report[8]=aSize>>8; //Size of pixel data in bytes (MSB)
sl@8
   219
	report[9]=aSize;	//Size of pixel data in bytes (LSB)
sl@8
   220
    int sizeWritten=MIN(aSize,report.Size()-10);
sl@8
   221
    memset(report.Buffer()+10, aValue, sizeWritten);
sl@8
   222
    Write(report);
sl@8
   223
sl@8
   224
    int remainingSize=aSize;
sl@8
   225
    //We need to keep on sending our pixel data until we are done
sl@8
   226
    while (report[1]==64)
sl@8
   227
        {
sl@8
   228
        report.Reset();
sl@8
   229
        remainingSize-=sizeWritten;
sl@8
   230
        report[0]=0x00; //Report ID
sl@8
   231
        report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
sl@8
   232
        sizeWritten=(report[1]==64?63:report[1]);
sl@8
   233
        memset(report.Buffer()+2, aValue, sizeWritten);
sl@8
   234
        Write(report);
sl@8
   235
        }
sl@8
   236
	}
sl@8
   237
sl@8
   238
/**
sl@8
   239
Set the defined pixel block to the given value.
sl@8
   240
@param X coordinate of our pixel block starting point.
sl@8
   241
@param Y coordinate of our pixel block starting point.
sl@8
   242
@param The height of our pixel block.
sl@8
   243
@param The size of our pixel data. Number of pixels divided by 8.
sl@8
   244
@param Pointer to our pixel data.
sl@8
   245
*/
sl@8
   246
void GP1212A01A::SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char* aPixels)
sl@8
   247
    {
sl@8
   248
	OffScreenTranslation(aX,aY);
sl@8
   249
    FutabaVfdReport report;
sl@8
   250
    report[0]=0x00; //Report ID
sl@8
   251
    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
sl@8
   252
    report[2]=0x1B; //Command ID
sl@8
   253
    report[3]=0x5B; //Command ID
sl@8
   254
    report[4]=0xF0; //Command ID
sl@8
   255
    report[5]=aX;   //X
sl@8
   256
    report[6]=aY;   //Y
sl@8
   257
    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.
sl@8
   258
	report[8]=aSize>>8; //Size of pixel data in bytes (MSB)
sl@8
   259
	report[9]=aSize;	//Size of pixel data in bytes (LSB)
sl@8
   260
    int sizeWritten=MIN(aSize,report.Size()-10);
sl@8
   261
    memcpy(report.Buffer()+10, aPixels, sizeWritten);
sl@8
   262
    Write(report);
sl@8
   263
sl@8
   264
    int remainingSize=aSize;
sl@8
   265
    //We need to keep on sending our pixel data until we are done
sl@8
   266
    while (report[1]==64)
sl@8
   267
        {
sl@8
   268
        report.Reset();
sl@8
   269
        remainingSize-=sizeWritten;
sl@8
   270
        report[0]=0x00; //Report ID
sl@8
   271
        report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
sl@8
   272
        sizeWritten=(report[1]==64?63:report[1]);
sl@8
   273
        memcpy(report.Buffer()+2, aPixels+(aSize-remainingSize), sizeWritten);
sl@8
   274
        Write(report);
sl@8
   275
        }
sl@8
   276
    }
sl@8
   277
sl@8
   278
/**
sl@8
   279
Using this function is advised against as is causes tearing.
sl@8
   280
Use Clear instead.
sl@8
   281
*/
sl@8
   282
void GP1212A01A::SendClearCommand()
sl@8
   283
	{
sl@8
   284
    //1BH,5BH,32H,4AH
sl@8
   285
    //Send Clear Display Command
sl@8
   286
	FutabaVfdReport report;
sl@8
   287
	report[0]=0x00; //Report ID
sl@8
   288
	report[1]=0x04; //Report length
sl@8
   289
	report[2]=0x1B; //Command ID
sl@8
   290
	report[3]=0x5B; //Command ID
sl@8
   291
	report[4]=0x32; //Command ID
sl@8
   292
	report[5]=0x4A; //Command ID
sl@8
   293
	Write(report);
sl@8
   294
	}
sl@8
   295
sl@8
   296
/**
sl@8
   297
Change our display position within our buffer.
sl@8
   298
*/
sl@8
   299
void GP1212A01A::SetDisplayPosition(DW aDw,unsigned char aX, unsigned char aY)
sl@8
   300
    {
sl@8
   301
    //1BH,5BH,Dw,Px,Py
sl@8
   302
    //Send Display Position Settings Command
sl@8
   303
    FutabaVfdReport report;
sl@8
   304
    report[0]=0x00; //Report ID
sl@8
   305
    report[1]=0x05; //Report length
sl@8
   306
    report[2]=0x1B; //Command ID
sl@8
   307
    report[3]=0x5B; //Command ID
sl@8
   308
    report[4]=aDw;  //Specify our DW
sl@8
   309
    report[5]=aX;   //X coordinate of our DW top-left corner
sl@8
   310
    report[6]=aY;   //Y coordinate of our DW top-left corner
sl@8
   311
    Write(report);
sl@8
   312
    }
sl@8
   313
sl@8
   314
/**
sl@8
   315
Change our display position within our buffer.
sl@8
   316
*/
sl@8
   317
void GP1212A01A::SetDisplayPosition(unsigned char aX, unsigned char aY)
sl@8
   318
	{
sl@8
   319
	//Specs apparently says both DW should remain the same
sl@8
   320
	//Just don't ask
sl@8
   321
    SetDisplayPosition(GP1212A01A::DW1,aX,aY);
sl@8
   322
    SetDisplayPosition(GP1212A01A::DW2,aX,aY);
sl@8
   323
	iDisplayPositionX=aX;
sl@8
   324
	iDisplayPositionY=aY;
sl@8
   325
	}
sl@8
   326
sl@8
   327
/**
sl@8
   328
Provide Y coordinate of our off screen buffer.
sl@8
   329
*/
sl@8
   330
unsigned char GP1212A01A::OffScreenY() const
sl@8
   331
	{
sl@8
   332
	//Overflowing is fine this is just what we want
sl@8
   333
	return iDisplayPositionY+HeightInPixels();
sl@8
   334
	}
sl@8
   335
sl@8
   336
/**
sl@8
   337
Put our off screen buffer on screen.
sl@8
   338
On screen buffer goes off screen.
sl@8
   339
*/
sl@8
   340
void GP1212A01A::SwapBuffers()
sl@8
   341
	{
sl@8
   342
	//Only perform buffer swapping if off screen mode is enabled
sl@8
   343
	if (OffScreenMode())
sl@8
   344
		{
sl@8
   345
		//Send host back buffer to device back buffer
sl@8
   346
        if (!iUseFrameDifferencing || iNeedFullFrameUpdate<KNumberOfFrameBeforeDiffAlgo)
sl@8
   347
            {
sl@8
   348
            iNeedFullFrameUpdate++;
sl@8
   349
            SetPixelBlock(0,0,63,FrameBufferSizeInBytes(),iFrameNext->Ptr());
sl@8
   350
            }
sl@8
   351
        else
sl@8
   352
            {
sl@8
   353
            //Frame diff algo is enabled
sl@8
   354
            //We are going to send to our device only the differences between next frame and previous frame
sl@8
   355
            SendModifiedPixelBlocks();
sl@8
   356
            }
sl@8
   357
		//Swap device front and back buffer
sl@8
   358
		SetDisplayPosition(iDisplayPositionX,OffScreenY());
sl@8
   359
sl@8
   360
        //Cycle through our frame buffers
sl@8
   361
        //We keep track of previous frame which is in fact our device back buffer.
sl@8
   362
        //We can then compare previous and next frame and send only the differences to our device.
sl@8
   363
        //This mechanism allows us to reduce traffic over our USB bus thus improving our frame rate from 14 FPS to 30 FPS.
sl@8
   364
        //Keep our previous frame pointer
sl@13
   365
        BitArrayHigh* previousFrame=iFramePrevious;
sl@8
   366
        //Current frame becomes the previous one
sl@8
   367
        iFramePrevious = iFrameCurrent;
sl@8
   368
        //Next frame becomes the current one
sl@8
   369
        iFrameCurrent = iFrameNext;
sl@8
   370
        //Next frame is now our former previous
sl@8
   371
        iFrameNext = previousFrame;
sl@8
   372
		}
sl@8
   373
	}
sl@8
   374
sl@8
   375
sl@8
   376
//Define the edge of our pixel block
sl@8
   377
//Pixel blocks of 32x32 seems to run almost as fast as full screen update in worse case scenarii.
sl@8
   378
//Though I wonder if in some situations 16 could be better. Make this an attribute at some point if need be.
sl@8
   379
const int KPixelBlockEdge = 32;
sl@8
   380
const int KPixelBlockSizeInBits = KPixelBlockEdge*KPixelBlockEdge;
sl@8
   381
const int KPixelBlockSizeInBytes = KPixelBlockSizeInBits/8;
sl@8
   382
sl@8
   383
sl@8
   384
/**
sl@8
   385
 * @brief GP1212A01A::SendModifiedPixelBlocks
sl@8
   386
 * Compare our back and front buffer and send to the device only the modified pixels.
sl@8
   387
 */
sl@8
   388
void GP1212A01A::SendModifiedPixelBlocks()
sl@8
   389
    {
sl@8
   390
    int w=WidthInPixels();
sl@8
   391
    int h=HeightInPixels();
sl@8
   392
sl@8
   393
sl@8
   394
    //TODO: optimize with memcmp and 16 inc
sl@8
   395
    /*
sl@8
   396
sl@8
   397
    for (int i=0;i<w;i++)
sl@8
   398
        {
sl@8
   399
        for (int j=0;j<h;j++)
sl@8
   400
            {
sl@8
   401
            //aX*HeightInPixels()+aY
sl@8
   402
            if ((*iFrameNext)[i*h+j]!=(*iFramePrevious)[i*h+j])
sl@8
   403
                {
sl@8
   404
                //We need to update that pixel
sl@8
   405
                SetPixelBlock(i,j,0,1,((*iFrameNext)[i*h+j]?0x01:0x00));
sl@8
   406
                //SetDisplayPosition(iDisplayPositionX,OffScreenY());
sl@8
   407
                //SetDisplayPosition(iDisplayPositionX,OffScreenY());
sl@8
   408
sl@8
   409
                //SetPixelBlock(i,j,15,32,iNextFrame->Ptr()+offset);
sl@8
   410
                }
sl@8
   411
            }
sl@8
   412
        }
sl@8
   413
    */
sl@8
   414
sl@13
   415
    BitArrayHigh nextBlock(KPixelBlockSizeInBits);
sl@13
   416
    BitArrayHigh previousBlock(KPixelBlockSizeInBits);
sl@8
   417
sl@8
   418
    for (int i=0;i<w;i+=KPixelBlockEdge)
sl@8
   419
        {
sl@8
   420
        for (int j=0;j<h;j+=KPixelBlockEdge)
sl@8
   421
            {
sl@8
   422
            //aX*HeightInPixels()+aY
sl@8
   423
            //int offset=(i*w/8)+(j/8);
sl@8
   424
sl@8
   425
#ifdef DEBUG_FRAME_DIFF
sl@8
   426
            QImage imagePrevious(KPixelBlockEdge,KPixelBlockEdge,QImage::Format_RGB32);
sl@8
   427
            QImage imageNext(KPixelBlockEdge,KPixelBlockEdge,QImage::Format_RGB32);
sl@8
   428
#endif
sl@8
   429
sl@8
   430
            //Get both our blocks from our buffers
sl@8
   431
            for (int x=i;x<i+KPixelBlockEdge;x++)
sl@8
   432
                {
sl@8
   433
                for (int y=j;y<j+KPixelBlockEdge;y++)
sl@8
   434
                    {
sl@8
   435
                    int blockOffset=(x-i)*KPixelBlockEdge+(y-j);
sl@8
   436
                    int frameOffset=x*h+y;
sl@8
   437
                    nextBlock.SetBitValue(blockOffset,(*iFrameNext)[frameOffset]);
sl@8
   438
                    previousBlock.SetBitValue(blockOffset,(*iFramePrevious)[frameOffset]);
sl@8
   439
sl@8
   440
#ifdef DEBUG_FRAME_DIFF
sl@8
   441
                    imageNext.setPixel(x-i,y-j,(nextBlock[blockOffset]?0xFFFFFFFF:0x00000000));
sl@8
   442
                    imagePrevious.setPixel(x-i,y-j,(previousBlock[blockOffset]?0xFFFFFFFF:0x00000000));
sl@8
   443
#endif
sl@8
   444
                    }
sl@8
   445
                }
sl@8
   446
sl@8
   447
#ifdef DEBUG_FRAME_DIFF
sl@8
   448
            QString previousName;
sl@8
   449
            QString nextName;
sl@8
   450
            QTextStream(&previousName) << "p" << i << "x" << j << ".png";
sl@8
   451
            QTextStream(&nextName) << "n" << i << "x" << j << ".png";
sl@8
   452
            imagePrevious.save(previousName);
sl@8
   453
            imageNext.save(nextName);
sl@8
   454
#endif
sl@8
   455
sl@8
   456
sl@8
   457
            //if (memcmp(iFrameNext->Ptr()+offset,iFramePrevious->Ptr()+offset,32 )) //32=(16*16/8)
sl@8
   458
            if (memcmp(nextBlock.Ptr(),previousBlock.Ptr(),KPixelBlockSizeInBytes)!=0)
sl@8
   459
                {
sl@8
   460
                //We need to update that block
sl@8
   461
                SetPixelBlock(i,j,KPixelBlockEdge-1,KPixelBlockSizeInBytes,nextBlock.Ptr());
sl@8
   462
                //SetPixelBlock(i,j,15,32,0xFF/*nextBlock.Ptr()*/);
sl@8
   463
                //SetDisplayPosition(iDisplayPositionX,OffScreenY());
sl@8
   464
                //SetDisplayPosition(iDisplayPositionX,OffScreenY());
sl@8
   465
sl@8
   466
                //SetPixelBlock(i,j,15,32,iFrameNext->Ptr()+offset);
sl@8
   467
                }
sl@8
   468
            }
sl@8
   469
        }
sl@8
   470
sl@8
   471
    }
sl@8
   472
sl@8
   473
/**
sl@8
   474
Translate the given pixel coordinate according to our off screen mode.
sl@8
   475
*/
sl@8
   476
void GP1212A01A::OffScreenTranslation(unsigned char& aX, unsigned char& aY)
sl@8
   477
	{
sl@8
   478
	if (OffScreenMode())
sl@8
   479
		{
sl@8
   480
		aX+=WidthInPixels()-iDisplayPositionX;
sl@8
   481
		aY+=HeightInPixels()-iDisplayPositionY;
sl@8
   482
		}
sl@8
   483
	}
sl@8
   484
sl@8
   485
sl@8
   486
/**
sl@8
   487
*/
sl@8
   488
void GP1212A01A::ResetBuffers()
sl@8
   489
	{
sl@8
   490
    //iNextFrame->ClearAll();
sl@8
   491
    //memset(iFrameAlpha,0x00,sizeof(iFrameAlpha));
sl@8
   492
	//memset(iFrameBeta,0x00,sizeof(iFrameBeta));
sl@8
   493
	}
sl@8
   494
sl@11
   495
sl@11
   496
/**
sl@11
   497
*/
sl@11
   498
void GP1212A01A::Request(TMiniDisplayRequest aRequest)
sl@11
   499
	{
sl@11
   500
	switch (aRequest)
sl@11
   501
		{
sl@11
   502
	case EMiniDisplayRequestDeviceId:
sl@11
   503
		RequestDeviceId();
sl@11
   504
		break;
sl@11
   505
	case EMiniDisplayRequestFirmwareRevision:
sl@11
   506
		RequestFirmwareRevision();
sl@11
   507
		break;
sl@11
   508
	case EMiniDisplayRequestPowerSupplyStatus:
sl@11
   509
		RequestPowerSupplyStatus();
sl@11
   510
		break;
sl@11
   511
	default:
sl@11
   512
		//Not supported
sl@11
   513
		break;
sl@11
   514
		};
sl@11
   515
	}
sl@11
   516
sl@8
   517
/**
sl@8
   518
*/
sl@8
   519
void GP1212A01A::RequestDeviceId()
sl@8
   520
    {
sl@8
   521
    if (RequestPending())
sl@8
   522
        {
sl@8
   523
        //Abort silently for now
sl@8
   524
        return;
sl@8
   525
        }
sl@8
   526
sl@8
   527
    //1BH,5BH,63H,49H,44H
sl@8
   528
    //Send Read ID command
sl@8
   529
    FutabaVfdReport report;
sl@8
   530
    report[0]=0x00; //Report ID
sl@8
   531
    report[1]=0x05; //Report length
sl@8
   532
    report[2]=0x1B; //Command ID
sl@8
   533
    report[3]=0x5B; //Command ID
sl@8
   534
    report[4]=0x63; //Command ID
sl@8
   535
    report[5]=0x49; //Command ID
sl@8
   536
    report[6]=0x44; //Command ID
sl@8
   537
    if (Write(report)==report.Size())
sl@8
   538
        {
sl@11
   539
        SetRequest(EMiniDisplayRequestDeviceId);
sl@8
   540
        }
sl@8
   541
    }
sl@8
   542
sl@8
   543
/**
sl@8
   544
*/
sl@8
   545
void GP1212A01A::RequestFirmwareRevision()
sl@8
   546
    {
sl@8
   547
    if (RequestPending())
sl@8
   548
        {
sl@8
   549
        //Abort silently for now
sl@8
   550
        return;
sl@8
   551
        }
sl@8
   552
sl@8
   553
    //1BH,5BH,63H,46H,52H
sl@8
   554
    //Send Software Revision Read Command
sl@8
   555
    FutabaVfdReport report;
sl@8
   556
    report[0]=0x00; //Report ID
sl@8
   557
    report[1]=0x05; //Report length
sl@8
   558
    report[2]=0x1B; //Command ID
sl@8
   559
    report[3]=0x5B; //Command ID
sl@8
   560
    report[4]=0x63; //Command ID
sl@8
   561
    report[5]=0x46; //Command ID
sl@8
   562
    report[6]=0x52; //Command ID
sl@8
   563
    if (Write(report)==report.Size())
sl@8
   564
        {
sl@11
   565
        SetRequest(EMiniDisplayRequestFirmwareRevision);
sl@8
   566
        }
sl@8
   567
    }
sl@8
   568
sl@8
   569
/**
sl@8
   570
*/
sl@8
   571
void GP1212A01A::RequestPowerSupplyStatus()
sl@8
   572
    {
sl@8
   573
    if (RequestPending())
sl@8
   574
        {
sl@8
   575
        //Abort silently for now
sl@8
   576
        return;
sl@8
   577
        }
sl@8
   578
    //1BH,5BH,63H,50H,4DH
sl@8
   579
    //Send Power Suppply Monitor Command
sl@8
   580
    FutabaVfdReport report;
sl@8
   581
    report[0]=0x00; //Report ID
sl@8
   582
    report[1]=0x05; //Report length
sl@8
   583
    report[2]=0x1B; //Command ID
sl@8
   584
    report[3]=0x5B; //Command ID
sl@8
   585
    report[4]=0x63; //Command ID
sl@8
   586
    report[5]=0x50; //Command ID
sl@8
   587
    report[6]=0x4D; //Command ID
sl@8
   588
    if (Write(report)==report.Size())
sl@8
   589
        {
sl@11
   590
        SetRequest(EMiniDisplayRequestPowerSupplyStatus);
sl@8
   591
        }
sl@8
   592
    }
sl@8
   593
sl@8
   594
sl@8
   595
/**
sl@8
   596
This is for development purposes only.
sl@8
   597
Production application should stick to off-screen mode to avoid tearing.
sl@8
   598
*/
sl@8
   599
void GP1212A01A::ToggleOffScreenMode()
sl@8
   600
	{
sl@8
   601
    SetOffScreenMode(!iOffScreenMode);
sl@8
   602
	}
sl@8
   603
sl@8
   604
/**
sl@8
   605
 * @brief GP1212A01A::SetOffScreenMode
sl@8
   606
 * @param aOn
sl@8
   607
 * @return
sl@8
   608
 */
sl@8
   609
void GP1212A01A::SetOffScreenMode(bool aOn)
sl@8
   610
    {
sl@8
   611
    if (aOn==iOffScreenMode)
sl@8
   612
    {
sl@8
   613
        //Nothing to do here
sl@8
   614
        return;
sl@8
   615
    }
sl@8
   616
sl@8
   617
    iOffScreenMode=aOn;
sl@8
   618
sl@8
   619
    //Clean up our buffers upon switching modes
sl@8
   620
    SetDisplayPosition(0,0);
sl@8
   621
    Clear();
sl@8
   622
    SwapBuffers();
sl@8
   623
    Clear();
sl@8
   624
    }
sl@8
   625
sl@8
   626
/**
sl@8
   627
Tries to complete our current request if we have one pending.
sl@8
   628
 */
sl@8
   629
TMiniDisplayRequest GP1212A01A::AttemptRequestCompletion()
sl@8
   630
    {
sl@8
   631
    if (!RequestPending())
sl@8
   632
        {
sl@8
   633
        return EMiniDisplayRequestNone;
sl@8
   634
        }
sl@8
   635
sl@8
   636
    int res=Read(iInputReport);
sl@8
   637
sl@8
   638
    if (!res)
sl@8
   639
        {
sl@8
   640
        return EMiniDisplayRequestNone;
sl@8
   641
        }
sl@8
   642
sl@8
   643
    //Process our request
sl@8
   644
    if (CurrentRequest()==EMiniDisplayRequestPowerSupplyStatus)
sl@8
   645
        {
sl@8
   646
        if (iInputReport[1]==0x4F && iInputReport[2]==0x4E)
sl@8
   647
            {
sl@8
   648
            iPowerOn = true;
sl@8
   649
            }
sl@8
   650
        else if (iInputReport[1]==0x4F && iInputReport[2]==0x46 && iInputReport[3]==0x46)
sl@8
   651
            {
sl@8
   652
            iPowerOn = false;
sl@8
   653
            }
sl@8
   654
        }
sl@8
   655
	else if (CurrentRequest()==EMiniDisplayRequestDeviceId)
sl@8
   656
		{
sl@8
   657
			unsigned char* ptr=&iInputReport[1];
sl@8
   658
			strcpy(iDeviceId,(const char*)ptr);
sl@8
   659
		}
sl@8
   660
	else if (CurrentRequest()==EMiniDisplayRequestFirmwareRevision)
sl@8
   661
		{
sl@8
   662
			unsigned char* ptr=&iInputReport[1];
sl@8
   663
			strcpy(iFirmwareRevision,(const char*)ptr);
sl@8
   664
		}
sl@8
   665
sl@11
   666
    TMiniDisplayRequest completed=CurrentRequest();
sl@8
   667
    //Our request was completed
sl@11
   668
    SetRequest(EMiniDisplayRequestNone);
sl@8
   669
sl@8
   670
    return completed;
sl@8
   671
    }
sl@8
   672
sl@8
   673
sl@8
   674
/**
sl@8
   675
Set our screen brightness.
sl@8
   676
@param The desired brightness level. Must be between MinBrightness and MaxBrightness.
sl@8
   677
*/
sl@8
   678
void GP1212A01A::SetBrightness(int aBrightness)
sl@8
   679
    {
sl@8
   680
    if (aBrightness<MinBrightness()||aBrightness>MaxBrightness())
sl@8
   681
        {
sl@8
   682
        //Brightness out of range.
sl@8
   683
        //Just ignore that request.
sl@8
   684
        return;
sl@8
   685
        }
sl@8
   686
sl@8
   687
    FutabaVfdReport report;
sl@8
   688
    report[0]=0x00; //Report ID
sl@8
   689
    report[1]=0x06; //Report size
sl@8
   690
    report[2]=0x1B; //Command ID
sl@8
   691
    report[3]=0x5C; //Command ID
sl@8
   692
    report[4]=0x3F; //Command ID
sl@8
   693
    report[5]=0x4C; //Command ID
sl@8
   694
    report[6]=0x44; //Command ID
sl@8
   695
    report[7]=0x30+aBrightness; //Brightness level
sl@8
   696
    Write(report);
sl@8
   697
    }
sl@8
   698
sl@8
   699