MiniDisplay/FutabaVfd.cpp
author sl
Wed, 28 May 2014 18:44:15 +0200
changeset 11 b935de604982
parent 9 52372bbbc0f8
child 18 79801cc3bc94
permissions -rw-r--r--
Sorting out start-up/shutdown sequence to avoid flashing old frame upon connection.
Adding a couple of option to clear our frames upong close and/or open.
     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 	//Just specify a one pixel block
   113 	//SetPixelBlock(aX,aY,0x00,0x01,aOn);
   114 	//
   115 	//int byteOffset=(aX*HeightInPixels()+aY)/8;
   116 	//int bitOffset=(aX*HeightInPixels()+aY)%8;
   117 	//iFrameBuffer[byteOffset] |= ( (aOn?0x01:0x00) << bitOffset );
   118 	if (aOn)
   119 		{
   120 		iFrameBuffer->SetBit(aX*HeightInPixels()+aY);
   121 		}
   122 	else
   123 		{
   124 		iFrameBuffer->ClearBit(aX*HeightInPixels()+aY);
   125 		}
   126 	}
   127 
   128 /**
   129 */
   130 void GP1212A01A::BitBlit(const BitArray& aBitmap, int aSrcWidth, int aSrcHeight, int aTargetX, int aTargetY) const
   131 	{
   132 	//TODO: amend loop values so that we don't keep on looping past our frame buffer dimensions.
   133 	for (int i=0;i<aSrcWidth;i++)
   134 		{
   135 		for (int j=0;j<aSrcHeight;j++)
   136 			{
   137 			iFrameBuffer->SetBitValue((aTargetX+i)*HeightInPixels()+aTargetY+j,aBitmap[+i*aSrcHeight+j]);
   138 			}
   139 		}
   140 	}
   141 
   142 /**
   143 Set all pixels on our screen to the desired value.
   144 This operation is performed off screen to avoid tearing.
   145 @param 8 pixels pattern
   146 */
   147 void GP1212A01A::SetAllPixels(unsigned char aPattern)
   148 	{
   149 	//With a single buffer
   150 	//unsigned char screen[2048]; //One screen worth of pixels
   151 	//memset(screen,0xFF,sizeof(screen));
   152 	//SetPixelBlock(0,0,63,sizeof(screen),screen);
   153 
   154 	//Using pattern SetPixelBlock variant.
   155 	memset(iFrameBuffer->Ptr(),aPattern,FrameBufferSizeInBytes());
   156 	//
   157 
   158 
   159 	}
   160 
   161 /**
   162 Set our screen brightness.
   163 @param The desired brightness level. Must be between MinBrightness and MaxBrightness.
   164 */
   165 void GP1212A01A::SetBrightness(int aBrightness)
   166     {
   167 	if (aBrightness<MinBrightness()||aBrightness>MaxBrightness())
   168         {
   169         //Brightness out of range.
   170         //Just ignore that request.
   171         return;
   172         }
   173 
   174     FutabaVfdReport report;
   175     report[0]=0x00; //Report ID
   176     report[1]=0x06; //Report size
   177     report[2]=0x1B; //Command ID
   178     report[3]=0x5C; //Command ID
   179     report[4]=0x3F; //Command ID
   180     report[5]=0x4C; //Command ID
   181     report[6]=0x44; //Command ID
   182     report[7]=0x30+aBrightness; //Brightness level
   183     Write(report);
   184 
   185 	}
   186 
   187 /**
   188 Set the defined pixel block to the given value.
   189 @param X coordinate of our pixel block starting point.
   190 @param Y coordinate of our pixel block starting point.
   191 @param The height of our pixel block.
   192 @param The size of our pixel data. Number of pixels divided by 8.
   193 @param The value set to 8 pixels used as a pattern.
   194 */
   195 void GP1212A01A::SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char aValue)
   196 	{
   197 	OffScreenTranslation(aX,aY);
   198     FutabaVfdReport report;
   199     report[0]=0x00; //Report ID
   200     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
   201     report[2]=0x1B; //Command ID
   202     report[3]=0x5B; //Command ID
   203     report[4]=0xF0; //Command ID
   204     report[5]=aX;   //X
   205     report[6]=aY;   //Y
   206     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.
   207 	report[8]=aSize>>8; //Size of pixel data in bytes (MSB)
   208 	report[9]=aSize;	//Size of pixel data in bytes (LSB)
   209     int sizeWritten=MIN(aSize,report.Size()-10);
   210     memset(report.Buffer()+10, aValue, sizeWritten);
   211     Write(report);
   212 
   213     int remainingSize=aSize;
   214     //We need to keep on sending our pixel data until we are done
   215     while (report[1]==64)
   216         {
   217         report.Reset();
   218         remainingSize-=sizeWritten;
   219         report[0]=0x00; //Report ID
   220         report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
   221         sizeWritten=(report[1]==64?63:report[1]);
   222         memset(report.Buffer()+2, aValue, sizeWritten);
   223         Write(report);
   224         }
   225 	}
   226 
   227 /**
   228 Set the defined pixel block to the given value.
   229 @param X coordinate of our pixel block starting point.
   230 @param Y coordinate of our pixel block starting point.
   231 @param The height of our pixel block.
   232 @param The size of our pixel data. Number of pixels divided by 8.
   233 @param Pointer to our pixel data.
   234 */
   235 void GP1212A01A::SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char* aPixels)
   236     {
   237 	OffScreenTranslation(aX,aY);
   238     FutabaVfdReport report;
   239     report[0]=0x00; //Report ID
   240     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
   241     report[2]=0x1B; //Command ID
   242     report[3]=0x5B; //Command ID
   243     report[4]=0xF0; //Command ID
   244     report[5]=aX;   //X
   245     report[6]=aY;   //Y
   246     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.
   247 	report[8]=aSize>>8; //Size of pixel data in bytes (MSB)
   248 	report[9]=aSize;	//Size of pixel data in bytes (LSB)
   249     int sizeWritten=MIN(aSize,report.Size()-10);
   250     memcpy(report.Buffer()+10, aPixels, sizeWritten);
   251     Write(report);
   252 
   253     int remainingSize=aSize;
   254     //We need to keep on sending our pixel data until we are done
   255     while (report[1]==64)
   256         {
   257         report.Reset();
   258         remainingSize-=sizeWritten;
   259         report[0]=0x00; //Report ID
   260         report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
   261         sizeWritten=(report[1]==64?63:report[1]);
   262         memcpy(report.Buffer()+2, aPixels+(aSize-remainingSize), sizeWritten);
   263         Write(report);
   264         }
   265     }
   266 
   267 
   268 /**
   269 Clear our client side back buffer.
   270 Call to SwapBuffers must follow to actually clear the display.
   271 */
   272 void GP1212A01A::Clear()
   273 	{
   274 	//memset(iFrameBuffer->Ptr(),0x00,FrameBufferSizeInBytes());
   275 	iFrameBuffer->ClearAll();
   276 	}
   277 
   278 /**
   279 Using this function is advised against as is causes tearing.
   280 Use Clear instead.
   281 */
   282 void GP1212A01A::SendClearCommand()
   283 	{
   284     //1BH,5BH,32H,4AH
   285     //Send Clear Display Command
   286 	FutabaVfdReport report;
   287 	report[0]=0x00; //Report ID
   288 	report[1]=0x04; //Report length
   289 	report[2]=0x1B; //Command ID
   290 	report[3]=0x5B; //Command ID
   291 	report[4]=0x32; //Command ID
   292 	report[5]=0x4A; //Command ID
   293 	Write(report);
   294 	}
   295 
   296 /**
   297 Change our display position within our buffer.
   298 */
   299 void GP1212A01A::SetDisplayPosition(DW aDw,unsigned char aX, unsigned char aY)
   300     {
   301     //1BH,5BH,Dw,Px,Py
   302     //Send Display Position Settings Command
   303     FutabaVfdReport report;
   304     report[0]=0x00; //Report ID
   305     report[1]=0x05; //Report length
   306     report[2]=0x1B; //Command ID
   307     report[3]=0x5B; //Command ID
   308     report[4]=aDw;  //Specify our DW
   309     report[5]=aX;   //X coordinate of our DW top-left corner
   310     report[6]=aY;   //Y coordinate of our DW top-left corner
   311     Write(report);
   312     }
   313 
   314 /**
   315 Change our display position within our buffer.
   316 */
   317 void GP1212A01A::SetDisplayPosition(unsigned char aX, unsigned char aY)
   318 	{
   319 	//Specs apparently says both DW should remain the same
   320 	//Just don't ask
   321     SetDisplayPosition(GP1212A01A::DW1,aX,aY);
   322     SetDisplayPosition(GP1212A01A::DW2,aX,aY);
   323 	iDisplayPositionX=aX;
   324 	iDisplayPositionY=aY;
   325 	}
   326 
   327 /**
   328 Provide Y coordinate of our off screen buffer.
   329 */
   330 unsigned char GP1212A01A::OffScreenY() const
   331 	{
   332 	//Overflowing is fine this is just what we want
   333 	return iDisplayPositionY+HeightInPixels();
   334 	}
   335 
   336 /**
   337 Put our off screen buffer on screen.
   338 On screen buffer goes off screen.
   339 */
   340 void GP1212A01A::SwapBuffers()
   341 	{
   342 	//Only perform buffer swapping if off screen mode is enabled
   343 	if (OffScreenMode())
   344 		{
   345 		//Send host back buffer to device back buffer
   346 		SetPixelBlock(0,0,63,FrameBufferSizeInBytes(),iFrameBuffer->Ptr());
   347 		//Swap device front and back buffer
   348 		SetDisplayPosition(iDisplayPositionX,OffScreenY());
   349 		//Swap host buffers
   350 		//unsigned char* backBuffer=iBackBuffer;
   351 		//iBackBuffer = iFrontBuffer;
   352 		//iFrontBuffer = backBuffer;
   353 		}
   354 	}
   355 
   356 /**
   357 Translate the given pixel coordinate according to our off screen mode.
   358 */
   359 void GP1212A01A::OffScreenTranslation(unsigned char& aX, unsigned char& aY)
   360 	{
   361 	if (OffScreenMode())
   362 		{
   363 		aX+=WidthInPixels()-iDisplayPositionX;
   364 		aY+=HeightInPixels()-iDisplayPositionY;
   365 		}
   366 	}
   367 
   368 
   369 /**
   370 */
   371 void GP1212A01A::ResetBuffers()
   372 	{
   373 	//iFrameBuffer->ClearAll();
   374 	//memset(iFrameBuffer,0x00,sizeof(iFrameBuffer));
   375 	//memset(iFrameBeta,0x00,sizeof(iFrameBeta));
   376 	}
   377 
   378 /**
   379 */
   380 void GP1212A01A::RequestDeviceId()
   381     {
   382     if (RequestPending())
   383         {
   384         //Abort silently for now
   385         return;
   386         }
   387 
   388     //1BH,5BH,63H,49H,44H
   389     //Send Read ID command
   390     FutabaVfdReport report;
   391     report[0]=0x00; //Report ID
   392     report[1]=0x05; //Report length
   393     report[2]=0x1B; //Command ID
   394     report[3]=0x5B; //Command ID
   395     report[4]=0x63; //Command ID
   396     report[5]=0x49; //Command ID
   397     report[6]=0x44; //Command ID
   398     if (Write(report)==report.Size())
   399         {
   400         iRequest=ERequestDeviceId;
   401         }
   402     }
   403 
   404 /**
   405 */
   406 void GP1212A01A::RequestFirmwareRevision()
   407     {
   408     if (RequestPending())
   409         {
   410         //Abort silently for now
   411         return;
   412         }
   413 
   414     //1BH,5BH,63H,46H,52H
   415     //Send Software Revision Read Command
   416     FutabaVfdReport report;
   417     report[0]=0x00; //Report ID
   418     report[1]=0x05; //Report length
   419     report[2]=0x1B; //Command ID
   420     report[3]=0x5B; //Command ID
   421     report[4]=0x63; //Command ID
   422     report[5]=0x46; //Command ID
   423     report[6]=0x52; //Command ID
   424     if (Write(report)==report.Size())
   425         {
   426         iRequest=ERequestFirmwareRevision;
   427         }
   428     }
   429 
   430 /**
   431 */
   432 void GP1212A01A::RequestPowerSupplyStatus()
   433     {
   434     if (RequestPending())
   435         {
   436         //Abort silently for now
   437         return;
   438         }
   439     //1BH,5BH,63H,50H,4DH
   440     //Send Power Suppply Monitor Command
   441     FutabaVfdReport report;
   442     report[0]=0x00; //Report ID
   443     report[1]=0x05; //Report length
   444     report[2]=0x1B; //Command ID
   445     report[3]=0x5B; //Command ID
   446     report[4]=0x63; //Command ID
   447     report[5]=0x50; //Command ID
   448     report[6]=0x4D; //Command ID
   449     if (Write(report)==report.Size())
   450         {
   451         iRequest=ERequestPowerSupplyStatus;
   452         }
   453     }
   454 
   455 
   456 /**
   457 This is for development purposes only.
   458 Production application should stick to off-screen mode to avoid tearing.
   459 */
   460 void GP1212A01A::ToggleOffScreenMode()
   461 	{
   462 	iOffScreenMode=!iOffScreenMode;
   463 	//Clean up our buffers upon switching modes	
   464 	SetDisplayPosition(0,0);
   465 	Clear();
   466 	SwapBuffers();
   467 	Clear();
   468 	}
   469 
   470 /**
   471  */
   472 GP1212A01A::Request GP1212A01A::AttemptRequestCompletion()
   473     {
   474     if (!RequestPending())
   475         {
   476         return ERequestNone;
   477         }
   478 
   479     int res=Read(iInputReport);
   480 
   481     if (!res)
   482         {
   483         return ERequestNone;
   484         }
   485 
   486     //Process our request
   487     if (CurrentRequest()==GP1212A01A::ERequestPowerSupplyStatus)
   488         {
   489         if (iInputReport[1]==0x4F && iInputReport[2]==0x4E)
   490             {
   491             iPowerOn = true;
   492             }
   493         else if (iInputReport[1]==0x4F && iInputReport[2]==0x46 && iInputReport[3]==0x46)
   494             {
   495             iPowerOn = false;
   496             }
   497         }
   498 
   499     Request completed=iRequest;
   500     //Our request was completed
   501     iRequest=ERequestNone;
   502 
   503     return completed;
   504     }