micropython — dostęp do wewnętrznych mechanizmów MicroPython i ich kontrola

Funkcje

micropython.const(expr: int) int

Używane do zadeklarowania, że wyrażenie jest stałą, tak aby kompilator mógł je zoptymalizować. Tej funkcji należy używać w następujący sposób:

from micropython import const

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

Stałe zadeklarowane w ten sposób są nadal dostępne jako zmienne globalne spoza modułu, w którym je zadeklarowano. Z drugiej strony, jeśli stała zaczyna się od podkreślenia, jest ukryta, nie jest dostępna jako zmienna globalna i nie zajmuje żadnej pamięci podczas wykonywania.

Funkcja const jest rozpoznawana bezpośrednio przez parser MicroPython i jest udostępniana jako część modułu micropython głównie po to, aby można było pisać skrypty działające zarówno pod CPython, jak i MicroPython, stosując powyższy wzorzec.

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

Jeśli podano level, to funkcja ustawia poziom optymalizacji dla kolejnych kompilacji skryptów i zwraca None. W przeciwnym razie zwraca bieżący poziom optymalizacji.

Poziom optymalizacji steruje następującymi funkcjami kompilacji:

  • Asercje: na poziomie 0 instrukcje asercji są włączone i kompilowane do kodu bajtowego; na poziomach 1 i wyższych asercje nie są kompilowane.

  • Wbudowana zmienna __debug__: na poziomie 0 zmienna ta rozwija się do True; na poziomach 1 i wyższych rozwija się do False.

  • Numery wierszy kodu źródłowego: na poziomach 0, 1 i 2 numery wierszy kodu źródłowego są przechowywane wraz z kodem bajtowym, dzięki czemu wyjątki mogą zgłaszać numer wiersza, w którym wystąpiły; na poziomach 3 i wyższych numery wierszy nie są przechowywane.

Domyślny poziom optymalizacji to zazwyczaj poziom 0.

micropython.alloc_emergency_exception_buf(size: int) None

Przydziela size bajtów pamięci RAM dla awaryjnego bufora wyjątków (dobrym rozmiarem jest około 100 bajtów). Bufor jest używany do tworzenia wyjątków w sytuacjach, gdy normalny przydział pamięci RAM by się nie powiódł (np. wewnątrz procedury obsługi przerwania), i dzięki temu dostarcza w takich sytuacjach przydatnych informacji o śladzie wykonania.

Dobrym sposobem użycia tej funkcji jest umieszczenie jej na początku głównego skryptu (np. boot.py lub main.py) – wtedy awaryjny bufor wyjątków będzie aktywny dla całego następującego po nim kodu.

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

Wypisuje informacje o aktualnie wykorzystywanej pamięci. Jeśli podano argument verbose, wypisywane są dodatkowe informacje.

Wypisywane informacje zależą od implementacji, ale obecnie obejmują ilość użytego stosu i sterty. W trybie szczegółowym wypisywana jest cała sterta ze wskazaniem, które bloki są używane, a które wolne.

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

Wypisuje informacje o aktualnie internowanych łańcuchach znaków. Jeśli podano argument verbose, wypisywane są dodatkowe informacje.

Wypisywane informacje zależą od implementacji, ale obecnie obejmują liczbę internowanych łańcuchów znaków i ilość zajmowanej przez nie pamięci RAM. W trybie szczegółowym wypisywane są nazwy wszystkich łańcuchów internowanych w pamięci RAM.

micropython.stack_use() int

Zwraca liczbę całkowitą reprezentującą bieżącą ilość wykorzystywanego stosu. Wartość bezwzględna nie jest szczególnie użyteczna – raczej należy jej używać do obliczania różnic w wykorzystaniu stosu w różnych punktach.

micropython.heap_lock() None

Blokuje stertę. W stanie zablokowanym nie może nastąpić żaden przydział pamięci, a próba jakiegokolwiek przydziału na stercie spowoduje zgłoszenie MemoryError.

Blokady się zagnieżdżają: wielokrotne wywołanie heap_lock() zwiększa głębokość blokady. Sterta pozostaje zablokowana, dopóki heap_unlock() nie zostanie wywołane tę samą liczbę razy.

Jeśli REPL stanie się aktywny przy zablokowanej stercie, zostanie ona przymusowo odblokowana.

micropython.heap_unlock() int

Zmniejsza głębokość blokady sterty o jeden i zwraca nową głębokość jako nieujemną liczbę całkowitą. Wartość zwracana 0 oznacza, że sterta nie jest już zablokowana, a przydziały są ponownie dozwolone.

micropython.heap_locked() int

Zwraca bieżącą głębokość blokady sterty jako nieujemną liczbę całkowitą; 0 oznacza, że sterta nie jest zablokowana.

Uwaga: ta funkcja nie jest dostępna na OpenMV Cam.

micropython.kbd_intr(chr: int) None

Ustawia znak, który będzie zgłaszał wyjątek KeyboardInterrupt. Domyślnie podczas wykonywania skryptu jest to ustawione na 3, co odpowiada Ctrl-C. Przekazanie do tej funkcji -1 wyłączy przechwytywanie Ctrl-C, a przekazanie 3 przywróci je.

Tej funkcji można użyć, aby zapobiec przechwytywaniu Ctrl-C w przychodzącym strumieniu znaków zwykle używanym dla REPL, na wypadek gdyby ten strumień był używany do innych celów.

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

