#include <eve.h>
#include <SPI.h>

volatile unsigned int cmdOffset = 0x0000;

void host_command(unsigned char data)
{
  SPI.setSS(LOW);
  delayMicroseconds(5);
  SPI.transfer(data);
  SPI.transfer(0x00);
  SPI.transfer(0x00);
  SPI.setSS(HIGH); 
}

void cmdparam8(unsigned char data)
{
  SPI.setSS(LOW);
  delayMicroseconds(5);
  SPI.transfer(data);
  SPI.setSS(HIGH); 
}

void wr8(unsigned long address, unsigned char data)
{
  SPI.setSS(LOW);
  delayMicroseconds(5);
  SPI.transfer(address >> 16 | 0x80);
  SPI.transfer(address >> 8);
  SPI.transfer(address);
  SPI.transfer(data);
  SPI.setSS(HIGH);  
}

void wr16(unsigned long address, unsigned int data)
{
  SPI.setSS(LOW);
  delayMicroseconds(5);
  SPI.transfer(address >> 16 | 0x80);
  SPI.transfer(address >> 8);
  SPI.transfer(address);
  SPI.transfer(data);
  SPI.transfer(data >> 8);
  SPI.setSS(HIGH);
}

void wr32(unsigned long address, unsigned long data)
{
  SPI.setSS(LOW);
  delayMicroseconds(5);
  SPI.transfer(address >> 16 | 0x80);
  SPI.transfer(address >> 8);
  SPI.transfer(address);
  SPI.transfer(data);
  SPI.transfer(data >>  8);
  SPI.transfer(data >> 16);
  SPI.transfer(data >> 24);
  SPI.setSS(HIGH);  
}


unsigned char rd8(unsigned long address)
{
  unsigned char data = 0;
  SPI.setSS(LOW);
  delayMicroseconds(5);
  SPI.transfer(address >> 16 | 0x00);
  SPI.transfer(address >> 8);
  SPI.transfer(address);
  SPI.transfer(0x00);
  data = SPI.transfer(0x00);
  SPI.setSS(HIGH);
  return(data);
}

unsigned int rd16(unsigned long address)
{
  unsigned int data = 0;
  SPI.setSS(LOW);
  delayMicroseconds(5);
  SPI.transfer(address >> 16 | 0x00);
  SPI.transfer(address >> 8);
  SPI.transfer(address);
  SPI.transfer(0x00);
  data = SPI.transfer(0x00); 
  data |= SPI.transfer(0x00) <<  8;
  SPI.setSS(HIGH);
  return(data);
}


unsigned int rd32(unsigned long address)
{
  unsigned long data = 0;
  SPI.setSS(LOW);
  delayMicroseconds(5);
  SPI.transfer(address >> 16 | 0x00);
  SPI.transfer(address >>  8);
  SPI.transfer(address);
  SPI.transfer(0x00);
  data = SPI.transfer(0x00) ;
  data |= SPI.transfer(0x00) << 8;
  data |= SPI.transfer(0x00) << 16; 
  data |= SPI.transfer(0x00) << 24;
  SPI.setSS(HIGH);
  return(data);
} 

unsigned long get_touch_tag(void)
{
	unsigned long value;

	value = rd32(REG_TOUCH_TAG);
	return value;
}

