FutabaGP1212A02.cpp
author sl
Sun, 31 Aug 2014 21:35:36 +0200
changeset 17 591e9f922c63
parent 16 42ba42be810d
child 19 9f659cde9ee8
permissions -rw-r--r--
GP1212A02: Clock support.
sl@8
     1
//
sl@8
     2
//
sl@8
     3
//
sl@8
     4
sl@10
     5
#include "FutabaGP1212A02.h"
sl@10
     6
sl@17
     7
#include <stdio.h>
sl@17
     8
#include <time.h>
sl@10
     9
sl@15
    10
const unsigned short KMaxDataMemoryAddress = 0x4FFF;
sl@15
    11
const unsigned short KFrameSizeInBytes = 0x800;
sl@15
    12
sl@10
    13
//
sl@10
    14
// class GP1212A02A
sl@10
    15
//
sl@10
    16
sl@10
    17
GP1212A02A::GP1212A02A():
sl@10
    18
	iDisplayPositionX(0),iDisplayPositionY(0),
sl@10
    19
    iOffScreenMode(true),
sl@10
    20
    iUseFrameDifferencing(true),
sl@10
    21
    iFrameNext(NULL),
sl@10
    22
    iFrameCurrent(NULL),
sl@10
    23
    iFramePrevious(NULL),
sl@10
    24
    iFrameAlpha(NULL),
sl@10
    25
    iFrameBeta(NULL),
sl@10
    26
    iFrameGamma(NULL),
sl@10
    27
    iNeedFullFrameUpdate(0),
sl@11
    28
    iPowerOn(false)
sl@10
    29
	{
sl@10
    30
	iDeviceId[0]=0;
sl@10
    31
	iFirmwareRevision[0]=0;
sl@10
    32
	//ResetBuffers();
sl@10
    33
	}
sl@10
    34
sl@10
    35
/**
sl@10
    36
*/
sl@10
    37
GP1212A02A::~GP1212A02A()
sl@10
    38
	{
sl@10
    39
    delete iFrameAlpha;
sl@10
    40
    iFrameAlpha=NULL;
sl@10
    41
    //
sl@10
    42
    delete iFrameBeta;
sl@10
    43
    iFrameBeta=NULL;
sl@10
    44
    //
sl@10
    45
    delete iFrameGamma;
sl@10
    46
    iFrameGamma=NULL;
sl@10
    47
    //
sl@10
    48
    iFrameNext=NULL;
sl@10
    49
    iFrameCurrent=NULL;
sl@10
    50
    iFramePrevious=NULL;
sl@10
    51
    //
sl@10
    52
    iNeedFullFrameUpdate=0;
sl@10
    53
	}
sl@10
    54
sl@10
    55
/**
sl@10
    56
*/
sl@10
    57
int GP1212A02A::Open()
sl@10
    58
	{
sl@10
    59
	int success = HidDevice::Open(KFutabaVendorId,KFutabaProductIdGP1212A02A,NULL);
sl@10
    60
	if (success)
sl@10
    61
		{
sl@10
    62
        //Allocate both frames
sl@10
    63
        delete iFrameAlpha;
sl@10
    64
        iFrameAlpha=NULL;
sl@13
    65
        iFrameAlpha=new BitArrayLow(KGP12xFrameBufferPixelCount);
sl@10
    66
        //
sl@10
    67
        delete iFrameBeta;
sl@10
    68
        iFrameBeta=NULL;
sl@13
    69
        iFrameBeta=new BitArrayLow(KGP12xFrameBufferPixelCount);
sl@10
    70
        //
sl@10
    71
        delete iFrameGamma;
sl@10
    72
        iFrameGamma=NULL;
sl@13
    73
        iFrameGamma=new BitArrayLow(KGP12xFrameBufferPixelCount);
sl@10
    74
        //
sl@10
    75
        iFrameNext=iFrameAlpha;
sl@10
    76
        iFrameCurrent=iFrameBeta;
sl@10
    77
        iFramePrevious=iFrameGamma;
sl@10
    78
sl@10
    79
sl@10
    80
        //To make sure it is synced properly
sl@10
    81
        iNeedFullFrameUpdate=0;
sl@10
    82
        //
sl@10
    83
		SetNonBlocking(1);
sl@13
    84
		//
sl@17
    85
		SendCommandClear();
sl@17
    86
		//
sl@17
    87
		SetClockSetting();
sl@14
    88
sl@17
    89
		//BMP box setup could be removed if we don't use it anymore
sl@14
    90
		//Setup BMP box
sl@14
    91
		BmpBoxSetting(EBmpBoxIdOne,0x0000,256,64);
sl@14
    92
		//Select current BMP box
sl@14
    93
		BmpBoxSelect(EBmpBoxIdOne);
sl@17
    94
		//
sl@17
    95
		iNextFrameAddress = 0x0000;
sl@14
    96
sl@17
    97
sl@14
    98
sl@10
    99
		}
sl@10
   100
	return success;
sl@10
   101
	}
sl@10
   102
sl@10
   103
/**
sl@14
   104
 Setting the BMP box
sl@14
   105
[Code] 1BH,5CH,42H,Pn,aL,aH,Pw,Ph
sl@14
   106
[Function] Setting the BMP box. BMP box can be defined the 3 area to DW. The position of BMP 
sl@14
   107
box is set based on the address of DW. 
sl@14
   108
* To write data in BMP box, BMP box select is necessary. 
sl@14
   109
* Specifiable horizontal size is 256dot (100H) MAX. If horizontal size specify 256dot, Pw = 00H 
sl@14
   110
Pn = Number of a BMP box 
sl@14
   111
aL = Lower byte of address 
sl@14
   112
aH = Upper byte of address 
sl@14
   113
Pw = BMP box width 
sl@14
   114
Ph = BMP box height 
sl@14
   115
sl@14
   116
[Definable area]
sl@14
   117
Pn = 31H - BMP box 1
sl@14
   118
Pn = 32H - BMP box 2
sl@14
   119
Pn = 33H - BMP box 3
sl@14
   120
0000H <= aL + aH * 100 <= 07FFH 
sl@14
   121
01H <= Pw <= 00H (=100H) 
sl@14
   122
01H <= Ph <= 08H
sl@14
   123
*/
sl@14
   124
