-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
Copy pathscreenServer.ino
196 lines (162 loc) · 7.68 KB
/
screenServer.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// Reads a screen image off the TFT and send it to a processing client sketch
// over the serial port. Use a high baud rate, e.g. for an ESP8266:
// Serial.begin(921600);
// At 921600 baud a 320 x 240 image with 16 bit colour transfers can be sent to the
// PC client in ~1.67s and 24 bit colour in ~2.5s which is close to the theoretical
// minimum transfer time.
// This sketch has been created to work with the TFT_eSPI library here:
// https://github.com/Bodmer/TFT_eSPI
// Created by: Bodmer 27/1/17
// Updated by: Bodmer 10/3/17
// Updated by: Bodmer 23/11/18 to support SDA reads and the ESP32
// Version: 0.08
// MIT licence applies, all text above must be included in derivative works
//====================================================================================
// Definitions
//====================================================================================
#define PIXEL_TIMEOUT 100 // 100ms Time-out between pixel requests
#define START_TIMEOUT 10000 // 10s Maximum time to wait at start transfer
#define BITS_PER_PIXEL 16 // 24 for RGB colour format, 16 for 565 colour format
// File names must be alpha-numeric characters (0-9, a-z, A-Z) or "/" underscore "_"
// other ascii characters are stripped out by client, including / generates
// sub-directories
#define DEFAULT_FILENAME "tft_screenshots/screenshot" // In case none is specified
#define FILE_TYPE "png" // jpg, bmp, png, tif are valid
// Filename extension
// '#' = add incrementing number, '@' = add timestamp, '%' add millis() timestamp,
// '*' = add nothing
// '@' and '%' will generate new unique filenames, so beware of cluttering up your
// hard drive with lots of images! The PC client sketch is set to limit the number of
// saved images to 1000 and will then prompt for a restart.
#define FILE_EXT '@'
// Number of pixels to send in a burst (minimum of 1), no benefit above 8
// NPIXELS values and render times:
// NPIXELS 1 = use readPixel() = >5s and 16 bit pixels only
// NPIXELS >1 using rectRead() 2 = 1.75s, 4 = 1.68s, 8 = 1.67s
#define NPIXELS 8 // Must be integer division of both TFT width and TFT height
//====================================================================================
// Screen server call with no filename
//====================================================================================
// Start a screen dump server (serial or network) - no filename specified
bool screenServer(void)
{
// With no filename the screenshot will be saved with a default name e.g. tft_screen_#.xxx
// where # is a number 0-9 and xxx is a file type specified below
return screenServer(DEFAULT_FILENAME);
}
//====================================================================================
// Screen server call with filename
//====================================================================================
// Start a screen dump server (serial or network) - filename specified
bool screenServer(String filename)
{
delay(0); // Equivalent to yield() for ESP8266;
bool result = serialScreenServer(filename); // Screenshot serial port server
//bool result = wifiScreenServer(filename); // Screenshot WiFi UDP port server (WIP)
delay(0); // Equivalent to yield()
//Serial.println();
//if (result) Serial.println(F("Screen dump passed :-)"));
//else Serial.println(F("Screen dump failed :-("));
return result;
}
//====================================================================================
// Serial server function that sends the data to the client
//====================================================================================
bool serialScreenServer(String filename)
{
// Precautionary receive buffer garbage flush for 50ms
uint32_t clearTime = millis() + 50;
while ( millis() < clearTime && Serial.read() >= 0) delay(0); // Equivalent to yield() for ESP8266;
bool wait = true;
uint32_t lastCmdTime = millis(); // Initialise start of command time-out
// Wait for the starting flag with a start time-out
while (wait)
{
delay(0); // Equivalent to yield() for ESP8266;
// Check serial buffer
if (Serial.available() > 0) {
// Read the command byte
uint8_t cmd = Serial.read();
// If it is 'S' (start command) then clear the serial buffer for 100ms and stop waiting
if ( cmd == 'S' ) {
// Precautionary receive buffer garbage flush for 50ms
clearTime = millis() + 50;
while ( millis() < clearTime && Serial.read() >= 0) delay(0); // Equivalent to yield() for ESP8266;
wait = false; // No need to wait anymore
lastCmdTime = millis(); // Set last received command time
// Send screen size etc using a simple header with delimiters for client checks
sendParameters(filename);
}
}
else
{
// Check for time-out
if ( millis() > lastCmdTime + START_TIMEOUT) return false;
}
}
uint8_t color[3 * NPIXELS]; // RGB and 565 format color buffer for N pixels
// Send all the pixels on the whole screen
for ( uint32_t y = 0; y < tft.height(); y++)
{
// Increment x by NPIXELS as we send NPIXELS for every byte received
for ( uint32_t x = 0; x < tft.width(); x += NPIXELS)
{
delay(0); // Equivalent to yield() for ESP8266;
// Wait here for serial data to arrive or a time-out elapses
while ( Serial.available() == 0 )
{
if ( millis() > lastCmdTime + PIXEL_TIMEOUT) return false;
delay(0); // Equivalent to yield() for ESP8266;
}
// Serial data must be available to get here, read 1 byte and
// respond with N pixels, i.e. N x 3 RGB bytes or N x 2 565 format bytes
if ( Serial.read() == 'X' ) {
// X command byte means abort, so clear the buffer and return
clearTime = millis() + 50;
while ( millis() < clearTime && Serial.read() >= 0) delay(0); // Equivalent to yield() for ESP8266;
return false;
}
// Save arrival time of the read command (for later time-out check)
lastCmdTime = millis();
#if defined BITS_PER_PIXEL && BITS_PER_PIXEL >= 24 && NPIXELS > 1
// 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
if (NPIXELS > 1) tft.readRect(x, y, NPIXELS, 1, (uint16_t *)color);
else
{
uint16_t c = tft.readPixel(x, y);
color[0] = c>>8;
color[1] = c & 0xFF; // Swap bytes
}
// Send buffer to client
Serial.write(color, 2 * NPIXELS); // Write all pixels in the buffer
#endif
}
}
Serial.flush(); // Make sure all pixel bytes have been despatched
return true;
}
//====================================================================================
// Send screen size etc using a simple header with delimiters for client checks
//====================================================================================
void sendParameters(String filename)
{
Serial.write('W'); // Width
Serial.write(tft.width() >> 8);
Serial.write(tft.width() & 0xFF);
Serial.write('H'); // Height
Serial.write(tft.height() >> 8);
Serial.write(tft.height() & 0xFF);
Serial.write('Y'); // Bits per pixel (16 or 24)
if (NPIXELS > 1) Serial.write(BITS_PER_PIXEL);
else Serial.write(16); // readPixel() only provides 16 bit values
Serial.write('?'); // Filename next
Serial.print(filename);
Serial.write('.'); // End of filename marker
Serial.write(FILE_EXT); // Filename extension identifier
Serial.write(*FILE_TYPE); // First character defines file type j,b,p,t
}