FutabaGP1212A02.cpp
author sl
Fri, 29 Aug 2014 22:32:13 +0200
changeset 13 70907579a3b6
parent 11 2d749a2bea34
child 14 86faea78ddf0
permissions -rw-r--r--
First working version of GP1212A02A.
     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 	return success;
    85 	}
    86 
    87 /**
    88 */
    89 void GP1212A02A::SetPixel(unsigned char aX, unsigned char aY, bool aOn)
    90 	{
    91 	//
    92 	//int byteOffset=(aX*HeightInPixels()+aY)/8;
    93 	//int bitOffset=(aX*HeightInPixels()+aY)%8;
    94     //iNextFrame[byteOffset] |= ( (aOn?0x01:0x00) << bitOffset );
    95 
    96     if (iOffScreenMode)
    97         {
    98         if (aOn)
    99             {
   100             iFrameNext->SetBit(aX*HeightInPixels()+aY);
   101             }
   102         else
   103             {
   104             iFrameNext->ClearBit(aX*HeightInPixels()+aY);
   105             }
   106         }
   107     else
   108         {
   109         //Just specify a one pixel block
   110         //TODO
   111         }
   112 	}
   113 
   114 /**
   115 */
   116 /*
   117 void GP1212A02A::BitBlit(const BitArray& aBitmap, int aSrcWidth, int aSrcHeight, int aTargetX, int aTargetY) const
   118 	{
   119 	//TODO: amend loop values so that we don't keep on looping past our frame buffer dimensions.
   120 	for (int i=0;i<aSrcWidth;i++)
   121 		{
   122 		for (int j=0;j<aSrcHeight;j++)
   123 			{
   124             iFrameNext->SetBitValue((aTargetX+i)*HeightInPixels()+aTargetY+j,aBitmap[+i*aSrcHeight+j]);
   125 			}
   126 		}
   127 	}
   128 */
   129 
   130 /**
   131 Clear our client side back buffer.
   132 Call to SwapBuffers must follow to actually clear the display.
   133 */
   134 void GP1212A02A::Clear()
   135     {
   136     //memset(iNextFrame->Ptr(),0x00,FrameBufferSizeInBytes());
   137     if (iOffScreenMode)
   138         {
   139         iFrameNext->ClearAll();
   140         }
   141     else
   142         {
   143         SendClearCommand();
   144         }
   145     }
   146 
   147 /**
   148 Turn on all pixels.
   149 Must be followed by a SwapBuffers call.
   150 */
   151 void GP1212A02A::Fill()
   152 	{
   153 	SetAllPixels(0xFF);
   154 	}
   155 
   156 /**
   157 Set all pixels on our screen to the desired value.
   158 This operation is performed off screen to avoid tearing.
   159 @param 8 pixels pattern
   160 */
   161 void GP1212A02A::SetAllPixels(unsigned char aPattern)
   162 	{
   163 	//With a single buffer
   164 	//unsigned char screen[2048]; //One screen worth of pixels
   165 	//memset(screen,0xFF,sizeof(screen));
   166 	//SetPixelBlock(0,0,63,sizeof(screen),screen);
   167 
   168 
   169     if (iOffScreenMode)
   170         {
   171         memset(iFrameNext->Ptr(),aPattern,FrameBufferSizeInBytes());
   172         }
   173     else
   174         {
   175         //Using pattern SetPixelBlock variant.
   176         //TODO
   177         }
   178 	//
   179 	}
   180 
   181 
   182 
   183 
   184 /**
   185 Using this function is advised against as is causes tearing.
   186 Use Clear instead.
   187 */
   188 void GP1212A02A::SetFrame(int aSize, unsigned char* aPixels)
   189 {
   190 	FutabaVfdReport report;
   191     report[0]=0x00; //Report ID
   192     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
   193     report[2]=0x1B; //Command ID
   194     report[3]=0x4A; //Command ID
   195     report[4]=0x30; //DW Display Window
   196     report[5]=0x00; //aL = DW lower byte
   197     report[6]=0x00; //aH = DW upper byte
   198     report[7]=0x30; //Direction of writing: Y
   199 	report[8]=aSize; //Size of pixel data in bytes (LSB)
   200 	report[9]=aSize>>8;	//Size of pixel data in bytes (MSB)
   201     int sizeWritten=MIN(aSize,report.Size()-10);
   202     memcpy(report.Buffer()+10, aPixels, sizeWritten);
   203     Write(report);
   204 
   205     int remainingSize=aSize;
   206     //We need to keep on sending our pixel data until we are done
   207     while (report[1]==64)
   208         {
   209         report.Reset();
   210         remainingSize-=sizeWritten;
   211         report[0]=0x00; //Report ID
   212         report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
   213         sizeWritten=(report[1]==64?63:report[1]);
   214         memcpy(report.Buffer()+2, aPixels+(aSize-remainingSize), sizeWritten);
   215         Write(report);
   216         }
   217 }
   218 
   219 /**
   220 Using this function is advised against as is causes tearing.
   221 Use Clear instead.
   222 */
   223 void GP1212A02A::SendClearCommand()
   224 	{
   225     //1BH,4AH,43H,44H
   226     //Send Clear Display Command
   227 	FutabaVfdReport report;
   228 	report[0]=0x00; //Report ID
   229 	report[1]=0x04; //Report length
   230 	report[2]=0x1B; //Command ID
   231 	report[3]=0x4A; //Command ID
   232 	report[4]=0x43; //Command ID
   233 	report[5]=0x44; //Command ID
   234 	Write(report);
   235 	}
   236 
   237 
   238 /**
   239 Provide Y coordinate of our off screen buffer.
   240 */
   241 unsigned char GP1212A02A::OffScreenY() const
   242 	{
   243 	//Overflowing is fine this is just what we want
   244 	return iDisplayPositionY+HeightInPixels();
   245 	}
   246 
   247 /**
   248 Put our off screen buffer on screen.
   249 On screen buffer goes off screen.
   250 */
   251 void GP1212A02A::SwapBuffers()
   252 	{
   253 	//Only perform buffer swapping if off screen mode is enabled
   254 	if (OffScreenMode())
   255 		{
   256 		//Send host back buffer to device back buffer
   257 		SetFrame(FrameBufferSizeInBytes(),iFrameNext->Ptr());
   258 
   259         //Cycle through our frame buffers
   260         //We keep track of previous frame which is in fact our device back buffer.
   261         //We can then compare previous and next frame and send only the differences to our device.
   262         //This mechanism allows us to reduce traffic over our USB bus thus improving our frame rate from 14 FPS to 30 FPS.
   263         //Keep our previous frame pointer
   264         BitArrayLow* previousFrame=iFramePrevious;
   265         //Current frame becomes the previous one
   266         iFramePrevious = iFrameCurrent;
   267         //Next frame becomes the current one
   268         iFrameCurrent = iFrameNext;
   269         //Next frame is now our former previous
   270         iFrameNext = previousFrame;
   271 		}
   272 	}
   273 
   274 
   275 //Define the edge of our pixel block
   276 //Pixel blocks of 32x32 seems to run almost as fast as full screen update in worse case scenarii.
   277 //Though I wonder if in some situations 16 could be better. Make this an attribute at some point if need be.
   278 const int KPixelBlockEdge = 32;
   279 const int KPixelBlockSizeInBits = KPixelBlockEdge*KPixelBlockEdge;
   280 const int KPixelBlockSizeInBytes = KPixelBlockSizeInBits/8;
   281 
   282 
   283 /**
   284 Translate the given pixel coordinate according to our off screen mode.
   285 */
   286 void GP1212A02A::OffScreenTranslation(unsigned char& aX, unsigned char& aY)
   287 	{
   288 	if (OffScreenMode())
   289 		{
   290 		aX+=WidthInPixels()-iDisplayPositionX;
   291 		aY+=HeightInPixels()-iDisplayPositionY;
   292 		}
   293 	}
   294 
   295 
   296 /**
   297 */
   298 void GP1212A02A::ResetBuffers()
   299 	{
   300     //iNextFrame->ClearAll();
   301     //memset(iFrameAlpha,0x00,sizeof(iFrameAlpha));
   302 	//memset(iFrameBeta,0x00,sizeof(iFrameBeta));
   303 	}
   304 
   305 /**
   306 */
   307 void GP1212A02A::RequestDeviceId()
   308     {
   309 	//Not supported
   310     }
   311 
   312 /**
   313 */
   314 void GP1212A02A::RequestFirmwareRevision()
   315     {
   316 	//Not supported
   317     }
   318 
   319 /**
   320 */
   321 void GP1212A02A::RequestPowerSupplyStatus()
   322     {
   323 	//Not supported
   324     }
   325 
   326 
   327 /**
   328 This is for development purposes only.
   329 Production application should stick to off-screen mode to avoid tearing.
   330 */
   331 void GP1212A02A::ToggleOffScreenMode()
   332 	{
   333     SetOffScreenMode(!iOffScreenMode);
   334 	}
   335 
   336 /**
   337  * @brief GP1212A02A::SetOffScreenMode
   338  * @param aOn
   339  * @return
   340  */
   341 void GP1212A02A::SetOffScreenMode(bool aOn)
   342     {
   343     if (aOn==iOffScreenMode)
   344     {
   345         //Nothing to do here
   346         return;
   347     }
   348 
   349     iOffScreenMode=aOn;
   350 
   351     //Clean up our buffers upon switching modes
   352     Clear();
   353     SwapBuffers();
   354     Clear();
   355     }
   356 
   357 /**
   358 Tries to complete our current request if we have one pending.
   359  */
   360 TMiniDisplayRequest GP1212A02A::AttemptRequestCompletion()
   361     {
   362 	//That display does not support any requests
   363 	return EMiniDisplayRequestNone;
   364 	}
   365 
   366 
   367 /**
   368 Set our screen brightness.
   369 @param The desired brightness level. Must be between MinBrightness and MaxBrightness.
   370 */
   371 void GP1212A02A::SetBrightness(int aBrightness)
   372     {
   373     if (aBrightness<MinBrightness()||aBrightness>MaxBrightness())
   374         {
   375         //Brightness out of range.
   376         //Just ignore that request.
   377         return;
   378         }
   379 
   380     FutabaVfdReport report;
   381     report[0]=0x00; //Report ID
   382     report[1]=0x04; //Report size
   383     report[2]=0x1B; //Command ID
   384     report[3]=0x4A; //Command ID
   385     report[4]=0x44; //Command ID
   386     report[5]=0x30+aBrightness; //Brightness level
   387     Write(report);
   388     }
   389 
   390 /**
   391 */
   392 bool GP1212A02A::PowerOn()
   393 	{
   394 	return iPowerOn;
   395 	}
   396 
   397 /**
   398 */
   399 char* GP1212A02A::DeviceId()
   400 	{
   401 	return iDeviceId;
   402 	}
   403 
   404 /**
   405 */
   406 char* GP1212A02A::FirmwareRevision()
   407 	{
   408 	return iFirmwareRevision;
   409 	}