Adding support for power on/off.
5 #include "FutabaGP1212A02.h"
8 const int KNumberOfFrameBeforeDiffAlgo = 3;
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;
88 BmpBoxSetting(EBmpBoxIdOne,0x0000,256,64);
90 //Select current BMP box
91 BmpBoxSelect(EBmpBoxIdOne);
93 iNextFrameAddress = 0x0000;
101 [Code] 1BH,5CH,42H,Pn,aL,aH,Pw,Ph
102 [Function] Setting the BMP box. BMP box can be defined the 3 area to DW. The position of BMP
103 box is set based on the address of DW.
104 * To write data in BMP box, BMP box select is necessary.
105 * Specifiable horizontal size is 256dot (100H) MAX. If horizontal size specify 256dot, Pw = 00H
106 Pn = Number of a BMP box
107 aL = Lower byte of address
108 aH = Upper byte of address
116 0000H <= aL + aH * 100 <= 07FFH
117 01H <= Pw <= 00H (=100H)
120 void GP1212A02A::BmpBoxSetting(TBmpBoxId aBoxId, unsigned short aAddress, int aWidth, int aHeight)
122 //TODO: check parameters validity
123 //1BH,5CH,42H,Pn,aL,aH,Pw,Ph
124 FutabaVfdReport report;
125 report[0]=0x00; //Report ID
126 report[1]=0x08; //Report length.
127 report[2]=0x1B; //Command ID
128 report[3]=0x5C; //Command ID
129 report[4]=0x42; //Command ID
131 report[6]=(unsigned char)aAddress; //aL = DM lower byte
132 report[7]=aAddress>>8; //aH = DM upper byte
133 report[8]=(aWidth==256?0x00:aWidth); //Pw = BMP box width 00==256
134 report[9]=aHeight/8; //Ph = BMP box height.
140 [Function]Select of BMP box
141 * Execution "BMP box select" is necessary before "Setting the Text box".
142 * In case of writing by the specified dot writing, it is necessary to cancel this command.
144 Pn = 30H - Remove the BMP box
149 void GP1212A02A::BmpBoxSelect(TBmpBoxId aBoxId)
151 //TODO: check parameters validity
152 FutabaVfdReport report;
153 report[0]=0x00; //Report ID
154 report[1]=0x04; //Report length.
155 report[2]=0x1B; //Command ID
156 report[3]=0x5C; //Command ID
157 report[4]=0x48; //Command ID
158 report[5]=aBoxId; //BMP box ID
165 void GP1212A02A::SetPixel(unsigned char aX, unsigned char aY, bool aOn)
168 //int byteOffset=(aX*HeightInPixels()+aY)/8;
169 //int bitOffset=(aX*HeightInPixels()+aY)%8;
170 //iNextFrame[byteOffset] |= ( (aOn?0x01:0x00) << bitOffset );
176 iFrameNext->SetBit(aX*HeightInPixels()+aY);
180 iFrameNext->ClearBit(aX*HeightInPixels()+aY);
185 //Just specify a one pixel block
193 void GP1212A02A::BitBlit(const BitArray& aBitmap, int aSrcWidth, int aSrcHeight, int aTargetX, int aTargetY) const
195 //TODO: amend loop values so that we don't keep on looping past our frame buffer dimensions.
196 for (int i=0;i<aSrcWidth;i++)
198 for (int j=0;j<aSrcHeight;j++)
200 iFrameNext->SetBitValue((aTargetX+i)*HeightInPixels()+aTargetY+j,aBitmap[+i*aSrcHeight+j]);
207 Clear our client side back buffer.
208 Call to SwapBuffers must follow to actually clear the display.
210 void GP1212A02A::Clear()
212 //memset(iNextFrame->Ptr(),0x00,FrameBufferSizeInBytes());
215 iFrameNext->ClearAll();
225 Must be followed by a SwapBuffers call.
227 void GP1212A02A::Fill()
233 Set all pixels on our screen to the desired value.
234 This operation is performed off screen to avoid tearing.
235 @param 8 pixels pattern
237 void GP1212A02A::SetAllPixels(unsigned char aPattern)
239 //With a single buffer
240 //unsigned char screen[2048]; //One screen worth of pixels
241 //memset(screen,0xFF,sizeof(screen));
242 //SetPixelBlock(0,0,63,sizeof(screen),screen);
247 memset(iFrameNext->Ptr(),aPattern,FrameBufferSizeInBytes());
251 //Using pattern SetPixelBlock variant.
262 [Code] 1BH,4AH,Pm,aL,aH,Ps,nL,nH,Pd...Pd
263 [Function] The BMP data is written in the DW(Display Window) or the Data memory.
264 Pm= DW or Data memory
267 Ps = Direction of writing
268 nL = number of BMP data length lower byte
269 nH = number of BMP data length upper byte
271 * If X direction is selected as Ps and data is written in the last address, the data in the last address is
272 overwritten with the remaining data.
273 [Definable area] Pm = 30H : DW
274 Pm = 31H: Data memory
275 0000H <= aL + aH * 100 <= 07FFH (DW)
276 0000H <= aL + aH * 100 <= 4FFFH (Data memory)
277 Ps = 30H: Y direction
278 Ps = 31H: X direction
279 0001H <= nL + nH * 100 <= 0100H(DW: X direction)
280 0001H <= nL + nH * 100 <= 0800H(DW: Y direction)
281 0001H <= nL + nH * 100 <= 0A00H(Data memory: X direction)
282 0001H <= nL + nH * 100 <= 5000H(Data memory: Y direction)
284 void GP1212A02A::BmpDataInput(TTarget aTarget, unsigned short aAddress, TDirection aDirection, unsigned short aSize, unsigned char* aPixels)
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]=0x4A; //Command ID
291 report[4]=aTarget; //Display Window or Data Memory
292 report[5]=(unsigned char)aAddress; //aL = DW lower byte
293 report[6]=aAddress>>8; //aH = DW upper byte
294 report[7]=aDirection; //Direction of writing: Y or X
295 report[8]=(unsigned char)aSize; //Size of pixel data in bytes (LSB)
296 report[9]=aSize>>8; //Size of pixel data in bytes (MSB)
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);
318 [Code] 1BH,5CH,44H,aL,aH
319 [Function] BMP data transfer from Data memory to DW.
320 Although source data is updated, data in BMP box is not updated. To reflect the update,
321 re-executing this command is necessary.
322 aL = Lower byte of address
323 aH = Upper byte of address
325 0000H <= aL + aH * 100 <= 4FFFH
327 void GP1212A02A::BmpBoxDataMemoryTransfer(unsigned short aAddress)
329 FutabaVfdReport report;
330 report[0]=0x00; //Report ID
331 report[1]=0x05; //Report length.
332 report[2]=0x1B; //Command ID
333 report[3]=0x5C; //Command ID
334 report[4]=0x44; //Command ID
335 report[5]=(unsigned char)aAddress; //aL = DM lower byte
336 report[6]=aAddress>>8; //aH = DM upper byte
341 Input BMP data in the BMP box
342 [Code] 1BH,5CH,5DH,nL,nH,Pd...Pd
343 [Function] BMP data is written the BMP box
344 * Number of definable data is due to BMP box size. If the data is over range, the over range data is
345 rewritten the final address.
346 nL = Lower byte of number of definition byte
347 nH = Upper byte of number of definition byte
349 [Definable area] Pn : BMP box size (Pw * Ph)
351 void GP1212A02A::BmpBoxDataInput(unsigned short aSize, unsigned char* aPixels)
353 FutabaVfdReport report;
354 report[0]=0x00; //Report ID
355 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
356 report[2]=0x1B; //Command ID
357 report[3]=0x5C; //Command ID
358 report[4]=0x5D; //Display Window or Data Memory
359 report[5]=(unsigned char)aSize; //Size of pixel data in bytes (LSB)
360 report[6]=aSize>>8; //Size of pixel data in bytes (MSB)
361 int sizeWritten=MIN(aSize,report.Size()-7);
362 memcpy(report.Buffer()+7, aPixels, sizeWritten);
365 int remainingSize=aSize;
366 //We need to keep on sending our pixel data until we are done
367 while (report[1]==64)
370 remainingSize-=sizeWritten;
371 report[0]=0x00; //Report ID
372 report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
373 sizeWritten=(report[1]==64?63:report[1]);
374 memcpy(report.Buffer()+2, aPixels+(aSize-remainingSize), sizeWritten);
380 Using this function is advised against as is causes tearing.
383 void GP1212A02A::SendClearCommand()
386 //Send Clear Display Command
387 FutabaVfdReport report;
388 report[0]=0x00; //Report ID
389 report[1]=0x04; //Report length
390 report[2]=0x1B; //Command ID
391 report[3]=0x4A; //Command ID
392 report[4]=0x43; //Command ID
393 report[5]=0x44; //Command ID
399 Provide Y coordinate of our off screen buffer.
401 unsigned char GP1212A02A::OffScreenY() const
403 //Overflowing is fine this is just what we want
404 return iDisplayPositionY+HeightInPixels();
408 Put our off screen buffer on screen.
409 On screen buffer goes off screen.
411 void GP1212A02A::SwapBuffers()
413 //Only perform buffer swapping if off screen mode is enabled
416 //Send pixel directly into BMP box
417 //BmpBoxDataInput(FrameBufferSizeInBytes(),iFrameNext->Ptr());
418 //Send pixel data directly into the display window
419 //BmpDataInput(ETargetDisplayWindow,0x0000,EDirectionY, FrameBufferSizeInBytes(),iFrameNext->Ptr());
420 //Send pixel data first to Data Memory then copy into the selected BMP box
421 //BmpDataInput(ETargetDataMemory,0x0000,EDirectionY, FrameBufferSizeInBytes(),iFrameNext->Ptr());
422 //BmpBoxDataMemoryTransfer(0x0000);
423 //Send pixel data first to Data Memory then copy into the selected BMP box, cycling through our Data Memory frmae
424 BmpDataInput(ETargetDataMemory,iNextFrameAddress,EDirectionY, FrameBufferSizeInBytes(),iFrameNext->Ptr());
425 BmpBoxDataMemoryTransfer(iNextFrameAddress);
426 iNextFrameAddress+=KFrameSizeInBytes;
427 if (iNextFrameAddress>KMaxDataMemoryAddress)
429 iNextFrameAddress=0x0000;
432 //Cycle through our frame buffers
433 //We keep track of previous frame which is in fact our device back buffer.
434 //We can then compare previous and next frame and send only the differences to our device.
435 //This mechanism allows us to reduce traffic over our USB bus thus improving our frame rate from 14 FPS to 30 FPS.
436 //Keep our previous frame pointer
437 BitArrayLow* previousFrame=iFramePrevious;
438 //Current frame becomes the previous one
439 iFramePrevious = iFrameCurrent;
440 //Next frame becomes the current one
441 iFrameCurrent = iFrameNext;
442 //Next frame is now our former previous
443 iFrameNext = previousFrame;
448 //Define the edge of our pixel block
449 //Pixel blocks of 32x32 seems to run almost as fast as full screen update in worse case scenarii.
450 //Though I wonder if in some situations 16 could be better. Make this an attribute at some point if need be.
451 const int KPixelBlockEdge = 32;
452 const int KPixelBlockSizeInBits = KPixelBlockEdge*KPixelBlockEdge;
453 const int KPixelBlockSizeInBytes = KPixelBlockSizeInBits/8;
457 Translate the given pixel coordinate according to our off screen mode.
459 void GP1212A02A::OffScreenTranslation(unsigned char& aX, unsigned char& aY)
463 aX+=WidthInPixels()-iDisplayPositionX;
464 aY+=HeightInPixels()-iDisplayPositionY;
471 void GP1212A02A::Request(TMiniDisplayRequest aRequest)
475 case EMiniDisplayRequestDeviceId:
478 case EMiniDisplayRequestFirmwareRevision:
479 RequestFirmwareRevision();
481 case EMiniDisplayRequestPowerSupplyStatus:
482 RequestPowerSupplyStatus();
493 void GP1212A02A::ResetBuffers()
495 //iNextFrame->ClearAll();
496 //memset(iFrameAlpha,0x00,sizeof(iFrameAlpha));
497 //memset(iFrameBeta,0x00,sizeof(iFrameBeta));
502 void GP1212A02A::RequestDeviceId()
509 [Code] 1BH,6AH,49H,44H
510 [Function] Send the ID code to the Host system. ID code is software version.
512 void GP1212A02A::RequestFirmwareRevision()
514 if (RequestPending())
516 //Abort silently for now
521 //Send Software Revision Read Command
522 FutabaVfdReport report;
523 report[0]=0x00; //Report ID
524 report[1]=0x04; //Report length
525 report[2]=0x1B; //Command ID
526 report[3]=0x6A; //Command ID
527 report[4]=0x49; //Command ID
528 report[5]=0x44; //Command ID
529 if (Write(report)==report.Size())
531 SetRequest(EMiniDisplayRequestFirmwareRevision);
538 void GP1212A02A::RequestPowerSupplyStatus()
545 This is for development purposes only.
546 Production application should stick to off-screen mode to avoid tearing.
548 void GP1212A02A::ToggleOffScreenMode()
550 SetOffScreenMode(!iOffScreenMode);
554 * @brief GP1212A02A::SetOffScreenMode
558 void GP1212A02A::SetOffScreenMode(bool aOn)
560 if (aOn==iOffScreenMode)
568 //Clean up our buffers upon switching modes
575 Tries to complete our current request if we have one pending.
577 TMiniDisplayRequest GP1212A02A::AttemptRequestCompletion()
579 if (!RequestPending())
581 return EMiniDisplayRequestNone;
584 int res=Read(iInputReport);
588 return EMiniDisplayRequestNone;
591 //Process our request
592 if (CurrentRequest()==EMiniDisplayRequestFirmwareRevision)
594 unsigned char* ptr=&iInputReport[2];
595 iInputReport[7]=0x00;
596 strcpy(iFirmwareRevision,(const char*)ptr);
599 TMiniDisplayRequest completed=CurrentRequest();
600 //Our request was completed
601 SetRequest(EMiniDisplayRequestNone);
608 Set our screen brightness.
609 @param The desired brightness level. Must be between MinBrightness and MaxBrightness.
611 void GP1212A02A::SetBrightness(int aBrightness)
613 if (aBrightness<MinBrightness()||aBrightness>MaxBrightness())
615 //Brightness out of range.
616 //Just ignore that request.
620 FutabaVfdReport report;
621 report[0]=0x00; //Report ID
622 report[1]=0x04; //Report size
623 report[2]=0x1B; //Command ID
624 report[3]=0x4A; //Command ID
625 report[4]=0x44; //Command ID
626 report[5]=0x30+aBrightness; //Brightness level
632 bool GP1212A02A::IsPowerOn()
639 char* GP1212A02A::DeviceId()
646 char* GP1212A02A::FirmwareRevision()
648 return iFirmwareRevision;
654 [Function]Control of the power supply for VFD
655 * If VFD power ON or OFF, at interval of 10s or more.
656 * When the VFD power off, VFD display is turn off, but the module can receive a data and
658 Ps = VFD Power control
660 Ps = 30H : VFD Power OFF
661 Ps = 31H : VFD Power ON (Default)
663 void GP1212A02A::SendCommandPower(TPowerStatus aPowerStatus)
665 FutabaVfdReport report;
666 report[0]=0x00; //Report ID
667 report[1]=0x04; //Report size
668 report[2]=0x1B; //Command ID
669 report[3]=0x4A; //Command ID
670 report[4]=0x42; //Command ID
671 report[5]=aPowerStatus; //ON or OFF
677 void GP1212A02A::TurnPowerOn()
679 SendCommandPower(EPowerOn);
684 void GP1212A02A::TurnPowerOff()
686 SendCommandPower(EPowerOff);