Update to screenshot sketches + others

Minor tweaks and re-arrangement of User and Custom font references
between header files
This commit is contained in:
Bodmer 2017-03-10 19:16:31 +00:00
parent 60e7d90750
commit 406aac051e
9 changed files with 728 additions and 486 deletions

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}
*/

View File

@ -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;
}