Files
TFT_eSPI/examples/320 x 240/TFT_Screen_Capture/screenServer.ino
T
Bodmer 40d35b1892 Examples menu now based on resolution
Reference to particular drivers in examples have been removed as
multiple display drivers are now supported.
Tabs replaced by spaces in header file by file editor.
RPi TFT with write strobe SPI clock rate dropped to 20MHz (display
cannot cope with new high rate siWriteBlock() function)
2017-04-24 22:35:11 +01:00

195 lines
7.7 KiB
Arduino

// Reads a screen image off the TFT and send it to a processing client sketch
// over the serial port. Use a high baud rate, e.g. for an ESP8266:
// Serial.begin(921600);
// At 921600 baud a 320 x 240 image with 16 bit colour transfers can be sent to the
// PC client in ~1.67s and 24 bit colour in ~2.5s which is close to the theoretical
// minimum transfer time.
// This sketch has been created to work with the TFT_eSPI library here:
// https://github.com/Bodmer/TFT_eSPI
// Created by: Bodmer 27/1/17
// Updated by: Bodmer 10/3/17
// Version: 0.07
// MIT licence applies, all text above must be included in derivative works
//====================================================================================
// Definitions
//====================================================================================
#define BAUD_RATE 250000 // Maximum Serial Monitor rate for other messages
#define DUMP_BAUD_RATE 921600 // Rate used for screen dumps
#define PIXEL_TIMEOUT 100 // 100ms Time-out between pixel requests
#define START_TIMEOUT 10000 // 10s Maximum time to wait at start transfer
#define BITS_PER_PIXEL 16 // 24 for RGB colour format, 16 for 565 colour format
// File names must be alpha-numeric characters (0-9, a-z, A-Z) or "/" underscore "_"
// other ascii characters are stripped out by client, including / generates
// sub-directories
#define DEFAULT_FILENAME "tft_screenshots/screenshot" // In case none is specified
#define FILE_TYPE "png" // jpg, bmp, png, tif are valid
// Filename extension
// '#' = add 0-9, '@' = add timestamp, '%' add millis() timestamp, '*' = add nothing
// '@' and '%' will generate new unique filenames, so beware of cluttering up your
// hard drive with lots of images! The PC client sketch is set to limit the number of
// saved images to 1000 and will then prompt for a restart.
#define FILE_EXT '%'
// Number of pixels to send in a burst (minimum of 1), no benefit above 8
// NPIXELS values and render times: 1 = 5.0s, 2 = 1.75s, 4 = 1.68s, 8 = 1.67s
#define NPIXELS 8 // Must be integer division of both TFT width and TFT height
//====================================================================================
// Screen server call with no filename
//====================================================================================
// Start a screen dump server (serial or network) - no filename specified
boolean screenServer(void)
{
// With no filename the screenshot will be saved with a default name e.g. tft_screen_#.xxx
// where # is a number 0-9 and xxx is a file type specified below
return screenServer(DEFAULT_FILENAME);
}
//====================================================================================
// Screen server call with filename
//====================================================================================
// Start a screen dump server (serial or network) - filename specified
boolean screenServer(String filename)
{
Serial.end(); // Stop the serial port (clears buffers too)
Serial.begin(DUMP_BAUD_RATE); // Force baud rate to be high
delay(0); // Equivalent to yield() for ESP8266;
boolean result = serialScreenServer(filename); // Screenshot serial port server
//boolean result = wifiScreenServer(filename); // Screenshot WiFi UDP port server (WIP)
Serial.end(); // Stop the serial port (clears buffers too)
Serial.begin(BAUD_RATE); // Return baud rate to normal
delay(0); // Equivalent to yield() for ESP8266;
//Serial.println();
//if (result) Serial.println(F("Screen dump passed :-)"));
//else Serial.println(F("Screen dump failed :-("));
return result;
}
//====================================================================================
// Serial server function that sends the data to the client
//====================================================================================
boolean serialScreenServer(String filename)
{
// Precautionary receive buffer garbage flush for 50ms
uint32_t clearTime = millis() + 50;
while ( millis() < clearTime && Serial.read() >= 0) delay(0); // Equivalent to yield() for ESP8266;
boolean wait = true;
uint32_t lastCmdTime = millis(); // Initialise start of command time-out
// Wait for the starting flag with a start time-out
while (wait)
{
delay(0); // Equivalent to yield() for ESP8266;
// Check serial buffer
if (Serial.available() > 0) {
// Read the command byte
uint8_t cmd = Serial.read();
// If it is 'S' (start command) then clear the serial buffer for 100ms and stop waiting
if ( cmd == 'S' ) {
// Precautionary receive buffer garbage flush for 50ms
clearTime = millis() + 50;
while ( millis() < clearTime && Serial.read() >= 0) delay(0); // Equivalent to yield() for ESP8266;
wait = false; // No need to wait anymore
lastCmdTime = millis(); // Set last received command time
// Send screen size etc using a simple header with delimiters for client checks
sendParameters(filename);
}
}
else
{
// Check for time-out
if ( millis() > lastCmdTime + START_TIMEOUT) return false;
}
}
uint8_t color[3 * NPIXELS]; // RGB and 565 format color buffer for N pixels
// Send all the pixels on the whole screen
for ( uint32_t y = 0; y < tft.height(); y++)
{
// Increment x by NPIXELS as we send NPIXELS for every byte received
for ( uint32_t x = 0; x < tft.width(); x += NPIXELS)
{
delay(0); // Equivalent to yield() for ESP8266;
// Wait here for serial data to arrive or a time-out elapses
while ( Serial.available() == 0 )
{
if ( millis() > lastCmdTime + PIXEL_TIMEOUT) return false;
delay(0); // Equivalent to yield() for ESP8266;
}
// Serial data must be available to get here, read 1 byte and
// respond with N pixels, i.e. N x 3 RGB bytes or N x 2 565 format bytes
if ( Serial.read() == 'X' ) {
// X command byte means abort, so clear the buffer and return
clearTime = millis() + 50;
while ( millis() < clearTime && Serial.read() >= 0) delay(0); // Equivalent to yield() for ESP8266;
return false;
}
// Save arrival time of the read command (for later time-out check)
lastCmdTime = millis();
#if defined BITS_PER_PIXEL && BITS_PER_PIXEL >= 24
// Fetch N RGB pixels from x,y and put in buffer
tft.readRectRGB(x, y, NPIXELS, 1, color);
// Send buffer to client
Serial.write(color, 3 * NPIXELS); // Write all pixels in the buffer
#else
// Fetch N 565 format pixels from x,y and put in buffer
tft.readRect(x, y, NPIXELS, 1, (uint16_t *)color);
// Send buffer to client
Serial.write(color, 2 * NPIXELS); // Write all pixels in the buffer
#endif
}
}
Serial.flush(); // Make sure all pixel bytes have been despatched
return true;
}
//====================================================================================
// Send screen size etc using a simple header with delimiters for client checks
//====================================================================================
void sendParameters(String filename)
{
Serial.write('W'); // Width
Serial.write(tft.width() >> 8);
Serial.write(tft.width() & 0xFF);
Serial.write('H'); // Height
Serial.write(tft.height() >> 8);
Serial.write(tft.height() & 0xFF);
Serial.write('Y'); // Bits per pixel (16 or 24)
Serial.write(BITS_PER_PIXEL);
Serial.write('?'); // Filename next
Serial.print(filename);
Serial.write('.'); // End of filename marker
Serial.write(FILE_EXT); // Filename extension identifier
Serial.write(*FILE_TYPE); // First character defines file type j,b,p,t
}