Planuje wykonanie funkcji func „już wkrótce”. Funkcji przekazywana jest wartość arg jako jej jedyny argument. „Już wkrótce” oznacza, że środowisko uruchomieniowe MicroPython dołoży wszelkich starań, aby wykonać funkcję jak najwcześniej, biorąc pod uwagę, że stara się ono również być wydajne oraz że spełnione są następujące warunki:

  • Zaplanowana funkcja nigdy nie wywłaszczy innej zaplanowanej funkcji.

  • Zaplanowane funkcje są zawsze wykonywane „pomiędzy opcode’ami”, co oznacza, że wszystkie podstawowe operacje Pythona (takie jak dołączanie do listy) są gwarantowanie atomowe.

  • Dany port może definiować „obszary krytyczne”, w obrębie których zaplanowane funkcje nigdy nie będą wykonywane. Funkcje mogą być planowane w obszarze krytycznym, ale nie zostaną wykonane, dopóki ten obszar nie zostanie opuszczony. Przykładem obszaru krytycznego jest wywłaszczająca procedura obsługi przerwania (IRQ).

  • Wewnątrz funkcji natywnego kodu zaplanowane funkcje nie są wywoływane, chyba że natywny kod wywoła funkcję, która konkretnie to robi.

  • Niektóre funkcje, w tym poll.poll, poll.ipoll, time.sleep oraz time.sleep_ms (w tym sleepy o zerowym czasie trwania), wywołają zaplanowane funkcje.

Zastosowaniem tej funkcji jest zaplanowanie wywołania zwrotnego z wywłaszczającego IRQ. Taki IRQ nakłada ograniczenia na kod uruchamiany w IRQ (na przykład sterta może być zablokowana), a zaplanowanie funkcji do późniejszego wywołania zniesie te ograniczenia.

Na portach wielowątkowych zachowanie zaplanowanej funkcji zależy od tego, czy dla danego portu włączona jest globalna blokada interpretera (GIL):

  • Jeśli GIL jest włączony, funkcja może wywłaszczyć dowolny wątek i działać w jego kontekście.

  • Jeśli GIL jest wyłączony, funkcja wywłaszczy tylko wątek główny i będzie działać w jego kontekście.

Uwaga: Jeśli schedule() jest wywoływane z wywłaszczającego IRQ, gdy przydział pamięci nie jest dozwolony, a wywołanie zwrotne przekazywane do schedule() jest metodą związaną, przekazanie jej bezpośrednio się nie powiedzie. Dzieje się tak, ponieważ utworzenie referencji do metody związanej powoduje przydział pamięci. Rozwiązaniem jest utworzenie referencji do metody w konstruktorze klasy i przekazanie tej referencji do schedule(). Jest to szczegółowo omówione tutaj reference documentation w sekcji „Creation of Python objects”.

Istnieje skończona kolejka do przechowywania zaplanowanych funkcji i schedule() zgłosi RuntimeError, jeśli kolejka jest pełna.

Klasy

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

Zapewnia bufor pierścieniowy o stałym rozmiarze dla bajtów z interfejsem strumienia. Można go traktować jako wariant kolejki FIFO klasy io.BytesIO. Dwie formy konstruktora różnią się jedynie sposobem dostarczenia bufora bazowego:

  • RingIO(size) przydziela bufor bazowy wewnętrznie. Klasyczny algorytm bufora pierścieniowego rezerwuje jeden bajt do śledzenia, więc przydzielony bufor jest o jeden bajt większy niż size, a instancja może pomieścić pełne size bajtów danych. Na przykład RingIO(16) przydziela 17-bajtowy bufor i mieści 16 bajtów danych.

  • RingIO(buffer) używa dostarczonego buffer w miejscu, zamiast przydzielać nowy. Ponieważ jeden bajt jest zarezerwowany do śledzenia, instancja może pomieścić len(buffer) - 1 bajtów danych. Na przykład RingIO(bytearray(16)) mieści 15 bajtów danych.

Instancja RingIO jest bezpieczna dla IRQ/wątków, gdy jest używana do przekazywania danych w jednym kierunku (na przykład zapisywana z IRQ i odczytywana z funkcji spoza IRQ, lub odwrotnie). Nie obowiązuje to, jeśli pojedyncza instancja jest zapisywana zarówno z kontekstu IRQ, jak i spoza IRQ, co często powodowałoby uszkodzenie danych.

any() int

Zwraca liczbę całkowitą zliczającą liczbę znaków, które można odczytać.

read(nbytes: int | None = None) bytes

Odczytuje dostępne znaki. Jest to funkcja nieblokująca. Jeśli określono nbytes, to odczytuje co najwyżej tyle bajtów, w przeciwnym razie odczytuje jak najwięcej danych.

Wartość zwracana: obiekt bytes zawierający odczytane bajty. Będzie obiektem bytes o zerowej długości, jeśli żadne dane nie są dostępne.

readline(nbytes: int | None = None) bytes

Odczytuje wiersz zakończony znakiem nowego wiersza lub powrotu karetki, jeśli taki istnieje w buforze, w przeciwnym razie zwraca dostępne bajty z bufora. Jeśli określono nbytes, to odczytuje co najwyżej tyle bajtów.

Wartość zwracana: obiekt bytes zawierający odczytany wiersz.

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

Odczytuje dostępne bajty do dostarczonego buf. Jeśli określono nbytes, to odczytuje co najwyżej tyle bajtów. W przeciwnym razie odczytuje co najwyżej len(buf) bajtów.

Wartość zwracana: liczba całkowita zliczająca liczbę bajtów odczytanych do buf.

write(buf: bytes | bytearray | memoryview) int

Nieblokujący zapis bajtów z buf do bufora pierścieniowego, ograniczony dostępnym miejscem w buforze pierścieniowym.

Wartość zwracana: liczba całkowita zliczająca zapisane bajty.

close() None

Operacja pusta (no-op) udostępniana jako część standardowego interfejsu stream. Nie ma wpływu na dane w buforze pierścieniowym.