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