# HG changeset patch # User sl # Date 1400787165 -7200 # Node ID d4e164906a1b780c637540e424388e67d26f0170 # Parent efa6ff02287c07aeba8c513ac11fb09f7b24e0dd Fixing our multiple report pixel transfer. Implementing support for off screen mode which is now the default. On screen mode is there for debug pruposes. diff -r efa6ff02287c -r d4e164906a1b inc/FutabaVfd.h --- a/inc/FutabaVfd.h Thu May 22 16:46:50 2014 +0200 +++ b/inc/FutabaVfd.h Thu May 22 21:32:45 2014 +0200 @@ -30,7 +30,6 @@ const unsigned short KFutabaProductIdGP1212A01A = 0x100C; const unsigned short KFutabaProductIdGP1212A02A = 0x1013; //Or is it 0x1015 - //typedef struct hid_device_info HidDeviceInfo; /** @@ -44,7 +43,6 @@ }; - /** Define a generic Futaba VFD command. */ @@ -73,8 +71,8 @@ class FutabaVfd : public HidDevice { public: - virtual int MinBrightness()=0; - virtual int MaxBrightness()=0; + virtual int MinBrightness() const=0; + virtual int MaxBrightness() const=0; virtual void SetBrightness(int aBrightness)=0; virtual void Clear()=0; }; @@ -85,10 +83,11 @@ class FutabaGraphicVfd : public FutabaVfd { public: - virtual int WidthInPixels()=0; - virtual int HeightInPixels()=0; - virtual void SetPixel(int aX, int aY, bool aOn)=0; - virtual void SetAllPixels(bool aOn)=0; + virtual int WidthInPixels() const=0; + virtual int HeightInPixels() const=0; + virtual void SetPixel(unsigned char aX, unsigned char aY, bool aOn)=0; + virtual void SetAllPixels(unsigned char aOn)=0; + virtual int FrameBufferSizeInBytes() const=0; }; /** @@ -98,8 +97,8 @@ { public: //From FutabaVfd - virtual int MinBrightness(){return 0;}; - virtual int MaxBrightness(){return 5;}; + virtual int MinBrightness() const {return 0;}; + virtual int MaxBrightness() const {return 5;}; }; /** @@ -110,26 +109,33 @@ class GP1212A01A : public GP1212XXXX { public: + GP1212A01A(); + // int Open(); //From FutabaGraphicVfd - virtual int WidthInPixels(){return 256;}; - virtual int HeightInPixels(){return 64;}; - virtual void SetPixel(int aX, int aY, bool aOn); - virtual void SetAllPixels(bool aOn); + virtual int WidthInPixels() const {return 256;}; + virtual int HeightInPixels() const {return 64;}; + virtual void SetPixel(unsigned char aX, unsigned char aY, bool aOn); + virtual void SetAllPixels(unsigned char aPattern); + virtual int FrameBufferSizeInBytes() const {return 2048;}; //256*64/8 //From FutabaVfd virtual void SetBrightness(int aBrightness); virtual void Clear(); //Specific to GP1212A01A - void SetPixelBlock(int aX, int aY, int aHeight, int aSize, unsigned char aValue); - void SetPixelBlock(int aX, int aY, int aHeight, int aSize, unsigned char* aPixels); + void SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char aValue); + void SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char* aPixels); // - void SetDisplayPosition(int aX, int aY); + void SetDisplayPosition(unsigned char aX, unsigned char aY); + void SwapBuffers(); // void RequestId(); void RequestFirmwareRevision(); void RequestPowerSupplyStatus(); - + // + void ToggleOffScreenMode(); + bool OffScreenMode() const {return iOffScreenMode;}; + private: enum DW { @@ -137,13 +143,21 @@ DW2=0xD0 }; - void SetDisplayPosition(DW aDw,int aX, int aY); + void SetDisplayPosition(DW aDw,unsigned char aX, unsigned char aY); + unsigned char OffScreenY() const; + void SendClearCommand(); + void OffScreenTranslation(unsigned char& aX, unsigned char& aY); private: + unsigned char iDisplayPositionX; + unsigned char iDisplayPositionY; + ///Off screen mode is the recommended default settings to avoid tearing. + ///Though turning it off can be useful for debugging + bool iOffScreenMode; /// //FutabaVfdReport iReport; /// - unsigned char iPixelBuffer[256][128]; + //unsigned char iPixelBuffer[256][128]; }; diff -r efa6ff02287c -r d4e164906a1b inc/MainWindow.h --- a/inc/MainWindow.h Thu May 22 16:46:50 2014 +0200 +++ b/inc/MainWindow.h Thu May 22 21:32:45 2014 +0200 @@ -41,6 +41,7 @@ ID_FUTABA_RESET_PIXEL, ID_FUTABA_SET_ALL_PIXELS, ID_FUTABA_SET_DISPLAY_POSITION, + ID_FUTABA_TOGGLE_OFF_SCREEN_MODE, ID_SELECT_FONT, ID_LAST }; @@ -73,6 +74,7 @@ long onFutabaSetPixel(FXObject *sender, FXSelector sel, void *ptr); long onFutabaResetPixel(FXObject *sender, FXSelector sel, void *ptr); long onFutabaSetDisplayPosition(FXObject *sender, FXSelector sel, void *ptr); + long onFutabaToggleOffScreenMode(FXObject *sender, FXSelector sel, void *ptr); // long onSelectFont(FXObject *sender, FXSelector sel, void *ptr); // @@ -112,6 +114,7 @@ FXButton *iButtonResetPixel; FXButton *iButtonSetAllPixels; FXButton *iButtonSetDisplayPosition; + FXButton *iButtonToggleOffScreenMode; //Font FXButton *iButtonSelectFont; 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 diff -r efa6ff02287c -r d4e164906a1b src/test.cpp --- a/src/test.cpp Thu May 22 16:46:50 2014 +0200 +++ b/src/test.cpp Thu May 22 21:32:45 2014 +0200 @@ -44,6 +44,7 @@ FXMAPFUNC(SEL_COMMAND, MainWindow::ID_FUTABA_RESET_PIXEL, MainWindow::onFutabaResetPixel ), FXMAPFUNC(SEL_COMMAND, MainWindow::ID_FUTABA_SET_ALL_PIXELS, MainWindow::onFutabaSetAllPixels ), FXMAPFUNC(SEL_COMMAND, MainWindow::ID_FUTABA_SET_DISPLAY_POSITION, MainWindow::onFutabaSetDisplayPosition ), + FXMAPFUNC(SEL_COMMAND, MainWindow::ID_FUTABA_TOGGLE_OFF_SCREEN_MODE, MainWindow::onFutabaToggleOffScreenMode ), FXMAPFUNC(SEL_COMMAND, MainWindow::ID_SELECT_FONT, MainWindow::onSelectFont ), FXMAPFUNC(SEL_TIMEOUT, MainWindow::ID_TIMER, MainWindow::onTimeout ), FXMAPFUNC(SEL_TIMEOUT, MainWindow::ID_MAC_TIMER, MainWindow::onMacTimeout ), @@ -122,6 +123,7 @@ // iButtonSetAllPixels = new FXButton(matrix, "Set All Pixels", NULL, this, ID_FUTABA_SET_ALL_PIXELS, BUTTON_NORMAL|LAYOUT_FILL_X); iButtonSetDisplayPosition = new FXButton(matrix, "Set Display Position", NULL, this, ID_FUTABA_SET_DISPLAY_POSITION, BUTTON_NORMAL|LAYOUT_FILL_X); + iButtonToggleOffScreenMode = new FXButton(matrix, "Switch to on-screen", NULL, this, ID_FUTABA_TOGGLE_OFF_SCREEN_MODE, BUTTON_NORMAL|LAYOUT_FILL_X); // // Output Group Box @@ -292,6 +294,7 @@ iButtonResetPixel->enable(); iButtonSetAllPixels->enable(); iButtonSetDisplayPosition->enable(); + iButtonToggleOffScreenMode->enable(); } } else @@ -318,6 +321,7 @@ iButtonResetPixel->disable(); iButtonSetAllPixels->disable(); iButtonSetDisplayPosition->disable(); + iButtonToggleOffScreenMode->disable(); // } @@ -545,6 +549,7 @@ MainWindow::onFutabaClearDisplay(FXObject *sender, FXSelector sel, void *ptr) { iVfd01.Clear(); + iVfd01.SwapBuffers(); return 1; } @@ -589,6 +594,7 @@ iTextFieldY->getText().scan("%d",&y); //SetPixel(x,y,0x01); iVfd01.SetPixel(x,y,true); + iVfd01.SwapBuffers(); return 1; } @@ -602,12 +608,14 @@ iTextFieldY->getText().scan("%d",&y); //SetPixel(x,y,0x00); iVfd01.SetPixel(x,y,false); + iVfd01.SwapBuffers(); return 1; } long MainWindow::onFutabaSetAllPixels(FXObject *sender, FXSelector sel, void *ptr) { - iVfd01.SetAllPixels(true); + iVfd01.SetAllPixels(0xFF); + iVfd01.SwapBuffers(); return 1; } @@ -626,6 +634,26 @@ } +/** + +*/ +long MainWindow::onFutabaToggleOffScreenMode(FXObject *sender, FXSelector sel, void *ptr) + { + iVfd01.ToggleOffScreenMode(); + if (iVfd01.OffScreenMode()) + { + iButtonToggleOffScreenMode->setText("Switch to on-screen"); + } + else + { + iButtonToggleOffScreenMode->setText("Switch to off-screen"); + } + return 1; + } + + + + long MainWindow::onFutabaReadId(FXObject *sender, FXSelector sel, void *ptr) {