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