הלוגיקה של כל מוצר משובץ היא מכונת מצבים — השאלה אם תכננתם אותה

כל מוצר משובץ עובר בין מצבים: כבוי, מתאתחל, ממתין, עובד, טוען, בתקלה. מכונת מצבים בקושחה היא הדרך ההנדסית לתת לזה מבנה — הגדרה מפורשת של המצבים, האירועים שמעבירים ביניהם והפעולות בכל מעבר. קושחה שנכתבת בלי המבנה הזה מגיעה תמיד לאותו מקום: סבך של דגלים בוליאניים ותנאים מקוננים שאף אחד כבר לא מעז לגעת בו, ובאגים מהסוג הגרוע — המוצר "נתקע במצב מוזר" שאיש לא מצליח לשחזר. במאמר הזה נעבור על שלוש דרכים לממש מכונת מצבים, ומתי כל אחת נכונה.

לפני שורת קוד אחת: דיאגרמת מצבים

מתחילים על הלוח, לא בעורך הקוד. מציירים עיגול לכל מצב, חץ לכל אירוע, ואז שואלים את שאלת הזהב על כל משבצת בטבלת מצבים×אירועים: מה קורה אם האירוע הזה מגיע במצב הזה? מה קורה אם לחצן ההפעלה נלחץ באמצע עדכון קושחה? מה קורה אם המטען מנותק בדיוק בזמן בדיקה עצמית? רוב הבאגים המביכים בשטח הם בדיוק המשבצות שאיש לא מילא. הדיאגרמה הזו היא גם שפה משותפת מצוינת עם הצד העסקי — אפשר לעבור עליה עם מנהל המוצר בלי לקרוא קוד. ליזמים שרוצים רקע כללי על עולם הקושחה — מומלץ להתחיל ממה זו קושחה.

מימוש 1: switch-case — הפשוט שעובד

המימוש המוכר: משתנה state ו-switch גדול בלולאה הראשית, עם case לכל מצב שבודק אירועים ומחליף מצב. בשביל מכונה של עד חמישה-שישה מצבים זה מימוש מצוין — קריא, קל לדיבוג, וכל מהנדס מבין אותו מיד. שני כללים שומרים עליו בריא: כל case חייב להסתיים מהר בלי המתנות חוסמות (delay בתוך מצב הורג את התגובתיות של כל המערכת), ואירועים מפסיקות לעולם לא מטופלים ישירות — הם נכנסים לתור אירועים והמכונה מטפלת בהם בהקשר הראשי, כמוסבר במאמר על פסיקות בקושחה. הבעיה מתחילה כשהמכונה גדלה: switch של חמש-עשרה מצבים עם לוגיקה בכל case הופך בדיוק לספגטי שניסינו למנוע.

מימוש 2: טבלת מעברים — כשהמכונה גדלה

בגישה טבלאית מפרידים את המבנה מהקוד: מגדירים מערך של רשומות מעבר — מצב נוכחי, אירוע, מצב יעד, פונקציית פעולה — ומנוע קטן וגנרי שרץ על הטבלה. היתרונות מצטברים מהר:

  • הלוגיקה גלויה במקום אחד. הטבלה היא תיעוד חי שמשקף אחד-לאחד את הדיאגרמה מהלוח — קל לסקור אותה מול האפיון ולמצוא מעברים חסרים.
  • הוספת מצב לא נוגעת בקיים. שורות חדשות בטבלה במקום עריכת switch ענק — פחות סיכוי לשבור מה שכבר עובד.
  • קל לבדיקה אוטומטית. מזינים למנוע רצפי אירועים ובודקים את מסלול המצבים — תשתית מצוינת לבדיקות אוטומטיות מול חומרה אמיתית.

מימוש 3: מכונה היררכית (HSM) — למוצרים מורכבים באמת

כשמצבים רבים חולקים התנהגות משותפת — למשל: מכל מצב עבודה, אירוע סוללה-חלשה עובר לטעינה — מכונה שטוחה מכריחה לשכפל את המעבר הזה בכל מצב. מכונת מצבים היררכית פותרת זאת עם מצבי-על: מצב "עובד" מכיל תתי-מצבים, ואירוע שלא טופל בתת-המצב מטפס למצב האב. מוסיפים לזה פעולות כניסה ויציאה לכל מצב — הדלקת חיישן בכניסה, כיבויו ביציאה — ומקבלים מבנה שמונע גם את באג ה"שכחתי לכבות" הקלאסי. זה הכלי הנכון למוצרים עם עשרות מצבים, והוא משתלב היטב גם בארכיטקטורות מבוססות RTOS, שבהן כל משימה מריצה מכונת מצבים משלה — על הבחירה הזו במאמר RTOS או Bare Metal.

שלושה כללים שחוצים את כל המימושים

  • מצב תקלה הוא מצב מתוכנן. לכל מכונה צריך מצב FAULT מוגדר עם דרך כניסה ברורה ודרך יציאה בטוחה — לא קריסה אקראית. יחד עם Watchdog ומנגנוני התאוששות זה מה שמבדיל מוצר שמחזיק בשטח ממוצר שחוזר במשלוחים.
  • המצב נשמר במקום אחד. ברגע שדגלים בוליאניים מפוזרים מתחילים לייצג "תת-מצבים" לא רשמיים — המכונה כבר לא משקפת את המציאות.
  • מצבי שינה הם חלק מהמכונה. כניסה ויציאה משינה הן מעברים לכל דבר, עם פעולות כניסה ויציאה מסודרות — ראו מצבי שינה במיקרו-בקר.

מכונת מצבים מתוכננת היטב היא ההשקעה עם התשואה הגבוהה ביותר בפרויקט קושחה: היא הופכת את לוגיקת המוצר ממשהו שמתגלה בדיעבד למשהו שמתוכנן מראש. מוזמנים להעמיק בעוד נושאי ליבה באשכול פיתוח תוכנה embedded — או לדבר איתנו כשלוגיקת המוצר שלכם מתחילה להסתבך.

רוצים להפוך רעיון למוצר? צרו קשר עם צוות פרוג'קטס האוס בע"מ – טלפון: 054-8936922 | דוא"ל: info@projects-house.com – ונשמח ללוות אתכם משלב הרעיון ועד המדף.