unsigned int cmd_busy(void)
{
	unsigned int cmdBufferRead;

	cmdBufferRead = rd16(REG_CMD_READ);	// Read the graphics processor read pointer

	if(cmdOffset != cmdBufferRead)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

void cmd_execute(void)
{
		uint32_t ftAddress;

	ftAddress = REG_CMD_WRITE;

	SPI.setSS(LOW);
	SPI.transfer((uint8_t)(ftAddress >> 16)); // Send Memory Write plus high address byte
	SPI.transfer((uint8_t)(ftAddress >> 8));	// Send middle address byte
	SPI.transfer((uint8_t)(ftAddress));			// Send low address byte
	SPI.transfer((uint8_t)(cmdOffset));			// Send data low byte
	SPI.transfer((uint8_t)(cmdOffset >> 8));	// Send data high byte
	SPI.setSS(HIGH);
	
}


void inc_cmdOffset(unsigned int increment)
{
	cmdOffset += increment;
	cmdOffset &= 0x0fff;
}


void start_cmd(unsigned long command)
{
	unsigned long ftAddress;
	ftAddress = RAM_CMD + cmdOffset;
	wr32(ftAddress, command);
	inc_cmdOffset(4);
}

void cmd_dl(unsigned long command)
{
  start_cmd(command);  
}

void write_string(const char *text)
{
	unsigned int textindex = 0;
	unsigned int padding = 0;

	while(text[textindex] != 0)
	{
		cmdparam8(text[textindex]);
		textindex++;
	}

	padding = textindex % 4;  // 0, 1, 2 oder 3
	padding = 4-padding; // 4, 3, 2, 1

	while(padding > 0)
	{
		cmdparam8(0);
		padding--;
		textindex++;
	}

	inc_cmdOffset(textindex);	// update the command-ram pointer
}

void cmd_swap(void)
{
  wr8(REG_DLSWAP, DLSWAP_FRAME);
}

void cmd_romfont(uint32_t font, uint32_t romslot)
{
	start_cmd(CMD_ROMFONT);
	
	cmdparam8((uint8_t)(font));
	cmdparam8((uint8_t)(font >> 8));
	cmdparam8((uint8_t)(0));
	cmdparam8((uint8_t)(0));

	cmdparam8((uint8_t)(romslot));
	cmdparam8((uint8_t)(romslot >> 8));
    cmdparam8((uint8_t)(0));
	cmdparam8((uint8_t)(0));
	
	inc_cmdOffset(8);	
}

void cmd_text(int16_t x0, int16_t y0, int16_t font, uint16_t options, const char* text)
{
	start_cmd(CMD_TEXT);

	cmdparam8((uint8_t)(x0));
	cmdparam8((uint8_t)(x0 >> 8));

	cmdparam8((uint8_t)(y0));
	cmdparam8((uint8_t)(y0 >> 8));

	cmdparam8((uint8_t)(font));
	cmdparam8((uint8_t)(font >> 8));

	cmdparam8((uint8_t)(options));
	cmdparam8((uint8_t)(options >> 8));

	inc_cmdOffset(8);	// update the command-ram pointer
	write_string(text);

}

void cmd_button(int16_t x0, int16_t y0, int16_t w0, int16_t h0, int16_t font, uint16_t options, const char* text)
{
	start_cmd(CMD_BUTTON);

	cmdparam8((uint8_t)(x0));
	cmdparam8((uint8_t)(x0 >> 8));

	cmdparam8((uint8_t)(y0));
	cmdparam8((uint8_t)(y0 >> 8));

	cmdparam8((uint8_t)(w0));
	cmdparam8((uint8_t)(w0 >> 8));

	cmdparam8((uint8_t)(h0));
	cmdparam8((uint8_t)(h0 >> 8));

	cmdparam8((uint8_t)(font));
	cmdparam8((uint8_t)(font >> 8));

	cmdparam8((uint8_t)(options));
	cmdparam8((uint8_t)(options >> 8));

	inc_cmdOffset(12);	// update the command-ram pointer
	write_string(text);
	
}

void cmd_clock(int16_t x0, int16_t y0, int16_t r0, uint16_t options, uint16_t hours, uint16_t minutes, uint16_t seconds)
{
	start_cmd(CMD_CLOCK);

	cmdparam8((uint8_t)(x0));
	cmdparam8((uint8_t)(x0 >> 8));

	cmdparam8((uint8_t)(y0));
	cmdparam8((uint8_t)(y0 >> 8));

	cmdparam8((uint8_t)(r0));
	cmdparam8((uint8_t)(r0 >> 8));

	cmdparam8((uint8_t)(options));
	cmdparam8((uint8_t)(options >> 8));

	cmdparam8((uint8_t)(hours));
	cmdparam8((uint8_t)(hours >> 8));

	cmdparam8((uint8_t)(minutes));
	cmdparam8((uint8_t)(minutes >> 8));

	cmdparam8((uint8_t)(seconds));
	cmdparam8((uint8_t)(seconds >> 8));
	cmdparam8(0x00); // millis low
	cmdparam8(0x00); // millis high
    SPI.setSS(HIGH);
	
	inc_cmdOffset(16);	// update the command-ram pointer
}


void cmd_bgcolor(uint32_t color)
{
	start_cmd(CMD_BGCOLOR);

	cmdparam8((uint8_t)(color));		// Send data low byte
	cmdparam8((uint8_t)(color >> 8));
	cmdparam8((uint8_t)(color >> 16));
	cmdparam8(0x00);
    SPI.setSS(HIGH);
	inc_cmdOffset(4);	// update the command-ram pointer
	
}


void cmd_fgcolor(uint32_t color)
{
	start_cmd(CMD_FGCOLOR);

	cmdparam8((uint8_t)(color));		// Send data low byte
	cmdparam8((uint8_t)(color >> 8));
	cmdparam8((uint8_t)(color >> 16));
	cmdparam8(0x00);
    SPI.setSS(HIGH); 
	inc_cmdOffset(4);	// update the command-ram pointer
}


void cmd_gradcolor(uint32_t color)
{
	start_cmd(CMD_GRADCOLOR);

	cmdparam8((uint8_t)(color));		// Send data low byte
	cmdparam8((uint8_t)(color >> 8));
	cmdparam8((uint8_t)(color >> 16));
	cmdparam8(0x00);
    SPI.setSS(HIGH);
	inc_cmdOffset(4);	// update the command-ram pointer
}


void cmd_gauge(int16_t x0, int16_t y0, int16_t r0, uint16_t options, uint16_t major, uint16_t minor, uint16_t val, uint16_t range)
{
	start_cmd(CMD_GAUGE);

	cmdparam8((uint8_t)(x0));
	cmdparam8((uint8_t)(x0 >> 8));

	cmdparam8((uint8_t)(y0));
	cmdparam8((uint8_t)(y0 >> 8));

	cmdparam8((uint8_t)(r0));
	cmdparam8((uint8_t)(r0 >> 8));

	cmdparam8((uint8_t)(options));
	cmdparam8((uint8_t)(options >> 8));

	cmdparam8((uint8_t)(major));
	cmdparam8((uint8_t)(major >> 8));

	cmdparam8((uint8_t)(minor));
	cmdparam8((uint8_t)(minor >> 8));

	cmdparam8((uint8_t)(val));
	cmdparam8((uint8_t)(val >> 8));

	cmdparam8((uint8_t)(range));
	cmdparam8((uint8_t)(range >> 8));
    SPI.setSS(HIGH); 
	inc_cmdOffset(16);	// update the command-ram pointer
}


void cmd_gradient(int16_t x0, int16_t y0, uint32_t rgb0, int16_t x1, int16_t y1, uint32_t rgb1)
{
	start_cmd(CMD_GRADIENT);

	cmdparam8((uint8_t)(x0));
	cmdparam8((uint8_t)(x0 >> 8));

	cmdparam8((uint8_t)(y0));
	cmdparam8((uint8_t)(y0 >> 8));

	cmdparam8((uint8_t)(rgb0));		// Send data low byte
	cmdparam8((uint8_t)(rgb0 >> 8));
	cmdparam8((uint8_t)(rgb0 >> 16));
	cmdparam8(0x00);

	cmdparam8((uint8_t)(x1));
	cmdparam8((uint8_t)(x1 >> 8));

	cmdparam8((uint8_t)(y1));
	cmdparam8((uint8_t)(y1 >> 8));

	cmdparam8((uint8_t)(rgb1));		// Send data low byte
	cmdparam8((uint8_t)(rgb1 >> 8));
	cmdparam8((uint8_t)(rgb1 >> 16));
	cmdparam8(0x00);
    SPI.setSS(HIGH);
	inc_cmdOffset(16);	// update the command-ram pointer
}


void cmd_keys(int16_t x0, int16_t y0, int16_t w0, int16_t h0, int16_t font, uint16_t options, const char* text)
{
	start_cmd(CMD_KEYS);

	cmdparam8((uint8_t)(x0));
	cmdparam8((uint8_t)(x0 >> 8));

	cmdparam8((uint8_t)(y0));
	cmdparam8((uint8_t)(y0 >> 8));

	cmdparam8((uint8_t)(w0));
	cmdparam8((uint8_t)(w0 >> 8));

	cmdparam8((uint8_t)(h0));
	cmdparam8((uint8_t)(h0 >> 8));

	cmdparam8((uint8_t)(font));
	cmdparam8((uint8_t)(font >> 8));

	cmdparam8((uint8_t)(options));
	cmdparam8((uint8_t)(options >> 8));

	inc_cmdOffset(12);	// update the command-ram pointer
	write_string(text);
	SPI.setSS(HIGH);
}


void cmd_progress(int16_t x0, int16_t y0, int16_t w0, int16_t h0, uint16_t options, uint16_t val, uint16_t range)
{
	start_cmd(CMD_PROGRESS);

	cmdparam8((uint8_t)(x0));
	cmdparam8((uint8_t)(x0 >> 8));

	cmdparam8((uint8_t)(y0));
	cmdparam8((uint8_t)(y0 >> 8));

	cmdparam8((uint8_t)(w0));
	cmdparam8((uint8_t)(w0 >> 8));

	cmdparam8((uint8_t)(h0));
	cmdparam8((uint8_t)(h0 >> 8));

	cmdparam8((uint8_t)(options));
	cmdparam8((uint8_t)(options >> 8));

	cmdparam8((uint8_t)(val));
	cmdparam8((uint8_t)(val >> 8));

	cmdparam8((uint8_t)(range));
	cmdparam8((uint8_t)(range >> 8));

	cmdparam8(0x00); // dummy byte for 4-byte alignement
	cmdparam8(0x00); // dummy byte for 4-byte alignement
    SPI.setSS(HIGH);
	inc_cmdOffset(16);	// update the command-ram pointer
}


void cmd_scrollbar(int16_t x0, int16_t y0, int16_t w0, int16_t h0, uint16_t options, uint16_t val, uint16_t size, uint16_t range)
{
	start_cmd(CMD_SCROLLBAR);

	cmdparam8((uint8_t)(x0));
	cmdparam8((uint8_t)(x0 >> 8));

	cmdparam8((uint8_t)(y0));
	cmdparam8((uint8_t)(y0 >> 8));

	cmdparam8((uint8_t)(w0));
	cmdparam8((uint8_t)(w0 >> 8));

	cmdparam8((uint8_t)(h0));
	cmdparam8((uint8_t)(h0 >> 8));

	cmdparam8((uint8_t)(options));
	cmdparam8((uint8_t)(options >> 8));

	cmdparam8((uint8_t)(val));
	cmdparam8((uint8_t)(val >> 8));

	cmdparam8((uint8_t)(size));
	cmdparam8((uint8_t)(size >> 8));

	cmdparam8((uint8_t)(range));
	cmdparam8((uint8_t)(range >> 8));
    SPI.setSS(HIGH);
	inc_cmdOffset(16);	// update the command-ram pointer
}


void cmd_slider(int16_t x1, int16_t y1, int16_t w1, int16_t h1, uint16_t options, uint16_t val, uint16_t range)
{
	start_cmd(CMD_SLIDER);

	cmdparam8((uint8_t)(x1));
	cmdparam8((uint8_t)(x1 >> 8));

	cmdparam8((uint8_t)(y1));
	cmdparam8((uint8_t)(y1 >> 8));

	cmdparam8((uint8_t)(w1));
	cmdparam8((uint8_t)(w1 >> 8));

	cmdparam8((uint8_t)(h1));
	cmdparam8((uint8_t)(h1 >> 8));

	cmdparam8((uint8_t)(options));
	cmdparam8((uint8_t)(options >> 8));

	cmdparam8((uint8_t)(val));
	cmdparam8((uint8_t)(val >> 8));

	cmdparam8((uint8_t)(range));
	cmdparam8((uint8_t)(range >> 8));

	cmdparam8(0x00); // dummy byte for 4-byte alignement
	cmdparam8(0x00); // dummy byte for 4-byte alignement
	SPI.setSS(HIGH);
    inc_cmdOffset(16);	// update the command-ram pointer
}


void _cmd_dial(int16_t x0, int16_t y0, int16_t r0, uint16_t options, uint16_t val)
{
	start_cmd(CMD_DIAL);

	cmdparam8((uint8_t)(x0));
	cmdparam8((uint8_t)(x0 >> 8));

	cmdparam8((uint8_t)(y0));
	cmdparam8((uint8_t)(y0 >> 8));

	cmdparam8((uint8_t)(r0));
	cmdparam8((uint8_t)(r0 >> 8));

	cmdparam8((uint8_t)(options));
	cmdparam8((uint8_t)(options >> 8));

	cmdparam8((uint8_t)(val));
	cmdparam8((uint8_t)(val >> 8));

	cmdparam8(0);
	cmdparam8(0);
    SPI.setSS(HIGH);
	inc_cmdOffset(12);	// update the command-ram pointer
}


void cmd_toggle(int16_t x0, int16_t y0, int16_t w0, int16_t font, uint16_t options, uint16_t state, const char* text)
{
	start_cmd(CMD_TOGGLE);

	cmdparam8((uint8_t)(x0));
	cmdparam8((uint8_t)(x0 >> 8));

	cmdparam8((uint8_t)(y0));
	cmdparam8((uint8_t)(y0 >> 8));

	cmdparam8((uint8_t)(w0));
	cmdparam8((uint8_t)(w0 >> 8));

	
	cmdparam8((uint8_t)(font));
	cmdparam8((uint8_t)(font >> 8));

	cmdparam8((uint8_t)(options));
	cmdparam8((uint8_t)(options >> 8));

	cmdparam8((uint8_t)(state));
	cmdparam8((uint8_t)(state >> 8));
    SPI.setSS(HIGH);
	inc_cmdOffset(12);	// update the command-ram pointer
	write_string(text);
}


#ifdef FT_81X_ENABLE
void cmd_setbase(uint32_t base)
{
	start_cmd(CMD_SETBASE);

	cmdparam8((uint8_t)(base));		// Send data low byte
	cmdparam8((uint8_t)(base >> 8));
	cmdparam8((uint8_t)(base >> 16));
	cmdparam8((uint8_t)(base >> 24));		// Send data high byte
	SPI.setSS(HIGH);
	inc_cmdOffset(12);	// update the command-ram pointer	
}
#endif

#ifdef FT_81X_ENABLE
void cmd_setbitmap(uint32_t addr, uint16_t fmt, uint16_t width, uint16_t height)
{
	start_cmd(CMD_SETBITMAP);

	cmdparam8((uint8_t)(addr));
	cmdparam8((uint8_t)(addr >> 8));
	cmdparam8((uint8_t)(addr >> 16));
	cmdparam8((uint8_t)(addr >> 24));
	
	cmdparam8((uint8_t)(fmt));
	cmdparam8((uint8_t)(fmt>> 8));

	cmdparam8((uint8_t)(width));
	cmdparam8((uint8_t)(width >> 8));

	cmdparam8((uint8_t)(height));
	cmdparam8((uint8_t)(height >> 8));

	cmdparam8(0);
	cmdparam8(0);	
    SPI.setSS(HIGH);
	inc_cmdOffset(12);	// update the command-ram pointer	
}
#endif


void cmd_number(int16_t x0, int16_t y0, int16_t font, uint16_t options, int32_t number)
{
	start_cmd(CMD_NUMBER);

	cmdparam8((uint8_t)(x0));
	cmdparam8((uint8_t)(x0 >> 8));

	cmdparam8((uint8_t)(y0));
	cmdparam8((uint8_t)(y0 >> 8));

	cmdparam8((uint8_t)(font));
	cmdparam8((uint8_t)(font >> 8));

	cmdparam8((uint8_t)(options));
	cmdparam8((uint8_t)(options >> 8));

	cmdparam8((uint8_t)(number));		// Send data low byte
	cmdparam8((uint8_t)(number >> 8));
	cmdparam8((uint8_t)(number >> 16));
	cmdparam8((uint8_t)(number >> 24));		// Send data high byte
    SPI.setSS(HIGH);
	inc_cmdOffset(12);	// update the command-ram pointer
}


// commands to operate on memory:

void cmd_memzero(uint32_t ptr, uint32_t num)
{
	start_cmd(CMD_MEMZERO);

	cmdparam8((uint8_t)(ptr));
	cmdparam8((uint8_t)(ptr >> 8));
	cmdparam8((uint8_t)(ptr >> 16));
	cmdparam8((uint8_t)(ptr >> 24));

	cmdparam8((uint8_t)(num));
	cmdparam8((uint8_t)(num >> 8));
	cmdparam8((uint8_t)(num >> 16));
	cmdparam8((uint8_t)(num >> 24));
    SPI.setSS(HIGH);
	inc_cmdOffset(8);	// update the command-ram pointer
}


void cmd_memset(uint32_t ptr, uint8_t value, uint32_t num)
{
	start_cmd(CMD_MEMSET);

	cmdparam8((uint8_t)(ptr));
	cmdparam8((uint8_t)(ptr >> 8));
	cmdparam8((uint8_t)(ptr >> 16));
	cmdparam8((uint8_t)(ptr >> 24));

	cmdparam8(value);
	cmdparam8(0);
	cmdparam8(0);
	cmdparam8(0);

	cmdparam8((uint8_t)(num));
	cmdparam8((uint8_t)(num >> 8));
	cmdparam8((uint8_t)(num >> 16));
	cmdparam8((uint8_t)(num >> 24));

	SPI.setSS(HIGH);
	inc_cmdOffset(12);	// update the command-ram pointer
}


/*
void ft800_cmd_memwrite(uint32_t dest, uint32_t num, const uint8_t *data)
{
	ft800_start_cmd(CMD_MEMWRITE);

	spi_transmit((uint8_t)(dest));
	spi_transmit((uint8_t)(dest >> 8));
	spi_transmit((uint8_t)(dest >> 16));
	spi_transmit((uint8_t)(dest >> 24));

	spi_transmit((uint8_t)(num));
	spi_transmit((uint8_t)(num >> 8));
	spi_transmit((uint8_t)(num >> 16));
	spi_transmit((uint8_t)(num >> 24));

	num = (num + 3)&(~3);

	for(count=0;count<len;count++)
	{
		spi_transmit(pgm_read_byte_far(data+count));
	}

	ft800_cs_clear();
	ft800_inc_cmdoffset(8+len);	// update the command-ram pointer
}
*/


void cmd_memcpy(uint32_t dest, uint32_t src, uint32_t num)
{
	start_cmd(CMD_MEMCPY);

	cmdparam8((uint8_t)(dest));
	cmdparam8((uint8_t)(dest >> 8));
	cmdparam8((uint8_t)(dest >> 16));
	cmdparam8((uint8_t)(dest >> 24));

	cmdparam8((uint8_t)(src));
	cmdparam8((uint8_t)(src >> 8));
	cmdparam8((uint8_t)(src >> 16));
	cmdparam8((uint8_t)(src >> 24));

	cmdparam8((uint8_t)(num));
	cmdparam8((uint8_t)(num >> 8));
	cmdparam8((uint8_t)(num >> 16));
	cmdparam8((uint8_t)(num >> 24));
    SPI.setSS(HIGH);
	inc_cmdOffset(12);	// update the command-ram pointer
}


void cmd_append(uint32_t ptr, uint32_t num)
{
	start_cmd(CMD_APPEND);

	cmdparam8((uint8_t)(ptr));
	cmdparam8((uint8_t)(ptr >> 8));
	cmdparam8((uint8_t)(ptr >> 16));
	cmdparam8((uint8_t)(ptr >> 24));

	cmdparam8((uint8_t)(num));
	cmdparam8((uint8_t)(num >> 8));
	cmdparam8((uint8_t)(num >> 16));
	cmdparam8((uint8_t)(num >> 24));
    SPI.setSS(HIGH);
	inc_cmdOffset(8);	// update the command-ram pointer
}


// commands for loading image data into FT800 memory:

void spi_flash_write(const uint8_t *data, uint16_t len)
{
	uint16_t count;

	len = (len + 3)&(~3);

	for(count=0;count<len;count++)
	{
		cmdparam8(fetch_flash_byte(data));
	}

	inc_cmdOffset(len);	// update the command-ram pointer
}


void cmd_inflate(uint32_t ptr, const uint8_t *data, uint16_t len)
{
	start_cmd(CMD_INFLATE);

	cmdparam8((uint8_t)(ptr));		// Send data low byte
	cmdparam8((uint8_t)(ptr >> 8));
	cmdparam8((uint8_t)(ptr >> 16));
	cmdparam8((uint8_t)(ptr >> 24));		// Send data high byte
    SPI.setSS(HIGH);
	inc_cmdOffset(4);	// update the command-ram pointer

	spi_flash_write(data,len);

}


void cmd_loadimage(uint32_t ptr, uint32_t options, const uint8_t *data, uint16_t len)
{
	start_cmd(CMD_LOADIMAGE);

	cmdparam8((uint8_t)(ptr));		// Send data low byte
	cmdparam8((uint8_t)(ptr >> 8));
	cmdparam8((uint8_t)(ptr >> 16));
	cmdparam8((uint8_t)(ptr >> 24));		// Send data high byte

	cmdparam8((uint8_t)(options));		// Send data low byte
	cmdparam8((uint8_t)(options >> 8));
	cmdparam8((uint8_t)(options >> 16));
	cmdparam8((uint8_t)(options >> 24));		// Send data high byte
    SPI.setSS(HIGH);
	inc_cmdOffset(8);	// update the command-ram pointer

	spi_flash_write(data,len);

}



void cmd_mediafifo(uint32_t ptr, uint32_t size)
{
	start_cmd(CMD_MEDIAFIFO);

	cmdparam8((uint8_t)(ptr));		// Send data low byte
	cmdparam8((uint8_t)(ptr >> 8));
	cmdparam8((uint8_t)(ptr >> 16));
	cmdparam8((uint8_t)(ptr >> 24));		// Send data high byte

	cmdparam8((uint8_t)(size));		// Send data low byte
	cmdparam8((uint8_t)(size >> 8));
	cmdparam8((uint8_t)(size >> 16));
	cmdparam8((uint8_t)(size >> 24));		// Send data high byte
	SPI.setSS(HIGH);
	inc_cmdOffset(8);	// update the command-ram pointer
}




// commands for setting the bitmap transform matrix:

void cmd_loadidentity(void)
{
	start_cmd(CMD_LOADIDENTIY);
	
}


void cmd_translate(int32_t tx, int32_t ty)
{
	start_cmd(CMD_TRANSLATE);

	cmdparam8((uint8_t)(tx));		// Send data low byte
	cmdparam8((uint8_t)(tx >> 8));
	cmdparam8((uint8_t)(tx >> 16));
	cmdparam8((uint8_t)(tx >> 24));		// Send data high byte

	cmdparam8((uint8_t)(ty));		// Send data low byte
	cmdparam8((uint8_t)(ty >> 8));
	cmdparam8((uint8_t)(ty >> 16));
	cmdparam8((uint8_t)(ty >> 24));		// Send data high byte
    SPI.setSS(HIGH);
	inc_cmdOffset(8);	// update the command-ram pointer
}


void cmd_scale(int32_t sx, int32_t sy)
{
	start_cmd(CMD_SCALE);

	cmdparam8((uint8_t)(sx));		// Send data low byte
	cmdparam8((uint8_t)(sx >> 8));
	cmdparam8((uint8_t)(sx >> 16));
	cmdparam8((uint8_t)(sx >> 24));		// Send data high byte

	cmdparam8((uint8_t)(sy));		// Send data low byte
	cmdparam8((uint8_t)(sy >> 8));
	cmdparam8((uint8_t)(sy >> 16));
	cmdparam8((uint8_t)(sy >> 24));		// Send data high byte
    SPI.setSS(HIGH);
	inc_cmdOffset(8);	// update the command-ram pointer
}


void cmd_rotate(int32_t ang)
{
	start_cmd(CMD_ROTATE);

	cmdparam8((uint8_t)(ang));		// Send data low byte
	cmdparam8((uint8_t)(ang >> 8));
	cmdparam8((uint8_t)(ang >> 16));
	cmdparam8((uint8_t)(ang >> 24));		// Send data high byte
    SPI.setSS(HIGH);
	inc_cmdOffset(4);	// update the command-ram pointer
}


void cmd_setmatrix(void)
{
	start_cmd(CMD_SETMATRIX);
	
}


// the description in the programmers guide is strange for this funtion
// while it is named *get*matrix, parameters 'a' to 'f' are supplied to
// the function and described as "output parameter"
// best guess is that this one allows to setup the matrix coefficients manually
// instead automagically like with _translate, _scale and _rotate
// if this assumption is correct it rather should be named cmd_setupmatrix()
void cmd_getmatrix(int32_t a, int32_t b, int32_t c, int32_t d, int32_t e, int32_t f)
{
	start_cmd(CMD_SETMATRIX);

	cmdparam8((uint8_t)(a));
	cmdparam8((uint8_t)(a >> 8));
	cmdparam8((uint8_t)(a >> 16));
	cmdparam8((uint8_t)(a >> 24));

	cmdparam8((uint8_t)(b));
	cmdparam8((uint8_t)(b >> 8));
	cmdparam8((uint8_t)(b >> 16));
	cmdparam8((uint8_t)(b >> 24));

	cmdparam8((uint8_t)(c));
	cmdparam8((uint8_t)(c >> 8));
	cmdparam8((uint8_t)(c >> 16));
	cmdparam8((uint8_t)(c >> 24));

	cmdparam8((uint8_t)(d));
	cmdparam8((uint8_t)(d >> 8));
	cmdparam8((uint8_t)(d >> 16));
	cmdparam8((uint8_t)(d >> 24));

	cmdparam8((uint8_t)(e));
	cmdparam8((uint8_t)(e >> 8));
	cmdparam8((uint8_t)(e >> 16));
	cmdparam8((uint8_t)(e >> 24));

	cmdparam8((uint8_t)(f));
	cmdparam8((uint8_t)(f >> 8));
	cmdparam8((uint8_t)(f >> 16));
	cmdparam8((uint8_t)(f >> 24));
    SPI.setSS(HIGH);
	inc_cmdOffset(24);	// update the command-ram pointer
}


// other commands:

void cmd_calibrate(void)
{
	start_cmd(CMD_CALIBRATE);

	cmdparam8(0);
	cmdparam8(0);
	cmdparam8(0);
	cmdparam8(0);
    SPI.setSS(HIGH);
	inc_cmdOffset(4);	// update the command-ram pointer
}


void cmd_coldstart(void)
{
	start_cmd(CMD_COLDSTART);
	
}


void cmd_interrupt(uint32_t ms)
{
	start_cmd(CMD_SNAPSHOT);

	cmdparam8((uint8_t)(ms));
	cmdparam8((uint8_t)(ms >> 8));
	cmdparam8((uint8_t)(ms >> 16));
	cmdparam8((uint8_t)(ms >> 24));
	SPI.setSS(HIGH);
	inc_cmdOffset(4);	// update the command-ram pointer
}


void cmd_logo(void)
{
	start_cmd(CMD_LOGO);

}


void cmd_screensaver(void)
{
	start_cmd(CMD_SCREENSAVER);
	
}


#ifdef FT_81X_ENABLE
void cmd_setrotate(uint32_t r)
{
	start_cmd(CMD_SETROTATE);

	cmdparam8((uint8_t)(r));
	cmdparam8((uint8_t)(r >> 8));
	cmdparam8uint8_t)(r >> 16));
	cmdparam8((uint8_t)(r >> 24));
	SPI.setSS(HIGH);
	inc_cmdOffset(4);	// update the command-ram pointer
}
#endif


