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