MiniDisplay/FutabaVfd.cpp
author sl
Wed, 28 May 2014 08:06:27 +0200
changeset 6 b1b049e28772
parent 4 7d34342ac6e9
child 9 52372bbbc0f8
permissions -rw-r--r--
Basic font rendering now working nicely.
sl@4
     1
sl@4
     2
#include "FutabaVfd.h"
sl@4
     3
//#include <stdlib.h>
sl@4
     4
#include <string.h>
sl@4
     5
sl@4
     6
sl@4
     7
//
sl@4
     8
//
sl@4
     9
//
sl@4
    10
sl@4
    11
sl@4
    12
sl@4
    13
sl@4
    14
sl@4
    15
//
sl@4
    16
//
sl@4
    17
//
sl@4
    18
sl@4
    19
FutabaVfdCommand::FutabaVfdCommand():/*iBuffer(NULL),*/iSize(0),iMaxSize(0)
sl@4
    20
    {
sl@4
    21
    }
sl@4
    22
sl@4
    23
FutabaVfdCommand::~FutabaVfdCommand()
sl@4
    24
    {
sl@4
    25
    //Delete();
sl@4
    26
    }
sl@4
    27
sl@4
    28
sl@4
    29
/**
sl@4
    30
sl@4
    31
*/
sl@4
    32
void FutabaVfdCommand::Reset()
sl@4
    33
    {
sl@4
    34
    memset(iReports,0,sizeof(iReports));
sl@4
    35
    }
sl@4
    36
sl@4
    37
sl@4
    38
sl@4
    39
/**
sl@4
    40
sl@4
    41
*/
sl@4
    42
/*
sl@4
    43
void FutabaVfdCommand::Create(int aMaxSize)
sl@4
    44
    {
sl@4
    45
    iBuffer=new unsigned char[aMaxSize];
sl@4
    46
    if (iBuffer)
sl@4
    47
        {
sl@4
    48
        iMaxSize = aMaxSize;
sl@4
    49
        iSize = 0;
sl@4
    50
        }
sl@4
    51
    }
sl@4
    52
*/
sl@4
    53
sl@4
    54
/**
sl@4
    55
sl@4
    56
*/
sl@4
    57
/*
sl@4
    58
void FutabaVfdCommand::Delete()
sl@4
    59
{
sl@4
    60
    delete[] iBuffer;
sl@4
    61
    iBuffer = NULL;
sl@4
    62
    iMaxSize = 0;
sl@4
    63
    iSize = 0;
sl@4
    64
}
sl@4
    65
*/
sl@4
    66
sl@4
    67
sl@4
    68
sl@4
    69
sl@4
    70
//
sl@4
    71
// class GP1212A01A
sl@4
    72
//
sl@4
    73
sl@4
    74
GP1212A01A::GP1212A01A():
sl@4
    75
	iDisplayPositionX(0),iDisplayPositionY(0),
sl@4
    76
	iOffScreenMode(true),iFrameBuffer(NULL)
sl@4
    77
	{
sl@4
    78
	//ResetBuffers();
sl@4
    79
	}
sl@4
    80
sl@4
    81
/**
sl@4
    82
*/
sl@4
    83
GP1212A01A::~GP1212A01A()
sl@4
    84
	{
sl@4
    85
	delete iFrameBuffer;
sl@4
    86
	iFrameBuffer=NULL;
sl@4
    87
	}
sl@4
    88
sl@4
    89
/**
sl@4
    90
*/
sl@4
    91
int GP1212A01A::Open()
sl@4
    92
	{
sl@4
    93
	int success = HidDevice::Open(KFutabaVendorId,KFutabaProductIdGP1212A01A,NULL);
sl@4
    94
	if (success)
sl@4
    95
		{
sl@4
    96
		delete iFrameBuffer;
sl@4
    97
		iFrameBuffer = NULL;
sl@4
    98
		iFrameBuffer=new BitArray(KGP12xFrameBufferPixelCount);
sl@4
    99
		SetNonBlocking(1);
sl@4
   100
		//Since we can't get our display position we for it to our default
sl@4
   101
		//This makes sure frames are in sync from the start
sl@4
   102
		SetDisplayPosition(iDisplayPositionX,iDisplayPositionY);
sl@4
   103
		//Now clear both front and back buffer on host and device
sl@4
   104
		Clear();
sl@4
   105
		SwapBuffers();
sl@4
   106
		Clear();
sl@4
   107
		SwapBuffers();
sl@4
   108
		}
sl@4
   109
	return success;
sl@4
   110
	}
