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