First draft implementation of Futaba MDM166AA.
authorStephaneLenclud
Wed, 04 Feb 2015 21:47:17 +0100
changeset 253fa4007c0b19
parent 24 9c233658ab28
child 26 f943cd500390
First draft implementation of Futaba MDM166AA.
Only clock and brightness working for now.
CMakeLists.txt
FutabaGP1212A02.cpp
FutabaGP1212A02.h
FutabaMDM166AA.cpp
FutabaMDM166AA.h
FutabaVfd.h
MiniDisplay.cpp
MiniDisplay.h
     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;