src/FutabaVfd.cpp
author sl
Tue, 27 May 2014 17:49:33 +0200
changeset 27 ee1305f3a6bf
parent 25 233a997193b8
permissions -rw-r--r--
Experimenting with our bitmap to bitarray convertion.
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@26
   134
void GP1212A01A::BitBlit(BitArray& aBitmap, int aSrcWidth, int aSrcHeight, int aTargetX, int aTargetY) const
sl@25
   135
	{
sl@26
   136
	//TODO: amend loop values so that we don't keep on looping past our frame buffer dimensions.
sl@25
   137
	for (int i=0;i<aSrcWidth;i++)
sl@25
   138
		{
sl@25
   139
		for (int j=0;j<aSrcHeight;j++)
sl@25
   140
			{
sl@25
   141
			iFrameBuffer->SetBitValue((aTargetX+i)*HeightInPixels()+aTargetY+j,aBitmap[+i*aSrcHeight+j]);
sl@25
   142
			}
sl@25
   143
		}
sl@10
   144
	}
sl@10
   145
sl@10
   146
/**
sl@23
   147
Set all pixels on our screen to the desired value.
sl@23
   148
This operation is performed off screen to avoid tearing.
sl@23
   149
@param 8 pixels pattern
sl@10
   150
*/
sl@23
   151
void GP1212A01A::SetAllPixels(unsigned char aPattern)
sl@10
   152
	{
sl@23
   153
	//With a single buffer
sl@23
   154
	//unsigned char screen[2048]; //One screen worth of pixels
sl@23
   155
	//memset(screen,0xFF,sizeof(screen));
sl@23
   156
	//SetPixelBlock(0,0,63,sizeof(screen),screen);
sl@10
   157
sl@23
   158
	//Using pattern SetPixelBlock variant.
sl@25
   159
	memset(iFrameBuffer->Ptr(),aPattern,FrameBufferSizeInBytes());
sl@25
   160
	//
sl@25
   161
sl@25
   162
sl@10
   163
	}
sl@10
   164
sl@10
   165
/**
sl@23
   166
Set our screen brightness.
sl@23
   167
@param The desired brightness level. Must be between MinBrightness and MaxBrightness.
sl@10
   168
*/
sl@10
   169
void GP1212A01A::SetBrightness(int aBrightness)
sl@18
   170
    {
sl@18
   171
	if (aBrightness<MinBrightness()||aBrightness>MaxBrightness())
sl@18
   172
        {
sl@18
   173
        //Brightness out of range.
sl@18
   174
        //Just ignore that request.
sl@18
   175
        return;
sl@18
   176
        }
sl@18
   177
sl@18
   178
    FutabaVfdReport report;
sl@18
   179
    report[0]=0x00; //Report ID
sl@18
   180
    report[1]=0x06; //Report size
sl@18
   181
    report[2]=0x1B; //Command ID
sl@18
   182
    report[3]=0x5C; //Command ID
sl@18
   183
    report[4]=0x3F; //Command ID
sl@18
   184
    report[5]=0x4C; //Command ID
sl@18
   185
    report[6]=0x44; //Command ID
sl@18
   186
    report[7]=0x30+aBrightness; //Brightness level
sl@18
   187
    Write(report);
sl@18
   188
sl@10
   189
	}
sl@10
   190
sl@10
   191
/**
sl@10
   192
Set the defined pixel block to the given value.
sl@10
   193
@param X coordinate of our pixel block starting point.
sl@10
   194
@param Y coordinate of our pixel block starting point.
sl@10
   195
@param The height of our pixel block.
sl@10
   196
@param The size of our pixel data. Number of pixels divided by 8.
sl@20
   197
@param The value set to 8 pixels used as a pattern.
sl@10
   198
*/
sl@23
   199