void GP1212A02A::BmpBoxSetting(TBmpBoxId aBoxId, unsigned short aAddress, int aWidth, int aHeight)
sl@14
   125
	{
sl@14
   126
	//TODO: check parameters validity
sl@14
   127
	//1BH,5CH,42H,Pn,aL,aH,Pw,Ph
sl@14
   128
	FutabaVfdReport report;
sl@14
   129
	report[0]=0x00; //Report ID
sl@14
   130
	report[1]=0x08; //Report length.
sl@14
   131
	report[2]=0x1B; //Command ID
sl@14
   132
	report[3]=0x5C; //Command ID
sl@14
   133
	report[4]=0x42; //Command ID
sl@14
   134
	report[5]=aBoxId; 
sl@14
   135
	report[6]=(unsigned char)aAddress; //aL = DM lower byte
sl@14
   136
	report[7]=aAddress>>8; //aH = DM upper byte
sl@14
   137
	report[8]=(aWidth==256?0x00:aWidth); //Pw = BMP box width 00==256
sl@14
   138
	report[9]=aHeight/8; //Ph = BMP box height.
sl@14
   139
	Write(report);
sl@14
   140
	}
sl@14
   141
sl@14
   142
/**
sl@14
   143
[Code]1BH,5CH,48H,Pn
sl@14
   144
[Function]Select of BMP box 
sl@14
   145
* Execution "BMP box select" is necessary before "Setting the Text box". 
sl@14
   146
* In case of writing by the specified dot writing, it is necessary to cancel this command. 
sl@14
   147
[Definable area]
sl@14
   148
Pn = 30H - Remove the BMP box 
sl@14
   149
Pn = 31H - BMP box 1
sl@14
   150
Pn = 32H - BMP box 2
sl@14
   151
Pn = 33H - BMP box 3
sl@14
   152
*/
sl@14
   153
void GP1212A02A::BmpBoxSelect(TBmpBoxId aBoxId)
sl@14
   154
	{
sl@14
   155
	//TODO: check parameters validity 
sl@14
   156
	FutabaVfdReport report;
sl@14
   157
	report[0]=0x00; //Report ID
sl@14
   158
	report[1]=0x04; //Report length.
sl@14
   159
	report[2]=0x1B; //Command ID
sl@14
   160
	report[3]=0x5C; //Command ID
sl@14
   161
	report[4]=0x48; //Command ID
sl@14
   162
	report[5]=aBoxId; //BMP box ID
sl@14
   163
	Write(report);
sl@14
   164
	}
sl@14
   165
sl@14
   166
sl@14
   167
/**
sl@10
   168
*/
sl@10
   169
void GP1212A02A::SetPixel(unsigned char aX, unsigned char aY, bool aOn)
sl@10
   170
	{
sl@10
   171
	//
sl@10
   172
	//int byteOffset=(aX*HeightInPixels()+aY)/8;
sl@10
   173
	//int bitOffset=(aX*HeightInPixels()+aY)%8;
sl@10
   174
    //iNextFrame[byteOffset] |= ( (aOn?0x01:0x00) << bitOffset );
sl@10
   175
sl@10
   176
    if (iOffScreenMode)
sl@10
   177
        {
sl@10
   178
        if (aOn)
sl@10
   179
            {
sl@10
   180
            iFrameNext->SetBit(aX*HeightInPixels()+aY);
sl@10
   181
            }
sl@10
   182
        else
sl@10
   183
            {
sl@10
   184
            iFrameNext->ClearBit(aX*HeightInPixels()+aY);
sl@10
   185
            }
sl@10
   186
        }
sl@10
   187
    else
sl@10
   188
        {
sl@10
   189
        //Just specify a one pixel block
sl@13
   190
        //TODO
sl@10
   191
        }
sl@10
   192
	}
sl@10
   193
sl@10
   194
/**
sl@10
   195
*/
sl@13
   196
/*
sl@10
   197
void GP1212A02A::BitBlit(const BitArray& aBitmap, int aSrcWidth, int aSrcHeight, int aTargetX, int aTargetY) const
sl@10
   198
	{
sl@10
   199
	//TODO: amend loop values so that we don't keep on looping past our frame buffer dimensions.
sl@10
   200
	for (int i=0;i<aSrcWidth;i++)
sl@10
   201
		{
sl@10
   202
		for (int j=0;j<aSrcHeight;j++)
sl@10
   203
			{
sl@10
   204
            iFrameNext->SetBitValue((aTargetX+i)*HeightInPixels()+aTargetY+j,aBitmap[+i*aSrcHeight+j]);
sl@10
   205
			}
sl@10
   206
		}
sl@10
   207
	}
sl@13
   208
*/
sl@10
   209
sl@10
   210
/**
sl@10
   211
Clear our client side back buffer.
sl@10
   212
Call to SwapBuffers must follow to actually clear the display.
sl@10
   213
*/
sl@10
   214
