Working on GP1212A02 support.
1.1 --- a/Display.h Thu Aug 21 21:53:35 2014 +0200
1.2 +++ b/Display.h Mon Aug 25 00:07:01 2014 +0200
1.3 @@ -11,6 +11,8 @@
1.4 class DisplayBase
1.5 {
1.6 public:
1.7 + virtual ~DisplayBase(){};
1.8 + //
1.9 virtual int Open()=0;
1.10 virtual void Close()=0;
1.11 //
1.12 @@ -18,6 +20,9 @@
1.13 virtual int MaxBrightness() const=0;
1.14 virtual void SetBrightness(int aBrightness)=0;
1.15 virtual void Clear()=0;
1.16 + virtual void Fill()=0;
1.17 + //
1.18 + virtual void SwapBuffers()=0;
1.19 };
1.20
1.21
2.1 --- a/FutabaGP1212A01.cpp Thu Aug 21 21:53:35 2014 +0200
2.2 +++ b/FutabaGP1212A01.cpp Mon Aug 25 00:07:01 2014 +0200
2.3 @@ -144,6 +144,15 @@
2.4 }
2.5
2.6 /**
2.7 +Turn on all pixels.
2.8 +Must be followed by a SwapBuffers call.
2.9 +*/
2.10 +void GP1212A01A::Fill()
2.11 + {
2.12 + SetAllPixels(0xFF);
2.13 + }
2.14 +
2.15 +/**
2.16 Set all pixels on our screen to the desired value.
2.17 This operation is performed off screen to avoid tearing.
2.18 @param 8 pixels pattern
3.1 --- a/FutabaGP1212A01.h Thu Aug 21 21:53:35 2014 +0200
3.2 +++ b/FutabaGP1212A01.h Mon Aug 25 00:07:01 2014 +0200
3.3 @@ -32,6 +32,7 @@
3.4 //From FutabaVfd
3.5 virtual void SetBrightness(int aBrightness);
3.6 virtual void Clear();
3.7 + virtual void Fill();
3.8
3.9 //Specific to GP1212A01A
3.10 void SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char aValue);
4.1 --- a/FutabaGP1212A02.cpp Thu Aug 21 21:53:35 2014 +0200
4.2 +++ b/FutabaGP1212A02.cpp Mon Aug 25 00:07:01 2014 +0200
4.3 @@ -2,4 +2,677 @@
4.4 //
4.5 //
4.6
4.7 -#include "FutabaGP1212A02.h"
4.8 \ No newline at end of file
4.9 +#include "FutabaGP1212A02.h"
4.10 +
4.11 +
4.12 +const int KNumberOfFrameBeforeDiffAlgo = 3;
4.13 +
4.14 +//
4.15 +// class GP1212A02A
4.16 +//
4.17 +
4.18 +GP1212A02A::GP1212A02A():
4.19 + iDisplayPositionX(0),iDisplayPositionY(0),
4.20 + iOffScreenMode(true),
4.21 + iUseFrameDifferencing(true),
4.22 + iFrameNext(NULL),
4.23 + iFrameCurrent(NULL),
4.24 + iFramePrevious(NULL),
4.25 + iFrameAlpha(NULL),
4.26 + iFrameBeta(NULL),
4.27 + iFrameGamma(NULL),
4.28 + iNeedFullFrameUpdate(0),
4.29 + iRequest(EMiniDisplayRequestNone),iPowerOn(false)
4.30 + {
4.31 + iDeviceId[0]=0;
4.32 + iFirmwareRevision[0]=0;
4.33 + //ResetBuffers();
4.34 + }
4.35 +
4.36 +/**
4.37 +*/
4.38 +GP1212A02A::~GP1212A02A()
4.39 + {
4.40 + delete iFrameAlpha;
4.41 + iFrameAlpha=NULL;
4.42 + //
4.43 + delete iFrameBeta;
4.44 + iFrameBeta=NULL;
4.45 + //
4.46 + delete iFrameGamma;
4.47 + iFrameGamma=NULL;
4.48 + //
4.49 + iFrameNext=NULL;
4.50 + iFrameCurrent=NULL;
4.51 + iFramePrevious=NULL;
4.52 + //
4.53 + iNeedFullFrameUpdate=0;
4.54 + }
4.55 +
4.56 +/**
4.57 +*/
4.58 +int GP1212A02A::Open()
4.59 + {
4.60 + int success = HidDevice::Open(KFutabaVendorId,KFutabaProductIdGP1212A02A,NULL);
4.61 + if (success)
4.62 + {
4.63 + //Allocate both frames
4.64 + delete iFrameAlpha;
4.65 + iFrameAlpha=NULL;
4.66 + iFrameAlpha=new BitArray(KGP12xFrameBufferPixelCount);
4.67 + //
4.68 + delete iFrameBeta;
4.69 + iFrameBeta=NULL;
4.70 + iFrameBeta=new BitArray(KGP12xFrameBufferPixelCount);
4.71 + //
4.72 + delete iFrameGamma;
4.73 + iFrameGamma=NULL;
4.74 + iFrameGamma=new BitArray(KGP12xFrameBufferPixelCount);
4.75 + //
4.76 + iFrameNext=iFrameAlpha;
4.77 + iFrameCurrent=iFrameBeta;
4.78 + iFramePrevious=iFrameGamma;
4.79 +
4.80 +
4.81 + //To make sure it is synced properly
4.82 + iNeedFullFrameUpdate=0;
4.83 + //
4.84 + SetNonBlocking(1);
4.85 + //Since we can't get our display position we force it to our default
4.86 + //This makes sure frames are in sync from the start
4.87 + //Clever clients will have taken care of putting back frame (0,0) before closing
4.88 + SetDisplayPosition(iDisplayPositionX,iDisplayPositionY);
4.89 + }
4.90 + return success;
4.91 + }
4.92 +
4.93 +/**
4.94 +*/
4.95 +void GP1212A02A::SetPixel(unsigned char aX, unsigned char aY, bool aOn)
4.96 + {
4.97 + //
4.98 + //int byteOffset=(aX*HeightInPixels()+aY)/8;
4.99 + //int bitOffset=(aX*HeightInPixels()+aY)%8;
4.100 + //iNextFrame[byteOffset] |= ( (aOn?0x01:0x00) << bitOffset );
4.101 +
4.102 + if (iOffScreenMode)
4.103 + {
4.104 + if (aOn)
4.105 + {
4.106 + iFrameNext->SetBit(aX*HeightInPixels()+aY);
4.107 + }
4.108 + else
4.109 + {
4.110 + iFrameNext->ClearBit(aX*HeightInPixels()+aY);
4.111 + }
4.112 + }
4.113 + else
4.114 + {
4.115 + //Just specify a one pixel block
4.116 + SetPixelBlock(aX,aY,0x00,0x01,aOn);
4.117 + }
4.118 + }
4.119 +
4.120 +/**
4.121 +*/
4.122 +void GP1212A02A::BitBlit(const BitArray& aBitmap, int aSrcWidth, int aSrcHeight, int aTargetX, int aTargetY) const
4.123 + {
4.124 + //TODO: amend loop values so that we don't keep on looping past our frame buffer dimensions.
4.125 + for (int i=0;i<aSrcWidth;i++)
4.126 + {
4.127 + for (int j=0;j<aSrcHeight;j++)
4.128 + {
4.129 + iFrameNext->SetBitValue((aTargetX+i)*HeightInPixels()+aTargetY+j,aBitmap[+i*aSrcHeight+j]);
4.130 + }
4.131 + }
4.132 + }
4.133 +
4.134 +/**
4.135 +Clear our client side back buffer.
4.136 +Call to SwapBuffers must follow to actually clear the display.
4.137 +*/
4.138 +void GP1212A02A::Clear()
4.139 + {
4.140 + //memset(iNextFrame->Ptr(),0x00,FrameBufferSizeInBytes());
4.141 + if (iOffScreenMode)
4.142 + {
4.143 + iFrameNext->ClearAll();
4.144 + }
4.145 + else
4.146 + {
4.147 + SendClearCommand();
4.148 + }
4.149 + }
4.150 +
4.151 +/**
4.152 +Turn on all pixels.
4.153 +Must be followed by a SwapBuffers call.
4.154 +*/
4.155 +void GP1212A02A::Fill()
4.156 + {
4.157 + SetAllPixels(0xFF);
4.158 + }
4.159 +
4.160 +/**
4.161 +Set all pixels on our screen to the desired value.
4.162 +This operation is performed off screen to avoid tearing.
4.163 +@param 8 pixels pattern
4.164 +*/
4.165 +void GP1212A02A::SetAllPixels(unsigned char aPattern)
4.166 + {
4.167 + //With a single buffer
4.168 + //unsigned char screen[2048]; //One screen worth of pixels
4.169 + //memset(screen,0xFF,sizeof(screen));
4.170 + //SetPixelBlock(0,0,63,sizeof(screen),screen);
4.171 +
4.172 +
4.173 + if (iOffScreenMode)
4.174 + {
4.175 + memset(iFrameNext->Ptr(),aPattern,FrameBufferSizeInBytes());
4.176 + }
4.177 + else
4.178 + {
4.179 + //Using pattern SetPixelBlock variant.
4.180 + SetPixelBlock(0,0,63,FrameBufferSizeInBytes(),aPattern);
4.181 + }
4.182 + //
4.183 + }
4.184 +
4.185 +
4.186 +/**
4.187 +Set the defined pixel block to the given value.
4.188 +@param X coordinate of our pixel block starting point.
4.189 +@param Y coordinate of our pixel block starting point.
4.190 +@param The height of our pixel block.
4.191 +@param The size of our pixel data. Number of pixels divided by 8.
4.192 +@param The value set to 8 pixels used as a pattern.
4.193 +*/
4.194 +void GP1212A02A::SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char aValue)
4.195 + {
4.196 + OffScreenTranslation(aX,aY);
4.197 + FutabaVfdReport report;
4.198 + report[0]=0x00; //Report ID
4.199 + 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.200 + report[2]=0x1B; //Command ID
4.201 + report[3]=0x5B; //Command ID
4.202 + report[4]=0xF0; //Command ID
4.203 + report[5]=aX; //X
4.204 + report[6]=aY; //Y
4.205 + report[7]=aHeight; //Y length before return. Though outside the specs, setting this to zero apparently allows us to modify a single pixel without touching any other.
4.206 + report[8]=aSize>>8; //Size of pixel data in bytes (MSB)
4.207 + report[9]=aSize; //Size of pixel data in bytes (LSB)
4.208 + int sizeWritten=MIN(aSize,report.Size()-10);
4.209 + memset(report.Buffer()+10, aValue, sizeWritten);
4.210 + Write(report);
4.211 +
4.212 + int remainingSize=aSize;
4.213 + //We need to keep on sending our pixel data until we are done
4.214 + while (report[1]==64)
4.215 + {
4.216 + report.Reset();
4.217 + remainingSize-=sizeWritten;
4.218 + report[0]=0x00; //Report ID
4.219 + report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
4.220 + sizeWritten=(report[1]==64?63:report[1]);
4.221 + memset(report.Buffer()+2, aValue, sizeWritten);
4.222 + Write(report);
4.223 + }
4.224 + }
4.225 +
4.226 +/**
4.227 +Set the defined pixel block to the given value.
4.228 +@param X coordinate of our pixel block starting point.
4.229 +@param Y coordinate of our pixel block starting point.
4.230 +@param The height of our pixel block.
4.231 +@param The size of our pixel data. Number of pixels divided by 8.
4.232 +@param Pointer to our pixel data.
4.233 +*/
4.234 +void GP1212A02A::SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char* aPixels)
4.235 + {
4.236 + OffScreenTranslation(aX,aY);
4.237 + FutabaVfdReport report;
4.238 + report[0]=0x00; //Report ID
4.239 + 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.240 + report[2]=0x1B; //Command ID
4.241 + report[3]=0x5B; //Command ID
4.242 + report[4]=0xF0; //Command ID
4.243 + report[5]=aX; //X
4.244 + report[6]=aY; //Y
4.245 + report[7]=aHeight; //Y length before return. Though outside the specs, setting this to zero apparently allows us to modify a single pixel without touching any other.
4.246 + report[8]=aSize>>8; //Size of pixel data in bytes (MSB)
4.247 + report[9]=aSize; //Size of pixel data in bytes (LSB)
4.248 + int sizeWritten=MIN(aSize,report.Size()-10);
4.249 + memcpy(report.Buffer()+10, aPixels, sizeWritten);
4.250 + Write(report);
4.251 +
4.252 + int remainingSize=aSize;
4.253 + //We need to keep on sending our pixel data until we are done
4.254 + while (report[1]==64)
4.255 + {
4.256 + report.Reset();
4.257 + remainingSize-=sizeWritten;
4.258 + report[0]=0x00; //Report ID
4.259 + report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
4.260 + sizeWritten=(report[1]==64?63:report[1]);
4.261 + memcpy(report.Buffer()+2, aPixels+(aSize-remainingSize), sizeWritten);
4.262 + Write(report);
4.263 + }
4.264 + }
4.265 +
4.266 +/**
4.267 +Using this function is advised against as is causes tearing.
4.268 +Use Clear instead.
4.269 +*/
4.270 +void GP1212A02A::SendClearCommand()
4.271 + {
4.272 + //1BH,5BH,32H,4AH
4.273 + //Send Clear Display Command
4.274 + FutabaVfdReport report;
4.275 + report[0]=0x00; //Report ID
4.276 + report[1]=0x04; //Report length
4.277 + report[2]=0x1B; //Command ID
4.278 + report[3]=0x5B; //Command ID
4.279 + report[4]=0x32; //Command ID
4.280 + report[5]=0x4A; //Command ID
4.281 + Write(report);
4.282 + }
4.283 +
4.284 +/**
4.285 +Change our display position within our buffer.
4.286 +*/
4.287 +void GP1212A02A::SetDisplayPosition(DW aDw,unsigned char aX, unsigned char aY)
4.288 + {
4.289 + //1BH,5BH,Dw,Px,Py
4.290 + //Send Display Position Settings Command
4.291 + FutabaVfdReport report;
4.292 + report[0]=0x00; //Report ID
4.293 + report[1]=0x05; //Report length
4.294 + report[2]=0x1B; //Command ID
4.295 + report[3]=0x5B; //Command ID
4.296 + report[4]=aDw; //Specify our DW
4.297 + report[5]=aX; //X coordinate of our DW top-left corner
4.298 + report[6]=aY; //Y coordinate of our DW top-left corner
4.299 + Write(report);
4.300 + }
4.301 +
4.302 +/**
4.303 +Change our display position within our buffer.
4.304 +*/
4.305 +void GP1212A02A::SetDisplayPosition(unsigned char aX, unsigned char aY)
4.306 + {
4.307 + //Specs apparently says both DW should remain the same
4.308 + //Just don't ask
4.309 + SetDisplayPosition(GP1212A02A::DW1,aX,aY);
4.310 + SetDisplayPosition(GP1212A02A::DW2,aX,aY);
4.311 + iDisplayPositionX=aX;
4.312 + iDisplayPositionY=aY;
4.313 + }
4.314 +
4.315 +/**
4.316 +Provide Y coordinate of our off screen buffer.
4.317 +*/
4.318 +unsigned char GP1212A02A::OffScreenY() const
4.319 + {
4.320 + //Overflowing is fine this is just what we want
4.321 + return iDisplayPositionY+HeightInPixels();
4.322 + }
4.323 +
4.324 +/**
4.325 +Put our off screen buffer on screen.
4.326 +On screen buffer goes off screen.
4.327 +*/
4.328 +void GP1212A02A::SwapBuffers()
4.329 + {
4.330 + //Only perform buffer swapping if off screen mode is enabled
4.331 + if (OffScreenMode())
4.332 + {
4.333 + //Send host back buffer to device back buffer
4.334 + if (!iUseFrameDifferencing || iNeedFullFrameUpdate<KNumberOfFrameBeforeDiffAlgo)
4.335 + {
4.336 + iNeedFullFrameUpdate++;
4.337 + SetPixelBlock(0,0,63,FrameBufferSizeInBytes(),iFrameNext->Ptr());
4.338 + }
4.339 + else
4.340 + {
4.341 + //Frame diff algo is enabled
4.342 + //We are going to send to our device only the differences between next frame and previous frame
4.343 + SendModifiedPixelBlocks();
4.344 + }
4.345 + //Swap device front and back buffer
4.346 + SetDisplayPosition(iDisplayPositionX,OffScreenY());
4.347 +
4.348 + //Cycle through our frame buffers
4.349 + //We keep track of previous frame which is in fact our device back buffer.
4.350 + //We can then compare previous and next frame and send only the differences to our device.
4.351 + //This mechanism allows us to reduce traffic over our USB bus thus improving our frame rate from 14 FPS to 30 FPS.
4.352 + //Keep our previous frame pointer
4.353 + BitArray* previousFrame=iFramePrevious;
4.354 + //Current frame becomes the previous one
4.355 + iFramePrevious = iFrameCurrent;
4.356 + //Next frame becomes the current one
4.357 + iFrameCurrent = iFrameNext;
4.358 + //Next frame is now our former previous
4.359 + iFrameNext = previousFrame;
4.360 + }
4.361 + }
4.362 +
4.363 +
4.364 +//Define the edge of our pixel block
4.365 +//Pixel blocks of 32x32 seems to run almost as fast as full screen update in worse case scenarii.
4.366 +//Though I wonder if in some situations 16 could be better. Make this an attribute at some point if need be.
4.367 +const int KPixelBlockEdge = 32;
4.368 +const int KPixelBlockSizeInBits = KPixelBlockEdge*KPixelBlockEdge;
4.369 +const int KPixelBlockSizeInBytes = KPixelBlockSizeInBits/8;
4.370 +
4.371 +
4.372 +/**
4.373 + * @brief GP1212A02A::SendModifiedPixelBlocks
4.374 + * Compare our back and front buffer and send to the device only the modified pixels.
4.375 + */
4.376 +void GP1212A02A::SendModifiedPixelBlocks()
4.377 + {
4.378 + int w=WidthInPixels();
4.379 + int h=HeightInPixels();
4.380 +
4.381 +
4.382 + //TODO: optimize with memcmp and 16 inc
4.383 + /*
4.384 +
4.385 + for (int i=0;i<w;i++)
4.386 + {
4.387 + for (int j=0;j<h;j++)
4.388 + {
4.389 + //aX*HeightInPixels()+aY
4.390 + if ((*iFrameNext)[i*h+j]!=(*iFramePrevious)[i*h+j])
4.391 + {
4.392 + //We need to update that pixel
4.393 + SetPixelBlock(i,j,0,1,((*iFrameNext)[i*h+j]?0x01:0x00));
4.394 + //SetDisplayPosition(iDisplayPositionX,OffScreenY());
4.395 + //SetDisplayPosition(iDisplayPositionX,OffScreenY());
4.396 +
4.397 + //SetPixelBlock(i,j,15,32,iNextFrame->Ptr()+offset);
4.398 + }
4.399 + }
4.400 + }
4.401 + */
4.402 +
4.403 + BitArray nextBlock(KPixelBlockSizeInBits);
4.404 + BitArray previousBlock(KPixelBlockSizeInBits);
4.405 +
4.406 + for (int i=0;i<w;i+=KPixelBlockEdge)
4.407 + {
4.408 + for (int j=0;j<h;j+=KPixelBlockEdge)
4.409 + {
4.410 + //aX*HeightInPixels()+aY
4.411 + //int offset=(i*w/8)+(j/8);
4.412 +
4.413 +#ifdef DEBUG_FRAME_DIFF
4.414 + QImage imagePrevious(KPixelBlockEdge,KPixelBlockEdge,QImage::Format_RGB32);
4.415 + QImage imageNext(KPixelBlockEdge,KPixelBlockEdge,QImage::Format_RGB32);
4.416 +#endif
4.417 +
4.418 + //Get both our blocks from our buffers
4.419 + for (int x=i;x<i+KPixelBlockEdge;x++)
4.420 + {
4.421 + for (int y=j;y<j+KPixelBlockEdge;y++)
4.422 + {
4.423 + int blockOffset=(x-i)*KPixelBlockEdge+(y-j);
4.424 + int frameOffset=x*h+y;
4.425 + nextBlock.SetBitValue(blockOffset,(*iFrameNext)[frameOffset]);
4.426 + previousBlock.SetBitValue(blockOffset,(*iFramePrevious)[frameOffset]);
4.427 +
4.428 +#ifdef DEBUG_FRAME_DIFF
4.429 + imageNext.setPixel(x-i,y-j,(nextBlock[blockOffset]?0xFFFFFFFF:0x00000000));
4.430 + imagePrevious.setPixel(x-i,y-j,(previousBlock[blockOffset]?0xFFFFFFFF:0x00000000));
4.431 +#endif
4.432 + }
4.433 + }
4.434 +
4.435 +#ifdef DEBUG_FRAME_DIFF
4.436 + QString previousName;
4.437 + QString nextName;
4.438 + QTextStream(&previousName) << "p" << i << "x" << j << ".png";
4.439 + QTextStream(&nextName) << "n" << i << "x" << j << ".png";
4.440 + imagePrevious.save(previousName);
4.441 + imageNext.save(nextName);
4.442 +#endif
4.443 +
4.444 +
4.445 + //if (memcmp(iFrameNext->Ptr()+offset,iFramePrevious->Ptr()+offset,32 )) //32=(16*16/8)
4.446 + if (memcmp(nextBlock.Ptr(),previousBlock.Ptr(),KPixelBlockSizeInBytes)!=0)
4.447 + {
4.448 + //We need to update that block
4.449 + SetPixelBlock(i,j,KPixelBlockEdge-1,KPixelBlockSizeInBytes,nextBlock.Ptr());
4.450 + //SetPixelBlock(i,j,15,32,0xFF/*nextBlock.Ptr()*/);
4.451 + //SetDisplayPosition(iDisplayPositionX,OffScreenY());
4.452 + //SetDisplayPosition(iDisplayPositionX,OffScreenY());
4.453 +
4.454 + //SetPixelBlock(i,j,15,32,iFrameNext->Ptr()+offset);
4.455 + }
4.456 + }
4.457 + }
4.458 +
4.459 + }
4.460 +
4.461 +/**
4.462 +Translate the given pixel coordinate according to our off screen mode.
4.463 +*/
4.464 +void GP1212A02A::OffScreenTranslation(unsigned char& aX, unsigned char& aY)
4.465 + {
4.466 + if (OffScreenMode())
4.467 + {
4.468 + aX+=WidthInPixels()-iDisplayPositionX;
4.469 + aY+=HeightInPixels()-iDisplayPositionY;
4.470 + }
4.471 + }
4.472 +
4.473 +
4.474 +/**
4.475 +*/
4.476 +void GP1212A02A::ResetBuffers()
4.477 + {
4.478 + //iNextFrame->ClearAll();
4.479 + //memset(iFrameAlpha,0x00,sizeof(iFrameAlpha));
4.480 + //memset(iFrameBeta,0x00,sizeof(iFrameBeta));
4.481 + }
4.482 +
4.483 +/**
4.484 +*/
4.485 +void GP1212A02A::RequestDeviceId()
4.486 + {
4.487 + if (RequestPending())
4.488 + {
4.489 + //Abort silently for now
4.490 + return;
4.491 + }
4.492 +
4.493 + //1BH,5BH,63H,49H,44H
4.494 + //Send Read ID command
4.495 + FutabaVfdReport report;
4.496 + report[0]=0x00; //Report ID
4.497 + report[1]=0x05; //Report length
4.498 + report[2]=0x1B; //Command ID
4.499 + report[3]=0x5B; //Command ID
4.500 + report[4]=0x63; //Command ID
4.501 + report[5]=0x49; //Command ID
4.502 + report[6]=0x44; //Command ID
4.503 + if (Write(report)==report.Size())
4.504 + {
4.505 + iRequest=EMiniDisplayRequestDeviceId;
4.506 + }
4.507 + }
4.508 +
4.509 +/**
4.510 +*/
4.511 +void GP1212A02A::RequestFirmwareRevision()
4.512 + {
4.513 + if (RequestPending())
4.514 + {
4.515 + //Abort silently for now
4.516 + return;
4.517 + }
4.518 +
4.519 + //1BH,5BH,63H,46H,52H
4.520 + //Send Software Revision Read Command
4.521 + FutabaVfdReport report;
4.522 + report[0]=0x00; //Report ID
4.523 + report[1]=0x05; //Report length
4.524 + report[2]=0x1B; //Command ID
4.525 + report[3]=0x5B; //Command ID
4.526 + report[4]=0x63; //Command ID
4.527 + report[5]=0x46; //Command ID
4.528 + report[6]=0x52; //Command ID
4.529 + if (Write(report)==report.Size())
4.530 + {
4.531 + iRequest=EMiniDisplayRequestFirmwareRevision;
4.532 + }
4.533 + }
4.534 +
4.535 +/**
4.536 +*/
4.537 +void GP1212A02A::RequestPowerSupplyStatus()
4.538 + {
4.539 + if (RequestPending())
4.540 + {
4.541 + //Abort silently for now
4.542 + return;
4.543 + }
4.544 + //1BH,5BH,63H,50H,4DH
4.545 + //Send Power Suppply Monitor Command
4.546 + FutabaVfdReport report;
4.547 + report[0]=0x00; //Report ID
4.548 + report[1]=0x05; //Report length
4.549 + report[2]=0x1B; //Command ID
4.550 + report[3]=0x5B; //Command ID
4.551 + report[4]=0x63; //Command ID
4.552 + report[5]=0x50; //Command ID
4.553 + report[6]=0x4D; //Command ID
4.554 + if (Write(report)==report.Size())
4.555 + {
4.556 + iRequest=EMiniDisplayRequestPowerSupplyStatus;
4.557 + }
4.558 + }
4.559 +
4.560 +
4.561 +/**
4.562 +This is for development purposes only.
4.563 +Production application should stick to off-screen mode to avoid tearing.
4.564 +*/
4.565 +void GP1212A02A::ToggleOffScreenMode()
4.566 + {
4.567 + SetOffScreenMode(!iOffScreenMode);
4.568 + }
4.569 +
4.570 +/**
4.571 + * @brief GP1212A02A::SetOffScreenMode
4.572 + * @param aOn
4.573 + * @return
4.574 + */
4.575 +void GP1212A02A::SetOffScreenMode(bool aOn)
4.576 + {
4.577 + if (aOn==iOffScreenMode)
4.578 + {
4.579 + //Nothing to do here
4.580 + return;
4.581 + }
4.582 +
4.583 + iOffScreenMode=aOn;
4.584 +
4.585 + //Clean up our buffers upon switching modes
4.586 + SetDisplayPosition(0,0);
4.587 + Clear();
4.588 + SwapBuffers();
4.589 + Clear();
4.590 + }
4.591 +
4.592 +/**
4.593 +Tries to complete our current request if we have one pending.
4.594 + */
4.595 +TMiniDisplayRequest GP1212A02A::AttemptRequestCompletion()
4.596 + {
4.597 + if (!RequestPending())
4.598 + {
4.599 + return EMiniDisplayRequestNone;
4.600 + }
4.601 +
4.602 + int res=Read(iInputReport);
4.603 +
4.604 + if (!res)
4.605 + {
4.606 + return EMiniDisplayRequestNone;
4.607 + }
4.608 +
4.609 + //Process our request
4.610 + if (CurrentRequest()==EMiniDisplayRequestPowerSupplyStatus)
4.611 + {
4.612 + if (iInputReport[1]==0x4F && iInputReport[2]==0x4E)
4.613 + {
4.614 + iPowerOn = true;
4.615 + }
4.616 + else if (iInputReport[1]==0x4F && iInputReport[2]==0x46 && iInputReport[3]==0x46)
4.617 + {
4.618 + iPowerOn = false;
4.619 + }
4.620 + }
4.621 + else if (CurrentRequest()==EMiniDisplayRequestDeviceId)
4.622 + {
4.623 + unsigned char* ptr=&iInputReport[1];
4.624 + strcpy(iDeviceId,(const char*)ptr);
4.625 + }
4.626 + else if (CurrentRequest()==EMiniDisplayRequestFirmwareRevision)
4.627 + {
4.628 + unsigned char* ptr=&iInputReport[1];
4.629 + strcpy(iFirmwareRevision,(const char*)ptr);
4.630 + }
4.631 +
4.632 + TMiniDisplayRequest completed=iRequest;
4.633 + //Our request was completed
4.634 + iRequest=EMiniDisplayRequestNone;
4.635 +
4.636 + return completed;
4.637 + }
4.638 +
4.639 +
4.640 +/**
4.641 +Set our screen brightness.
4.642 +@param The desired brightness level. Must be between MinBrightness and MaxBrightness.
4.643 +*/
4.644 +void GP1212A02A::SetBrightness(int aBrightness)
4.645 + {
4.646 + if (aBrightness<MinBrightness()||aBrightness>MaxBrightness())
4.647 + {
4.648 + //Brightness out of range.
4.649 + //Just ignore that request.
4.650 + return;
4.651 + }
4.652 +
4.653 + FutabaVfdReport report;
4.654 + report[0]=0x00; //Report ID
4.655 + report[1]=0x04; //Report size
4.656 + report[2]=0x1B; //Command ID
4.657 + report[3]=0x4A; //Command ID
4.658 + report[4]=0x44; //Command ID
4.659 + report[7]=0x30+aBrightness; //Brightness level
4.660 + Write(report);
4.661 + }
4.662 +
4.663 +/**
4.664 +*/
4.665 +bool GP1212A02A::PowerOn()
4.666 + {
4.667 + return iPowerOn;
4.668 + }
4.669 +
4.670 +/**
4.671 +*/
4.672 +char* GP1212A02A::DeviceId()
4.673 + {
4.674 + return iDeviceId;
4.675 + }
4.676 +
4.677 +/**
4.678 +*/
4.679 +char* GP1212A02A::FirmwareRevision()
4.680 + {
4.681 + return iFirmwareRevision;
4.682 + }
5.1 --- a/FutabaGP1212A02.h Thu Aug 21 21:53:35 2014 +0200
5.2 +++ b/FutabaGP1212A02.h Mon Aug 25 00:07:01 2014 +0200
5.3 @@ -7,6 +7,109 @@
5.4
5.5 #include "FutabaGP1212.h"
5.6
5.7 +#include "FutabaGP1212.h"
5.8 +#include "FutabaVfd.h"
5.9 +
5.10 +/**
5.11 +GP1212A01A is a graphic display module using a FUTABA 256x64dots VFD.
5.12 +The module do not include character ROM, the customer will compile the character
5.13 +by themselves (from main system).
5.14 +*/
5.15 +class GP1212A02A : public GP1212XXXX
5.16 + {
5.17 +public:
5.18 +
5.19 + GP1212A02A();
5.20 + ~GP1212A02A();
5.21 +
5.22 + //From DisplayBase
5.23 + int Open();
5.24 + virtual void SwapBuffers();
5.25 +
5.26 + //From GraphicDisplay
5.27 + virtual void SetPixel(unsigned char aX, unsigned char aY, bool aOn);
5.28 + virtual void SetAllPixels(unsigned char aPattern);
5.29 + virtual int FrameBufferSizeInBytes() const {return KGP12xFrameBufferSizeInBytes;}
5.30 + virtual void BitBlit(const BitArray& aBitmap, int aSrcWidth, int aSrcHeight, int aTargetX, int aTargetY) const;
5.31 + virtual void SetBrightness(int aBrightness);
5.32 + virtual void Clear();
5.33 + virtual void Fill();
5.34 +
5.35 + //Specific to GP1212A01A
5.36 + void SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char aValue);
5.37 + void SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char* aPixels);
5.38 + //Define display position within our display RAM
5.39 + void SetDisplayPosition(unsigned char aX, unsigned char aY);
5.40 + unsigned char DisplayPositionX() const {return iDisplayPositionX;}
5.41 + unsigned char DisplayPositionY() const {return iDisplayPositionY;}
5.42 +
5.43 + //
5.44 + void RequestDeviceId();
5.45 + void RequestFirmwareRevision();
5.46 + void RequestPowerSupplyStatus();
5.47 + //
5.48 + void ToggleOffScreenMode();
5.49 + void SetOffScreenMode(bool aOn);
5.50 + bool OffScreenMode() const {return iOffScreenMode;}
5.51 + //
5.52 + void SetFrameDifferencing(bool aOn){iUseFrameDifferencing=aOn;}
5.53 + bool FrameDifferencing() const {return iUseFrameDifferencing;}
5.54 + //
5.55 + bool RequestPending(){return iRequest!=EMiniDisplayRequestNone;}
5.56 + TMiniDisplayRequest CurrentRequest(){return iRequest;}
5.57 + void CancelRequest(){iRequest=EMiniDisplayRequestNone;}
5.58 + TMiniDisplayRequest AttemptRequestCompletion();
5.59 + FutabaVfdReport& InputReport() {return iInputReport;}
5.60 + bool PowerOn();
5.61 + char* DeviceId();
5.62 + char* FirmwareRevision();
5.63 +
5.64 +private:
5.65 + enum DW
5.66 + {
5.67 + DW1=0xC0,
5.68 + DW2=0xD0
5.69 + };
5.70 +
5.71 + void SetDisplayPosition(DW aDw,unsigned char aX, unsigned char aY);
5.72 + unsigned char OffScreenY() const;
5.73 + void SendClearCommand();
5.74 + void OffScreenTranslation(unsigned char& aX, unsigned char& aY);
5.75 + void ResetBuffers();
5.76 + void SendModifiedPixelBlocks();
5.77 +
5.78 +private:
5.79 + unsigned char iDisplayPositionX;
5.80 + unsigned char iDisplayPositionY;
5.81 + ///Off screen mode is the recommended default settings to avoid tearing.
5.82 + ///Though turning it off can be useful for debugging
5.83 + bool iOffScreenMode;
5.84 + ///Frame differences algo is used to reduce USB bus traffic and improve frame rate in typical use case
5.85 + bool iUseFrameDifferencing;
5.86 + ///
5.87 + //FutabaVfdReport iReport;
5.88 + ///
5.89 + //unsigned char iFrameBuffer[256*64];
5.90 + BitArray* iFrameNext;
5.91 + BitArray* iFrameCurrent;
5.92 + BitArray* iFramePrevious;
5.93 + //
5.94 + BitArray* iFrameAlpha;
5.95 + BitArray* iFrameBeta;
5.96 + BitArray* iFrameGamma;
5.97 + //
5.98 + int iNeedFullFrameUpdate;
5.99 + //unsigned char iFrameBeta[256*64];
5.100 + //unsigned char *iFrontBuffer;
5.101 + //unsigned char *iBackBuffer;
5.102 + TMiniDisplayRequest iRequest;
5.103 + FutabaVfdReport iInputReport;
5.104 + //
5.105 + char iDeviceId[KFutabaMaxHidReportSize];
5.106 + char iFirmwareRevision[KFutabaMaxHidReportSize];
5.107 + bool iPowerOn;
5.108 + };
5.109 +
5.110
5.111
5.112 #endif
6.1 --- a/FutabaVfd.h Thu Aug 21 21:53:35 2014 +0200
6.2 +++ b/FutabaVfd.h Mon Aug 25 00:07:01 2014 +0200
6.3 @@ -31,7 +31,7 @@
6.4 //Define Futaba vendor ID to filter our list of device
6.5 const unsigned short KFutabaVendorId = 0x1008;
6.6 const unsigned short KFutabaProductIdGP1212A01A = 0x100C;
6.7 -const unsigned short KFutabaProductIdGP1212A02A = 0x1013; //Or is it 0x1015
6.8 +const unsigned short KFutabaProductIdGP1212A02A = 0x1015;
6.9
6.10 //typedef struct hid_device_info HidDeviceInfo;
6.11
7.1 --- a/MiniDisplay.cpp Thu Aug 21 21:53:35 2014 +0200
7.2 +++ b/MiniDisplay.cpp Mon Aug 25 00:07:01 2014 +0200
7.3 @@ -1,29 +1,46 @@
7.4
7.5 #include "MiniDisplay.h"
7.6 #include "FutabaGP1212A01.h"
7.7 -
7.8 -
7.9 +#include "FutabaGP1212A02.h"
7.10
7.11
7.12
7.13 //Open & Close functions
7.14 MiniDisplayDevice MiniDisplayOpen(TMiniDisplayType aType)
7.15 {
7.16 - GP1212A01A* device=NULL;
7.17 - device=new GP1212A01A();
7.18 + GraphicDisplay* device=NULL;
7.19 +
7.20 + switch (aType)
7.21 + {
7.22 + case EMiniDisplayAutoDetect:
7.23 + //TODO
7.24 + device=new GP1212A01A();
7.25 + break;
7.26 +
7.27 + case EMiniDisplayFutabaGP1212A01:
7.28 + device=new GP1212A01A();
7.29 + break;
7.30 +
7.31 + case EMiniDisplayFutabaGP1212A02:
7.32 + device=new GP1212A02A();
7.33 + break;
7.34 + };
7.35 +
7.36 int success = device->Open();
7.37 if (!success)
7.38 {
7.39 delete device;
7.40 - return NULL;
7.41 + device=NULL;
7.42 }
7.43
7.44 return device;
7.45 }
7.46
7.47 +//
7.48 +
7.49 void MiniDisplayClose(MiniDisplayDevice aDevice)
7.50 {
7.51 - delete ((GP1212A01A*)aDevice);
7.52 + delete ((GraphicDisplay*)aDevice);
7.53 }
7.54
7.55
7.56 @@ -34,7 +51,7 @@
7.57 return;
7.58 }
7.59
7.60 - ((GP1212A01A*)aDevice)->SetAllPixels(0x00);
7.61 + ((GraphicDisplay*)aDevice)->Clear();
7.62 }
7.63
7.64
7.65 @@ -45,7 +62,7 @@
7.66 return;
7.67 }
7.68
7.69 - ((GP1212A01A*)aDevice)->SetAllPixels(0xFF);
7.70 + ((GraphicDisplay*)aDevice)->Fill();
7.71 }
7.72
7.73
7.74 @@ -56,7 +73,7 @@
7.75 return;
7.76 }
7.77
7.78 - ((GP1212A01A*)aDevice)->SwapBuffers();
7.79 + ((GraphicDisplay*)aDevice)->SwapBuffers();
7.80 }
7.81
7.82 //-------------------------------------------------------------
7.83 @@ -67,7 +84,7 @@
7.84 return 0;
7.85 }
7.86
7.87 - return ((GP1212A01A*)aDevice)->MaxBrightness();
7.88 + return ((GraphicDisplay*)aDevice)->MaxBrightness();
7.89 }
7.90
7.91 //-------------------------------------------------------------
7.92 @@ -78,7 +95,7 @@
7.93 return 0;
7.94 }
7.95
7.96 - return ((GP1212A01A*)aDevice)->MinBrightness();
7.97 + return ((GraphicDisplay*)aDevice)->MinBrightness();
7.98 }
7.99
7.100 //-------------------------------------------------------------
7.101 @@ -89,7 +106,7 @@
7.102 return;
7.103 }
7.104
7.105 - ((GP1212A01A*)aDevice)->SetBrightness(aBrightness);
7.106 + ((GraphicDisplay*)aDevice)->SetBrightness(aBrightness);
7.107 }
7.108
7.109 //-------------------------------------------------------------
7.110 @@ -100,7 +117,7 @@
7.111 return 0;
7.112 }
7.113
7.114 - return ((GP1212A01A*)aDevice)->WidthInPixels();
7.115 + return ((GraphicDisplay*)aDevice)->WidthInPixels();
7.116 }
7.117
7.118 //-------------------------------------------------------------
7.119 @@ -111,14 +128,14 @@
7.120 return 0;
7.121 }
7.122
7.123 - return ((GP1212A01A*)aDevice)->HeightInPixels();
7.124 + return ((GraphicDisplay*)aDevice)->HeightInPixels();
7.125 }
7.126
7.127 //-------------------------------------------------------------
7.128 void MiniDisplaySetPixel(MiniDisplayDevice aDevice, int aX, int aY, int aValue)
7.129 {
7.130 //aValue&=0x00FFFFFF; //Filter out alpha component
7.131 - return ((GP1212A01A*)aDevice)->SetPixel(aX,aY,aValue);
7.132 + return ((GraphicDisplay*)aDevice)->SetPixel(aX,aY,aValue);
7.133 }
7.134
7.135 //-------------------------------------------------------------