void GP1212A01A::SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char aValue)
sl@10
   200
	{
sl@23
   201
	OffScreenTranslation(aX,aY);
sl@23
   202
    FutabaVfdReport report;
sl@23
   203
    report[0]=0x00; //Report ID
sl@23
   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@23
   205
    report[2]=0x1B; //Command ID
sl@23
   206
    report[3]=0x5B; //Command ID
sl@23
   207
    report[4]=0xF0; //Command ID
sl@23
   208
    report[5]=aX;   //X
sl@23
   209
    report[6]=aY;   //Y
sl@23
   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@23
   211
	report[8]=aSize>>8; //Size of pixel data in bytes (MSB)
sl@23
   212
	report[9]=aSize;	//Size of pixel data in bytes (LSB)
sl@23
   213
    int sizeWritten=MIN(aSize,report.Size()-10);
sl@23
   214
    memset(report.Buffer()+10, aValue, sizeWritten);
sl@23
   215
    Write(report);
sl@23
   216
sl@23
   217
    int remainingSize=aSize;
sl@23
   218
    //We need to keep on sending our pixel data until we are done
sl@23
   219
    while (report[1]==64)
sl@23
   220
        {
sl@23
   221
        report.Reset();
sl@23
   222
        remainingSize-=sizeWritten;
sl@23
   223
        report[0]=0x00; //Report ID
sl@23
   224
        report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
sl@23
   225
        sizeWritten=(report[1]==64?63:report[1]);
sl@23
   226
        memset(report.Buffer()+2, aValue, sizeWritten);
sl@23
   227
        Write(report);
sl@23
   228
        }
sl@10
   229
	}
sl@10
   230
sl@20
   231
/**
sl@20
   232
Set the defined pixel block to the given value.
sl@20
   233
@param X coordinate of our pixel block starting point.
sl@20
   234
@param Y coordinate of our pixel block starting point.
sl@20
   235
@param The height of our pixel block.
sl@20
   236
@param The size of our pixel data. Number of pixels divided by 8.
sl@20
   237
@param Pointer to our pixel data.
sl@20
   238
*/
sl@23
   239
void GP1212A01A::SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char* aPixels)
sl@20
   240
    {
sl@23
   241
	OffScreenTranslation(aX,aY);
sl@20
   242
    FutabaVfdReport report;
sl@20
   243
    report[0]=0x00; //Report ID
sl@23
   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@20
   245
    report[2]=0x1B; //Command ID
sl@20
   246
    report[3]=0x5B; //Command ID
sl@20
   247
    report[4]=0xF0; //Command ID
sl@20
   248
    report[5]=aX;   //X
sl@20
   249
    report[6]=aY;   //Y
sl@20
   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@23
   251
	report[8]=aSize>>8; //Size of pixel data in bytes (MSB)
sl@23
   252
	report[9]=aSize;	//Size of pixel data in bytes (LSB)
sl@20
   253
    int sizeWritten=MIN(aSize,report.Size()-10);
sl@20
   254
    memcpy(report.Buffer()+10, aPixels, sizeWritten);
sl@20
   255
    Write(report);
sl@20
   256
sl@20
   257
    int remainingSize=aSize;
sl@20
   258
    //We need to keep on sending our pixel data until we are done
sl@20
   259
    while (report[1]==64)
sl@20
   260
        {
sl@20
   261
        report.Reset();
sl@20
   262
        remainingSize-=sizeWritten;
sl@20
   263
        report[0]=0x00; //Report ID
sl@23
   264
        report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size
sl@20
   265
        sizeWritten=(report[1]==64?63:report[1]);
sl@20
   266
        memcpy(report.Buffer()+2, aPixels+(aSize-remainingSize), sizeWritten);
sl@20
   267
        Write(report);
sl@20
   268
        }
sl@20
   269
    }
sl@20
   270
sl@10
   271
sl@10
   272
/**
sl@25
   273
Clear our client side back buffer.
sl@25
   274
Call to SwapBuffers must follow to actually clear the display.
sl@10
   275
*/
sl@10
   276
void GP1212A01A::Clear()
sl@10
   277
	{
sl@25
   278
	//memset(iFrameBuffer->Ptr(),0x00,FrameBufferSizeInBytes());
sl@25
   279
	iFrameBuffer->ClearAll();
sl@23
   280
	}
sl@23
   281
sl@23
   282
/**
sl@23
   283
Using this function is advised against as is causes tearing.
sl@23
   284
Use Clear instead.
sl@23
   285
*/
sl@23
   286