void GP1212A02A::Clear()
sl@10
   215
    {
sl@10
   216
    //memset(iNextFrame->Ptr(),0x00,FrameBufferSizeInBytes());
sl@10
   217
    if (iOffScreenMode)
sl@10
   218
        {
sl@10
   219
        iFrameNext->ClearAll();
sl@10
   220
        }
sl@10
   221
    else
sl@10
   222
        {
sl@17
   223
        SendCommandClear();
sl@10
   224
        }
sl@10
   225
    }
sl@10
   226
sl@10
   227
/**
sl@10
   228
Turn on all pixels.
sl@10
   229
Must be followed by a SwapBuffers call.
sl@10
   230
*/
sl@10
   231
void GP1212A02A::Fill()
sl@10
   232
	{
sl@10
   233
	SetAllPixels(0xFF);
sl@10
   234
	}
sl@10
   235
sl@10
   236
/**
sl@10
   237
Set all pixels on our screen to the desired value.
sl@10
   238
This operation is performed off screen to avoid tearing.
sl@10
   239
@param 8 pixels pattern
sl@10
   240
*/
sl@10
   241
void GP1212A02A::SetAllPixels(unsigned char aPattern)
sl@10
   242
	{
sl@10
   243
	//With a single buffer
sl@10
   244
	//unsigned char screen[2048]; //One screen worth of pixels
sl@10
   245
	//memset(screen,0xFF,sizeof(screen));
sl@10
   246
	//SetPixelBlock(0,0,63,sizeof(screen),screen);
sl@10
   247
sl@10
   248
sl@10
   249
    if (iOffScreenMode)
sl@10
   250
        {
sl@10
   251
        memset(iFrameNext->Ptr(),aPattern,FrameBufferSizeInBytes());
sl@10
   252
        }
sl@10
   253
    else
sl@10
   254
        {
sl@10
   255
        //Using pattern SetPixelBlock variant.
sl@13
   256
        //TODO
sl@10
   257
        }
sl@10
   258
	//
sl@10
   259
	}
sl@10
   260
sl@10
   261
sl@13
   262
sl@13
   263
sl@10
   264
/**
sl@14
   265
BMP data input 
sl@14
   266
[Code] 1BH,4AH,Pm,aL,aH,Ps,nL,nH,Pd...Pd
sl@14
   267
[Function] The BMP data is written in the DW(Display Window) or the Data memory. 
sl@14
   268
Pm= DW or Data memory 
sl@14
   269
aL = DW lower byte 
sl@14
   270
aH = DW upper byte 
sl@14
   271
Ps = Direction of writing 
sl@14
   272
nL = number of BMP data length lower byte 
sl@14
   273
nH = number of BMP data length upper byte 
sl@14
   274
Pd = BMP data 
sl@14
   275
* If X direction is selected as Ps and data is written in the last address, the data in the last address is 
sl@14
   276
overwritten with the remaining data.  
sl@14
   277
[Definable area] Pm = 30H : DW
sl@14
   278
 Pm = 31H: Data memory 
sl@14
   279
0000H <= aL + aH * 100 <= 07FFH (DW)
sl@14
   280
0000H <= aL + aH * 100 <= 4FFFH (Data memory) 
sl@14
   281
Ps = 30H: Y direction 
sl@14
   282
Ps = 31H: X direction 
sl@14
   283
0001H <= nL + nH * 100 <= 0100H(DW: X direction) 
sl@14
   284
0001H <= nL + nH * 100 <= 0800H(DW: Y direction) 
sl@14
   285
0001H <= nL + nH * 100 <= 0A00H(Data memory: X direction) 
sl@14
   286
0001H <= nL + nH * 100 <= 5000H(Data memory: Y direction) 
sl@10
   287
*/
sl@14
   288
void GP1212A02A::BmpDataInput(TTarget aTarget, unsigned short aAddress, TDirection aDirection, unsigned short aSize, unsigned char* aPixels)
sl@13
   289
{
sl@13
   290
	FutabaVfdReport report;
sl@10
   291
    report[0]=0x00; //Report ID
sl@10
   292
    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@10
   293
    report[2]=0x1B; //Command ID
sl@13
   294
    report[3]=0x4A; //Command ID
sl@14
   295
    report[4]=aTarget; //Display Window or Data Memory
sl@14
   296
    report[5]=(unsigned char)aAddress; //aL = DW lower byte
sl@14
   297
    report[6]=aAddress>>8; //aH = DW upper byte
sl@14
   298
    report[7]=aDirection; //Direction of writing: Y or X
sl@14
   299
	report[8]=(unsigned char)aSize; //Size of pixel data in bytes (LSB)
sl@13
   300
	report[9]=aSize>>8;	//Size of pixel data in bytes (MSB)
sl@10
   301
    int sizeWritten=MIN(aSize,report.Size()-10);
sl@10
   302
    memcpy(report.Buffer()+10, aPixels, sizeWritten);
sl@10
   303
    Write(report);
sl@10
   304
sl@10
   305
    int remainingSize=aSize;
sl@10
   306
    //We need to keep on sending our pixel data until we are done
sl@10
   307
    while (report[1]==64)
sl@10
   308
        {
sl@10
   309
        report.Reset();
sl@10
   310
        remainingSize-=sizeWritten;
sl@10
   311
        report[0]=0x00; //Report ID
sl@10
   312
        report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
sl@10
   313
        sizeWritten=(report[1]==64?63:report[1]);
sl@10
   314
        memcpy(report.Buffer()+2, aPixels+(aSize-remainingSize), sizeWritten);
sl@10
   315
        Write(report);
sl@10
   316
        }
sl@13
   317
}
sl@10
   318
sl@14
   319
sl@14
   320
