5 #include "FutabaGP1212A02.h"
 
     8 const int KNumberOfFrameBeforeDiffAlgo = 3;
 
    14 GP1212A02A::GP1212A02A():
 
    15 	iDisplayPositionX(0),iDisplayPositionY(0),
 
    17     iUseFrameDifferencing(true),
 
    24     iNeedFullFrameUpdate(0),
 
    28 	iFirmwareRevision[0]=0;
 
    34 GP1212A02A::~GP1212A02A()
 
    49     iNeedFullFrameUpdate=0;
 
    54 int GP1212A02A::Open()
 
    56 	int success = HidDevice::Open(KFutabaVendorId,KFutabaProductIdGP1212A02A,NULL);
 
    59         //Allocate both frames
 
    62         iFrameAlpha=new BitArrayLow(KGP12xFrameBufferPixelCount);
 
    66         iFrameBeta=new BitArrayLow(KGP12xFrameBufferPixelCount);
 
    70         iFrameGamma=new BitArrayLow(KGP12xFrameBufferPixelCount);
 
    72         iFrameNext=iFrameAlpha;
 
    73         iFrameCurrent=iFrameBeta;
 
    74         iFramePrevious=iFrameGamma;
 
    77         //To make sure it is synced properly
 
    78         iNeedFullFrameUpdate=0;
 
    85 		BmpBoxSetting(EBmpBoxIdOne,0x0000,256,64);
 
    87 		//Select current BMP box
 
    88 		BmpBoxSelect(EBmpBoxIdOne);
 
    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 
 
   112 0000H <= aL + aH * 100 <= 07FFH 
 
   113 01H <= Pw <= 00H (=100H) 
 
   116 void GP1212A02A::BmpBoxSetting(TBmpBoxId aBoxId, unsigned short aAddress, int aWidth, int aHeight)
 
   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
 
   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.
 
   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. 
 
   140 Pn = 30H - Remove the BMP box 
 
   145 void GP1212A02A::BmpBoxSelect(TBmpBoxId aBoxId)
 
   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
 
   161 void GP1212A02A::SetPixel(unsigned char aX, unsigned char aY, bool aOn)
 
   164 	//int byteOffset=(aX*HeightInPixels()+aY)/8;
 
   165 	//int bitOffset=(aX*HeightInPixels()+aY)%8;
 
   166     //iNextFrame[byteOffset] |= ( (aOn?0x01:0x00) << bitOffset );
 
   172             iFrameNext->SetBit(aX*HeightInPixels()+aY);
 
   176             iFrameNext->ClearBit(aX*HeightInPixels()+aY);
 
   181         //Just specify a one pixel block
 
   189 void GP1212A02A::BitBlit(const BitArray& aBitmap, int aSrcWidth, int aSrcHeight, int aTargetX, int aTargetY) const
 
   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++)
 
   194 		for (int j=0;j<aSrcHeight;j++)
 
   196             iFrameNext->SetBitValue((aTargetX+i)*HeightInPixels()+aTargetY+j,aBitmap[+i*aSrcHeight+j]);
 
   203 Clear our client side back buffer.
 
   204 Call to SwapBuffers must follow to actually clear the display.
 
   206 void GP1212A02A::Clear()
 
   208     //memset(iNextFrame->Ptr(),0x00,FrameBufferSizeInBytes());
 
   211         iFrameNext->ClearAll();
 
   221 Must be followed by a SwapBuffers call.
 
   223 void GP1212A02A::Fill()
 
   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
 
   233 void GP1212A02A::SetAllPixels(unsigned char aPattern)
 
   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);
 
   243         memset(iFrameNext->Ptr(),aPattern,FrameBufferSizeInBytes());
 
   247         //Using pattern SetPixelBlock variant.
 
   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 
 
   263 Ps = Direction of writing 
 
   264 nL = number of BMP data length lower byte 
 
   265 nH = number of BMP data length upper byte 
 
   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) 
 
   280 void GP1212A02A::BmpDataInput(TTarget aTarget, unsigned short aAddress, TDirection aDirection, unsigned short aSize, unsigned char* aPixels)
 
   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);
 
   297     int remainingSize=aSize;
 
   298     //We need to keep on sending our pixel data until we are done
 
   299     while (report[1]==64)
 
   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);
 
   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 
 
   321 0000H <= aL + aH * 100 <= 4FFFH 
 
   323 void GP1212A02A::BmpBoxDataMemoryTransfer(unsigned short aAddress)
 
   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
 
   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 
 
   345 [Definable area] Pn : BMP box size (Pw * Ph)
 
   347 void GP1212A02A::BmpBoxDataInput(unsigned short aSize, unsigned char* aPixels)
 
   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);
 
   361     int remainingSize=aSize;
 
   362     //We need to keep on sending our pixel data until we are done
 
   363     while (report[1]==64)
 
   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);
 
   376 Using this function is advised against as is causes tearing.
 
   379 void GP1212A02A::SendClearCommand()
 
   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
 
   395 Provide Y coordinate of our off screen buffer.
 
   397 unsigned char GP1212A02A::OffScreenY() const
 
   399 	//Overflowing is fine this is just what we want
 
   400 	return iDisplayPositionY+HeightInPixels();
 
   404 Put our off screen buffer on screen.
 
   405 On screen buffer goes off screen.
 
   407 void GP1212A02A::SwapBuffers()
 
   409 	//Only perform buffer swapping if off screen mode is enabled
 
   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);
 
   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;
 
   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;
 
   445 Translate the given pixel coordinate according to our off screen mode.
 
   447 void GP1212A02A::OffScreenTranslation(unsigned char& aX, unsigned char& aY)
 
   451 		aX+=WidthInPixels()-iDisplayPositionX;
 
   452 		aY+=HeightInPixels()-iDisplayPositionY;
 
   459 void GP1212A02A::ResetBuffers()
 
   461     //iNextFrame->ClearAll();
 
   462     //memset(iFrameAlpha,0x00,sizeof(iFrameAlpha));
 
   463 	//memset(iFrameBeta,0x00,sizeof(iFrameBeta));
 
   468 void GP1212A02A::RequestDeviceId()
 
   475 void GP1212A02A::RequestFirmwareRevision()
 
   482 void GP1212A02A::RequestPowerSupplyStatus()
 
   489 This is for development purposes only.
 
   490 Production application should stick to off-screen mode to avoid tearing.
 
   492 void GP1212A02A::ToggleOffScreenMode()
 
   494     SetOffScreenMode(!iOffScreenMode);
 
   498  * @brief GP1212A02A::SetOffScreenMode
 
   502 void GP1212A02A::SetOffScreenMode(bool aOn)
 
   504     if (aOn==iOffScreenMode)
 
   512     //Clean up our buffers upon switching modes
 
   519 Tries to complete our current request if we have one pending.
 
   521 TMiniDisplayRequest GP1212A02A::AttemptRequestCompletion()
 
   523 	//That display does not support any requests
 
   524 	return EMiniDisplayRequestNone;
 
   529 Set our screen brightness.
 
   530 @param The desired brightness level. Must be between MinBrightness and MaxBrightness.
 
   532 void GP1212A02A::SetBrightness(int aBrightness)
 
   534     if (aBrightness<MinBrightness()||aBrightness>MaxBrightness())
 
   536         //Brightness out of range.
 
   537         //Just ignore that request.
 
   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
 
   553 bool GP1212A02A::PowerOn()
 
   560 char* GP1212A02A::DeviceId()
 
   567 char* GP1212A02A::FirmwareRevision()
 
   569 	return iFirmwareRevision;