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