/**
sl@14
   321
Data memory transfer
sl@14
   322
[Code] 1BH,5CH,44H,aL,aH
sl@14
   323
[Function] BMP data transfer from Data memory to DW. 
sl@14
   324
Although source data is updated, data in BMP box is not updated. To reflect the update, 
sl@14
   325
re-executing this command is necessary. 
sl@14
   326
aL = Lower byte of address 
sl@14
   327
aH = Upper byte of address 
sl@14
   328
[Definable area]
sl@14
   329
0000H <= aL + aH * 100 <= 4FFFH 
sl@14
   330
*/
sl@14
   331
void GP1212A02A::BmpBoxDataMemoryTransfer(unsigned short aAddress)
sl@14
   332
	{
sl@14
   333
	FutabaVfdReport report;
sl@14
   334
	report[0]=0x00; //Report ID
sl@14
   335
    report[1]=0x05; //Report length.
sl@14
   336
    report[2]=0x1B; //Command ID
sl@14
   337
    report[3]=0x5C; //Command ID
sl@14
   338
    report[4]=0x44; //Command ID
sl@14
   339
    report[5]=(unsigned char)aAddress; //aL = DM lower byte
sl@14
   340
    report[6]=aAddress>>8; //aH = DM upper byte
sl@14
   341
	Write(report);
sl@14
   342
	}
sl@14
   343
sl@14
   344
/**
sl@14
   345
Input BMP data in the BMP box 
sl@14
   346
[Code] 1BH,5CH,5DH,nL,nH,Pd...Pd
sl@14
   347
[Function] BMP data is written the BMP box 
sl@14
   348
* Number of definable data is due to BMP box size. If the data is over range, the over range data is 
sl@14
   349
rewritten the final address. 
sl@14
   350
nL = Lower byte of number of definition byte 
sl@14
   351
nH = Upper byte of number of definition byte 
sl@14
   352
Pd = BMP data 
sl@14
   353
[Definable area] Pn : BMP box size (Pw * Ph)
sl@14
   354
*/
sl@14
   355
void GP1212A02A::BmpBoxDataInput(unsigned short aSize, unsigned char* aPixels)
sl@14
   356
	{
sl@14
   357
	FutabaVfdReport report;
sl@14
   358
    report[0]=0x00; //Report ID
sl@14
   359
    report[1]=(aSize<=report.Size()-7?aSize+0x05:64); //Report length. -7 is for our header first 10 bytes. +5 is for our Futaba header size
sl@14
   360
    report[2]=0x1B; //Command ID
sl@14
   361
    report[3]=0x5C; //Command ID
sl@14
   362
    report[4]=0x5D; //Display Window or Data Memory
sl@14
   363
	report[5]=(unsigned char)aSize; //Size of pixel data in bytes (LSB)
sl@14
   364
	report[6]=aSize>>8;	//Size of pixel data in bytes (MSB)
sl@14
   365
    int sizeWritten=MIN(aSize,report.Size()-7);
sl@14
   366
    memcpy(report.Buffer()+7, aPixels, sizeWritten);
sl@14
   367
    Write(report);
sl@14
   368
sl@14
   369
    int remainingSize=aSize;
sl@14
   370
    //We need to keep on sending our pixel data until we are done
sl@14
   371
    while (report[1]==64)
sl@14
   372
        {
sl@14
   373
        report.Reset();
sl@14
   374
        remainingSize-=sizeWritten;
sl@14
   375
        report[0]=0x00; //Report ID
sl@14
   376
        report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
sl@14
   377
        sizeWritten=(report[1]==64?63:report[1]);
sl@14
   378
        memcpy(report.Buffer()+2, aPixels+(aSize-remainingSize), sizeWritten);
sl@14
   379
        Write(report);
sl@14
   380
        }
sl@14
   381
	}
sl@14
   382
sl@10
   383
/**
sl@10
   384
Using this function is advised against as is causes tearing.
sl@10
   385
Use Clear instead.
sl@10
   386
*/
sl@17
   387
void GP1212A02A::SendCommandClear()
sl@10
   388
	{
sl@13
   389
    //1BH,4AH,43H,44H
sl@10
   390
    //Send Clear Display Command
sl@10
   391
	FutabaVfdReport report;
sl@10
   392
	report[0]=0x00; //Report ID
sl@10
   393
	report[1]=0x04; //Report length
sl@10
   394
	report[2]=0x1B; //Command ID
sl@13
   395
	report[3]=0x4A; //Command ID
sl@13
   396
	report[4]=0x43; //Command ID
sl@13
   397
	report[5]=0x44; //Command ID
sl@10
   398
	Write(report);
sl@10
   399
	}
sl@10
   400
sl@10
   401
sl@10
   402
/**
sl@10
   403
Provide Y coordinate of our off screen buffer.
sl@10
   404
*/
sl@10
   405
unsigned char GP1212A02A::OffScreenY() const
sl@10
   406
	{
sl@10
   407
	//Overflowing is fine this is just what we want
sl@10
   408
	return iDisplayPositionY+HeightInPixels();
sl@10
   409
	}
sl@10
   410
sl@10
   411
/**
sl@10
   412
Put our off screen buffer on screen.
sl@10
   413
On screen buffer goes off screen.
sl@10
   414
*/
sl@10
   415
