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