FutabaGP1212A02.cpp
author sl
Sun, 31 Aug 2014 18:33:31 +0200
changeset 16 42ba42be810d
parent 15 105f2c0d3cf1
child 17 591e9f922c63
permissions -rw-r--r--
Adding support for power on/off.
     1 //
     2 //
     3 //
     4 
     5 #include "FutabaGP1212A02.h"
     6 
     7 
     8 const int KNumberOfFrameBeforeDiffAlgo = 3;
     9 
    10 const unsigned short KMaxDataMemoryAddress = 0x4FFF;
    11 const unsigned short KFrameSizeInBytes = 0x800;
    12 
    13 //
    14 // class GP1212A02A
    15 //
    16 
    17 GP1212A02A::GP1212A02A():
    18 	iDisplayPositionX(0),iDisplayPositionY(0),
    19     iOffScreenMode(true),
    20     iUseFrameDifferencing(true),
    21     iFrameNext(NULL),
    22     iFrameCurrent(NULL),
    23     iFramePrevious(NULL),
    24     iFrameAlpha(NULL),
    25     iFrameBeta(NULL),
    26     iFrameGamma(NULL),
    27     iNeedFullFrameUpdate(0),
    28     iPowerOn(false)
    29 	{
    30 	iDeviceId[0]=0;
    31 	iFirmwareRevision[0]=0;
    32 	//ResetBuffers();
    33 	}
    34 
    35 /**
    36 */
    37 GP1212A02A::~GP1212A02A()
    38 	{
    39     delete iFrameAlpha;
    40     iFrameAlpha=NULL;
    41     //
    42     delete iFrameBeta;
    43     iFrameBeta=NULL;
    44     //
    45     delete iFrameGamma;
    46     iFrameGamma=NULL;
    47     //
    48     iFrameNext=NULL;
    49     iFrameCurrent=NULL;
    50     iFramePrevious=NULL;
    51     //
    52     iNeedFullFrameUpdate=0;
    53 	}
    54 
    55 /**
    56 */
    57 int GP1212A02A::Open()
    58 	{
    59 	int success = HidDevice::Open(KFutabaVendorId,KFutabaProductIdGP1212A02A,NULL);
    60 	if (success)
    61 		{
    62         //Allocate both frames
    63         delete iFrameAlpha;
    64         iFrameAlpha=NULL;
    65         iFrameAlpha=new BitArrayLow(KGP12xFrameBufferPixelCount);
    66         //
    67         delete iFrameBeta;
    68         iFrameBeta=NULL;
    69         iFrameBeta=new BitArrayLow(KGP12xFrameBufferPixelCount);
    70         //
    71         delete iFrameGamma;
    72         iFrameGamma=NULL;
    73         iFrameGamma=new BitArrayLow(KGP12xFrameBufferPixelCount);
    74         //
    75         iFrameNext=iFrameAlpha;
    76         iFrameCurrent=iFrameBeta;
    77         iFramePrevious=iFrameGamma;
    78 
    79 
    80         //To make sure it is synced properly
    81         iNeedFullFrameUpdate=0;
    82         //
    83 		SetNonBlocking(1);
    84 		//
    85 		SendClearCommand();
    86 
    87 		//Setup BMP box
    88 		BmpBoxSetting(EBmpBoxIdOne,0x0000,256,64);
    89 
    90 		//Select current BMP box
    91 		BmpBoxSelect(EBmpBoxIdOne);
    92 
    93 		iNextFrameAddress = 0x0000;
    94 
    95 		}
    96 	return success;
    97 	}
    98 
    99 /**
   100  Setting the BMP box
   101 [Code] 1BH,5CH,42H,Pn,aL,aH,Pw,Ph
   102 [Function] Setting the BMP box. BMP box can be defined the 3 area to DW. The position of BMP 
   103 box is set based on the address of DW. 
   104 * To write data in BMP box, BMP box select is necessary. 
   105 * Specifiable horizontal size is 256dot (100H) MAX. If horizontal size specify 256dot, Pw = 00H 
   106 Pn = Number of a BMP box 
   107 aL = Lower byte of address 
   108 aH = Upper byte of address 
   109 Pw = BMP box width 
   110 Ph = BMP box height 
   111 
   112 [Definable area]
   113 Pn = 31H - BMP box 1
   114 Pn = 32H - BMP box 2
   115 Pn = 33H - BMP box 3
   116 0000H <= aL + aH * 100 <= 07FFH 
   117 01H <= Pw <= 00H (=100H) 
   118 01H <= Ph <= 08H
   119 */
   120 void GP1212A02A::BmpBoxSetting(TBmpBoxId aBoxId, unsigned short aAddress, int aWidth, int aHeight)
   121 	{
   122 	//TODO: check parameters validity
   123 	//1BH,5CH,42H,Pn,aL,aH,Pw,Ph
   124 	FutabaVfdReport report;
   125 	report[0]=0x00; //Report ID
   126 	report[1]=0x08; //Report length.
   127 	report[2]=0x1B; //Command ID
   128 	report[3]=0x5C; //Command ID
   129 	report[4]=0x42; //Command ID
   130 	report[5]=aBoxId; 
   131 	report[6]=(unsigned char)aAddress; //aL = DM lower byte
   132 	report[7]=aAddress>>8; //aH = DM upper byte
   133 	report[8]=(aWidth==256?0x00:aWidth); //Pw = BMP box width 00==256
   134 	report[9]=aHeight/8; //Ph = BMP box height.
   135 	Write(report);
   136 	}
   137 
   138 /**
   139 [Code]1BH,5CH,48H,Pn
   140 [Function]Select of BMP box 
   141 * Execution "BMP box select" is necessary before "Setting the Text box". 
   142 * In case of writing by the specified dot writing, it is necessary to cancel this command. 
   143 [Definable area]
   144 Pn = 30H - Remove the BMP box 
   145 Pn = 31H - BMP box 1
   146 Pn = 32H - BMP box 2
   147 Pn = 33H - BMP box 3
   148 */
   149 void GP1212A02A::BmpBoxSelect(TBmpBoxId aBoxId)
   150 	{
   151 	//TODO: check parameters validity 
   152 	FutabaVfdReport report;
   153 	report[0]=0x00; //Report ID
   154 	report[1]=0x04; //Report length.
   155 	report[2]=0x1B; //Command ID
   156 	report[3]=0x5C; //Command ID
   157 	report[4]=0x48; //Command ID
   158 	report[5]=aBoxId; //BMP box ID
   159 	Write(report);
   160 	}
   161 
   162 
   163 /**
   164 */
   165 void GP1212A02A::SetPixel(unsigned char aX, unsigned char aY, bool aOn)
   166 	{
   167 	//
   168 	//int byteOffset=(aX*HeightInPixels()+aY)/8;
   169 	//int bitOffset=(aX*HeightInPixels()+aY)%8;
   170     //iNextFrame[byteOffset] |= ( (aOn?0x01:0x00) << bitOffset );
   171 
   172     if (iOffScreenMode)
   173         {
   174         if (aOn)
   175             {
   176             iFrameNext->SetBit(aX*HeightInPixels()+aY);
   177             }
   178         else
   179             {
   180             iFrameNext->ClearBit(aX*HeightInPixels()+aY);
   181             }
   182         }
   183     else
   184         {
   185         //Just specify a one pixel block
   186         //TODO
   187         }
   188 	}
   189 
   190 /**
   191 */
   192 /*
   193 void GP1212A02A::BitBlit(const BitArray& aBitmap, int aSrcWidth, int aSrcHeight, int aTargetX, int aTargetY) const
   194 	{
   195 	//TODO: amend loop values so that we don't keep on looping past our frame buffer dimensions.
   196 	for (int i=0;i<aSrcWidth;i++)
   197 		{
   198 		for (int j=0;j<aSrcHeight;j++)
   199 			{
   200             iFrameNext->SetBitValue((aTargetX+i)*HeightInPixels()+aTargetY+j,aBitmap[+i*aSrcHeight+j]);
   201 			}
   202 		}
   203 	}
   204 */
   205 
   206 /**
   207 Clear our client side back buffer.
   208 Call to SwapBuffers must follow to actually clear the display.
   209 */
   210 void GP1212A02A::Clear()
   211     {
   212     //memset(iNextFrame->Ptr(),0x00,FrameBufferSizeInBytes());
   213     if (iOffScreenMode)
   214         {
   215         iFrameNext->ClearAll();
   216         }
   217     else
   218         {
   219         SendClearCommand();
   220         }
   221     }
   222 
   223 /**
   224 Turn on all pixels.
   225 Must be followed by a SwapBuffers call.
   226 */
   227 void GP1212A02A::Fill()
   228 	{
   229 	SetAllPixels(0xFF);
   230 	}
   231 
   232 /**
   233 Set all pixels on our screen to the desired value.
   234 This operation is performed off screen to avoid tearing.
   235 @param 8 pixels pattern
   236 */
   237 void GP1212A02A::SetAllPixels(unsigned char aPattern)
   238 	{
   239 	//With a single buffer
   240 	//unsigned char screen[2048]; //One screen worth of pixels
   241 	//memset(screen,0xFF,sizeof(screen));
   242 	//SetPixelBlock(0,0,63,sizeof(screen),screen);
   243 
   244 
   245     if (iOffScreenMode)
   246         {
   247         memset(iFrameNext->Ptr(),aPattern,FrameBufferSizeInBytes());
   248         }
   249     else
   250         {
   251         //Using pattern SetPixelBlock variant.
   252         //TODO
   253         }
   254 	//
   255 	}
   256 
   257 
   258 
   259 
   260 /**
   261 BMP data input 
   262 [Code] 1BH,4AH,Pm,aL,aH,Ps,nL,nH,Pd...Pd
   263 [Function] The BMP data is written in the DW(Display Window) or the Data memory. 
   264 Pm= DW or Data memory 
   265 aL = DW lower byte 
   266 aH = DW upper byte 
   267 Ps = Direction of writing 
   268 nL = number of BMP data length lower byte 
   269 nH = number of BMP data length upper byte 
   270 Pd = BMP data 
   271 * If X direction is selected as Ps and data is written in the last address, the data in the last address is 
   272 overwritten with the remaining data.  
   273 [Definable area] Pm = 30H : DW
   274  Pm = 31H: Data memory 
   275 0000H <= aL + aH * 100 <= 07FFH (DW)
   276 0000H <= aL + aH * 100 <= 4FFFH (Data memory) 
   277 Ps = 30H: Y direction 
   278 Ps = 31H: X direction 
   279 0001H <= nL + nH * 100 <= 0100H(DW: X direction) 
   280 0001H <= nL + nH * 100 <= 0800H(DW: Y direction) 
   281 0001H <= nL + nH * 100 <= 0A00H(Data memory: X direction) 
   282 0001H <= nL + nH * 100 <= 5000H(Data memory: Y direction) 
   283 */
   284 void GP1212A02A::BmpDataInput(TTarget aTarget, unsigned short aAddress, TDirection aDirection, unsigned short aSize, unsigned char* aPixels)
   285 {
   286 	FutabaVfdReport report;
   287     report[0]=0x00; //Report ID
   288     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
   289     report[2]=0x1B; //Command ID
   290     report[3]=0x4A; //Command ID
   291     report[4]=aTarget; //Display Window or Data Memory
   292     report[5]=(unsigned char)aAddress; //aL = DW lower byte
   293     report[6]=aAddress>>8; //aH = DW upper byte
   294     report[7]=aDirection; //Direction of writing: Y or X
   295 	report[8]=(unsigned char)aSize; //Size of pixel data in bytes (LSB)
   296 	report[9]=aSize>>8;	//Size of pixel data in bytes (MSB)
   297     int sizeWritten=MIN(aSize,report.Size()-10);
   298     memcpy(report.Buffer()+10, aPixels, sizeWritten);
   299     Write(report);
   300 
   301     int remainingSize=aSize;
   302     //We need to keep on sending our pixel data until we are done
   303     while (report[1]==64)
   304         {
   305         report.Reset();
   306         remainingSize-=sizeWritten;
   307         report[0]=0x00; //Report ID
   308         report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
   309         sizeWritten=(report[1]==64?63:report[1]);
   310         memcpy(report.Buffer()+2, aPixels+(aSize-remainingSize), sizeWritten);
   311         Write(report);
   312         }
   313 }
   314 
   315 
   316 /**
   317 Data memory transfer
   318 [Code] 1BH,5CH,44H,aL,aH
   319 [Function] BMP data transfer from Data memory to DW. 
   320 Although source data is updated, data in BMP box is not updated. To reflect the update, 
   321 re-executing this command is necessary. 
   322 aL = Lower byte of address 
   323 aH = Upper byte of address 
   324 [Definable area]
   325 0000H <= aL + aH * 100 <= 4FFFH 
   326 */
   327 void GP1212A02A::BmpBoxDataMemoryTransfer(unsigned short aAddress)
   328 	{
   329 	FutabaVfdReport report;
   330 	report[0]=0x00; //Report ID
   331     report[1]=0x05; //Report length.
   332     report[2]=0x1B; //Command ID
   333     report[3]=0x5C; //Command ID
   334     report[4]=0x44; //Command ID
   335     report[5]=(unsigned char)aAddress; //aL = DM lower byte
   336     report[6]=aAddress>>8; //aH = DM upper byte
   337 	Write(report);
   338 	}
   339 
   340 /**
   341 Input BMP data in the BMP box 
   342 [Code] 1BH,5CH,5DH,nL,nH,Pd...Pd
   343 [Function] BMP data is written the BMP box 
   344 * Number of definable data is due to BMP box size. If the data is over range, the over range data is 
   345 rewritten the final address. 
   346 nL = Lower byte of number of definition byte 
   347 nH = Upper byte of number of definition byte 
   348 Pd = BMP data 
   349 [Definable area] Pn : BMP box size (Pw * Ph)
   350 */
   351 void GP1212A02A::BmpBoxDataInput(unsigned short aSize, unsigned char* aPixels)
   352 	{
   353 	FutabaVfdReport report;
   354     report[0]=0x00; //Report ID
   355     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
   356     report[2]=0x1B; //Command ID
   357     report[3]=0x5C; //Command ID
   358     report[4]=0x5D; //Display Window or Data Memory
   359 	report[5]=(unsigned char)aSize; //Size of pixel data in bytes (LSB)
   360 	report[6]=aSize>>8;	//Size of pixel data in bytes (MSB)
   361     int sizeWritten=MIN(aSize,report.Size()-7);
   362     memcpy(report.Buffer()+7, aPixels, sizeWritten);
   363     Write(report);
   364 
   365     int remainingSize=aSize;
   366     //We need to keep on sending our pixel data until we are done
   367     while (report[1]==64)
   368         {
   369         report.Reset();
   370         remainingSize-=sizeWritten;
   371         report[0]=0x00; //Report ID
   372         report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
   373         sizeWritten=(report[1]==64?63:report[1]);
   374         memcpy(report.Buffer()+2, aPixels+(aSize-remainingSize), sizeWritten);
   375         Write(report);
   376         }
   377 	}
   378 
   379 /**
   380 Using this function is advised against as is causes tearing.
   381 Use Clear instead.
   382 */
   383 void GP1212A02A::SendClearCommand()
   384 	{
   385     //1BH,4AH,43H,44H
   386     //Send Clear Display Command
   387 	FutabaVfdReport report;
   388 	report[0]=0x00; //Report ID
   389 	report[1]=0x04; //Report length
   390 	report[2]=0x1B; //Command ID
   391 	report[3]=0x4A; //Command ID
   392 	report[4]=0x43; //Command ID
   393 	report[5]=0x44; //Command ID
   394 	Write(report);
   395 	}
   396 
   397 
   398 /**
   399 Provide Y coordinate of our off screen buffer.
   400 */
   401 unsigned char GP1212A02A::OffScreenY() const
   402 	{
   403 	//Overflowing is fine this is just what we want
   404 	return iDisplayPositionY+HeightInPixels();
   405 	}
   406 
   407 /**
   408 Put our off screen buffer on screen.
   409 On screen buffer goes off screen.
   410 */
   411 void GP1212A02A::SwapBuffers()
   412 	{
   413 	//Only perform buffer swapping if off screen mode is enabled
   414 	if (OffScreenMode())
   415 		{
   416 		//Send pixel directly into BMP box
   417 		//BmpBoxDataInput(FrameBufferSizeInBytes(),iFrameNext->Ptr());
   418 		//Send pixel data directly into the display window
   419 		//BmpDataInput(ETargetDisplayWindow,0x0000,EDirectionY, FrameBufferSizeInBytes(),iFrameNext->Ptr());
   420 		//Send pixel data first to Data Memory then copy into the selected BMP box	
   421 		//BmpDataInput(ETargetDataMemory,0x0000,EDirectionY, FrameBufferSizeInBytes(),iFrameNext->Ptr());
   422 		//BmpBoxDataMemoryTransfer(0x0000);
   423 		//Send pixel data first to Data Memory then copy into the selected BMP box, cycling through our Data Memory frmae
   424 		BmpDataInput(ETargetDataMemory,iNextFrameAddress,EDirectionY, FrameBufferSizeInBytes(),iFrameNext->Ptr());
   425 		BmpBoxDataMemoryTransfer(iNextFrameAddress);
   426 		iNextFrameAddress+=KFrameSizeInBytes;
   427 		if (iNextFrameAddress>KMaxDataMemoryAddress)
   428 		{
   429 			iNextFrameAddress=0x0000;
   430 		}
   431 
   432         //Cycle through our frame buffers
   433         //We keep track of previous frame which is in fact our device back buffer.
   434         //We can then compare previous and next frame and send only the differences to our device.
   435         //This mechanism allows us to reduce traffic over our USB bus thus improving our frame rate from 14 FPS to 30 FPS.
   436         //Keep our previous frame pointer
   437         BitArrayLow* previousFrame=iFramePrevious;
   438         //Current frame becomes the previous one
   439         iFramePrevious = iFrameCurrent;
   440         //Next frame becomes the current one
   441         iFrameCurrent = iFrameNext;
   442         //Next frame is now our former previous
   443         iFrameNext = previousFrame;
   444 		}
   445 	}
   446 
   447 
   448 //Define the edge of our pixel block
   449 //Pixel blocks of 32x32 seems to run almost as fast as full screen update in worse case scenarii.
   450 //Though I wonder if in some situations 16 could be better. Make this an attribute at some point if need be.
   451 const int KPixelBlockEdge = 32;
   452 const int KPixelBlockSizeInBits = KPixelBlockEdge*KPixelBlockEdge;
   453 const int KPixelBlockSizeInBytes = KPixelBlockSizeInBits/8;
   454 
   455 
   456 /**
   457 Translate the given pixel coordinate according to our off screen mode.
   458 */
   459 void GP1212A02A::OffScreenTranslation(unsigned char& aX, unsigned char& aY)
   460 	{
   461 	if (OffScreenMode())
   462 		{
   463 		aX+=WidthInPixels()-iDisplayPositionX;
   464 		aY+=HeightInPixels()-iDisplayPositionY;
   465 		}
   466 	}
   467 
   468 
   469 /**
   470 */
   471 void GP1212A02A::Request(TMiniDisplayRequest aRequest)
   472 	{
   473 	switch (aRequest)
   474 		{
   475 	case EMiniDisplayRequestDeviceId:
   476 		RequestDeviceId();
   477 		break;
   478 	case EMiniDisplayRequestFirmwareRevision:
   479 		RequestFirmwareRevision();
   480 		break;
   481 	case EMiniDisplayRequestPowerSupplyStatus:
   482 		RequestPowerSupplyStatus();
   483 		break;
   484 	default:
   485 		//Not supported
   486 		break;
   487 		};
   488 	}
   489 
   490 
   491 /**
   492 */
   493 void GP1212A02A::ResetBuffers()
   494 	{
   495     //iNextFrame->ClearAll();
   496     //memset(iFrameAlpha,0x00,sizeof(iFrameAlpha));
   497 	//memset(iFrameBeta,0x00,sizeof(iFrameBeta));
   498 	}
   499 
   500 /**
   501 */
   502 void GP1212A02A::RequestDeviceId()
   503     {
   504 	//Not supported
   505     }
   506 
   507 /**
   508 ID code 
   509 [Code] 1BH,6AH,49H,44H
   510 [Function] Send the ID code to the Host system. ID code is software version.
   511 */
   512 void GP1212A02A::RequestFirmwareRevision()
   513     {
   514     if (RequestPending())
   515         {
   516         //Abort silently for now
   517         return;
   518         }
   519 
   520     //1BH,6AH,49H,44H
   521     //Send Software Revision Read Command
   522     FutabaVfdReport report;
   523     report[0]=0x00; //Report ID
   524     report[1]=0x04; //Report length
   525     report[2]=0x1B; //Command ID
   526     report[3]=0x6A; //Command ID
   527     report[4]=0x49; //Command ID
   528     report[5]=0x44; //Command ID
   529     if (Write(report)==report.Size())
   530         {
   531         SetRequest(EMiniDisplayRequestFirmwareRevision);
   532         }
   533 
   534     }
   535 
   536 /**
   537 */
   538 void GP1212A02A::RequestPowerSupplyStatus()
   539     {
   540 	//Not supported
   541     }
   542 
   543 
   544 /**
   545 This is for development purposes only.
   546 Production application should stick to off-screen mode to avoid tearing.
   547 */
   548 void GP1212A02A::ToggleOffScreenMode()
   549 	{
   550     SetOffScreenMode(!iOffScreenMode);
   551 	}
   552 
   553 /**
   554  * @brief GP1212A02A::SetOffScreenMode
   555  * @param aOn
   556  * @return
   557  */
   558 void GP1212A02A::SetOffScreenMode(bool aOn)
   559     {
   560     if (aOn==iOffScreenMode)
   561     {
   562         //Nothing to do here
   563         return;
   564     }
   565 
   566     iOffScreenMode=aOn;
   567 
   568     //Clean up our buffers upon switching modes
   569     Clear();
   570     SwapBuffers();
   571     Clear();
   572     }
   573 
   574 /**
   575 Tries to complete our current request if we have one pending.
   576  */
   577 TMiniDisplayRequest GP1212A02A::AttemptRequestCompletion()
   578     {
   579     if (!RequestPending())
   580         {
   581         return EMiniDisplayRequestNone;
   582         }
   583 
   584     int res=Read(iInputReport);
   585 
   586     if (!res)
   587         {
   588         return EMiniDisplayRequestNone;
   589         }
   590 
   591     //Process our request
   592 	if (CurrentRequest()==EMiniDisplayRequestFirmwareRevision)
   593 		{
   594 			unsigned char* ptr=&iInputReport[2];
   595 			iInputReport[7]=0x00;
   596 			strcpy(iFirmwareRevision,(const char*)ptr);
   597 		}
   598 
   599     TMiniDisplayRequest completed=CurrentRequest();
   600     //Our request was completed
   601     SetRequest(EMiniDisplayRequestNone);
   602 
   603     return completed;
   604 	}
   605 
   606 
   607 /**
   608 Set our screen brightness.
   609 @param The desired brightness level. Must be between MinBrightness and MaxBrightness.
   610 */
   611 void GP1212A02A::SetBrightness(int aBrightness)
   612     {
   613     if (aBrightness<MinBrightness()||aBrightness>MaxBrightness())
   614         {
   615         //Brightness out of range.
   616         //Just ignore that request.
   617         return;
   618         }
   619 
   620     FutabaVfdReport report;
   621     report[0]=0x00; //Report ID
   622     report[1]=0x04; //Report size
   623     report[2]=0x1B; //Command ID
   624     report[3]=0x4A; //Command ID
   625     report[4]=0x44; //Command ID
   626     report[5]=0x30+aBrightness; //Brightness level
   627     Write(report);
   628     }
   629 
   630 /**
   631 */
   632 bool GP1212A02A::IsPowerOn()
   633 	{
   634 	return iPowerOn;
   635 	}
   636 
   637 /**
   638 */
   639 char* GP1212A02A::DeviceId()
   640 	{
   641 	return iDeviceId;
   642 	}
   643 
   644 /**
   645 */
   646 char* GP1212A02A::FirmwareRevision()
   647 	{
   648 	return iFirmwareRevision;
   649 	}
   650 
   651 /**
   652 VFD Power ON/OFF 
   653 [Code]1BH,4AH,42H,Ps
   654 [Function]Control of the power supply for VFD 
   655 * If VFD power ON or OFF, at interval of 10s or more. 
   656 * When the VFD power off, VFD display is turn off, but the module can receive a data and 
   657 process.
   658 Ps = VFD Power control 
   659 [Definable area]
   660 Ps = 30H : VFD Power OFF 
   661 Ps = 31H : VFD Power ON  (Default)
   662 */
   663 void GP1212A02A::SendCommandPower(TPowerStatus aPowerStatus)
   664 	{
   665 	FutabaVfdReport report;
   666     report[0]=0x00; //Report ID
   667     report[1]=0x04; //Report size
   668     report[2]=0x1B; //Command ID
   669     report[3]=0x4A; //Command ID
   670     report[4]=0x42; //Command ID
   671     report[5]=aPowerStatus; //ON or OFF
   672     Write(report);
   673 	}
   674 
   675 /**
   676 */
   677 void GP1212A02A::TurnPowerOn()
   678 	{
   679 	SendCommandPower(EPowerOn);
   680 	}
   681 
   682 /**
   683 */
   684 void GP1212A02A::TurnPowerOff()
   685 	{
   686 	SendCommandPower(EPowerOff);
   687 	}