void GP1212A02A::SwapBuffers()
sl@10
   416
	{
sl@10
   417
	//Only perform buffer swapping if off screen mode is enabled
sl@10
   418
	if (OffScreenMode())
sl@10
   419
		{
sl@14
   420
		//Send pixel directly into BMP box
sl@15
   421
		//BmpBoxDataInput(FrameBufferSizeInBytes(),iFrameNext->Ptr());
sl@14
   422
		//Send pixel data directly into the display window
sl@14
   423
		//BmpDataInput(ETargetDisplayWindow,0x0000,EDirectionY, FrameBufferSizeInBytes(),iFrameNext->Ptr());
sl@14
   424
		//Send pixel data first to Data Memory then copy into the selected BMP box	
sl@14
   425
		//BmpDataInput(ETargetDataMemory,0x0000,EDirectionY, FrameBufferSizeInBytes(),iFrameNext->Ptr());
sl@14
   426
		//BmpBoxDataMemoryTransfer(0x0000);
sl@15
   427
		//Send pixel data first to Data Memory then copy into the selected BMP box, cycling through our Data Memory frmae
sl@15
   428
		BmpDataInput(ETargetDataMemory,iNextFrameAddress,EDirectionY, FrameBufferSizeInBytes(),iFrameNext->Ptr());
sl@15
   429
		BmpBoxDataMemoryTransfer(iNextFrameAddress);
sl@15
   430
		iNextFrameAddress+=KFrameSizeInBytes;
sl@15
   431
		if (iNextFrameAddress>KMaxDataMemoryAddress)
sl@15
   432
		{
sl@15
   433
			iNextFrameAddress=0x0000;
sl@15
   434
		}
sl@10
   435
sl@10
   436
        //Cycle through our frame buffers
sl@10
   437
        //We keep track of previous frame which is in fact our device back buffer.
sl@10
   438
        //We can then compare previous and next frame and send only the differences to our device.
sl@10
   439
        //This mechanism allows us to reduce traffic over our USB bus thus improving our frame rate from 14 FPS to 30 FPS.
sl@10
   440
        //Keep our previous frame pointer
sl@13
   441
        BitArrayLow* previousFrame=iFramePrevious;
sl@10
   442
        //Current frame becomes the previous one
sl@10
   443
        iFramePrevious = iFrameCurrent;
sl@10
   444
        //Next frame becomes the current one
sl@10
   445
        iFrameCurrent = iFrameNext;
sl@10
   446
        //Next frame is now our former previous
sl@10
   447
        iFrameNext = previousFrame;
sl@10
   448
		}
sl@10
   449
	}
sl@10
   450
sl@10
   451
sl@10
   452
//Define the edge of our pixel block
sl@10
   453
//Pixel blocks of 32x32 seems to run almost as fast as full screen update in worse case scenarii.
sl@10
   454
//Though I wonder if in some situations 16 could be better. Make this an attribute at some point if need be.
sl@10
   455
const int KPixelBlockEdge = 32;
sl@10
   456
const int KPixelBlockSizeInBits = KPixelBlockEdge*KPixelBlockEdge;
sl@10
   457
const int KPixelBlockSizeInBytes = KPixelBlockSizeInBits/8;
sl@10
   458
sl@10
   459
sl@10
   460
/**
sl@10
   461
Translate the given pixel coordinate according to our off screen mode.
sl@10
   462
*/
sl@10
   463
void GP1212A02A::OffScreenTranslation(unsigned char& aX, unsigned char& aY)
sl@10
   464
	{
sl@10
   465
	if (OffScreenMode())
sl@10
   466
		{
sl@10
   467
		aX+=WidthInPixels()-iDisplayPositionX;
sl@10
   468
		aY+=HeightInPixels()-iDisplayPositionY;
sl@10
   469
		}
sl@10
   470
	}
sl@10
   471
sl@10
   472
sl@10
   473
/**
sl@10
   474
*/
sl@15
   475
void GP1212A02A::Request(TMiniDisplayRequest aRequest)
sl@15
   476
	{
sl@15
   477
	switch (aRequest)
sl@15
   478
		{
sl@15
   479
	case EMiniDisplayRequestDeviceId:
sl@15
   480
		RequestDeviceId();
sl@15
   481
		break;
sl@15
   482
	case EMiniDisplayRequestFirmwareRevision:
sl@15
   483
		RequestFirmwareRevision();
sl@15
   484
		break;
sl@15
   485
	case EMiniDisplayRequestPowerSupplyStatus:
sl@15
   486
		RequestPowerSupplyStatus();
sl@15
   487
		break;
sl@15
   488
	default:
sl@15
   489
		//Not supported
sl@15
   490
		break;
sl@15
   491
		};
sl@15
   492
	}
sl@15
   493
sl@15
   494
sl@15
   495
/**
sl@15
   496
*/
sl@10
   497
void GP1212A02A::ResetBuffers()
sl@10
   498
	{
sl@10
   499
    //iNextFrame->ClearAll();
sl@10
   500
    //memset(iFrameAlpha,0x00,sizeof(iFrameAlpha));
sl@10
   501
	//memset(iFrameBeta,0x00,sizeof(iFrameBeta));
sl@10
   502
	}
sl@10
   503
sl@10
   504
/**
sl@10
   505
*/
sl@10
   506
void GP1212A02A::RequestDeviceId()
sl@10
   507
    {
sl@11
   508
	//Not supported
sl@10
   509
    }
sl@10
   510
sl@10
   511
/**
sl@15
   512
ID code 
sl@15
   513
[Code] 1BH,6AH,49H,44H
sl@15
   514
[Function] Send the ID code to the Host system. ID code is software version.
sl@10
   515
*/
sl@10
   516
