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