14.3.2. כלב השמירה (watchdog)¶
כלב השמירה (watchdog) החומרתי הוא הרצפה שעליה יושבת כל בחירת הקשחה אחרת. הוא טיימר עצמאי זעיר שמאפס את המעבד כאשר לא נאמר לו אחרת זמן רב מדי. סקריפט שנתקע על חיישן לא-יציב, קריאת רשת שחוסמת מעבר לתום-הזמן שלה, מקצה-זיכרון תקוע בפינה של הערמה, חריגה שנמלטה מהלולאה – אף אחד מהם לא עוצר את כלב השמירה (watchdog). הטיימר סופר לאחור ללא קשר, והמצלמה מאתחלת מחדש.
עבור מוצר נשלח, כלב שמירה (watchdog) אינו אופציונלי. בלעדיו, כל אחד ממצבי הכשל לעיל משאיר את המצלמה מתה עד שמישהו שם לב ומבצע לה מחזור-חשמל. איתו, המצלמה חוזרת לפעולה בעצמה והעדות היחידה לכשל היא שורה אחת ביומן.
ראה גם
עמוד טיימר כלב השמירה בפרק החומרה מכסה מהו כלב שמירה (watchdog) ברמת החומרה ואת היסודות של ה-API של machine.WDT. עמוד זה מכסה מה משתנה עבור פריסת ייצור.
14.3.2.1. הפעלת כלב השמירה (watchdog)¶
machine.WDT הוא ה-API. הוא מגובה-חומרה: לאחר שנבנה, הטיימר רץ עד האיפוס הבא. אין stop(), אין deinit(), אין מילוט באמצעות Ctrl-C. זה כל העניין.
הגדרה טיפוסית בראש main.py, מיד לפני הלולאה שהוא מגן עליה:
from machine import WDT
wdt = WDT(timeout=10_000) # milliseconds
main.py הוא הבית הנכון לכלב השמירה (watchdog) משום ששם חיה הלולאה. איפוס כלב שמירה הוא איפוס חומרה, כך שנתיב האתחול-הקר רץ מחדש ו-main.py נכנס שוב ללולאה בעצמו – ההתאוששות עובדת ללא שום חיווט ב-boot.py. הפעלת כלב השמירה (watchdog) ב-boot.py במקום זאת פירושה שכל איפוס רך (Ctrl-D של מפתח, למשל) מוסר ליישום טיימר חומרה שאין לו דרך לעצור, מה שמהווה מטרד על השולחן ומלכודת בקוד הגדרת ייצור שרץ לפני שהלולאה מוכנה.
בחר את תום-הזמן להיות פי 2 עד פי 3 ארוך יותר מזמן האיטרציה הגרוע ביותר שנצפה של הלולאה הראשית. רעידות בקצב-הפריימים, קריאת חיישן איטית על חיישן קר, גמגום Wi-Fi קצר – אף אחד מאלה לא אמור להפעיל את כלב השמירה (watchdog). תקיעה אמיתית (לולאה אינסופית, קריאת I/O חסומה) כן אמורה. תומי-זמן קצרים-מדי הופכים את כלב השמירה למקור של איפוסים שגויים; תומי-זמן ארוכים-מדי מאפשרים למצלמה לשבת ללא מענה במשך דקות לפני שההתאוששות מופעלת.
14.3.2.2. האכלתו¶
wdt.feed() מאפס את הספירה-לאחור. קרא לו פעם אחת בכל איטרציה של הלולאה הראשית, בראש גוף הלולאה כך שההאכלה מתרחשת ללא תנאי לפני כל עבודה שעלולה להיתקע:
while True:
wdt.feed()
frame = csi0.snapshot()
process(frame)
14.3.2.3. שרידות חריגות¶
כלב השמירה (watchdog) מטפל בתקיעות. חריגות הן מצב כשל שונה. חריגה לא-מטופלת מבעבעת אל הרמה העליונה של הסקריפט, main.py יוצא, והמצלמה צונחת ל-REPL. כלב השמירה אז מופעל לאחר תום-הזמן שלו משום ששום דבר אינו מאכיל אותו מה-REPL, המצלמה מתאפסת, ו-main.py רץ שוב – כך שההתאוששות אכן עובדת, אבל השדה משלם תום-זמן-מלא-בתוספת-אתחול-מחדש עבור כל קריסה, ה-traceback הולך ל-USB stdout שאיש אינו קורא, וכל מצב בזיכרון שהיישום שמר נעלם.
עטיפת הלולאה הראשית ב-try / except ברמה-עליונה הופכת קריסה לאירוע מתועד שהיישום ממשיך דרכו, מבלי לשלם עבור איפוס:
import logging
log = logging.getLogger(__name__)
while True:
wdt.feed()
try:
frame = csi0.snapshot()
process(frame)
except Exception:
log.exception("frame loop iteration failed")
תפיסת Exception (לא BaseException) שומרת על KeyboardInterrupt ו-SystemExit עובדים, וזה מה שמפתח המחובר דרך USB רוצה.
תבנית זו היא החצי התוכנתי של חיוניות: כלב השמירה (watchdog) תופס את התקיעות, העוטף תופס את הקריסות, והיומן רושם את מה שאחד מהם תפס.
14.3.2.4. לדעת מדוע אתחול קרה¶
כל איפוס רך וכל איפוס כלב שמירה (watchdog) מופיע בסופו של דבר כאתחול חדש. עוזר האבחון בזמן-אתחול רושם את machine.reset_cause() בכל אתחול קר; השורה reset cause היא מה שמספר לשדה אם ההתאוששות אכן הופעלה לעומת המצלמה שפשוט מבצעת מחזור-חשמל רגיל.
שורת סיבת-האיפוס היא מה שהופך את עבודת כלב השמירה (watchdog) לנראית ביומן. יומן מלא באיפוסי watchdog timeout אומר שהיישום נתקע וכלב השמירה התאושש ממנו. יומן בלעדיהם אומר שכלב השמירה לא נאלץ להפעל – מה שבדרך כלל אומר שהיישום בריא, אבל יכול גם לומר שתום-הזמן מוגדר ארוך מדי כדי לתפוס את התקיעות שמתרחשות בפועל.
14.3.2.5. מתנע מלא¶
main.py שמושך יחד את כלב השמירה (watchdog), הגדרת רישום, אבחון בזמן-אתחול, והעוטף נראה כך:
import logging
from machine import WDT
from app.logging_setup import setup_logging, log_boot_diagnostics
setup_logging('/sdcard/logs/app.log')
log_boot_diagnostics()
log = logging.getLogger(__name__)
wdt = WDT(timeout=10_000)
while True:
wdt.feed()
try:
step()
except Exception:
log.exception("loop iteration failed")
step() היא עבודת היישום הפר-איטרציה; שאר הפיגום הזה אינו משתנה בין מוצרים. הקשחה היא כלב שמירה (watchdog) אחד, עוטף אחד, ואתחול מתועד בכל אתחול קר – לא הרבה קוד, וההבדל בין מצלמה שמתאוששת בעצמה לבין אחת שזקוקה לקריאת שירות.