First draft implementation of Futaba MDM166AA.
Only clock and brightness working for now.
5 #include "FutabaMDM166AA.h"
12 static void sleep(unsigned int mseconds)
14 clock_t goal = mseconds + clock();
15 while (goal > clock());
23 iDisplayPositionX(0),iDisplayPositionY(0),
25 iUseFrameDifferencing(true),
32 iNeedFullFrameUpdate(0),
36 iFirmwareRevision[0]=0;
57 iNeedFullFrameUpdate=0;
64 int success = HidDevice::Open(KTargaVendorId,KFutabaProductIdMDM166AA,NULL);
67 //Allocate both frames
70 iFrameAlpha=new BitArrayLow(KMDM166AAFrameBufferPixelCount);
74 iFrameBeta=new BitArrayLow(KMDM166AAFrameBufferPixelCount);
78 iFrameGamma=new BitArrayLow(KMDM166AAFrameBufferPixelCount);
80 iFrameNext=iFrameAlpha;
81 iFrameCurrent=iFrameBeta;
82 iFramePrevious=iFrameGamma;
85 //To make sure it is synced properly
86 iNeedFullFrameUpdate=0;
100 Display RAM filled with 00H.
101 Address Counter is set by 00H.
102 Dimming is set to 50%.
104 void MDM166AA::SendCommandReset()
106 FutabaVfdReport report;
107 report[0]=0x00; //Report ID
108 report[1]=0x01; //Report length.
109 report[2]=0x1F; //Command ID
111 //Wait until reset is done. Is that needed?
117 Set Address Counter (AC) values: 1BH + 60H + xxH
119 AC value represents the start address for graphic data.
120 There are 192 bytes as display RAM. It can be set on anywhere even if AC value is not visible area.
121 The default value is 00H.
123 When clock is displayed, AC value is set 00H.
125 void MDM166AA::SendCommandSetAddressCounter(unsigned char aAddressCounter)
127 FutabaVfdReport report;
128 report[0]=0x00; //Report ID
129 report[1]=0x03; //Report length.
130 report[2]=0x1B; //Command ID
131 report[3]=0x60; //Command ID
132 report[4]=aAddressCounter;
139 void MDM166AA::SetPixel(unsigned char aX, unsigned char aY, unsigned int aPixel)
142 //int byteOffset=(aX*HeightInPixels()+aY)/8;
143 //int bitOffset=(aX*HeightInPixels()+aY)%8;
144 //iNextFrame[byteOffset] |= ( (aOn?0x01:0x00) << bitOffset );
146 //Pixel is on if any of the non-alpha component is not null
147 bool on = (aPixel&0x00FFFFFF)!=0x00000000;
153 iFrameNext->SetBit(aX*HeightInPixels()+aY);
157 iFrameNext->ClearBit(aX*HeightInPixels()+aY);
162 //Just specify a one pixel block
170 void MDM166AA::BitBlit(const BitArray& aBitmap, int aSrcWidth, int aSrcHeight, int aTargetX, int aTargetY) const
172 //TODO: amend loop values so that we don't keep on looping past our frame buffer dimensions.
173 for (int i=0;i<aSrcWidth;i++)
175 for (int j=0;j<aSrcHeight;j++)
177 iFrameNext->SetBitValue((aTargetX+i)*HeightInPixels()+aTargetY+j,aBitmap[+i*aSrcHeight+j]);
184 Clear our client side back buffer.
185 Call to SwapBuffers must follow to actually clear the display.
187 void MDM166AA::Clear()
189 //That one also clear the symbols
191 //TODO: Consider just clearing the pixels instead
196 Must be followed by a SwapBuffers call.
198 void MDM166AA::Fill()
204 Set all pixels on our screen to the desired value.
205 This operation is performed off screen to avoid tearing.
206 @param 8 pixels pattern
208 void MDM166AA::SetAllPixels(unsigned char aPattern)
210 //With a single buffer
211 //unsigned char screen[2048]; //One screen worth of pixels
212 //memset(screen,0xFF,sizeof(screen));
213 //SetPixelBlock(0,0,63,sizeof(screen),screen);
218 memset(iFrameNext->Ptr(),aPattern,FrameBufferSizeInBytes());
222 //Using pattern SetPixelBlock variant.
234 Whole display RAM areas including invisible area are filled with 00H data.
236 SL: Though there is no invisible area with that device.
238 void MDM166AA::SendCommandClear()
240 //Send Clear Display Command
241 FutabaVfdReport report;
242 report[0]=0x00; //Report ID
243 report[1]=0x02; //Report length
244 report[2]=0x1B; //Command ID
245 report[3]=0x50; //Command ID
251 Provide Y coordinate of our off screen buffer.
253 unsigned char MDM166AA::OffScreenY() const
255 //Overflowing is fine this is just what we want
256 return iDisplayPositionY+HeightInPixels();
260 Put our off screen buffer on screen.
261 On screen buffer goes off screen.
263 void MDM166AA::SwapBuffers()
265 //Only perform buffer swapping if off screen mode is enabled
268 //Send pixel directly into BMP box
269 //BmpBoxDataInput(FrameBufferSizeInBytes(),iFrameNext->Ptr());
270 //Send pixel data directly into the display window
271 //BmpDataInput(ETargetDisplayWindow,0x0000,EDirectionY, FrameBufferSizeInBytes(),iFrameNext->Ptr());
272 //Send pixel data first to Data Memory then copy into the selected BMP box
273 //BmpDataInput(ETargetDataMemory,0x0000,EDirectionY, FrameBufferSizeInBytes(),iFrameNext->Ptr());
274 //BmpBoxDataMemoryTransfer(0x0000);
275 //Send pixel data first to Data Memory then copy into the selected BMP box, cycling through our Data Memory frmae
276 //BmpDataInput(ETargetDataMemory,iNextFrameAddress,EDirectionY, FrameBufferSizeInBytes(),iFrameNext->Ptr());
277 //BmpBoxDataMemoryTransfer(iNextFrameAddress);
280 //Cycle through our frame buffers
281 //We keep track of previous frame which is in fact our device back buffer.
282 //We can then compare previous and next frame and send only the differences to our device.
283 //This mechanism allows us to reduce traffic over our USB bus thus improving our frame rate from 14 FPS to 30 FPS.
284 //Keep our previous frame pointer
285 BitArrayLow* previousFrame=iFramePrevious;
286 //Current frame becomes the previous one
287 iFramePrevious = iFrameCurrent;
288 //Next frame becomes the current one
289 iFrameCurrent = iFrameNext;
290 //Next frame is now our former previous
291 iFrameNext = previousFrame;
297 Set the defined pixel block to the given value.
298 @param X coordinate of our pixel block starting point.
299 @param Y coordinate of our pixel block starting point.
300 @param The height of our pixel block.
301 @param The size of our pixel data. Number of pixels divided by 8.
302 @param Pointer to our pixel data.
304 void MDM166AA::SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char* aPixels)
306 //TODO: Assuming 0,0 for now, do the math later
307 SendCommandSetAddressCounter(0);
309 const int KMaxPixelBytes=48;
311 FutabaVfdReport report;
312 report[0]=0x00; //Report ID
313 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
314 report[2]=0x1B; //Command ID
315 report[3]=0x70; //Command ID
317 report[4]=MAX(KMaxPixelBytes,aSize); //Size of pixel data in bytes
318 int sizeWritten=MIN(aSize,report.Size()-10);
319 memcpy(report.Buffer()+10, aPixels, sizeWritten);
322 int remainingSize=aSize;
323 //We need to keep on sending our pixel data until we are done
324 while (report[1]==64)
327 remainingSize-=sizeWritten;
328 report[0]=0x00; //Report ID
329 report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
330 sizeWritten=(report[1]==64?63:report[1]);
331 memcpy(report.Buffer()+2, aPixels+(aSize-remainingSize), sizeWritten);
338 //Define the edge of our pixel block
339 //Pixel blocks of 32x32 seems to run almost as fast as full screen update in worse case scenarii.
340 //Though I wonder if in some situations 16 could be better. Make this an attribute at some point if need be.
341 const int KPixelBlockEdge = 32;
342 const int KPixelBlockSizeInBits = KPixelBlockEdge*KPixelBlockEdge;
343 const int KPixelBlockSizeInBytes = KPixelBlockSizeInBits/8;
347 Translate the given pixel coordinate according to our off screen mode.
349 void MDM166AA::OffScreenTranslation(unsigned char& aX, unsigned char& aY)
353 aX+=WidthInPixels()-iDisplayPositionX;
354 aY+=HeightInPixels()-iDisplayPositionY;
361 void MDM166AA::Request(TMiniDisplayRequest aRequest)
365 case EMiniDisplayRequestDeviceId:
368 case EMiniDisplayRequestFirmwareRevision:
369 RequestFirmwareRevision();
371 case EMiniDisplayRequestPowerSupplyStatus:
372 RequestPowerSupplyStatus();
383 void MDM166AA::ResetBuffers()
385 //iNextFrame->ClearAll();
386 //memset(iFrameAlpha,0x00,sizeof(iFrameAlpha));
387 //memset(iFrameBeta,0x00,sizeof(iFrameBeta));
392 void MDM166AA::RequestDeviceId()
399 [Code] 1BH,6AH,49H,44H
400 [Function] Send the ID code to the Host system. ID code is software version.
402 void MDM166AA::RequestFirmwareRevision()
404 if (RequestPending())
406 //Abort silently for now
411 //Send Software Revision Read Command
412 FutabaVfdReport report;
413 report[0]=0x00; //Report ID
414 report[1]=0x04; //Report length
415 report[2]=0x1B; //Command ID
416 report[3]=0x6A; //Command ID
417 report[4]=0x49; //Command ID
418 report[5]=0x44; //Command ID
419 if (Write(report)==report.Size())
421 SetRequest(EMiniDisplayRequestFirmwareRevision);
428 void MDM166AA::RequestPowerSupplyStatus()
435 This is for development purposes only.
436 Production application should stick to off-screen mode to avoid tearing.
438 void MDM166AA::ToggleOffScreenMode()
440 SetOffScreenMode(!iOffScreenMode);
444 * @brief MDM166AA::SetOffScreenMode
448 void MDM166AA::SetOffScreenMode(bool aOn)
450 if (aOn==iOffScreenMode)
458 //Clean up our buffers upon switching modes
465 Tries to complete our current request if we have one pending.
467 TMiniDisplayRequest MDM166AA::AttemptRequestCompletion()
469 if (!RequestPending())
471 return EMiniDisplayRequestNone;
474 int res=Read(iInputReport);
478 return EMiniDisplayRequestNone;
481 //Process our request
482 if (CurrentRequest()==EMiniDisplayRequestFirmwareRevision)
484 unsigned char* ptr=&iInputReport[2];
485 iInputReport[7]=0x00;
486 strcpy(iFirmwareRevision,(const char*)ptr);
489 TMiniDisplayRequest completed=CurrentRequest();
490 //Our request was completed
491 SetRequest(EMiniDisplayRequestNone);
498 Set our screen brightness.
499 @param The desired brightness level. Must be between MinBrightness and MaxBrightness.
501 void MDM166AA::SetBrightness(int aBrightness)
503 if (aBrightness<MinBrightness()||aBrightness>MaxBrightness())
505 //Brightness out of range.
506 //Just ignore that request.
510 FutabaVfdReport report;
511 report[0]=0x00; //Report ID
512 report[1]=0x03; //Report size
513 report[2]=0x1B; //Command ID
514 report[3]=0x40; //Command ID
515 report[4]=aBrightness; //Brightness level
521 bool MDM166AA::IsPowerOn()
528 char* MDM166AA::DeviceId()
535 char* MDM166AA::FirmwareRevision()
537 return iFirmwareRevision;
542 void MDM166AA::ShowClock()
544 SendCommandClockDisplay(EClockLarge,EClock24);
550 void MDM166AA::HideClock()
560 [Function]Setting the clock data. The setting data is cleared, if the Reset command is input or power is turned off.
564 void MDM166AA::SendCommandClockSetting(unsigned char aHour, unsigned char aMinute)
566 FutabaVfdReport report;
567 report[0]=0x00; //Report ID
568 report[1]=0x04; //Report size
569 report[2]=0x1B; //Command ID
570 report[3]=0x00; //Command ID
572 //Minutes and Hours needs to be in hexadecimal view
573 //To get 21:59 you need to pass in 0x21:0x59
574 //Weirdest format ever, I know
575 report[4]=(aMinute/10*16)+aMinute%10;
576 report[5]=(aHour/10*16)+aHour%10;
583 Set display clock settings according to local system time.
584 This needs to be redone whenever we open or turn on our display.
586 void MDM166AA::SetClockSetting()
589 struct tm * timeinfo;
592 timeinfo = localtime ( &rawtime );
594 SendCommandClockSetting(timeinfo->tm_hour,timeinfo->tm_min);
600 [Code] 1BH,Ps,aL,aH,Pf
601 [Function] Clock is displayed small or big.
603 void MDM166AA::SendCommandClockDisplay(TClockSize aClockSize, TClockFormat aClockFormat)
605 FutabaVfdReport report;
606 report[0]=0x00; //Report ID
607 report[1]=0x03; //Report size
608 report[2]=0x1B; //Command ID
609 report[3]=aClockSize; //
610 report[4]=aClockFormat; //