void GP1212A01A::SendClearCommand()
sl@23
   287
	{
sl@21
   288
    //1BH,5BH,32H,4AH
sl@21
   289
    //Send Clear Display Command
sl@10
   290
	FutabaVfdReport report;
sl@10
   291
	report[0]=0x00; //Report ID
sl@10
   292
	report[1]=0x04; //Report length
sl@19
   293
	report[2]=0x1B; //Command ID
sl@19
   294
	report[3]=0x5B; //Command ID
sl@19
   295
	report[4]=0x32; //Command ID
sl@19
   296
	report[5]=0x4A; //Command ID
sl@10
   297
	Write(report);
sl@19
   298
	}
sl@19
   299
sl@19
   300
/**
sl@21
   301
Change our display position within our buffer.
sl@21
   302
*/
sl@23
   303
void GP1212A01A::SetDisplayPosition(DW aDw,unsigned char aX, unsigned char aY)
sl@21
   304
    {
sl@21
   305
    //1BH,5BH,Dw,Px,Py
sl@21
   306
    //Send Display Position Settings Command
sl@21
   307
    FutabaVfdReport report;
sl@21
   308
    report[0]=0x00; //Report ID
sl@21
   309
    report[1]=0x05; //Report length
sl@21
   310
    report[2]=0x1B; //Command ID
sl@21
   311
    report[3]=0x5B; //Command ID
sl@21
   312
    report[4]=aDw;  //Specify our DW
sl@21
   313
    report[5]=aX;   //X coordinate of our DW top-left corner
sl@22
   314
    report[6]=aY;   //Y coordinate of our DW top-left corner
sl@21
   315
    Write(report);
sl@21
   316
    }
sl@21
   317
sl@21
   318
/**
sl@22
   319
Change our display position within our buffer.
sl@22
   320
*/
sl@23
   321
void GP1212A01A::SetDisplayPosition(unsigned char aX, unsigned char aY)
sl@22
   322
	{
sl@22
   323
	//Specs apparently says both DW should remain the same
sl@22
   324
	//Just don't ask
sl@22
   325
    SetDisplayPosition(GP1212A01A::DW1,aX,aY);
sl@22
   326
    SetDisplayPosition(GP1212A01A::DW2,aX,aY);
sl@23
   327
	iDisplayPositionX=aX;
sl@23
   328
	iDisplayPositionY=aY;
sl@23
   329
	}
sl@23
   330
sl@23
   331
/**
sl@23
   332
Provide Y coordinate of our off screen buffer.
sl@23
   333
*/
sl@23
   334
unsigned char GP1212A01A::OffScreenY() const
sl@23
   335
	{
sl@23
   336
	//Overflowing is fine this is just what we want
sl@23
   337
	return iDisplayPositionY+HeightInPixels();
sl@23
   338
	}
sl@23
   339
sl@23
   340
/**
sl@23
   341
Put our off screen buffer on screen.
sl@23
   342
On screen buffer goes off screen.
sl@23
   343
*/
sl@23
   344
void GP1212A01A::SwapBuffers()
sl@23
   345
	{
sl@23
   346
	//Only perform buffer swapping if off screen mode is enabled
sl@23
   347
	if (OffScreenMode())
sl@23
   348
		{
sl@25
   349
		//Send host back buffer to device back buffer
sl@25
   350
		SetPixelBlock(0,0,63,FrameBufferSizeInBytes(),iFrameBuffer->Ptr());
sl@25
   351
		//Swap device front and back buffer
sl@23
   352
		SetDisplayPosition(iDisplayPositionX,OffScreenY());
sl@25
   353
		//Swap host buffers
sl@25
   354
		//unsigned char* backBuffer=iBackBuffer;
sl@25
   355
		//iBackBuffer = iFrontBuffer;
sl@25
   356
		//iFrontBuffer = backBuffer;
sl@23
   357
		}
sl@23
   358
	}
sl@23
   359
sl@23
   360
/**
sl@23
   361
Translate the given pixel coordinate according to our off screen mode.
sl@23
   362
*/
sl@23
   363
