1.1 --- a/FutabaGP1212A02.cpp Thu Aug 21 21:53:35 2014 +0200
1.2 +++ b/FutabaGP1212A02.cpp Mon Aug 25 00:07:01 2014 +0200
1.3 @@ -2,4 +2,677 @@
1.4 //
1.5 //
1.6
1.7 -#include "FutabaGP1212A02.h"
1.8 \ No newline at end of file
1.9 +#include "FutabaGP1212A02.h"
1.10 +
1.11 +
1.12 +const int KNumberOfFrameBeforeDiffAlgo = 3;
1.13 +
1.14 +//
1.15 +// class GP1212A02A
1.16 +//
1.17 +
1.18 +GP1212A02A::GP1212A02A():
1.19 + iDisplayPositionX(0),iDisplayPositionY(0),
1.20 + iOffScreenMode(true),
1.21 + iUseFrameDifferencing(true),
1.22 + iFrameNext(NULL),
1.23 + iFrameCurrent(NULL),
1.24 + iFramePrevious(NULL),
1.25 + iFrameAlpha(NULL),
1.26 + iFrameBeta(NULL),
1.27 + iFrameGamma(NULL),
1.28 + iNeedFullFrameUpdate(0),
1.29 + iRequest(EMiniDisplayRequestNone),iPowerOn(false)
1.30 + {
1.31 + iDeviceId[0]=0;
1.32 + iFirmwareRevision[0]=0;
1.33 + //ResetBuffers();
1.34 + }
1.35 +
1.36 +/**
1.37 +*/
1.38 +GP1212A02A::~GP1212A02A()
1.39 + {
1.40 + delete iFrameAlpha;
1.41 + iFrameAlpha=NULL;
1.42 + //
1.43 + delete iFrameBeta;
1.44 + iFrameBeta=NULL;
1.45 + //
1.46 + delete iFrameGamma;
1.47 + iFrameGamma=NULL;
1.48 + //
1.49 + iFrameNext=NULL;
1.50 + iFrameCurrent=NULL;
1.51 + iFramePrevious=NULL;
1.52 + //
1.53 + iNeedFullFrameUpdate=0;
1.54 + }
1.55 +
1.56 +/**
1.57 +*/
1.58 +int GP1212A02A::Open()
1.59 + {
1.60 + int success = HidDevice::Open(KFutabaVendorId,KFutabaProductIdGP1212A02A,NULL);
1.61 + if (success)
1.62 + {
1.63 + //Allocate both frames
1.64 + delete iFrameAlpha;
1.65 + iFrameAlpha=NULL;
1.66 + iFrameAlpha=new BitArray(KGP12xFrameBufferPixelCount);
1.67 + //
1.68 + delete iFrameBeta;
1.69 + iFrameBeta=NULL;
1.70 + iFrameBeta=new BitArray(KGP12xFrameBufferPixelCount);
1.71 + //
1.72 + delete iFrameGamma;
1.73 + iFrameGamma=NULL;
1.74 + iFrameGamma=new BitArray(KGP12xFrameBufferPixelCount);
1.75 + //
1.76 + iFrameNext=iFrameAlpha;
1.77 + iFrameCurrent=iFrameBeta;
1.78 + iFramePrevious=iFrameGamma;
1.79 +
1.80 +
1.81 + //To make sure it is synced properly
1.82 + iNeedFullFrameUpdate=0;
1.83 + //
1.84 + SetNonBlocking(1);
1.85 + //Since we can't get our display position we force it to our default
1.86 + //This makes sure frames are in sync from the start
1.87 + //Clever clients will have taken care of putting back frame (0,0) before closing
1.88 + SetDisplayPosition(iDisplayPositionX,iDisplayPositionY);
1.89 + }
1.90 + return success;
1.91 + }
1.92 +
1.93 +/**
1.94 +*/
1.95 +void GP1212A02A::SetPixel(unsigned char aX, unsigned char aY, bool aOn)
1.96 + {
1.97 + //
1.98 + //int byteOffset=(aX*HeightInPixels()+aY)/8;
1.99 + //int bitOffset=(aX*HeightInPixels()+aY)%8;
1.100 + //iNextFrame[byteOffset] |= ( (aOn?0x01:0x00) << bitOffset );
1.101 +
1.102 + if (iOffScreenMode)
1.103 + {
1.104 + if (aOn)
1.105 + {
1.106 + iFrameNext->SetBit(aX*HeightInPixels()+aY);
1.107 + }
1.108 + else
1.109 + {
1.110 + iFrameNext->ClearBit(aX*HeightInPixels()+aY);
1.111 + }
1.112 + }
1.113 + else
1.114 + {
1.115 + //Just specify a one pixel block
1.116 + SetPixelBlock(aX,aY,0x00,0x01,aOn);
1.117 + }
1.118 + }
1.119 +
1.120 +/**
1.121 +*/
1.122 +void GP1212A02A::BitBlit(const BitArray& aBitmap, int aSrcWidth, int aSrcHeight, int aTargetX, int aTargetY) const
1.123 + {
1.124 + //TODO: amend loop values so that we don't keep on looping past our frame buffer dimensions.
1.125 + for (int i=0;i<aSrcWidth;i++)
1.126 + {
1.127 + for (int j=0;j<aSrcHeight;j++)
1.128 + {
1.129 + iFrameNext->SetBitValue((aTargetX+i)*HeightInPixels()+aTargetY+j,aBitmap[+i*aSrcHeight+j]);
1.130 + }
1.131 + }
1.132 + }
1.133 +
1.134 +/**
1.135 +Clear our client side back buffer.
1.136 +Call to SwapBuffers must follow to actually clear the display.
1.137 +*/
1.138 +void GP1212A02A::Clear()
1.139 + {
1.140 + //memset(iNextFrame->Ptr(),0x00,FrameBufferSizeInBytes());
1.141 + if (iOffScreenMode)
1.142 + {
1.143 + iFrameNext->ClearAll();
1.144 + }
1.145 + else
1.146 + {
1.147 + SendClearCommand();
1.148 + }
1.149 + }
1.150 +
1.151 +/**
1.152 +Turn on all pixels.
1.153 +Must be followed by a SwapBuffers call.
1.154 +*/
1.155 +void GP1212A02A::Fill()
1.156 + {
1.157 + SetAllPixels(0xFF);
1.158 + }
1.159 +
1.160 +/**
1.161 +Set all pixels on our screen to the desired value.
1.162 +This operation is performed off screen to avoid tearing.
1.163 +@param 8 pixels pattern
1.164 +*/
1.165 +void GP1212A02A::SetAllPixels(unsigned char aPattern)
1.166 + {
1.167 + //With a single buffer
1.168 + //unsigned char screen[2048]; //One screen worth of pixels
1.169 + //memset(screen,0xFF,sizeof(screen));
1.170 + //SetPixelBlock(0,0,63,sizeof(screen),screen);
1.171 +
1.172 +
1.173 + if (iOffScreenMode)
1.174 + {
1.175 + memset(iFrameNext->Ptr(),aPattern,FrameBufferSizeInBytes());
1.176 + }
1.177 + else
1.178 + {
1.179 + //Using pattern SetPixelBlock variant.
1.180 + SetPixelBlock(0,0,63,FrameBufferSizeInBytes(),aPattern);
1.181 + }
1.182 + //
1.183 + }
1.184 +
1.185 +
1.186 +/**
1.187 +Set the defined pixel block to the given value.
1.188 +@param X coordinate of our pixel block starting point.
1.189 +@param Y coordinate of our pixel block starting point.
1.190 +@param The height of our pixel block.
1.191 +@param The size of our pixel data. Number of pixels divided by 8.
1.192 +@param The value set to 8 pixels used as a pattern.
1.193 +*/
1.194 +void GP1212A02A::SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char aValue)
1.195 + {
1.196 + OffScreenTranslation(aX,aY);
1.197 + FutabaVfdReport report;
1.198 + report[0]=0x00; //Report ID
1.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
1.200 + report[2]=0x1B; //Command ID
1.201 + report[3]=0x5B; //Command ID
1.202 + report[4]=0xF0; //Command ID
1.203 + report[5]=aX; //X
1.204 + report[6]=aY; //Y
1.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.
1.206 + report[8]=aSize>>8; //Size of pixel data in bytes (MSB)
1.207 + report[9]=aSize; //Size of pixel data in bytes (LSB)
1.208 + int sizeWritten=MIN(aSize,report.Size()-10);
1.209 + memset(report.Buffer()+10, aValue, sizeWritten);
1.210 + Write(report);
1.211 +
1.212 + int remainingSize=aSize;
1.213 + //We need to keep on sending our pixel data until we are done
1.214 + while (report[1]==64)
1.215 + {
1.216 + report.Reset();
1.217 + remainingSize-=sizeWritten;
1.218 + report[0]=0x00; //Report ID
1.219 + report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
1.220 + sizeWritten=(report[1]==64?63:report[1]);
1.221 + memset(report.Buffer()+2, aValue, sizeWritten);
1.222 + Write(report);
1.223 + }
1.224 + }
1.225 +
1.226 +/**
1.227 +Set the defined pixel block to the given value.
1.228 +@param X coordinate of our pixel block starting point.
1.229 +@param Y coordinate of our pixel block starting point.
1.230 +@param The height of our pixel block.
1.231 +@param The size of our pixel data. Number of pixels divided by 8.
1.232 +@param Pointer to our pixel data.
1.233 +*/
1.234 +void GP1212A02A::SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char* aPixels)
1.235 + {
1.236 + OffScreenTranslation(aX,aY);
1.237 + FutabaVfdReport report;
1.238 + report[0]=0x00; //Report ID
1.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
1.240 + report[2]=0x1B; //Command ID
1.241 + report[3]=0x5B; //Command ID
1.242 + report[4]=0xF0; //Command ID
1.243 + report[5]=aX; //X
1.244 + report[6]=aY; //Y
1.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.
1.246 + report[8]=aSize>>8; //Size of pixel data in bytes (MSB)
1.247 + report[9]=aSize; //Size of pixel data in bytes (LSB)
1.248 + int sizeWritten=MIN(aSize,report.Size()-10);
1.249 + memcpy(report.Buffer()+10, aPixels, sizeWritten);
1.250 + Write(report);
1.251 +
1.252 + int remainingSize=aSize;
1.253 + //We need to keep on sending our pixel data until we are done
1.254 + while (report[1]==64)
1.255 + {
1.256 + report.Reset();
1.257 + remainingSize-=sizeWritten;
1.258 + report[0]=0x00; //Report ID
1.259 + report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
1.260 + sizeWritten=(report[1]==64?63:report[1]);
1.261 + memcpy(report.Buffer()+2, aPixels+(aSize-remainingSize), sizeWritten);
1.262 + Write(report);
1.263 + }
1.264 + }
1.265 +
1.266 +/**
1.267 +Using this function is advised against as is causes tearing.
1.268 +Use Clear instead.
1.269 +*/
1.270 +void GP1212A02A::SendClearCommand()
1.271 + {
1.272 + //1BH,5BH,32H,4AH
1.273 + //Send Clear Display Command
1.274 + FutabaVfdReport report;
1.275 + report[0]=0x00; //Report ID
1.276 + report[1]=0x04; //Report length
1.277 + report[2]=0x1B; //Command ID
1.278 + report[3]=0x5B; //Command ID
1.279 + report[4]=0x32; //Command ID
1.280 + report[5]=0x4A; //Command ID
1.281 + Write(report);
1.282 + }
1.283 +
1.284 +/**
1.285 +Change our display position within our buffer.
1.286 +*/
1.287 +void GP1212A02A::SetDisplayPosition(DW aDw,unsigned char aX, unsigned char aY)
1.288 + {
1.289 + //1BH,5BH,Dw,Px,Py
1.290 + //Send Display Position Settings Command
1.291 + FutabaVfdReport report;
1.292 + report[0]=0x00; //Report ID
1.293 + report[1]=0x05; //Report length
1.294 + report[2]=0x1B; //Command ID
1.295 + report[3]=0x5B; //Command ID
1.296 + report[4]=aDw; //Specify our DW
1.297 + report[5]=aX; //X coordinate of our DW top-left corner
1.298 + report[6]=aY; //Y coordinate of our DW top-left corner
1.299 + Write(report);
1.300 + }
1.301 +
1.302 +/**
1.303 +Change our display position within our buffer.
1.304 +*/
1.305 +void GP1212A02A::SetDisplayPosition(unsigned char aX, unsigned char aY)
1.306 + {
1.307 + //Specs apparently says both DW should remain the same
1.308 + //Just don't ask
1.309 + SetDisplayPosition(GP1212A02A::DW1,aX,aY);
1.310 + SetDisplayPosition(GP1212A02A::DW2,aX,aY);
1.311 + iDisplayPositionX=aX;
1.312 + iDisplayPositionY=aY;
1.313 + }
1.314 +
1.315 +/**
1.316 +Provide Y coordinate of our off screen buffer.
1.317 +*/
1.318 +unsigned char GP1212A02A::OffScreenY() const
1.319 + {
1.320 + //Overflowing is fine this is just what we want
1.321 + return iDisplayPositionY+HeightInPixels();
1.322 + }
1.323 +
1.324 +/**
1.325 +Put our off screen buffer on screen.
1.326 +On screen buffer goes off screen.
1.327 +*/
1.328 +void GP1212A02A::SwapBuffers()
1.329 + {
1.330 + //Only perform buffer swapping if off screen mode is enabled
1.331 + if (OffScreenMode())
1.332 + {
1.333 + //Send host back buffer to device back buffer
1.334 + if (!iUseFrameDifferencing || iNeedFullFrameUpdate<KNumberOfFrameBeforeDiffAlgo)
1.335 + {
1.336 + iNeedFullFrameUpdate++;
1.337 + SetPixelBlock(0,0,63,FrameBufferSizeInBytes(),iFrameNext->Ptr());
1.338 + }
1.339 + else
1.340 + {
1.341 + //Frame diff algo is enabled
1.342 + //We are going to send to our device only the differences between next frame and previous frame
1.343 + SendModifiedPixelBlocks();
1.344 + }
1.345 + //Swap device front and back buffer
1.346 + SetDisplayPosition(iDisplayPositionX,OffScreenY());
1.347 +
1.348 + //Cycle through our frame buffers
1.349 + //We keep track of previous frame which is in fact our device back buffer.
1.350 + //We can then compare previous and next frame and send only the differences to our device.
1.351 + //This mechanism allows us to reduce traffic over our USB bus thus improving our frame rate from 14 FPS to 30 FPS.
1.352 + //Keep our previous frame pointer
1.353 + BitArray* previousFrame=iFramePrevious;
1.354 + //Current frame becomes the previous one
1.355 + iFramePrevious = iFrameCurrent;
1.356 + //Next frame becomes the current one
1.357 + iFrameCurrent = iFrameNext;
1.358 + //Next frame is now our former previous
1.359 + iFrameNext = previousFrame;
1.360 + }
1.361 + }
1.362 +
1.363 +
1.364 +//Define the edge of our pixel block
1.365 +//Pixel blocks of 32x32 seems to run almost as fast as full screen update in worse case scenarii.
1.366 +//Though I wonder if in some situations 16 could be better. Make this an attribute at some point if need be.
1.367 +const int KPixelBlockEdge = 32;
1.368 +const int KPixelBlockSizeInBits = KPixelBlockEdge*KPixelBlockEdge;
1.369 +const int KPixelBlockSizeInBytes = KPixelBlockSizeInBits/8;
1.370 +
1.371 +
1.372 +/**
1.373 + * @brief GP1212A02A::SendModifiedPixelBlocks
1.374 + * Compare our back and front buffer and send to the device only the modified pixels.
1.375 + */
1.376 +void GP1212A02A::SendModifiedPixelBlocks()
1.377 + {
1.378 + int w=WidthInPixels();
1.379 + int h=HeightInPixels();
1.380 +
1.381 +
1.382 + //TODO: optimize with memcmp and 16 inc
1.383 + /*
1.384 +
1.385 + for (int i=0;i<w;i++)
1.386 + {
1.387 + for (int j=0;j<h;j++)
1.388 + {
1.389 + //aX*HeightInPixels()+aY
1.390 + if ((*iFrameNext)[i*h+j]!=(*iFramePrevious)[i*h+j])
1.391 + {
1.392 + //We need to update that pixel
1.393 + SetPixelBlock(i,j,0,1,((*iFrameNext)[i*h+j]?0x01:0x00));
1.394 + //SetDisplayPosition(iDisplayPositionX,OffScreenY());
1.395 + //SetDisplayPosition(iDisplayPositionX,OffScreenY());
1.396 +
1.397 + //SetPixelBlock(i,j,15,32,iNextFrame->Ptr()+offset);
1.398 + }
1.399 + }
1.400 + }
1.401 + */
1.402 +
1.403 + BitArray nextBlock(KPixelBlockSizeInBits);
1.404 + BitArray previousBlock(KPixelBlockSizeInBits);
1.405 +
1.406 + for (int i=0;i<w;i+=KPixelBlockEdge)
1.407 + {
1.408 + for (int j=0;j<h;j+=KPixelBlockEdge)
1.409 + {
1.410 + //aX*HeightInPixels()+aY
1.411 + //int offset=(i*w/8)+(j/8);
1.412 +
1.413 +#ifdef DEBUG_FRAME_DIFF
1.414 + QImage imagePrevious(KPixelBlockEdge,KPixelBlockEdge,QImage::Format_RGB32);
1.415 + QImage imageNext(KPixelBlockEdge,KPixelBlockEdge,QImage::Format_RGB32);
1.416 +#endif
1.417 +
1.418 + //Get both our blocks from our buffers
1.419 + for (int x=i;x<i+KPixelBlockEdge;x++)
1.420 + {
1.421 + for (int y=j;y<j+KPixelBlockEdge;y++)
1.422 + {
1.423 + int blockOffset=(x-i)*KPixelBlockEdge+(y-j);
1.424 + int frameOffset=x*h+y;
1.425 + nextBlock.SetBitValue(blockOffset,(*iFrameNext)[frameOffset]);
1.426 + previousBlock.SetBitValue(blockOffset,(*iFramePrevious)[frameOffset]);
1.427 +
1.428 +#ifdef DEBUG_FRAME_DIFF
1.429 + imageNext.setPixel(x-i,y-j,(nextBlock[blockOffset]?0xFFFFFFFF:0x00000000));
1.430 + imagePrevious.setPixel(x-i,y-j,(previousBlock[blockOffset]?0xFFFFFFFF:0x00000000));
1.431 +#endif
1.432 + }
1.433 + }
1.434 +
1.435 +#ifdef DEBUG_FRAME_DIFF
1.436 + QString previousName;
1.437 + QString nextName;
1.438 + QTextStream(&previousName) << "p" << i << "x" << j << ".png";
1.439 + QTextStream(&nextName) << "n" << i << "x" << j << ".png";
1.440 + imagePrevious.save(previousName);
1.441 + imageNext.save(nextName);
1.442 +#endif
1.443 +
1.444 +
1.445 + //if (memcmp(iFrameNext->Ptr()+offset,iFramePrevious->Ptr()+offset,32 )) //32=(16*16/8)
1.446 + if (memcmp(nextBlock.Ptr(),previousBlock.Ptr(),KPixelBlockSizeInBytes)!=0)
1.447 + {
1.448 + //We need to update that block
1.449 + SetPixelBlock(i,j,KPixelBlockEdge-1,KPixelBlockSizeInBytes,nextBlock.Ptr());
1.450 + //SetPixelBlock(i,j,15,32,0xFF/*nextBlock.Ptr()*/);
1.451 + //SetDisplayPosition(iDisplayPositionX,OffScreenY());
1.452 + //SetDisplayPosition(iDisplayPositionX,OffScreenY());
1.453 +
1.454 + //SetPixelBlock(i,j,15,32,iFrameNext->Ptr()+offset);
1.455 + }
1.456 + }
1.457 + }
1.458 +
1.459 + }
1.460 +
1.461 +/**
1.462 +Translate the given pixel coordinate according to our off screen mode.
1.463 +*/
1.464 +void GP1212A02A::OffScreenTranslation(unsigned char& aX, unsigned char& aY)
1.465 + {
1.466 + if (OffScreenMode())
1.467 + {
1.468 + aX+=WidthInPixels()-iDisplayPositionX;
1.469 + aY+=HeightInPixels()-iDisplayPositionY;
1.470 + }
1.471 + }
1.472 +
1.473 +
1.474 +/**
1.475 +*/
1.476 +void GP1212A02A::ResetBuffers()
1.477 + {
1.478 + //iNextFrame->ClearAll();
1.479 + //memset(iFrameAlpha,0x00,sizeof(iFrameAlpha));
1.480 + //memset(iFrameBeta,0x00,sizeof(iFrameBeta));
1.481 + }
1.482 +
1.483 +/**
1.484 +*/
1.485 +void GP1212A02A::RequestDeviceId()
1.486 + {
1.487 + if (RequestPending())
1.488 + {
1.489 + //Abort silently for now
1.490 + return;
1.491 + }
1.492 +
1.493 + //1BH,5BH,63H,49H,44H
1.494 + //Send Read ID command
1.495 + FutabaVfdReport report;
1.496 + report[0]=0x00; //Report ID
1.497 + report[1]=0x05; //Report length
1.498 + report[2]=0x1B; //Command ID
1.499 + report[3]=0x5B; //Command ID
1.500 + report[4]=0x63; //Command ID
1.501 + report[5]=0x49; //Command ID
1.502 + report[6]=0x44; //Command ID
1.503 + if (Write(report)==report.Size())
1.504 + {
1.505 + iRequest=EMiniDisplayRequestDeviceId;
1.506 + }
1.507 + }
1.508 +
1.509 +/**
1.510 +*/
1.511 +void GP1212A02A::RequestFirmwareRevision()
1.512 + {
1.513 + if (RequestPending())
1.514 + {
1.515 + //Abort silently for now
1.516 + return;
1.517 + }
1.518 +
1.519 + //1BH,5BH,63H,46H,52H
1.520 + //Send Software Revision Read Command
1.521 + FutabaVfdReport report;
1.522 + report[0]=0x00; //Report ID
1.523 + report[1]=0x05; //Report length
1.524 + report[2]=0x1B; //Command ID
1.525 + report[3]=0x5B; //Command ID
1.526 + report[4]=0x63; //Command ID
1.527 + report[5]=0x46; //Command ID
1.528 + report[6]=0x52; //Command ID
1.529 + if (Write(report)==report.Size())
1.530 + {
1.531 + iRequest=EMiniDisplayRequestFirmwareRevision;
1.532 + }
1.533 + }
1.534 +
1.535 +/**
1.536 +*/
1.537 +void GP1212A02A::RequestPowerSupplyStatus()
1.538 + {
1.539 + if (RequestPending())
1.540 + {
1.541 + //Abort silently for now
1.542 + return;
1.543 + }
1.544 + //1BH,5BH,63H,50H,4DH
1.545 + //Send Power Suppply Monitor Command
1.546 + FutabaVfdReport report;
1.547 + report[0]=0x00; //Report ID
1.548 + report[1]=0x05; //Report length
1.549 + report[2]=0x1B; //Command ID
1.550 + report[3]=0x5B; //Command ID
1.551 + report[4]=0x63; //Command ID
1.552 + report[5]=0x50; //Command ID
1.553 + report[6]=0x4D; //Command ID
1.554 + if (Write(report)==report.Size())
1.555 + {
1.556 + iRequest=EMiniDisplayRequestPowerSupplyStatus;
1.557 + }
1.558 + }
1.559 +
1.560 +
1.561 +/**
1.562 +This is for development purposes only.
1.563 +Production application should stick to off-screen mode to avoid tearing.
1.564 +*/
1.565 +void GP1212A02A::ToggleOffScreenMode()
1.566 + {
1.567 + SetOffScreenMode(!iOffScreenMode);
1.568 + }
1.569 +
1.570 +/**
1.571 + * @brief GP1212A02A::SetOffScreenMode
1.572 + * @param aOn
1.573 + * @return
1.574 + */
1.575 +void GP1212A02A::SetOffScreenMode(bool aOn)
1.576 + {
1.577 + if (aOn==iOffScreenMode)
1.578 + {
1.579 + //Nothing to do here
1.580 + return;
1.581 + }
1.582 +
1.583 + iOffScreenMode=aOn;
1.584 +
1.585 + //Clean up our buffers upon switching modes
1.586 + SetDisplayPosition(0,0);
1.587 + Clear();
1.588 + SwapBuffers();
1.589 + Clear();
1.590 + }
1.591 +
1.592 +/**
1.593 +Tries to complete our current request if we have one pending.
1.594 + */
1.595 +TMiniDisplayRequest GP1212A02A::AttemptRequestCompletion()
1.596 + {
1.597 + if (!RequestPending())
1.598 + {
1.599 + return EMiniDisplayRequestNone;
1.600 + }
1.601 +
1.602 + int res=Read(iInputReport);
1.603 +
1.604 + if (!res)
1.605 + {
1.606 + return EMiniDisplayRequestNone;
1.607 + }
1.608 +
1.609 + //Process our request
1.610 + if (CurrentRequest()==EMiniDisplayRequestPowerSupplyStatus)
1.611 + {
1.612 + if (iInputReport[1]==0x4F && iInputReport[2]==0x4E)
1.613 + {
1.614 + iPowerOn = true;
1.615 + }
1.616 + else if (iInputReport[1]==0x4F && iInputReport[2]==0x46 && iInputReport[3]==0x46)
1.617 + {
1.618 + iPowerOn = false;
1.619 + }
1.620 + }
1.621 + else if (CurrentRequest()==EMiniDisplayRequestDeviceId)
1.622 + {
1.623 + unsigned char* ptr=&iInputReport[1];
1.624 + strcpy(iDeviceId,(const char*)ptr);
1.625 + }
1.626 + else if (CurrentRequest()==EMiniDisplayRequestFirmwareRevision)
1.627 + {
1.628 + unsigned char* ptr=&iInputReport[1];
1.629 + strcpy(iFirmwareRevision,(const char*)ptr);
1.630 + }
1.631 +
1.632 + TMiniDisplayRequest completed=iRequest;
1.633 + //Our request was completed
1.634 + iRequest=EMiniDisplayRequestNone;
1.635 +
1.636 + return completed;
1.637 + }
1.638 +
1.639 +
1.640 +/**
1.641 +Set our screen brightness.
1.642 +@param The desired brightness level. Must be between MinBrightness and MaxBrightness.
1.643 +*/
1.644 +void GP1212A02A::SetBrightness(int aBrightness)
1.645 + {
1.646 + if (aBrightness<MinBrightness()||aBrightness>MaxBrightness())
1.647 + {
1.648 + //Brightness out of range.
1.649 + //Just ignore that request.
1.650 + return;
1.651 + }
1.652 +
1.653 + FutabaVfdReport report;
1.654 + report[0]=0x00; //Report ID
1.655 + report[1]=0x04; //Report size
1.656 + report[2]=0x1B; //Command ID
1.657 + report[3]=0x4A; //Command ID
1.658 + report[4]=0x44; //Command ID
1.659 + report[7]=0x30+aBrightness; //Brightness level
1.660 + Write(report);
1.661 + }
1.662 +
1.663 +/**
1.664 +*/
1.665 +bool GP1212A02A::PowerOn()
1.666 + {
1.667 + return iPowerOn;
1.668 + }
1.669 +
1.670 +/**
1.671 +*/
1.672 +char* GP1212A02A::DeviceId()
1.673 + {
1.674 + return iDeviceId;
1.675 + }
1.676 +
1.677 +/**
1.678 +*/
1.679 +char* GP1212A02A::FirmwareRevision()
1.680 + {
1.681 + return iFirmwareRevision;
1.682 + }