sl@4
   111
sl@4
   112
/**
sl@4
   113
*/
sl@4
   114
void GP1212A01A::SetPixel(unsigned char aX, unsigned char aY, bool aOn)
sl@4
   115
	{
sl@4
   116
	//Just specify a one pixel block
sl@4
   117
	//SetPixelBlock(aX,aY,0x00,0x01,aOn);
sl@4
   118
	//
sl@4
   119
	//int byteOffset=(aX*HeightInPixels()+aY)/8;
sl@4
   120
	//int bitOffset=(aX*HeightInPixels()+aY)%8;
sl@4
   121
	//iFrameBuffer[byteOffset] |= ( (aOn?0x01:0x00) << bitOffset );
sl@4
   122
	if (aOn)
sl@4
   123
		{
sl@4
   124
		iFrameBuffer->SetBit(aX*HeightInPixels()+aY);
sl@4
   125
		}
sl@4
   126
	else
sl@4
   127
		{
sl@4
   128
		iFrameBuffer->ClearBit(aX*HeightInPixels()+aY);
sl@4
   129
		}
sl@4
   130
	}
sl@4
   131
sl@4
   132
/**
sl@4
   133
*/
sl@6
   134
void GP1212A01A::BitBlit(const BitArray& aBitmap, int aSrcWidth, int aSrcHeight, int aTargetX, int aTargetY) const
sl@4
   135
	{
sl@4
   136
	//TODO: amend loop values so that we don't keep on looping past our frame buffer dimensions.
sl@4
   137
	for (int i=0;i<aSrcWidth;i++)
sl@4
   138
		{
sl@4
   139
		for (int j=0;j<aSrcHeight;j++)
sl@4
   140
			{
sl@4
   141
			iFrameBuffer->SetBitValue((aTargetX+i)*HeightInPixels()+aTargetY+j,aBitmap[+i*aSrcHeight+j]);
sl@4
   142
			}
sl@4
   143
		}
sl@4
   144
	}
sl@4
   145
sl@4
   146
/**
sl@4
   147
Set all pixels on our screen to the desired value.
sl@4
   148
This operation is performed off screen to avoid tearing.
sl@4
   149
@param 8 pixels pattern
sl@4
   150
*/
sl@4
   151
void GP1212A01A::SetAllPixels(unsigned char aPattern)
sl@4
   152
	{
sl@4
   153
	//With a single buffer
sl@4
   154
	//unsigned char screen[2048]; //One screen worth of pixels
sl@4
   155
	//memset(screen,0xFF,sizeof(screen));
sl@4
   156
	//SetPixelBlock(0,0,63,sizeof(screen),screen);
sl@4
   157
sl@4
   158
	//Using pattern SetPixelBlock variant.
sl@4
   159
	memset(iFrameBuffer->Ptr(),aPattern,FrameBufferSizeInBytes());
sl@4
   160
	//
sl@4
   161
sl@4
   162
sl@4
   163
	}
sl@4
   164
sl@4
   165
/**
sl@4
   166
Set our screen brightness.
sl@4
   167
@param The desired brightness level. Must be between MinBrightness and MaxBrightness.
sl@4
   168
*/
sl@4
   169
void GP1212A01A::SetBrightness(int aBrightness)
sl@4
   170
    {
sl@4
   171
	if (aBrightness<MinBrightness()||aBrightness>MaxBrightness())
sl@4
   172
        {
sl@4
   173
        //Brightness out of range.
sl@4
   174
        //Just ignore that request.
sl@4
   175
        return;
sl@4
   176
        }
sl@4
   177
sl@4
   178
    FutabaVfdReport report;
sl@4
   179
    report[0]=0x00; //Report ID
sl@4
   180
    report[1]=0x06; //Report size
sl@4
   181
    report[2]=0x1B; //Command ID
sl@4
   182
    report[3]=0x5C; //Command ID
sl@4
   183
    report[4]=0x3F; //Command ID
sl@4
   184
    report[5]=0x4C; //Command ID
sl@4
   185
    report[6]=0x44; //Command ID
sl@4
   186
    report[7]=0x30+aBrightness; //Brightness level
sl@4
   187
    Write(report);
sl@4
   188
sl@4
   189
	}
sl@4
   190
sl@4
   191
