////////////////////////////////////////////////////////////////////////////////////////////////////
//
//                          Test NXT LCD Display Drawing Execution Speed
//
// This program is used to test the execution speed of the LCD display
// drawing cababilities of the NXT brick.
//
// The basic methodology is to:
//  [1] measure the time to loop 1,000 times through an empty 'for' loop.
//  [2] measure the time to loop 1,000 times through an 'for' loop containing
//      210 identical statements.
//  [3] Take the time difference between the two loops to find the time to
//      execute 10,000 statements.
//  [4] Interpret to determine the number of microseconds per statement.
//
////////////////////////////////////////////////////////////////////////////////////////////////////

#pragma platform(NXT)

const int kNumberOfLoops = 1000; // 1K x 10 instructions per loop = 10K instructions

const TTimers  executionTimer = T1;

//
// Types of tests that can be performed.
//
typedef enum
{
	typeIdleLoop,

	typeSetPixel,
	typeClearPixel,

	typeDrawText,
	typeFormatAndDrawText,

	typeEraseScreen,

	typeDrawRect,
	typeFillRect,
	typeEraseRect,

	typeDrawEllipse,
	typeFillEllipse,
	typeEraseEllipse,

	typeDrawVertLine,
	typeDrawHorizLine,
	typeDrawDiagonalLine,


	typeLast,
} TInstructions;

int index;

long idleLoopTime = 0;
float fElapsedTime[(TInstructions) (typeLast)];
long loopTime;
long elapsed;

