sl@8: //
StephaneLenclud@35: // Copyright (C) 2014-2015 Stéphane Lenclud.
sl@8: //
StephaneLenclud@35: // This file is part of MiniDisplay.
StephaneLenclud@35: //
StephaneLenclud@35: // MiniDisplay is free software: you can redistribute it and/or modify
StephaneLenclud@35: // it under the terms of the GNU General Public License as published by
StephaneLenclud@35: // the Free Software Foundation, either version 3 of the License, or
StephaneLenclud@35: // (at your option) any later version.
StephaneLenclud@35: //
StephaneLenclud@35: // MiniDisplay is distributed in the hope that it will be useful,
StephaneLenclud@35: // but WITHOUT ANY WARRANTY; without even the implied warranty of
StephaneLenclud@35: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
StephaneLenclud@35: // GNU General Public License for more details.
StephaneLenclud@35: //
StephaneLenclud@35: // You should have received a copy of the GNU General Public License
StephaneLenclud@35: // along with MiniDisplay. If not, see .
sl@8: //
sl@8:
sl@10: #include "FutabaGP1212A02.h"
sl@10:
sl@17: #include
sl@17: #include
sl@10:
sl@15: const unsigned short KMaxDataMemoryAddress = 0x4FFF;
sl@15: const unsigned short KFrameSizeInBytes = 0x800;
sl@15:
sl@20:
StephaneLenclud@25: static void sleep(unsigned int mseconds)
sl@20: {
sl@20: clock_t goal = mseconds + clock();
sl@20: while (goal > clock());
sl@20: }
sl@20:
sl@10: //
sl@10: // class GP1212A02A
sl@10: //
sl@10:
sl@10: GP1212A02A::GP1212A02A():
sl@10: iDisplayPositionX(0),iDisplayPositionY(0),
sl@10: iOffScreenMode(true),
sl@10: iUseFrameDifferencing(true),
sl@10: iFrameNext(NULL),
sl@10: iFrameCurrent(NULL),
sl@10: iFramePrevious(NULL),
sl@10: iFrameAlpha(NULL),
sl@10: iFrameBeta(NULL),
sl@10: iFrameGamma(NULL),
StephaneLenclud@29: iNeedFullFrameUpdate(0)
sl@10: {
sl@10: iDeviceId[0]=0;
sl@10: iFirmwareRevision[0]=0;
sl@10: //ResetBuffers();
sl@10: }
sl@10:
sl@10: /**
sl@10: */
sl@10: GP1212A02A::~GP1212A02A()
sl@10: {
sl@10: delete iFrameAlpha;
sl@10: iFrameAlpha=NULL;
sl@10: //
sl@10: delete iFrameBeta;
sl@10: iFrameBeta=NULL;
sl@10: //
sl@10: delete iFrameGamma;
sl@10: iFrameGamma=NULL;
sl@10: //
sl@10: iFrameNext=NULL;
sl@10: iFrameCurrent=NULL;
sl@10: iFramePrevious=NULL;
sl@10: //
sl@10: iNeedFullFrameUpdate=0;
sl@10: }
sl@10:
sl@10: /**
sl@10: */
sl@10: int GP1212A02A::Open()
sl@10: {
sl@10: int success = HidDevice::Open(KFutabaVendorId,KFutabaProductIdGP1212A02A,NULL);
sl@10: if (success)
sl@10: {
sl@10: //Allocate both frames
sl@10: delete iFrameAlpha;
sl@10: iFrameAlpha=NULL;
sl@13: iFrameAlpha=new BitArrayLow(KGP12xFrameBufferPixelCount);
sl@10: //
sl@10: delete iFrameBeta;
sl@10: iFrameBeta=NULL;
sl@13: iFrameBeta=new BitArrayLow(KGP12xFrameBufferPixelCount);
sl@10: //
sl@10: delete iFrameGamma;
sl@10: iFrameGamma=NULL;
sl@13: iFrameGamma=new BitArrayLow(KGP12xFrameBufferPixelCount);
sl@10: //
sl@10: iFrameNext=iFrameAlpha;
sl@10: iFrameCurrent=iFrameBeta;
sl@10: iFramePrevious=iFrameGamma;
sl@10:
sl@10:
sl@10: //To make sure it is synced properly
sl@10: iNeedFullFrameUpdate=0;
sl@10: //
sl@10: SetNonBlocking(1);
sl@13: //
sl@17: SendCommandClear();
sl@17: //
sl@17: SetClockSetting();
sl@14:
sl@17: //BMP box setup could be removed if we don't use it anymore
sl@14: //Setup BMP box
sl@14: BmpBoxSetting(EBmpBoxIdOne,0x0000,256,64);
sl@14: //Select current BMP box
sl@14: BmpBoxSelect(EBmpBoxIdOne);
sl@17: //
sl@17: iNextFrameAddress = 0x0000;
sl@14:
sl@20: //Beta font test
sl@21: /*
sl@21: SendCommandFontAction(EFontDelete);
sl@21:
sl@21: //SendCommandSelectFontSize(EFontLarge);
sl@20: //SendCommandReset();
sl@20:
sl@21:
sl@21:
sl@20: unsigned char charPixels[]={ 0xFF,0xFF,0xFF,0xFF,
sl@20: 0x80,0x00,0x00,0x01,
sl@20: 0x80,0x00,0x00,0x01,
sl@20: 0x80,0x00,0x00,0x01,
sl@20: 0x80,0x00,0x00,0x01,
sl@20: 0x80,0x00,0x00,0x01,
sl@20: 0x80,0x00,0x00,0x01,
sl@20: 0x81,0xFF,0xFF,0xE1,
sl@20: 0x80,0x00,0x00,0x01,
sl@20: 0x80,0x00,0x00,0x01,
sl@20: 0x80,0x00,0x00,0x01,
sl@20: 0x80,0x00,0x00,0x01,
sl@20: 0x80,0x00,0x00,0x01,
sl@20: 0x80,0x00,0x00,0x01,
sl@20: 0x80,0x00,0x00,0x01,
sl@20: 0xFF,0xFF,0xFF,0xFF};
sl@20:
sl@20:
sl@21: //SendCommandFontAction(EFontStore);
sl@20: for (unsigned short i=0;i<16;i++)
sl@20: {
sl@21: //SendCommandFontAction(EFontDelete);
sl@21:
sl@20: SendCommandDefineCharacter(EFont16x32,0x0030+i,charPixels);
sl@20: //SendCommandFontAction(EFontStore);
sl@21:
sl@21:
sl@20: //sleep(100);
sl@20: }
sl@20: */
sl@21: //SendCommandFontAction(EFontTransfer);
sl@20:
sl@20:
sl@20: //SendCommandDefineCharacter(EFont16x32,0x0031,charPixels);
sl@20: //SendCommandFontAction(EFontStore);
sl@20:
sl@20:
sl@20: //
sl@20:
sl@17:
sl@14:
sl@10: }
sl@10: return success;
sl@10: }
sl@10:
sl@10: /**
sl@14: Setting the BMP box
sl@14: [Code] 1BH,5CH,42H,Pn,aL,aH,Pw,Ph
sl@14: [Function] Setting the BMP box. BMP box can be defined the 3 area to DW. The position of BMP
sl@14: box is set based on the address of DW.
sl@14: * To write data in BMP box, BMP box select is necessary.
sl@14: * Specifiable horizontal size is 256dot (100H) MAX. If horizontal size specify 256dot, Pw = 00H
sl@14: Pn = Number of a BMP box
sl@14: aL = Lower byte of address
sl@14: aH = Upper byte of address
sl@14: Pw = BMP box width
sl@14: Ph = BMP box height
sl@14:
sl@14: [Definable area]
sl@14: Pn = 31H - BMP box 1
sl@14: Pn = 32H - BMP box 2
sl@14: Pn = 33H - BMP box 3
sl@14: 0000H <= aL + aH * 100 <= 07FFH
sl@14: 01H <= Pw <= 00H (=100H)
sl@14: 01H <= Ph <= 08H
sl@14: */
sl@14: void GP1212A02A::BmpBoxSetting(TBmpBoxId aBoxId, unsigned short aAddress, int aWidth, int aHeight)
sl@14: {
sl@14: //TODO: check parameters validity
sl@14: //1BH,5CH,42H,Pn,aL,aH,Pw,Ph
sl@14: FutabaVfdReport report;
sl@14: report[0]=0x00; //Report ID
sl@14: report[1]=0x08; //Report length.
sl@14: report[2]=0x1B; //Command ID
sl@14: report[3]=0x5C; //Command ID
sl@14: report[4]=0x42; //Command ID
sl@14: report[5]=aBoxId;
sl@14: report[6]=(unsigned char)aAddress; //aL = DM lower byte
sl@14: report[7]=aAddress>>8; //aH = DM upper byte
sl@14: report[8]=(aWidth==256?0x00:aWidth); //Pw = BMP box width 00==256
sl@14: report[9]=aHeight/8; //Ph = BMP box height.
sl@14: Write(report);
sl@14: }
sl@14:
sl@14: /**
sl@14: [Code]1BH,5CH,48H,Pn
sl@14: [Function]Select of BMP box
sl@14: * Execution "BMP box select" is necessary before "Setting the Text box".
sl@14: * In case of writing by the specified dot writing, it is necessary to cancel this command.
sl@14: [Definable area]
sl@14: Pn = 30H - Remove the BMP box
sl@14: Pn = 31H - BMP box 1
sl@14: Pn = 32H - BMP box 2
sl@14: Pn = 33H - BMP box 3
sl@14: */
sl@14: void GP1212A02A::BmpBoxSelect(TBmpBoxId aBoxId)
sl@14: {
sl@14: //TODO: check parameters validity
sl@14: FutabaVfdReport report;
sl@14: report[0]=0x00; //Report ID
sl@14: report[1]=0x04; //Report length.
sl@14: report[2]=0x1B; //Command ID
sl@14: report[3]=0x5C; //Command ID
sl@14: report[4]=0x48; //Command ID
sl@14: report[5]=aBoxId; //BMP box ID
sl@14: Write(report);
sl@14: }
sl@14:
sl@14:
sl@14: /**
sl@10: */
sl@22: void GP1212A02A::SetPixel(unsigned char aX, unsigned char aY, unsigned int aPixel)
sl@10: {
sl@10: //
sl@10: //int byteOffset=(aX*HeightInPixels()+aY)/8;
sl@10: //int bitOffset=(aX*HeightInPixels()+aY)%8;
sl@10: //iNextFrame[byteOffset] |= ( (aOn?0x01:0x00) << bitOffset );
sl@10:
sl@22: //Pixel is on if any of the non-alpha component is not null
sl@22: bool on = (aPixel&0x00FFFFFF)!=0x00000000;
sl@22:
sl@10: if (iOffScreenMode)
sl@10: {
sl@22: if (on)
sl@10: {
sl@10: iFrameNext->SetBit(aX*HeightInPixels()+aY);
sl@10: }
sl@10: else
sl@10: {
sl@10: iFrameNext->ClearBit(aX*HeightInPixels()+aY);
sl@10: }
sl@10: }
sl@10: else
sl@10: {
sl@10: //Just specify a one pixel block
sl@13: //TODO
sl@10: }
sl@10: }
sl@10:
sl@10: /**
sl@10: */
sl@13: /*
sl@10: void GP1212A02A::BitBlit(const BitArray& aBitmap, int aSrcWidth, int aSrcHeight, int aTargetX, int aTargetY) const
sl@10: {
sl@10: //TODO: amend loop values so that we don't keep on looping past our frame buffer dimensions.
sl@10: for (int i=0;iSetBitValue((aTargetX+i)*HeightInPixels()+aTargetY+j,aBitmap[+i*aSrcHeight+j]);
sl@10: }
sl@10: }
sl@10: }
sl@13: */
sl@10:
sl@10: /**
sl@10: Clear our client side back buffer.
sl@10: Call to SwapBuffers must follow to actually clear the display.
sl@10: */
sl@10: void GP1212A02A::Clear()
sl@10: {
sl@10: //memset(iNextFrame->Ptr(),0x00,FrameBufferSizeInBytes());
sl@10: if (iOffScreenMode)
sl@10: {
sl@10: iFrameNext->ClearAll();
sl@10: }
sl@10: else
sl@10: {
sl@17: SendCommandClear();
sl@10: }
sl@10: }
sl@10:
sl@10: /**
sl@10: Turn on all pixels.
sl@10: Must be followed by a SwapBuffers call.
sl@10: */
sl@10: void GP1212A02A::Fill()
sl@10: {
sl@10: SetAllPixels(0xFF);
sl@10: }
sl@10:
sl@10: /**
sl@10: Set all pixels on our screen to the desired value.
sl@10: This operation is performed off screen to avoid tearing.
sl@10: @param 8 pixels pattern
sl@10: */
sl@10: void GP1212A02A::SetAllPixels(unsigned char aPattern)
sl@10: {
sl@10: //With a single buffer
sl@10: //unsigned char screen[2048]; //One screen worth of pixels
sl@10: //memset(screen,0xFF,sizeof(screen));
sl@10: //SetPixelBlock(0,0,63,sizeof(screen),screen);
sl@10:
sl@10:
sl@10: if (iOffScreenMode)
sl@10: {
sl@10: memset(iFrameNext->Ptr(),aPattern,FrameBufferSizeInBytes());
sl@10: }
sl@10: else
sl@10: {
sl@10: //Using pattern SetPixelBlock variant.
sl@13: //TODO
sl@10: }
sl@10: //
sl@10: }
sl@10:
sl@10:
sl@13:
sl@13:
sl@10: /**
sl@14: BMP data input
sl@14: [Code] 1BH,4AH,Pm,aL,aH,Ps,nL,nH,Pd...Pd
sl@14: [Function] The BMP data is written in the DW(Display Window) or the Data memory.
sl@14: Pm= DW or Data memory
sl@14: aL = DW lower byte
sl@14: aH = DW upper byte
sl@14: Ps = Direction of writing
sl@14: nL = number of BMP data length lower byte
sl@14: nH = number of BMP data length upper byte
sl@14: Pd = BMP data
sl@14: * If X direction is selected as Ps and data is written in the last address, the data in the last address is
sl@14: overwritten with the remaining data.
sl@14: [Definable area] Pm = 30H : DW
sl@14: Pm = 31H: Data memory
sl@14: 0000H <= aL + aH * 100 <= 07FFH (DW)
sl@14: 0000H <= aL + aH * 100 <= 4FFFH (Data memory)
sl@14: Ps = 30H: Y direction
sl@14: Ps = 31H: X direction
sl@14: 0001H <= nL + nH * 100 <= 0100H(DW: X direction)
sl@14: 0001H <= nL + nH * 100 <= 0800H(DW: Y direction)
sl@14: 0001H <= nL + nH * 100 <= 0A00H(Data memory: X direction)
sl@14: 0001H <= nL + nH * 100 <= 5000H(Data memory: Y direction)
sl@10: */
sl@14: void GP1212A02A::BmpDataInput(TTarget aTarget, unsigned short aAddress, TDirection aDirection, unsigned short aSize, unsigned char* aPixels)
sl@13: {
sl@13: FutabaVfdReport report;
sl@10: report[0]=0x00; //Report ID
sl@10: 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
sl@10: report[2]=0x1B; //Command ID
sl@13: report[3]=0x4A; //Command ID
sl@14: report[4]=aTarget; //Display Window or Data Memory
sl@14: report[5]=(unsigned char)aAddress; //aL = DW lower byte
sl@14: report[6]=aAddress>>8; //aH = DW upper byte
sl@14: report[7]=aDirection; //Direction of writing: Y or X
sl@14: report[8]=(unsigned char)aSize; //Size of pixel data in bytes (LSB)
sl@13: report[9]=aSize>>8; //Size of pixel data in bytes (MSB)
sl@10: int sizeWritten=MIN(aSize,report.Size()-10);
sl@10: memcpy(report.Buffer()+10, aPixels, sizeWritten);
sl@10: Write(report);
sl@10:
sl@10: int remainingSize=aSize;
sl@10: //We need to keep on sending our pixel data until we are done
sl@10: while (report[1]==64)
sl@10: {
sl@10: report.Reset();
sl@10: remainingSize-=sizeWritten;
sl@10: report[0]=0x00; //Report ID
sl@10: report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
sl@10: sizeWritten=(report[1]==64?63:report[1]);
sl@10: memcpy(report.Buffer()+2, aPixels+(aSize-remainingSize), sizeWritten);
sl@10: Write(report);
sl@10: }
sl@13: }
sl@10:
sl@14:
sl@14: /**
sl@14: Data memory transfer
sl@14: [Code] 1BH,5CH,44H,aL,aH
sl@14: [Function] BMP data transfer from Data memory to DW.
sl@14: Although source data is updated, data in BMP box is not updated. To reflect the update,
sl@14: re-executing this command is necessary.
sl@14: aL = Lower byte of address
sl@14: aH = Upper byte of address
sl@14: [Definable area]
sl@14: 0000H <= aL + aH * 100 <= 4FFFH
sl@14: */
sl@14: void GP1212A02A::BmpBoxDataMemoryTransfer(unsigned short aAddress)
sl@14: {
sl@14: FutabaVfdReport report;
sl@14: report[0]=0x00; //Report ID
sl@14: report[1]=0x05; //Report length.
sl@14: report[2]=0x1B; //Command ID
sl@14: report[3]=0x5C; //Command ID
sl@14: report[4]=0x44; //Command ID
sl@14: report[5]=(unsigned char)aAddress; //aL = DM lower byte
sl@14: report[6]=aAddress>>8; //aH = DM upper byte
sl@14: Write(report);
sl@14: }
sl@14:
sl@14: /**
sl@14: Input BMP data in the BMP box
sl@14: [Code] 1BH,5CH,5DH,nL,nH,Pd...Pd
sl@14: [Function] BMP data is written the BMP box
sl@14: * Number of definable data is due to BMP box size. If the data is over range, the over range data is
sl@14: rewritten the final address.
sl@14: nL = Lower byte of number of definition byte
sl@14: nH = Upper byte of number of definition byte
sl@14: Pd = BMP data
sl@14: [Definable area] Pn : BMP box size (Pw * Ph)
sl@14: */
sl@14: void GP1212A02A::BmpBoxDataInput(unsigned short aSize, unsigned char* aPixels)
sl@14: {
sl@14: FutabaVfdReport report;
sl@14: report[0]=0x00; //Report ID
sl@14: report[1]=(aSize<=report.Size()-7?aSize+0x05:64); //Report length. -7 is for our header first 10 bytes. +5 is for our Futaba header size
sl@14: report[2]=0x1B; //Command ID
sl@14: report[3]=0x5C; //Command ID
sl@14: report[4]=0x5D; //Display Window or Data Memory
sl@14: report[5]=(unsigned char)aSize; //Size of pixel data in bytes (LSB)
sl@14: report[6]=aSize>>8; //Size of pixel data in bytes (MSB)
sl@14: int sizeWritten=MIN(aSize,report.Size()-7);
sl@14: memcpy(report.Buffer()+7, aPixels, sizeWritten);
sl@14: Write(report);
sl@14:
sl@14: int remainingSize=aSize;
sl@14: //We need to keep on sending our pixel data until we are done
sl@14: while (report[1]==64)
sl@14: {
sl@14: report.Reset();
sl@14: remainingSize-=sizeWritten;
sl@14: report[0]=0x00; //Report ID
sl@14: report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
sl@14: sizeWritten=(report[1]==64?63:report[1]);
sl@14: memcpy(report.Buffer()+2, aPixels+(aSize-remainingSize), sizeWritten);
sl@14: Write(report);
sl@14: }
sl@14: }
sl@14:
sl@10: /**
sl@10: Using this function is advised against as is causes tearing.
sl@10: Use Clear instead.
sl@10: */
sl@17: void GP1212A02A::SendCommandClear()
sl@10: {
sl@13: //1BH,4AH,43H,44H
sl@10: //Send Clear Display Command
sl@10: FutabaVfdReport report;
sl@10: report[0]=0x00; //Report ID
sl@10: report[1]=0x04; //Report length
sl@10: report[2]=0x1B; //Command ID
sl@13: report[3]=0x4A; //Command ID
sl@13: report[4]=0x43; //Command ID
sl@13: report[5]=0x44; //Command ID
sl@10: Write(report);
sl@10: }
sl@10:
sl@10:
sl@10: /**
sl@20: Returns to default setting.
sl@20: * The other command is not receive until this command complete. Please don’t send the any data
sl@20: from a host during “BUSY”
sl@20: * Delete the User definable font to the RAM.
sl@20: * If the VFD Power Off, VFD Power turn ON after the RESET command.
sl@20: */
sl@20: void GP1212A02A::SendCommandReset()
sl@20: {
sl@20: //1BH,4AH,43H,44H
sl@20: //Send Clear Display Command
sl@20: FutabaVfdReport report;
sl@20: report[0]=0x00; //Report ID
sl@20: report[1]=0x04; //Report length
sl@20: report[2]=0x1B; //Command ID
sl@20: report[3]=0x4A; //Command ID
sl@20: report[4]=0x52; //Command ID
sl@20: report[5]=0x53; //Command ID
sl@20: Write(report);
sl@20: //Wait until reset is done. Is that needed?
sl@20: sleep(2000);
sl@20:
sl@20: }
sl@20:
sl@20:
sl@20: /**
sl@10: Provide Y coordinate of our off screen buffer.
sl@10: */
sl@10: unsigned char GP1212A02A::OffScreenY() const
sl@10: {
sl@10: //Overflowing is fine this is just what we want
sl@10: return iDisplayPositionY+HeightInPixels();
sl@10: }
sl@10:
sl@10: /**
sl@10: Put our off screen buffer on screen.
sl@10: On screen buffer goes off screen.
sl@10: */
sl@10: void GP1212A02A::SwapBuffers()
sl@10: {
sl@10: //Only perform buffer swapping if off screen mode is enabled
sl@10: if (OffScreenMode())
sl@10: {
sl@14: //Send pixel directly into BMP box
sl@15: //BmpBoxDataInput(FrameBufferSizeInBytes(),iFrameNext->Ptr());
StephaneLenclud@23:
StephaneLenclud@23: //This appears to be the fastest scheme when running on our HTPC
sl@14: //Send pixel data directly into the display window
StephaneLenclud@23: BmpDataInput(ETargetDisplayWindow,0x0000,EDirectionY, FrameBufferSizeInBytes(),iFrameNext->Ptr());
StephaneLenclud@23:
sl@14: //Send pixel data first to Data Memory then copy into the selected BMP box
sl@14: //BmpDataInput(ETargetDataMemory,0x0000,EDirectionY, FrameBufferSizeInBytes(),iFrameNext->Ptr());
sl@14: //BmpBoxDataMemoryTransfer(0x0000);
StephaneLenclud@23:
StephaneLenclud@23: //Send pixel data first to Data Memory then copy into the selected BMP box, cycling through our Data Memory frame
StephaneLenclud@23: #if 0
sl@15: BmpDataInput(ETargetDataMemory,iNextFrameAddress,EDirectionY, FrameBufferSizeInBytes(),iFrameNext->Ptr());
sl@15: BmpBoxDataMemoryTransfer(iNextFrameAddress);
sl@15: iNextFrameAddress+=KFrameSizeInBytes;
sl@15: if (iNextFrameAddress>KMaxDataMemoryAddress)
sl@15: {
sl@15: iNextFrameAddress=0x0000;
sl@15: }
StephaneLenclud@23: #endif
sl@10:
sl@10: //Cycle through our frame buffers
sl@10: //We keep track of previous frame which is in fact our device back buffer.
sl@10: //We can then compare previous and next frame and send only the differences to our device.
sl@10: //This mechanism allows us to reduce traffic over our USB bus thus improving our frame rate from 14 FPS to 30 FPS.
sl@10: //Keep our previous frame pointer
sl@13: BitArrayLow* previousFrame=iFramePrevious;
sl@10: //Current frame becomes the previous one
sl@10: iFramePrevious = iFrameCurrent;
sl@10: //Next frame becomes the current one
sl@10: iFrameCurrent = iFrameNext;
sl@10: //Next frame is now our former previous
sl@10: iFrameNext = previousFrame;
sl@10: }
sl@10: }
sl@10:
sl@10:
sl@10: //Define the edge of our pixel block
sl@10: //Pixel blocks of 32x32 seems to run almost as fast as full screen update in worse case scenarii.
sl@10: //Though I wonder if in some situations 16 could be better. Make this an attribute at some point if need be.
sl@10: const int KPixelBlockEdge = 32;
sl@10: const int KPixelBlockSizeInBits = KPixelBlockEdge*KPixelBlockEdge;
sl@10: const int KPixelBlockSizeInBytes = KPixelBlockSizeInBits/8;
sl@10:
sl@10:
sl@10: /**
sl@10: Translate the given pixel coordinate according to our off screen mode.
sl@10: */
sl@10: void GP1212A02A::OffScreenTranslation(unsigned char& aX, unsigned char& aY)
sl@10: {
sl@10: if (OffScreenMode())
sl@10: {
sl@10: aX+=WidthInPixels()-iDisplayPositionX;
sl@10: aY+=HeightInPixels()-iDisplayPositionY;
sl@10: }
sl@10: }
sl@10:
sl@10:
sl@10: /**
sl@10: */
sl@15: void GP1212A02A::Request(TMiniDisplayRequest aRequest)
sl@15: {
sl@15: switch (aRequest)
sl@15: {
sl@15: case EMiniDisplayRequestDeviceId:
sl@15: RequestDeviceId();
sl@15: break;
sl@15: case EMiniDisplayRequestFirmwareRevision:
sl@15: RequestFirmwareRevision();
sl@15: break;
sl@15: case EMiniDisplayRequestPowerSupplyStatus:
sl@15: RequestPowerSupplyStatus();
sl@15: break;
sl@15: default:
sl@15: //Not supported
sl@15: break;
sl@15: };
sl@15: }
sl@15:
sl@15:
sl@15: /**
sl@15: */
sl@10: void GP1212A02A::ResetBuffers()
sl@10: {
sl@10: //iNextFrame->ClearAll();
sl@10: //memset(iFrameAlpha,0x00,sizeof(iFrameAlpha));
sl@10: //memset(iFrameBeta,0x00,sizeof(iFrameBeta));
sl@10: }
sl@10:
sl@10: /**
sl@10: */
sl@10: void GP1212A02A::RequestDeviceId()
sl@10: {
sl@11: //Not supported
sl@10: }
sl@10:
sl@10: /**
sl@15: ID code
sl@15: [Code] 1BH,6AH,49H,44H
sl@15: [Function] Send the ID code to the Host system. ID code is software version.
sl@10: */
sl@10: void GP1212A02A::RequestFirmwareRevision()
sl@10: {
sl@15: if (RequestPending())
sl@15: {
sl@15: //Abort silently for now
sl@15: return;
sl@15: }
sl@15:
sl@15: //1BH,6AH,49H,44H
sl@15: //Send Software Revision Read Command
sl@15: FutabaVfdReport report;
sl@15: report[0]=0x00; //Report ID
sl@15: report[1]=0x04; //Report length
sl@15: report[2]=0x1B; //Command ID
sl@15: report[3]=0x6A; //Command ID
sl@15: report[4]=0x49; //Command ID
sl@15: report[5]=0x44; //Command ID
sl@15: if (Write(report)==report.Size())
sl@15: {
sl@15: SetRequest(EMiniDisplayRequestFirmwareRevision);
sl@15: }
sl@15:
sl@10: }
sl@10:
sl@10: /**
sl@10: */
sl@10: void GP1212A02A::RequestPowerSupplyStatus()
sl@10: {
sl@11: //Not supported
sl@10: }
sl@10:
sl@10:
sl@10: /**
sl@10: This is for development purposes only.
sl@10: Production application should stick to off-screen mode to avoid tearing.
sl@10: */
sl@10: void GP1212A02A::ToggleOffScreenMode()
sl@10: {
sl@10: SetOffScreenMode(!iOffScreenMode);
sl@10: }
sl@10:
sl@10: /**
sl@10: * @brief GP1212A02A::SetOffScreenMode
sl@10: * @param aOn
sl@10: * @return
sl@10: */
sl@10: void GP1212A02A::SetOffScreenMode(bool aOn)
sl@10: {
sl@10: if (aOn==iOffScreenMode)
sl@10: {
sl@10: //Nothing to do here
sl@10: return;
sl@10: }
sl@10:
sl@10: iOffScreenMode=aOn;
sl@10:
sl@10: //Clean up our buffers upon switching modes
sl@10: Clear();
sl@10: SwapBuffers();
sl@10: Clear();
sl@10: }
sl@10:
sl@10: /**
sl@10: Tries to complete our current request if we have one pending.
sl@10: */
sl@10: TMiniDisplayRequest GP1212A02A::AttemptRequestCompletion()
sl@10: {
sl@15: if (!RequestPending())
sl@15: {
sl@15: return EMiniDisplayRequestNone;
sl@15: }
sl@15:
sl@15: int res=Read(iInputReport);
sl@15:
sl@15: if (!res)
sl@15: {
sl@15: return EMiniDisplayRequestNone;
sl@15: }
sl@15:
sl@15: //Process our request
sl@15: if (CurrentRequest()==EMiniDisplayRequestFirmwareRevision)
sl@15: {
sl@15: unsigned char* ptr=&iInputReport[2];
sl@15: iInputReport[7]=0x00;
sl@15: strcpy(iFirmwareRevision,(const char*)ptr);
sl@15: }
sl@15:
sl@15: TMiniDisplayRequest completed=CurrentRequest();
sl@15: //Our request was completed
sl@15: SetRequest(EMiniDisplayRequestNone);
sl@15:
sl@15: return completed;
sl@11: }
sl@10:
sl@10:
sl@10: /**
sl@10: Set our screen brightness.
sl@10: @param The desired brightness level. Must be between MinBrightness and MaxBrightness.
sl@10: */
sl@10: void GP1212A02A::SetBrightness(int aBrightness)
sl@10: {
sl@10: if (aBrightnessMaxBrightness())
sl@10: {
sl@10: //Brightness out of range.
sl@10: //Just ignore that request.
sl@10: return;
sl@10: }
sl@10:
sl@10: FutabaVfdReport report;
sl@10: report[0]=0x00; //Report ID
sl@10: report[1]=0x04; //Report size
sl@10: report[2]=0x1B; //Command ID
sl@10: report[3]=0x4A; //Command ID
sl@10: report[4]=0x44; //Command ID
sl@13: report[5]=0x30+aBrightness; //Brightness level
sl@10: Write(report);
sl@10: }
sl@10:
sl@10: /**
sl@16: VFD Power ON/OFF
sl@16: [Code]1BH,4AH,42H,Ps
sl@16: [Function]Control of the power supply for VFD
sl@16: * If VFD power ON or OFF, at interval of 10s or more.
sl@16: * When the VFD power off, VFD display is turn off, but the module can receive a data and
sl@16: process.
sl@16: Ps = VFD Power control
sl@16: [Definable area]
sl@16: Ps = 30H : VFD Power OFF
sl@16: Ps = 31H : VFD Power ON (Default)
sl@16: */
sl@16: void GP1212A02A::SendCommandPower(TPowerStatus aPowerStatus)
sl@16: {
sl@16: FutabaVfdReport report;
sl@16: report[0]=0x00; //Report ID
sl@16: report[1]=0x04; //Report size
sl@16: report[2]=0x1B; //Command ID
sl@16: report[3]=0x4A; //Command ID
sl@16: report[4]=0x42; //Command ID
sl@16: report[5]=aPowerStatus; //ON or OFF
sl@16: Write(report);
sl@16: }
sl@16:
sl@16: /**
sl@16: */
sl@16: void GP1212A02A::TurnPowerOn()
sl@16: {
sl@16: SendCommandPower(EPowerOn);
sl@17: SetClockSetting();
sl@16: }
sl@16:
sl@16: /**
sl@16: */
sl@16: void GP1212A02A::TurnPowerOff()
sl@16: {
sl@16: SendCommandPower(EPowerOff);
sl@16: }
sl@17:
sl@17:
sl@17: /**
sl@20: Provide the length of our character string for the given clock format.
sl@20: @param The clock format to evaluate.
sl@20: @return Number of characters for the given clock format.
sl@17: */
sl@17: int GP1212A02A::ClockCharCount(TClockFormat aFormat)
sl@17: {
sl@17: switch (aFormat)
sl@17: {
sl@17: case EClockDay12:
sl@19: return 13;
sl@17: case EClockDay24:
sl@17: return 10;
sl@17: case EClock12:
sl@19: return 8;
sl@17: case EClock24:
sl@17: return 5;
sl@17: }
sl@17:
sl@17: return 10;
sl@17: }
sl@17:
sl@17: /**
sl@20: @return Clock character width in pixels.
sl@17: */
sl@21: int GP1212A02A::ClockCharWidthInPixels(TFontSizeLogical aSize)
sl@17: {
sl@17: switch (aSize)
sl@17: {
sl@21: case EFontTiny:
sl@17: return 6;
sl@21: case EFontSmall:
sl@17: return 8;
sl@21: case EFontMedium:
sl@17: return 12;
sl@21: case EFontLarge:
sl@17: return 16;
sl@17: }
sl@17:
sl@17: return 16;
sl@17: }
sl@17:
sl@17: /**
sl@20: @return Clock character height in pixels.
sl@17: */
sl@21: int GP1212A02A::ClockCharHeightInPixels(TFontSizeLogical aSize)
sl@17: {
sl@17: switch (aSize)
sl@17: {
sl@21: case EFontTiny:
sl@17: return 8;
sl@21: case EFontSmall:
sl@17: return 16;
sl@21: case EFontMedium:
sl@17: return 24;
sl@21: case EFontLarge:
sl@17: return 32;
sl@17: }
sl@17:
sl@17: return 32;
sl@17: }
sl@17:
sl@17: /**
sl@17: Return the Display Window address for centering the clock corresponding to the given parameters.
sl@17: */
sl@21: unsigned short GP1212A02A::ClockCenterAddress(TClockFormat aFormat, TFontSizeLogical aSize)
sl@17: {
sl@17: int charCount=ClockCharCount(aFormat);
sl@17: int halfWidth=(ClockCharWidthInPixels(aSize)*charCount)/2;
sl@17: int halfHeight=(ClockCharHeightInPixels(aSize))/2;
sl@17: int x=(WidthInPixels()/2)-halfWidth;
sl@17: int y=(HeightInPixels()/2)-halfHeight;
sl@17:
sl@17: int yOffset=y/8;
sl@17: int xOffset=x*8; //Not sure why...
sl@17:
sl@17: unsigned short address = yOffset+xOffset;
sl@17: //
sl@17: return address;
sl@17: }
sl@17:
sl@17: /**
sl@17: */
sl@17: void GP1212A02A::ShowClock()
sl@17: {
sl@21: SendCommandClockDisplay(EClock24,ClockCenterAddress(EClock24,EFontLarge),EFontLarge);
sl@17: }
sl@17:
sl@17: /**
sl@17: */
sl@17: void GP1212A02A::HideClock()
sl@17: {
sl@17: SendCommandClockCancel();
sl@17: }
sl@17:
sl@17:
sl@17: /**
sl@17: Clock setting
sl@17: [Code]1BH,6BH,53H,Pd,Ph,Pm
sl@17: [Function]Setting the clock data. The setting data is cleared, if the Reset command is input or power
sl@17: is turned off.
sl@17: Pd = Day of the week
sl@17: Ph = hour
sl@17: Pm = minute
sl@17: [Definable area]
sl@17: Pd = 00H : Sunday
sl@17: Pd = 01H : Monday
sl@17: ...
sl@17: Pd = 06H : Saturday
sl@17: * Clock setting is canceled, when Pd is input value that is larger than 07H, or Ph is input value that is
sl@17: larger than 18H,or Pm is input value that is larger than 3CH.
sl@17: */
sl@17: void GP1212A02A::SendCommandClockSetting(TWeekDay aWeekDay, unsigned char aHour, unsigned char aMinute)
sl@17: {
sl@17: FutabaVfdReport report;
sl@17: report[0]=0x00; //Report ID
sl@17: report[1]=0x06; //Report size
sl@17: report[2]=0x1B; //Command ID
sl@17: report[3]=0x6B; //Command ID
sl@17: report[4]=0x53; //Command ID
sl@17: report[5]=aWeekDay; //Sunday to Saturday
sl@17: report[6]=aHour;
sl@17: report[7]=aMinute;
sl@17:
sl@17: Write(report);
sl@17: }
sl@17:
sl@17:
sl@17: /**
sl@17: Set display clock settings according to local system time.
sl@17: This needs to be redone whenever we open or turn on our display.
sl@17: */
sl@17: void GP1212A02A::SetClockSetting()
sl@17: {
sl@17: time_t rawtime;
sl@17: struct tm * timeinfo;
sl@17:
sl@17: time ( &rawtime );
sl@17: timeinfo = localtime ( &rawtime );
sl@17: //
sl@17: SendCommandClockSetting((TWeekDay)timeinfo->tm_wday,timeinfo->tm_hour,timeinfo->tm_min);
sl@17: }
sl@17:
sl@17:
sl@17: /**
sl@17: Clock display
sl@17: [Code] 1BH,6BH,55H,Ps,aL,aH,Pf
sl@17: [Function] Clock is displayed. The display position and the font size can be freely decided.
sl@17: Ps = Display type select
sl@17: aL,aH = Address
sl@17: Pf = Font size select
sl@17: [Definable area]
sl@17: Ps = 00H : 24hour Ex.[12:34]
sl@17: Ps = 01H : 24hour + day of the week Ex.[Wed._12:34]
sl@17: Ps = 10H : 12hour Ex.[PM_00:34]
sl@17: Ps = 11H : 12hour + day of the week Ex.[Wed._PM_00:34]
sl@17: Pf = 30H : 6x8 dot
sl@17: Pf = 31H : 8x16dot
sl@17: Pf = 32H : 12x24 dot
sl@17: Pf = 33H : 16x32 dot
sl@17: * When the clock data is not input, clock is not displayed.
sl@17: * The clock display is maintained until Clock display cancel "Clear display" RESET command is input
sl@17: or power is turned off.
sl@17: The clock display area
sl@17: Graphic can be displayed excluding the clock display area.
sl@17: The self adjustment for the position
sl@17: that cannot be displayed.
sl@17: * Excluding the clock display area can be input other display commands.
sl@17: */
sl@21: void GP1212A02A::SendCommandClockDisplay(TClockFormat aClockFormat, unsigned short aAddress, TFontSizeLogical aSize)
sl@17: {
sl@17: FutabaVfdReport report;
sl@17: report[0]=0x00; //Report ID
sl@17: report[1]=0x07; //Report size
sl@17: report[2]=0x1B; //Command ID
sl@17: report[3]=0x6B; //Command ID
sl@17: report[4]=0x55; //Command ID
sl@17: report[5]=aClockFormat; //
sl@17: report[6]=(unsigned char)aAddress; //aL
sl@17: report[7]=aAddress>>8; //aH
sl@17: report[8]=aSize;
sl@17:
sl@17: Write(report);
sl@17: }
sl@17:
sl@17:
sl@17: /**
sl@17: Clock display cancel
sl@17: [Code] 1BH,6BH,3DH,58H
sl@17: [Function] Clock display is canceled.
sl@17: */
sl@17: void GP1212A02A::SendCommandClockCancel()
sl@17: {
sl@17: FutabaVfdReport report;
sl@17: report[0]=0x00; //Report ID
sl@17: report[1]=0x04; //Report size
sl@17: report[2]=0x1B; //Command ID
sl@17: report[3]=0x6B; //Command ID
sl@17: report[4]=0x3D; //Command ID
sl@17: report[5]=0x58; //
sl@17:
sl@17: Write(report);
sl@17: }
sl@20:
sl@20:
sl@20: /**
sl@20: @return Size in bytes of a character for a given font size.
sl@20: */
sl@20: int GP1212A02A::CharacterSizeInBytes(TFontSize aFontSize)
sl@20: {
sl@20: switch (aFontSize)
sl@20: {
sl@20: case EFont6x8:
sl@20: return 6;
sl@20: case EFont8x16:
sl@20: return 16;
sl@20: case EFont12x24:
sl@20: return 36;
sl@20: case EFont16x32:
sl@20: return 64;
sl@20: case EFont16x16:
sl@20: return 32;
sl@20: case EFont24x24:
sl@20: return 72;
sl@20: case EFont32x32:
sl@20: return 128;
sl@20: }
sl@20:
sl@20: return 0;
sl@20: }
sl@20:
sl@20: /**
sl@20: Define the User definable font (RAM)
sl@20: [Code] 1BH,6AH,47H,Pf,cL,(cH),Pd...Pd
sl@20: [Function] Define the User definable font into RAM. A maximum 16 characters can be defined
sl@20: within each font size.
sl@20: The User definable fonts are displayed the defined code. It is a same process to normal fonts.
sl@20: The User definable fonts are valid until they redefined, Reset command, or the power off.
sl@20: If define the user definable font over 16 characters, at first defined user definable font is removed
sl@20: If the defined code is specified, existing data is re-written.
sl@20: If the 16x16, 24x24, 32x32 size define, it must specify the “cH”
sl@20: Pf = Font size
sl@20: cL = Lower byte of User definable font code
sl@20: cH = Upper byte of User definable font code
sl@20: Pd = Definition data
sl@20: [Definable area]
sl@20: Pf = 30H : 6x8 dot (Pd=6 byte)
sl@20: Pf = 31H : 8x16 dot (Pd=16 byte)
sl@20: Pf = 32H : 12x24 dot (Pd=36 byte)
sl@20: Pf = 33H : 16x32 dot (Pd=64 byte)
sl@20: Pf = 34H : 16x16 dot (Pd=32 byte)
sl@20: Pf = 35H : 24x24 dot (Pd=72 byte)
sl@20: Pf = 36H : 32x32 dot (Pd=128 byte)
sl@20: cL = ANK code (Pf=30H~33H : 1 byte code)
sl@20: cL,cH = Shift-JIS code (Pf=34H~36H : 2 byte code)
sl@20: */
sl@20: void GP1212A02A::SendCommandDefineCharacter(TFontSize aFontSize, unsigned short aCharacterCode, unsigned char* aPixels)
sl@20: {
sl@20: unsigned char reportSize=0;
sl@20: unsigned char headerSize=0;
sl@20: unsigned char dataSize=CharacterSizeInBytes(aFontSize);
sl@20: FutabaVfdReport report;
sl@20:
sl@20: if (aFontSize>=EFont16x16)
sl@20: {
sl@20: //16 bits char code
sl@20: headerSize=8;
sl@20: reportSize = (dataSize<=report.Size()-headerSize?dataSize+0x06:64); //Report length. -7 is for our header first 7 bytes. +5 is for our Futaba header size
sl@20: report[7] = aCharacterCode>>8;
sl@20: }
sl@20: else
sl@20: {
sl@20: //8 bits char code
sl@20: headerSize=7;
sl@20: reportSize = (dataSize<=report.Size()-headerSize?dataSize+0x05:64); //Report length. -7 is for our header first 7 bytes. +5 is for our Futaba header size
sl@20: }
sl@20:
sl@20:
sl@20: report[0]=0x00; //Report ID
sl@20: report[1]=reportSize; //Report size
sl@20: report[2]=0x1B; //Command ID
sl@20: report[3]=0x6A; //Command ID
sl@20: report[4]=0x47; //Command ID
sl@20: report[5]=aFontSize; //
sl@20: report[6] = (unsigned char) aCharacterCode;
sl@20: //7th byte was set above already
sl@20: int sizeWritten=MIN(dataSize,report.Size()-headerSize);
sl@20: memcpy(report.Buffer()+headerSize, aPixels, sizeWritten);
sl@20: Write(report);
sl@20:
sl@20: int remainingSize=dataSize;
sl@20: //We need to keep on sending our pixel data until we are done
sl@20: while (report[1]==64)
sl@20: {
sl@20: report.Reset();
sl@20: remainingSize-=sizeWritten;
sl@20: report[0]=0x00; //Report ID
sl@20: report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
sl@20: sizeWritten=(report[1]==64?63:report[1]);
sl@20: memcpy(report.Buffer()+2, aPixels+(dataSize-remainingSize), sizeWritten);
sl@20: Write(report);
sl@20: }
sl@20: }
sl@20:
sl@20:
sl@20: /**
sl@20: User definable font store / transfer / delete
sl@20: [Code] 1BH,6AH,45H,Ps
sl@20: [Function] Store, transfer, or delete the User definable font to FROM.
sl@20: * Define the user definable font, after the user definable font is stored
sl@20: * The user definable font store is stored the all defined user definable font data.
sl@20: * The use definable font delete is deleted the all defined to FROM and RAM user definable font data.
sl@20: Ps = store / transfer / delete
sl@20: [Definable area]
sl@20: Ps = 30H : Store
sl@20: Ps = 31H : Transfer
sl@20: Ps = 32H : Delete
sl@20: */
sl@20: void GP1212A02A::SendCommandFontAction(TFontAction aFontAction)
sl@20: {
sl@20: FutabaVfdReport report;
sl@20: report[0]=0x00; //Report ID
sl@20: report[1]=0x04; //Report size
sl@20: report[2]=0x1B; //Command ID
sl@20: report[3]=0x6A; //Command ID
sl@20: report[4]=0x45; //Command ID
sl@20: report[5]=aFontAction; //Ps
sl@20:
sl@20: Write(report);
sl@20: }
sl@21:
sl@21:
sl@21: /**
sl@21: [Code]1BH,4AH,46H,Pf
sl@21: [Function]Setting the font size
sl@21: Pf = Font size
sl@21: [Definable area]
sl@21: Pf = 30H?6x8 dot
sl@21: Pf = 31H?8x16dot and 16x16 dot
sl@21: Pf = 32H?12x24 dot and 24x24 dot
sl@21: Pf = 33H?16x32 dot and 32x32 dot
sl@21: */
sl@21: void GP1212A02A::SendCommandSelectFontSize(TFontSizeLogical aFontSoze)
sl@21: {
sl@21: FutabaVfdReport report;
sl@21: report[0]=0x00; //Report ID
sl@21: report[1]=0x04; //Report size
sl@21: report[2]=0x1B; //Command ID
sl@21: report[3]=0x4A; //Command ID
sl@21: report[4]=0x46; //Command ID
sl@21: report[5]=aFontSoze; //Pf
sl@21:
sl@21: Write(report);
sl@21: }