/**
sl@4
   192
Set the defined pixel block to the given value.
sl@4
   193
@param X coordinate of our pixel block starting point.
sl@4
   194
@param Y coordinate of our pixel block starting point.
sl@4
   195
@param The height of our pixel block.
sl@4
   196
@param The size of our pixel data. Number of pixels divided by 8.
sl@4
   197
@param The value set to 8 pixels used as a pattern.
sl@4
   198
*/
sl@4
   199
void GP1212A01A::SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char aValue)
sl@4
   200
	{
sl@4
   201
	OffScreenTranslation(aX,aY);
sl@4
   202
    FutabaVfdReport report;
sl@4
   203
    report[0]=0x00; //Report ID
sl@4
   204
    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@4
   205
    report[2]=0x1B; //Command ID
sl@4
   206
    report[3]=0x5B; //Command ID
sl@4
   207
    report[4]=0xF0; //Command ID
sl@4
   208
    report[5]=aX;   //X
sl@4
   209
    report[6]=aY;   //Y
sl@4
   210
    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.
sl@4
   211
	report[8]=aSize>>8; //Size of pixel data in bytes (MSB)
sl@4
   212
	report[9]=aSize;	//Size of pixel data in bytes (LSB)
sl@4
   213
    int sizeWritten=MIN(aSize,report.Size()-10);
sl@4
   214
    memset(report.Buffer()+10, aValue, sizeWritten);
sl@4
   215
    Write(report);
sl@4
   216
sl@4
   217
    int remainingSize=aSize;
sl@4
   218
    //We need to keep on sending our pixel data until we are done
sl@4
   219
    while (report[1]==64)
sl@4
   220
        {
sl@4
   221
        report.Reset();
sl@4
   222
        remainingSize-=sizeWritten;
sl@4
   223
        report[0]=0x00; //Report ID
sl@4
   224
        report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
sl@4
   225
        sizeWritten=(report[1]==64?63:report[1]);
sl@4
   226
        memset(report.Buffer()+2, aValue, sizeWritten);
sl@4
   227
        Write(report);
sl@4
   228
        }
sl@4
   229
	}
sl@4
   230
sl@4
   231
/**
sl@4
   232
Set the defined pixel block to the given value.
sl@4
   233
@param X coordinate of our pixel block starting point.
sl@4
   234
@param Y coordinate of our pixel block starting point.
sl@4
   235
@param The height of our pixel block.
sl@4
   236
@param The size of our pixel data. Number of pixels divided by 8.
sl@4
   237
@param Pointer to our pixel data.
sl@4
   238
*/
sl@4
   239
void GP1212A01A::SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char* aPixels)
sl@4
   240
    {
sl@4
   241
	OffScreenTranslation(aX,aY);
sl@4
   242
    FutabaVfdReport report;
sl@4
   243
    report[0]=0x00; //Report ID
sl@4
   244
    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@4
   245
    report[2]=0x1B; //Command ID
sl@4
   246
    report[3]=0x5B; //Command ID
sl@4
   247
    report[4]=0xF0; //Command ID
sl@4
   248
    report[5]=aX;   //X
sl@4
   249
    report[6]=aY;   //Y
sl@4
   250
    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.
sl@4
   251
	report[8]=aSize>>8; //Size of pixel data in bytes (MSB)
sl@4
   252
	report[9]=aSize;	//Size of pixel data in bytes (LSB)
sl@4
   253
    int sizeWritten=MIN(aSize,report.Size()-10);
sl@4
   254
    memcpy(report.Buffer()+10, aPixels, sizeWritten);
sl@4
   255
    Write(report);
sl@4
   256
sl@4
   257
    int remainingSize=aSize;
sl@4
   258
    //We need to keep on sending our pixel data until we are done
sl@4
   259
    while (report[1]==64)
sl@4
   260
        {
sl@4
   261
        report.Reset();
sl@4
   262
        remainingSize-=sizeWritten;
sl@4
   263
        report[0]=0x00; //Report ID
sl@4
   264
        report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
sl@4
   265
        sizeWritten=(report[1]==64?63:report[1]);
sl@4
   266
        memcpy(report.Buffer()+2, aPixels+(aSize-remainingSize), sizeWritten);
sl@4
   267
        Write(report);
sl@4
   268
        }
sl@4
   269
    }
sl@4
   270
sl@4
   271
sl@4
   272