inline void measureTime(const TInstructions nInstructionType)
{
	int x  = 50;
	int y  = 32;
	int x1 = 18;
	int y1 =  0;
	int x2 = 81;
	int y2 = 63;

	time1[executionTimer] = 0;
  for (index = 1; index <= kNumberOfLoops; ++index)
	{
    //
		// to measure a different instruction type, simply change the
		// definition of the following constant.
		//
		switch (nInstructionType)
		{
			//
			// Since 'nInstructionType' is a constant, code optimizer will eliminate
			// the 'switch' instruction and the 'dead code' for the unreachable
			// cases.
			//
			case typeIdleLoop:
				break;

			case typeSetPixel:
		    {
		    	nxtSetPixel(x, y); nxtSetPixel(x, y); nxtSetPixel(x, y); nxtSetPixel(x, y); nxtSetPixel(x, y);
		    	nxtSetPixel(x, y); nxtSetPixel(x, y); nxtSetPixel(x, y); nxtSetPixel(x, y); nxtSetPixel(x, y);
				}
				break;

			case typeClearPixel:
		    {
		    	nxtClearPixel(x, y); nxtClearPixel(x, y); nxtClearPixel(x, y); nxtClearPixel(x, y); nxtClearPixel(x, y);
		    	nxtClearPixel(x, y); nxtClearPixel(x, y); nxtClearPixel(x, y); nxtClearPixel(x, y); nxtClearPixel(x, y);
				}
				break;

			case typeDrawText:
		    {
		    	nxtDisplayStringAt( 7,  7, "Mindstorms NXT");
		    	nxtDisplayStringAt( 7,  7, "Mindstorms NXT");
		    	nxtDisplayStringAt( 7,  7, "Mindstorms NXT");
		    	nxtDisplayStringAt( 7,  7, "Mindstorms NXT");
		    	nxtDisplayStringAt( 7,  7, "Mindstorms NXT");

		    	nxtDisplayStringAt( 7,  7, "Mindstorms NXT");
		    	nxtDisplayStringAt( 7,  7, "Mindstorms NXT");
		    	nxtDisplayStringAt( 7,  7, "Mindstorms NXT");
		    	nxtDisplayStringAt( 7,  7, "Mindstorms NXT");
		    	nxtDisplayStringAt( 7,  7, "Mindstorms NXT");
				}
				break;

				case typeFormatAndDrawText:
		    {
		    	nxtDisplayStringAt( 7,  7, "Number is %d", x);
		    	nxtDisplayStringAt( 7,  7, "Number is %d", x);
		    	nxtDisplayStringAt( 7,  7, "Number is %d", x);
		    	nxtDisplayStringAt( 7,  7, "Number is %d", x);
		    	nxtDisplayStringAt( 7,  7, "Number is %d", x);

		    	nxtDisplayStringAt( 7,  7, "Number is %d", x);
		    	nxtDisplayStringAt( 7,  7, "Number is %d", x);
		    	nxtDisplayStringAt( 7,  7, "Number is %d", x);
		    	nxtDisplayStringAt( 7,  7, "Number is %d", x);
		    	nxtDisplayStringAt( 7,  7, "Number is %d", x);
				}
		    /*{
		    	nxtDisplayTextLine(3, "Number is %d", x);
		    	nxtDisplayTextLine(3, "Number is %d", x);
		    	nxtDisplayTextLine(3, "Number is %d", x);
		    	nxtDisplayTextLine(3, "Number is %d", x);
		    	nxtDisplayTextLine(3, "Number is %d", x);

		    	nxtDisplayTextLine(3, "Number is %d", x);
		    	nxtDisplayTextLine(3, "Number is %d", x);
		    	nxtDisplayTextLine(3, "Number is %d", x);
		    	nxtDisplayTextLine(3, "Number is %d", x);
		    	nxtDisplayTextLine(3, "Number is %d", x);
				}*/
				break;


			case typeEraseScreen:
		    {
		    	eraseDisplay(); eraseDisplay(); eraseDisplay(); eraseDisplay(); eraseDisplay();
		    	eraseDisplay(); eraseDisplay(); eraseDisplay(); eraseDisplay(); eraseDisplay();
				}
				break;

			case typeDrawRect:
		    {
		    	nxtDrawRect(x1, y1, x2, y2); nxtDrawRect(x1, y1, x2, y2); nxtDrawRect(x1, y1, x2, y2); nxtDrawRect(x1, y1, x2, y2); nxtDrawRect(x1, y1, x2, y2);
		    	nxtDrawRect(x1, y1, x2, y2); nxtDrawRect(x1, y1, x2, y2); nxtDrawRect(x1, y1, x2, y2); nxtDrawRect(x1, y1, x2, y2); nxtDrawRect(x1, y1, x2, y2);
				}
				break;

			case typeFillRect:
		    {
		    	nxtFillRect(x1, y1, x2, y2); nxtFillRect(x1, y1, x2, y2); nxtFillRect(x1, y1, x2, y2); nxtFillRect(x1, y1, x2, y2); nxtFillRect(x1, y1, x2, y2);
		    	nxtFillRect(x1, y1, x2, y2); nxtFillRect(x1, y1, x2, y2); nxtFillRect(x1, y1, x2, y2); nxtFillRect(x1, y1, x2, y2); nxtFillRect(x1, y1, x2, y2);
				}
				break;

			case typeEraseRect:
		    {
		    	nxtEraseRect(x1, y1, x2, y2); nxtEraseRect(x1, y1, x2, y2); nxtEraseRect(x1, y1, x2, y2); nxtEraseRect(x1, y1, x2, y2); nxtEraseRect(x1, y1, x2, y2);
		    	nxtEraseRect(x1, y1, x2, y2); nxtEraseRect(x1, y1, x2, y2); nxtEraseRect(x1, y1, x2, y2); nxtEraseRect(x1, y1, x2, y2); nxtEraseRect(x1, y1, x2, y2);
				}
				break;

			case typeDrawEllipse:
		    {
		    	nxtDrawEllipse(x1, y1, x2, y2); nxtDrawEllipse(x1, y1, x2, y2);
		    	nxtDrawEllipse(x1, y1, x2, y2); nxtDrawEllipse(x1, y1, x2, y2);
		    	nxtDrawEllipse(x1, y1, x2, y2); nxtDrawEllipse(x1, y1, x2, y2);
		    	nxtDrawEllipse(x1, y1, x2, y2); nxtDrawEllipse(x1, y1, x2, y2);
		    	nxtDrawEllipse(x1, y1, x2, y2); nxtDrawEllipse(x1, y1, x2, y2);
		    	nxtDrawEllipse(x1, y1, x2, y2); nxtDrawEllipse(x1, y1, x2, y2);
				}
				break;

			case typeFillEllipse:
		    {
		    	nxtFillEllipse(x1, y1, x2, y2); nxtFillEllipse(x1, y1, x2, y2);
		    	nxtFillEllipse(x1, y1, x2, y2); nxtFillEllipse(x1, y1, x2, y2);
		    	nxtFillEllipse(x1, y1, x2, y2); nxtFillEllipse(x1, y1, x2, y2);
		    	nxtFillEllipse(x1, y1, x2, y2); nxtFillEllipse(x1, y1, x2, y2);
		    	nxtFillEllipse(x1, y1, x2, y2); nxtFillEllipse(x1, y1, x2, y2);
				}
				break;

			case typeEraseEllipse:
		    {
		    	nxtEraseEllipse(x1, y1, x2, y2); nxtEraseEllipse(x1, y1, x2, y2);
		    	nxtEraseEllipse(x1, y1, x2, y2); nxtEraseEllipse(x1, y1, x2, y2);
		    	nxtEraseEllipse(x1, y1, x2, y2); nxtEraseEllipse(x1, y1, x2, y2);
		    	nxtEraseEllipse(x1, y1, x2, y2); nxtEraseEllipse(x1, y1, x2, y2);
		    	nxtEraseEllipse(x1, y1, x2, y2); nxtEraseEllipse(x1, y1, x2, y2);
				}
				break;

			case typeDrawVertLine:
		    {
		    	nxtDrawLine(x1, y1, x1, y2); nxtDrawLine(x1, y1, x1, y2);
		    	nxtDrawLine(x1, y1, x1, y2); nxtDrawLine(x1, y1, x1, y2);
		    	nxtDrawLine(x1, y1, x1, y2); nxtDrawLine(x1, y1, x1, y2);
		    	nxtDrawLine(x1, y1, x1, y2); nxtDrawLine(x1, y1, x1, y2);
		    	nxtDrawLine(x1, y1, x1, y2); nxtDrawLine(x1, y1, x1, y2);
				}
				break;

			case typeDrawHorizLine:
		    {
		    	nxtDrawLine(x1, y1, x2, y1); nxtDrawLine(x1, y1, x2, y1);
		    	nxtDrawLine(x1, y1, x2, y1); nxtDrawLine(x1, y1, x2, y1);
		    	nxtDrawLine(x1, y1, x2, y1); nxtDrawLine(x1, y1, x2, y1);
		    	nxtDrawLine(x1, y1, x2, y1); nxtDrawLine(x1, y1, x2, y1);
		    	nxtDrawLine(x1, y1, x2, y1); nxtDrawLine(x1, y1, x2, y1);
				}
				break;

			case typeDrawDiagonalLine:
		    {
		    	nxtDrawLine(x1, y1, x2, y2); nxtDrawLine(x1, y1, x2, y2);
		    	nxtDrawLine(x1, y1, x2, y2); nxtDrawLine(x1, y1, x2, y2);
		    	nxtDrawLine(x1, y1, x2, y2); nxtDrawLine(x1, y1, x2, y2);
		    	nxtDrawLine(x1, y1, x2, y2); nxtDrawLine(x1, y1, x2, y2);
		    	nxtDrawLine(x1, y1, x2, y2); nxtDrawLine(x1, y1, x2, y2);
				}
				break;

		}
	}
	loopTime = time10[executionTimer];
	if (loopTime < 3276)   // Overflow 15 bits?
		loopTime = time1[executionTimer];
	else
	  loopTime *= 10;

  elapsed = loopTime - idleLoopTime;
	fElapsedTime[nInstructionType] = ((float) elapsed) / (float) 10.0;
	if (nInstructionType == typeIdleLoop)
		idleLoopTime = loopTime;

	// 'elapsed' contains the number of 1 msec 'ticks' to execute 10,000 (1,000 loops
	// each with 10) statements. Thus if 'elapsed' is 146, a single statement took
	// 14.6 microseconds:
	//   - 146 millisecons total 'adjusted' time in loop (146 ticks x 1 milliseconds)
	//   - 146 milliseconds is same as 146,000 microseconds
	//   - divide by 10,000 to get 14.6 microseconds

	PlaySound(soundBlip);
	return;
}

task main()
{

	for (index = typeIdleLoop; index < typeLast; ++index)
	  fElapsedTime[index] = 0;

	measureTime(typeIdleLoop);

	measureTime(typeSetPixel);
	measureTime(typeClearPixel);

	measureTime(typeDrawRect);
	measureTime(typeFillRect);
	measureTime(typeEraseRect);

	measureTime(typeDrawText);
	measureTime(typeFormatAndDrawText);

	measureTime(typeDrawEllipse);
	measureTime(typeFillEllipse);
	measureTime(typeEraseEllipse);

	measureTime(typeDrawVertLine);
	measureTime(typeDrawHorizLine);
	measureTime(typeDrawDiagonalLine);

	measureTime(typeEraseScreen);

	PlaySound(soundBeepBeep);
	while (bSoundActive)
	{}
	return;
}