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