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