micropython — גישה ושליטה ברכיבים הפנימיים של MicroPython#

פונקציות#

micropython.const(expr: int) int#

משמש כדי להצהיר שהביטוי הוא קבוע כך שהמהדר יכול לבצע לו אופטימיזציה. השימוש בפונקציה זו צריך להיות כדלקמן:

from micropython import const

CONST_X = const(123)
CONST_Y = const(2 * CONST_X + 1)

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

פונקציית const זו מזוהה ישירות על ידי המנתח של MicroPython ומסופקת כחלק מהמודול micropython בעיקר כדי שניתן יהיה לכתוב סקריפטים שרצים גם תחת CPython וגם תחת MicroPython, על ידי מעקב אחר התבנית שלעיל.

micropython.opt_level(level: int | None = None) int | None#

אם level ניתן אז פונקציה זו מגדירה את רמת האופטימיזציה להידור עתידי של סקריפטים, ומחזירה None. אחרת היא מחזירה את רמת האופטימיזציה הנוכחית.

רמת האופטימיזציה שולטת על תכונות ההידור הבאות:

  • טענות (Assertions): ברמה 0 משפטי טענה מאופשרים ומהודרים אל הbytecode; ברמות 1 ומעלה טענות אינן מהודרות.

  • המשתנה המובנה __debug__: ברמה 0 משתנה זה מתרחב ל-True; ברמות 1 ומעלה הוא מתרחב ל-False.

  • מספרי שורות בקוד המקור: ברמות 0, 1 ו-2 מספרי שורות הקוד נשמרים יחד עם הbytecode כך שחריגות יכולות לדווח על מספר השורה שבה הן התרחשו; ברמות 3 ומעלה מספרי שורות אינם נשמרים.

רמת האופטימיזציה המוגדרת כברירת מחדל היא בדרך כלל רמה 0.

micropython.alloc_emergency_exception_buf(size: int) None#

הקצו size בתים של RAM עבור חוצץ חריגות החירום (גודל טוב הוא בסביבות 100 בתים). החוצץ משמש ליצירת חריגות במקרים שבהם הקצאת RAM רגילה הייתה נכשלת (למשל בתוך מטפל פסיקה) ובכך לספק מידע traceback שימושי במצבים אלה.

דרך טובה להשתמש בפונקציה זו היא למקם אותה בתחילת הסקריפט הראשי שלכם (למשל boot.py או main.py) ואז חוצץ חריגות החירום יהיה פעיל עבור כל הקוד שאחריו.

micropython.mem_info(verbose: Any | None = None) None#

הדפיסו מידע על הזיכרון שבשימוש כעת. אם הארגומנט verbose ניתן אז מידע נוסף מודפס.

המידע שמודפס תלוי במימוש, אך כעת כולל את כמות המחסנית (stack) והערמה (heap) שבשימוש. במצב verbose הוא מדפיס את כל הערמה תוך ציון אילו בלוקים בשימוש ואילו פנויים.

micropython.qstr_info(verbose: Any | None = None) None#

הדפיסו מידע על מחרוזות מועצמות (interned) שבשימוש כעת. אם הארגומנט verbose ניתן אז מידע נוסף מודפס.

המידע שמודפס תלוי במימוש, אך כעת כולל את מספר המחרוזות המועצמות וכמות ה-RAM שהן משתמשות בה. במצב verbose הוא מדפיס את שמות כל המחרוזות המועצמות ב-RAM.

micropython.stack_use() int#

החזירו מספר שלם המייצג את כמות המחסנית (stack) שבשימוש כעת. הערך המוחלט של זה אינו שימושי במיוחד, אלא יש להשתמש בו לחישוב הפרשים בשימוש המחסנית בנקודות שונות.

micropython.heap_lock() None#

נעלו את הערמה (heap). בעוד שהיא נעולה, לא יכולה להתרחש הקצאת זיכרון ו-MemoryError יועלה אם יבוצע ניסיון להקצאת ערמה כלשהי.

