1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/MiniDisplay/FutabaVfd.cpp Tue May 27 19:50:28 2014 +0200
1.3 @@ -0,0 +1,446 @@
1.4 +
1.5 +#include "FutabaVfd.h"
1.6 +//#include <stdlib.h>
1.7 +#include <string.h>
1.8 +
1.9 +
1.10 +//
1.11 +//
1.12 +//
1.13 +
1.14 +
1.15 +
1.16 +
1.17 +
1.18 +//
1.19 +//
1.20 +//
1.21 +
1.22 +FutabaVfdCommand::FutabaVfdCommand():/*iBuffer(NULL),*/iSize(0),iMaxSize(0)
1.23 + {
1.24 + }
1.25 +
1.26 +FutabaVfdCommand::~FutabaVfdCommand()
1.27 + {
1.28 + //Delete();
1.29 + }
1.30 +
1.31 +
1.32 +/**
1.33 +
1.34 +*/
1.35 +void FutabaVfdCommand::Reset()
1.36 + {
1.37 + memset(iReports,0,sizeof(iReports));
1.38 + }
1.39 +
1.40 +
1.41 +
1.42 +/**
1.43 +
1.44 +*/
1.45 +/*
1.46 +void FutabaVfdCommand::Create(int aMaxSize)
1.47 + {
1.48 + iBuffer=new unsigned char[aMaxSize];
1.49 + if (iBuffer)
1.50 + {
1.51 + iMaxSize = aMaxSize;
1.52 + iSize = 0;
1.53 + }
1.54 + }
1.55 +*/
1.56 +
1.57 +/**
1.58 +
1.59 +*/
1.60 +/*
1.61 +void FutabaVfdCommand::Delete()
1.62 +{
1.63 + delete[] iBuffer;
1.64 + iBuffer = NULL;
1.65 + iMaxSize = 0;
1.66 + iSize = 0;
1.67 +}
1.68 +*/
1.69 +
1.70 +
1.71 +
1.72 +
1.73 +//
1.74 +// class GP1212A01A
1.75 +//
1.76 +
1.77 +GP1212A01A::GP1212A01A():
1.78 + iDisplayPositionX(0),iDisplayPositionY(0),
1.79 + iOffScreenMode(true),iFrameBuffer(NULL)
1.80 + {
1.81 + //ResetBuffers();
1.82 + }
1.83 +
1.84 +/**
1.85 +*/
1.86 +GP1212A01A::~GP1212A01A()
1.87 + {
1.88 + delete iFrameBuffer;
1.89 + iFrameBuffer=NULL;
1.90 + }
1.91 +
1.92 +/**
1.93 +*/
1.94 +int GP1212A01A::Open()
1.95 + {
1.96 + int success = HidDevice::Open(KFutabaVendorId,KFutabaProductIdGP1212A01A,NULL);
1.97 + if (success)
1.98 + {
1.99 + delete iFrameBuffer;
1.100 + iFrameBuffer = NULL;
1.101 + iFrameBuffer=new BitArray(KGP12xFrameBufferPixelCount);
1.102 + SetNonBlocking(1);
1.103 + //Since we can't get our display position we for it to our default
1.104 + //This makes sure frames are in sync from the start
1.105 + SetDisplayPosition(iDisplayPositionX,iDisplayPositionY);
1.106 + //Now clear both front and back buffer on host and device
1.107 + Clear();
1.108 + SwapBuffers();
1.109 + Clear();
1.110 + SwapBuffers();
1.111 + }
1.112 + return success;
1.113 + }
1.114 +
1.115 +/**
1.116 +*/
1.117 +void GP1212A01A::SetPixel(unsigned char aX, unsigned char aY, bool aOn)
1.118 + {
1.119 + //Just specify a one pixel block
1.120 + //SetPixelBlock(aX,aY,0x00,0x01,aOn);
1.121 + //
1.122 + //int byteOffset=(aX*HeightInPixels()+aY)/8;
1.123 + //int bitOffset=(aX*HeightInPixels()+aY)%8;
1.124 + //iFrameBuffer[byteOffset] |= ( (aOn?0x01:0x00) << bitOffset );
1.125 + if (aOn)
1.126 + {
1.127 + iFrameBuffer->SetBit(aX*HeightInPixels()+aY);
1.128 + }
1.129 + else
1.130 + {
1.131 + iFrameBuffer->ClearBit(aX*HeightInPixels()+aY);
1.132 + }
1.133 + }
1.134 +
1.135 +/**
1.136 +*/
1.137 +void GP1212A01A::BitBlit(BitArray& aBitmap, int aSrcWidth, int aSrcHeight, int aTargetX, int aTargetY) const
1.138 + {
1.139 + //TODO: amend loop values so that we don't keep on looping past our frame buffer dimensions.
1.140 + for (int i=0;i<aSrcWidth;i++)
1.141 + {
1.142 + for (int j=0;j<aSrcHeight;j++)
1.143 + {
1.144 + iFrameBuffer->SetBitValue((aTargetX+i)*HeightInPixels()+aTargetY+j,aBitmap[+i*aSrcHeight+j]);
1.145 + }
1.146 + }
1.147 + }
1.148 +
1.149 +/**
1.150 +Set all pixels on our screen to the desired value.
1.151 +This operation is performed off screen to avoid tearing.
1.152 +@param 8 pixels pattern
1.153 +*/
1.154 +void GP1212A01A::SetAllPixels(unsigned char aPattern)
1.155 + {
1.156 + //With a single buffer
1.157 + //unsigned char screen[2048]; //One screen worth of pixels
1.158 + //memset(screen,0xFF,sizeof(screen));
1.159 + //SetPixelBlock(0,0,63,sizeof(screen),screen);
1.160 +
1.161 + //Using pattern SetPixelBlock variant.
1.162 + memset(iFrameBuffer->Ptr(),aPattern,FrameBufferSizeInBytes());
1.163 + //
1.164 +
1.165 +
1.166 + }
1.167 +
1.168 +/**
1.169 +Set our screen brightness.
1.170 +@param The desired brightness level. Must be between MinBrightness and MaxBrightness.
1.171 +*/
1.172 +void GP1212A01A::SetBrightness(int aBrightness)
1.173 + {
1.174 + if (aBrightness<MinBrightness()||aBrightness>MaxBrightness())
1.175 + {
1.176 + //Brightness out of range.
1.177 + //Just ignore that request.
1.178 + return;
1.179 + }
1.180 +
1.181 + FutabaVfdReport report;
1.182 + report[0]=0x00; //Report ID
1.183 + report[1]=0x06; //Report size
1.184 + report[2]=0x1B; //Command ID
1.185 + report[3]=0x5C; //Command ID
1.186 + report[4]=0x3F; //Command ID
1.187 + report[5]=0x4C; //Command ID
1.188 + report[6]=0x44; //Command ID
1.189 + report[7]=0x30+aBrightness; //Brightness level
1.190 + Write(report);
1.191 +
1.192 + }
1.193 +
1.194 +/**
1.195 +Set the defined pixel block to the given value.
1.196 +@param X coordinate of our pixel block starting point.
1.197 +@param Y coordinate of our pixel block starting point.
1.198 +@param The height of our pixel block.
1.199 +@param The size of our pixel data. Number of pixels divided by 8.
1.200 +@param The value set to 8 pixels used as a pattern.
1.201 +*/
1.202 +void GP1212A01A::SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char aValue)
1.203 + {
1.204 + OffScreenTranslation(aX,aY);
1.205 + FutabaVfdReport report;
1.206 + report[0]=0x00; //Report ID
1.207 + 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.208 + report[2]=0x1B; //Command ID
1.209 + report[3]=0x5B; //Command ID
1.210 + report[4]=0xF0; //Command ID
1.211 + report[5]=aX; //X
1.212 + report[6]=aY; //Y
1.213 + 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.214 + report[8]=aSize>>8; //Size of pixel data in bytes (MSB)
1.215 + report[9]=aSize; //Size of pixel data in bytes (LSB)
1.216 + int sizeWritten=MIN(aSize,report.Size()-10);
1.217 + memset(report.Buffer()+10, aValue, sizeWritten);
1.218 + Write(report);
1.219 +
1.220 + int remainingSize=aSize;
1.221 + //We need to keep on sending our pixel data until we are done
1.222 + while (report[1]==64)
1.223 + {
1.224 + report.Reset();
1.225 + remainingSize-=sizeWritten;
1.226 + report[0]=0x00; //Report ID
1.227 + report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
1.228 + sizeWritten=(report[1]==64?63:report[1]);
1.229 + memset(report.Buffer()+2, aValue, sizeWritten);
1.230 + Write(report);
1.231 + }
1.232 + }
1.233 +
1.234 +/**
1.235 +Set the defined pixel block to the given value.
1.236 +@param X coordinate of our pixel block starting point.
1.237 +@param Y coordinate of our pixel block starting point.
1.238 +@param The height of our pixel block.
1.239 +@param The size of our pixel data. Number of pixels divided by 8.
1.240 +@param Pointer to our pixel data.
1.241 +*/
1.242 +void GP1212A01A::SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char* aPixels)
1.243 + {
1.244 + OffScreenTranslation(aX,aY);
1.245 + FutabaVfdReport report;
1.246 + report[0]=0x00; //Report ID
1.247 + 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.248 + report[2]=0x1B; //Command ID
1.249 + report[3]=0x5B; //Command ID
1.250 + report[4]=0xF0; //Command ID
1.251 + report[5]=aX; //X
1.252 + report[6]=aY; //Y
1.253 + 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.254 + report[8]=aSize>>8; //Size of pixel data in bytes (MSB)
1.255 + report[9]=aSize; //Size of pixel data in bytes (LSB)
1.256 + int sizeWritten=MIN(aSize,report.Size()-10);
1.257 + memcpy(report.Buffer()+10, aPixels, sizeWritten);
1.258 + Write(report);
1.259 +
1.260 + int remainingSize=aSize;
1.261 + //We need to keep on sending our pixel data until we are done
1.262 + while (report[1]==64)
1.263 + {
1.264 + report.Reset();
1.265 + remainingSize-=sizeWritten;
1.266 + report[0]=0x00; //Report ID
1.267 + report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
1.268 + sizeWritten=(report[1]==64?63:report[1]);
1.269 + memcpy(report.Buffer()+2, aPixels+(aSize-remainingSize), sizeWritten);
1.270 + Write(report);
1.271 + }
1.272 + }
1.273 +
1.274 +
1.275 +/**
1.276 +Clear our client side back buffer.
1.277 +Call to SwapBuffers must follow to actually clear the display.
1.278 +*/
1.279 +void GP1212A01A::Clear()
1.280 + {
1.281 + //memset(iFrameBuffer->Ptr(),0x00,FrameBufferSizeInBytes());
1.282 + iFrameBuffer->ClearAll();
1.283 + }
1.284 +
1.285 +/**
1.286 +Using this function is advised against as is causes tearing.
1.287 +Use Clear instead.
1.288 +*/
1.289 +void GP1212A01A::SendClearCommand()
1.290 + {
1.291 + //1BH,5BH,32H,4AH
1.292 + //Send Clear Display Command
1.293 + FutabaVfdReport report;
1.294 + report[0]=0x00; //Report ID
1.295 + report[1]=0x04; //Report length
1.296 + report[2]=0x1B; //Command ID
1.297 + report[3]=0x5B; //Command ID
1.298 + report[4]=0x32; //Command ID
1.299 + report[5]=0x4A; //Command ID
1.300 + Write(report);
1.301 + }
1.302 +
1.303 +/**
1.304 +Change our display position within our buffer.
1.305 +*/
1.306 +void GP1212A01A::SetDisplayPosition(DW aDw,unsigned char aX, unsigned char aY)
1.307 + {
1.308 + //1BH,5BH,Dw,Px,Py
1.309 + //Send Display Position Settings Command
1.310 + FutabaVfdReport report;
1.311 + report[0]=0x00; //Report ID
1.312 + report[1]=0x05; //Report length
1.313 + report[2]=0x1B; //Command ID
1.314 + report[3]=0x5B; //Command ID
1.315 + report[4]=aDw; //Specify our DW
1.316 + report[5]=aX; //X coordinate of our DW top-left corner
1.317 + report[6]=aY; //Y coordinate of our DW top-left corner
1.318 + Write(report);
1.319 + }
1.320 +
1.321 +/**
1.322 +Change our display position within our buffer.
1.323 +*/
1.324 +void GP1212A01A::SetDisplayPosition(unsigned char aX, unsigned char aY)
1.325 + {
1.326 + //Specs apparently says both DW should remain the same
1.327 + //Just don't ask
1.328 + SetDisplayPosition(GP1212A01A::DW1,aX,aY);
1.329 + SetDisplayPosition(GP1212A01A::DW2,aX,aY);
1.330 + iDisplayPositionX=aX;
1.331 + iDisplayPositionY=aY;
1.332 + }
1.333 +
1.334 +/**
1.335 +Provide Y coordinate of our off screen buffer.
1.336 +*/
1.337 +unsigned char GP1212A01A::OffScreenY() const
1.338 + {
1.339 + //Overflowing is fine this is just what we want
1.340 + return iDisplayPositionY+HeightInPixels();
1.341 + }
1.342 +
1.343 +/**
1.344 +Put our off screen buffer on screen.
1.345 +On screen buffer goes off screen.
1.346 +*/
1.347 +void GP1212A01A::SwapBuffers()
1.348 + {
1.349 + //Only perform buffer swapping if off screen mode is enabled
1.350 + if (OffScreenMode())
1.351 + {
1.352 + //Send host back buffer to device back buffer
1.353 + SetPixelBlock(0,0,63,FrameBufferSizeInBytes(),iFrameBuffer->Ptr());
1.354 + //Swap device front and back buffer
1.355 + SetDisplayPosition(iDisplayPositionX,OffScreenY());
1.356 + //Swap host buffers
1.357 + //unsigned char* backBuffer=iBackBuffer;
1.358 + //iBackBuffer = iFrontBuffer;
1.359 + //iFrontBuffer = backBuffer;
1.360 + }
1.361 + }
1.362 +
1.363 +/**
1.364 +Translate the given pixel coordinate according to our off screen mode.
1.365 +*/
1.366 +void GP1212A01A::OffScreenTranslation(unsigned char& aX, unsigned char& aY)
1.367 + {
1.368 + if (OffScreenMode())
1.369 + {
1.370 + aX+=WidthInPixels()-iDisplayPositionX;
1.371 + aY+=HeightInPixels()-iDisplayPositionY;
1.372 + }
1.373 + }
1.374 +
1.375 +
1.376 +/**
1.377 +*/
1.378 +void GP1212A01A::ResetBuffers()
1.379 + {
1.380 + //iFrameBuffer->ClearAll();
1.381 + //memset(iFrameBuffer,0x00,sizeof(iFrameBuffer));
1.382 + //memset(iFrameBeta,0x00,sizeof(iFrameBeta));
1.383 + }
1.384 +
1.385 +/**
1.386 +*/
1.387 +void GP1212A01A::RequestId()
1.388 + {
1.389 + //1BH,5BH,63H,49H,44H
1.390 + //Send Read ID command
1.391 + FutabaVfdReport report;
1.392 + report[0]=0x00; //Report ID
1.393 + report[1]=0x05; //Report length
1.394 + report[2]=0x1B; //Command ID
1.395 + report[3]=0x5B; //Command ID
1.396 + report[4]=0x63; //Command ID
1.397 + report[5]=0x49; //Command ID
1.398 + report[6]=0x44; //Command ID
1.399 + Write(report);
1.400 + }
1.401 +
1.402 +/**
1.403 +*/
1.404 +void GP1212A01A::RequestFirmwareRevision()
1.405 + {
1.406 + //1BH,5BH,63H,46H,52H
1.407 + //Send Software Revision Read Command
1.408 + FutabaVfdReport report;
1.409 + report[0]=0x00; //Report ID
1.410 + report[1]=0x05; //Report length
1.411 + report[2]=0x1B; //Command ID
1.412 + report[3]=0x5B; //Command ID
1.413 + report[4]=0x63; //Command ID
1.414 + report[5]=0x46; //Command ID
1.415 + report[6]=0x52; //Command ID
1.416 + Write(report);
1.417 + }
1.418 +
1.419 +/**
1.420 +*/
1.421 +void GP1212A01A::RequestPowerSupplyStatus()
1.422 + {
1.423 + //1BH,5BH,63H,50H,4DH
1.424 + //Send Power Suppply Monitor Command
1.425 + FutabaVfdReport report;
1.426 + report[0]=0x00; //Report ID
1.427 + report[1]=0x05; //Report length
1.428 + report[2]=0x1B; //Command ID
1.429 + report[3]=0x5B; //Command ID
1.430 + report[4]=0x63; //Command ID
1.431 + report[5]=0x50; //Command ID
1.432 + report[6]=0x4D; //Command ID
1.433 + Write(report);
1.434 + }
1.435 +
1.436 +
1.437 +/**
1.438 +This is for development purposes only.
1.439 +Production application should stick to off-screen mode to avoid tearing.
1.440 +*/
1.441 +void GP1212A01A::ToggleOffScreenMode()
1.442 + {
1.443 + iOffScreenMode=!iOffScreenMode;
1.444 + //Clean up our buffers upon switching modes
1.445 + SetDisplayPosition(0,0);
1.446 + Clear();
1.447 + SwapBuffers();
1.448 + Clear();
1.449 + }
1.450 \ No newline at end of file