From 3314530bbbeccb2a344ef75391d197228a75070e Mon Sep 17 00:00:00 2001 From: Bodmer Date: Tue, 28 Feb 2017 22:13:16 +0000 Subject: [PATCH] Add processing screenshot viewer --- ...LIScreenshotViewer licence information.txt | 23 -- Tools/ILIScreenshotViewer.exe | Bin 16896 -> 0 bytes Tools/Screenshot_client/Screenshot_client.pde | 285 ++++++++++++++++ .../TFT_Screen_Capture/TFT_Screen_Capture.ino | 165 ++++++++++ .../TFT_Screen_Capture/processing_sketch.ino | 304 ++++++++++++++++++ .../TFT_Screen_Capture/screenServer.ino | 152 +++++++++ 6 files changed, 906 insertions(+), 23 deletions(-) delete mode 100644 Tools/ILIScreenshotViewer licence information.txt delete mode 100644 Tools/ILIScreenshotViewer.exe create mode 100644 Tools/Screenshot_client/Screenshot_client.pde create mode 100644 examples/ILI9341/TFT_Screen_Capture/TFT_Screen_Capture.ino create mode 100644 examples/ILI9341/TFT_Screen_Capture/processing_sketch.ino create mode 100644 examples/ILI9341/TFT_Screen_Capture/screenServer.ino diff --git a/Tools/ILIScreenshotViewer licence information.txt b/Tools/ILIScreenshotViewer licence information.txt deleted file mode 100644 index 2c9f877..0000000 --- a/Tools/ILIScreenshotViewer licence information.txt +++ /dev/null @@ -1,23 +0,0 @@ - -This ILIScreenshotViewer.exe file is part of the Arduino ILI9341_due library. - -A set of compatible functions is included in the "ESP8266_uncannyEyes" example. - -The original library licence conditions that apply to the software in this folder are: - -Copyright (c) 2014 Marek Buriak - -Sources can be found at https://github.com/marekburiak/ILI9341_Due. - -ILI9341_due is free software you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 2.1 of the License, or -(at your option) any later version. - -ILI9341_due is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with ILI9341_due. If not, see . diff --git a/Tools/ILIScreenshotViewer.exe b/Tools/ILIScreenshotViewer.exe deleted file mode 100644 index d9f4ed92b984202825858c42de4efe19a035df36..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16896 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 diff --git a/Tools/Screenshot_client/Screenshot_client.pde b/Tools/Screenshot_client/Screenshot_client.pde new file mode 100644 index 0000000..22f6afd --- /dev/null +++ b/Tools/Screenshot_client/Screenshot_client.pde @@ -0,0 +1,285 @@ +// This is a Processing sketch, see https://processing.org/ to download the IDE + +// The sketch is a client that requests TFT screenshots from an Arduino board. +// The arduino must call a screenshot server function to respond with pixels. + +// It has been created to work with the TFT_eSPI library here: +// https://github.com/Bodmer/TFT_eSPI + +// The library provides a member function that reads the RGB values of screen pixels +// and an example TFT_Screen_Capture + +// Captured images are stored in the sketch folder, use "Sketch" menu option +// "Show Sketch Folder" or press Ctrl+K + +// Created by: Bodmer 27/1/17 + +// MIT licence applies, all text above must be included in derivative works + +import processing.serial.*; + +Serial serial; // Create an instance called serial + +// ########################################################################################### +// # These are the values to change for a particular setup # +// # +int serial_port = 1; // Use enumerated value from list provided when sketch is run # +int serial_baud_rate = 921600; // Maximum tested is 921600 # +// # +int tft_width = 240; // TFT width in portrait orientation # +int tft_height = 320; // TFT height # +//int tft_width = 320; // TFT width in landscape orientation # +//int tft_height = 240; // TFT height # +// # +// Change the image file type saved here, comment out all but one # +//String image_type = ".jpg"; // # +String image_type = ".png"; // # +//String image_type = ".bmp"; // # +//String image_type = ".tif"; // # +// # +boolean save_border = true; // Save the image with a border # +int border = 5; // Border pixel width # +boolean fade = false; // Fade out image after saving # +// # +int max_images = 10; // Maximum of numbered saved images before over-writing files # +// # +// # End of the values to change for a particular setup # +// ########################################################################################### + +int serialCount = 0; // Count of colour bytes arriving + +int bgcolor = 255; // Background color + +PImage img, tft_img; + +color light_blue = color(50, 128, 255); + +int[] rgb = new int[6]; // Buffer for the RGB colour bytes + +int indexRed = 0; // Colour byte index in the array +int indexGreen = 1; +int indexBlue = 2; + +long end = 10; // Whether we've heard from the microcontroller + +int n = 0; // Whether we've heard from the microcontroller + +boolean got_image = false; + +int x_offset = (500 - tft_width) /2; // Image offsets in the window +int y_offset = 20; // +int xpos, ypos; // Pixel position + +int beginTime = 0; +int pixelWaitTime = 100; // Wait a maximum of 100ms gap for image pixels to arrive +int lastPixelTime = 0; // Time that "image send" command was sent + +int state = 0; // State machine current state + +int progress_bar = 0; +int pixel_count = 0; +float percentage = 0; + +int drawLoopCount = 0; + +void setup() { + + size(500, 540); // Stage size, could handle 480 pixel scrren + noStroke(); // No border on the next thing drawn + + img = createImage(500, 540, ARGB); + for (int i = 0; i < img.pixels.length; i++) { + float a = map(i, 0, img.pixels.length, 255, 0); + img.pixels[i] = color(0, 153, 204, a); + } + + tft_img = createImage(tft_width, tft_height, ARGB); + for (int i = 0; i < tft_img.pixels.length; i++) { + tft_img.pixels[i] = color(0, 0, 0, 255); + } + + frameRate(5000); // High frame rate so draw() loops fast + + xpos = 0; + ypos = 0; + + // Print a list of the available serial ports + println("-----------------------"); + println("Available Serial Ports:"); + println("-----------------------"); + printArray(Serial.list()); + println("-----------------------"); + + print("Port currently used: ["); + print(serial_port); + println("]"); + + String portName = Serial.list()[serial_port]; + + delay(1000); + + serial = new Serial(this, portName, serial_baud_rate); + + state = 99; +} + +void draw() { + drawLoopCount++; + switch(state) { + + case 0: // Init varaibles, send start request + tint(255, 255); + textAlign(CENTER); + textSize(20); + + println(""); + //println("Clearing pipe..."); + beginTime = millis() + 200; + while ( millis() < beginTime ) + { + serial.read(); + } + println("Ready to receive image"); + serial.write("S"); + xpos = 0; + ypos = 0; + serialCount = 0; + progress_bar = 0; + pixel_count = 0; + percentage = 0; + drawLoopCount = 0; + lastPixelTime = millis() + 1000; + state = 1; + break; + + case 1: // Console message, give server some time + println("Requesting image"); + delay(10); + state = 2; + break; + + case 2: // Get size and set start time for render time report + // To do: Read image size info, currently hard coded + beginTime = millis(); + state = 3; + break; + + case 3: // Request pixels and reder them + if ( serial.available() > 0 ) { + + // Add the latest byte from the serial port to array: + while (serial.available()>0) + { + rgb[serialCount] = serial.read(); + serialCount++; + + // If we have 3 colour bytes: + if (serialCount >= 3 ) { + serialCount = 0; + pixel_count++; + stroke(rgb[indexRed], rgb[indexGreen], rgb[indexBlue]); + point(xpos + x_offset, ypos + y_offset); + lastPixelTime = millis(); + xpos++; + if (xpos >= tft_width) { + xpos = 0; + print("."); + progress_bar++; + if (progress_bar >31) + { + progress_bar = 0; + percentage = 0.5 + 100 * pixel_count/(0.001 + tft_width * tft_height); + if (percentage > 100) percentage = 100; + println(" [ " + (int)percentage + "% ]"); + } + ypos++; + if (ypos>=tft_height) { + ypos = 0; + println("Image fetch time = " + (millis()-beginTime)/1000.0 + " s"); + state = 5; + } + } + } + } + } else + { + + if (millis() > (lastPixelTime + pixelWaitTime)) + { + println(""); + System.err.println("No response, trying again..."); + state = 4; + } else + { + // Request 64 more pixels (ESP8266 buffer size) + serial.write("RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"); + serial.write("RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"); + } + } + break; + + case 4: // Time-out, flush serial buffer + println(); + //println("Clearing serial pipe after a time-out"); + int clearTime = millis() + 50; + while ( millis() < clearTime ) + { + serial.read(); + } + state = 0; + break; + + case 5: // Save the image tot he sketch folder + println(); + String filename = "tft_screen_" + n + image_type; + println("Saving image as \"" + filename); // Does not execute + if (save_border) + { + PImage partialSave = get(x_offset - border, y_offset - border, tft_width + 2*border, tft_height + 2*border); + partialSave.save(filename); + } else { + PImage partialSave = get(x_offset, y_offset, tft_width, tft_height); + partialSave.save(filename); + } + + n = n + 1; + if (n>9) n = 0; + drawLoopCount = 0; // Reset value ready for counting in step 6 + state = 6; + break; + + case 6: // Fade the old image if enabled + delay(10); + if (fade) + { + tint(255, drawLoopCount); + image(tft_img, x_offset, y_offset); + } + if (drawLoopCount > 50) state = 0; // Wait for fade to end + break; + + case 99: // Draw image viewer window + textAlign(CENTER); + textSize(20); + background(bgcolor); + image(img, 0, 0); + + fill(0); + text("Bodmer's TFT image viewer", width/2, height-10); + + stroke(0, 0, 0); + + rect(x_offset - border, y_offset - border, tft_width - 1 + 2*border, tft_height - 1 + 2*border); + + fill(100); + rect(x_offset, y_offset, tft_width-1, tft_height-1); + + state = 0; + break; + + default: + println(""); + System.err.println("Error state reached - check sketch!"); + break; + } +} \ No newline at end of file diff --git a/examples/ILI9341/TFT_Screen_Capture/TFT_Screen_Capture.ino b/examples/ILI9341/TFT_Screen_Capture/TFT_Screen_Capture.ino new file mode 100644 index 0000000..ceed295 --- /dev/null +++ b/examples/ILI9341/TFT_Screen_Capture/TFT_Screen_Capture.ino @@ -0,0 +1,165 @@ +/* + This example draws rainbow colours on the screen, adds text in various + fast rendering fonts and then sends the TFT screen to a PC over the serial + port to a processing sketch. + + This sketch uses the GLCD, 2, 4, 6 fonts. + + Make sure all the display driver and pin comnenctions are correct by + editting the User_Setup.h file in the TFT_eSPI library folder. + + ######################################################################### + ###### DON'T FORGET TO UPDATE THE User_Setup.h FILE IN THE LIBRARY ###### + ######################################################################### +*/ + +#include // Hardware-specific library +#include + +TFT_eSPI tft = TFT_eSPI(); // Invoke custom library with default width and height + +//TFT_eSPI tft = TFT_eSPI(240, 320); // Could invoke custom library declaring width and height + +unsigned long targetTime = 0; +byte red = 31; +byte green = 0; +byte blue = 0; +byte state = 0; +unsigned int colour = red << 11; // Colour order is RGB 5+6+5 bits each + +void setup(void) { + Serial.begin(921600); + + tft.init(); + tft.setRotation(0); + tft.fillScreen(TFT_BLACK); + + targetTime = millis() + 1000; +} + +void loop() { + + if (targetTime < millis()) { + targetTime = millis() + 4000; + + rainbow_fill(); // Fill the screen with rainbow colours + + // The standard AdaFruit font still works as before + tft.setTextColor(TFT_BLACK); // Background is not defined so it is transparent + + tft.setCursor (60, 5); + tft.setTextFont(0); // Select font 0 which is the Adafruit font + tft.print("Original Adafruit font!"); + + //tft.drawString("Original Adafruit font!",60,5,1); + + // The new larger fonts do not need to use the .setCursor call, coords are embedded + tft.setTextColor(TFT_BLACK); // Do not plot the background colour + // Overlay the black text on top of the rainbow plot (the advantage of not drawing the backgorund colour!) + tft.drawCentreString("Font size 2", 120, 14, 2); // Draw text centre at position 120, 14 using font 2 + tft.drawCentreString("Font size 4", 120, 30, 4); // Draw text centre at position 120, 30 using font 4 + tft.drawCentreString("12.34", 120, 54, 6); // Draw text centre at position 120, 54 using font 6 + + tft.drawCentreString("12.34 is in font size 6", 120, 92, 2); // Draw text centre at position 120, 92 using font 2 + // Note the x position is the top of the font! + + // draw a floating point number + float pi = 3.14159; // Value to print + int precision = 3; // Number of digits after decimal point + int xpos = 90; // x position + int ypos = 110; // y position + int font = 2; // font number 2 + xpos += tft.drawFloat(pi, precision, xpos, ypos, font); // Draw rounded number and return new xpos delta for next print position + tft.drawString(" is pi", xpos, ypos, font); // Continue printing from new x position + + tft.setTextSize(1); // We are using a size multiplier of 1 + + tft.setTextColor(TFT_BLACK); // Set text colour to black, no background (so transparent) + + tft.setCursor(36, 150, 4); // Set cursor to x = 36, y = 150 and use font 4 + tft.println("Transparent..."); // As we use println, the cursor moves to the next line + + tft.setCursor(30, 175); // Set cursor to x = 30, y = 175 + tft.setTextColor(TFT_WHITE, TFT_BLACK); // Set text colour to white and background to black + tft.println(" White on black "); + + tft.setTextFont(4); // Select font 4 without moving cursor + tft.setCursor(50, 210); // Set cursor to x = 50, y = 210 without changing the font + tft.setTextColor(TFT_WHITE); + // By using #TFT print we can use all the formatting features like printing HEX + tft.print(57005, HEX); // Cursor does no move to next line + tft.println(48879, HEX); // print and move cursor to next line + + tft.setTextColor(TFT_GREEN, TFT_BLACK); // This time we will use green text on a black background + tft.setTextFont(2); // Select font 2 + + // An easier way to position text and blank old text is to set the datum and use width padding + tft.setTextDatum(BC_DATUM); // Bottom centre for text datum + tft.setTextPadding(241); // Pad text to full screen wdth (240 pixels + 1 spare for +/-1 position rounding) + tft.drawString("Ode to a Small Lump of Green Putty", 120, 300 - 32); + tft.drawString("I Found in My Armpit One Midsummer", 120, 300 - 16); + tft.drawString("Morning", 120, 300); + tft.setTextDatum(TL_DATUM); // Reset to top left for text datum + screenServer(); + } +} + +// Fill screen with a rainbow pattern +void rainbow_fill() +{ + // The colours and state are not initialised so the start colour changes each time the funtion is called + + for (int i = 319; i >= 0; i--) { + // This is a "state machine" that ramps up/down the colour brightnesses in sequence + switch (state) { + case 0: + green ++; + if (green == 64) { + green = 63; + state = 1; + } + break; + case 1: + red--; + if (red == 255) { + red = 0; + state = 2; + } + break; + case 2: + blue ++; + if (blue == 32) { + blue = 31; + state = 3; + } + break; + case 3: + green --; + if (green == 255) { + green = 0; + state = 4; + } + break; + case 4: + red ++; + if (red == 32) { + red = 31; + state = 5; + } + break; + case 5: + blue --; + if (blue == 255) { + blue = 0; + state = 0; + } + break; + } + colour = red << 11 | green << 5 | blue; + // Draw a line 1 pixel wide in the selected colour + tft.drawFastHLine(0, i, tft.width(), colour); // in this example tft.width() returns the pixel width of the display + } +} + + + diff --git a/examples/ILI9341/TFT_Screen_Capture/processing_sketch.ino b/examples/ILI9341/TFT_Screen_Capture/processing_sketch.ino new file mode 100644 index 0000000..4fafcbd --- /dev/null +++ b/examples/ILI9341/TFT_Screen_Capture/processing_sketch.ino @@ -0,0 +1,304 @@ +// Below is a copy of the processing sketch that can be used to capture the images +// The sketch beow is NOT and Arduino IDE sketch! + +// Copy the sketch content below and remove the /* and */ at the beginning and end. +// The sketch runs in Processing version 3.3, it can be downloaded here: +// https://processing.org/download/ + +// When the sketch is loaded in Processing, save it as "Screenshot_Client", and click +// the run triangle. Then check the serial port list in the console report, edit the +// Processing sketch to use the right port by changing the port number allocated in +// "int serial_port = X;" at line 26 (see line 43 below) + +// The Arduino IDE and Processing will share a serial port, make sure only one +// program tries to use the port at any time. Processing may "freeze" otherwise. + +/* <<<<<<<<<<<<<<<<<<<<<<<<< REMOVE THIS LINE <<<<<<<<<<<<<<<<<<<<<<<<< + +// This is a Processing sketch, see https://processing.org/ to download the IDE + +// The sketch is a client that requests TFT screenshots from an Arduino board. +// The arduino must call a screenshot server function to respond with pixels. + +// It has been created to work with the TFT_eSPI library here: +// https://github.com/Bodmer/TFT_eSPI + +// The library provides a member function that reads the RGB values of screen pixels +// and an example TFT_Screen_Capture + +// Captured images are stored in the Processing sketch folder, use "Sketch" menu option +// "Show Sketch Folder" or press Ctrl+K in the Processing IDE. + +// Created by: Bodmer 27/1/17 + +// MIT licence applies, all text above must be included in derivative works + +import processing.serial.*; + +Serial serial; // Create an instance called serial + +// ########################################################################################### +// # These are the values to change for a particular setup # +// # +int serial_port = 0; // Use enumerated value from list provided when sketch is run # +int serial_baud_rate = 921600; // Maximum tested is 921600 # +// # +int tft_width = 240; // TFT width in portrait orientation # +int tft_height = 320; // TFT height # +//int tft_width = 320; // TFT width in landscape orientation # +//int tft_height = 240; // TFT height # +// # +// Change the image file type saved here, comment out all but one # +//String image_type = ".jpg"; // # +String image_type = ".png"; // # +//String image_type = ".bmp"; // # +//String image_type = ".tif"; // # +// # +boolean save_border = true; // Save the image with a border # +int border = 5; // Border pixel width # +boolean fade = false; // Fade out image after saving # +// # +int max_images = 10; // Maximum of numbered saved images before over-writing files # +// # +// # End of the values to change for a particular setup # +// ########################################################################################### + +int serialCount = 0; // Count of colour bytes arriving + +int bgcolor = 255; // Background color + +PImage img, tft_img; + +color light_blue = color(50, 128, 255); + +int[] rgb = new int[6]; // Buffer for the RGB colour bytes + +int indexRed = 0; // Colour byte index in the array +int indexGreen = 1; +int indexBlue = 2; + +long end = 10; // Whether we've heard from the microcontroller + +int n = 0; // Whether we've heard from the microcontroller + +boolean got_image = false; + +int x_offset = (500 - tft_width) /2; // Image offsets in the window +int y_offset = 20; // +int xpos, ypos; // Pixel position + +int beginTime = 0; +int pixelWaitTime = 100; // Wait a maximum of 100ms gap for image pixels to arrive +int lastPixelTime = 0; // Time that "image send" command was sent + +int state = 0; // State machine current state + +int progress_bar = 0; +int pixel_count = 0; +float percentage = 0; + +int drawLoopCount = 0; + +void setup() { + + size(500, 540); // Stage size, could handle 480 pixel scrren + noStroke(); // No border on the next thing drawn + + img = createImage(500, 540, ARGB); + for (int i = 0; i < img.pixels.length; i++) { + float a = map(i, 0, img.pixels.length, 255, 0); + img.pixels[i] = color(0, 153, 204, a); + } + + tft_img = createImage(tft_width, tft_height, ARGB); + for (int i = 0; i < tft_img.pixels.length; i++) { + tft_img.pixels[i] = color(0, 0, 0, 255); + } + + frameRate(5000); // High frame rate so draw() loops fast + + xpos = 0; + ypos = 0; + + // Print a list of the available serial ports + println("-----------------------"); + println("Available Serial Ports:"); + println("-----------------------"); + printArray(Serial.list()); + println("-----------------------"); + + print("Port currently used: ["); + print(serial_port); + println("]"); + + String portName = Serial.list()[serial_port]; + + delay(1000); + + serial = new Serial(this, portName, serial_baud_rate); + + state = 99; +} + +void draw() { + drawLoopCount++; + switch(state) { + + case 0: // Init varaibles, send start request + tint(255, 255); + textAlign(CENTER); + textSize(20); + + println(""); + //println("Clearing pipe..."); + beginTime = millis() + 200; + while ( millis() < beginTime ) + { + serial.read(); + } + println("Ready to receive image"); + serial.write("S"); + xpos = 0; + ypos = 0; + serialCount = 0; + progress_bar = 0; + pixel_count = 0; + percentage = 0; + drawLoopCount = 0; + lastPixelTime = millis() + 1000; + state = 1; + break; + + case 1: // Console message, give server some time + println("Requesting image"); + delay(10); + state = 2; + break; + + case 2: // Get size and set start time for render time report + // To do: Read image size info, currently hard coded + beginTime = millis(); + state = 3; + break; + + case 3: // Request pixels and reder them + if ( serial.available() > 0 ) { + + // Add the latest byte from the serial port to array: + while (serial.available()>0) + { + rgb[serialCount] = serial.read(); + serialCount++; + + // If we have 3 colour bytes: + if (serialCount >= 3 ) { + serialCount = 0; + pixel_count++; + stroke(rgb[indexRed], rgb[indexGreen], rgb[indexBlue]); + point(xpos + x_offset, ypos + y_offset); + lastPixelTime = millis(); + xpos++; + if (xpos >= tft_width) { + xpos = 0; + print("."); + progress_bar++; + if (progress_bar >31) + { + progress_bar = 0; + percentage = 0.5 + 100 * pixel_count/(0.001 + tft_width * tft_height); + if (percentage > 100) percentage = 100; + println(" [ " + (int)percentage + "% ]"); + } + ypos++; + if (ypos>=tft_height) { + ypos = 0; + println("Image fetch time = " + (millis()-beginTime)/1000.0 + " s"); + state = 5; + } + } + } + } + } else + { + + if (millis() > (lastPixelTime + pixelWaitTime)) + { + println(""); + System.err.println("No response, trying again..."); + state = 4; + } else + { + // Request 64 more pixels (ESP8266 buffer size) + serial.write("RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"); + serial.write("RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"); + } + } + break; + + case 4: // Time-out, flush serial buffer + println(); + //println("Clearing serial pipe after a time-out"); + int clearTime = millis() + 50; + while ( millis() < clearTime ) + { + serial.read(); + } + state = 0; + break; + + case 5: // Save the image tot he sketch folder + println(); + String filename = "tft_screen_" + n + image_type; + println("Saving image as \"" + filename); // Does not execute + if (save_border) + { + PImage partialSave = get(x_offset - border, y_offset - border, tft_width + 2*border, tft_height + 2*border); + partialSave.save(filename); + } else { + PImage partialSave = get(x_offset, y_offset, tft_width, tft_height); + partialSave.save(filename); + } + + n = n + 1; + if (n>9) n = 0; + drawLoopCount = 0; // Reset value ready for counting in step 6 + state = 6; + break; + + case 6: // Fade the old image if enabled + delay(10); + if (fade) + { + tint(255, drawLoopCount); + image(tft_img, x_offset, y_offset); + } + if (drawLoopCount > 50) state = 0; // Wait for fade to end + break; + + case 99: // Draw image viewer window + textAlign(CENTER); + textSize(20); + background(bgcolor); + image(img, 0, 0); + + fill(0); + text("Bodmer's TFT image viewer", width/2, height-10); + + stroke(0, 0, 0); + + rect(x_offset - border, y_offset - border, tft_width - 1 + 2*border, tft_height - 1 + 2*border); + + fill(100); + rect(x_offset, y_offset, tft_width-1, tft_height-1); + + state = 0; + break; + + default: + println(""); + System.err.println("Error state reached - check sketch!"); + break; + } +} + +*/ // <<<<<<<<<<<<<<<<<<<<<<<<< REMOVE THIS LINE <<<<<<<<<<<<<<<<<<<<<<<<< diff --git a/examples/ILI9341/TFT_Screen_Capture/screenServer.ino b/examples/ILI9341/TFT_Screen_Capture/screenServer.ino new file mode 100644 index 0000000..53a8dc0 --- /dev/null +++ b/examples/ILI9341/TFT_Screen_Capture/screenServer.ino @@ -0,0 +1,152 @@ +// TFT screenshot server + +// This is a sketch support tab containing function calls to read a screen image +// off a TFT and send it to a processing client sketch over the serial port. + +// See the processing_sketch tab, it contains a capy of the processing sketch. + +// Use a high baud rate, for an ESP8266: +/* + Serial.begin(921600); +*/ +// 240 x 320 images take about 3.5s to transfer at 921600 baud(minimum is ~2.5s) + +// 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 + +// The MIT permissive free software license applies, include all text above in +// derivatives. + +#define BAUD_RATE 250000 // Maximum Arduino IDE Serial Monitor rate +#define DUMP_BAUD_RATE 921600 // Rate used for screen dumps by ESP8266 + +#define PIXEL_TIMEOUT 100 // 100ms Time-out between pixel requests +#define START_TIMEOUT 10000 // 10s Maximum time to wait at start transfer + +// Start a screen dump server (serial or network) +boolean screenServer(void) +{ + Serial.end(); // Stop the serial port (clears buffers too) + Serial.begin(DUMP_BAUD_RATE); // Force baud rate to be high + yield(); + + boolean result = serialScreenServer(); // Screenshot serial port server + //boolean result = wifiDump(); // Screenshot WiFi UDP port server (WIP) + + Serial.end(); // Stop the serial port (clears buffers too) + Serial.begin(BAUD_RATE); // Return baud rate to normal + yield(); + + //Serial.println(); + //if (result) Serial.println(F("Screen dump passed :-)")); + //else Serial.println(F("Screen dump failed :-(")); + + return result; +} + +// Screenshot serial port server (Processing sketch acts as client) +boolean serialScreenServer(void) +{ + // Serial commands from client: + // 'S' to start the transfer process (To do: reply with width + height) + // 'R' or any character except 'X' to request pixel + // 'X' to abort and return immediately to caller + // Returned boolean values: + // true = image despatched OK + // false = time-out or abort command received + + // Precautionary receive buffer garbage flush for 50ms + uint32_t clearTime = millis() + 50; + while ( millis() < clearTime ) { + Serial.read(); + yield(); + } + + 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) + { + yield(); + // 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(); + yield(); + } + wait = false; // No need to wait anymore + lastCmdTime = millis(); // Set last received command time + + // Send screen size, not supported by processing sketch yet + //Serial.write('W'); + //Serial.write(tft.width() >> 8); + //Serial.write(tft.width() & 0xFF); + //Serial.write('H'); + //Serial.write(tft.height() >> 8); + //Serial.write(tft.height() & 0xFF); + //Serial.write('Y'); + } + } + else + { + // Check for time-out + if ( millis() > lastCmdTime + START_TIMEOUT) return false; + } + } + + uint8_t color[3]; // RGB color buffer for 1 pixel + + // Send all the pixels on the whole screen (typically 5 seconds at 921600 baud) + for ( uint32_t y = 0; y < tft.height(); y++) + { + // Increment x by 2 as we send 2 pixels for every byte received + for ( uint32_t x = 0; x < tft.width(); x += 1) + { + yield(); + + // Wait here for serial data to arrive or a time-out elapses + while ( Serial.available() == 0 ) + { + yield; + if ( millis() > lastCmdTime + PIXEL_TIMEOUT) return false; + } + + // Serial data must be available to get here, read 1 byte and + // respond with N pixels, i.e. N x 3 RGB bytes + if ( Serial.read() == 'X' ) { + // X command byte means abort, so clear the buffer and return + clearTime = millis() + 50; + while ( millis() < clearTime ) Serial.read(); + return false; + } + // Save arrival time of the read command (for later time-out check) + lastCmdTime = millis(); + + // Fetch data for N pixels starting at x,y + tft.readRectRGB(x, y, 1, 1, color); + // Send values to client + Serial.write(color[0]); // Pixel 1 red + Serial.write(color[1]); // Pixel 1 green + Serial.write(color[2]); // Pixel 1 blue + //Serial.write(color[3]); // Pixel 2 red + //Serial.write(color[4]); // Pixel 2 green + //Serial.write(color[5]); // Pixel 2 blue + } + } + + // Receive buffer excess command flush for 50ms + clearTime = millis() + 50; + while ( millis() < clearTime ) Serial.read(); + + return true; +} +