First working version of GP1212A02A.
5 #include "FutabaGP1212A02.h"
8 const int KNumberOfFrameBeforeDiffAlgo = 3;
14 GP1212A02A::GP1212A02A():
15 iDisplayPositionX(0),iDisplayPositionY(0),
17 iUseFrameDifferencing(true),
24 iNeedFullFrameUpdate(0),
28 iFirmwareRevision[0]=0;
34 GP1212A02A::~GP1212A02A()
49 iNeedFullFrameUpdate=0;
54 int GP1212A02A::Open()
56 int success = HidDevice::Open(KFutabaVendorId,KFutabaProductIdGP1212A02A,NULL);
59 //Allocate both frames
62 iFrameAlpha=new BitArrayLow(KGP12xFrameBufferPixelCount);
66 iFrameBeta=new BitArrayLow(KGP12xFrameBufferPixelCount);
70 iFrameGamma=new BitArrayLow(KGP12xFrameBufferPixelCount);
72 iFrameNext=iFrameAlpha;
73 iFrameCurrent=iFrameBeta;
74 iFramePrevious=iFrameGamma;
77 //To make sure it is synced properly
78 iNeedFullFrameUpdate=0;
89 void GP1212A02A::SetPixel(unsigned char aX, unsigned char aY, bool aOn)
92 //int byteOffset=(aX*HeightInPixels()+aY)/8;
93 //int bitOffset=(aX*HeightInPixels()+aY)%8;
94 //iNextFrame[byteOffset] |= ( (aOn?0x01:0x00) << bitOffset );
100 iFrameNext->SetBit(aX*HeightInPixels()+aY);
104 iFrameNext->ClearBit(aX*HeightInPixels()+aY);
109 //Just specify a one pixel block
117 void GP1212A02A::BitBlit(const BitArray& aBitmap, int aSrcWidth, int aSrcHeight, int aTargetX, int aTargetY) const
119 //TODO: amend loop values so that we don't keep on looping past our frame buffer dimensions.
120 for (int i=0;i<aSrcWidth;i++)
122 for (int j=0;j<aSrcHeight;j++)
124 iFrameNext->SetBitValue((aTargetX+i)*HeightInPixels()+aTargetY+j,aBitmap[+i*aSrcHeight+j]);
131 Clear our client side back buffer.
132 Call to SwapBuffers must follow to actually clear the display.
134 void GP1212A02A::Clear()
136 //memset(iNextFrame->Ptr(),0x00,FrameBufferSizeInBytes());
139 iFrameNext->ClearAll();
149 Must be followed by a SwapBuffers call.
151 void GP1212A02A::Fill()
157 Set all pixels on our screen to the desired value.
158 This operation is performed off screen to avoid tearing.
159 @param 8 pixels pattern
161 void GP1212A02A::SetAllPixels(unsigned char aPattern)
163 //With a single buffer
164 //unsigned char screen[2048]; //One screen worth of pixels
165 //memset(screen,0xFF,sizeof(screen));
166 //SetPixelBlock(0,0,63,sizeof(screen),screen);
171 memset(iFrameNext->Ptr(),aPattern,FrameBufferSizeInBytes());
175 //Using pattern SetPixelBlock variant.
185 Using this function is advised against as is causes tearing.
188 void GP1212A02A::SetFrame(int aSize, unsigned char* aPixels)
190 FutabaVfdReport report;
191 report[0]=0x00; //Report ID
192 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
193 report[2]=0x1B; //Command ID
194 report[3]=0x4A; //Command ID
195 report[4]=0x30; //DW Display Window
196 report[5]=0x00; //aL = DW lower byte
197 report[6]=0x00; //aH = DW upper byte
198 report[7]=0x30; //Direction of writing: Y
199 report[8]=aSize; //Size of pixel data in bytes (LSB)
200 report[9]=aSize>>8; //Size of pixel data in bytes (MSB)
201 int sizeWritten=MIN(aSize,report.Size()-10);
202 memcpy(report.Buffer()+10, aPixels, sizeWritten);
205 int remainingSize=aSize;
206 //We need to keep on sending our pixel data until we are done
207 while (report[1]==64)
210 remainingSize-=sizeWritten;
211 report[0]=0x00; //Report ID
212 report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
213 sizeWritten=(report[1]==64?63:report[1]);
214 memcpy(report.Buffer()+2, aPixels+(aSize-remainingSize), sizeWritten);
220 Using this function is advised against as is causes tearing.
223 void GP1212A02A::SendClearCommand()
226 //Send Clear Display Command
227 FutabaVfdReport report;
228 report[0]=0x00; //Report ID
229 report[1]=0x04; //Report length
230 report[2]=0x1B; //Command ID
231 report[3]=0x4A; //Command ID
232 report[4]=0x43; //Command ID
233 report[5]=0x44; //Command ID
239 Provide Y coordinate of our off screen buffer.
241 unsigned char GP1212A02A::OffScreenY() const
243 //Overflowing is fine this is just what we want
244 return iDisplayPositionY+HeightInPixels();
248 Put our off screen buffer on screen.
249 On screen buffer goes off screen.
251 void GP1212A02A::SwapBuffers()
253 //Only perform buffer swapping if off screen mode is enabled
256 //Send host back buffer to device back buffer
257 SetFrame(FrameBufferSizeInBytes(),iFrameNext->Ptr());
259 //Cycle through our frame buffers
260 //We keep track of previous frame which is in fact our device back buffer.
261 //We can then compare previous and next frame and send only the differences to our device.
262 //This mechanism allows us to reduce traffic over our USB bus thus improving our frame rate from 14 FPS to 30 FPS.
263 //Keep our previous frame pointer
264 BitArrayLow* previousFrame=iFramePrevious;
265 //Current frame becomes the previous one
266 iFramePrevious = iFrameCurrent;
267 //Next frame becomes the current one
268 iFrameCurrent = iFrameNext;
269 //Next frame is now our former previous
270 iFrameNext = previousFrame;
275 //Define the edge of our pixel block
276 //Pixel blocks of 32x32 seems to run almost as fast as full screen update in worse case scenarii.
277 //Though I wonder if in some situations 16 could be better. Make this an attribute at some point if need be.
278 const int KPixelBlockEdge = 32;
279 const int KPixelBlockSizeInBits = KPixelBlockEdge*KPixelBlockEdge;
280 const int KPixelBlockSizeInBytes = KPixelBlockSizeInBits/8;
284 Translate the given pixel coordinate according to our off screen mode.
286 void GP1212A02A::OffScreenTranslation(unsigned char& aX, unsigned char& aY)
290 aX+=WidthInPixels()-iDisplayPositionX;
291 aY+=HeightInPixels()-iDisplayPositionY;
298 void GP1212A02A::ResetBuffers()
300 //iNextFrame->ClearAll();
301 //memset(iFrameAlpha,0x00,sizeof(iFrameAlpha));
302 //memset(iFrameBeta,0x00,sizeof(iFrameBeta));
307 void GP1212A02A::RequestDeviceId()
314 void GP1212A02A::RequestFirmwareRevision()
321 void GP1212A02A::RequestPowerSupplyStatus()
328 This is for development purposes only.
329 Production application should stick to off-screen mode to avoid tearing.
331 void GP1212A02A::ToggleOffScreenMode()
333 SetOffScreenMode(!iOffScreenMode);
337 * @brief GP1212A02A::SetOffScreenMode
341 void GP1212A02A::SetOffScreenMode(bool aOn)
343 if (aOn==iOffScreenMode)
351 //Clean up our buffers upon switching modes
358 Tries to complete our current request if we have one pending.
360 TMiniDisplayRequest GP1212A02A::AttemptRequestCompletion()
362 //That display does not support any requests
363 return EMiniDisplayRequestNone;
368 Set our screen brightness.
369 @param The desired brightness level. Must be between MinBrightness and MaxBrightness.
371 void GP1212A02A::SetBrightness(int aBrightness)
373 if (aBrightness<MinBrightness()||aBrightness>MaxBrightness())
375 //Brightness out of range.
376 //Just ignore that request.
380 FutabaVfdReport report;
381 report[0]=0x00; //Report ID
382 report[1]=0x04; //Report size
383 report[2]=0x1B; //Command ID
384 report[3]=0x4A; //Command ID
385 report[4]=0x44; //Command ID
386 report[5]=0x30+aBrightness; //Brightness level
392 bool GP1212A02A::PowerOn()
399 char* GP1212A02A::DeviceId()
406 char* GP1212A02A::FirmwareRevision()
408 return iFirmwareRevision;