/**
sl@4
   273
Clear our client side back buffer.
sl@4
   274
Call to SwapBuffers must follow to actually clear the display.
sl@4
   275
*/
sl@4
   276
void GP1212A01A::Clear()
sl@4
   277
	{
sl@4
   278
	//memset(iFrameBuffer->Ptr(),0x00,FrameBufferSizeInBytes());
sl@4
   279
	iFrameBuffer->ClearAll();
sl@4
   280
	}
sl@4
   281
sl@4
   282
/**
sl@4
   283
Using this function is advised against as is causes tearing.
sl@4
   284
Use Clear instead.
sl@4
   285
*/
sl@4
   286
void GP1212A01A::SendClearCommand()
sl@4
   287
	{
sl@4
   288
    //1BH,5BH,32H,4AH
sl@4
   289
    //Send Clear Display Command
sl@4
   290
	FutabaVfdReport report;
sl@4
   291
	report[0]=0x00; //Report ID
sl@4
   292
	report[1]=0x04; //Report length
sl@4
   293
	report[2]=0x1B; //Command ID
sl@4
   294
	report[3]=0x5B; //Command ID
sl@4
   295
	report[4]=0x32; //Command ID
sl@4
   296
	report[5]=0x4A; //Command ID
sl@4
   297
	Write(report);
sl@4
   298
	}
sl@4
   299
sl@4
   300
/**
sl@4
   301
Change our display position within our buffer.
sl@4
   302
*/
sl@4
   303
void GP1212A01A::SetDisplayPosition(DW aDw,unsigned char aX, unsigned char aY)
sl@4
   304
    {
sl@4
   305
    //1BH,5BH,Dw,Px,Py
sl@4
   306
    //Send Display Position Settings Command
sl@4
   307
    FutabaVfdReport report;
sl@4
   308
    report[0]=0x00; //Report ID
sl@4
   309
    report[1]=0x05; //Report length
sl@4
   310
    report[2]=0x1B; //Command ID
sl@4
   311
    report[3]=0x5B; //Command ID
sl@4
   312
    report[4]=aDw;  //Specify our DW
sl@4
   313
    report[5]=aX;   //X coordinate of our DW top-left corner
sl@4
   314
    report[6]=aY;   //Y coordinate of our DW top-left corner
sl@4
   315
    Write(report);
sl@4
   316
    }
sl@4
   317
sl@4
   318
/**
sl@4
   319
Change our display position within our buffer.
sl@4
   320
*/
sl@4
   321
void GP1212A01A::SetDisplayPosition(unsigned char aX, unsigned char aY)
sl@4
   322
	{
sl@4
   323
	//Specs apparently says both DW should remain the same
sl@4
   324
	//Just don't ask
sl@4
   325
    SetDisplayPosition(GP1212A01A::DW1,aX,aY);
sl@4
   326
    SetDisplayPosition(GP1212A01A::DW2,aX,aY);
sl@4
   327
	iDisplayPositionX=aX;
sl@4
   328
	iDisplayPositionY=aY;
sl@4
   329
	}
sl@4
   330
sl@4
   331
/**
sl@4
   332
Provide Y coordinate of our off screen buffer.
sl@4
   333
*/
sl@4
   334
unsigned char GP1212A01A::OffScreenY() const
sl@4
   335
	{
sl@4
   336
	//Overflowing is fine this is just what we want
sl@4
   337
	return iDisplayPositionY+HeightInPixels();
sl@4
   338
	}
sl@4
   339
sl@4
   340
/**
sl@4
   341
Put our off screen buffer on screen.
sl@4
   342
On screen buffer goes off screen.
sl@4
   343
*/
sl@4
   344
void GP1212A01A::SwapBuffers()
sl@4
   345
	{
sl@4
   346
	//Only perform buffer swapping if off screen mode is enabled
sl@4
   347
	if (OffScreenMode())
sl@4
   348
		{
sl@4
   349
		//Send host back buffer to device back buffer
sl@4
   350
		SetPixelBlock(0,0,63,FrameBufferSizeInBytes(),iFrameBuffer->Ptr());
sl@4
   351
		//Swap device front and back buffer
sl@4
   352
		SetDisplayPosition(iDisplayPositionX,OffScreenY());
sl@4
   353
		//Swap host buffers
sl@4
   354
		//unsigned char* backBuffer=iBackBuffer;
sl@4
   355
		//iBackBuffer = iFrontBuffer;
sl@4
   356
		//iFrontBuffer = backBuffer;
sl@4
   357
		}
sl@4
   358
	}