void cmd_sketch(int16_t x0, int16_t y0, uint16_t w0, uint16_t h0, uint32_t ptr, uint16_t format)
{
	start_cmd(CMD_SKETCH);

	cmdparam8((uint8_t)(x0));
	cmdparam8((uint8_t)(x0 >> 8));

	cmdparam8((uint8_t)(y0));
	cmdparam8((uint8_t)(y0 >> 8));

	cmdparam8((uint8_t)(w0));
	cmdparam8((uint8_t)(w0 >> 8));

	cmdparam8((uint8_t)(h0));
	cmdparam8((uint8_t)(h0 >> 8));

	cmdparam8((uint8_t)(ptr));
	cmdparam8((uint8_t)(ptr >> 8));
	cmdparam8((uint8_t)(ptr >> 16));
	cmdparam8((uint8_t)(ptr >> 24));

	cmdparam8((uint8_t)(format));
	cmdparam8((uint8_t)(format >> 8));

	cmdparam8(0);
	cmdparam8(0);
	SPI.setSS(HIGH);
	inc_cmdOffset(16);	// update the command-ram pointer
}


void cmd_snapshot(uint32_t ptr)
{
	start_cmd(CMD_SNAPSHOT);

	cmdparam8((uint8_t)(ptr));
	cmdparam8((uint8_t)(ptr >> 8));
	cmdparam8((uint8_t)(ptr >> 16));
	cmdparam8((uint8_t)(ptr >> 24));
    SPI.setSS(HIGH);
	inc_cmdOffset(4);	// update the command-ram pointer
}


