acidportal

- 😈 Worlds smallest Evil Portal on a LilyGo T-QT
git clone git://git.acid.vegas/acidportal.git
Log | Files | Refs | Archive | README | LICENSE

ESP8266_uncannyEyes.ino (19608B)

      1 // Adapted by Bodmer to work with a NodeMCU and ILI9341 or ST7735 display.
      2 //
      3 // This code currently does not "blink" the eye!
      4 //
      5 // Library used is here:
      6 // https://github.com/Bodmer/TFT_eSPI
      7 //
      8 // To do, maybe, one day:
      9 // 1. Get the eye to blink
     10 // 2. Add another screen for another eye
     11 // 3. Add variable to set how wide open the eye is
     12 // 4. Add a reflected highlight to the cornea
     13 // 5. Add top eyelid shadow to eye surface
     14 // 6. Add aliasing to blur mask edge
     15 //
     16 // With one lidded eye drawn the code runs at 28-33fps (at 27-40MHz SPI clock)
     17 // which is quite reasonable. Operation at an 80MHz SPI clock is possible but
     18 // the display may not be able to cope with a clock rate that high and the
     19 // performance improvement is small. Operate the ESP8266 at 160MHz for best
     20 // frame rate. Note the images are stored in SPI FLASH (PROGMEM) so performance
     21 // will be constrained by the increased memory access time.
     22 
     23 // Original header for this sketch is below. Note: the technical aspects of the
     24 // text no longer apply to this modified version of the sketch:
     25 /*
     26 //--------------------------------------------------------------------------
     27 // Uncanny eyes for PJRC Teensy 3.1 with Adafruit 1.5" OLED (product #1431)
     28 // or 1.44" TFT LCD (#2088).  This uses Teensy-3.1-specific features and
     29 // WILL NOT work on normal Arduino or other boards!  Use 72 MHz (Optimized)
     30 // board speed -- OLED does not work at 96 MHz.
     31 //
     32 // Adafruit invests time and resources providing this open source code,
     33 // please support Adafruit and open-source hardware by purchasing products
     34 // from Adafruit!
     35 //
     36 // Written by Phil Burgess / Paint Your Dragon for Adafruit Industries.
     37 // MIT license.  SPI FIFO insight from Paul Stoffregen's ILI9341_t3 library.
     38 // Inspired by David Boccabella's (Marcwolf) hybrid servo/OLED eye concept.
     39 //--------------------------------------------------------------------------
     40 */
     41 
     42 #include <SPI.h>
     43 #include <TFT_eSPI.h> // Hardware-specific library
     44 
     45 // Enable ONE of these #includes for the various eyes:
     46 #include "defaultEye.h"        // Standard human-ish hazel eye
     47 //#include "noScleraEye.h"       // Large iris, no sclera
     48 //#include "dragonEye.h"         // Slit pupil fiery dragon/demon eye
     49 //#include "goatEye.h"           // Horizontal pupil goat/Krampus eye
     50 
     51 
     52 #define DISPLAY_DC      D3 // Data/command pin for BOTH displays
     53 #define DISPLAY_RESET   D4 // Reset pin for BOTH displays
     54 #define SELECT_L_PIN    D8 // LEFT eye chip select pin
     55 #define SELECT_R_PIN    D8 // RIGHT eye chip select pin
     56 
     57 // INPUT CONFIG (for eye motion -- enable or comment out as needed) --------
     58 
     59 // The ESP8266 is rather constrained here as it only has one analogue port.
     60 // An I2C ADC could be used for more analogue channels
     61 //#define JOYSTICK_X_PIN A0 // Analogue pin for eye horiz pos (else auto)
     62 //#define JOYSTICK_Y_PIN A0 // Analogue pin for eye vert position (")
     63 //#define JOYSTICK_X_FLIP   // If set, reverse stick X axis
     64 //#define JOYSTICK_Y_FLIP   // If set, reverse stick Y axis
     65 #define TRACKING          // If enabled, eyelid tracks pupil
     66 //#define IRIS_PIN       A0 // Photocell or potentiometer (else auto iris)
     67 //#define IRIS_PIN_FLIP     // If set, reverse reading from dial/photocell
     68 //#define IRIS_SMOOTH       // If enabled, filter input from IRIS_PIN
     69 #define IRIS_MIN      140 // Clip lower analogRead() range from IRIS_PIN
     70 #define IRIS_MAX      260 // Clip upper "
     71 #define WINK_L_PIN      0 // Pin for LEFT eye wink button
     72 #define BLINK_PIN       1 // Pin for blink button (BOTH eyes)
     73 #define WINK_R_PIN      2 // Pin for RIGHT eye wink button
     74 #define AUTOBLINK         // If enabled, eyes blink autonomously
     75 
     76 // Probably don't need to edit any config below this line, -----------------
     77 // unless building a single-eye project (pendant, etc.), in which case one
     78 // of the two elements in the eye[] array further down can be commented out.
     79 
     80 // Eye blinks are a tiny 3-state machine.  Per-eye allows winks + blinks.
     81 #define NOBLINK 0     // Not currently engaged in a blink
     82 #define ENBLINK 1     // Eyelid is currently closing
     83 #define DEBLINK 2     // Eyelid is currently opening
     84 typedef struct {
     85   int8_t   pin;       // Optional button here for indiv. wink
     86   uint8_t  state;     // NOBLINK/ENBLINK/DEBLINK
     87   int32_t  duration;  // Duration of blink state (micros)
     88   uint32_t startTime; // Time (micros) of last state change
     89 } eyeBlink;
     90 
     91 struct {
     92   TFT_eSPI tft; // OLED/eye[e].tft object
     93   uint8_t     cs;      // Chip select pin
     94   eyeBlink    blink;   // Current blink state
     95 } eye[] = { // OK to comment out one of these for single-eye display:
     96   TFT_eSPI(),SELECT_L_PIN,{WINK_L_PIN,NOBLINK},
     97   //TFT_eSPI(),SELECT_R_PIN,{WINK_R_PIN,NOBLINK},
     98 };
     99 
    100 #define NUM_EYES (sizeof(eye) / sizeof(eye[0]))
    101 
    102 uint32_t fstart = 0;  // start time to improve frame rate calculation at startup
    103 
    104 // INITIALIZATION -- runs once at startup ----------------------------------
    105 
    106 void setup(void) {
    107   uint8_t e = 0;
    108   
    109   Serial.begin(250000);
    110   randomSeed(analogRead(A0)); // Seed random() from floating analogue input
    111 
    112   eye[e].tft.init();
    113   eye[e].tft.fillScreen(TFT_BLACK);
    114   eye[e].tft.setRotation(0);
    115 
    116   fstart = millis()-1; // Subtract 1 to avoid divide by zero later
    117 }
    118 
    119 
    120 // EYE-RENDERING FUNCTION --------------------------------------------------
    121 #define BUFFER_SIZE 256 // 64 to 512 seems optimum = 30 fps for default eye
    122 void drawEye( // Renders one eye.  Inputs must be pre-clipped & valid.
    123   // Use native 32 bit variables where possible as this is 10% faster!
    124   uint8_t  e,       // Eye array index; 0 or 1 for left/right
    125   uint32_t iScale,  // Scale factor for iris
    126   uint32_t  scleraX, // First pixel X offset into sclera image
    127   uint32_t  scleraY, // First pixel Y offset into sclera image
    128   uint32_t  uT,      // Upper eyelid threshold value
    129   uint32_t  lT) {    // Lower eyelid threshold value
    130 
    131   uint32_t  screenX, screenY, scleraXsave;
    132   int32_t  irisX, irisY;
    133   uint32_t p, a;
    134   uint32_t d;
    135 
    136   uint32_t pixels = 0;
    137   uint16_t pbuffer[BUFFER_SIZE]; // This one needs to be 16 bit
    138   
    139   // Set up raw pixel dump to entire screen.  Although such writes can wrap
    140   // around automatically from end of rect back to beginning, the region is
    141   // reset on each frame here in case of an SPI glitch.
    142 
    143   //eye[e].tft.setAddrWindow(319-127, 0, 319, 127);
    144   eye[e].tft.setAddrWindow(0, 0, 128, 128);
    145   
    146   //digitalWrite(eye[e].cs, LOW);                       // Chip select
    147 
    148   // Now just issue raw 16-bit values for every pixel...
    149 
    150   scleraXsave = scleraX; // Save initial X value to reset on each line
    151   irisY       = scleraY - (SCLERA_HEIGHT - IRIS_HEIGHT) / 2;
    152   for(screenY=0; screenY<SCREEN_HEIGHT; screenY++, scleraY++, irisY++) {
    153     scleraX = scleraXsave;
    154     irisX   = scleraXsave - (SCLERA_WIDTH - IRIS_WIDTH) / 2;
    155     for(screenX=0; screenX<SCREEN_WIDTH; screenX++, scleraX++, irisX++) {
    156       if((pgm_read_byte(lower + screenY * SCREEN_WIDTH + screenX) <= lT) ||
    157          (pgm_read_byte(upper + screenY * SCREEN_WIDTH + screenX) <= uT)) {             // Covered by eyelid
    158         p = 0;
    159       } else if((irisY < 0) || (irisY >= IRIS_HEIGHT) ||
    160                 (irisX < 0) || (irisX >= IRIS_WIDTH)) { // In sclera
    161         p = pgm_read_word(sclera + scleraY * SCLERA_WIDTH + scleraX);
    162       } else {                                          // Maybe iris...
    163         p = pgm_read_word(polar + irisY * IRIS_WIDTH + irisX);                        // Polar angle/dist
    164         d = (iScale * (p & 0x7F)) / 128;                // Distance (Y)
    165         if(d < IRIS_MAP_HEIGHT) {                       // Within iris area
    166           a = (IRIS_MAP_WIDTH * (p >> 7)) / 512;        // Angle (X)
    167           p = pgm_read_word(iris + d * IRIS_MAP_WIDTH + a);                               // Pixel = iris
    168         } else {                                        // Not in iris
    169           p = pgm_read_word(sclera + scleraY * SCLERA_WIDTH + scleraX);                 // Pixel = sclera
    170         }
    171       }
    172       *(pbuffer + pixels++) = p>>8 | p<<8;
    173 
    174       if (pixels >= BUFFER_SIZE) { yield(); eye[e].tft.pushColors((uint8_t*)pbuffer, pixels*2); pixels = 0;}
    175     }
    176   }
    177 
    178    if (pixels) { eye[e].tft.pushColors(pbuffer, pixels); pixels = 0;}
    179 }
    180 
    181 
    182 // EYE ANIMATION -----------------------------------------------------------
    183 
    184 const uint8_t ease[] = { // Ease in/out curve for eye movements 3*t^2-2*t^3
    185     0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  2,  2,  2,  3,   // T
    186     3,  3,  4,  4,  4,  5,  5,  6,  6,  7,  7,  8,  9,  9, 10, 10,   // h
    187    11, 12, 12, 13, 14, 15, 15, 16, 17, 18, 18, 19, 20, 21, 22, 23,   // x
    188    24, 25, 26, 27, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39,   // 2
    189    40, 41, 42, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 56, 57, 58,   // A
    190    60, 61, 62, 63, 65, 66, 67, 69, 70, 72, 73, 74, 76, 77, 78, 80,   // l
    191    81, 83, 84, 85, 87, 88, 90, 91, 93, 94, 96, 97, 98,100,101,103,   // e
    192   104,106,107,109,110,112,113,115,116,118,119,121,122,124,125,127,   // c
    193   128,130,131,133,134,136,137,139,140,142,143,145,146,148,149,151,   // J
    194   152,154,155,157,158,159,161,162,164,165,167,168,170,171,172,174,   // a
    195   175,177,178,179,181,182,183,185,186,188,189,190,192,193,194,195,   // c
    196   197,198,199,201,202,203,204,205,207,208,209,210,211,213,214,215,   // o
    197   216,217,218,219,220,221,222,224,225,226,227,228,228,229,230,231,   // b
    198   232,233,234,235,236,237,237,238,239,240,240,241,242,243,243,244,   // s
    199   245,245,246,246,247,248,248,249,249,250,250,251,251,251,252,252,   // o
    200   252,253,253,253,254,254,254,254,254,255,255,255,255,255,255,255 }; // n
    201 
    202 #ifdef AUTOBLINK
    203 uint32_t timeOfLastBlink = 0L, timeToNextBlink = 0L;
    204 #endif
    205 
    206 void frame( // Process motion for a single frame of left or right eye
    207   uint32_t        iScale) {     // Iris scale (0-1023) passed in
    208   static uint32_t frames   = 0; // Used in frame rate calculation
    209   static uint8_t  eyeIndex = 0; // eye[] array counter
    210   int32_t         eyeX, eyeY;
    211   uint32_t        t = micros(); // Time at start of function
    212 
    213   Serial.print((++frames * 1000) / (millis() - fstart)); Serial.println("fps");// Show frame rate
    214 
    215   if(++eyeIndex >= NUM_EYES) eyeIndex = 0; // Cycle through eyes, 1 per call
    216 
    217  // Autonomous X/Y eye motion
    218       // Periodically initiates motion to a new random point, random speed,
    219       // holds there for random period until next motion.
    220 
    221   static bool  eyeInMotion      = false;
    222   static int32_t  eyeOldX=512, eyeOldY=512, eyeNewX=512, eyeNewY=512;
    223   static uint32_t eyeMoveStartTime = 0L;
    224   static int32_t  eyeMoveDuration  = 0L;
    225 
    226   int32_t dt = t - eyeMoveStartTime;      // uS elapsed since last eye event
    227   if(eyeInMotion) {                       // Currently moving?
    228     if(dt >= eyeMoveDuration) {           // Time up?  Destination reached.
    229       eyeInMotion      = false;           // Stop moving
    230       eyeMoveDuration  = random(3000000L); // 0-3 sec stop
    231       eyeMoveStartTime = t;               // Save initial time of stop
    232       eyeX = eyeOldX = eyeNewX;           // Save position
    233       eyeY = eyeOldY = eyeNewY;
    234     } else { // Move time's not yet fully elapsed -- interpolate position
    235       int16_t e = ease[255 * dt / eyeMoveDuration] + 1;   // Ease curve
    236       eyeX = eyeOldX + (((eyeNewX - eyeOldX) * e) / 256); // Interp X
    237       eyeY = eyeOldY + (((eyeNewY - eyeOldY) * e) / 256); // and Y
    238     }
    239   } else {                                // Eye stopped
    240     eyeX = eyeOldX;
    241     eyeY = eyeOldY;
    242     if(dt > eyeMoveDuration) {            // Time up?  Begin new move.
    243       int16_t  dx, dy;
    244       uint32_t d;
    245       do {                                // Pick new dest in circle
    246         eyeNewX = random(1024);
    247         eyeNewY = random(1024);
    248         dx      = (eyeNewX * 2) - 1023;
    249         dy      = (eyeNewY * 2) - 1023;
    250       } while((d = (dx * dx + dy * dy)) > (1023 * 1023)); // Keep trying
    251       eyeMoveDuration  = random(50000, 150000);//random(72000, 144000); // ~1/14 - ~1/7 sec
    252       eyeMoveStartTime = t;               // Save initial time of move
    253       eyeInMotion      = true;            // Start move on next frame
    254     }
    255   }
    256 
    257   // Blinking
    258 /*
    259 #ifdef AUTOBLINK
    260   // Similar to the autonomous eye movement above -- blink start times
    261   // and durations are random (within ranges).
    262   if((t - timeOfLastBlink) >= timeToNextBlink) { // Start new blink?
    263     timeOfLastBlink = t;
    264     uint32_t blinkDuration = random(36000, 72000); // ~1/28 - ~1/14 sec
    265     // Set up durations for both eyes (if not already winking)
    266     for(uint8_t e=0; e<NUM_EYES; e++) {
    267       if(eye[e].blink.state == NOBLINK) {
    268         eye[e].blink.state     = ENBLINK;
    269         eye[e].blink.startTime = t;
    270         eye[e].blink.duration  = blinkDuration;
    271       }
    272     }
    273     timeToNextBlink = blinkDuration * 3 + random(4000000);
    274   }
    275 #endif
    276 */
    277 /*
    278   if(eye[eyeIndex].blink.state) { // Eye currently blinking?
    279     // Check if current blink state time has elapsed
    280     if((t - eye[eyeIndex].blink.startTime) >= eye[eyeIndex].blink.duration) {
    281       // Yes -- increment blink state, unless...
    282       if((eye[eyeIndex].blink.state == ENBLINK) &&  // Enblinking and...
    283         ((digitalRead(BLINK_PIN) == LOW) ||         // blink or wink held...
    284           digitalRead(eye[eyeIndex].blink.pin) == LOW)) {
    285         // Don't advance state yet -- eye is held closed instead
    286       } else { // No buttons, or other state...
    287         if(++eye[eyeIndex].blink.state > DEBLINK) { // Deblinking finished?
    288           eye[eyeIndex].blink.state = NOBLINK;      // No longer blinking
    289         } else { // Advancing from ENBLINK to DEBLINK mode
    290           eye[eyeIndex].blink.duration *= 2; // DEBLINK is 1/2 ENBLINK speed
    291           eye[eyeIndex].blink.startTime = t;
    292         }
    293       }
    294     }
    295   } else { // Not currently blinking...check buttons!
    296     if(digitalRead(BLINK_PIN) == LOW) {
    297       // Manually-initiated blinks have random durations like auto-blink
    298       uint32_t blinkDuration = random(36000, 72000);
    299       for(uint8_t e=0; e<NUM_EYES; e++) {
    300         if(eye[e].blink.state == NOBLINK) {
    301           eye[e].blink.state     = ENBLINK;
    302           eye[e].blink.startTime = t;
    303           eye[e].blink.duration  = blinkDuration;
    304         }
    305       }
    306     } else if(digitalRead(eye[eyeIndex].blink.pin) == LOW) { // Wink!
    307       eye[eyeIndex].blink.state     = ENBLINK;
    308       eye[eyeIndex].blink.startTime = t;
    309       eye[eyeIndex].blink.duration  = random(45000, 90000);
    310     }
    311   }
    312 */
    313   // Process motion, blinking and iris scale into renderable values
    314 
    315   // Iris scaling: remap from 0-1023 input to iris map height pixel units
    316   iScale = ((IRIS_MAP_HEIGHT + 1) * 1024) /
    317            (1024 - (iScale * (IRIS_MAP_HEIGHT - 1) / IRIS_MAP_HEIGHT));
    318 
    319   // Scale eye X/Y positions (0-1023) to pixel units used by drawEye()
    320   eyeX = map(eyeX, 0, 1023, 0, SCLERA_WIDTH  - 128);
    321   eyeY = map(eyeY, 0, 1023, 0, SCLERA_HEIGHT - 128);
    322   if(eyeIndex == 1) eyeX = (SCLERA_WIDTH - 128) - eyeX; // Mirrored display
    323 
    324   // Horizontal position is offset so that eyes are very slightly crossed
    325   // to appear fixated (converged) at a conversational distance.  Number
    326   // here was extracted from my posterior and not mathematically based.
    327   // I suppose one could get all clever with a range sensor, but for now...
    328   eyeX += 4;
    329   if(eyeX > (SCLERA_WIDTH - 128)) eyeX = (SCLERA_WIDTH - 128);
    330 
    331   // Eyelids are rendered using a brightness threshold image.  This same
    332   // map can be used to simplify another problem: making the upper eyelid
    333   // track the pupil (eyes tend to open only as much as needed -- e.g. look
    334   // down and the upper eyelid drops).  Just sample a point in the upper
    335   // lid map slightly above the pupil to determine the rendering threshold.
    336   static uint8_t uThreshold = 128;
    337   uint8_t        lThreshold, n;
    338 
    339 #ifdef TRACKING
    340   int16_t sampleX = SCLERA_WIDTH  / 2 - (eyeX / 2), // Reduce X influence
    341           sampleY = SCLERA_HEIGHT / 2 - (eyeY + IRIS_HEIGHT / 4);
    342   // Eyelid is slightly asymmetrical, so two readings are taken, averaged
    343   if(sampleY < 0) n = 0;
    344   else            n = (pgm_read_byte(upper + sampleY * SCREEN_WIDTH + sampleX) +
    345                        pgm_read_byte(upper + sampleY * SCREEN_WIDTH + (SCREEN_WIDTH - 1 - sampleX))) / 2;
    346   uThreshold = (uThreshold * 3 + n) / 4; // Filter/soften motion
    347   // Lower eyelid doesn't track the same way, but seems to be pulled upward
    348   // by tension from the upper lid.
    349   lThreshold = 254 - uThreshold;
    350 #else // No tracking -- eyelids full open unless blink modifies them
    351   uThreshold = lThreshold = 0;
    352 #endif
    353 
    354   // The upper/lower thresholds are then scaled relative to the current
    355   // blink position so that blinks work together with pupil tracking.
    356   if(eye[eyeIndex].blink.state) { // Eye currently blinking?
    357     uint32_t s = (t - eye[eyeIndex].blink.startTime);
    358     if(s >= eye[eyeIndex].blink.duration) s = 255;   // At or past blink end
    359     else s = 255 * s / eye[eyeIndex].blink.duration; // Mid-blink
    360     s          = (eye[eyeIndex].blink.state == DEBLINK) ? 1 + s : 256 - s;
    361     n          = (uThreshold * s + 254 * (257 - s)) / 256;
    362     lThreshold = (lThreshold * s + 254 * (257 - s)) / 256;
    363   } else {
    364     n          = uThreshold;
    365   }
    366 
    367   // Pass all the derived values to the eye-rendering function:
    368   drawEye(eyeIndex, iScale, eyeX, eyeY, n, lThreshold);
    369 
    370 }
    371 
    372 
    373 // AUTONOMOUS IRIS SCALING (if no photocell or dial) -----------------------
    374 
    375 #if !defined(IRIS_PIN) || (IRIS_PIN < 0)
    376 
    377 // Autonomous iris motion uses a fractal behavior to similate both the major
    378 // reaction of the eye plus the continuous smaller adjustments that occur.
    379 
    380 uint16_t oldIris = (IRIS_MIN + IRIS_MAX) / 2, newIris;
    381 
    382 void split( // Subdivides motion path into two sub-paths w/randimization
    383   int16_t  startValue, // Iris scale value (IRIS_MIN to IRIS_MAX) at start
    384   int16_t  endValue,   // Iris scale value at end
    385   uint32_t startTime,  // micros() at start
    386   int32_t  duration,   // Start-to-end time, in microseconds
    387   int16_t  range) {    // Allowable scale value variance when subdividing
    388 
    389   if(range >= 8) {     // Limit subdvision count, because recursion
    390     range    /= 2;     // Split range & time in half for subdivision,
    391     duration /= 2;     // then pick random center point within range:
    392     int16_t  midValue = (startValue + endValue - range) / 2 + random(range);
    393     uint32_t midTime  = startTime + duration;
    394     split(startValue, midValue, startTime, duration, range); // First half
    395     split(midValue  , endValue, midTime  , duration, range); // Second half
    396   } else {             // No more subdivisons, do iris motion...
    397     int32_t dt;        // Time (micros) since start of motion
    398     int16_t v;         // Interim value
    399     while((dt = (micros() - startTime)) < duration) {
    400       v = startValue + (((endValue - startValue) * dt) / duration);
    401       if(v < IRIS_MIN)      v = IRIS_MIN; // Clip just in case
    402       else if(v > IRIS_MAX) v = IRIS_MAX;
    403       frame(v);        // Draw frame w/interim iris scale value
    404     }
    405   }
    406 }
    407 
    408 #endif // !IRIS_PIN
    409 
    410 
    411 // MAIN LOOP -- runs continuously after setup() ----------------------------
    412 
    413 void loop() {
    414 
    415 #if defined(IRIS_PIN) && (IRIS_PIN >= 0) // Interactive iris
    416 
    417   uint16_t v = 512; //analogRead(IRIS_PIN);       // Raw dial/photocell reading
    418 #ifdef IRIS_PIN_FLIP
    419   v = 1023 - v;
    420 #endif
    421   v = map(v, 0, 1023, IRIS_MIN, IRIS_MAX); // Scale to iris range
    422 #ifdef IRIS_SMOOTH // Filter input (gradual motion)
    423   static uint16_t irisValue = (IRIS_MIN + IRIS_MAX) / 2;
    424   irisValue = ((irisValue * 15) + v) / 16;
    425   frame(irisValue);
    426 #else // Unfiltered (immediate motion)
    427   frame(v);
    428 #endif // IRIS_SMOOTH
    429 
    430 #else  // Autonomous iris scaling -- invoke recursive function
    431 
    432   newIris = random(IRIS_MIN, IRIS_MAX);
    433   split(oldIris, newIris, micros(), 10000000L, IRIS_MAX - IRIS_MIN);
    434   oldIris = newIris;
    435 
    436 #endif // IRIS_PIN
    437 
    438 //screenshotToConsole();
    439 }
    440 
    441 
    442