void GP1212A02A::RequestFirmwareRevision()
sl@10
   517
    {
sl@15
   518
    if (RequestPending())
sl@15
   519
        {
sl@15
   520
        //Abort silently for now
sl@15
   521
        return;
sl@15
   522
        }
sl@15
   523
sl@15
   524
    //1BH,6AH,49H,44H
sl@15
   525
    //Send Software Revision Read Command
sl@15
   526
    FutabaVfdReport report;
sl@15
   527
    report[0]=0x00; //Report ID
sl@15
   528
    report[1]=0x04; //Report length
sl@15
   529
    report[2]=0x1B; //Command ID
sl@15
   530
    report[3]=0x6A; //Command ID
sl@15
   531
    report[4]=0x49; //Command ID
sl@15
   532
    report[5]=0x44; //Command ID
sl@15
   533
    if (Write(report)==report.Size())
sl@15
   534
        {
sl@15
   535
        SetRequest(EMiniDisplayRequestFirmwareRevision);
sl@15
   536
        }
sl@15
   537
sl@10
   538
    }
sl@10
   539
sl@10
   540
/**
sl@10
   541
*/
sl@10
   542
void GP1212A02A::RequestPowerSupplyStatus()
sl@10
   543
    {
sl@11
   544
	//Not supported
sl@10
   545
    }
sl@10
   546
sl@10
   547
sl@10
   548
/**
sl@10
   549
This is for development purposes only.
sl@10
   550
Production application should stick to off-screen mode to avoid tearing.
sl@10
   551
*/
sl@10
   552
void GP1212A02A::ToggleOffScreenMode()
sl@10
   553
	{
sl@10
   554
    SetOffScreenMode(!iOffScreenMode);
sl@10
   555
	}
sl@10
   556
sl@10
   557
/**
sl@10
   558
 * @brief GP1212A02A::SetOffScreenMode
sl@10
   559
 * @param aOn
sl@10
   560
 * @return
sl@10
   561
 */
sl@10
   562
void GP1212A02A::SetOffScreenMode(bool aOn)
sl@10
   563
    {
sl@10
   564
    if (aOn==iOffScreenMode)
sl@10
   565
    {
sl@10
   566
        //Nothing to do here
sl@10
   567
        return;
sl@10
   568
    }
sl@10
   569
sl@10
   570
    iOffScreenMode=aOn;
sl@10
   571
sl@10
   572
    //Clean up our buffers upon switching modes
sl@10
   573
    Clear();
sl@10
   574
    SwapBuffers();
sl@10
   575
    Clear();
sl@10
   576
    }
sl@10
   577
sl@10
   578
/**
sl@10
   579
Tries to complete our current request if we have one pending.
sl@10
   580
 */
sl@10
   581
TMiniDisplayRequest GP1212A02A::AttemptRequestCompletion()
sl@10
   582
    {
sl@15
   583
    if (!RequestPending())
sl@15
   584
        {
sl@15
   585
        return EMiniDisplayRequestNone;
sl@15
   586
        }
sl@15
   587
sl@15
   588
    int res=Read(iInputReport);
sl@15
   589
sl@15
   590
    if (!res)
sl@15
   591
        {
sl@15
   592
        return EMiniDisplayRequestNone;
sl@15
   593
        }
sl@15
   594
sl@15
   595
    //Process our request
sl@15
   596
	if (CurrentRequest()==EMiniDisplayRequestFirmwareRevision)
sl@15
   597
		{
sl@15
   598
			unsigned char* ptr=&iInputReport[2];
sl@15
   599
			iInputReport[7]=0x00;
sl@15
   600
			strcpy(iFirmwareRevision,(const char*)ptr);
sl@15
   601
		}
sl@15
   602
sl@15
   603
    TMiniDisplayRequest completed=CurrentRequest();
sl@15
   604
    //Our request was completed
sl@15
   605
    SetRequest(EMiniDisplayRequestNone);
sl@15
   606
sl@15
   607
    return completed;
sl@11
   608
	}
sl@10
   609
sl@10
   610
sl@10
   611
/**
sl@10
   612
Set our screen brightness.
sl@10
   613
@param The desired brightness level. Must be between MinBrightness and MaxBrightness.
sl@10
   614
*/
sl@10
   615
void GP1212A02A::SetBrightness(int aBrightness)
sl@10
   616
    {
sl@10
   617
    if (aBrightness<MinBrightness()||aBrightness>MaxBrightness())
sl@10
   618
        {
sl@10
   619
        //Brightness out of range.
sl@10
   620
        //Just ignore that request.
sl@10
   621
        return;
sl@10
   622
        }
sl@10
   623
sl@10
   624
    FutabaVfdReport report;
sl@10
   625
    report[0]=0x00; //Report ID
sl@10
   626
    report[1]=0x04; //Report size
sl@10
   627
    report[2]=0x1B; //Command ID
sl@10
   628
    report[3]=0x4A; //Command ID
sl@10
   629
    report[4]=0x44; //Command ID
sl@13
   630
    report[5]=0x30+aBrightness; //Brightness level
sl@10
   631
    Write(report);
sl@10
   632
    }
sl@10
   633
sl@10
   634
/**
sl@10
   635
*/
sl@16
   636
bool GP1212A02A::IsPowerOn()
sl@10
   637
	{
sl@10
   638
	return iPowerOn;
sl@10
   639
	}
sl@10
   640
sl@10
   641
/**
sl@10
   642
*/
sl@10
   643
char* GP1212A02A::DeviceId()
sl@10
   644
	{
sl@10
   645
	return iDeviceId;
sl@10
   646
	}
sl@10
   647
sl@10
   648
/**
sl@10
   649
*/
sl@10
   650
char* GP1212A02A::FirmwareRevision()
sl@10
   651
	{
sl@10
   652
	return iFirmwareRevision;
sl@10
   653
	}
sl@16
   654
sl@16
   655
