Bufor kołowy #2: implementacja

Implementacja bufora kołowego w c

W tej części zajmiemy się implementacją bufora kołowego w języku c. Jak wspomniałem w poprzednim artykule, do wydzielenia obszaru pamięci na potrzeby bufora wykorzystamy tablicę. Będzie to bardzo wygodne, ponieważ tablica zajmuje ciągły obszar w pamięci.

Struktura bufora kołowego

Typ zmiennej tablicowej możesz dobrać według swoich potrzeb, ja zdecydował się na jednobajtowy typ char. Podobnie jest z ilością elementów tablicy. Musisz dobrać odpowiednią wielkość, w zależności od tego, jaką ilość danych i z jaką częstotliwością będziesz chciał do niej zapisywać – tak, aby nadążać z ich odczytem i przetwarzaniem.

Jak już wiesz, potrzebne są nam jeszcze dwie zmienne do przechowywania indeksów head i tail. W celu zapewnienia przejrzystości kodu wszystkie niezbędne elementy do prawidłowego działania bufora ubierzemy w strukturę i utworzymy specjalny typ strukturalny.

Jak widzisz, oprócz znanych już Tobie zmiennych head, tail pojawiła się jeszcze jedna zmienna – zmienna wskaźnikowa. Podczas pisania programów, możliwe, że będziesz potrzebował więcej niż jednego bufora, a każdy z nich będzie potrzebował oddzielnej tablicy i dlatego potrzebujemy tej zmiennej. Posłuży ona do przechowywania adresu danej tablicy, aby móc do niej dopisywać i odczytywać z niej wartości. Słowo const informuje kompilator, aby ten nie pozwolił nam przez nieuwagę zmienić przechowywanego adresu tablicy, ponieważ w tym wypadku byłoby to bardzo niepożądane – moglibyśmy np. nadpisać jakieś inne dane. Przy takim zapisie stały jest wskaźnik, ale wartości w komórkach pamięci na które wskazuje mogą być zmieniane. Poniżej deklaracja bufora wraz z inicjacją: podajemy adres tablicy, a pozostałym zmiennym przypisujemy wartość 0.

Pozostało już tylko napisać dwie funkcje: jedną do dodawania danych do bufora, drugą do odczytywania danych z bufora. Jeśli dokładnie przeczytałeś poprzedni artykuł nie powinieneś mieć najmniejszego problemu z ich zrozumieniem. Przy każdej linii kody dodam komentarz, aby nie było żadnych wątpliwości 🙂

Wpisywanie danych do bufora

Jak sama nazwa wskazuje, funkcja służy do dodawania znaku do bufora kołowego. Jako argumenty przyjmuje wskaźnik do utworzonej struktury oraz wartość, którą chcemy do niej dodać i zwraca wartość typu int8_t – może nią być 0, jeśli dodawanie elementu przebiegło pomyślnie lub -1, jeśli bufor jest pełny. W tym przypadku nie zdecydowałem się na nadpisywanie danych, ani oczekiwanie na zwolnienie miejsca w buforze. W razie potrzeby możesz to łatwo zmienić. Poniżej ciało funkcji:

Odczytywanie danych z bufora

Jak można się domyślić, ta funkcja służy do pobierania danych z bufora. Funkcja, podobnie jak poprzednia, zwraca 0, jeśli pobieranie przebiegło pomyślnie lub -1, jeśli wystąpił błąd – bufor jest pusty. Jako argumenty przyjmuje wskaźnik do utworzonej struktury oraz wskaźnik do zmiennej, do której chcemy zapisać odczytaną wartość.

Podsumowanie

Mam nadzieję, że jesteś miło zaskoczony prostotą tego kodu. Jeżeli pracujesz w środowisku wielowątkowym to należy jeszcze pamiętać o zapewnieniu atomowości operacji zapisu i odczytu danych z bufora. W kolejnym i już ostatnim artykule z serii o buforze kołowym, wykorzystamy powyższą implementację i w oparciu o nią stworzymy nieblokującą obsługę UART, korzystając z ogromnych zalet jakie daje nam obsługa przerwań w mikrokontrolerach. Rezultatem będzie wygodna i prosta w użyciu biblioteka, którą stosuję w niemal każdym projekcie.

Bufor kołowy #3: przykład obsługi UART