@@ -59,6 +59,8 @@ int iPupilFactor = 42;
5959uint32_t boopSum = 0 ,
6060 boopSumFiltered = 0 ;
6161bool booped = false ;
62+ bool eyelidsClosed = false ;
63+ bool eyelidsWide = false ;
6264int fixate = 7 ;
6365uint8_t lightSensorFailCount = 0 ;
6466
@@ -135,34 +137,52 @@ uint32_t availableRAM(void) {
135137
136138// USER CALLABLE FUNCTIONS
137139
138- // set the booped flag
139- void eyesWide (bool t) {
140- booped = t;
140+ // Start a blink.
141+ void eyesBlink () {
142+ Serial.println (" eyesBlink()" );
143+ timeToNextBlink = 0 ;
141144}
142145
143- // start a blink
144- void eyesBlink () {
145- timeToNextBlink = 0 ;
146+ // Force the booped flag to be set true.
147+ void eyesBoop () {
148+ Serial.println (" eyesBoop()" );
149+ boopSum = 99999 ;
150+ }
151+
152+ // Close eyelids.
153+ void eyesClose () {
154+ Serial.println (" eyesClose()" );
155+ eyelidsClosed = true ;
146156}
147157
148- // force the eyes to a position on the screen
158+ // Return the eyes to normal random movement.
159+ void eyesNormal () {
160+ // Serial.println("eyesNormal()");
161+ moveEyesRandomly = true ;
162+ }
163+
164+ // Open eyelids wide.
165+ void eyesWide () {
166+ Serial.println (" eyesWide()" );
167+ eyelidsWide = true ;
168+ }
169+
170+ // Force the eyes to a position on the screen.
149171void eyesToCorner (float x, float y, bool immediate) {
172+ // Serial.println("eyesToCorner(" + String(x) + ", " + String(-y) + ", " + (immediate ? "TRUE" : "FALSE") + ")");
150173 moveEyesRandomly = false ;
151174 eyeTargetX = x;
152175 eyeTargetY = y;
153- if (immediate)
176+ if (immediate)
154177 eyeMoveDuration = 0 ;
155178}
156179
157- // return the eyes to normal random movement
158- void eyesNormal () {
159- moveEyesRandomly = true ;
160- }
161-
162180
163181// SETUP FUNCTION - CALLED ONCE AT PROGRAM START ---------------------------
164182
165183void setup () {
184+ Serial.println (" SETUP BEGINS" );
185+
166186 if (!arcada.arcadaBegin ()) fatal (" Arcada init fail!" , 100 );
167187#if defined(USE_TINYUSB)
168188 if (!arcada.filesysBeginMSD ()) fatal (" No filesystem found!" , 250 );
@@ -214,10 +234,10 @@ void setup() {
214234 #endif
215235
216236 yield ();
217- if (showSplashScreen) {
218- if (arcada.drawBMP ((char *)" /splash.bmp" , 0 , 0 , (eye[0 ].display )) == IMAGE_SUCCESS) {
237+ if (showSplashScreen) {
238+ if (arcada.drawBMP ((char *)" /splash.bmp" , 0 , 0 , (eye[0 ].display )) == IMAGE_SUCCESS) {
219239 Serial.println (" Splashing" );
220- if (NUM_EYES > 1 ) { // other eye
240+ if (NUM_EYES > 1 ) { // other eye
221241 yield ();
222242 arcada.drawBMP ((char *)" /splash.bmp" , 0 , 0 , (eye[1 ].display ));
223243 }
@@ -448,10 +468,11 @@ void setup() {
448468 }
449469
450470 lastLightReadTime = micros () + 2000000 ; // Delay initial light reading
471+
472+ Serial.println (" END OF SETUP" );
451473}
452474
453475
454-
455476// LOOP FUNCTION - CALLED REPEATEDLY UNTIL POWER-OFF -----------------------
456477
457478/*
@@ -502,29 +523,29 @@ void loop() {
502523 // Eye movement
503524 int32_t dt = t - eyeMoveStartTime; // uS elapsed since last eye event
504525 if (eyeInMotion) { // Currently moving?
505- if (dt >= eyeMoveDuration) { // Time up? Destination reached.
506- eyeInMotion = false ; // Stop moving
507- if (moveEyesRandomly) {
508- eyeMoveDuration = random (10000 , 3000000 ); // 0.01-3 sec stop
509- eyeMoveStartTime = t; // Save initial time of stop
526+ if (dt >= eyeMoveDuration) { // Time up? Destination reached.
527+ eyeInMotion = false ; // Stop moving
528+ if (moveEyesRandomly) {
529+ eyeMoveDuration = random (10000 , 3000000 ); // 0.01-3 sec stop
530+ eyeMoveStartTime = t; // Save initial time of stop
510531 }
511532 eyeX = eyeOldX = eyeNewX; // Save position
512533 eyeY = eyeOldY = eyeNewY;
513534 } else { // Move time's not yet fully elapsed -- interpolate position
514535 float e = (float )dt / float (eyeMoveDuration); // 0.0 to 1.0 during move
515536 e = 3 * e * e - 2 * e * e * e; // Easing function: 3*e^2-2*e^3 0.0 to 1.0
516- eyeX = eyeOldX + (eyeNewX - eyeOldX) * e; // Interp X
517- eyeY = eyeOldY + (eyeNewY - eyeOldY) * e; // and Y
537+ eyeX = eyeOldX + (eyeNewX - eyeOldX) * e; // Interp X
538+ eyeY = eyeOldY + (eyeNewY - eyeOldY) * e; // and Y
518539 }
519- } else { // Eye stopped
540+ } else { // Eye stopped
520541 eyeX = eyeOldX;
521542 eyeY = eyeOldY;
522- if (dt > eyeMoveDuration) { // Time up? Begin new move.
543+ if (dt > eyeMoveDuration) { // Time up? Begin new move.
523544 // r is the radius in X and Y that the eye can go, from (0,0) in the center.
524545 float r = (float )mapDiameter - (float )DISPLAY_SIZE * M_PI_2; // radius of motion
525546 r *= 0.6 ; // calibration constant
526547
527- if (moveEyesRandomly) {
548+ if (moveEyesRandomly) {
528549 eyeNewX = random (-r, r);
529550 float h = sqrt (r * r - x * x);
530551 eyeNewY = random (-h, h);
@@ -537,9 +558,9 @@ void loop() {
537558 eyeNewY += mapRadius;
538559
539560 // Set the duration for this move, and start it going.
540- eyeMoveDuration = random (83000 , 166000 ); // ~1/12 - ~1/6 sec
541- eyeMoveStartTime = t; // Save initial time of move
542- eyeInMotion = true ; // Start move on next frame
561+ eyeMoveDuration = random (83000 , 166000 ); // ~1/12 - ~1/6 sec
562+ eyeMoveStartTime = t; // Save initial time of move
563+ eyeInMotion = true ; // Start move on next frame
543564 }
544565 }
545566
@@ -581,24 +602,31 @@ void loop() {
581602 iy = (int )map2screen (mapRadius - eye[eyeNum].eyeY ) + (DISPLAY_SIZE/2 ); // on screen
582603 iy += irisRadius * trackFactor;
583604 if (eyeNum & 1 ) ix = DISPLAY_SIZE - 1 - ix; // Flip for right eye
584- if (iy > upperOpen[ix] ) {
605+ if (eyelidsWide ) {
585606 uq = 1.0 ;
586- } else if (iy < upperClosed[ix]) {
587- uq = 0.0 ;
588- } else {
589- uq = (float )(iy - upperClosed[ix]) / (float )(upperOpen[ix] - upperClosed[ix]);
590- }
591- if (booped) {
607+ lq = 1.0 ;
608+ } else if (booped) {
592609 uq = 0.9 ;
593610 lq = 0.7 ;
594611 } else {
612+ if (iy > upperOpen[ix]) {
613+ uq = 1.0 ;
614+ } else if (iy < upperClosed[ix]) {
615+ uq = 0.0 ;
616+ } else {
617+ uq = (float )(iy - upperClosed[ix]) / (float )(upperOpen[ix] - upperClosed[ix]);
618+ }
595619 lq = 1.0 - uq;
596620 }
597621 } else {
598622 // If no tracking, eye is FULLY OPEN when not blinking
599623 uq = 1.0 ;
600624 lq = 1.0 ;
601625 }
626+ if (eyelidsClosed) {
627+ uq = 0.0 ;
628+ lq = 0.0 ;
629+ }
602630 // Dampen eyelid movements slightly
603631 // SAVE upper & lower lid factors per eye,
604632 // they need to stay consistent across frame
@@ -629,13 +657,14 @@ void loop() {
629657 // of both screens is about 1/2 this.
630658 frames++;
631659 if (((t - lastFrameRateReportTime) >= 1000000 ) && t) { // Once per sec.
632- Serial.println ( (frames * 1000 ) / (t / 1000 ));
660+ Serial.printf ( " Frame rate: %d \n " , (frames * 1000 ) / (t / 1000 ));
633661 lastFrameRateReportTime = t;
634662 }
635663
636664 // Once per frame (of eye #0), reset boopSum...
637665 if ((eyeNum == 0 ) && (boopPin >= 0 )) {
638666 boopSumFiltered = ((boopSumFiltered * 3 ) + boopSum) / 4 ;
667+ // Serial.printf("boopSum: %d, boopSumFiltered: %d, boopThreshold: %d, booped: %s\n", boopSum, boopSumFiltered, boopThreshold, (booped ? "true" : "false"));
639668 if (boopSumFiltered > boopThreshold) {
640669 if (!booped) {
641670 Serial.println (" BOOP!" );
@@ -647,6 +676,12 @@ void loop() {
647676 boopSum = 0 ;
648677 }
649678
679+ // Once per frame (of eye #1), reset eyelid states...
680+ if (eyeNum == 1 ) {
681+ eyelidsClosed = false ;
682+ eyelidsWide = false ;
683+ }
684+
650685 float mins = (float )millis () / 60000.0 ;
651686 if (eye[eyeNum].iris .iSpin ) {
652687 // Spin works in fixed amount per frame (eyes may lose sync, but "wagon wheel" tricks work)
0 commit comments