First draft implementation of Futaba MDM166AA.
Only clock and brightness working for now.
1.1 --- a/CMakeLists.txt Wed Feb 04 17:45:46 2015 +0100
1.2 +++ b/CMakeLists.txt Wed Feb 04 21:47:17 2015 +0100
1.3 @@ -15,6 +15,7 @@
1.4 FutabaGP1212.cpp
1.5 FutabaGP1212A01.cpp
1.6 FutabaGP1212A02.cpp
1.7 + FutabaMDM166AA.cpp
1.8 HidDevice.cpp
1.9 MiniDisplay.cpp
1.10 ../../GitHub/hidapi/windows/hid.c)
1.11 @@ -26,6 +27,7 @@
1.12 FutabaGP1212.h
1.13 FutabaGP1212A01.h
1.14 FutabaGP1212A02.h
1.15 + FutabaMDM166AA.h
1.16 HidDevice.h
1.17 HidReport.h
1.18 MiniDisplay.h
2.1 --- a/FutabaGP1212A02.cpp Wed Feb 04 17:45:46 2015 +0100
2.2 +++ b/FutabaGP1212A02.cpp Wed Feb 04 21:47:17 2015 +0100
2.3 @@ -11,7 +11,7 @@
2.4 const unsigned short KFrameSizeInBytes = 0x800;
2.5
2.6
2.7 -void sleep(unsigned int mseconds)
2.8 +static void sleep(unsigned int mseconds)
2.9 {
2.10 clock_t goal = mseconds + clock();
2.11 while (goal > clock());
3.1 --- a/FutabaGP1212A02.h Wed Feb 04 17:45:46 2015 +0100
3.2 +++ b/FutabaGP1212A02.h Wed Feb 04 21:47:17 2015 +0100
3.3 @@ -6,14 +6,17 @@
3.4 #define FUTABA_GP1212A02_H
3.5
3.6 #include "FutabaGP1212.h"
3.7 -
3.8 -#include "FutabaGP1212.h"
3.9 #include "FutabaVfd.h"
3.10
3.11 /**
3.12 -GP1212A01A is a graphic display module using a FUTABA 256x64dots VFD.
3.13 -The module do not include character ROM, the customer will compile the character
3.14 -by themselves (from main system).
3.15 +GP1212A02A is a graphic display module using a FUTABA 256x64dots VFD.
3.16 +The module will support the interface of I2C, RS-232C and USB2.0 communications.
3.17 +The module include flash ROM (4Mbyte), the customer will definable the BMP data and download
3.18 +character.
3.19 +It realizes displaying a Japanese font (refer to Table-24) and BMP by I2C, RS-232C or USB2.0
3.20 +communications. Other font tables (ex. Chinese, Korean, European and custom font) can be appended to
3.21 +flash ROM.
3.22 +Since a DC/DC converter is included, 5V power source is required to operate the module.
3.23 */
3.24 class GP1212A02A : public GP1212XXXX
3.25 {
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/FutabaMDM166AA.cpp Wed Feb 04 21:47:17 2015 +0100
4.3 @@ -0,0 +1,614 @@
4.4 +//
4.5 +//
4.6 +//
4.7 +
4.8 +#include "FutabaMDM166AA.h"
4.9 +
4.10 +#include <stdio.h>
4.11 +#include <time.h>
4.12 +
4.13 +
4.14 +
4.15 +static void sleep(unsigned int mseconds)
4.16 + {
4.17 + clock_t goal = mseconds + clock();
4.18 + while (goal > clock());
4.19 + }
4.20 +
4.21 +//
4.22 +// class MDM166AA
4.23 +//
4.24 +
4.25 +MDM166AA::MDM166AA():
4.26 + iDisplayPositionX(0),iDisplayPositionY(0),
4.27 + iOffScreenMode(true),
4.28 + iUseFrameDifferencing(true),
4.29 + iFrameNext(NULL),
4.30 + iFrameCurrent(NULL),
4.31 + iFramePrevious(NULL),
4.32 + iFrameAlpha(NULL),
4.33 + iFrameBeta(NULL),
4.34 + iFrameGamma(NULL),
4.35 + iNeedFullFrameUpdate(0),
4.36 + iPowerOn(false)
4.37 + {
4.38 + iDeviceId[0]=0;
4.39 + iFirmwareRevision[0]=0;
4.40 + //ResetBuffers();
4.41 + }
4.42 +
4.43 +/**
4.44 +*/
4.45 +MDM166AA::~MDM166AA()
4.46 + {
4.47 + delete iFrameAlpha;
4.48 + iFrameAlpha=NULL;
4.49 + //
4.50 + delete iFrameBeta;
4.51 + iFrameBeta=NULL;
4.52 + //
4.53 + delete iFrameGamma;
4.54 + iFrameGamma=NULL;
4.55 + //
4.56 + iFrameNext=NULL;
4.57 + iFrameCurrent=NULL;
4.58 + iFramePrevious=NULL;
4.59 + //
4.60 + iNeedFullFrameUpdate=0;
4.61 + }
4.62 +
4.63 +/**
4.64 +*/
4.65 +int MDM166AA::Open()
4.66 + {
4.67 + int success = HidDevice::Open(KTargaVendorId,KFutabaProductIdMDM166AA,NULL);
4.68 + if (success)
4.69 + {
4.70 + //Allocate both frames
4.71 + delete iFrameAlpha;
4.72 + iFrameAlpha=NULL;
4.73 + iFrameAlpha=new BitArrayLow(KMDM166AAFrameBufferPixelCount);
4.74 + //
4.75 + delete iFrameBeta;
4.76 + iFrameBeta=NULL;
4.77 + iFrameBeta=new BitArrayLow(KMDM166AAFrameBufferPixelCount);
4.78 + //
4.79 + delete iFrameGamma;
4.80 + iFrameGamma=NULL;
4.81 + iFrameGamma=new BitArrayLow(KMDM166AAFrameBufferPixelCount);
4.82 + //
4.83 + iFrameNext=iFrameAlpha;
4.84 + iFrameCurrent=iFrameBeta;
4.85 + iFramePrevious=iFrameGamma;
4.86 +
4.87 +
4.88 + //To make sure it is synced properly
4.89 + iNeedFullFrameUpdate=0;
4.90 + //
4.91 + SetNonBlocking(1);
4.92 + //
4.93 + SendCommandClear();
4.94 + //
4.95 + SetClockSetting();
4.96 +
4.97 + }
4.98 + return success;
4.99 + }
4.100 +
4.101 +
4.102 +/**
4.103 +Display RAM filled with 00H.
4.104 +Address Counter is set by 00H.
4.105 +Dimming is set to 50%.
4.106 +*/
4.107 +void MDM166AA::SendCommandReset()
4.108 + {
4.109 + FutabaVfdReport report;
4.110 + report[0]=0x00; //Report ID
4.111 + report[1]=0x01; //Report length.
4.112 + report[2]=0x1F; //Command ID
4.113 + Write(report);
4.114 + //Wait until reset is done. Is that needed?
4.115 + //sleep(2000);
4.116 + }
4.117 +
4.118 +
4.119 +/**
4.120 +Set Address Counter (AC) values: 1BH + 60H + xxH
4.121 +xxH: 00 ~ BFH
4.122 +AC value represents the start address for graphic data.
4.123 +There are 192 bytes as display RAM. It can be set on anywhere even if AC value is not visible area.
4.124 +The default value is 00H.
4.125 +Default: 00H
4.126 +When clock is displayed, AC value is set 00H.
4.127 +*/
4.128 +void MDM166AA::SendCommandSetAddressCounter(unsigned char aAddressCounter)
4.129 + {
4.130 + FutabaVfdReport report;
4.131 + report[0]=0x00; //Report ID
4.132 + report[1]=0x03; //Report length.
4.133 + report[2]=0x1B; //Command ID
4.134 + report[3]=0x60; //Command ID
4.135 + report[4]=aAddressCounter;
4.136 + Write(report);
4.137 + }
4.138 +
4.139 +
4.140 +/**
4.141 +*/
4.142 +void MDM166AA::SetPixel(unsigned char aX, unsigned char aY, unsigned int aPixel)
4.143 + {
4.144 + //
4.145 + //int byteOffset=(aX*HeightInPixels()+aY)/8;
4.146 + //int bitOffset=(aX*HeightInPixels()+aY)%8;
4.147 + //iNextFrame[byteOffset] |= ( (aOn?0x01:0x00) << bitOffset );
4.148 +
4.149 + //Pixel is on if any of the non-alpha component is not null
4.150 + bool on = (aPixel&0x00FFFFFF)!=0x00000000;
4.151 +
4.152 + if (iOffScreenMode)
4.153 + {
4.154 + if (on)
4.155 + {
4.156 + iFrameNext->SetBit(aX*HeightInPixels()+aY);
4.157 + }
4.158 + else
4.159 + {
4.160 + iFrameNext->ClearBit(aX*HeightInPixels()+aY);
4.161 + }
4.162 + }
4.163 + else
4.164 + {
4.165 + //Just specify a one pixel block
4.166 + //TODO
4.167 + }
4.168 + }
4.169 +
4.170 +/**
4.171 +*/
4.172 +/*
4.173 +void MDM166AA::BitBlit(const BitArray& aBitmap, int aSrcWidth, int aSrcHeight, int aTargetX, int aTargetY) const
4.174 + {
4.175 + //TODO: amend loop values so that we don't keep on looping past our frame buffer dimensions.
4.176 + for (int i=0;i<aSrcWidth;i++)
4.177 + {
4.178 + for (int j=0;j<aSrcHeight;j++)
4.179 + {
4.180 + iFrameNext->SetBitValue((aTargetX+i)*HeightInPixels()+aTargetY+j,aBitmap[+i*aSrcHeight+j]);
4.181 + }
4.182 + }
4.183 + }
4.184 +*/
4.185 +
4.186 +/**
4.187 +Clear our client side back buffer.
4.188 +Call to SwapBuffers must follow to actually clear the display.
4.189 +*/
4.190 +void MDM166AA::Clear()
4.191 + {
4.192 + //That one also clear the symbols
4.193 + SendCommandClear();
4.194 + //TODO: Consider just clearing the pixels instead
4.195 + }
4.196 +
4.197 +/**
4.198 +Turn on all pixels.
4.199 +Must be followed by a SwapBuffers call.
4.200 +*/
4.201 +void MDM166AA::Fill()
4.202 + {
4.203 + SetAllPixels(0xFF);
4.204 + }
4.205 +
4.206 +/**
4.207 +Set all pixels on our screen to the desired value.
4.208 +This operation is performed off screen to avoid tearing.
4.209 +@param 8 pixels pattern
4.210 +*/
4.211 +void MDM166AA::SetAllPixels(unsigned char aPattern)
4.212 + {
4.213 + //With a single buffer
4.214 + //unsigned char screen[2048]; //One screen worth of pixels
4.215 + //memset(screen,0xFF,sizeof(screen));
4.216 + //SetPixelBlock(0,0,63,sizeof(screen),screen);
4.217 +
4.218 +
4.219 + if (iOffScreenMode)
4.220 + {
4.221 + memset(iFrameNext->Ptr(),aPattern,FrameBufferSizeInBytes());
4.222 + }
4.223 + else
4.224 + {
4.225 + //Using pattern SetPixelBlock variant.
4.226 + //TODO
4.227 + }
4.228 + //
4.229 + }
4.230 +
4.231 +
4.232 +
4.233 +
4.234 +
4.235 +
4.236 +/**
4.237 +Whole display RAM areas including invisible area are filled with 00H data.
4.238 +(Include the symbol)
4.239 +SL: Though there is no invisible area with that device.
4.240 +*/
4.241 +void MDM166AA::SendCommandClear()
4.242 + {
4.243 + //Send Clear Display Command
4.244 + FutabaVfdReport report;
4.245 + report[0]=0x00; //Report ID
4.246 + report[1]=0x02; //Report length
4.247 + report[2]=0x1B; //Command ID
4.248 + report[3]=0x50; //Command ID
4.249 + Write(report);
4.250 + }
4.251 +
4.252 +
4.253 +/**
4.254 +Provide Y coordinate of our off screen buffer.
4.255 +*/
4.256 +unsigned char MDM166AA::OffScreenY() const
4.257 + {
4.258 + //Overflowing is fine this is just what we want
4.259 + return iDisplayPositionY+HeightInPixels();
4.260 + }
4.261 +
4.262 +/**
4.263 +Put our off screen buffer on screen.
4.264 +On screen buffer goes off screen.
4.265 +*/
4.266 +void MDM166AA::SwapBuffers()
4.267 + {
4.268 + //Only perform buffer swapping if off screen mode is enabled
4.269 + if (OffScreenMode())
4.270 + {
4.271 + //Send pixel directly into BMP box
4.272 + //BmpBoxDataInput(FrameBufferSizeInBytes(),iFrameNext->Ptr());
4.273 + //Send pixel data directly into the display window
4.274 + //BmpDataInput(ETargetDisplayWindow,0x0000,EDirectionY, FrameBufferSizeInBytes(),iFrameNext->Ptr());
4.275 + //Send pixel data first to Data Memory then copy into the selected BMP box
4.276 + //BmpDataInput(ETargetDataMemory,0x0000,EDirectionY, FrameBufferSizeInBytes(),iFrameNext->Ptr());
4.277 + //BmpBoxDataMemoryTransfer(0x0000);
4.278 + //Send pixel data first to Data Memory then copy into the selected BMP box, cycling through our Data Memory frmae
4.279 + //BmpDataInput(ETargetDataMemory,iNextFrameAddress,EDirectionY, FrameBufferSizeInBytes(),iFrameNext->Ptr());
4.280 + //BmpBoxDataMemoryTransfer(iNextFrameAddress);
4.281 +
4.282 +
4.283 + //Cycle through our frame buffers
4.284 + //We keep track of previous frame which is in fact our device back buffer.
4.285 + //We can then compare previous and next frame and send only the differences to our device.
4.286 + //This mechanism allows us to reduce traffic over our USB bus thus improving our frame rate from 14 FPS to 30 FPS.
4.287 + //Keep our previous frame pointer
4.288 + BitArrayLow* previousFrame=iFramePrevious;
4.289 + //Current frame becomes the previous one
4.290 + iFramePrevious = iFrameCurrent;
4.291 + //Next frame becomes the current one
4.292 + iFrameCurrent = iFrameNext;
4.293 + //Next frame is now our former previous
4.294 + iFrameNext = previousFrame;
4.295 + }
4.296 + }
4.297 +
4.298 +
4.299 +/**
4.300 +Set the defined pixel block to the given value.
4.301 +@param X coordinate of our pixel block starting point.
4.302 +@param Y coordinate of our pixel block starting point.
4.303 +@param The height of our pixel block.
4.304 +@param The size of our pixel data. Number of pixels divided by 8.
4.305 +@param Pointer to our pixel data.
4.306 +*/
4.307 +void MDM166AA::SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char* aPixels)
4.308 + {
4.309 + //TODO: Assuming 0,0 for now, do the math later
4.310 + SendCommandSetAddressCounter(0);
4.311 +
4.312 + const int KMaxPixelBytes=48;
4.313 +
4.314 + FutabaVfdReport report;
4.315 + report[0]=0x00; //Report ID
4.316 + 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
4.317 + report[2]=0x1B; //Command ID
4.318 + report[3]=0x70; //Command ID
4.319 + //TODO: All rubbish
4.320 + report[4]=MAX(KMaxPixelBytes,aSize); //Size of pixel data in bytes
4.321 + int sizeWritten=MIN(aSize,report.Size()-10);
4.322 + memcpy(report.Buffer()+10, aPixels, sizeWritten);
4.323 + Write(report);
4.324 +
4.325 + int remainingSize=aSize;
4.326 + //We need to keep on sending our pixel data until we are done
4.327 + while (report[1]==64)
4.328 + {
4.329 + report.Reset();
4.330 + remainingSize-=sizeWritten;
4.331 + report[0]=0x00; //Report ID
4.332 + report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
4.333 + sizeWritten=(report[1]==64?63:report[1]);
4.334 + memcpy(report.Buffer()+2, aPixels+(aSize-remainingSize), sizeWritten);
4.335 + Write(report);
4.336 + }
4.337 + }
4.338 +
4.339 +
4.340 +
4.341 +//Define the edge of our pixel block
4.342 +//Pixel blocks of 32x32 seems to run almost as fast as full screen update in worse case scenarii.
4.343 +//Though I wonder if in some situations 16 could be better. Make this an attribute at some point if need be.
4.344 +const int KPixelBlockEdge = 32;
4.345 +const int KPixelBlockSizeInBits = KPixelBlockEdge*KPixelBlockEdge;
4.346 +const int KPixelBlockSizeInBytes = KPixelBlockSizeInBits/8;
4.347 +
4.348 +
4.349 +/**
4.350 +Translate the given pixel coordinate according to our off screen mode.
4.351 +*/
4.352 +void MDM166AA::OffScreenTranslation(unsigned char& aX, unsigned char& aY)
4.353 + {
4.354 + if (OffScreenMode())
4.355 + {
4.356 + aX+=WidthInPixels()-iDisplayPositionX;
4.357 + aY+=HeightInPixels()-iDisplayPositionY;
4.358 + }
4.359 + }
4.360 +
4.361 +
4.362 +/**
4.363 +*/
4.364 +void MDM166AA::Request(TMiniDisplayRequest aRequest)
4.365 + {
4.366 + switch (aRequest)
4.367 + {
4.368 + case EMiniDisplayRequestDeviceId:
4.369 + RequestDeviceId();
4.370 + break;
4.371 + case EMiniDisplayRequestFirmwareRevision:
4.372 + RequestFirmwareRevision();
4.373 + break;
4.374 + case EMiniDisplayRequestPowerSupplyStatus:
4.375 + RequestPowerSupplyStatus();
4.376 + break;
4.377 + default:
4.378 + //Not supported
4.379 + break;
4.380 + };
4.381 + }
4.382 +
4.383 +
4.384 +/**
4.385 +*/
4.386 +void MDM166AA::ResetBuffers()
4.387 + {
4.388 + //iNextFrame->ClearAll();
4.389 + //memset(iFrameAlpha,0x00,sizeof(iFrameAlpha));
4.390 + //memset(iFrameBeta,0x00,sizeof(iFrameBeta));
4.391 + }
4.392 +
4.393 +/**
4.394 +*/
4.395 +void MDM166AA::RequestDeviceId()
4.396 + {
4.397 + //Not supported
4.398 + }
4.399 +
4.400 +/**
4.401 +ID code
4.402 +[Code] 1BH,6AH,49H,44H
4.403 +[Function] Send the ID code to the Host system. ID code is software version.
4.404 +*/
4.405 +void MDM166AA::RequestFirmwareRevision()
4.406 + {
4.407 + if (RequestPending())
4.408 + {
4.409 + //Abort silently for now
4.410 + return;
4.411 + }
4.412 +
4.413 + //1BH,6AH,49H,44H
4.414 + //Send Software Revision Read Command
4.415 + FutabaVfdReport report;
4.416 + report[0]=0x00; //Report ID
4.417 + report[1]=0x04; //Report length
4.418 + report[2]=0x1B; //Command ID
4.419 + report[3]=0x6A; //Command ID
4.420 + report[4]=0x49; //Command ID
4.421 + report[5]=0x44; //Command ID
4.422 + if (Write(report)==report.Size())
4.423 + {
4.424 + SetRequest(EMiniDisplayRequestFirmwareRevision);
4.425 + }
4.426 +
4.427 + }
4.428 +
4.429 +/**
4.430 +*/
4.431 +void MDM166AA::RequestPowerSupplyStatus()
4.432 + {
4.433 + //Not supported
4.434 + }
4.435 +
4.436 +
4.437 +/**
4.438 +This is for development purposes only.
4.439 +Production application should stick to off-screen mode to avoid tearing.
4.440 +*/
4.441 +void MDM166AA::ToggleOffScreenMode()
4.442 + {
4.443 + SetOffScreenMode(!iOffScreenMode);
4.444 + }
4.445 +
4.446 +/**
4.447 + * @brief MDM166AA::SetOffScreenMode
4.448 + * @param aOn
4.449 + * @return
4.450 + */
4.451 +void MDM166AA::SetOffScreenMode(bool aOn)
4.452 + {
4.453 + if (aOn==iOffScreenMode)
4.454 + {
4.455 + //Nothing to do here
4.456 + return;
4.457 + }
4.458 +
4.459 + iOffScreenMode=aOn;
4.460 +
4.461 + //Clean up our buffers upon switching modes
4.462 + Clear();
4.463 + SwapBuffers();
4.464 + Clear();
4.465 + }
4.466 +
4.467 +/**
4.468 +Tries to complete our current request if we have one pending.
4.469 + */
4.470 +TMiniDisplayRequest MDM166AA::AttemptRequestCompletion()
4.471 + {
4.472 + if (!RequestPending())
4.473 + {
4.474 + return EMiniDisplayRequestNone;
4.475 + }
4.476 +
4.477 + int res=Read(iInputReport);
4.478 +
4.479 + if (!res)
4.480 + {
4.481 + return EMiniDisplayRequestNone;
4.482 + }
4.483 +
4.484 + //Process our request
4.485 + if (CurrentRequest()==EMiniDisplayRequestFirmwareRevision)
4.486 + {
4.487 + unsigned char* ptr=&iInputReport[2];
4.488 + iInputReport[7]=0x00;
4.489 + strcpy(iFirmwareRevision,(const char*)ptr);
4.490 + }
4.491 +
4.492 + TMiniDisplayRequest completed=CurrentRequest();
4.493 + //Our request was completed
4.494 + SetRequest(EMiniDisplayRequestNone);
4.495 +
4.496 + return completed;
4.497 + }
4.498 +
4.499 +
4.500 +/**
4.501 +Set our screen brightness.
4.502 +@param The desired brightness level. Must be between MinBrightness and MaxBrightness.
4.503 +*/
4.504 +void MDM166AA::SetBrightness(int aBrightness)
4.505 + {
4.506 + if (aBrightness<MinBrightness()||aBrightness>MaxBrightness())
4.507 + {
4.508 + //Brightness out of range.
4.509 + //Just ignore that request.
4.510 + return;
4.511 + }
4.512 +
4.513 + FutabaVfdReport report;
4.514 + report[0]=0x00; //Report ID
4.515 + report[1]=0x03; //Report size
4.516 + report[2]=0x1B; //Command ID
4.517 + report[3]=0x40; //Command ID
4.518 + report[4]=aBrightness; //Brightness level
4.519 + Write(report);
4.520 + }
4.521 +
4.522 +/**
4.523 +*/
4.524 +bool MDM166AA::IsPowerOn()
4.525 + {
4.526 + return iPowerOn;
4.527 + }
4.528 +
4.529 +/**
4.530 +*/
4.531 +char* MDM166AA::DeviceId()
4.532 + {
4.533 + return iDeviceId;
4.534 + }
4.535 +
4.536 +/**
4.537 +*/
4.538 +char* MDM166AA::FirmwareRevision()
4.539 + {
4.540 + return iFirmwareRevision;
4.541 + }
4.542 +
4.543 +/**
4.544 +*/
4.545 +void MDM166AA::ShowClock()
4.546 + {
4.547 + SendCommandClockDisplay(EClockLarge,EClock24);
4.548 + SetClockSetting();
4.549 + }
4.550 +
4.551 +/**
4.552 +*/
4.553 +void MDM166AA::HideClock()
4.554 + {
4.555 + //TODO: or reset
4.556 + Clear();
4.557 + }
4.558 +
4.559 +
4.560 +/**
4.561 +Clock setting
4.562 +[Code]1BH,00H,Pm,Ph
4.563 +[Function]Setting the clock data. The setting data is cleared, if the Reset command is input or power is turned off.
4.564 +Ph = hour
4.565 +Pm = minute
4.566 +*/
4.567 +void MDM166AA::SendCommandClockSetting(unsigned char aHour, unsigned char aMinute)
4.568 + {
4.569 + FutabaVfdReport report;
4.570 + report[0]=0x00; //Report ID
4.571 + report[1]=0x04; //Report size
4.572 + report[2]=0x1B; //Command ID
4.573 + report[3]=0x00; //Command ID
4.574 +
4.575 + //Minutes and Hours needs to be in hexadecimal view
4.576 + //To get 21:59 you need to pass in 0x21:0x59
4.577 + //Weirdest format ever, I know
4.578 + report[4]=(aMinute/10*16)+aMinute%10;
4.579 + report[5]=(aHour/10*16)+aHour%10;
4.580 +
4.581 + Write(report);
4.582 + }
4.583 +
4.584 +
4.585 +/**
4.586 +Set display clock settings according to local system time.
4.587 +This needs to be redone whenever we open or turn on our display.
4.588 +*/
4.589 +void MDM166AA::SetClockSetting()
4.590 + {
4.591 + time_t rawtime;
4.592 + struct tm * timeinfo;
4.593 +
4.594 + time ( &rawtime );
4.595 + timeinfo = localtime ( &rawtime );
4.596 + //
4.597 + SendCommandClockSetting(timeinfo->tm_hour,timeinfo->tm_min);
4.598 + }
4.599 +
4.600 +
4.601 +/**
4.602 +Clock display
4.603 +[Code] 1BH,Ps,aL,aH,Pf
4.604 +[Function] Clock is displayed small or big.
4.605 +*/
4.606 +void MDM166AA::SendCommandClockDisplay(TClockSize aClockSize, TClockFormat aClockFormat)
4.607 + {
4.608 + FutabaVfdReport report;
4.609 + report[0]=0x00; //Report ID
4.610 + report[1]=0x03; //Report size
4.611 + report[2]=0x1B; //Command ID
4.612 + report[3]=aClockSize; //
4.613 + report[4]=aClockFormat; //
4.614 +
4.615 + Write(report);
4.616 + }
4.617 +
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/FutabaMDM166AA.h Wed Feb 04 21:47:17 2015 +0100
5.3 @@ -0,0 +1,140 @@
5.4 +//
5.5 +//
5.6 +//
5.7 +
5.8 +#ifndef FUTABA_MDM166AA_H
5.9 +#define FUTABA_MDM166AA_H
5.10 +
5.11 +#include "FutabaVfd.h"
5.12 +
5.13 +
5.14 +const int KMDM166AAWidthInPixels = 96;
5.15 +const int KMDM166AAHeightInPixels = 16;
5.16 +const int KMDM166AAPixelsPerByte = 8;
5.17 +const int KMDM166AAFrameBufferSizeInBytes = KMDM166AAWidthInPixels*KMDM166AAHeightInPixels/KMDM166AAPixelsPerByte; //96*16/8=192
5.18 +const int KMDM166AAFrameBufferPixelCount = KMDM166AAWidthInPixels*KMDM166AAHeightInPixels;
5.19 +
5.20 +
5.21 +/**
5.22 +MDM166AA is a graphic display module using a FUTABA 96x16dots VFD.
5.23 +*/
5.24 +class MDM166AA : public FutabaGraphicDisplay
5.25 + {
5.26 +public:
5.27 +
5.28 + MDM166AA();
5.29 + ~MDM166AA();
5.30 +
5.31 + //From DisplayBase
5.32 + virtual int Open();
5.33 + virtual void SwapBuffers();
5.34 + //Brightness support
5.35 + virtual int MinBrightness() const {return 0;}
5.36 + virtual int MaxBrightness() const {return 2;}
5.37 + virtual void SetBrightness(int aBrightness);
5.38 + //Clock support
5.39 + virtual void ShowClock();
5.40 + virtual void HideClock();
5.41 + virtual bool SupportClock(){return true;}
5.42 +
5.43 + //From GraphicDisplay
5.44 + virtual int WidthInPixels() const {return KMDM166AAWidthInPixels;}
5.45 + virtual int HeightInPixels() const {return KMDM166AAHeightInPixels;}
5.46 +
5.47 + virtual void SetPixel(unsigned char aX, unsigned char aY, unsigned int aPixel);
5.48 + virtual void SetAllPixels(unsigned char aPattern);
5.49 + virtual int FrameBufferSizeInBytes() const {return KMDM166AAFrameBufferSizeInBytes;}
5.50 + virtual void Clear();
5.51 + virtual void Fill();
5.52 + virtual void Request(TMiniDisplayRequest aRequest);
5.53 +
5.54 + //
5.55 + void ToggleOffScreenMode();
5.56 + void SetOffScreenMode(bool aOn);
5.57 + bool OffScreenMode() const {return iOffScreenMode;}
5.58 + //
5.59 + void SetFrameDifferencing(bool aOn){iUseFrameDifferencing=aOn;}
5.60 + bool FrameDifferencing() const {return iUseFrameDifferencing;}
5.61 + //
5.62 + TMiniDisplayRequest AttemptRequestCompletion();
5.63 + FutabaVfdReport& InputReport() {return iInputReport;}
5.64 + bool IsPowerOn();
5.65 + char* DeviceId();
5.66 + char* FirmwareRevision();
5.67 +
5.68 +private:
5.69 +
5.70 + enum TClockFormat
5.71 + {
5.72 + EClock12 = 0x00,
5.73 + EClock24 = 0x01,
5.74 + };
5.75 +
5.76 + enum TClockSize
5.77 + {
5.78 + EClockSmall = 0x01,
5.79 + EClockLarge = 0x02
5.80 + };
5.81 +
5.82 +
5.83 +private:
5.84 + //Specific to MDM166AA
5.85 + //General setting command
5.86 + void SendCommandClear();
5.87 + void SendCommandReset();
5.88 + void SendCommandSetAddressCounter(unsigned char aAddressCounter);
5.89 + //void SendCommandWriteGraphicData();
5.90 + //
5.91 + //Clock commands
5.92 + void SendCommandClockSetting(unsigned char aHour, unsigned char aMinute);
5.93 + void SendCommandClockDisplay(TClockSize aClockSize, TClockFormat aClockFormat);
5.94 +
5.95 + void SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char* aPixels);
5.96 +
5.97 +private:
5.98 + void RequestDeviceId();
5.99 + void RequestFirmwareRevision();
5.100 + void RequestPowerSupplyStatus();
5.101 + //
5.102 + void SetClockSetting();
5.103 +
5.104 +
5.105 +private:
5.106 + unsigned char OffScreenY() const;
5.107 + void OffScreenTranslation(unsigned char& aX, unsigned char& aY);
5.108 + void ResetBuffers();
5.109 +
5.110 +private:
5.111 + unsigned char iDisplayPositionX;
5.112 + unsigned char iDisplayPositionY;
5.113 + ///Off screen mode is the recommended default settings to avoid tearing.
5.114 + ///Though turning it off can be useful for debugging
5.115 + bool iOffScreenMode;
5.116 + ///Frame differences algo is used to reduce USB bus traffic and improve frame rate in typical use case
5.117 + bool iUseFrameDifferencing;
5.118 + ///
5.119 + //FutabaVfdReport iReport;
5.120 + ///
5.121 + //unsigned char iFrameBuffer[256*64];
5.122 + BitArrayLow* iFrameNext;
5.123 + BitArrayLow* iFrameCurrent;
5.124 + BitArrayLow* iFramePrevious;
5.125 + //
5.126 + BitArrayLow* iFrameAlpha;
5.127 + BitArrayLow* iFrameBeta;
5.128 + BitArrayLow* iFrameGamma;
5.129 + //
5.130 + int iNeedFullFrameUpdate;
5.131 + //unsigned char iFrameBeta[256*64];
5.132 + //unsigned char *iFrontBuffer;
5.133 + //unsigned char *iBackBuffer;
5.134 + FutabaVfdReport iInputReport;
5.135 + //
5.136 + char iDeviceId[KFutabaMaxHidReportSize];
5.137 + char iFirmwareRevision[KFutabaMaxHidReportSize];
5.138 + bool iPowerOn;
5.139 + };
5.140 +
5.141 +
5.142 +
5.143 +#endif
6.1 --- a/FutabaVfd.h Wed Feb 04 17:45:46 2015 +0100
6.2 +++ b/FutabaVfd.h Wed Feb 04 21:47:17 2015 +0100
6.3 @@ -28,9 +28,12 @@
6.4 const int KHidReportIdIndex=0;
6.5 const int KFutabaHidReportSizeIndex=1;
6.6 //Define Futaba vendor ID to filter our list of device
6.7 +const unsigned short KTargaVendorId = 0x19C2;
6.8 const unsigned short KFutabaVendorId = 0x1008;
6.9 const unsigned short KFutabaProductIdGP1212A01A = 0x100C;
6.10 const unsigned short KFutabaProductIdGP1212A02A = 0x1015;
6.11 +const unsigned short KFutabaProductIdMDM166AA = 0x6A11;
6.12 +
6.13
6.14 //typedef struct hid_device_info HidDeviceInfo;
6.15
7.1 --- a/MiniDisplay.cpp Wed Feb 04 17:45:46 2015 +0100
7.2 +++ b/MiniDisplay.cpp Wed Feb 04 21:47:17 2015 +0100
7.3 @@ -2,13 +2,18 @@
7.4 #include "MiniDisplay.h"
7.5 #include "FutabaGP1212A01.h"
7.6 #include "FutabaGP1212A02.h"
7.7 +#include "FutabaMDM166AA.h"
7.8
7.9 -
7.10 +/**
7.11 +Make sure you update this list when adding a new display.
7.12 +The order has to match the one from TMiniDisplayType.
7.13 +*/
7.14 wchar_t* KDisplayNames[]=
7.15 {
7.16 L"Auto-Detect",
7.17 L"Futaba GP1212A01",
7.18 L"Futaba GP1212A02",
7.19 + L"Futaba MDM166AA",
7.20 L"Unknown display device"
7.21 };
7.22
7.23 @@ -27,6 +32,10 @@
7.24 device=new GP1212A02A();
7.25 break;
7.26
7.27 + case EMiniDisplayFutabaMDM166AA:
7.28 + device=new MDM166AA();
7.29 + break;
7.30 +
7.31 case EMiniDisplayAutoDetectFailed:
7.32 //Auto detect sequence failed
7.33 return NULL;
8.1 --- a/MiniDisplay.h Wed Feb 04 17:45:46 2015 +0100
8.2 +++ b/MiniDisplay.h Wed Feb 04 21:47:17 2015 +0100
8.3 @@ -30,7 +30,7 @@
8.4 EMiniDisplayAutoDetect=0,
8.5 EMiniDisplayFutabaGP1212A01,
8.6 EMiniDisplayFutabaGP1212A02,
8.7 - //EMiniDisplayFutabaMDM166AA,
8.8 + EMiniDisplayFutabaMDM166AA,
8.9 EMiniDisplayAutoDetectFailed
8.10 }
8.11 TMiniDisplayType;