diff -r efa6ff02287c -r d4e164906a1b src/FutabaVfd.cpp --- a/src/FutabaVfd.cpp Thu May 22 16:46:50 2014 +0200 +++ b/src/FutabaVfd.cpp Thu May 22 21:32:45 2014 +0200 @@ -71,53 +71,50 @@ // class GP1212A01A // +GP1212A01A::GP1212A01A():iDisplayPositionX(0),iDisplayPositionY(0),iOffScreenMode(true) + { + } + int GP1212A01A::Open() { int success = HidDevice::Open(KFutabaVendorId,KFutabaProductIdGP1212A01A,NULL); if (success) { SetNonBlocking(1); + //Since we can't get our display position we for it to our default + //This makes sure frames are in sync from the start + SetDisplayPosition(iDisplayPositionX,iDisplayPositionY); } return success; } /** */ -void GP1212A01A::SetPixel(int aX, int aY, bool aOn) +void GP1212A01A::SetPixel(unsigned char aX, unsigned char aY, bool aOn) { //Just specify a one pixel block SetPixelBlock(aX,aY,0x00,0x01,aOn); } /** +Set all pixels on our screen to the desired value. +This operation is performed off screen to avoid tearing. +@param 8 pixels pattern */ -void GP1212A01A::SetAllPixels(bool aOn) +void GP1212A01A::SetAllPixels(unsigned char aPattern) { - //One pixel at a time - /* - for (int i=0;i<256;i++) - { - for (int j=0;j<64;j++) - { - SetPixel(i,j,0x01); - } - } - */ + //With a single buffer + //unsigned char screen[2048]; //One screen worth of pixels + //memset(screen,0xFF,sizeof(screen)); + //SetPixelBlock(0,0,63,sizeof(screen),screen); - //16x16=256 pixels at a time goes much faster - //TODO: use even larger blocks - for (int i=0;i<256;i+=16) - { - for (int j=0;j<64;j+=16) - { - SetPixelBlock(i,j,15,32,(aOn?0xFF:0x00)); - //FXThread::sleep(1000000000); - } - } - + //Using pattern SetPixelBlock variant. + SetPixelBlock(0,0,63,FrameBufferSizeInBytes(),aPattern); } /** +Set our screen brightness. +@param The desired brightness level. Must be between MinBrightness and MaxBrightness. */ void GP1212A01A::SetBrightness(int aBrightness) { @@ -149,23 +146,36 @@ @param The size of our pixel data. Number of pixels divided by 8. @param The value set to 8 pixels used as a pattern. */ -void GP1212A01A::SetPixelBlock(int aX, int aY, int aHeight, int aSize, unsigned char aValue) +void GP1212A01A::SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char aValue) { - //Size must be 63 or below - FutabaVfdReport report; - report[0]=0x00; //Report ID - report[1]=0x08+aSize; //Report length - report[2]=0x1B; // - report[3]=0x5B; // - report[4]=0xF0; // - report[5]=aX; //X - report[6]=aY; //Y - 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. - report[8]=0x00; //Size of pixel data in bytes (MSB) - report[9]=aSize; //Size of pixel data in bytes (LSB) - memset(report.Buffer()+10, aValue, aSize); - //iOutputReportBuffer[10]=aValue; //Pixel data - Write(report); + OffScreenTranslation(aX,aY); + FutabaVfdReport report; + report[0]=0x00; //Report ID + 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 + report[2]=0x1B; //Command ID + report[3]=0x5B; //Command ID + report[4]=0xF0; //Command ID + report[5]=aX; //X + report[6]=aY; //Y + 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. + report[8]=aSize>>8; //Size of pixel data in bytes (MSB) + report[9]=aSize; //Size of pixel data in bytes (LSB) + int sizeWritten=MIN(aSize,report.Size()-10); + memset(report.Buffer()+10, aValue, sizeWritten); + Write(report); + + int remainingSize=aSize; + //We need to keep on sending our pixel data until we are done + while (report[1]==64) + { + report.Reset(); + remainingSize-=sizeWritten; + report[0]=0x00; //Report ID + report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size + sizeWritten=(report[1]==64?63:report[1]); + memset(report.Buffer()+2, aValue, sizeWritten); + Write(report); + } } /** @@ -176,19 +186,20 @@ @param The size of our pixel data. Number of pixels divided by 8. @param Pointer to our pixel data. */ -void GP1212A01A::SetPixelBlock(int aX, int aY, int aHeight, int aSize, unsigned char* aPixels) +void GP1212A01A::SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char* aPixels) { + OffScreenTranslation(aX,aY); FutabaVfdReport report; report[0]=0x00; //Report ID - report[1]=0x08+(aSize<=report.Size()-10?aSize:64); //Report length. -10 is for our header first 10 bytes + 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 report[2]=0x1B; //Command ID report[3]=0x5B; //Command ID report[4]=0xF0; //Command ID report[5]=aX; //X report[6]=aY; //Y 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. - unsigned short* sizePtr=(unsigned short*)report.Buffer()+8; //Size of pixel data in bytes (MSB) - *sizePtr=aSize; //Put our size over 2 bytes + report[8]=aSize>>8; //Size of pixel data in bytes (MSB) + report[9]=aSize; //Size of pixel data in bytes (LSB) int sizeWritten=MIN(aSize,report.Size()-10); memcpy(report.Buffer()+10, aPixels, sizeWritten); Write(report); @@ -200,7 +211,7 @@ report.Reset(); remainingSize-=sizeWritten; report[0]=0x00; //Report ID - report[1]=(remainingSize<=report.Size()-2?aSize:64); //Report length, should be 64 or the remaining size + report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size sizeWritten=(report[1]==64?63:report[1]); memcpy(report.Buffer()+2, aPixels+(aSize-remainingSize), sizeWritten); Write(report); @@ -210,9 +221,21 @@ /** Clear our display's screen. +This operation is performed off screen to avoid tearing. */ void GP1212A01A::Clear() { + //Using pattern SetPixelBlock variant. + //First fill our off screen buffer with the desired values + SetPixelBlock(0,0,63,FrameBufferSizeInBytes(),(unsigned char)0x00); + } + +/** +Using this function is advised against as is causes tearing. +Use Clear instead. +*/ +void GP1212A01A::SendClearCommand() + { //1BH,5BH,32H,4AH //Send Clear Display Command FutabaVfdReport report; @@ -228,7 +251,7 @@ /** Change our display position within our buffer. */ -void GP1212A01A::SetDisplayPosition(DW aDw,int aX, int aY) +void GP1212A01A::SetDisplayPosition(DW aDw,unsigned char aX, unsigned char aY) { //1BH,5BH,Dw,Px,Py //Send Display Position Settings Command @@ -246,12 +269,48 @@ /** Change our display position within our buffer. */ -void GP1212A01A::SetDisplayPosition(int aX, int aY) +void GP1212A01A::SetDisplayPosition(unsigned char aX, unsigned char aY) { //Specs apparently says both DW should remain the same //Just don't ask SetDisplayPosition(GP1212A01A::DW1,aX,aY); SetDisplayPosition(GP1212A01A::DW2,aX,aY); + iDisplayPositionX=aX; + iDisplayPositionY=aY; + } + +/** +Provide Y coordinate of our off screen buffer. +*/ +unsigned char GP1212A01A::OffScreenY() const + { + //Overflowing is fine this is just what we want + return iDisplayPositionY+HeightInPixels(); + } + +/** +Put our off screen buffer on screen. +On screen buffer goes off screen. +*/ +void GP1212A01A::SwapBuffers() + { + //Only perform buffer swapping if off screen mode is enabled + if (OffScreenMode()) + { + SetDisplayPosition(iDisplayPositionX,OffScreenY()); + } + } + +/** +Translate the given pixel coordinate according to our off screen mode. +*/ +void GP1212A01A::OffScreenTranslation(unsigned char& aX, unsigned char& aY) + { + if (OffScreenMode()) + { + aX+=WidthInPixels()-iDisplayPositionX; + aY+=HeightInPixels()-iDisplayPositionY; + } } /** */ @@ -302,4 +361,19 @@ report[5]=0x50; //Command ID report[6]=0x4D; //Command ID Write(report); - } \ No newline at end of file + } + + +/** +This is for development purposes only. +Production application should stick to off-screen mode to avoid tearing. +*/ +void GP1212A01A::ToggleOffScreenMode() + { + iOffScreenMode=!iOffScreenMode; + //Clean up our buffers upon switching modes + SetDisplayPosition(0,0); + Clear(); + SwapBuffers(); + Clear(); + } \ No newline at end of file