FutabaGP1212A02.cpp
author StephaneLenclud
Thu, 05 Feb 2015 11:41:19 +0100
changeset 27 949be5444c57
parent 25 3fa4007c0b19
parent 23 e63ba12d7a18
child 29 9b44c6e1651c
permissions -rw-r--r--
MDM166AA swap buffers now working.
     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     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 		
   506 		//This appears to be the fastest scheme when running on our HTPC
   507 		//Send pixel data directly into the display window
   508 		BmpDataInput(ETargetDisplayWindow,0x0000,EDirectionY, FrameBufferSizeInBytes(),iFrameNext->Ptr());
   509 		
   510 		//Send pixel data first to Data Memory then copy into the selected BMP box	
   511 		//BmpDataInput(ETargetDataMemory,0x0000,EDirectionY, FrameBufferSizeInBytes(),iFrameNext->Ptr());
   512 		//BmpBoxDataMemoryTransfer(0x0000);
   513 		
   514 		//Send pixel data first to Data Memory then copy into the selected BMP box, cycling through our Data Memory frame
   515 #if 0
   516 		BmpDataInput(ETargetDataMemory,iNextFrameAddress,EDirectionY, FrameBufferSizeInBytes(),iFrameNext->Ptr());
   517 		BmpBoxDataMemoryTransfer(iNextFrameAddress);
   518 		iNextFrameAddress+=KFrameSizeInBytes;
   519 		if (iNextFrameAddress>KMaxDataMemoryAddress)
   520 		{
   521 			iNextFrameAddress=0x0000;
   522 		}
   523 #endif
   524 
   525         //Cycle through our frame buffers
   526         //We keep track of previous frame which is in fact our device back buffer.
   527         //We can then compare previous and next frame and send only the differences to our device.
   528         //This mechanism allows us to reduce traffic over our USB bus thus improving our frame rate from 14 FPS to 30 FPS.
   529         //Keep our previous frame pointer
   530         BitArrayLow* previousFrame=iFramePrevious;
   531         //Current frame becomes the previous one
   532         iFramePrevious = iFrameCurrent;
   533         //Next frame becomes the current one
   534         iFrameCurrent = iFrameNext;
   535         //Next frame is now our former previous
   536         iFrameNext = previousFrame;
   537 		}
   538 	}
   539 
   540 
   541 //Define the edge of our pixel block
   542 //Pixel blocks of 32x32 seems to run almost as fast as full screen update in worse case scenarii.
   543 //Though I wonder if in some situations 16 could be better. Make this an attribute at some point if need be.
   544 const int KPixelBlockEdge = 32;
   545 const int KPixelBlockSizeInBits = KPixelBlockEdge*KPixelBlockEdge;
   546 const int KPixelBlockSizeInBytes = KPixelBlockSizeInBits/8;
   547 
   548 
   549 /**
   550 Translate the given pixel coordinate according to our off screen mode.
   551 */
   552 void GP1212A02A::OffScreenTranslation(unsigned char& aX, unsigned char& aY)
   553 	{
   554 	if (OffScreenMode())
   555 		{
   556 		aX+=WidthInPixels()-iDisplayPositionX;
   557 		aY+=HeightInPixels()-iDisplayPositionY;
   558 		}
   559 	}
   560 
   561 
   562 /**
   563 */
   564 void GP1212A02A::Request(TMiniDisplayRequest aRequest)
   565 	{
   566 	switch (aRequest)
   567 		{
   568 	case EMiniDisplayRequestDeviceId:
   569 		RequestDeviceId();
   570 		break;
   571 	case EMiniDisplayRequestFirmwareRevision:
   572 		RequestFirmwareRevision();
   573 		break;
   574 	case EMiniDisplayRequestPowerSupplyStatus:
   575 		RequestPowerSupplyStatus();
   576 		break;
   577 	default:
   578 		//Not supported
   579 		break;
   580 		};
   581 	}
   582 
   583 
   584 /**
   585 */
   586 void GP1212A02A::ResetBuffers()
   587 	{
   588     //iNextFrame->ClearAll();
   589     //memset(iFrameAlpha,0x00,sizeof(iFrameAlpha));
   590 	//memset(iFrameBeta,0x00,sizeof(iFrameBeta));
   591 	}
   592 
   593 /**
   594 */
   595 void GP1212A02A::RequestDeviceId()
   596     {
   597 	//Not supported
   598     }
   599 
   600 /**
   601 ID code 
   602 [Code] 1BH,6AH,49H,44H
   603 [Function] Send the ID code to the Host system. ID code is software version.
   604 */
   605 void GP1212A02A::RequestFirmwareRevision()
   606     {
   607     if (RequestPending())
   608         {
   609         //Abort silently for now
   610         return;
   611         }
   612 
   613     //1BH,6AH,49H,44H
   614     //Send Software Revision Read Command
   615     FutabaVfdReport report;
   616     report[0]=0x00; //Report ID
   617     report[1]=0x04; //Report length
   618     report[2]=0x1B; //Command ID
   619     report[3]=0x6A; //Command ID
   620     report[4]=0x49; //Command ID
   621     report[5]=0x44; //Command ID
   622     if (Write(report)==report.Size())
   623         {
   624         SetRequest(EMiniDisplayRequestFirmwareRevision);
   625         }
   626 
   627     }
   628 
   629 /**
   630 */
   631 void GP1212A02A::RequestPowerSupplyStatus()
   632     {
   633 	//Not supported
   634     }
   635 
   636 
   637 /**
   638 This is for development purposes only.
   639 Production application should stick to off-screen mode to avoid tearing.
   640 */
   641 void GP1212A02A::ToggleOffScreenMode()
   642 	{
   643     SetOffScreenMode(!iOffScreenMode);
   644 	}
   645 
   646 /**
   647  * @brief GP1212A02A::SetOffScreenMode
   648  * @param aOn
   649  * @return
   650  */
   651 void GP1212A02A::SetOffScreenMode(bool aOn)
   652     {
   653     if (aOn==iOffScreenMode)
   654     {
   655         //Nothing to do here
   656         return;
   657     }
   658 
   659     iOffScreenMode=aOn;
   660 
   661     //Clean up our buffers upon switching modes
   662     Clear();
   663     SwapBuffers();
   664     Clear();
   665     }
   666 
   667 /**
   668 Tries to complete our current request if we have one pending.
   669  */
   670 TMiniDisplayRequest GP1212A02A::AttemptRequestCompletion()
   671     {
   672     if (!RequestPending())
   673         {
   674         return EMiniDisplayRequestNone;
   675         }
   676 
   677     int res=Read(iInputReport);
   678 
   679     if (!res)
   680         {
   681         return EMiniDisplayRequestNone;
   682         }
   683 
   684     //Process our request
   685 	if (CurrentRequest()==EMiniDisplayRequestFirmwareRevision)
   686 		{
   687 			unsigned char* ptr=&iInputReport[2];
   688 			iInputReport[7]=0x00;
   689 			strcpy(iFirmwareRevision,(const char*)ptr);
   690 		}
   691 
   692     TMiniDisplayRequest completed=CurrentRequest();
   693     //Our request was completed
   694     SetRequest(EMiniDisplayRequestNone);
   695 
   696     return completed;
   697 	}
   698 
   699 
   700 /**
   701 Set our screen brightness.
   702 @param The desired brightness level. Must be between MinBrightness and MaxBrightness.
   703 */
   704 void GP1212A02A::SetBrightness(int aBrightness)
   705     {
   706     if (aBrightness<MinBrightness()||aBrightness>MaxBrightness())
   707         {
   708         //Brightness out of range.
   709         //Just ignore that request.
   710         return;
   711         }
   712 
   713     FutabaVfdReport report;
   714     report[0]=0x00; //Report ID
   715     report[1]=0x04; //Report size
   716     report[2]=0x1B; //Command ID
   717     report[3]=0x4A; //Command ID
   718     report[4]=0x44; //Command ID
   719     report[5]=0x30+aBrightness; //Brightness level
   720     Write(report);
   721     }
   722 
   723 /**
   724 */
   725 bool GP1212A02A::IsPowerOn()
   726 	{
   727 	return iPowerOn;
   728 	}
   729 
   730 /**
   731 */
   732 char* GP1212A02A::DeviceId()
   733 	{
   734 	return iDeviceId;
   735 	}
   736 
   737 /**
   738 */
   739 char* GP1212A02A::FirmwareRevision()
   740 	{
   741 	return iFirmwareRevision;
   742 	}
   743 
   744 /**
   745 VFD Power ON/OFF 
   746 [Code]1BH,4AH,42H,Ps
   747 [Function]Control of the power supply for VFD 
   748 * If VFD power ON or OFF, at interval of 10s or more. 
   749 * When the VFD power off, VFD display is turn off, but the module can receive a data and 
   750 process.
   751 Ps = VFD Power control 
   752 [Definable area]
   753 Ps = 30H : VFD Power OFF 
   754 Ps = 31H : VFD Power ON  (Default)
   755 */
   756 void GP1212A02A::SendCommandPower(TPowerStatus aPowerStatus)
   757 	{
   758 	FutabaVfdReport report;
   759     report[0]=0x00; //Report ID
   760     report[1]=0x04; //Report size
   761     report[2]=0x1B; //Command ID
   762     report[3]=0x4A; //Command ID
   763     report[4]=0x42; //Command ID
   764     report[5]=aPowerStatus; //ON or OFF
   765     Write(report);
   766 	}
   767 
   768 /**
   769 */
   770 void GP1212A02A::TurnPowerOn()
   771 	{
   772 	SendCommandPower(EPowerOn);
   773 	SetClockSetting();
   774 	}
   775 
   776 /**
   777 */
   778 void GP1212A02A::TurnPowerOff()
   779 	{
   780 	SendCommandPower(EPowerOff);
   781 	}
   782 
   783 
   784 /**
   785 Provide the length of our character string for the given clock format.
   786 @param The clock format to evaluate.
   787 @return Number of characters for the given clock format.
   788 */
   789 int GP1212A02A::ClockCharCount(TClockFormat aFormat)
   790 	{
   791 	switch (aFormat)
   792 		{
   793 	case EClockDay12:
   794 		return 13;
   795 	case EClockDay24:
   796 		return 10;
   797 	case EClock12:
   798 		return 8;
   799 	case EClock24:
   800 		return 5;
   801 		}
   802 
   803 	return 10;
   804 	}
   805 
   806 /**
   807 @return Clock character width in pixels.
   808 */
   809 int GP1212A02A::ClockCharWidthInPixels(TFontSizeLogical aSize)
   810 	{
   811 	switch (aSize)
   812 		{
   813 	case EFontTiny:
   814 		return 6;
   815 	case EFontSmall:
   816 		return 8;
   817 	case EFontMedium:
   818 		return 12;
   819 	case EFontLarge:
   820 		return 16;
   821 		}
   822 
   823 	return 16;
   824 	}
   825 
   826 /**
   827 @return Clock character height in pixels.
   828 */
   829 int GP1212A02A::ClockCharHeightInPixels(TFontSizeLogical aSize)
   830 	{
   831 	switch (aSize)
   832 		{
   833 	case EFontTiny:
   834 		return 8;
   835 	case EFontSmall:
   836 		return 16;
   837 	case EFontMedium:
   838 		return 24;
   839 	case EFontLarge:
   840 		return 32;
   841 		}
   842 
   843 	return 32;
   844 	}
   845 
   846 /**
   847 Return the Display Window address for centering the clock corresponding to the given parameters.
   848 */
   849 unsigned short GP1212A02A::ClockCenterAddress(TClockFormat aFormat, TFontSizeLogical aSize)
   850 	{
   851 		int charCount=ClockCharCount(aFormat);
   852 		int halfWidth=(ClockCharWidthInPixels(aSize)*charCount)/2;
   853 		int halfHeight=(ClockCharHeightInPixels(aSize))/2;
   854 		int x=(WidthInPixels()/2)-halfWidth;
   855 		int y=(HeightInPixels()/2)-halfHeight;
   856 
   857 		int yOffset=y/8;
   858 		int xOffset=x*8; //Not sure why...
   859 
   860 		unsigned short address = yOffset+xOffset;
   861 		//
   862 		return address;
   863 	}
   864 
   865 /**
   866 */
   867 void GP1212A02A::ShowClock()
   868 	{
   869 	SendCommandClockDisplay(EClock24,ClockCenterAddress(EClock24,EFontLarge),EFontLarge);
   870 	}
   871 
   872 /**
   873 */
   874 void GP1212A02A::HideClock()
   875 	{
   876 	SendCommandClockCancel();
   877 	}
   878 
   879 
   880 /**
   881 Clock setting 
   882 [Code]1BH,6BH,53H,Pd,Ph,Pm 
   883 [Function]Setting the clock data. The setting data is cleared, if the Reset command is input or power 
   884 is turned off. 
   885 Pd = Day of the week 
   886 Ph = hour 
   887 Pm = minute 
   888 [Definable area]
   889 Pd = 00H : Sunday 
   890 Pd = 01H : Monday 
   891 ...
   892 Pd = 06H : Saturday 
   893 * Clock setting is canceled, when Pd is input value that is larger than 07H, or Ph is input value that is 
   894 larger than 18H,or Pm is input value that is larger than 3CH. 
   895 */
   896 void GP1212A02A::SendCommandClockSetting(TWeekDay aWeekDay, unsigned char aHour, unsigned char aMinute)
   897 	{
   898 	FutabaVfdReport report;
   899     report[0]=0x00; //Report ID
   900     report[1]=0x06; //Report size
   901     report[2]=0x1B; //Command ID
   902     report[3]=0x6B; //Command ID
   903     report[4]=0x53; //Command ID
   904     report[5]=aWeekDay; //Sunday to Saturday
   905 	report[6]=aHour;
   906 	report[7]=aMinute;
   907 
   908     Write(report);
   909 	}
   910 
   911 
   912 /**
   913 Set display clock settings according to local system time.
   914 This needs to be redone whenever we open or turn on our display.
   915 */
   916 void GP1212A02A::SetClockSetting()
   917 	{
   918 	time_t rawtime;
   919 	struct tm * timeinfo;
   920 
   921 	time ( &rawtime );
   922 	timeinfo = localtime ( &rawtime );
   923 	//
   924 	SendCommandClockSetting((TWeekDay)timeinfo->tm_wday,timeinfo->tm_hour,timeinfo->tm_min);
   925 	}
   926 
   927 
   928 /**
   929 Clock display
   930 [Code] 1BH,6BH,55H,Ps,aL,aH,Pf
   931 [Function] Clock is displayed. The display position and the font size can be freely decided. 
   932 Ps = Display type select 
   933 aL,aH = Address 
   934 Pf = Font size select 
   935 [Definable area]
   936 Ps = 00H : 24hour Ex.[12:34] 
   937 Ps = 01H : 24hour + day of the week  Ex.[Wed._12:34] 
   938 Ps = 10H : 12hour Ex.[PM_00:34] 
   939 Ps = 11H : 12hour + day of the week  Ex.[Wed._PM_00:34] 
   940 Pf = 30H : 6x8 dot 
   941 Pf = 31H : 8x16dot
   942 Pf = 32H : 12x24 dot 
   943 Pf = 33H : 16x32 dot 
   944 * When the clock data is not input, clock is not displayed. 
   945 * The clock display is maintained until Clock display cancel "Clear display" RESET command is input 
   946 or power is turned off. 
   947 The clock display area
   948 Graphic can be displayed excluding the clock display area.
   949 The self adjustment for the position 
   950 that cannot be displayed. 
   951 * Excluding the clock display area can be input other display commands.
   952 */
   953 void GP1212A02A::SendCommandClockDisplay(TClockFormat aClockFormat, unsigned short aAddress, TFontSizeLogical aSize)
   954 	{
   955 	FutabaVfdReport report;
   956     report[0]=0x00; //Report ID
   957     report[1]=0x07; //Report size
   958     report[2]=0x1B; //Command ID
   959     report[3]=0x6B; //Command ID
   960     report[4]=0x55; //Command ID
   961     report[5]=aClockFormat; //
   962 	report[6]=(unsigned char)aAddress;	//aL
   963 	report[7]=aAddress>>8;				//aH
   964 	report[8]=aSize;
   965 
   966     Write(report);
   967 	}
   968 
   969 
   970 /**
   971  Clock display cancel 
   972 [Code] 1BH,6BH,3DH,58H
   973 [Function] Clock display is canceled.
   974 */
   975 void GP1212A02A::SendCommandClockCancel()
   976 	{
   977 	FutabaVfdReport report;
   978     report[0]=0x00; //Report ID
   979     report[1]=0x04; //Report size
   980     report[2]=0x1B; //Command ID
   981     report[3]=0x6B; //Command ID
   982     report[4]=0x3D; //Command ID
   983     report[5]=0x58; //
   984 
   985     Write(report);
   986 	}
   987 
   988 
   989 /**
   990 @return Size in bytes of a character for a given font size.
   991 */
   992 int GP1212A02A::CharacterSizeInBytes(TFontSize aFontSize)
   993 	{
   994 	switch (aFontSize)
   995 		{
   996 	case EFont6x8:
   997 		return 6;
   998 	case EFont8x16:
   999 		return 16;
  1000 	case EFont12x24:
  1001 		return 36;
  1002 	case EFont16x32:
  1003 		return 64;
  1004 	case EFont16x16:
  1005 		return 32;
  1006 	case EFont24x24:
  1007 		return 72;
  1008 	case EFont32x32:
  1009 		return 128;
  1010 		}
  1011 
  1012 	return 0;
  1013 	}
  1014 
  1015 /**
  1016 Define the User definable font (RAM) 
  1017 [Code] 1BH,6AH,47H,Pf,cL,(cH),Pd...Pd
  1018 [Function] Define the User definable font into RAM. A maximum 16 characters can be defined 
  1019 within each font size. 
  1020 The User definable fonts are displayed the defined code. It is a same process to normal fonts.  
  1021 The User definable fonts are valid until they redefined, Reset command, or the power off. 
  1022 If define the user definable font over 16 characters, at first defined user definable font is removed    
  1023 If the defined code is specified, existing data is re-written. 
  1024 If the 16x16, 24x24, 32x32 size define, it must specify the “cH” 
  1025 Pf = Font size 
  1026 cL = Lower byte of User definable font code 
  1027 cH = Upper byte of User definable font code 
  1028 Pd = Definition data 
  1029 [Definable area]
  1030 Pf = 30H : 6x8 dot  (Pd=6 byte) 
  1031 Pf = 31H : 8x16 dot  (Pd=16 byte) 
  1032 Pf = 32H : 12x24 dot  (Pd=36 byte) 
  1033 Pf = 33H : 16x32 dot  (Pd=64 byte) 
  1034 Pf = 34H : 16x16 dot  (Pd=32 byte) 
  1035 Pf = 35H : 24x24 dot  (Pd=72 byte) 
  1036 Pf = 36H : 32x32 dot  (Pd=128 byte) 
  1037 cL = ANK code (Pf=30H~33H : 1 byte code) 
  1038 cL,cH = Shift-JIS code (Pf=34H~36H : 2 byte code)
  1039 */
  1040 void GP1212A02A::SendCommandDefineCharacter(TFontSize aFontSize, unsigned short aCharacterCode, unsigned char* aPixels)
  1041 	{
  1042 	unsigned char reportSize=0;
  1043 	unsigned char headerSize=0;
  1044 	unsigned char dataSize=CharacterSizeInBytes(aFontSize);
  1045 	FutabaVfdReport report;
  1046 
  1047 	if (aFontSize>=EFont16x16)
  1048 	{
  1049 		//16 bits char code
  1050 		headerSize=8;
  1051 		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
  1052 		report[7] = aCharacterCode>>8;	
  1053 	}
  1054 	else
  1055 	{
  1056 		//8 bits char code
  1057 		headerSize=7;
  1058 		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
  1059 	}
  1060 
  1061 	
  1062     report[0]=0x00; //Report ID
  1063     report[1]=reportSize; //Report size
  1064     report[2]=0x1B; //Command ID
  1065     report[3]=0x6A; //Command ID
  1066     report[4]=0x47; //Command ID
  1067     report[5]=aFontSize; //
  1068 	report[6] = (unsigned char) aCharacterCode;
  1069 	//7th byte was set above already
  1070 	int sizeWritten=MIN(dataSize,report.Size()-headerSize);
  1071     memcpy(report.Buffer()+headerSize, aPixels, sizeWritten);
  1072     Write(report);
  1073 
  1074     int remainingSize=dataSize;
  1075     //We need to keep on sending our pixel data until we are done
  1076     while (report[1]==64)
  1077         {
  1078         report.Reset();
  1079         remainingSize-=sizeWritten;
  1080         report[0]=0x00; //Report ID
  1081         report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
  1082         sizeWritten=(report[1]==64?63:report[1]);
  1083         memcpy(report.Buffer()+2, aPixels+(dataSize-remainingSize), sizeWritten);
  1084         Write(report);
  1085         }
  1086 	}
  1087 
  1088 
  1089 /**
  1090 User definable font store / transfer / delete 
  1091 [Code] 1BH,6AH,45H,Ps
  1092 [Function] Store, transfer, or delete the User definable font to FROM.  
  1093 * Define the user definable font, after the user definable font is stored 
  1094 * The user definable font store is stored the all defined user definable font data. 
  1095 * The use definable font delete is deleted the all defined to FROM and RAM user definable font data. 
  1096 Ps = store / transfer / delete 
  1097 [Definable area]
  1098 Ps = 30H : Store
  1099 Ps = 31H : Transfer
  1100 Ps = 32H : Delete
  1101 */
  1102 void GP1212A02A::SendCommandFontAction(TFontAction aFontAction)
  1103 	{
  1104 	FutabaVfdReport report;
  1105     report[0]=0x00; //Report ID
  1106     report[1]=0x04; //Report size
  1107     report[2]=0x1B; //Command ID
  1108     report[3]=0x6A; //Command ID
  1109     report[4]=0x45; //Command ID
  1110     report[5]=aFontAction; //Ps
  1111 
  1112     Write(report);
  1113 	}
  1114 
  1115 
  1116 /**
  1117 [Code]1BH,4AH,46H,Pf
  1118 [Function]Setting the font size 
  1119  Pf = Font size 
  1120 [Definable area]
  1121 Pf = 30H?6x8 dot 
  1122 Pf = 31H?8x16dot and 16x16 dot 
  1123 Pf = 32H?12x24 dot and 24x24 dot 
  1124 Pf = 33H?16x32 dot and 32x32 dot
  1125 */
  1126 void GP1212A02A::SendCommandSelectFontSize(TFontSizeLogical aFontSoze)
  1127 	{
  1128 	FutabaVfdReport report;
  1129     report[0]=0x00; //Report ID
  1130     report[1]=0x04; //Report size
  1131     report[2]=0x1B; //Command ID
  1132     report[3]=0x4A; //Command ID
  1133     report[4]=0x46; //Command ID
  1134     report[5]=aFontSoze; //Pf
  1135 
  1136     Write(report);
  1137 	}