נעילות מקוננות: קריאה ל-heap_lock() מספר פעמים מגדילה את עומק הנעילה. הערמה נשארת נעולה עד ש-heap_unlock() נקראה אותו מספר פעמים.

אם ה-REPL הופך לפעיל בעוד שהערמה נעולה אז היא תיפתח בכוח.

micropython.heap_unlock() int#

הפחיתו את עומק נעילת הערמה באחד והחזירו את העומק החדש כמספר שלם אי-שלילי. ערך החזרה של 0 משמעו שהערמה אינה נעולה עוד והקצאות מותרות שוב.

micropython.heap_locked() int#

החזירו את עומק נעילת הערמה הנוכחי כמספר שלם אי-שלילי; 0 משמעו שהערמה אינה נעולה.

הערה: פונקציה זו אינה זמינה ב-OpenMV Cam.

micropython.kbd_intr(chr: int) None#

הגדירו את התו שיעלה חריגת KeyboardInterrupt. כברירת מחדל זה מוגדר ל-3 במהלך ביצוע הסקריפט, התואם ל-Ctrl-C. העברת -1 לפונקציה זו תשבית את לכידת Ctrl-C, והעברת 3 תשחזר אותה.

פונקציה זו יכולה לשמש למניעת לכידת Ctrl-C על הזרם הנכנס של תווים שמשמש בדרך כלל עבור ה-REPL, במקרה שהזרם הזה משמש למטרות אחרות.

micropython.schedule(func: Callable[[Any], Any], arg: Any) None#

תזמנו את הפונקציה func להתבצע ”בקרוב מאוד“. לפונקציה מועבר הערך arg כארגומנט היחיד שלה. ”בקרוב מאוד“ משמעו ש-MicroPython runtime יעשה כמיטב יכולתו לבצע את הפונקציה בזמן המוקדם ביותר האפשרי, בהינתן שהוא גם מנסה להיות יעיל, ושהתנאים הבאים מתקיימים:

  • פונקציה מתוזמנת לעולם לא תקדים (preempt) פונקציה מתוזמנת אחרת.

  • פונקציות מתוזמנות מתבצעות תמיד ”בין opcodes“ מה שאומר שכל פעולות Python הבסיסיות (כגון הוספה לרשימה) מובטחות להיות אטומיות.

  • port נתון עשוי להגדיר ”אזורים קריטיים“ שבתוכם פונקציות מתוזמנות לעולם לא יתבצעו. ניתן לתזמן פונקציות בתוך אזור קריטי אך הן לא יתבצעו עד שיוצאים מאזור זה. דוגמה לאזור קריטי היא מטפל פסיקה מקדים (IRQ).

  • בתוך פונקציות קוד מקורי (native), פונקציות מתוזמנות אינן נקראות אלא אם הקוד המקורי קורא לפונקציה שעושה זאת באופן ספציפי.

  • פונקציות מסוימות כולל poll.poll, poll.ipoll, time.sleep ו-time.sleep_ms (כולל שינה באורך אפס) יקראו לפונקציות מתוזמנות.

שימוש לפונקציה זו הוא לתזמן פונקציית callback מ-IRQ מקדים. IRQ כזה מטיל מגבלות על הקוד שרץ ב-IRQ (למשל הערמה עשויה להיות נעולה) ותזמון פונקציה לקרוא מאוחר יותר יסיר את המגבלות הללו.

ב-ports מרובי-תהליכונים, התנהגות הפונקציה המתוזמנת תלויה בשאלה האם ה-Global Interpreter Lock (GIL) מאופשר עבור ה-port הספציפי:

  • אם GIL מאופשר, הפונקציה יכולה להקדים כל תהליכון ולרוץ בהקשר שלו.

  • אם GIL מושבת, הפונקציה תקדים רק את התהליכון הראשי ותרוץ בהקשר שלו.