sl@4
   359
sl@4
   360
/**
sl@4
   361
Translate the given pixel coordinate according to our off screen mode.
sl@4
   362
*/
sl@4
   363
void GP1212A01A::OffScreenTranslation(unsigned char& aX, unsigned char& aY)
sl@4
   364
	{
sl@4
   365
	if (OffScreenMode())
sl@4
   366
		{
sl@4
   367
		aX+=WidthInPixels()-iDisplayPositionX;
sl@4
   368
		aY+=HeightInPixels()-iDisplayPositionY;
sl@4
   369
		}
sl@4
   370
	}
sl@4
   371
sl@4
   372
sl@4
   373
/**
sl@4
   374
*/
sl@4
   375
void GP1212A01A::ResetBuffers()
sl@4
   376
	{
sl@4
   377
	//iFrameBuffer->ClearAll();
sl@4
   378
	//memset(iFrameBuffer,0x00,sizeof(iFrameBuffer));
sl@4
   379
	//memset(iFrameBeta,0x00,sizeof(iFrameBeta));
sl@4
   380
	}
sl@4
   381
sl@4
   382
/**
sl@4
   383
*/
sl@4
   384
void GP1212A01A::RequestId()
sl@4
   385
    {
sl@4
   386
    //1BH,5BH,63H,49H,44H
sl@4
   387
    //Send Read ID command
sl@4
   388
    FutabaVfdReport report;
sl@4
   389
    report[0]=0x00; //Report ID
sl@4
   390
    report[1]=0x05; //Report length
sl@4
   391
    report[2]=0x1B; //Command ID
sl@4
   392
    report[3]=0x5B; //Command ID
sl@4
   393
    report[4]=0x63; //Command ID
sl@4
   394
    report[5]=0x49; //Command ID
sl@4
   395
    report[6]=0x44; //Command ID
sl@4
   396
    Write(report);
sl@4
   397
    }
sl@4
   398
sl@4
   399
/**
sl@4
   400
*/
sl@4
   401
void GP1212A01A::RequestFirmwareRevision()
sl@4
   402
    {
sl@4
   403
    //1BH,5BH,63H,46H,52H
sl@4
   404
    //Send Software Revision Read Command
sl@4
   405
    FutabaVfdReport report;
sl@4
   406
    report[0]=0x00; //Report ID
sl@4
   407
    report[1]=0x05; //Report length
sl@4
   408
    report[2]=0x1B; //Command ID
sl@4
   409
    report[3]=0x5B; //Command ID
sl@4
   410
    report[4]=0x63; //Command ID
sl@4
   411
    report[5]=0x46; //Command ID
sl@4
   412
    report[6]=0x52; //Command ID
sl@4
   413
    Write(report);
sl@4
   414
    }
sl@4
   415
sl@4
   416
/**
sl@4
   417
*/
sl@4
   418
void GP1212A01A::RequestPowerSupplyStatus()
sl@4
   419
    {
sl@4
   420
    //1BH,5BH,63H,50H,4DH
sl@4
   421
    //Send Power Suppply Monitor Command
sl@4
   422
    FutabaVfdReport report;
sl@4
   423
    report[0]=0x00; //Report ID
sl@4
   424
    report[1]=0x05; //Report length
sl@4
   425
    report[2]=0x1B; //Command ID
sl@4
   426
    report[3]=0x5B; //Command ID
sl@4
   427
    report[4]=0x63; //Command ID
sl@4
   428
    report[5]=0x50; //Command ID
sl@4
   429
    report[6]=0x4D; //Command ID
sl@4
   430
    Write(report);
sl@4
   431
    }
sl@4
   432
sl@4
   433
sl@4
   434
/**
sl@4
   435
This is for development purposes only.
sl@4
   436
Production application should stick to off-screen mode to avoid tearing.
sl@4
   437
*/
sl@4
   438
void GP1212A01A::ToggleOffScreenMode()
sl@4
   439
	{
sl@4
   440
	iOffScreenMode=!iOffScreenMode;
sl@4
   441
	//Clean up our buffers upon switching modes	
sl@4
   442
	SetDisplayPosition(0,0);
sl@4
   443
	Clear();
sl@4
   444
	SwapBuffers();
sl@4
   445
	Clear();
sl@6
   446
	}