#include <Stepper.h>

// ===========================================
//          אזור הגדרות משתמש
// ===========================================

// --- הגדרות חומרה ---
// פינים של מנוע הצעד
#define IN1 8
#define IN2 9
#define IN3 10
#define IN4 11

// מספר הצעדים לסיבוב מלא של המנוע (כולל הגיר)
// עבור 28BYJ-48 זה בדרך כלל 2048
const int STEPS_PER_REV = 2048;

// --- הגדרות מכאניות (ניתן לשנות בקלות) ---
// מספר החוליות בשרשרת
const float CHAIN_LINKS = 94.0;

// מספר השיניים בגלגל השיניים (Sprocket)
const float SPROCKET_TEETH = 7.0;

// --- הגדרות תזמון ---
// משך הזמן הרצוי לסיבוב מלא של השרשרת (בשעות)
const unsigned long TARGET_HOURS = 12;


// ===========================================
//          חישובים אוטומטיים
// ===========================================

// 1. חישוב מספר סיבובי גלגל השיניים הנדרשים לסיבוב שרשרת מלא
// (כל שן מזיזה חוליה אחת, לכן זה היחס ביניהם)
const double SPROCKET_REVS_PER_CHAIN_REV = (double)CHAIN_LINKS / SPROCKET_TEETH;

// 2. חישוב סך הצעדים (כולל שבר עשרוני) הנדרשים לסיבוב שרשרת מלא
const double TOTAL_STEPS_FLOAT = STEPS_PER_REV * SPROCKET_REVS_PER_CHAIN_REV;

// 3. חישוב משך הזמן הכולל במילישניות
// (שימוש ב-UL כדי למנוע גלישה של מספר שלם בחישוב)
const unsigned long PERIOD_MS = TARGET_HOURS * 3600UL * 1000UL;

// 4. חישוב זמן ההמתנה הממוצע המדויק (עם שבר עשרוני) בין כל צעד
const double AVG_INTERVAL_MS = (double)PERIOD_MS / TOTAL_STEPS_FLOAT;

// 5. פיצול זמן ההמתנה לחלק שלם ולשארית עשרונית
// זהו זמן ההמתנה הבסיסי (החלק השלם)
const unsigned long BASE_INTERVAL = (unsigned long)AVG_INTERVAL_MS;

// זוהי השארית העשרונית שנוסיף לצבירה בכל פעם
const double INTERVAL_REMAINDER = AVG_INTERVAL_MS - BASE_INTERVAL;


// ===========================================
//           משתנים גלובליים
// ===========================================

// יצירת אובייקט המנוע
// סדר הפינים (IN1, IN3, IN2, IN4) הוא הסדר הנכון עבור ספריית Stepper.h
Stepper motor(STEPS_PER_REV, IN1, IN3, IN2, IN4);

// משתנה לצבירת שאריות הזמן העשרוניות
double remainderAccumulator = 0.0;


// ===========================================
//              פונקציות תוכנה
// ===========================================

void setup() {
  // אין צורך להגדיר מהירות, אנו שולטים בכל צעד באופן ידני
}

void loop() {
  // 1. בצע תמיד צעד אחד בכיוון הרצוי (למשל: נגד כיוון השעון)
  motor.step(-1);

  // 2. קבע את זמן ההמתנה הנוכחי לערך הבסיסי (החלק השלם)
  unsigned long currentDelay = BASE_INTERVAL;

  // 3. הוסף את שארית הזמן העשרונית לצבירה
  remainderAccumulator += INTERVAL_REMAINDER;

  // 4. בדוק אם צברנו מספיק "חלקיקי זמן" כדי להוסיף מילישנייה שלמה
  if (remainderAccumulator >= 1.0) {
    // אם כן, הוסף מילישנייה אחת להמתנה הנוכחית
    currentDelay += 1;
    // והפחת את המילישנייה ש"בזבזנו" מהצבירה
    remainderAccumulator -= 1.0;
  }

  // 5. המתן את הזמן המדויק שחושב (הבסיסי, או הבסיסי + 1)
  delay(currentDelay);
}