/**
sl@16
   656
VFD Power ON/OFF 
sl@16
   657
[Code]1BH,4AH,42H,Ps
sl@16
   658
[Function]Control of the power supply for VFD 
sl@16
   659
* If VFD power ON or OFF, at interval of 10s or more. 
sl@16
   660
* When the VFD power off, VFD display is turn off, but the module can receive a data and 
sl@16
   661
process.
sl@16
   662
Ps = VFD Power control 
sl@16
   663
[Definable area]
sl@16
   664
Ps = 30H : VFD Power OFF 
sl@16
   665
Ps = 31H : VFD Power ON  (Default)
sl@16
   666
*/
sl@16
   667
void GP1212A02A::SendCommandPower(TPowerStatus aPowerStatus)
sl@16
   668
	{
sl@16
   669
	FutabaVfdReport report;
sl@16
   670
    report[0]=0x00; //Report ID
sl@16
   671
    report[1]=0x04; //Report size
sl@16
   672
    report[2]=0x1B; //Command ID
sl@16
   673
    report[3]=0x4A; //Command ID
sl@16
   674
    report[4]=0x42; //Command ID
sl@16
   675
    report[5]=aPowerStatus; //ON or OFF
sl@16
   676
    Write(report);
sl@16
   677
	}
sl@16
   678
sl@16
   679
/**
sl@16
   680
*/
sl@16
   681
void GP1212A02A::TurnPowerOn()
sl@16
   682
	{
sl@16
   683
	SendCommandPower(EPowerOn);
sl@17
   684
	SetClockSetting();
sl@16
   685
	}
sl@16
   686
sl@16
   687
/**
sl@16
   688
*/
sl@16
   689
void GP1212A02A::TurnPowerOff()
sl@16
   690
	{
sl@16
   691
	SendCommandPower(EPowerOff);
sl@16
   692
	}
sl@17
   693
sl@17
   694
sl@17
   695
/**
sl@17
   696
Number of characters for the given clock format.
sl@17
   697
@return 
sl@17
   698
*/
sl@17
   699
int GP1212A02A::ClockCharCount(TClockFormat aFormat)
sl@17
   700
	{
sl@17
   701
	switch (aFormat)
sl@17
   702
		{
sl@17
   703
	case EClockDay12:
sl@17
   704
	case EClockDay24:
sl@17
   705
		return 10;
sl@17
   706
	case EClock12:
sl@17
   707
	case EClock24:
sl@17
   708
		return 5;
sl@17
   709
		}
sl@17
   710
sl@17
   711
	return 10;
sl@17
   712
	}
sl@17
   713
sl@17
   714
/**
sl@17
   715
@return 
sl@17
   716
*/
sl@17
   717
int GP1212A02A::ClockCharWidthInPixels(TClockSize aSize)
sl@17
   718
	{
sl@17
   719
	switch (aSize)
sl@17
   720
		{
sl@17
   721
	case EClockTiny:
sl@17
   722
		return 6;
sl@17
   723
	case EClockSmall:
sl@17
   724
		return 8;
sl@17
   725
	case EClockMedium:
sl@17
   726
		return 12;
sl@17
   727
	case EClockLarge:
sl@17
   728
		return 16;
sl@17
   729
		}
sl@17
   730
sl@17
   731
	return 16;
sl@17
   732
	}
sl@17
   733
sl@17
   734
/**
sl@17
   735
@return 
sl@17
   736
*/
sl@17
   737
int GP1212A02A::ClockCharHeightInPixels(TClockSize aSize)
sl@17
   738
	{
sl@17
   739
	switch (aSize)
sl@17
   740
		{
sl@17
   741
	case EClockTiny:
sl@17
   742
		return 8;
sl@17
   743
	case EClockSmall:
sl@17
   744
		return 16;
sl@17
   745
	case EClockMedium:
sl@17
   746
		return 24;
sl@17
   747
	case EClockLarge:
sl@17
   748
		return 32;
sl@17
   749
		}
sl@17
   750
sl@17
   751
	return 32;
sl@17
   752
	}
sl@17
   753
sl@17
   754
/**
sl@17
   755
Return the Display Window address for centering the clock corresponding to the given parameters.
sl@17
   756
*/
sl@17
   757
unsigned short GP1212A02A::ClockCenterAddress(TClockFormat aFormat, TClockSize aSize)
sl@17
   758
	{
sl@17
   759
		int charCount=ClockCharCount(aFormat);
sl@17
   760
		int halfWidth=(ClockCharWidthInPixels(aSize)*charCount)/2;
sl@17
   761
		int halfHeight=(ClockCharHeightInPixels(aSize))/2;
sl@17
   762
		int x=(WidthInPixels()/2)-halfWidth;
sl@17
   763
		int y=(HeightInPixels()/2)-halfHeight;
sl@17
   764
sl@17
   765
		int yOffset=y/8;
sl@17
   766
		int xOffset=x*8; //Not sure why...
sl@17
   767
sl@17
   768
		unsigned short address = yOffset+xOffset;
sl@17
   769
		//
sl@17
   770
		return address;
sl@17
   771
	}
sl@17
   772
sl@17
   773
/**
sl@17
   774
*/
sl@17
   775
void GP1212A02A::ShowClock()
sl@17
   776
	{
sl@17
   777
	SendCommandClockDisplay(EClockDay24,ClockCenterAddress(EClockDay24,EClockLarge),EClockLarge);
sl@17
   778
	}
sl@17
   779
sl@17
   780
/**
sl@17
   781
*/
sl@17
   782
void GP1212A02A::HideClock()
sl@17
   783
	{
sl@17
   784
	SendCommandClockCancel();
sl@17
   785
	}
sl@17
   786
sl@17
   787
sl@17
   788
