Frame diff algo now working nicely and providing twice the frame rate.
7 #ifdef DEBUG_FRAME_DIFF
24 FutabaVfdCommand::FutabaVfdCommand():/*iBuffer(NULL),*/iSize(0),iMaxSize(0)
28 FutabaVfdCommand::~FutabaVfdCommand()
37 void FutabaVfdCommand::Reset()
39 memset(iReports,0,sizeof(iReports));
48 void FutabaVfdCommand::Create(int aMaxSize)
50 iBuffer=new unsigned char[aMaxSize];
63 void FutabaVfdCommand::Delete()
79 GP1212A01A::GP1212A01A():
80 iDisplayPositionX(0),iDisplayPositionY(0),
88 iNeedFullFrameUpdate(0),
89 iRequest(ERequestNone),iPowerOn(false)
96 GP1212A01A::~GP1212A01A()
111 iNeedFullFrameUpdate=0;
116 int GP1212A01A::Open()
118 int success = HidDevice::Open(KFutabaVendorId,KFutabaProductIdGP1212A01A,NULL);
121 //Allocate both frames
124 iFrameAlpha=new BitArray(KGP12xFrameBufferPixelCount);
128 iFrameBeta=new BitArray(KGP12xFrameBufferPixelCount);
132 iFrameGamma=new BitArray(KGP12xFrameBufferPixelCount);
134 iFrameNext=iFrameAlpha;
135 iFrameCurrent=iFrameBeta;
136 iFramePrevious=iFrameGamma;
139 //To make sure it is synced properly
140 iNeedFullFrameUpdate=0;
143 //Since we can't get our display position we force it to our default
144 //This makes sure frames are in sync from the start
145 //Clever clients will have taken care of putting back frame (0,0) before closing
146 SetDisplayPosition(iDisplayPositionX,iDisplayPositionY);
153 void GP1212A01A::SetPixel(unsigned char aX, unsigned char aY, bool aOn)
156 //int byteOffset=(aX*HeightInPixels()+aY)/8;
157 //int bitOffset=(aX*HeightInPixels()+aY)%8;
158 //iNextFrame[byteOffset] |= ( (aOn?0x01:0x00) << bitOffset );
164 iFrameNext->SetBit(aX*HeightInPixels()+aY);
168 iFrameNext->ClearBit(aX*HeightInPixels()+aY);
173 //Just specify a one pixel block
174 SetPixelBlock(aX,aY,0x00,0x01,aOn);
180 void GP1212A01A::BitBlit(const BitArray& aBitmap, int aSrcWidth, int aSrcHeight, int aTargetX, int aTargetY) const
182 //TODO: amend loop values so that we don't keep on looping past our frame buffer dimensions.
183 for (int i=0;i<aSrcWidth;i++)
185 for (int j=0;j<aSrcHeight;j++)
187 iFrameNext->SetBitValue((aTargetX+i)*HeightInPixels()+aTargetY+j,aBitmap[+i*aSrcHeight+j]);
193 Clear our client side back buffer.
194 Call to SwapBuffers must follow to actually clear the display.
196 void GP1212A01A::Clear()
198 //memset(iNextFrame->Ptr(),0x00,FrameBufferSizeInBytes());
201 iFrameNext->ClearAll();
210 Set all pixels on our screen to the desired value.
211 This operation is performed off screen to avoid tearing.
212 @param 8 pixels pattern
214 void GP1212A01A::SetAllPixels(unsigned char aPattern)
216 //With a single buffer
217 //unsigned char screen[2048]; //One screen worth of pixels
218 //memset(screen,0xFF,sizeof(screen));
219 //SetPixelBlock(0,0,63,sizeof(screen),screen);
224 memset(iFrameNext->Ptr(),aPattern,FrameBufferSizeInBytes());
228 //Using pattern SetPixelBlock variant.
229 SetPixelBlock(0,0,63,FrameBufferSizeInBytes(),aPattern);
236 Set the defined pixel block to the given value.
237 @param X coordinate of our pixel block starting point.
238 @param Y coordinate of our pixel block starting point.
239 @param The height of our pixel block.
240 @param The size of our pixel data. Number of pixels divided by 8.
241 @param The value set to 8 pixels used as a pattern.
243 void GP1212A01A::SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char aValue)
245 OffScreenTranslation(aX,aY);
246 FutabaVfdReport report;
247 report[0]=0x00; //Report ID
248 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
249 report[2]=0x1B; //Command ID
250 report[3]=0x5B; //Command ID
251 report[4]=0xF0; //Command ID
254 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.
255 report[8]=aSize>>8; //Size of pixel data in bytes (MSB)
256 report[9]=aSize; //Size of pixel data in bytes (LSB)
257 int sizeWritten=MIN(aSize,report.Size()-10);
258 memset(report.Buffer()+10, aValue, sizeWritten);
261 int remainingSize=aSize;
262 //We need to keep on sending our pixel data until we are done
263 while (report[1]==64)
266 remainingSize-=sizeWritten;
267 report[0]=0x00; //Report ID
268 report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
269 sizeWritten=(report[1]==64?63:report[1]);
270 memset(report.Buffer()+2, aValue, sizeWritten);
276 Set the defined pixel block to the given value.
277 @param X coordinate of our pixel block starting point.
278 @param Y coordinate of our pixel block starting point.
279 @param The height of our pixel block.
280 @param The size of our pixel data. Number of pixels divided by 8.
281 @param Pointer to our pixel data.
283 void GP1212A01A::SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char* aPixels)
285 OffScreenTranslation(aX,aY);
286 FutabaVfdReport report;
287 report[0]=0x00; //Report ID
288 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
289 report[2]=0x1B; //Command ID
290 report[3]=0x5B; //Command ID
291 report[4]=0xF0; //Command ID
294 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.
295 report[8]=aSize>>8; //Size of pixel data in bytes (MSB)
296 report[9]=aSize; //Size of pixel data in bytes (LSB)
297 int sizeWritten=MIN(aSize,report.Size()-10);
298 memcpy(report.Buffer()+10, aPixels, sizeWritten);
301 int remainingSize=aSize;
302 //We need to keep on sending our pixel data until we are done
303 while (report[1]==64)
306 remainingSize-=sizeWritten;
307 report[0]=0x00; //Report ID
308 report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
309 sizeWritten=(report[1]==64?63:report[1]);
310 memcpy(report.Buffer()+2, aPixels+(aSize-remainingSize), sizeWritten);
316 Using this function is advised against as is causes tearing.
319 void GP1212A01A::SendClearCommand()
322 //Send Clear Display Command
323 FutabaVfdReport report;
324 report[0]=0x00; //Report ID
325 report[1]=0x04; //Report length
326 report[2]=0x1B; //Command ID
327 report[3]=0x5B; //Command ID
328 report[4]=0x32; //Command ID
329 report[5]=0x4A; //Command ID
334 Change our display position within our buffer.
336 void GP1212A01A::SetDisplayPosition(DW aDw,unsigned char aX, unsigned char aY)
339 //Send Display Position Settings Command
340 FutabaVfdReport report;
341 report[0]=0x00; //Report ID
342 report[1]=0x05; //Report length
343 report[2]=0x1B; //Command ID
344 report[3]=0x5B; //Command ID
345 report[4]=aDw; //Specify our DW
346 report[5]=aX; //X coordinate of our DW top-left corner
347 report[6]=aY; //Y coordinate of our DW top-left corner
352 Change our display position within our buffer.
354 void GP1212A01A::SetDisplayPosition(unsigned char aX, unsigned char aY)
356 //Specs apparently says both DW should remain the same
358 SetDisplayPosition(GP1212A01A::DW1,aX,aY);
359 SetDisplayPosition(GP1212A01A::DW2,aX,aY);
360 iDisplayPositionX=aX;
361 iDisplayPositionY=aY;
365 Provide Y coordinate of our off screen buffer.
367 unsigned char GP1212A01A::OffScreenY() const
369 //Overflowing is fine this is just what we want
370 return iDisplayPositionY+HeightInPixels();
374 Put our off screen buffer on screen.
375 On screen buffer goes off screen.
377 void GP1212A01A::SwapBuffers()
379 //Only perform buffer swapping if off screen mode is enabled
382 //Send host back buffer to device back buffer
383 if (iNeedFullFrameUpdate<3)
385 //TODO: enable this once SendModifiedPixelBlocks works
386 iNeedFullFrameUpdate++;
387 SetPixelBlock(0,0,63,FrameBufferSizeInBytes(),iFrameNext->Ptr());
391 SendModifiedPixelBlocks();
393 //Swap device front and back buffer
394 SetDisplayPosition(iDisplayPositionX,OffScreenY());
396 //Cycle through our frame buffers
397 //We keep track of previous frame which is in fact our device back buffer.
398 //We can then compare previous and next frame and send only the differences to our device.
399 //This mechanism allows us to reduce traffic over our USB bus thus improving our frame rate from 14 FPS to 30 FPS.
400 //Keep our previous frame pointer
401 BitArray* previousFrame=iFramePrevious;
402 //Current frame becomes the previous one
403 iFramePrevious = iFrameCurrent;
404 //Next frame becomes the current one
405 iFrameCurrent = iFrameNext;
406 //Next frame is now our former previous
407 iFrameNext = previousFrame;
413 * @brief GP1212A01A::SendModifiedPixelBlocks
414 * Compare our back and front buffer and send to the device only the modified pixels.
415 * TODO: Get this working at some point.
417 void GP1212A01A::SendModifiedPixelBlocks()
419 //The largest pixel block we can sanely send with one report is 16*16
420 //const int KBlocksPerRow = WidthInPixels()/16; //16
421 //const int KBlocksPerColumn = HeightInPixels()/16; //4
423 int w=WidthInPixels();
424 int h=HeightInPixels();
428 //TODO: optimize with memcmp and 16 inc
430 for (int i=0;i<w;i++)
432 for (int j=0;j<h;j++)
434 //aX*HeightInPixels()+aY
435 if ((*iFrameNext)[i*h+j]!=(*iFramePrevious)[i*h+j])
437 //We need to update that pixel
438 SetPixelBlock(i,j,0,1,((*iFrameNext)[i*h+j]?0x01:0x00));
439 //SetDisplayPosition(iDisplayPositionX,OffScreenY());
440 //SetDisplayPosition(iDisplayPositionX,OffScreenY());
442 //SetPixelBlock(i,j,15,32,iNextFrame->Ptr()+offset);
448 BitArray nextBlock(16*16);
449 BitArray previousBlock(16*16);
451 for (int i=0;i<w;i+=16)
453 for (int j=0;j<h;j+=16)
455 //aX*HeightInPixels()+aY
456 //int offset=(i*w/8)+(j/8);
458 #ifdef DEBUG_FRAME_DIFF
459 QImage imagePrevious(16,16,QImage::Format_RGB32);
460 QImage imageNext(16,16,QImage::Format_RGB32);
463 //Get both our blocks from our buffers
464 for (int x=i;x<i+16;x++)
466 for (int y=j;y<j+16;y++)
468 nextBlock.SetBitValue((x-i)*16+(y-j),(*iFrameNext)[x*h+y]);
469 previousBlock.SetBitValue((x-i)*16+(y-j),(*iFramePrevious)[x*h+y]);
471 #ifdef DEBUG_FRAME_DIFF
472 imageNext.setPixel(x-i,y-j,(nextBlock[(x-i)*16+(y-j)]?0xFFFFFFFF:0x00000000));
473 imagePrevious.setPixel(x-i,y-j,(previousBlock[(x-i)*16+(y-j)]?0xFFFFFFFF:0x00000000));
478 #ifdef DEBUG_FRAME_DIFF
479 QString previousName;
481 QTextStream(&previousName) << "p" << i << "x" << j << ".png";
482 QTextStream(&nextName) << "n" << i << "x" << j << ".png";
483 imagePrevious.save(previousName);
484 imageNext.save(nextName);
488 //if (memcmp(iFrameNext->Ptr()+offset,iFramePrevious->Ptr()+offset,32 )) //32=(16*16/8)
489 if (memcmp(nextBlock.Ptr(),previousBlock.Ptr(),32 )!=0) //32=(16*16/8)
491 //We need to update that block
492 SetPixelBlock(i,j,15,32,nextBlock.Ptr());
493 //SetPixelBlock(i,j,15,32,0xFF/*nextBlock.Ptr()*/);
494 //SetDisplayPosition(iDisplayPositionX,OffScreenY());
495 //SetDisplayPosition(iDisplayPositionX,OffScreenY());
497 //SetPixelBlock(i,j,15,32,iFrameNext->Ptr()+offset);
505 Translate the given pixel coordinate according to our off screen mode.
507 void GP1212A01A::OffScreenTranslation(unsigned char& aX, unsigned char& aY)
511 aX+=WidthInPixels()-iDisplayPositionX;
512 aY+=HeightInPixels()-iDisplayPositionY;
519 void GP1212A01A::ResetBuffers()
521 //iNextFrame->ClearAll();
522 //memset(iFrameAlpha,0x00,sizeof(iFrameAlpha));
523 //memset(iFrameBeta,0x00,sizeof(iFrameBeta));
528 void GP1212A01A::RequestDeviceId()
530 if (RequestPending())
532 //Abort silently for now
536 //1BH,5BH,63H,49H,44H
537 //Send Read ID command
538 FutabaVfdReport report;
539 report[0]=0x00; //Report ID
540 report[1]=0x05; //Report length
541 report[2]=0x1B; //Command ID
542 report[3]=0x5B; //Command ID
543 report[4]=0x63; //Command ID
544 report[5]=0x49; //Command ID
545 report[6]=0x44; //Command ID
546 if (Write(report)==report.Size())
548 iRequest=ERequestDeviceId;
554 void GP1212A01A::RequestFirmwareRevision()
556 if (RequestPending())
558 //Abort silently for now
562 //1BH,5BH,63H,46H,52H
563 //Send Software Revision Read Command
564 FutabaVfdReport report;
565 report[0]=0x00; //Report ID
566 report[1]=0x05; //Report length
567 report[2]=0x1B; //Command ID
568 report[3]=0x5B; //Command ID
569 report[4]=0x63; //Command ID
570 report[5]=0x46; //Command ID
571 report[6]=0x52; //Command ID
572 if (Write(report)==report.Size())
574 iRequest=ERequestFirmwareRevision;
580 void GP1212A01A::RequestPowerSupplyStatus()
582 if (RequestPending())
584 //Abort silently for now
587 //1BH,5BH,63H,50H,4DH
588 //Send Power Suppply Monitor Command
589 FutabaVfdReport report;
590 report[0]=0x00; //Report ID
591 report[1]=0x05; //Report length
592 report[2]=0x1B; //Command ID
593 report[3]=0x5B; //Command ID
594 report[4]=0x63; //Command ID
595 report[5]=0x50; //Command ID
596 report[6]=0x4D; //Command ID
597 if (Write(report)==report.Size())
599 iRequest=ERequestPowerSupplyStatus;
605 This is for development purposes only.
606 Production application should stick to off-screen mode to avoid tearing.
608 void GP1212A01A::ToggleOffScreenMode()
610 SetOffScreenMode(!iOffScreenMode);
614 * @brief GP1212A01A::SetOffScreenMode
618 void GP1212A01A::SetOffScreenMode(bool aOn)
620 if (aOn==iOffScreenMode)
628 //Clean up our buffers upon switching modes
629 SetDisplayPosition(0,0);
637 GP1212A01A::Request GP1212A01A::AttemptRequestCompletion()
639 if (!RequestPending())
644 int res=Read(iInputReport);
651 //Process our request
652 if (CurrentRequest()==GP1212A01A::ERequestPowerSupplyStatus)
654 if (iInputReport[1]==0x4F && iInputReport[2]==0x4E)
658 else if (iInputReport[1]==0x4F && iInputReport[2]==0x46 && iInputReport[3]==0x46)
664 Request completed=iRequest;
665 //Our request was completed
666 iRequest=ERequestNone;
673 Set our screen brightness.
674 @param The desired brightness level. Must be between MinBrightness and MaxBrightness.
676 void GP1212A01A::SetBrightness(int aBrightness)
678 if (aBrightness<MinBrightness()||aBrightness>MaxBrightness())
680 //Brightness out of range.
681 //Just ignore that request.
685 FutabaVfdReport report;
686 report[0]=0x00; //Report ID
687 report[1]=0x06; //Report size
688 report[2]=0x1B; //Command ID
689 report[3]=0x5C; //Command ID
690 report[4]=0x3F; //Command ID
691 report[5]=0x4C; //Command ID
692 report[6]=0x44; //Command ID
693 report[7]=0x30+aBrightness; //Brightness level