void cmd_spinner(int16_t x0, int16_t y0, uint16_t style, uint16_t scale)
{
	start_cmd(CMD_SPINNER);

	cmdparam8((uint8_t)(x0));
	cmdparam8((uint8_t)(x0 >> 8));

	cmdparam8((uint8_t)(y0));
	cmdparam8((uint8_t)(y0 >> 8));

	cmdparam8((uint8_t)(style));
	cmdparam8((uint8_t)(style >> 8));

	cmdparam8((uint8_t)(scale));
	cmdparam8((uint8_t)(scale >> 8));
    SPI.setSS(HIGH);
	inc_cmdOffset(8);	// update the command-ram pointer
}


void cmd_stop(void)
{
	start_cmd(CMD_STOP);

}


void cmd_track(int16_t x0, int16_t y0, int16_t w0, int16_t h0, int16_t tag)
{
	start_cmd(CMD_TRACK);

	cmdparam8((uint8_t)(x0));
	cmdparam8((uint8_t)(x0 >> 8));

	cmdparam8((uint8_t)(y0));
	cmdparam8((uint8_t)(y0 >> 8));

	cmdparam8((uint8_t)(w0));
	cmdparam8((uint8_t)(w0 >> 8));

	cmdparam8((uint8_t)(h0));
	cmdparam8((uint8_t)(h0 >> 8));

	cmdparam8((uint8_t)(tag));
	cmdparam8((uint8_t)(tag >> 8));

	cmdparam8(0);
	cmdparam8(0);
    SPI.setSS(HIGH);
	inc_cmdOffset(12);	// update the command-ram pointer
}
/*
void cmd_point(int16_t x0, int16_t y0, uint16_t size)
{
	uint32_t calc;

	start_cmd((DL_BEGIN | POINTS));

	calc = POINT_SIZE(size*16);
	cmdparam8((uint8_t)(calc));
	cmdparam8((uint8_t)(calc >> 8));
	cmdparam8((uint8_t)(calc >> 16));
	cmdparam8((uint8_t)(calc >> 24));

	calc = VERTEX2F(x0 * 16, y0 * 16);
	cmdparam8((uint8_t)(calc));
	cmdparam8((uint8_t)(calc >> 8));
	cmdparam8((uint8_t)(calc >> 16));
	cmdparam8((uint8_t)(calc >> 24));

	cmdparam8((uint8_t)(DL_END));		// Send data low byte
	cmdparam8((uint8_t)(DL_END >> 8));
	cmdparam8((uint8_t)(DL_END >> 16));
	cmdparam8((uint8_t)(DL_END >> 24));		// Send data high byte
    SPI.setSS(HIGH);
	inc_cmdOffset(12);	// update the command-ram pointer
}


void cmd_line(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t width)
{
	uint32_t calc;

	start_cmd((DL_BEGIN | LINES));

	calc = LINE_WIDTH(width * 16);
	cmdparam8((uint8_t)(calc));
	cmdparam8((uint8_t)(calc >> 8));
	cmdparam8((uint8_t)(calc >> 16));
	cmdparam8((uint8_t)(calc >> 24));

	calc = VERTEX2F(x0 * 16, y0 * 16);
	cmdparam8((uint8_t)(calc));
	cmdparam8((uint8_t)(calc >> 8));
	cmdparam8((uint8_t)(calc >> 16));
	cmdparam8((uint8_t)(calc >> 24));

	calc = VERTEX2F(x1 * 16, y1 * 16);
	cmdparam8((uint8_t)(calc));
	cmdparam8((uint8_t)(calc >> 8));
	cmdparam8((uint8_t)(calc >> 16));
	cmdparam8((uint8_t)(calc >> 24));

	cmdparam8((uint8_t)(DL_END));		// Send data low byte
	cmdparam8((uint8_t)(DL_END >> 8));
	cmdparam8((uint8_t)(DL_END >> 16));
	cmdparam8((uint8_t)(DL_END >> 24));		// Send data high byte
    SPI.setSS(HIGH);
	inc_cmdOffset(16);	// update the command-ram pointer
}


void cmd_rect(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t corner)
{
	uint32_t calc;

	start_cmd((DL_BEGIN | RECTS));

	calc = LINE_WIDTH(corner * 16);
	cmdparam8((uint8_t)(calc));
	cmdparam8((uint8_t)(calc >> 8));
	cmdparam8((uint8_t)(calc >> 16));
	cmdparam8((uint8_t)(calc >> 24));

	calc = VERTEX2F(x0 * 16, y0 * 16);
	cmdparam8((uint8_t)(calc));
	cmdparam8((uint8_t)(calc >> 8));
	cmdparam8((uint8_t)(calc >> 16));
	cmdparam8((uint8_t)(calc >> 24));

	calc = VERTEX2F(x1 * 16, y1 * 16);
	cmdparam8((uint8_t)(calc));
	cmdparam8((uint8_t)(calc >> 8));
	cmdparam8((uint8_t)(calc >> 16));
	cmdparam8((uint8_t)(calc >> 24));

	cmdparam8((uint8_t)(DL_END));		// Send data low byte
	cmdparam8((uint8_t)(DL_END >> 8));
	cmdparam8((uint8_t)(DL_END >> 16));
	cmdparam8((uint8_t)(DL_END >> 24));		// Send data high byte
    SPI.setSS(HIGH);
	inc_cmdOffset(16);	// update the command-ram pointer
}

// init
/*
void ft800_init(void)
{
	uint8_t gpio;
	uint8_t chipid;

	ft800_pdn_set();
	DELAY_MS(6);	// minimum time for power-down is 5ms
	ft800_pdn_clear();
	DELAY_MS(21);	// minimum time to allow from rising PD_N to first access is 20ms

	ft800_cmdWrite(FT_CLKEXT);	// Set FT800 for external clock
// 	ft800_cmdWrite(FT_CLK48M);	// Set FT800 for 48MHz PLL
	ft800_cmdWrite(FT_ACTIVE);	// Start FT800

	chipid = ft800_memRead8(REG_ID);	// Read ID register
	while(chipid != 0x7C)	// if chipid is not 0x7c, continue to read it until it is, FT81x may need a moment for it's power on selftest
	{
		chipid = ft800_memRead8(REG_ID);
	}

	ft800_memWrite8(REG_PCLK, 0x00);		// Set PCLK to zero - don't clock the LCD until later
	ft800_memWrite8(REG_PWM_DUTY, 10);		// Turn off backlight

	// Initialize Display
	ft800_memWrite16(REG_HSIZE,   FT_HSIZE);	// active display width
	ft800_memWrite16(REG_HCYCLE,  FT_HCYCLE);	// total number of clocks per line, incl front/back porch
	ft800_memWrite16(REG_HOFFSET, FT_HOFFSET);	// start of active line
	ft800_memWrite16(REG_HSYNC0,  FT_HSYNC0);	// start of horizontal sync pulse
	ft800_memWrite16(REG_HSYNC1,  FT_HSYNC1);	// end of horizontal sync pulse
	ft800_memWrite16(REG_VSIZE,   FT_VSIZE);	// active display height
	ft800_memWrite16(REG_VCYCLE,  FT_VCYCLE);	// total number of lines per screen, incl pre/post
	ft800_memWrite16(REG_VOFFSET, FT_VOFFSET);	// start of active screen
	ft800_memWrite16(REG_VSYNC0,  FT_VSYNC0);	// start of vertical sync pulse
	ft800_memWrite16(REG_VSYNC1,  FT_VSYNC1);	// end of vertical sync pulse
	ft800_memWrite8(REG_SWIZZLE,  FT_SWIZZLE);	// FT800 output to LCD - pin order
	ft800_memWrite8(REG_PCLK_POL, FT_PCLKPOL);	// LCD data is clocked in on this PCLK edge
	// Don't set PCLK yet - wait for just after the first display list

	// Configure Touch
	ft800_memWrite8(REG_TOUCH_MODE, FT_TMODE_CONTINUOUS);	// enable touch
	ft800_memWrite16(REG_TOUCH_RZTHRESH, FT_TOUCH_RZTHRESH);	// Eliminate any false touches

	// Configure Audio - not used, so disable it
	ft800_memWrite8(REG_VOL_PB, 0x00);		// turn recorded audio volume down
//	ft800_memWrite8(REG_VOL_SOUND, 0xff);		// turn synthesizer volume on
	ft800_memWrite8(REG_VOL_SOUND, 0x00);		// turn synthesizer volume off
	ft800_memWrite16(REG_SOUND, 0x6000);		// set synthesizer to mute

	ft800_memWrite32(FT_RAM_DL, DL_CLEAR_RGB);
	ft800_memWrite32(FT_RAM_DL + 4, (DL_CLEAR | CLR_COL | CLR_STN | CLR_TAG));
	ft800_memWrite32(FT_RAM_DL + 8, DL_DISPLAY);	// end of display list
	ft800_memWrite32(REG_DLSWAP, FT_DLSWAP_FRAME);

	// Nothing is being displayed yet... the pixel clock is still 0x00

	gpio = ft800_memRead8(REG_GPIO_DIR);
	gpio |= 0x82; // set DISP to Output although it always is output, set GPIO1 to Output - Audio Enable on VM800B
	ft800_memWrite8(REG_GPIO_DIR, gpio);

	gpio = ft800_memRead8(REG_GPIO);	// Read the FT800 GPIO register for a read/modify/write operation
//	gpio |= 0x82;						// set bit 7 of FT800 GPIO register (DISP), set GPIO1 to High to enable Audio - others are inputs
	gpio |= 0x80;						// set bit 7 of FT800 GPIO register (DISP), others are inputs
	ft800_memWrite8(REG_GPIO, gpio);	// Enable the DISP signal to the LCD panel
	ft800_memWrite8(REG_PCLK, FT_PCLK);	// Now start clocking data to the LCD panel

	ft800_memWrite8(REG_PWM_DUTY, 80);	// Turn on backlight

	DELAY_MS(10);	// just to be safe
} 
*/