/**
sl@17
   789
Clock setting 
sl@17
   790
[Code]1BH,6BH,53H,Pd,Ph,Pm 
sl@17
   791
[Function]Setting the clock data. The setting data is cleared, if the Reset command is input or power 
sl@17
   792
is turned off. 
sl@17
   793
Pd = Day of the week 
sl@17
   794
Ph = hour 
sl@17
   795
Pm = minute 
sl@17
   796
[Definable area]
sl@17
   797
Pd = 00H : Sunday 
sl@17
   798
Pd = 01H : Monday 
sl@17
   799
...
sl@17
   800
Pd = 06H : Saturday 
sl@17
   801
* Clock setting is canceled, when Pd is input value that is larger than 07H, or Ph is input value that is 
sl@17
   802
larger than 18H,or Pm is input value that is larger than 3CH. 
sl@17
   803
*/
sl@17
   804
void GP1212A02A::SendCommandClockSetting(TWeekDay aWeekDay, unsigned char aHour, unsigned char aMinute)
sl@17
   805
	{
sl@17
   806
	FutabaVfdReport report;
sl@17
   807
    report[0]=0x00; //Report ID
sl@17
   808
    report[1]=0x06; //Report size
sl@17
   809
    report[2]=0x1B; //Command ID
sl@17
   810
    report[3]=0x6B; //Command ID
sl@17
   811
    report[4]=0x53; //Command ID
sl@17
   812
    report[5]=aWeekDay; //Sunday to Saturday
sl@17
   813
	report[6]=aHour;
sl@17
   814
	report[7]=aMinute;
sl@17
   815
sl@17
   816
    Write(report);
sl@17
   817
	}
sl@17
   818
sl@17
   819
sl@17
   820
/**
sl@17
   821
Set display clock settings according to local system time.
sl@17
   822
This needs to be redone whenever we open or turn on our display.
sl@17
   823
*/
sl@17
   824
void GP1212A02A::SetClockSetting()
sl@17
   825
	{
sl@17
   826
	time_t rawtime;
sl@17
   827
	struct tm * timeinfo;
sl@17
   828
sl@17
   829
	time ( &rawtime );
sl@17
   830
	timeinfo = localtime ( &rawtime );
sl@17
   831
	//
sl@17
   832
	SendCommandClockSetting((TWeekDay)timeinfo->tm_wday,timeinfo->tm_hour,timeinfo->tm_min);
sl@17
   833
	}
sl@17
   834
sl@17
   835
sl@17
   836
/**
sl@17
   837
Clock display
sl@17
   838
[Code] 1BH,6BH,55H,Ps,aL,aH,Pf
sl@17
   839
[Function] Clock is displayed. The display position and the font size can be freely decided. 
sl@17
   840
Ps = Display type select 
sl@17
   841
aL,aH = Address 
sl@17
   842
Pf = Font size select 
sl@17
   843
[Definable area]
sl@17
   844
Ps = 00H : 24hour Ex.[12:34] 
sl@17
   845
Ps = 01H : 24hour + day of the week  Ex.[Wed._12:34] 
sl@17
   846
Ps = 10H : 12hour Ex.[PM_00:34] 
sl@17
   847
Ps = 11H : 12hour + day of the week  Ex.[Wed._PM_00:34] 
sl@17
   848
Pf = 30H : 6x8 dot 
sl@17
   849
Pf = 31H : 8x16dot
sl@17
   850
Pf = 32H : 12x24 dot 
sl@17
   851
Pf = 33H : 16x32 dot 
sl@17
   852
* When the clock data is not input, clock is not displayed. 
sl@17
   853
* The clock display is maintained until Clock display cancel "Clear display" RESET command is input 
sl@17
   854
or power is turned off. 
sl@17
   855
The clock display area
sl@17
   856
Graphic can be displayed excluding the clock display area.
sl@17
   857
The self adjustment for the position 
sl@17
   858
that cannot be displayed. 
sl@17
   859
* Excluding the clock display area can be input other display commands.
sl@17
   860
*/
sl@17
   861
void GP1212A02A::SendCommandClockDisplay(TClockFormat aClockFormat, unsigned short aAddress, TClockSize aSize)
sl@17
   862
	{
sl@17
   863
	FutabaVfdReport report;
sl@17
   864
    report[0]=0x00; //Report ID
sl@17
   865
    report[1]=0x07; //Report size
sl@17
   866
    report[2]=0x1B; //Command ID
sl@17
   867
    report[3]=0x6B; //Command ID
sl@17
   868
    report[4]=0x55; //Command ID
sl@17
   869
    report[5]=aClockFormat; //
sl@17
   870
	report[6]=(unsigned char)aAddress;	//aL
sl@17
   871
	report[7]=aAddress>>8;				//aH
sl@17
   872
	report[8]=aSize;
sl@17
   873
sl@17
   874
    Write(report);
sl@17
   875
	}
sl@17
   876
sl@17
   877
sl@17
   878
/**
sl@17
   879
 Clock display cancel 
sl@17
   880
[Code] 1BH,6BH,3DH,58H
sl@17
   881
[Function] Clock display is canceled.
sl@17
   882
*/
sl@17
   883
void GP1212A02A::SendCommandClockCancel()
sl@17
   884
	{
sl@17
   885
	FutabaVfdReport report;
sl@17
   886
    report[0]=0x00; //Report ID
sl@17
   887
    report[1]=0x04; //Report size
sl@17
   888
    report[2]=0x1B; //Command ID
sl@17
   889
    report[3]=0x6B; //Command ID
sl@17
   890
    report[4]=0x3D; //Command ID
sl@17
   891
    report[5]=0x58; //
sl@17
   892
sl@17
   893
    Write(report);
sl@17
   894
	}