הערה: אם schedule() נקראת מ-IRQ מקדים, כאשר הקצאת זיכרון אינה מותרת וה-callback שיועבר ל-schedule() הוא מתודה כבולה (bound method), העברתו ישירות תיכשל. הסיבה לכך היא שיצירת הפניה למתודה כבולה גורמת להקצאת זיכרון. פתרון הוא ליצור הפניה למתודה בבנאי המחלקה ולהעביר את ההפניה הזו ל-schedule(). הדבר נדון בפירוט כאן reference documentation תחת ”Creation of Python objects“.

קיימת תור סופי להחזקת הפונקציות המתוזמנות ו-schedule() תעלה RuntimeError אם התור מלא.

מחלקות#

class micropython.RingIO(size: int)#
class micropython.RingIO(buffer: bytes | bytearray | memoryview)

מספק ringbuffer בגודל קבוע עבור בתים עם ממשק זרם (stream). ניתן להתייחס אליו כווריאנט תור-FIFO של io.BytesIO. שתי צורות הבנאי נבדלות רק באופן שבו החוצץ המגבה מסופק:

  • RingIO(size) מקצה את החוצץ המגבה באופן פנימי. אלגוריתם ה-ringbuffer הקלאסי שומר בית אחד למעקב, כך שהחוצץ המוקצה גדול בבית אחד מ-size והמופע יכול להחזיק את מלוא size הבתים של נתונים. לדוגמה, RingIO(16) מקצה חוצץ בגודל 17 בתים ומחזיק 16 בתים של נתונים.

  • RingIO(buffer) משתמש ב-buffer שסופק במקומו במקום להקצות אחד. מכיוון שבית אחד שמור למעקב, המופע יכול להחזיק len(buffer) - 1 בתים של נתונים. לדוגמה, RingIO(bytearray(16)) מחזיק 15 בתים של נתונים.

מופע RingIO הוא בטוח לשימוש מ-IRQ/תהליכונים כאשר משמש להעברת נתונים בכיוון יחיד (למשל נכתב אליו מ-IRQ ונקרא מפונקציה שאינה IRQ, או להפך). זה אינו תקף אם מופע יחיד נכתב אליו הן מהקשרי IRQ והן מהקשרים שאינם IRQ, מה שלעתים קרובות יגרום לשחיתות נתונים.

any() int#

מחזיר מספר שלם הסופר את מספר התווים שניתן לקרוא.

read(nbytes: int | None = None) bytes#

קראו את התווים הזמינים. זו פונקציה לא-חוסמת. אם nbytes מצוין אז קראו לכל היותר מספר זה של בתים, אחרת קראו כמה שיותר נתונים.

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

readline(nbytes: int | None = None) bytes#

קראו שורה, המסתיימת בתו שורה חדשה או return אם קיים כזה בחוצץ, אחרת החזירו את הבתים הזמינים בחוצץ. אם nbytes מצוין אז קראו לכל היותר מספר זה של בתים.

ערך החזרה: אובייקט bytes המכיל את השורה שנקראה.

readinto(buf: bytearray | memoryview, nbytes: int | None = None) int#

קראו את הבתים הזמינים אל ה-buf שסופק. אם nbytes מצוין אז קראו לכל היותר מספר זה של בתים. אחרת, קראו לכל היותר len(buf) בתים.

ערך החזרה: ספירת מספר שלם של מספר הבתים שנקראו אל buf.

write(buf: bytes | bytearray | memoryview) int#

כתיבה לא-חוסמת של בתים מ-buf אל ה-ringbuffer, מוגבלת על ידי המקום הזמין ב-ringbuffer.

ערך החזרה: ספירת מספר שלם של בתים שנכתבו.

close() None#

פעולת ריק (No-op) המסופקת כחלק מממשק stream הסטנדרטי. אין לה השפעה על נתונים ב-ringbuffer.