mirror of
https://github.com/Bodmer/TFT_eSPI.git
synced 2024-09-21 10:27:11 +00:00
Update to screenshot sketches + others
Minor tweaks and re-arrangement of User and Custom font references between header files
This commit is contained in:
parent
60e7d90750
commit
406aac051e
32
TFT_eSPI.h
32
TFT_eSPI.h
@ -19,20 +19,10 @@
|
||||
#ifndef _TFT_eSPIH_
|
||||
#define _TFT_eSPIH_
|
||||
|
||||
// Include header file that defines the fonts loaded and the pins to be used
|
||||
// Include header file that defines the fonts loaded, the TFT drivers
|
||||
// available and the pins to be used
|
||||
#include <User_Setup_Select.h>
|
||||
|
||||
// Load the right driver definitions <<<<<<<<<<<<<<<<<<<<< ADD NEW DRIVERS TO THE LIST HERE <<<<<<<<<<<<<<<<<<<<<<<
|
||||
#if defined (ILI9341_DRIVER)
|
||||
#include <TFT_Drivers/ILI9341_Defines.h>
|
||||
#elif defined (ST7735_DRIVER)
|
||||
#include <TFT_Drivers/ST7735_Defines.h>
|
||||
#elif defined (ILI9163_DRIVER)
|
||||
#include <TFT_Drivers/ILI9163_Defines.h>
|
||||
#elif defined (S6D02A1_DRIVER)
|
||||
#include <TFT_Drivers/S6D02A1_Defines.h>
|
||||
#endif
|
||||
|
||||
// If the frequency is not defined, set a default
|
||||
#ifndef SPI_FREQUENCY
|
||||
#define SPI_FREQUENCY 20000000
|
||||
@ -107,14 +97,10 @@
|
||||
|
||||
#include <Fonts/GFXFF/gfxfont.h>
|
||||
|
||||
// New custom fonts
|
||||
#include <Fonts/Custom/Orbitron_Light_24.h> // CF_OL24
|
||||
#include <Fonts/Custom/Orbitron_Light_32.h> // CF_OL32
|
||||
#include <Fonts/Custom/Roboto_Thin_24.h> // CF_RT24
|
||||
#include <Fonts/Custom/Satisfy_24.h> // CF_S24
|
||||
#include <Fonts/Custom/Yellowtail_32.h> // CF_Y32
|
||||
// Call up any user custom fonts
|
||||
#include <User_Setups/User_Custom_Fonts.h>
|
||||
|
||||
// Free fonts
|
||||
// Original Adafruit_GFX "Free Fonts"
|
||||
#include <Fonts/GFXFF/TomThumb.h> // TT1
|
||||
|
||||
#include <Fonts/GFXFF/FreeMono9pt7b.h> // FF1 or FM9
|
||||
@ -179,9 +165,6 @@
|
||||
#include <Fonts/GFXFF/FreeSerifBoldItalic18pt7b.h> // FF47 or FSBI18
|
||||
#include <Fonts/GFXFF/FreeSerifBoldItalic24pt7b.h> // FF48 or FSBI24
|
||||
|
||||
// Swap any type
|
||||
template <typename T> static inline void
|
||||
swap(T& a, T& b) { T t = a; a = b; b = t; }
|
||||
|
||||
//These enumerate the text plotting alignment (reference datum point)
|
||||
#define TL_DATUM 0 // Top left (default)
|
||||
@ -222,6 +205,11 @@ swap(T& a, T& b) { T t = a; a = b; b = t; }
|
||||
#define TFT_GREENYELLOW 0xAFE5 /* 173, 255, 47 */
|
||||
#define TFT_PINK 0xF81F
|
||||
|
||||
|
||||
// Swap any type
|
||||
template <typename T> static inline void
|
||||
swap(T& a, T& b) { T t = a; a = b; b = t; }
|
||||
|
||||
// This is a structure to conveniently hold infomation on the default fonts
|
||||
// Stores pointer to font character image address table, width table and height
|
||||
|
||||
|
BIN
Tools/Screenshot_client/ILI9341_example.png
Normal file
BIN
Tools/Screenshot_client/ILI9341_example.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.0 KiB |
@ -1,76 +1,85 @@
|
||||
// Latest at 03/03/17
|
||||
|
||||
// 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.
|
||||
// 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
|
||||
// The sketch must only be run when the designated serial port is available and enumerated
|
||||
// otherwise the screenshot window may freeze and that process will need to be terminated
|
||||
// This is a limitation of the Processing environment and not the sketch.
|
||||
// If anyone knows how to determine if a serial port is available at start up the PM me
|
||||
// on (Bodmer) the Arduino forum.
|
||||
|
||||
// Captured images are stored in the sketch folder, use "Sketch" menu option
|
||||
// "Show Sketch Folder" or press Ctrl+K
|
||||
// The block below contains variables that the user may need to change for a particular setup
|
||||
// As a minimum set the serial port and baud rate must be defined. The capture window is
|
||||
// automatically resized for landscape, portrait and different TFT resolutions.
|
||||
|
||||
// Created by: Bodmer 27/1/17
|
||||
// Captured images are stored in the sketch folder, use the Processing IDE "Sketch" menu
|
||||
// option "Show Sketch Folder" or press Ctrl+K
|
||||
|
||||
// Created by: Bodmer 5/3/17
|
||||
// Updated by: Bodmer 10/3/17
|
||||
// Version: 0.06
|
||||
|
||||
// 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 serial_port = 0; // Use enumerated value from list provided when sketch is run #
|
||||
// #
|
||||
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 #
|
||||
// On an Arduino Due Programming Port use a baud rate of:115200) #
|
||||
// On an Arduino Due Native USB Port use a baud rate of any value #
|
||||
int serial_baud_rate = 921600; // #
|
||||
// #
|
||||
// Change the image file type saved here, comment out all but one #
|
||||
//String image_type = ".jpg"; // #
|
||||
String image_type = ".png"; // #
|
||||
String image_type = ".png"; // Lossless compression #
|
||||
//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 = true ; // Fade out image after saving #
|
||||
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
|
||||
// These are default values, this sketch obtains the actual values from the Arduino board
|
||||
int tft_width = 480; // default TFT width (automatic - sent by Arduino)
|
||||
int tft_height = 480; // default TFT height (automatic - sent by Arduino)
|
||||
int color_bytes = 2; // 2 for 16 bit, 3 for three RGB bytes (automatic - sent by Arduino)
|
||||
|
||||
int bgcolor = 255; // Background color
|
||||
import processing.serial.*;
|
||||
|
||||
PImage img, tft_img;
|
||||
Serial serial; // Create an instance called serial
|
||||
|
||||
color light_blue = color(50, 128, 255);
|
||||
int serialCount = 0; // Count of colour bytes arriving
|
||||
|
||||
int[] rgb = new int[6]; // Buffer for the RGB colour bytes
|
||||
// Stage window graded background colours
|
||||
color bgcolor1 = color(0, 100, 104); // Arduino IDE style background color 1
|
||||
color bgcolor2 = color(77, 183, 187); // Arduino IDE style background color 2
|
||||
//color bgcolor2 = color(255, 255, 255); // White
|
||||
|
||||
// TFT image frame greyscale value (dark grey)
|
||||
color frameColor = 42;
|
||||
|
||||
int[] rgb = new int[3]; // Buffer for the colour bytes
|
||||
int indexRed = 0; // Colour byte index in the array
|
||||
int indexGreen = 1;
|
||||
int indexBlue = 2;
|
||||
|
||||
long end = 10;
|
||||
|
||||
int n = 0;
|
||||
|
||||
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 y_offset = 20;
|
||||
|
||||
int xpos = 0, ypos = 0; // Current pixel position
|
||||
|
||||
int beginTime = 0;
|
||||
int pixelWaitTime = 1000; // Maximum 1000ms wait for image pixels to arrive
|
||||
@ -78,32 +87,25 @@ 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 progress_bar = 0; // Console progress bar dot count
|
||||
int pixel_count = 0; // Number of pixels read for 1 screen
|
||||
float percentage = 0; // Percentage of pixels received
|
||||
|
||||
int drawLoopCount = 0;
|
||||
int saved_image_count = 0; // Stats - number of images processed
|
||||
int bad_image_count = 0; // Stats - number of images that had lost pixels
|
||||
|
||||
int drawLoopCount = 0; // Used for the fade out
|
||||
|
||||
void setup() {
|
||||
|
||||
size(500, 540); // Stage size, could handle 480 pixel scrren
|
||||
size(500, 540); // Stage size, can handle 480 pixels wide screen
|
||||
noStroke(); // No border on the next thing drawn
|
||||
noSmooth(); // No anti-aliasing to avoid adjacent pixel colour merging
|
||||
|
||||
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);
|
||||
}
|
||||
// Graded background and title
|
||||
drawWindow();
|
||||
|
||||
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;
|
||||
frameRate(2000); // High frame rate so draw() loops fast
|
||||
|
||||
// Print a list of the available serial ports
|
||||
println("-----------------------");
|
||||
@ -118,27 +120,20 @@ void setup() {
|
||||
|
||||
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(0, 0, 0, 255);
|
||||
println();
|
||||
flushBuffer();
|
||||
println("");
|
||||
//println("Clearing pipe...");
|
||||
beginTime = millis() + 200;
|
||||
while ( millis() < beginTime )
|
||||
{
|
||||
serial.read();
|
||||
}
|
||||
println("Ready to receive image");
|
||||
print("Ready: ");
|
||||
|
||||
xpos = 0;
|
||||
ypos = 0;
|
||||
@ -146,139 +141,72 @@ void draw() {
|
||||
progress_bar = 0;
|
||||
pixel_count = 0;
|
||||
percentage = 0;
|
||||
drawLoopCount = 0;
|
||||
drawLoopCount = frameCount;
|
||||
lastPixelTime = millis() + 1000;
|
||||
|
||||
state = 1;
|
||||
break;
|
||||
|
||||
case 1: // Console message, give server some time
|
||||
println("Requesting image");
|
||||
print("requesting image ");
|
||||
serial.write("S");
|
||||
delay(10);
|
||||
delay(10);
|
||||
beginTime = millis() + 1000;
|
||||
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();
|
||||
noTint();
|
||||
state = 3;
|
||||
case 2: // Get size and set start time for rendering duration report
|
||||
if (millis() > beginTime) {
|
||||
System.err.println(" - no response!");
|
||||
state = 0;
|
||||
}
|
||||
if ( getSize() == true ) { // Go to next state when we have the size and bits per pixel
|
||||
flushBuffer(); // Precaution in case image header size increases in later versions
|
||||
beginTime = millis();
|
||||
state = 3;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // Request pixels and render returned RGB values
|
||||
state = renderPixels(); // State will change when all pixels are rendered
|
||||
|
||||
// Request more pixels, changing the number requested allows the average transfer rate to be controlled
|
||||
// The pixel transfer rate is dependant on four things:
|
||||
// 1. The frame rate defined in this Processing sketch in setup()
|
||||
// 2. The baud rate of the serial link (~10 bit periods per byte)
|
||||
// 3. The number of request bytes 'R' sent in the lines below
|
||||
// 4. The number of pixels sent in a burst by the server sketch (defined via NPIXELS)
|
||||
|
||||
if ( serial.available() > 0 ) {
|
||||
|
||||
// Add the latest byte from the serial port to array:
|
||||
while (serial.available()>0)
|
||||
{
|
||||
rgb[serialCount++] = serial.read();
|
||||
|
||||
// If we have 3 colour bytes:
|
||||
if (serialCount >= 3 ) {
|
||||
serialCount = 0;
|
||||
pixel_count++;
|
||||
stroke(rgb[indexRed], rgb[indexGreen], rgb[indexBlue],1000);
|
||||
// We seem to get some pixel transparency so draw twice
|
||||
point(xpos + x_offset, ypos + y_offset);
|
||||
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;
|
||||
}
|
||||
}
|
||||
// Request 32pixels
|
||||
serial.write("RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR");
|
||||
//serial.write("RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"); // 32 x NPIXELS more
|
||||
serial.write("RRRRRRRRRRRRRRRR"); // 16 x NPIXELS more
|
||||
//serial.write("RRRRRRRR"); // 8 x NPIXELS more
|
||||
//serial.write("RRRR"); // 4 x NPIXELS more
|
||||
//serial.write("RR"); // 2 x NPIXELS more
|
||||
//serial.write("R"); // 1 x NPIXELS more
|
||||
break;
|
||||
|
||||
case 4: // Time-out, flush serial buffer
|
||||
case 4: // Pixel receive time-out, flush serial buffer
|
||||
println();
|
||||
//println("Clearing serial pipe after a time-out");
|
||||
int clearTime = millis() + 50;
|
||||
while ( millis() < clearTime )
|
||||
{
|
||||
serial.read();
|
||||
}
|
||||
flushBuffer();
|
||||
state = 6;
|
||||
break;
|
||||
|
||||
case 5: // Save the image tot he sketch folder
|
||||
println();
|
||||
String filename = "tft_screen_" + n + image_type;
|
||||
println("Saving image as \"" + filename);
|
||||
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>=max_images) n = 0;
|
||||
drawLoopCount = 0; // Reset value ready for counting in step 6
|
||||
case 5: // Save the image to the sketch folder (Ctrl+K to access)
|
||||
saveScreenshot();
|
||||
saved_image_count++;
|
||||
println("Saved image count = " + saved_image_count);
|
||||
if (bad_image_count > 0) System.err.println(" Bad image count = " + bad_image_count);
|
||||
drawLoopCount = frameCount; // Reset value ready for counting in step 6
|
||||
state = 6;
|
||||
break;
|
||||
|
||||
case 6: // Fade the old image if enabled
|
||||
int opacity = drawLoopCount; // So we get increasing fade
|
||||
if (drawLoopCount > 50) // End fade after 50 cycles
|
||||
{
|
||||
opacity = 255;
|
||||
state = 0;
|
||||
}
|
||||
delay(10);
|
||||
if (fade)
|
||||
{
|
||||
tint(255, opacity);
|
||||
image(tft_img, x_offset, y_offset);
|
||||
}
|
||||
|
||||
if ( fadedImage() == true ) state = 0; // Go to next state when image has faded
|
||||
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(255);
|
||||
rect(x_offset, y_offset, tft_width-1, tft_height-1);
|
||||
|
||||
drawWindow();
|
||||
delay(50); // Delay here seems to be required for the IDE console to get ready
|
||||
state = 0;
|
||||
break;
|
||||
|
||||
@ -287,4 +215,185 @@ void draw() {
|
||||
System.err.println("Error state reached - check sketch!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void drawWindow()
|
||||
{
|
||||
// Graded background in Arduino colours
|
||||
for (int i = 0; i < height - 25; i++) {
|
||||
float inter = map(i, 0, height - 25, 0, 1);
|
||||
color c = lerpColor(bgcolor1, bgcolor2, inter);
|
||||
stroke(c);
|
||||
line(0, i, 500, i);
|
||||
}
|
||||
fill(bgcolor2);
|
||||
rect( 0, height-25, width-1, 24);
|
||||
textAlign(CENTER);
|
||||
textSize(20);
|
||||
fill(0);
|
||||
text("Bodmer's TFT image viewer", width/2, height-6);
|
||||
}
|
||||
|
||||
void flushBuffer()
|
||||
{
|
||||
//println("Clearing serial pipe after a time-out");
|
||||
int clearTime = millis() + 50;
|
||||
while ( millis() < clearTime ) serial.read();
|
||||
}
|
||||
|
||||
boolean getSize()
|
||||
{
|
||||
if ( serial.available() > 6 ) {
|
||||
println();
|
||||
char code = (char)serial.read();
|
||||
if (code == 'W') {
|
||||
tft_width = serial.read()<<8 | serial.read();
|
||||
}
|
||||
code = (char)serial.read();
|
||||
if (code == 'H') {
|
||||
tft_height = serial.read()<<8 | serial.read();
|
||||
}
|
||||
code = (char)serial.read();
|
||||
if (code == 'Y') {
|
||||
int bits_per_pixel = (char)serial.read();
|
||||
if (bits_per_pixel == 24) color_bytes = 3;
|
||||
else color_bytes = 2;
|
||||
}
|
||||
code = (char)serial.read();
|
||||
if (code == '?') {
|
||||
drawWindow();
|
||||
|
||||
x_offset = (500 - tft_width) /2;
|
||||
tint(0, 0, 0, 255);
|
||||
noStroke();
|
||||
fill(frameColor);
|
||||
rect((width - tft_width)/2 - border, y_offset - border, tft_width + 2 * border, tft_height + 2 * border);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int renderPixels()
|
||||
{
|
||||
if ( serial.available() > 0 ) {
|
||||
|
||||
// Add the latest byte from the serial port to array:
|
||||
while (serial.available()>0)
|
||||
{
|
||||
rgb[serialCount++] = serial.read();
|
||||
|
||||
// If we have 3 colour bytes:
|
||||
if ( serialCount >= color_bytes ) {
|
||||
serialCount = 0;
|
||||
pixel_count++;
|
||||
if (color_bytes == 3)
|
||||
{
|
||||
stroke(rgb[indexRed], rgb[indexGreen], rgb[indexBlue], 1000);
|
||||
} else
|
||||
{
|
||||
stroke( (rgb[1] & 0x1F)<<3, (rgb[1] & 0xE0)>>3 | (rgb[0] & 0x07)<<5, (rgb[0] & 0xF8));
|
||||
//stroke( (rgb[1] & 0xF8), (rgb[0] & 0xE0)>>3 | (rgb[1] & 0x07)<<5, (rgb[0] & 0x1F)<<3);
|
||||
}
|
||||
// We get some pixel merge aliasing if smooth() is defined, so draw pixel twice
|
||||
point(xpos + x_offset, ypos + y_offset);
|
||||
//point(xpos + x_offset, ypos + y_offset);
|
||||
|
||||
lastPixelTime = millis();
|
||||
xpos++;
|
||||
if (xpos >= tft_width) {
|
||||
xpos = 0;
|
||||
progressBar();
|
||||
ypos++;
|
||||
if (ypos>=tft_height) {
|
||||
ypos = 0;
|
||||
if ((int)percentage <100) {
|
||||
while(progress_bar++ < 64) print(" ");
|
||||
percent(100);
|
||||
}
|
||||
println("Image fetch time = " + (millis()-beginTime)/1000.0 + " s");
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else
|
||||
{
|
||||
if (millis() > (lastPixelTime + pixelWaitTime))
|
||||
{
|
||||
println("");
|
||||
System.err.println(pixelWaitTime + "ms time-out for pixels exceeded...");
|
||||
if (pixel_count > 0) {
|
||||
bad_image_count++;
|
||||
System.err.print("Pixels missing = " + (tft_width * tft_height - pixel_count));
|
||||
System.err.println(", corrupted image not saved");
|
||||
System.err.println("Good image count = " + saved_image_count);
|
||||
System.err.println(" Bad image count = " + bad_image_count);
|
||||
}
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
void progressBar()
|
||||
{
|
||||
progress_bar++;
|
||||
print(".");
|
||||
if (progress_bar >63)
|
||||
{
|
||||
progress_bar = 0;
|
||||
percentage = 0.5 + 100 * pixel_count/(0.001 + tft_width * tft_height);
|
||||
percent(percentage);
|
||||
}
|
||||
}
|
||||
|
||||
void percent(float percentage)
|
||||
{
|
||||
if (percentage > 100) percentage = 100;
|
||||
println(" [ " + (int)percentage + "% ]");
|
||||
textAlign(LEFT);
|
||||
textSize(16);
|
||||
noStroke();
|
||||
fill(bgcolor2);
|
||||
rect(10, height - 25, 70, 20);
|
||||
fill(0);
|
||||
text(" [ " + (int)percentage + "% ]", 10, height-8);
|
||||
}
|
||||
|
||||
void saveScreenshot()
|
||||
{
|
||||
println();
|
||||
String filename = "tft_screen_" + n + image_type;
|
||||
println("Saving image as \"" + filename);
|
||||
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>=max_images) n = 0;
|
||||
}
|
||||
|
||||
boolean fadedImage()
|
||||
{
|
||||
int opacity = frameCount - drawLoopCount; // So we get increasing fade
|
||||
if (fade)
|
||||
{
|
||||
tint(255, opacity);
|
||||
//image(tft_img, x_offset, y_offset);
|
||||
noStroke();
|
||||
fill(50, 50, 50, opacity);
|
||||
rect( (width - tft_width)/2, y_offset, tft_width, tft_height);
|
||||
delay(10);
|
||||
}
|
||||
if (opacity > 50) // End fade after 50 cycles
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 13 KiB |
Binary file not shown.
Before Width: | Height: | Size: 9.8 KiB |
@ -24,3 +24,25 @@
|
||||
//#include <User_Setups/Setup4_S6D02A1.h> // Setup file configured for my S6D02A1
|
||||
|
||||
//#include <User_Setups/SetupX_Template.h> // Setup file template for copying/editting
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// DON'T TINKER WITH ANY OF THE FOLLOWING LINES, THESE ADD THE TFT DRIVERS //
|
||||
// THEY ARE HERE FOR BODMER'S CONVENIENCE! //
|
||||
// //
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Load the right driver definition - do not tinker here !
|
||||
#if defined (ILI9341_DRIVER)
|
||||
#include <TFT_Drivers/ILI9341_Defines.h>
|
||||
#elif defined (ST7735_DRIVER)
|
||||
#include <TFT_Drivers/ST7735_Defines.h>
|
||||
#elif defined (ILI9163_DRIVER)
|
||||
#include <TFT_Drivers/ILI9163_Defines.h>
|
||||
#elif defined (S6D02A1_DRIVER)
|
||||
#include <TFT_Drivers/S6D02A1_Defines.h>
|
||||
#endif
|
||||
|
@ -1,24 +1,41 @@
|
||||
/*
|
||||
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 has been written to test the Processing screenshot client.
|
||||
|
||||
This sketch uses the GLCD, 2, 4, 6 fonts.
|
||||
It has been created to work with the TFT_eSPI library here:
|
||||
https://github.com/Bodmer/TFT_eSPI
|
||||
|
||||
It sends screenshots to a PC running a Processing client sketch.
|
||||
|
||||
The Processing IDE that will run the client sketch can be downloaded
|
||||
here: https://processing.org/
|
||||
|
||||
The Processing sketch needed is contained within a tab attached to this
|
||||
Arduino sketch. Cut and copy that tab into the Processing IDE and run.
|
||||
|
||||
This sketch uses the GLCD, 2, 4, 6 fonts only.
|
||||
|
||||
Make sure all the display driver and pin comnenctions are correct by
|
||||
editting the User_Setup.h file in the TFT_eSPI library folder.
|
||||
|
||||
Maximum recommended SPI clock rate is 27MHz when reading pixels, 40MHz
|
||||
seems to be OK with ILI9341 displays but this is above the manufacturers
|
||||
specifed maximum clock rate.
|
||||
|
||||
#########################################################################
|
||||
###### DON'T FORGET TO UPDATE THE User_Setup.h FILE IN THE LIBRARY ######
|
||||
#########################################################################
|
||||
*/
|
||||
|
||||
// Created by: Bodmer 5/3/17
|
||||
// Updated by: Bodmer 10/3/17
|
||||
// Version: 0.06
|
||||
|
||||
// MIT licence applies, all text above must be included in derivative works
|
||||
|
||||
#include <TFT_eSPI.h> // Hardware-specific library
|
||||
#include <SPI.h>
|
||||
|
||||
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
|
||||
TFT_eSPI tft = TFT_eSPI(); // Invoke custom library with default width and height
|
||||
|
||||
unsigned long targetTime = 0;
|
||||
byte red = 31;
|
||||
@ -34,72 +51,76 @@ void setup(void) {
|
||||
tft.setRotation(0);
|
||||
tft.fillScreen(TFT_BLACK);
|
||||
|
||||
randomSeed(analogRead(A0));
|
||||
|
||||
targetTime = millis() + 1000;
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
if (targetTime < millis()) {
|
||||
targetTime = millis() + 4000;
|
||||
|
||||
targetTime = millis() + 1500; // Wait a minimum of 1.5s
|
||||
|
||||
tft.setRotation(random(4));
|
||||
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.setTextColor(TFT_BLACK); // Text background is not defined so it is transparent
|
||||
tft.setTextDatum(TC_DATUM); // Top Centre datum
|
||||
int xpos = tft.width()/2; // Centre of screen
|
||||
|
||||
tft.setTextFont(0); // Select font 0 which is the Adafruit font
|
||||
tft.print("Original Adafruit font!");
|
||||
|
||||
//tft.drawString("Original Adafruit font!",60,5,1);
|
||||
tft.drawString("Original Adafruit font!", xpos, 5);
|
||||
|
||||
// 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.drawString("Font size 2", xpos, 14, 2); // Draw text centre at position xpos, 14 using font 2
|
||||
tft.drawString("Font size 4", xpos, 30, 4); // Draw text centre at position xpos, 30 using font 4
|
||||
tft.drawString("12.34", xpos, 54, 6); // Draw text centre at position xpos, 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
|
||||
tft.drawString("12.34 is in font size 6", xpos, 92, 2); // Draw text centre at position xpos, 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
|
||||
float pi = 3.1415926; // Value to print
|
||||
int precision = 3; // Number of digits after decimal point
|
||||
|
||||
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.setTextDatum(TR_DATUM); // Top Right datum so text butts neatly to xpos (right justified)
|
||||
|
||||
tft.drawFloat(pi, precision, xpos, ypos, 2); // Draw rounded number and return new xpos delta for next print position
|
||||
|
||||
tft.setTextDatum(TL_DATUM); // Top Left datum so text butts neatly to xpos (left justified)
|
||||
|
||||
tft.drawString(" is pi", xpos, ypos, 2);
|
||||
|
||||
tft.setTextSize(1); // We are using a font size multiplier of 1
|
||||
tft.setTextDatum(TC_DATUM); // Top Centre datum
|
||||
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.drawString("Transparent...", xpos, 125, 4); // Font 4
|
||||
|
||||
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_WHITE, TFT_BLACK); // Set text colour to white and background to black
|
||||
tft.drawString("White on black", xpos, 150, 4); // Font 4
|
||||
|
||||
tft.setTextColor(TFT_GREEN, TFT_BLACK); // This time we will use green text on a black background
|
||||
tft.setTextFont(2); // Select font 2
|
||||
|
||||
tft.setTextFont(2); // Select font 2, now we do not need to specify the font in drawString()
|
||||
|
||||
// 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(BC_DATUM); // Bottom centre for text datum
|
||||
tft.setTextPadding(tft.width() + 1); // Pad text to full screen width + 1 spare for +/-1 position rounding
|
||||
|
||||
tft.drawString("Ode to a Small Lump of Green Putty", xpos, 230 - 32);
|
||||
tft.drawString("I Found in My Armpit One Midsummer", xpos, 230 - 16);
|
||||
tft.drawString("Morning", xpos, 230);
|
||||
|
||||
tft.setTextDatum(TL_DATUM); // Reset to top left for text datum
|
||||
tft.setTextPadding(0); // Reset text padding to 0 pixels
|
||||
|
||||
// Now call the screen server to send a copy of the TFT screen to the PC running the Processing client sketch
|
||||
screenServer();
|
||||
}
|
||||
}
|
||||
@ -108,8 +129,9 @@ void loop() {
|
||||
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--) {
|
||||
int rotation = tft.getRotation();
|
||||
tft.setRotation(random(4));
|
||||
for (int i = tft.height() - 1; i >= 0; i--) {
|
||||
// This is a "state machine" that ramps up/down the colour brightnesses in sequence
|
||||
switch (state) {
|
||||
case 0:
|
||||
@ -159,6 +181,7 @@ void rainbow_fill()
|
||||
// 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
|
||||
}
|
||||
tft.setRotation(rotation);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,56 +1,51 @@
|
||||
// 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!
|
||||
// This is a copy of the processing sketch that can be used to capture the images
|
||||
// Copy the sketch below and remove the /* and */ at the beginning and end.
|
||||
|
||||
// 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:
|
||||
// The sketch runs in Processing version 3.3 on a PC, 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.
|
||||
// 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
|
||||
// The sketch must only be run when the designated serial port is available and enumerated
|
||||
// otherwise the screenshot window may freeze and that process will need to be terminated
|
||||
// This is a limitation of the Processing environment and not the sketch.
|
||||
// If anyone knows how to determine if a serial port is available at start up the PM me
|
||||
// on (Bodmer) the Arduino forum.
|
||||
|
||||
// Captured images are stored in the Processing sketch folder, use "Sketch" menu option
|
||||
// "Show Sketch Folder" or press Ctrl+K in the Processing IDE.
|
||||
// The block below contains variables that the user may need to change for a particular setup
|
||||
// As a minimum set the serial port and baud rate must be defined. The capture window is
|
||||
// automatically resized for landscape, portrait and different TFT resolutions.
|
||||
|
||||
// Created by: Bodmer 27/1/17
|
||||
// Captured images are stored in the sketch folder, use the Processing IDE "Sketch" menu
|
||||
// option "Show Sketch Folder" or press Ctrl+K
|
||||
|
||||
// Created by: Bodmer 5/3/17
|
||||
// Updated by: Bodmer 10/3/17
|
||||
// Version: 0.06
|
||||
|
||||
// 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 #
|
||||
// On an Arduino Due Programming Port use a baud rate of:115200) #
|
||||
// On an Arduino Due Native USB Port use a baud rate of any value #
|
||||
int serial_baud_rate = 921600; // #
|
||||
// #
|
||||
// Change the image file type saved here, comment out all but one #
|
||||
//String image_type = ".jpg"; // #
|
||||
String image_type = ".png"; // #
|
||||
String image_type = ".png"; // Lossless compression #
|
||||
//String image_type = ".bmp"; // #
|
||||
//String image_type = ".tif"; // #
|
||||
// #
|
||||
@ -63,62 +58,62 @@ int max_images = 10; // Maximum of numbered saved images before over-writing fil
|
||||
// # End of the values to change for a particular setup #
|
||||
// ###########################################################################################
|
||||
|
||||
int serialCount = 0; // Count of colour bytes arriving
|
||||
// These are default values, this sketch obtains the actual values from the Arduino board
|
||||
int tft_width = 480; // default TFT width (automatic - sent by Arduino)
|
||||
int tft_height = 480; // default TFT height (automatic - sent by Arduino)
|
||||
int color_bytes = 2; // 2 for 16 bit, 3 for three RGB bytes (automatic - sent by Arduino)
|
||||
|
||||
int bgcolor = 255; // Background color
|
||||
import processing.serial.*;
|
||||
|
||||
PImage img, tft_img;
|
||||
Serial serial; // Create an instance called serial
|
||||
|
||||
color light_blue = color(50, 128, 255);
|
||||
int serialCount = 0; // Count of colour bytes arriving
|
||||
|
||||
int[] rgb = new int[6]; // Buffer for the RGB colour bytes
|
||||
// Stage window graded background colours
|
||||
color bgcolor1 = color(0, 100, 104); // Arduino IDE style background color 1
|
||||
color bgcolor2 = color(77, 183, 187); // Arduino IDE style background color 2
|
||||
//color bgcolor2 = color(255, 255, 255); // White
|
||||
|
||||
// TFT image frame greyscale value (dark grey)
|
||||
color frameColor = 42;
|
||||
|
||||
int[] rgb = new int[3]; // Buffer for the 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 n = 0;
|
||||
|
||||
int x_offset = (500 - tft_width) /2; // Image offsets in the window
|
||||
int y_offset = 20; //
|
||||
int xpos, ypos; // Pixel position
|
||||
int y_offset = 20;
|
||||
|
||||
int xpos = 0, ypos = 0; // Current pixel position
|
||||
|
||||
int beginTime = 0;
|
||||
int pixelWaitTime = 100; // Wait a maximum of 100ms gap for image pixels to arrive
|
||||
int pixelWaitTime = 1000; // Maximum 1000ms wait 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 progress_bar = 0; // Console progress bar dot count
|
||||
int pixel_count = 0; // Number of pixels read for 1 screen
|
||||
float percentage = 0; // Percentage of pixels received
|
||||
|
||||
int drawLoopCount = 0;
|
||||
int saved_image_count = 0; // Stats - number of images processed
|
||||
int bad_image_count = 0; // Stats - number of images that had lost pixels
|
||||
|
||||
int drawLoopCount = 0; // Used for the fade out
|
||||
|
||||
void setup() {
|
||||
|
||||
size(500, 540); // Stage size, could handle 480 pixel scrren
|
||||
size(500, 540); // Stage size, can handle 480 pixels wide screen
|
||||
noStroke(); // No border on the next thing drawn
|
||||
noSmooth(); // No anti-aliasing to avoid adjacent pixel colour merging
|
||||
|
||||
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);
|
||||
}
|
||||
// Graded background and title
|
||||
drawWindow();
|
||||
|
||||
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;
|
||||
frameRate(2000); // High frame rate so draw() loops fast
|
||||
|
||||
// Print a list of the available serial ports
|
||||
println("-----------------------");
|
||||
@ -133,164 +128,93 @@ void setup() {
|
||||
|
||||
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);
|
||||
|
||||
tint(0, 0, 0, 255);
|
||||
println();
|
||||
flushBuffer();
|
||||
println("");
|
||||
//println("Clearing pipe...");
|
||||
beginTime = millis() + 200;
|
||||
while ( millis() < beginTime )
|
||||
{
|
||||
serial.read();
|
||||
}
|
||||
println("Ready to receive image");
|
||||
serial.write("S");
|
||||
print("Ready: ");
|
||||
|
||||
xpos = 0;
|
||||
ypos = 0;
|
||||
serialCount = 0;
|
||||
progress_bar = 0;
|
||||
pixel_count = 0;
|
||||
percentage = 0;
|
||||
drawLoopCount = 0;
|
||||
drawLoopCount = frameCount;
|
||||
lastPixelTime = millis() + 1000;
|
||||
|
||||
state = 1;
|
||||
break;
|
||||
|
||||
case 1: // Console message, give server some time
|
||||
println("Requesting image");
|
||||
delay(10);
|
||||
print("requesting image ");
|
||||
serial.write("S");
|
||||
delay(10);
|
||||
beginTime = millis() + 1000;
|
||||
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");
|
||||
}
|
||||
case 2: // Get size and set start time for rendering duration report
|
||||
if (millis() > beginTime) {
|
||||
System.err.println(" - no response!");
|
||||
state = 0;
|
||||
}
|
||||
if ( getSize() == true ) { // Go to next state when we have the size and bits per pixel
|
||||
flushBuffer(); // Precaution in case image header size increases in later versions
|
||||
beginTime = millis();
|
||||
state = 3;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: // Time-out, flush serial buffer
|
||||
case 3: // Request pixels and render returned RGB values
|
||||
state = renderPixels(); // State will change when all pixels are rendered
|
||||
|
||||
// Request more pixels, changing the number requested allows the average transfer rate to be controlled
|
||||
// The pixel transfer rate is dependant on four things:
|
||||
// 1. The frame rate defined in this Processing sketch in setup()
|
||||
// 2. The baud rate of the serial link (~10 bit periods per byte)
|
||||
// 3. The number of request bytes 'R' sent in the lines below
|
||||
// 4. The number of pixels sent in a burst by the server sketch (defined via NPIXELS)
|
||||
|
||||
//serial.write("RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"); // 32 x NPIXELS more
|
||||
serial.write("RRRRRRRRRRRRRRRR"); // 16 x NPIXELS more
|
||||
//serial.write("RRRRRRRR"); // 8 x NPIXELS more
|
||||
//serial.write("RRRR"); // 4 x NPIXELS more
|
||||
//serial.write("RR"); // 2 x NPIXELS more
|
||||
//serial.write("R"); // 1 x NPIXELS more
|
||||
break;
|
||||
|
||||
case 4: // Pixel receive 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;
|
||||
flushBuffer();
|
||||
state = 6;
|
||||
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
|
||||
case 5: // Save the image to the sketch folder (Ctrl+K to access)
|
||||
saveScreenshot();
|
||||
saved_image_count++;
|
||||
println("Saved image count = " + saved_image_count);
|
||||
if (bad_image_count > 0) System.err.println(" Bad image count = " + bad_image_count);
|
||||
drawLoopCount = frameCount; // 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
|
||||
if ( fadedImage() == true ) state = 0; // Go to next state when image has faded
|
||||
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);
|
||||
|
||||
drawWindow();
|
||||
delay(50); // Delay here seems to be required for the IDE console to get ready
|
||||
state = 0;
|
||||
break;
|
||||
|
||||
@ -301,4 +225,186 @@ void draw() {
|
||||
}
|
||||
}
|
||||
|
||||
*/ // <<<<<<<<<<<<<<<<<<<<<<<<< REMOVE THIS LINE <<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
void drawWindow()
|
||||
{
|
||||
// Graded background in Arduino colours
|
||||
for (int i = 0; i < height - 25; i++) {
|
||||
float inter = map(i, 0, height - 25, 0, 1);
|
||||
color c = lerpColor(bgcolor1, bgcolor2, inter);
|
||||
stroke(c);
|
||||
line(0, i, 500, i);
|
||||
}
|
||||
fill(bgcolor2);
|
||||
rect( 0, height-25, width-1, 24);
|
||||
textAlign(CENTER);
|
||||
textSize(20);
|
||||
fill(0);
|
||||
text("Bodmer's TFT image viewer", width/2, height-6);
|
||||
}
|
||||
|
||||
void flushBuffer()
|
||||
{
|
||||
//println("Clearing serial pipe after a time-out");
|
||||
int clearTime = millis() + 50;
|
||||
while ( millis() < clearTime ) serial.read();
|
||||
}
|
||||
|
||||
boolean getSize()
|
||||
{
|
||||
if ( serial.available() > 6 ) {
|
||||
println();
|
||||
char code = (char)serial.read();
|
||||
if (code == 'W') {
|
||||
tft_width = serial.read()<<8 | serial.read();
|
||||
}
|
||||
code = (char)serial.read();
|
||||
if (code == 'H') {
|
||||
tft_height = serial.read()<<8 | serial.read();
|
||||
}
|
||||
code = (char)serial.read();
|
||||
if (code == 'Y') {
|
||||
int bits_per_pixel = (char)serial.read();
|
||||
if (bits_per_pixel == 24) color_bytes = 3;
|
||||
else color_bytes = 2;
|
||||
}
|
||||
code = (char)serial.read();
|
||||
if (code == '?') {
|
||||
drawWindow();
|
||||
|
||||
x_offset = (500 - tft_width) /2;
|
||||
tint(0, 0, 0, 255);
|
||||
noStroke();
|
||||
fill(frameColor);
|
||||
rect((width - tft_width)/2 - border, y_offset - border, tft_width + 2 * border, tft_height + 2 * border);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int renderPixels()
|
||||
{
|
||||
if ( serial.available() > 0 ) {
|
||||
|
||||
// Add the latest byte from the serial port to array:
|
||||
while (serial.available()>0)
|
||||
{
|
||||
rgb[serialCount++] = serial.read();
|
||||
|
||||
// If we have 3 colour bytes:
|
||||
if ( serialCount >= color_bytes ) {
|
||||
serialCount = 0;
|
||||
pixel_count++;
|
||||
if (color_bytes == 3)
|
||||
{
|
||||
stroke(rgb[indexRed], rgb[indexGreen], rgb[indexBlue], 1000);
|
||||
} else
|
||||
{
|
||||
stroke( (rgb[1] & 0x1F)<<3, (rgb[1] & 0xE0)>>3 | (rgb[0] & 0x07)<<5, (rgb[0] & 0xF8));
|
||||
//stroke( (rgb[1] & 0xF8), (rgb[0] & 0xE0)>>3 | (rgb[1] & 0x07)<<5, (rgb[0] & 0x1F)<<3);
|
||||
}
|
||||
// We get some pixel merge aliasing if smooth() is defined, so draw pixel twice
|
||||
point(xpos + x_offset, ypos + y_offset);
|
||||
//point(xpos + x_offset, ypos + y_offset);
|
||||
|
||||
lastPixelTime = millis();
|
||||
xpos++;
|
||||
if (xpos >= tft_width) {
|
||||
xpos = 0;
|
||||
progressBar();
|
||||
ypos++;
|
||||
if (ypos>=tft_height) {
|
||||
ypos = 0;
|
||||
if ((int)percentage <100) {
|
||||
while(progress_bar++ < 64) print(" ");
|
||||
percent(100);
|
||||
}
|
||||
println("Image fetch time = " + (millis()-beginTime)/1000.0 + " s");
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else
|
||||
{
|
||||
if (millis() > (lastPixelTime + pixelWaitTime))
|
||||
{
|
||||
println("");
|
||||
System.err.println(pixelWaitTime + "ms time-out for pixels exceeded...");
|
||||
if (pixel_count > 0) {
|
||||
bad_image_count++;
|
||||
System.err.print("Pixels missing = " + (tft_width * tft_height - pixel_count));
|
||||
System.err.println(", corrupted image not saved");
|
||||
System.err.println("Good image count = " + saved_image_count);
|
||||
System.err.println(" Bad image count = " + bad_image_count);
|
||||
}
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
void progressBar()
|
||||
{
|
||||
progress_bar++;
|
||||
print(".");
|
||||
if (progress_bar >63)
|
||||
{
|
||||
progress_bar = 0;
|
||||
percentage = 0.5 + 100 * pixel_count/(0.001 + tft_width * tft_height);
|
||||
percent(percentage);
|
||||
}
|
||||
}
|
||||
|
||||
void percent(float percentage)
|
||||
{
|
||||
if (percentage > 100) percentage = 100;
|
||||
println(" [ " + (int)percentage + "% ]");
|
||||
textAlign(LEFT);
|
||||
textSize(16);
|
||||
noStroke();
|
||||
fill(bgcolor2);
|
||||
rect(10, height - 25, 70, 20);
|
||||
fill(0);
|
||||
text(" [ " + (int)percentage + "% ]", 10, height-8);
|
||||
}
|
||||
|
||||
void saveScreenshot()
|
||||
{
|
||||
println();
|
||||
String filename = "tft_screen_" + n + image_type;
|
||||
println("Saving image as \"" + filename);
|
||||
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>=max_images) n = 0;
|
||||
}
|
||||
|
||||
boolean fadedImage()
|
||||
{
|
||||
int opacity = frameCount - drawLoopCount; // So we get increasing fade
|
||||
if (fade)
|
||||
{
|
||||
tint(255, opacity);
|
||||
//image(tft_img, x_offset, y_offset);
|
||||
noStroke();
|
||||
fill(50, 50, 50, opacity);
|
||||
rect( (width - tft_width)/2, y_offset, tft_width, tft_height);
|
||||
delay(10);
|
||||
}
|
||||
if (opacity > 50) // End fade after 50 cycles
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
*/
|
||||
|
@ -1,68 +1,62 @@
|
||||
// TFT screenshot server
|
||||
// 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);
|
||||
|
||||
// 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 copy 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)
|
||||
// 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.06
|
||||
|
||||
// The MIT permissive free software license applies, include all text above in
|
||||
// derivatives.
|
||||
// MIT licence applies, all text above must be included in derivative works
|
||||
|
||||
#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
|
||||
#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
|
||||
|
||||
// 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
|
||||
|
||||
|
||||
// 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();
|
||||
|
||||
delay(0); // Equivalent to yield() for ESP8266;
|
||||
|
||||
boolean result = serialScreenServer(); // Screenshot serial port server
|
||||
//boolean result = wifiDump(); // Screenshot WiFi UDP port server (WIP)
|
||||
|
||||
//boolean result = wifiScreenServer(); // 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();
|
||||
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;
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
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
|
||||
@ -70,7 +64,7 @@ boolean serialScreenServer(void)
|
||||
// Wait for the starting flag with a start time-out
|
||||
while (wait)
|
||||
{
|
||||
yield();
|
||||
delay(0); // Equivalent to yield() for ESP8266;
|
||||
// Check serial buffer
|
||||
if (Serial.available() > 0) {
|
||||
// Read the command byte
|
||||
@ -79,21 +73,21 @@ boolean serialScreenServer(void)
|
||||
if ( cmd == 'S' ) {
|
||||
// Precautionary receive buffer garbage flush for 50ms
|
||||
clearTime = millis() + 50;
|
||||
while ( millis() < clearTime ) {
|
||||
Serial.read();
|
||||
yield();
|
||||
}
|
||||
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, 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');
|
||||
// Send screen size using a simple header with delimiters for client checks
|
||||
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');
|
||||
Serial.write(BITS_PER_PIXEL);
|
||||
Serial.write('?');
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -103,49 +97,49 @@ boolean serialScreenServer(void)
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t color[3]; // RGB color buffer for 1 pixel
|
||||
|
||||
// Send all the pixels on the whole screen (typically 5 seconds at 921600 baud)
|
||||
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 2 as we send 2 pixels for every byte received
|
||||
for ( uint32_t x = 0; x < tft.width(); x += 1)
|
||||
// Increment x by NPIXELS as we send NPIXELS for every byte received
|
||||
for ( uint32_t x = 0; x < tft.width(); x += NPIXELS)
|
||||
{
|
||||
yield();
|
||||
delay(0); // Equivalent to yield() for ESP8266;
|
||||
|
||||
// Wait here for serial data to arrive or a time-out elapses
|
||||
while ( Serial.available() == 0 )
|
||||
{
|
||||
yield;
|
||||
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
|
||||
// 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();
|
||||
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();
|
||||
|
||||
// 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
|
||||
#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
|
||||
}
|
||||
}
|
||||
|
||||
// Receive buffer excess command flush for 50ms
|
||||
clearTime = millis() + 50;
|
||||
while ( millis() < clearTime ) Serial.read();
|
||||
|
||||
Serial.flush(); // Make sure all pixel bytes have been despatched
|
||||
|
||||
return true;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user