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.
1.1 --- a/inc/FutabaVfd.h Thu May 22 16:46:50 2014 +0200
1.2 +++ b/inc/FutabaVfd.h Thu May 22 21:32:45 2014 +0200
1.3 @@ -30,7 +30,6 @@
1.4 const unsigned short KFutabaProductIdGP1212A01A = 0x100C;
1.5 const unsigned short KFutabaProductIdGP1212A02A = 0x1013; //Or is it 0x1015
1.6
1.7 -
1.8 //typedef struct hid_device_info HidDeviceInfo;
1.9
1.10 /**
1.11 @@ -44,7 +43,6 @@
1.12 };
1.13
1.14
1.15 -
1.16 /**
1.17 Define a generic Futaba VFD command.
1.18 */
1.19 @@ -73,8 +71,8 @@
1.20 class FutabaVfd : public HidDevice
1.21 {
1.22 public:
1.23 - virtual int MinBrightness()=0;
1.24 - virtual int MaxBrightness()=0;
1.25 + virtual int MinBrightness() const=0;
1.26 + virtual int MaxBrightness() const=0;
1.27 virtual void SetBrightness(int aBrightness)=0;
1.28 virtual void Clear()=0;
1.29 };
1.30 @@ -85,10 +83,11 @@
1.31 class FutabaGraphicVfd : public FutabaVfd
1.32 {
1.33 public:
1.34 - virtual int WidthInPixels()=0;
1.35 - virtual int HeightInPixels()=0;
1.36 - virtual void SetPixel(int aX, int aY, bool aOn)=0;
1.37 - virtual void SetAllPixels(bool aOn)=0;
1.38 + virtual int WidthInPixels() const=0;
1.39 + virtual int HeightInPixels() const=0;
1.40 + virtual void SetPixel(unsigned char aX, unsigned char aY, bool aOn)=0;
1.41 + virtual void SetAllPixels(unsigned char aOn)=0;
1.42 + virtual int FrameBufferSizeInBytes() const=0;
1.43 };
1.44
1.45 /**
1.46 @@ -98,8 +97,8 @@
1.47 {
1.48 public:
1.49 //From FutabaVfd
1.50 - virtual int MinBrightness(){return 0;};
1.51 - virtual int MaxBrightness(){return 5;};
1.52 + virtual int MinBrightness() const {return 0;};
1.53 + virtual int MaxBrightness() const {return 5;};
1.54 };
1.55
1.56 /**
1.57 @@ -110,26 +109,33 @@
1.58 class GP1212A01A : public GP1212XXXX
1.59 {
1.60 public:
1.61 + GP1212A01A();
1.62 + //
1.63 int Open();
1.64 //From FutabaGraphicVfd
1.65 - virtual int WidthInPixels(){return 256;};
1.66 - virtual int HeightInPixels(){return 64;};
1.67 - virtual void SetPixel(int aX, int aY, bool aOn);
1.68 - virtual void SetAllPixels(bool aOn);
1.69 + virtual int WidthInPixels() const {return 256;};
1.70 + virtual int HeightInPixels() const {return 64;};
1.71 + virtual void SetPixel(unsigned char aX, unsigned char aY, bool aOn);
1.72 + virtual void SetAllPixels(unsigned char aPattern);
1.73 + virtual int FrameBufferSizeInBytes() const {return 2048;}; //256*64/8
1.74 //From FutabaVfd
1.75 virtual void SetBrightness(int aBrightness);
1.76 virtual void Clear();
1.77
1.78 //Specific to GP1212A01A
1.79 - void SetPixelBlock(int aX, int aY, int aHeight, int aSize, unsigned char aValue);
1.80 - void SetPixelBlock(int aX, int aY, int aHeight, int aSize, unsigned char* aPixels);
1.81 + void SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char aValue);
1.82 + void SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char* aPixels);
1.83 //
1.84 - void SetDisplayPosition(int aX, int aY);
1.85 + void SetDisplayPosition(unsigned char aX, unsigned char aY);
1.86 + void SwapBuffers();
1.87 //
1.88 void RequestId();
1.89 void RequestFirmwareRevision();
1.90 void RequestPowerSupplyStatus();
1.91 -
1.92 + //
1.93 + void ToggleOffScreenMode();
1.94 + bool OffScreenMode() const {return iOffScreenMode;};
1.95 +
1.96 private:
1.97 enum DW
1.98 {
1.99 @@ -137,13 +143,21 @@
1.100 DW2=0xD0
1.101 };
1.102
1.103 - void SetDisplayPosition(DW aDw,int aX, int aY);
1.104 + void SetDisplayPosition(DW aDw,unsigned char aX, unsigned char aY);
1.105 + unsigned char OffScreenY() const;
1.106 + void SendClearCommand();
1.107 + void OffScreenTranslation(unsigned char& aX, unsigned char& aY);
1.108
1.109 private:
1.110 + unsigned char iDisplayPositionX;
1.111 + unsigned char iDisplayPositionY;
1.112 + ///Off screen mode is the recommended default settings to avoid tearing.
1.113 + ///Though turning it off can be useful for debugging
1.114 + bool iOffScreenMode;
1.115 ///
1.116 //FutabaVfdReport iReport;
1.117 ///
1.118 - unsigned char iPixelBuffer[256][128];
1.119 + //unsigned char iPixelBuffer[256][128];
1.120 };
1.121
1.122
2.1 --- a/inc/MainWindow.h Thu May 22 16:46:50 2014 +0200
2.2 +++ b/inc/MainWindow.h Thu May 22 21:32:45 2014 +0200
2.3 @@ -41,6 +41,7 @@
2.4 ID_FUTABA_RESET_PIXEL,
2.5 ID_FUTABA_SET_ALL_PIXELS,
2.6 ID_FUTABA_SET_DISPLAY_POSITION,
2.7 + ID_FUTABA_TOGGLE_OFF_SCREEN_MODE,
2.8 ID_SELECT_FONT,
2.9 ID_LAST
2.10 };
2.11 @@ -73,6 +74,7 @@
2.12 long onFutabaSetPixel(FXObject *sender, FXSelector sel, void *ptr);
2.13 long onFutabaResetPixel(FXObject *sender, FXSelector sel, void *ptr);
2.14 long onFutabaSetDisplayPosition(FXObject *sender, FXSelector sel, void *ptr);
2.15 + long onFutabaToggleOffScreenMode(FXObject *sender, FXSelector sel, void *ptr);
2.16 //
2.17 long onSelectFont(FXObject *sender, FXSelector sel, void *ptr);
2.18 //
2.19 @@ -112,6 +114,7 @@
2.20 FXButton *iButtonResetPixel;
2.21 FXButton *iButtonSetAllPixels;
2.22 FXButton *iButtonSetDisplayPosition;
2.23 + FXButton *iButtonToggleOffScreenMode;
2.24 //Font
2.25 FXButton *iButtonSelectFont;
2.26
3.1 --- a/src/FutabaVfd.cpp Thu May 22 16:46:50 2014 +0200
3.2 +++ b/src/FutabaVfd.cpp Thu May 22 21:32:45 2014 +0200
3.3 @@ -71,53 +71,50 @@
3.4 // class GP1212A01A
3.5 //
3.6
3.7 +GP1212A01A::GP1212A01A():iDisplayPositionX(0),iDisplayPositionY(0),iOffScreenMode(true)
3.8 + {
3.9 + }
3.10 +
3.11 int GP1212A01A::Open()
3.12 {
3.13 int success = HidDevice::Open(KFutabaVendorId,KFutabaProductIdGP1212A01A,NULL);
3.14 if (success)
3.15 {
3.16 SetNonBlocking(1);
3.17 + //Since we can't get our display position we for it to our default
3.18 + //This makes sure frames are in sync from the start
3.19 + SetDisplayPosition(iDisplayPositionX,iDisplayPositionY);
3.20 }
3.21 return success;
3.22 }
3.23
3.24 /**
3.25 */
3.26 -void GP1212A01A::SetPixel(int aX, int aY, bool aOn)
3.27 +void GP1212A01A::SetPixel(unsigned char aX, unsigned char aY, bool aOn)
3.28 {
3.29 //Just specify a one pixel block
3.30 SetPixelBlock(aX,aY,0x00,0x01,aOn);
3.31 }
3.32
3.33 /**
3.34 +Set all pixels on our screen to the desired value.
3.35 +This operation is performed off screen to avoid tearing.
3.36 +@param 8 pixels pattern
3.37 */
3.38 -void GP1212A01A::SetAllPixels(bool aOn)
3.39 +void GP1212A01A::SetAllPixels(unsigned char aPattern)
3.40 {
3.41 - //One pixel at a time
3.42 - /*
3.43 - for (int i=0;i<256;i++)
3.44 - {
3.45 - for (int j=0;j<64;j++)
3.46 - {
3.47 - SetPixel(i,j,0x01);
3.48 - }
3.49 - }
3.50 - */
3.51 + //With a single buffer
3.52 + //unsigned char screen[2048]; //One screen worth of pixels
3.53 + //memset(screen,0xFF,sizeof(screen));
3.54 + //SetPixelBlock(0,0,63,sizeof(screen),screen);
3.55
3.56 - //16x16=256 pixels at a time goes much faster
3.57 - //TODO: use even larger blocks
3.58 - for (int i=0;i<256;i+=16)
3.59 - {
3.60 - for (int j=0;j<64;j+=16)
3.61 - {
3.62 - SetPixelBlock(i,j,15,32,(aOn?0xFF:0x00));
3.63 - //FXThread::sleep(1000000000);
3.64 - }
3.65 - }
3.66 -
3.67 + //Using pattern SetPixelBlock variant.
3.68 + SetPixelBlock(0,0,63,FrameBufferSizeInBytes(),aPattern);
3.69 }
3.70
3.71 /**
3.72 +Set our screen brightness.
3.73 +@param The desired brightness level. Must be between MinBrightness and MaxBrightness.
3.74 */
3.75 void GP1212A01A::SetBrightness(int aBrightness)
3.76 {
3.77 @@ -149,23 +146,36 @@
3.78 @param The size of our pixel data. Number of pixels divided by 8.
3.79 @param The value set to 8 pixels used as a pattern.
3.80 */
3.81 -void GP1212A01A::SetPixelBlock(int aX, int aY, int aHeight, int aSize, unsigned char aValue)
3.82 +void GP1212A01A::SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char aValue)
3.83 {
3.84 - //Size must be 63 or below
3.85 - FutabaVfdReport report;
3.86 - report[0]=0x00; //Report ID
3.87 - report[1]=0x08+aSize; //Report length
3.88 - report[2]=0x1B; //
3.89 - report[3]=0x5B; //
3.90 - report[4]=0xF0; //
3.91 - report[5]=aX; //X
3.92 - report[6]=aY; //Y
3.93 - 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.
3.94 - report[8]=0x00; //Size of pixel data in bytes (MSB)
3.95 - report[9]=aSize; //Size of pixel data in bytes (LSB)
3.96 - memset(report.Buffer()+10, aValue, aSize);
3.97 - //iOutputReportBuffer[10]=aValue; //Pixel data
3.98 - Write(report);
3.99 + OffScreenTranslation(aX,aY);
3.100 + FutabaVfdReport report;
3.101 + report[0]=0x00; //Report ID
3.102 + 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
3.103 + report[2]=0x1B; //Command ID
3.104 + report[3]=0x5B; //Command ID
3.105 + report[4]=0xF0; //Command ID
3.106 + report[5]=aX; //X
3.107 + report[6]=aY; //Y
3.108 + 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.
3.109 + report[8]=aSize>>8; //Size of pixel data in bytes (MSB)
3.110 + report[9]=aSize; //Size of pixel data in bytes (LSB)
3.111 + int sizeWritten=MIN(aSize,report.Size()-10);
3.112 + memset(report.Buffer()+10, aValue, sizeWritten);
3.113 + Write(report);
3.114 +
3.115 + int remainingSize=aSize;
3.116 + //We need to keep on sending our pixel data until we are done
3.117 + while (report[1]==64)
3.118 + {
3.119 + report.Reset();
3.120 + remainingSize-=sizeWritten;
3.121 + report[0]=0x00; //Report ID
3.122 + report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
3.123 + sizeWritten=(report[1]==64?63:report[1]);
3.124 + memset(report.Buffer()+2, aValue, sizeWritten);
3.125 + Write(report);
3.126 + }
3.127 }
3.128
3.129 /**
3.130 @@ -176,19 +186,20 @@
3.131 @param The size of our pixel data. Number of pixels divided by 8.
3.132 @param Pointer to our pixel data.
3.133 */
3.134 -void GP1212A01A::SetPixelBlock(int aX, int aY, int aHeight, int aSize, unsigned char* aPixels)
3.135 +void GP1212A01A::SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char* aPixels)
3.136 {
3.137 + OffScreenTranslation(aX,aY);
3.138 FutabaVfdReport report;
3.139 report[0]=0x00; //Report ID
3.140 - report[1]=0x08+(aSize<=report.Size()-10?aSize:64); //Report length. -10 is for our header first 10 bytes
3.141 + 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
3.142 report[2]=0x1B; //Command ID
3.143 report[3]=0x5B; //Command ID
3.144 report[4]=0xF0; //Command ID
3.145 report[5]=aX; //X
3.146 report[6]=aY; //Y
3.147 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.
3.148 - unsigned short* sizePtr=(unsigned short*)report.Buffer()+8; //Size of pixel data in bytes (MSB)
3.149 - *sizePtr=aSize; //Put our size over 2 bytes
3.150 + report[8]=aSize>>8; //Size of pixel data in bytes (MSB)
3.151 + report[9]=aSize; //Size of pixel data in bytes (LSB)
3.152 int sizeWritten=MIN(aSize,report.Size()-10);
3.153 memcpy(report.Buffer()+10, aPixels, sizeWritten);
3.154 Write(report);
3.155 @@ -200,7 +211,7 @@
3.156 report.Reset();
3.157 remainingSize-=sizeWritten;
3.158 report[0]=0x00; //Report ID
3.159 - report[1]=(remainingSize<=report.Size()-2?aSize:64); //Report length, should be 64 or the remaining size
3.160 + report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
3.161 sizeWritten=(report[1]==64?63:report[1]);
3.162 memcpy(report.Buffer()+2, aPixels+(aSize-remainingSize), sizeWritten);
3.163 Write(report);
3.164 @@ -210,9 +221,21 @@
3.165
3.166 /**
3.167 Clear our display's screen.
3.168 +This operation is performed off screen to avoid tearing.
3.169 */
3.170 void GP1212A01A::Clear()
3.171 {
3.172 + //Using pattern SetPixelBlock variant.
3.173 + //First fill our off screen buffer with the desired values
3.174 + SetPixelBlock(0,0,63,FrameBufferSizeInBytes(),(unsigned char)0x00);
3.175 + }
3.176 +
3.177 +/**
3.178 +Using this function is advised against as is causes tearing.
3.179 +Use Clear instead.
3.180 +*/
3.181 +void GP1212A01A::SendClearCommand()
3.182 + {
3.183 //1BH,5BH,32H,4AH
3.184 //Send Clear Display Command
3.185 FutabaVfdReport report;
3.186 @@ -228,7 +251,7 @@
3.187 /**
3.188 Change our display position within our buffer.
3.189 */
3.190 -void GP1212A01A::SetDisplayPosition(DW aDw,int aX, int aY)
3.191 +void GP1212A01A::SetDisplayPosition(DW aDw,unsigned char aX, unsigned char aY)
3.192 {
3.193 //1BH,5BH,Dw,Px,Py
3.194 //Send Display Position Settings Command
3.195 @@ -246,12 +269,48 @@
3.196 /**
3.197 Change our display position within our buffer.
3.198 */
3.199 -void GP1212A01A::SetDisplayPosition(int aX, int aY)
3.200 +void GP1212A01A::SetDisplayPosition(unsigned char aX, unsigned char aY)
3.201 {
3.202 //Specs apparently says both DW should remain the same
3.203 //Just don't ask
3.204 SetDisplayPosition(GP1212A01A::DW1,aX,aY);
3.205 SetDisplayPosition(GP1212A01A::DW2,aX,aY);
3.206 + iDisplayPositionX=aX;
3.207 + iDisplayPositionY=aY;
3.208 + }
3.209 +
3.210 +/**
3.211 +Provide Y coordinate of our off screen buffer.
3.212 +*/
3.213 +unsigned char GP1212A01A::OffScreenY() const
3.214 + {
3.215 + //Overflowing is fine this is just what we want
3.216 + return iDisplayPositionY+HeightInPixels();
3.217 + }
3.218 +
3.219 +/**
3.220 +Put our off screen buffer on screen.
3.221 +On screen buffer goes off screen.
3.222 +*/
3.223 +void GP1212A01A::SwapBuffers()
3.224 + {
3.225 + //Only perform buffer swapping if off screen mode is enabled
3.226 + if (OffScreenMode())
3.227 + {
3.228 + SetDisplayPosition(iDisplayPositionX,OffScreenY());
3.229 + }
3.230 + }
3.231 +
3.232 +/**
3.233 +Translate the given pixel coordinate according to our off screen mode.
3.234 +*/
3.235 +void GP1212A01A::OffScreenTranslation(unsigned char& aX, unsigned char& aY)
3.236 + {
3.237 + if (OffScreenMode())
3.238 + {
3.239 + aX+=WidthInPixels()-iDisplayPositionX;
3.240 + aY+=HeightInPixels()-iDisplayPositionY;
3.241 + }
3.242 }
3.243 /**
3.244 */
3.245 @@ -302,4 +361,19 @@
3.246 report[5]=0x50; //Command ID
3.247 report[6]=0x4D; //Command ID
3.248 Write(report);
3.249 - }
3.250 \ No newline at end of file
3.251 + }
3.252 +
3.253 +
3.254 +/**
3.255 +This is for development purposes only.
3.256 +Production application should stick to off-screen mode to avoid tearing.
3.257 +*/
3.258 +void GP1212A01A::ToggleOffScreenMode()
3.259 + {
3.260 + iOffScreenMode=!iOffScreenMode;
3.261 + //Clean up our buffers upon switching modes
3.262 + SetDisplayPosition(0,0);
3.263 + Clear();
3.264 + SwapBuffers();
3.265 + Clear();
3.266 + }
3.267 \ No newline at end of file
4.1 --- a/src/test.cpp Thu May 22 16:46:50 2014 +0200
4.2 +++ b/src/test.cpp Thu May 22 21:32:45 2014 +0200
4.3 @@ -44,6 +44,7 @@
4.4 FXMAPFUNC(SEL_COMMAND, MainWindow::ID_FUTABA_RESET_PIXEL, MainWindow::onFutabaResetPixel ),
4.5 FXMAPFUNC(SEL_COMMAND, MainWindow::ID_FUTABA_SET_ALL_PIXELS, MainWindow::onFutabaSetAllPixels ),
4.6 FXMAPFUNC(SEL_COMMAND, MainWindow::ID_FUTABA_SET_DISPLAY_POSITION, MainWindow::onFutabaSetDisplayPosition ),
4.7 + FXMAPFUNC(SEL_COMMAND, MainWindow::ID_FUTABA_TOGGLE_OFF_SCREEN_MODE, MainWindow::onFutabaToggleOffScreenMode ),
4.8 FXMAPFUNC(SEL_COMMAND, MainWindow::ID_SELECT_FONT, MainWindow::onSelectFont ),
4.9 FXMAPFUNC(SEL_TIMEOUT, MainWindow::ID_TIMER, MainWindow::onTimeout ),
4.10 FXMAPFUNC(SEL_TIMEOUT, MainWindow::ID_MAC_TIMER, MainWindow::onMacTimeout ),
4.11 @@ -122,6 +123,7 @@
4.12 //
4.13 iButtonSetAllPixels = new FXButton(matrix, "Set All Pixels", NULL, this, ID_FUTABA_SET_ALL_PIXELS, BUTTON_NORMAL|LAYOUT_FILL_X);
4.14 iButtonSetDisplayPosition = new FXButton(matrix, "Set Display Position", NULL, this, ID_FUTABA_SET_DISPLAY_POSITION, BUTTON_NORMAL|LAYOUT_FILL_X);
4.15 + iButtonToggleOffScreenMode = new FXButton(matrix, "Switch to on-screen", NULL, this, ID_FUTABA_TOGGLE_OFF_SCREEN_MODE, BUTTON_NORMAL|LAYOUT_FILL_X);
4.16 //
4.17
4.18 // Output Group Box
4.19 @@ -292,6 +294,7 @@
4.20 iButtonResetPixel->enable();
4.21 iButtonSetAllPixels->enable();
4.22 iButtonSetDisplayPosition->enable();
4.23 + iButtonToggleOffScreenMode->enable();
4.24 }
4.25 }
4.26 else
4.27 @@ -318,6 +321,7 @@
4.28 iButtonResetPixel->disable();
4.29 iButtonSetAllPixels->disable();
4.30 iButtonSetDisplayPosition->disable();
4.31 + iButtonToggleOffScreenMode->disable();
4.32 //
4.33 }
4.34
4.35 @@ -545,6 +549,7 @@
4.36 MainWindow::onFutabaClearDisplay(FXObject *sender, FXSelector sel, void *ptr)
4.37 {
4.38 iVfd01.Clear();
4.39 + iVfd01.SwapBuffers();
4.40 return 1;
4.41 }
4.42
4.43 @@ -589,6 +594,7 @@
4.44 iTextFieldY->getText().scan("%d",&y);
4.45 //SetPixel(x,y,0x01);
4.46 iVfd01.SetPixel(x,y,true);
4.47 + iVfd01.SwapBuffers();
4.48 return 1;
4.49 }
4.50
4.51 @@ -602,12 +608,14 @@
4.52 iTextFieldY->getText().scan("%d",&y);
4.53 //SetPixel(x,y,0x00);
4.54 iVfd01.SetPixel(x,y,false);
4.55 + iVfd01.SwapBuffers();
4.56 return 1;
4.57 }
4.58
4.59 long MainWindow::onFutabaSetAllPixels(FXObject *sender, FXSelector sel, void *ptr)
4.60 {
4.61 - iVfd01.SetAllPixels(true);
4.62 + iVfd01.SetAllPixels(0xFF);
4.63 + iVfd01.SwapBuffers();
4.64 return 1;
4.65 }
4.66
4.67 @@ -626,6 +634,26 @@
4.68 }
4.69
4.70
4.71 +/**
4.72 +
4.73 +*/
4.74 +long MainWindow::onFutabaToggleOffScreenMode(FXObject *sender, FXSelector sel, void *ptr)
4.75 + {
4.76 + iVfd01.ToggleOffScreenMode();
4.77 + if (iVfd01.OffScreenMode())
4.78 + {
4.79 + iButtonToggleOffScreenMode->setText("Switch to on-screen");
4.80 + }
4.81 + else
4.82 + {
4.83 + iButtonToggleOffScreenMode->setText("Switch to off-screen");
4.84 + }
4.85 + return 1;
4.86 + }
4.87 +
4.88 +
4.89 +
4.90 +
4.91 long
4.92 MainWindow::onFutabaReadId(FXObject *sender, FXSelector sel, void *ptr)
4.93 {