acidportal- 😈 Worlds smallest Evil Portal on a LilyGo T-QT |
git clone git://git.acid.vegas/acidportal.git |
Log | Files | Refs | Archive | README | LICENSE |
processing_sketch.ino (17336B)
1 // This is a copy of the processing sketch that can be used to capture the images 2 // Copy the sketch below and remove the /* and */ at the beginning and end. 3 4 // The sketch runs in Processing version 3.3 on a PC, it can be downloaded here: 5 // https://processing.org/download/ 6 7 /* 8 9 // This is a Processing sketch, see https://processing.org/ to download the IDE 10 11 // The sketch is a client that requests TFT screenshots from an Arduino board. 12 // The Arduino must call a screenshot server function to respond with pixels. 13 14 // It has been created to work with the TFT_eSPI library here: 15 // https://github.com/Bodmer/TFT_eSPI 16 17 // The sketch must only be run when the designated serial port is available and enumerated 18 // otherwise the screenshot window may freeze and that process will need to be terminated 19 // This is a limitation of the Processing environment and not the sketch. 20 // If anyone knows how to determine if a serial port is available at start up the PM me 21 // on (Bodmer) the Arduino forum. 22 23 // The block below contains variables that the user may need to change for a particular setup 24 // As a minimum set the serial port and baud rate must be defined. The capture window is 25 // automatically resized for landscape, portrait and different TFT resolutions. 26 27 // Captured images are stored in the sketch folder, use the Processing IDE "Sketch" menu 28 // option "Show Sketch Folder" or press Ctrl+K 29 30 // Created by: Bodmer 5/3/17 31 // Updated by: Bodmer 12/3/17 32 // Version: 0.07 33 34 // MIT licence applies, all text above must be included in derivative works 35 36 37 // ########################################################################################### 38 // # These are the values to change for a particular setup # 39 // # 40 int serial_port = 0; // Use enumerated value from list provided when sketch is run # 41 // # 42 // On an Arduino Due Programming Port use a baud rate of:115200) # 43 // On an Arduino Due Native USB Port use a baud rate of any value # 44 int serial_baud_rate = 921600; // # 45 // # 46 // Change the image file type saved here, comment out all but one # 47 //String image_type = ".jpg"; // # 48 String image_type = ".png"; // Lossless compression # 49 //String image_type = ".bmp"; // # 50 //String image_type = ".tif"; // # 51 // # 52 boolean save_border = true; // Save the image with a border # 53 int border = 5; // Border pixel width # 54 boolean fade = false; // Fade out image after saving # 55 // # 56 int max_images = 100; // Maximum of numbered file images before over-writing files # 57 // # 58 int max_allowed = 1000; // Maximum number of save images allowed before a restart # 59 // # 60 // # End of the values to change for a particular setup # 61 // ########################################################################################### 62 63 // These are default values, this sketch obtains the actual values from the Arduino board 64 int tft_width = 480; // default TFT width (automatic - sent by Arduino) 65 int tft_height = 480; // default TFT height (automatic - sent by Arduino) 66 int color_bytes = 2; // 2 for 16 bit, 3 for three RGB bytes (automatic - sent by Arduino) 67 68 import processing.serial.*; 69 70 Serial serial; // Create an instance called serial 71 72 int serialCount = 0; // Count of colour bytes arriving 73 74 // Stage window graded background colours 75 color bgcolor1 = color(0, 100, 104); // Arduino IDE style background color 1 76 color bgcolor2 = color(77, 183, 187); // Arduino IDE style background color 2 77 //color bgcolor2 = color(255, 255, 255); // White 78 79 // TFT image frame greyscale value (dark grey) 80 color frameColor = 42; 81 82 color buttonStopped = color(255, 0, 0); 83 color buttonRunning = color(128, 204, 206); 84 color buttonDimmed = color(180, 0, 0); 85 boolean dimmed = false; 86 boolean running = true; 87 boolean mouseClick = false; 88 89 int[] rgb = new int[3]; // Buffer for the colour bytes 90 int indexRed = 0; // Colour byte index in the array 91 int indexGreen = 1; 92 int indexBlue = 2; 93 94 int n = 0; 95 96 int x_offset = (500 - tft_width) /2; // Image offsets in the window 97 int y_offset = 20; 98 99 int xpos = 0, ypos = 0; // Current pixel position 100 101 int beginTime = 0; 102 int pixelWaitTime = 1000; // Maximum 1000ms wait for image pixels to arrive 103 int lastPixelTime = 0; // Time that "image send" command was sent 104 105 int requestTime = 0; 106 int requestCount = 0; 107 108 int state = 0; // State machine current state 109 110 int progress_bar = 0; // Console progress bar dot count 111 int pixel_count = 0; // Number of pixels read for 1 screen 112 float percentage = 0; // Percentage of pixels received 113 114 int saved_image_count = 0; // Stats - number of images processed 115 int bad_image_count = 0; // Stats - number of images that had lost pixels 116 String filename = ""; 117 118 int drawLoopCount = 0; // Used for the fade out 119 120 void setup() { 121 122 size(500, 540); // Stage size, can handle 480 pixels wide screen 123 noStroke(); // No border on the next thing drawn 124 noSmooth(); // No anti-aliasing to avoid adjacent pixel colour merging 125 126 // Graded background and title 127 drawWindow(); 128 129 frameRate(2000); // High frame rate so draw() loops fast 130 131 // Print a list of the available serial ports 132 println("-----------------------"); 133 println("Available Serial Ports:"); 134 println("-----------------------"); 135 printArray(Serial.list()); 136 println("-----------------------"); 137 138 print("Port currently used: ["); 139 print(serial_port); 140 println("]"); 141 142 String portName = Serial.list()[serial_port]; 143 144 serial = new Serial(this, portName, serial_baud_rate); 145 146 state = 99; 147 } 148 149 void draw() { 150 151 if (mouseClick) buttonClicked(); 152 153 switch(state) { 154 155 case 0: // Init varaibles, send start request 156 if (running) { 157 tint(0, 0, 0, 255); 158 flushBuffer(); 159 println(""); 160 print("Ready: "); 161 162 xpos = 0; 163 ypos = 0; 164 serialCount = 0; 165 progress_bar = 0; 166 pixel_count = 0; 167 percentage = 0; 168 drawLoopCount = frameCount; 169 lastPixelTime = millis() + 1000; 170 171 state = 1; 172 } else { 173 if (millis() > beginTime) { 174 beginTime = millis() + 500; 175 dimmed = !dimmed; 176 if (dimmed) drawButton(buttonDimmed); 177 else drawButton(buttonStopped); 178 } 179 } 180 break; 181 182 case 1: // Console message, give server some time 183 print("requesting image "); 184 serial.write("S"); 185 delay(10); 186 beginTime = millis(); 187 requestTime = millis() + 1000; 188 requestCount = 1; 189 state = 2; 190 break; 191 192 case 2: // Get size and set start time for rendering duration report 193 if (millis() > requestTime) { 194 requestCount++; 195 print("*"); 196 serial.clear(); 197 serial.write("S"); 198 if (requestCount > 32) { 199 requestCount = 0; 200 System.err.println(" - no response!"); 201 state = 0; 202 } 203 requestTime = millis() + 1000; 204 } 205 if ( getSize() == true ) { // Go to next state when we have the size and bits per pixel 206 getFilename(); 207 flushBuffer(); // Precaution in case image header size increases in later versions 208 lastPixelTime = millis() + 1000; 209 beginTime = millis(); 210 state = 3; 211 } 212 break; 213 214 case 3: // Request pixels and render returned RGB values 215 state = renderPixels(); // State will change when all pixels are rendered 216 217 // Request more pixels, changing the number requested allows the average transfer rate to be controlled 218 // The pixel transfer rate is dependant on four things: 219 // 1. The frame rate defined in this Processing sketch in setup() 220 // 2. The baud rate of the serial link (~10 bit periods per byte) 221 // 3. The number of request bytes 'R' sent in the lines below 222 // 4. The number of pixels sent in a burst by the server sketch (defined via NPIXELS) 223 224 //serial.write("RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"); // 32 x NPIXELS more 225 serial.write("RRRRRRRRRRRRRRRR"); // 16 x NPIXELS more 226 //serial.write("RRRRRRRR"); // 8 x NPIXELS more 227 //serial.write("RRRR"); // 4 x NPIXELS more 228 //serial.write("RR"); // 2 x NPIXELS more 229 //serial.write("R"); // 1 x NPIXELS more 230 if (!running) state = 4; 231 break; 232 233 case 4: // Pixel receive time-out, flush serial buffer 234 flushBuffer(); 235 state = 6; 236 break; 237 238 case 5: // Save the image to the sketch folder (Ctrl+K to access) 239 saveScreenshot(); 240 saved_image_count++; 241 println("Saved image count = " + saved_image_count); 242 if (bad_image_count > 0) System.err.println(" Bad image count = " + bad_image_count); 243 drawLoopCount = frameCount; // Reset value ready for counting in step 6 244 state = 6; 245 break; 246 247 case 6: // Fade the old image if enabled 248 if ( fadedImage() == true ) state = 0; // Go to next state when image has faded 249 break; 250 251 case 99: // Draw image viewer window 252 drawWindow(); 253 delay(50); // Delay here seems to be required for the IDE console to get ready 254 state = 0; 255 break; 256 257 default: 258 println(""); 259 System.err.println("Error state reached - check sketch!"); 260 break; 261 } 262 } 263 264 void drawWindow() 265 { 266 // Graded background in Arduino colours 267 for (int i = 0; i < height - 25; i++) { 268 float inter = map(i, 0, height - 25, 0, 1); 269 color c = lerpColor(bgcolor1, bgcolor2, inter); 270 stroke(c); 271 line(0, i, 500, i); 272 } 273 fill(bgcolor2); 274 rect( 0, height-25, width-1, 24); 275 textAlign(CENTER); 276 textSize(20); 277 fill(0); 278 text("Bodmer's TFT image viewer", width/2, height-6); 279 280 if (running) drawButton(buttonRunning); 281 else drawButton(buttonStopped); 282 } 283 284 void flushBuffer() 285 { 286 //println("Clearing serial pipe after a time-out"); 287 int clearTime = millis() + 50; 288 while ( millis() < clearTime ) serial.clear(); 289 } 290 291 boolean getSize() 292 { 293 if ( serial.available() > 6 ) { 294 println(); 295 char code = (char)serial.read(); 296 if (code == 'W') { 297 tft_width = serial.read()<<8 | serial.read(); 298 } 299 code = (char)serial.read(); 300 if (code == 'H') { 301 tft_height = serial.read()<<8 | serial.read(); 302 } 303 code = (char)serial.read(); 304 if (code == 'Y') { 305 int bits_per_pixel = (char)serial.read(); 306 if (bits_per_pixel == 24) color_bytes = 3; 307 else color_bytes = 2; 308 } 309 code = (char)serial.read(); 310 if (code == '?') { 311 drawWindow(); 312 313 x_offset = (500 - tft_width) /2; 314 tint(0, 0, 0, 255); 315 noStroke(); 316 fill(frameColor); 317 rect((width - tft_width)/2 - border, y_offset - border, tft_width + 2 * border, tft_height + 2 * border); 318 return true; 319 } 320 } 321 return false; 322 } 323 324 void saveScreenshot() 325 { 326 println(); 327 if (saved_image_count < max_allowed) 328 { 329 if (filename == "") filename = "tft_screen_" + (n++); 330 filename = filename + image_type; 331 println("Saving image as \"" + filename + "\""); 332 if (save_border) 333 { 334 PImage partialSave = get(x_offset - border, y_offset - border, tft_width + 2*border, tft_height + 2*border); 335 partialSave.save(filename); 336 } else { 337 PImage partialSave = get(x_offset, y_offset, tft_width, tft_height); 338 partialSave.save(filename); 339 } 340 341 if (n>=max_images) n = 0; 342 } 343 else 344 { 345 System.err.println(max_allowed + " saved image count exceeded, restart the sketch"); 346 } 347 } 348 349 void getFilename() 350 { 351 int readTime = millis() + 20; 352 int inByte = 0; 353 filename = ""; 354 while ( serial.available() > 0 && millis() < readTime && inByte != '.') 355 { 356 inByte = serial.read(); 357 if (inByte == ' ') inByte = '_'; 358 if ( unicodeCheck(inByte) ) filename += (char)inByte; 359 } 360 361 inByte = serial.read(); 362 if (inByte == '@') filename += "_" + timeCode(); 363 else if (inByte == '#') filename += "_" + saved_image_count%100; 364 else if (inByte == '%') filename += "_" + millis(); 365 else if (inByte != '*') filename = ""; 366 367 inByte = serial.read(); 368 if (inByte == 'j') image_type =".jpg"; 369 else if (inByte == 'b') image_type =".bmp"; 370 else if (inByte == 'p') image_type =".png"; 371 else if (inByte == 't') image_type =".tif"; 372 } 373 374 boolean unicodeCheck(int unicode) 375 { 376 if ( unicode >= '0' && unicode <= '9' ) return true; 377 if ( (unicode >= 'A' && unicode <= 'Z' ) || (unicode >= 'a' && unicode <= 'z')) return true; 378 if ( unicode == '_' || unicode == '/' ) return true; 379 return false; 380 } 381 382 String timeCode() 383 { 384 String timeCode = (int)year() + "_" + (int)month() + "_" + (int)day() + "_"; 385 timeCode += (int)hour() + "_" + (int)minute() + "_" + (int)second(); 386 return timeCode; 387 } 388 389 int renderPixels() 390 { 391 if ( serial.available() > 0 ) { 392 393 // Add the latest byte from the serial port to array: 394 while (serial.available()>0) 395 { 396 rgb[serialCount++] = serial.read(); 397 398 // If we have 3 colour bytes: 399 if ( serialCount >= color_bytes ) { 400 serialCount = 0; 401 pixel_count++; 402 if (color_bytes == 3) 403 { 404 stroke(rgb[indexRed], rgb[indexGreen], rgb[indexBlue], 1000); 405 } else 406 { // Can cater for various byte orders 407 //stroke( (rgb[0] & 0x1F)<<3, (rgb[0] & 0xE0)>>3 | (rgb[1] & 0x07)<<5, (rgb[1] & 0xF8)); 408 //stroke( (rgb[1] & 0x1F)<<3, (rgb[1] & 0xE0)>>3 | (rgb[0] & 0x07)<<5, (rgb[0] & 0xF8)); 409 stroke( (rgb[0] & 0xF8), (rgb[1] & 0xE0)>>3 | (rgb[0] & 0x07)<<5, (rgb[1] & 0x1F)<<3); 410 //stroke( (rgb[1] & 0xF8), (rgb[0] & 0xE0)>>3 | (rgb[1] & 0x07)<<5, (rgb[0] & 0x1F)<<3); 411 } 412 // We get some pixel merge aliasing if smooth() is defined, so draw pixel twice 413 point(xpos + x_offset, ypos + y_offset); 414 //point(xpos + x_offset, ypos + y_offset); 415 416 lastPixelTime = millis(); 417 xpos++; 418 if (xpos >= tft_width) { 419 xpos = 0; 420 progressBar(); 421 ypos++; 422 if (ypos>=tft_height) { 423 ypos = 0; 424 if ((int)percentage <100) { 425 while (progress_bar++ < 64) print(" "); 426 percent(100); 427 } 428 println("Image fetch time = " + (millis()-beginTime)/1000.0 + " s"); 429 return 5; 430 } 431 } 432 } 433 } 434 } else 435 { 436 if (millis() > (lastPixelTime + pixelWaitTime)) 437 { 438 println(""); 439 System.err.println(pixelWaitTime + "ms time-out for pixels exceeded..."); 440 if (pixel_count > 0) { 441 bad_image_count++; 442 System.err.print("Pixels missing = " + (tft_width * tft_height - pixel_count)); 443 System.err.println(", corrupted image not saved"); 444 System.err.println("Good image count = " + saved_image_count); 445 System.err.println(" Bad image count = " + bad_image_count); 446 } 447 return 4; 448 } 449 } 450 return 3; 451 } 452 453 void progressBar() 454 { 455 progress_bar++; 456 print("."); 457 if (progress_bar >63) 458 { 459 progress_bar = 0; 460 percentage = 0.5 + 100 * pixel_count/(0.001 + tft_width * tft_height); 461 percent(percentage); 462 } 463 } 464 465 void percent(float percentage) 466 { 467 if (percentage > 100) percentage = 100; 468 println(" [ " + (int)percentage + "% ]"); 469 textAlign(LEFT); 470 textSize(16); 471 noStroke(); 472 fill(bgcolor2); 473 rect(10, height - 25, 70, 20); 474 fill(0); 475 text(" [ " + (int)percentage + "% ]", 10, height-8); 476 } 477 478 boolean fadedImage() 479 { 480 int opacity = frameCount - drawLoopCount; // So we get increasing fade 481 if (fade) 482 { 483 tint(255, opacity); 484 //image(tft_img, x_offset, y_offset); 485 noStroke(); 486 fill(50, 50, 50, opacity); 487 rect( (width - tft_width)/2, y_offset, tft_width, tft_height); 488 delay(10); 489 } 490 if (opacity > 50) // End fade after 50 cycles 491 { 492 return true; 493 } 494 return false; 495 } 496 497 void drawButton(color buttonColor) 498 { 499 stroke(0); 500 fill(buttonColor); 501 rect(500 - 100, 540 - 26, 80, 24); 502 textAlign(CENTER); 503 textSize(20); 504 fill(0); 505 if (running) text(" Pause ", 500 - 60, height-7); 506 else text(" Run ", 500 - 60, height-7); 507 } 508 509 void buttonClicked() 510 { 511 mouseClick = false; 512 if (running) { 513 running = false; 514 drawButton(buttonStopped); 515 System.err.println(""); 516 System.err.println("Stopped - click 'Run' button: "); 517 //noStroke(); 518 //fill(50); 519 //rect( (width - tft_width)/2, y_offset, tft_width, tft_height); 520 beginTime = millis() + 500; 521 dimmed = false; 522 state = 4; 523 } else { 524 running = true; 525 drawButton(buttonRunning); 526 } 527 } 528 529 void mousePressed() { 530 if (mouseX > (500 - 100) && mouseX < (500 - 20) && mouseY > (540 - 26) && mouseY < (540 - 2)) { 531 mouseClick = true; 532 } 533 } 534 535 */