void GP1212A01A::OffScreenTranslation(unsigned char& aX, unsigned char& aY)
sl@23
   364
	{
sl@23
   365
	if (OffScreenMode())
sl@23
   366
		{
sl@23
   367
		aX+=WidthInPixels()-iDisplayPositionX;
sl@23
   368
		aY+=HeightInPixels()-iDisplayPositionY;
sl@23
   369
		}
sl@22
   370
	}
sl@25
   371
sl@25
   372
sl@25
   373
/**
sl@25
   374
*/
sl@25
   375
void GP1212A01A::ResetBuffers()
sl@25
   376
	{
sl@25
   377
	//iFrameBuffer->ClearAll();
sl@25
   378
	//memset(iFrameBuffer,0x00,sizeof(iFrameBuffer));
sl@25
   379
	//memset(iFrameBeta,0x00,sizeof(iFrameBeta));
sl@25
   380
	}
sl@25
   381
sl@22
   382
/**
sl@19
   383
*/
sl@19
   384
void GP1212A01A::RequestId()
sl@19
   385
    {
sl@19
   386
    //1BH,5BH,63H,49H,44H
sl@19
   387
    //Send Read ID command
sl@19
   388
    FutabaVfdReport report;
sl@19
   389
    report[0]=0x00; //Report ID
sl@19
   390
    report[1]=0x05; //Report length
sl@19
   391
    report[2]=0x1B; //Command ID
sl@19
   392
    report[3]=0x5B; //Command ID
sl@19
   393
    report[4]=0x63; //Command ID
sl@19
   394
    report[5]=0x49; //Command ID
sl@19
   395
    report[6]=0x44; //Command ID
sl@19
   396
    Write(report);
sl@19
   397
    }
sl@19
   398
sl@19
   399
/**
sl@19
   400
*/
sl@19
   401
void GP1212A01A::RequestFirmwareRevision()
sl@19
   402
    {
sl@19
   403
    //1BH,5BH,63H,46H,52H
sl@19
   404
    //Send Software Revision Read Command
sl@19
   405
    FutabaVfdReport report;
sl@19
   406
    report[0]=0x00; //Report ID
sl@19
   407
    report[1]=0x05; //Report length
sl@19
   408
    report[2]=0x1B; //Command ID
sl@19
   409
    report[3]=0x5B; //Command ID
sl@19
   410
    report[4]=0x63; //Command ID
sl@19
   411
    report[5]=0x46; //Command ID
sl@19
   412
    report[6]=0x52; //Command ID
sl@19
   413
    Write(report);
sl@19
   414
    }
sl@19
   415
sl@19
   416
/**
sl@19
   417
*/
sl@19
   418
void GP1212A01A::RequestPowerSupplyStatus()
sl@19
   419
    {
sl@19
   420
    //1BH,5BH,63H,50H,4DH
sl@19
   421
    //Send Power Suppply Monitor Command
sl@19
   422
    FutabaVfdReport report;
sl@19
   423
    report[0]=0x00; //Report ID
sl@19
   424
    report[1]=0x05; //Report length
sl@19
   425
    report[2]=0x1B; //Command ID
sl@19
   426
    report[3]=0x5B; //Command ID
sl@19
   427
    report[4]=0x63; //Command ID
sl@19
   428
    report[5]=0x50; //Command ID
sl@19
   429
    report[6]=0x4D; //Command ID
sl@19
   430
    Write(report);
sl@23
   431
    }
sl@23
   432
sl@23
   433
sl@23
   434
/**
sl@23
   435
This is for development purposes only.
sl@23
   436
Production application should stick to off-screen mode to avoid tearing.
sl@23
   437
*/
sl@23
   438
void GP1212A01A::ToggleOffScreenMode()
sl@23
   439
	{
sl@23
   440
	iOffScreenMode=!iOffScreenMode;
sl@23
   441
	//Clean up our buffers upon switching modes	
sl@23
   442
	SetDisplayPosition(0,0);
sl@23
   443
	Clear();
sl@23
   444
	SwapBuffers();
sl@23
   445
	Clear();
sl@23
   446
	}