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