Display auto detect implementation.
5 #include "FutabaGP1212A02.h"
10 const unsigned short KMaxDataMemoryAddress = 0x4FFF;
11 const unsigned short KFrameSizeInBytes = 0x800;
17 GP1212A02A::GP1212A02A():
18 iDisplayPositionX(0),iDisplayPositionY(0),
20 iUseFrameDifferencing(true),
27 iNeedFullFrameUpdate(0),
31 iFirmwareRevision[0]=0;
37 GP1212A02A::~GP1212A02A()
52 iNeedFullFrameUpdate=0;
57 int GP1212A02A::Open()
59 int success = HidDevice::Open(KFutabaVendorId,KFutabaProductIdGP1212A02A,NULL);
62 //Allocate both frames
65 iFrameAlpha=new BitArrayLow(KGP12xFrameBufferPixelCount);
69 iFrameBeta=new BitArrayLow(KGP12xFrameBufferPixelCount);
73 iFrameGamma=new BitArrayLow(KGP12xFrameBufferPixelCount);
75 iFrameNext=iFrameAlpha;
76 iFrameCurrent=iFrameBeta;
77 iFramePrevious=iFrameGamma;
80 //To make sure it is synced properly
81 iNeedFullFrameUpdate=0;
89 //BMP box setup could be removed if we don't use it anymore
91 BmpBoxSetting(EBmpBoxIdOne,0x0000,256,64);
92 //Select current BMP box
93 BmpBoxSelect(EBmpBoxIdOne);
95 iNextFrameAddress = 0x0000;
105 [Code] 1BH,5CH,42H,Pn,aL,aH,Pw,Ph
106 [Function] Setting the BMP box. BMP box can be defined the 3 area to DW. The position of BMP
107 box is set based on the address of DW.
108 * To write data in BMP box, BMP box select is necessary.
109 * Specifiable horizontal size is 256dot (100H) MAX. If horizontal size specify 256dot, Pw = 00H
110 Pn = Number of a BMP box
111 aL = Lower byte of address
112 aH = Upper byte of address
120 0000H <= aL + aH * 100 <= 07FFH
121 01H <= Pw <= 00H (=100H)
124 void GP1212A02A::BmpBoxSetting(TBmpBoxId aBoxId, unsigned short aAddress, int aWidth, int aHeight)
126 //TODO: check parameters validity
127 //1BH,5CH,42H,Pn,aL,aH,Pw,Ph
128 FutabaVfdReport report;
129 report[0]=0x00; //Report ID
130 report[1]=0x08; //Report length.
131 report[2]=0x1B; //Command ID
132 report[3]=0x5C; //Command ID
133 report[4]=0x42; //Command ID
135 report[6]=(unsigned char)aAddress; //aL = DM lower byte
136 report[7]=aAddress>>8; //aH = DM upper byte
137 report[8]=(aWidth==256?0x00:aWidth); //Pw = BMP box width 00==256
138 report[9]=aHeight/8; //Ph = BMP box height.
144 [Function]Select of BMP box
145 * Execution "BMP box select" is necessary before "Setting the Text box".
146 * In case of writing by the specified dot writing, it is necessary to cancel this command.
148 Pn = 30H - Remove the BMP box
153 void GP1212A02A::BmpBoxSelect(TBmpBoxId aBoxId)
155 //TODO: check parameters validity
156 FutabaVfdReport report;
157 report[0]=0x00; //Report ID
158 report[1]=0x04; //Report length.
159 report[2]=0x1B; //Command ID
160 report[3]=0x5C; //Command ID
161 report[4]=0x48; //Command ID
162 report[5]=aBoxId; //BMP box ID
169 void GP1212A02A::SetPixel(unsigned char aX, unsigned char aY, bool aOn)
172 //int byteOffset=(aX*HeightInPixels()+aY)/8;
173 //int bitOffset=(aX*HeightInPixels()+aY)%8;
174 //iNextFrame[byteOffset] |= ( (aOn?0x01:0x00) << bitOffset );
180 iFrameNext->SetBit(aX*HeightInPixels()+aY);
184 iFrameNext->ClearBit(aX*HeightInPixels()+aY);
189 //Just specify a one pixel block
197 void GP1212A02A::BitBlit(const BitArray& aBitmap, int aSrcWidth, int aSrcHeight, int aTargetX, int aTargetY) const
199 //TODO: amend loop values so that we don't keep on looping past our frame buffer dimensions.
200 for (int i=0;i<aSrcWidth;i++)
202 for (int j=0;j<aSrcHeight;j++)
204 iFrameNext->SetBitValue((aTargetX+i)*HeightInPixels()+aTargetY+j,aBitmap[+i*aSrcHeight+j]);
211 Clear our client side back buffer.
212 Call to SwapBuffers must follow to actually clear the display.
214 void GP1212A02A::Clear()
216 //memset(iNextFrame->Ptr(),0x00,FrameBufferSizeInBytes());
219 iFrameNext->ClearAll();
229 Must be followed by a SwapBuffers call.
231 void GP1212A02A::Fill()
237 Set all pixels on our screen to the desired value.
238 This operation is performed off screen to avoid tearing.
239 @param 8 pixels pattern
241 void GP1212A02A::SetAllPixels(unsigned char aPattern)
243 //With a single buffer
244 //unsigned char screen[2048]; //One screen worth of pixels
245 //memset(screen,0xFF,sizeof(screen));
246 //SetPixelBlock(0,0,63,sizeof(screen),screen);
251 memset(iFrameNext->Ptr(),aPattern,FrameBufferSizeInBytes());
255 //Using pattern SetPixelBlock variant.
266 [Code] 1BH,4AH,Pm,aL,aH,Ps,nL,nH,Pd...Pd
267 [Function] The BMP data is written in the DW(Display Window) or the Data memory.
268 Pm= DW or Data memory
271 Ps = Direction of writing
272 nL = number of BMP data length lower byte
273 nH = number of BMP data length upper byte
275 * If X direction is selected as Ps and data is written in the last address, the data in the last address is
276 overwritten with the remaining data.
277 [Definable area] Pm = 30H : DW
278 Pm = 31H: Data memory
279 0000H <= aL + aH * 100 <= 07FFH (DW)
280 0000H <= aL + aH * 100 <= 4FFFH (Data memory)
281 Ps = 30H: Y direction
282 Ps = 31H: X direction
283 0001H <= nL + nH * 100 <= 0100H(DW: X direction)
284 0001H <= nL + nH * 100 <= 0800H(DW: Y direction)
285 0001H <= nL + nH * 100 <= 0A00H(Data memory: X direction)
286 0001H <= nL + nH * 100 <= 5000H(Data memory: Y direction)
288 void GP1212A02A::BmpDataInput(TTarget aTarget, unsigned short aAddress, TDirection aDirection, unsigned short aSize, unsigned char* aPixels)
290 FutabaVfdReport report;
291 report[0]=0x00; //Report ID
292 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
293 report[2]=0x1B; //Command ID
294 report[3]=0x4A; //Command ID
295 report[4]=aTarget; //Display Window or Data Memory
296 report[5]=(unsigned char)aAddress; //aL = DW lower byte
297 report[6]=aAddress>>8; //aH = DW upper byte
298 report[7]=aDirection; //Direction of writing: Y or X
299 report[8]=(unsigned char)aSize; //Size of pixel data in bytes (LSB)
300 report[9]=aSize>>8; //Size of pixel data in bytes (MSB)
301 int sizeWritten=MIN(aSize,report.Size()-10);
302 memcpy(report.Buffer()+10, aPixels, sizeWritten);
305 int remainingSize=aSize;
306 //We need to keep on sending our pixel data until we are done
307 while (report[1]==64)
310 remainingSize-=sizeWritten;
311 report[0]=0x00; //Report ID
312 report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
313 sizeWritten=(report[1]==64?63:report[1]);
314 memcpy(report.Buffer()+2, aPixels+(aSize-remainingSize), sizeWritten);
322 [Code] 1BH,5CH,44H,aL,aH
323 [Function] BMP data transfer from Data memory to DW.
324 Although source data is updated, data in BMP box is not updated. To reflect the update,
325 re-executing this command is necessary.
326 aL = Lower byte of address
327 aH = Upper byte of address
329 0000H <= aL + aH * 100 <= 4FFFH
331 void GP1212A02A::BmpBoxDataMemoryTransfer(unsigned short aAddress)
333 FutabaVfdReport report;
334 report[0]=0x00; //Report ID
335 report[1]=0x05; //Report length.
336 report[2]=0x1B; //Command ID
337 report[3]=0x5C; //Command ID
338 report[4]=0x44; //Command ID
339 report[5]=(unsigned char)aAddress; //aL = DM lower byte
340 report[6]=aAddress>>8; //aH = DM upper byte
345 Input BMP data in the BMP box
346 [Code] 1BH,5CH,5DH,nL,nH,Pd...Pd
347 [Function] BMP data is written the BMP box
348 * Number of definable data is due to BMP box size. If the data is over range, the over range data is
349 rewritten the final address.
350 nL = Lower byte of number of definition byte
351 nH = Upper byte of number of definition byte
353 [Definable area] Pn : BMP box size (Pw * Ph)
355 void GP1212A02A::BmpBoxDataInput(unsigned short aSize, unsigned char* aPixels)
357 FutabaVfdReport report;
358 report[0]=0x00; //Report ID
359 report[1]=(aSize<=report.Size()-7?aSize+0x05:64); //Report length. -7 is for our header first 10 bytes. +5 is for our Futaba header size
360 report[2]=0x1B; //Command ID
361 report[3]=0x5C; //Command ID
362 report[4]=0x5D; //Display Window or Data Memory
363 report[5]=(unsigned char)aSize; //Size of pixel data in bytes (LSB)
364 report[6]=aSize>>8; //Size of pixel data in bytes (MSB)
365 int sizeWritten=MIN(aSize,report.Size()-7);
366 memcpy(report.Buffer()+7, aPixels, sizeWritten);
369 int remainingSize=aSize;
370 //We need to keep on sending our pixel data until we are done
371 while (report[1]==64)
374 remainingSize-=sizeWritten;
375 report[0]=0x00; //Report ID
376 report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
377 sizeWritten=(report[1]==64?63:report[1]);
378 memcpy(report.Buffer()+2, aPixels+(aSize-remainingSize), sizeWritten);
384 Using this function is advised against as is causes tearing.
387 void GP1212A02A::SendCommandClear()
390 //Send Clear Display Command
391 FutabaVfdReport report;
392 report[0]=0x00; //Report ID
393 report[1]=0x04; //Report length
394 report[2]=0x1B; //Command ID
395 report[3]=0x4A; //Command ID
396 report[4]=0x43; //Command ID
397 report[5]=0x44; //Command ID
403 Provide Y coordinate of our off screen buffer.
405 unsigned char GP1212A02A::OffScreenY() const
407 //Overflowing is fine this is just what we want
408 return iDisplayPositionY+HeightInPixels();
412 Put our off screen buffer on screen.
413 On screen buffer goes off screen.
415 void GP1212A02A::SwapBuffers()
417 //Only perform buffer swapping if off screen mode is enabled
420 //Send pixel directly into BMP box
421 //BmpBoxDataInput(FrameBufferSizeInBytes(),iFrameNext->Ptr());
422 //Send pixel data directly into the display window
423 //BmpDataInput(ETargetDisplayWindow,0x0000,EDirectionY, FrameBufferSizeInBytes(),iFrameNext->Ptr());
424 //Send pixel data first to Data Memory then copy into the selected BMP box
425 //BmpDataInput(ETargetDataMemory,0x0000,EDirectionY, FrameBufferSizeInBytes(),iFrameNext->Ptr());
426 //BmpBoxDataMemoryTransfer(0x0000);
427 //Send pixel data first to Data Memory then copy into the selected BMP box, cycling through our Data Memory frmae
428 BmpDataInput(ETargetDataMemory,iNextFrameAddress,EDirectionY, FrameBufferSizeInBytes(),iFrameNext->Ptr());
429 BmpBoxDataMemoryTransfer(iNextFrameAddress);
430 iNextFrameAddress+=KFrameSizeInBytes;
431 if (iNextFrameAddress>KMaxDataMemoryAddress)
433 iNextFrameAddress=0x0000;
436 //Cycle through our frame buffers
437 //We keep track of previous frame which is in fact our device back buffer.
438 //We can then compare previous and next frame and send only the differences to our device.
439 //This mechanism allows us to reduce traffic over our USB bus thus improving our frame rate from 14 FPS to 30 FPS.
440 //Keep our previous frame pointer
441 BitArrayLow* previousFrame=iFramePrevious;
442 //Current frame becomes the previous one
443 iFramePrevious = iFrameCurrent;
444 //Next frame becomes the current one
445 iFrameCurrent = iFrameNext;
446 //Next frame is now our former previous
447 iFrameNext = previousFrame;
452 //Define the edge of our pixel block
453 //Pixel blocks of 32x32 seems to run almost as fast as full screen update in worse case scenarii.
454 //Though I wonder if in some situations 16 could be better. Make this an attribute at some point if need be.
455 const int KPixelBlockEdge = 32;
456 const int KPixelBlockSizeInBits = KPixelBlockEdge*KPixelBlockEdge;
457 const int KPixelBlockSizeInBytes = KPixelBlockSizeInBits/8;
461 Translate the given pixel coordinate according to our off screen mode.
463 void GP1212A02A::OffScreenTranslation(unsigned char& aX, unsigned char& aY)
467 aX+=WidthInPixels()-iDisplayPositionX;
468 aY+=HeightInPixels()-iDisplayPositionY;
475 void GP1212A02A::Request(TMiniDisplayRequest aRequest)
479 case EMiniDisplayRequestDeviceId:
482 case EMiniDisplayRequestFirmwareRevision:
483 RequestFirmwareRevision();
485 case EMiniDisplayRequestPowerSupplyStatus:
486 RequestPowerSupplyStatus();
497 void GP1212A02A::ResetBuffers()
499 //iNextFrame->ClearAll();
500 //memset(iFrameAlpha,0x00,sizeof(iFrameAlpha));
501 //memset(iFrameBeta,0x00,sizeof(iFrameBeta));
506 void GP1212A02A::RequestDeviceId()
513 [Code] 1BH,6AH,49H,44H
514 [Function] Send the ID code to the Host system. ID code is software version.
516 void GP1212A02A::RequestFirmwareRevision()
518 if (RequestPending())
520 //Abort silently for now
525 //Send Software Revision Read Command
526 FutabaVfdReport report;
527 report[0]=0x00; //Report ID
528 report[1]=0x04; //Report length
529 report[2]=0x1B; //Command ID
530 report[3]=0x6A; //Command ID
531 report[4]=0x49; //Command ID
532 report[5]=0x44; //Command ID
533 if (Write(report)==report.Size())
535 SetRequest(EMiniDisplayRequestFirmwareRevision);
542 void GP1212A02A::RequestPowerSupplyStatus()
549 This is for development purposes only.
550 Production application should stick to off-screen mode to avoid tearing.
552 void GP1212A02A::ToggleOffScreenMode()
554 SetOffScreenMode(!iOffScreenMode);
558 * @brief GP1212A02A::SetOffScreenMode
562 void GP1212A02A::SetOffScreenMode(bool aOn)
564 if (aOn==iOffScreenMode)
572 //Clean up our buffers upon switching modes
579 Tries to complete our current request if we have one pending.
581 TMiniDisplayRequest GP1212A02A::AttemptRequestCompletion()
583 if (!RequestPending())
585 return EMiniDisplayRequestNone;
588 int res=Read(iInputReport);
592 return EMiniDisplayRequestNone;
595 //Process our request
596 if (CurrentRequest()==EMiniDisplayRequestFirmwareRevision)
598 unsigned char* ptr=&iInputReport[2];
599 iInputReport[7]=0x00;
600 strcpy(iFirmwareRevision,(const char*)ptr);
603 TMiniDisplayRequest completed=CurrentRequest();
604 //Our request was completed
605 SetRequest(EMiniDisplayRequestNone);
612 Set our screen brightness.
613 @param The desired brightness level. Must be between MinBrightness and MaxBrightness.
615 void GP1212A02A::SetBrightness(int aBrightness)
617 if (aBrightness<MinBrightness()||aBrightness>MaxBrightness())
619 //Brightness out of range.
620 //Just ignore that request.
624 FutabaVfdReport report;
625 report[0]=0x00; //Report ID
626 report[1]=0x04; //Report size
627 report[2]=0x1B; //Command ID
628 report[3]=0x4A; //Command ID
629 report[4]=0x44; //Command ID
630 report[5]=0x30+aBrightness; //Brightness level
636 bool GP1212A02A::IsPowerOn()
643 char* GP1212A02A::DeviceId()
650 char* GP1212A02A::FirmwareRevision()
652 return iFirmwareRevision;
658 [Function]Control of the power supply for VFD
659 * If VFD power ON or OFF, at interval of 10s or more.
660 * When the VFD power off, VFD display is turn off, but the module can receive a data and
662 Ps = VFD Power control
664 Ps = 30H : VFD Power OFF
665 Ps = 31H : VFD Power ON (Default)
667 void GP1212A02A::SendCommandPower(TPowerStatus aPowerStatus)
669 FutabaVfdReport report;
670 report[0]=0x00; //Report ID
671 report[1]=0x04; //Report size
672 report[2]=0x1B; //Command ID
673 report[3]=0x4A; //Command ID
674 report[4]=0x42; //Command ID
675 report[5]=aPowerStatus; //ON or OFF
681 void GP1212A02A::TurnPowerOn()
683 SendCommandPower(EPowerOn);
689 void GP1212A02A::TurnPowerOff()
691 SendCommandPower(EPowerOff);
696 Number of characters for the given clock format.
699 int GP1212A02A::ClockCharCount(TClockFormat aFormat)
717 int GP1212A02A::ClockCharWidthInPixels(TClockSize aSize)
737 int GP1212A02A::ClockCharHeightInPixels(TClockSize aSize)
755 Return the Display Window address for centering the clock corresponding to the given parameters.
757 unsigned short GP1212A02A::ClockCenterAddress(TClockFormat aFormat, TClockSize aSize)
759 int charCount=ClockCharCount(aFormat);
760 int halfWidth=(ClockCharWidthInPixels(aSize)*charCount)/2;
761 int halfHeight=(ClockCharHeightInPixels(aSize))/2;
762 int x=(WidthInPixels()/2)-halfWidth;
763 int y=(HeightInPixels()/2)-halfHeight;
766 int xOffset=x*8; //Not sure why...
768 unsigned short address = yOffset+xOffset;
775 void GP1212A02A::ShowClock()
777 SendCommandClockDisplay(EClockDay24,ClockCenterAddress(EClockDay24,EClockLarge),EClockLarge);
782 void GP1212A02A::HideClock()
784 SendCommandClockCancel();
790 [Code]1BH,6BH,53H,Pd,Ph,Pm
791 [Function]Setting the clock data. The setting data is cleared, if the Reset command is input or power
801 * Clock setting is canceled, when Pd is input value that is larger than 07H, or Ph is input value that is
802 larger than 18H,or Pm is input value that is larger than 3CH.
804 void GP1212A02A::SendCommandClockSetting(TWeekDay aWeekDay, unsigned char aHour, unsigned char aMinute)
806 FutabaVfdReport report;
807 report[0]=0x00; //Report ID
808 report[1]=0x06; //Report size
809 report[2]=0x1B; //Command ID
810 report[3]=0x6B; //Command ID
811 report[4]=0x53; //Command ID
812 report[5]=aWeekDay; //Sunday to Saturday
821 Set display clock settings according to local system time.
822 This needs to be redone whenever we open or turn on our display.
824 void GP1212A02A::SetClockSetting()
827 struct tm * timeinfo;
830 timeinfo = localtime ( &rawtime );
832 SendCommandClockSetting((TWeekDay)timeinfo->tm_wday,timeinfo->tm_hour,timeinfo->tm_min);
838 [Code] 1BH,6BH,55H,Ps,aL,aH,Pf
839 [Function] Clock is displayed. The display position and the font size can be freely decided.
840 Ps = Display type select
842 Pf = Font size select
844 Ps = 00H : 24hour Ex.[12:34]
845 Ps = 01H : 24hour + day of the week Ex.[Wed._12:34]
846 Ps = 10H : 12hour Ex.[PM_00:34]
847 Ps = 11H : 12hour + day of the week Ex.[Wed._PM_00:34]
852 * When the clock data is not input, clock is not displayed.
853 * The clock display is maintained until Clock display cancel "Clear display" RESET command is input
854 or power is turned off.
855 The clock display area
856 Graphic can be displayed excluding the clock display area.
857 The self adjustment for the position
858 that cannot be displayed.
859 * Excluding the clock display area can be input other display commands.
861 void GP1212A02A::SendCommandClockDisplay(TClockFormat aClockFormat, unsigned short aAddress, TClockSize aSize)
863 FutabaVfdReport report;
864 report[0]=0x00; //Report ID
865 report[1]=0x07; //Report size
866 report[2]=0x1B; //Command ID
867 report[3]=0x6B; //Command ID
868 report[4]=0x55; //Command ID
869 report[5]=aClockFormat; //
870 report[6]=(unsigned char)aAddress; //aL
871 report[7]=aAddress>>8; //aH
880 [Code] 1BH,6BH,3DH,58H
881 [Function] Clock display is canceled.
883 void GP1212A02A::SendCommandClockCancel()
885 FutabaVfdReport report;
886 report[0]=0x00; //Report ID
887 report[1]=0x04; //Report size
888 report[2]=0x1B; //Command ID
889 report[3]=0x6B; //Command ID
890 report[4]=0x3D; //Command ID