MiniDisplay/FutabaVfd.cpp
author sl
Thu, 29 May 2014 19:46:57 +0200
changeset 18 79801cc3bc94
parent 11 b935de604982
child 19 be04ffbb561c
permissions -rw-r--r--
Restoring some of our on-screen functionality for debug purposes.
We could prove that updating a single pixel is much faster than updating our
whole screen. Single pixel updates runs at full 24 FPS.
     1 
     2 #include "FutabaVfd.h"
     3 //#include <stdlib.h>
     4 #include <string.h>
     5 
     6 
     7 //
     8 //
     9 //
    10 
    11 
    12 
    13 
    14 
    15 //
    16 //
    17 //
    18 
    19 FutabaVfdCommand::FutabaVfdCommand():/*iBuffer(NULL),*/iSize(0),iMaxSize(0)
    20     {
    21     }
    22 
    23 FutabaVfdCommand::~FutabaVfdCommand()
    24     {
    25     //Delete();
    26     }
    27 
    28 
    29 /**
    30 
    31 */
    32 void FutabaVfdCommand::Reset()
    33     {
    34     memset(iReports,0,sizeof(iReports));
    35     }
    36 
    37 
    38 
    39 /**
    40 
    41 */
    42 /*
    43 void FutabaVfdCommand::Create(int aMaxSize)
    44     {
    45     iBuffer=new unsigned char[aMaxSize];
    46     if (iBuffer)
    47         {
    48         iMaxSize = aMaxSize;
    49         iSize = 0;
    50         }
    51     }
    52 */
    53 
    54 /**
    55 
    56 */
    57 /*
    58 void FutabaVfdCommand::Delete()
    59 {
    60     delete[] iBuffer;
    61     iBuffer = NULL;
    62     iMaxSize = 0;
    63     iSize = 0;
    64 }
    65 */
    66 
    67 
    68 
    69 
    70 //
    71 // class GP1212A01A
    72 //
    73 
    74 GP1212A01A::GP1212A01A():
    75 	iDisplayPositionX(0),iDisplayPositionY(0),
    76     iOffScreenMode(true),iFrameBuffer(NULL),iRequest(ERequestNone),iPowerOn(false)
    77 	{
    78 	//ResetBuffers();
    79 	}
    80 
    81 /**
    82 */
    83 GP1212A01A::~GP1212A01A()
    84 	{
    85 	delete iFrameBuffer;
    86 	iFrameBuffer=NULL;
    87 	}
    88 
    89 /**
    90 */
    91 int GP1212A01A::Open()
    92 	{
    93 	int success = HidDevice::Open(KFutabaVendorId,KFutabaProductIdGP1212A01A,NULL);
    94 	if (success)
    95 		{
    96 		delete iFrameBuffer;
    97 		iFrameBuffer = NULL;
    98 		iFrameBuffer=new BitArray(KGP12xFrameBufferPixelCount);
    99 		SetNonBlocking(1);
   100         //Since we can't get our display position we force it to our default
   101 		//This makes sure frames are in sync from the start
   102         //Clever clients will have taken care of putting back frame (0,0) before closing
   103 		SetDisplayPosition(iDisplayPositionX,iDisplayPositionY);
   104 		}
   105 	return success;
   106 	}
   107 
   108 /**
   109 */
   110 void GP1212A01A::SetPixel(unsigned char aX, unsigned char aY, bool aOn)
   111 	{
   112 	//
   113 	//int byteOffset=(aX*HeightInPixels()+aY)/8;
   114 	//int bitOffset=(aX*HeightInPixels()+aY)%8;
   115 	//iFrameBuffer[byteOffset] |= ( (aOn?0x01:0x00) << bitOffset );
   116 
   117     if (iOffScreenMode)
   118         {
   119         if (aOn)
   120             {
   121             iFrameBuffer->SetBit(aX*HeightInPixels()+aY);
   122             }
   123         else
   124             {
   125             iFrameBuffer->ClearBit(aX*HeightInPixels()+aY);
   126             }
   127         }
   128     else
   129         {
   130         //Just specify a one pixel block
   131         SetPixelBlock(aX,aY,0x00,0x01,aOn);
   132         }
   133 	}
   134 
   135 /**
   136 */
   137 void GP1212A01A::BitBlit(const BitArray& aBitmap, int aSrcWidth, int aSrcHeight, int aTargetX, int aTargetY) const
   138 	{
   139 	//TODO: amend loop values so that we don't keep on looping past our frame buffer dimensions.
   140 	for (int i=0;i<aSrcWidth;i++)
   141 		{
   142 		for (int j=0;j<aSrcHeight;j++)
   143 			{
   144 			iFrameBuffer->SetBitValue((aTargetX+i)*HeightInPixels()+aTargetY+j,aBitmap[+i*aSrcHeight+j]);
   145 			}
   146 		}
   147 	}
   148 
   149 /**
   150 Set all pixels on our screen to the desired value.
   151 This operation is performed off screen to avoid tearing.
   152 @param 8 pixels pattern
   153 */
   154 void GP1212A01A::SetAllPixels(unsigned char aPattern)
   155 	{
   156 	//With a single buffer
   157 	//unsigned char screen[2048]; //One screen worth of pixels
   158 	//memset(screen,0xFF,sizeof(screen));
   159 	//SetPixelBlock(0,0,63,sizeof(screen),screen);
   160 
   161 
   162     if (iOffScreenMode)
   163         {
   164         memset(iFrameBuffer->Ptr(),aPattern,FrameBufferSizeInBytes());
   165         }
   166     else
   167         {
   168         //Using pattern SetPixelBlock variant.
   169         SetPixelBlock(0,0,63,FrameBufferSizeInBytes(),aPattern);
   170         }
   171 	//
   172 	}
   173 
   174 
   175 /**
   176 Set the defined pixel block to the given value.
   177 @param X coordinate of our pixel block starting point.
   178 @param Y coordinate of our pixel block starting point.
   179 @param The height of our pixel block.
   180 @param The size of our pixel data. Number of pixels divided by 8.
   181 @param The value set to 8 pixels used as a pattern.
   182 */
   183 void GP1212A01A::SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char aValue)
   184 	{
   185 	OffScreenTranslation(aX,aY);
   186     FutabaVfdReport report;
   187     report[0]=0x00; //Report ID
   188     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
   189     report[2]=0x1B; //Command ID
   190     report[3]=0x5B; //Command ID
   191     report[4]=0xF0; //Command ID
   192     report[5]=aX;   //X
   193     report[6]=aY;   //Y
   194     report[7]=aHeight; //Y length before return. Though outside the specs, setting this to zero apparently allows us to modify a single pixel without touching any other.
   195 	report[8]=aSize>>8; //Size of pixel data in bytes (MSB)
   196 	report[9]=aSize;	//Size of pixel data in bytes (LSB)
   197     int sizeWritten=MIN(aSize,report.Size()-10);
   198     memset(report.Buffer()+10, aValue, sizeWritten);
   199     Write(report);
   200 
   201     int remainingSize=aSize;
   202     //We need to keep on sending our pixel data until we are done
   203     while (report[1]==64)
   204         {
   205         report.Reset();
   206         remainingSize-=sizeWritten;
   207         report[0]=0x00; //Report ID
   208         report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
   209         sizeWritten=(report[1]==64?63:report[1]);
   210         memset(report.Buffer()+2, aValue, sizeWritten);
   211         Write(report);
   212         }
   213 	}
   214 
   215 /**
   216 Set the defined pixel block to the given value.
   217 @param X coordinate of our pixel block starting point.
   218 @param Y coordinate of our pixel block starting point.
   219 @param The height of our pixel block.
   220 @param The size of our pixel data. Number of pixels divided by 8.
   221 @param Pointer to our pixel data.
   222 */
   223 void GP1212A01A::SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char* aPixels)
   224     {
   225 	OffScreenTranslation(aX,aY);
   226     FutabaVfdReport report;
   227     report[0]=0x00; //Report ID
   228     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
   229     report[2]=0x1B; //Command ID
   230     report[3]=0x5B; //Command ID
   231     report[4]=0xF0; //Command ID
   232     report[5]=aX;   //X
   233     report[6]=aY;   //Y
   234     report[7]=aHeight; //Y length before return. Though outside the specs, setting this to zero apparently allows us to modify a single pixel without touching any other.
   235 	report[8]=aSize>>8; //Size of pixel data in bytes (MSB)
   236 	report[9]=aSize;	//Size of pixel data in bytes (LSB)
   237     int sizeWritten=MIN(aSize,report.Size()-10);
   238     memcpy(report.Buffer()+10, aPixels, sizeWritten);
   239     Write(report);
   240 
   241     int remainingSize=aSize;
   242     //We need to keep on sending our pixel data until we are done
   243     while (report[1]==64)
   244         {
   245         report.Reset();
   246         remainingSize-=sizeWritten;
   247         report[0]=0x00; //Report ID
   248         report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
   249         sizeWritten=(report[1]==64?63:report[1]);
   250         memcpy(report.Buffer()+2, aPixels+(aSize-remainingSize), sizeWritten);
   251         Write(report);
   252         }
   253     }
   254 
   255 
   256 /**
   257 Clear our client side back buffer.
   258 Call to SwapBuffers must follow to actually clear the display.
   259 */
   260 void GP1212A01A::Clear()
   261 	{
   262 	//memset(iFrameBuffer->Ptr(),0x00,FrameBufferSizeInBytes());
   263     if (iOffScreenMode)
   264         {
   265         iFrameBuffer->ClearAll();
   266         }
   267     else
   268         {
   269         SendClearCommand();
   270         }
   271 	}
   272 
   273 /**
   274 Using this function is advised against as is causes tearing.
   275 Use Clear instead.
   276 */
   277 void GP1212A01A::SendClearCommand()
   278 	{
   279     //1BH,5BH,32H,4AH
   280     //Send Clear Display Command
   281 	FutabaVfdReport report;
   282 	report[0]=0x00; //Report ID
   283 	report[1]=0x04; //Report length
   284 	report[2]=0x1B; //Command ID
   285 	report[3]=0x5B; //Command ID
   286 	report[4]=0x32; //Command ID
   287 	report[5]=0x4A; //Command ID
   288 	Write(report);
   289 	}
   290 
   291 /**
   292 Change our display position within our buffer.
   293 */
   294 void GP1212A01A::SetDisplayPosition(DW aDw,unsigned char aX, unsigned char aY)
   295     {
   296     //1BH,5BH,Dw,Px,Py
   297     //Send Display Position Settings Command
   298     FutabaVfdReport report;
   299     report[0]=0x00; //Report ID
   300     report[1]=0x05; //Report length
   301     report[2]=0x1B; //Command ID
   302     report[3]=0x5B; //Command ID
   303     report[4]=aDw;  //Specify our DW
   304     report[5]=aX;   //X coordinate of our DW top-left corner
   305     report[6]=aY;   //Y coordinate of our DW top-left corner
   306     Write(report);
   307     }
   308 
   309 /**
   310 Change our display position within our buffer.
   311 */
   312 void GP1212A01A::SetDisplayPosition(unsigned char aX, unsigned char aY)
   313 	{
   314 	//Specs apparently says both DW should remain the same
   315 	//Just don't ask
   316     SetDisplayPosition(GP1212A01A::DW1,aX,aY);
   317     SetDisplayPosition(GP1212A01A::DW2,aX,aY);
   318 	iDisplayPositionX=aX;
   319 	iDisplayPositionY=aY;
   320 	}
   321 
   322 /**
   323 Provide Y coordinate of our off screen buffer.
   324 */
   325 unsigned char GP1212A01A::OffScreenY() const
   326 	{
   327 	//Overflowing is fine this is just what we want
   328 	return iDisplayPositionY+HeightInPixels();
   329 	}
   330 
   331 /**
   332 Put our off screen buffer on screen.
   333 On screen buffer goes off screen.
   334 */
   335 void GP1212A01A::SwapBuffers()
   336 	{
   337 	//Only perform buffer swapping if off screen mode is enabled
   338 	if (OffScreenMode())
   339 		{
   340 		//Send host back buffer to device back buffer
   341 		SetPixelBlock(0,0,63,FrameBufferSizeInBytes(),iFrameBuffer->Ptr());
   342 		//Swap device front and back buffer
   343 		SetDisplayPosition(iDisplayPositionX,OffScreenY());
   344 		//Swap host buffers
   345 		//unsigned char* backBuffer=iBackBuffer;
   346 		//iBackBuffer = iFrontBuffer;
   347 		//iFrontBuffer = backBuffer;
   348 		}
   349 	}
   350 
   351 /**
   352 Translate the given pixel coordinate according to our off screen mode.
   353 */
   354 void GP1212A01A::OffScreenTranslation(unsigned char& aX, unsigned char& aY)
   355 	{
   356 	if (OffScreenMode())
   357 		{
   358 		aX+=WidthInPixels()-iDisplayPositionX;
   359 		aY+=HeightInPixels()-iDisplayPositionY;
   360 		}
   361 	}
   362 
   363 
   364 /**
   365 */
   366 void GP1212A01A::ResetBuffers()
   367 	{
   368 	//iFrameBuffer->ClearAll();
   369 	//memset(iFrameBuffer,0x00,sizeof(iFrameBuffer));
   370 	//memset(iFrameBeta,0x00,sizeof(iFrameBeta));
   371 	}
   372 
   373 /**
   374 */
   375 void GP1212A01A::RequestDeviceId()
   376     {
   377     if (RequestPending())
   378         {
   379         //Abort silently for now
   380         return;
   381         }
   382 
   383     //1BH,5BH,63H,49H,44H
   384     //Send Read ID command
   385     FutabaVfdReport report;
   386     report[0]=0x00; //Report ID
   387     report[1]=0x05; //Report length
   388     report[2]=0x1B; //Command ID
   389     report[3]=0x5B; //Command ID
   390     report[4]=0x63; //Command ID
   391     report[5]=0x49; //Command ID
   392     report[6]=0x44; //Command ID
   393     if (Write(report)==report.Size())
   394         {
   395         iRequest=ERequestDeviceId;
   396         }
   397     }
   398 
   399 /**
   400 */
   401 void GP1212A01A::RequestFirmwareRevision()
   402     {
   403     if (RequestPending())
   404         {
   405         //Abort silently for now
   406         return;
   407         }
   408 
   409     //1BH,5BH,63H,46H,52H
   410     //Send Software Revision Read Command
   411     FutabaVfdReport report;
   412     report[0]=0x00; //Report ID
   413     report[1]=0x05; //Report length
   414     report[2]=0x1B; //Command ID
   415     report[3]=0x5B; //Command ID
   416     report[4]=0x63; //Command ID
   417     report[5]=0x46; //Command ID
   418     report[6]=0x52; //Command ID
   419     if (Write(report)==report.Size())
   420         {
   421         iRequest=ERequestFirmwareRevision;
   422         }
   423     }
   424 
   425 /**
   426 */
   427 void GP1212A01A::RequestPowerSupplyStatus()
   428     {
   429     if (RequestPending())
   430         {
   431         //Abort silently for now
   432         return;
   433         }
   434     //1BH,5BH,63H,50H,4DH
   435     //Send Power Suppply Monitor Command
   436     FutabaVfdReport report;
   437     report[0]=0x00; //Report ID
   438     report[1]=0x05; //Report length
   439     report[2]=0x1B; //Command ID
   440     report[3]=0x5B; //Command ID
   441     report[4]=0x63; //Command ID
   442     report[5]=0x50; //Command ID
   443     report[6]=0x4D; //Command ID
   444     if (Write(report)==report.Size())
   445         {
   446         iRequest=ERequestPowerSupplyStatus;
   447         }
   448     }
   449 
   450 
   451 /**
   452 This is for development purposes only.
   453 Production application should stick to off-screen mode to avoid tearing.
   454 */
   455 void GP1212A01A::ToggleOffScreenMode()
   456 	{
   457 	iOffScreenMode=!iOffScreenMode;
   458 	//Clean up our buffers upon switching modes	
   459 	SetDisplayPosition(0,0);
   460 	Clear();
   461 	SwapBuffers();
   462 	Clear();
   463 	}
   464 
   465 /**
   466  * @brief GP1212A01A::SetOffScreenMode
   467  * @param aOn
   468  * @return
   469  */
   470 void GP1212A01A::SetOffScreenMode(bool aOn)
   471     {
   472     if (aOn==iOffScreenMode)
   473     {
   474         //Nothing to do here
   475         return;
   476     }
   477 
   478     iOffScreenMode=aOn;
   479 
   480     //Clean up our buffers upon switching modes
   481     SetDisplayPosition(0,0);
   482     Clear();
   483     SwapBuffers();
   484     Clear();
   485     }
   486 
   487 /**
   488  */
   489 GP1212A01A::Request GP1212A01A::AttemptRequestCompletion()
   490     {
   491     if (!RequestPending())
   492         {
   493         return ERequestNone;
   494         }
   495 
   496     int res=Read(iInputReport);
   497 
   498     if (!res)
   499         {
   500         return ERequestNone;
   501         }
   502 
   503     //Process our request
   504     if (CurrentRequest()==GP1212A01A::ERequestPowerSupplyStatus)
   505         {
   506         if (iInputReport[1]==0x4F && iInputReport[2]==0x4E)
   507             {
   508             iPowerOn = true;
   509             }
   510         else if (iInputReport[1]==0x4F && iInputReport[2]==0x46 && iInputReport[3]==0x46)
   511             {
   512             iPowerOn = false;
   513             }
   514         }
   515 
   516     Request completed=iRequest;
   517     //Our request was completed
   518     iRequest=ERequestNone;
   519 
   520     return completed;
   521     }
   522 
   523 
   524 /**
   525 Set our screen brightness.
   526 @param The desired brightness level. Must be between MinBrightness and MaxBrightness.
   527 */
   528 void GP1212A01A::SetBrightness(int aBrightness)
   529     {
   530     if (aBrightness<MinBrightness()||aBrightness>MaxBrightness())
   531         {
   532         //Brightness out of range.
   533         //Just ignore that request.
   534         return;
   535         }
   536 
   537     FutabaVfdReport report;
   538     report[0]=0x00; //Report ID
   539     report[1]=0x06; //Report size
   540     report[2]=0x1B; //Command ID
   541     report[3]=0x5C; //Command ID
   542     report[4]=0x3F; //Command ID
   543     report[5]=0x4C; //Command ID
   544     report[6]=0x44; //Command ID
   545     report[7]=0x30+aBrightness; //Brightness level
   546     Write(report);
   547     }
   548 
   549