Skip to content
Xaeian edited this page Oct 23, 2026 · 2 revisions

Pico Database

PDB (pico database) przechowuje w pamięci flash mikrokontrolera małe rekordy, na przykład mailbox bootloadera, dziennik zdarzeń albo dane fabryczne. Pamięć flash działa jak zeszyt pisany długopisem: zapisanej linii nie da się poprawić, a skasować można tylko całą stronę. Dlatego PDB niczego nie zmienia, tylko dopisuje kolejne rekordy.

Strona i rekord

Strona PDB

  • Każda strona zaczyna się nagłówkiem zapisywanym zaraz po jej skasowaniu, więc strona bez nagłówka nie zawiera danych.
  • Dalej są rekordy o jednakowym rozmiarze, a numery nadaje im sam PDB: 1, 2, 3.
  • Na końcu rekordu jest suma kontrolna CRC, zapisywana jako ostatnia. Rekord bez poprawnego CRC nie został dokończony i przy odczycie jest pomijany.

Dwie strony w pierścieniu

Dwie strony w pierścieniu

Gdy nowsza strona się zapełni, PDB kasuje starszą i zapisuje dalej na niej, więc zawsze zostaje jedna pełna strona historii. Dane, których nie wolno stracić, na przykład dane fabryczne, zajmują jedną stronę bez pierścienia: po jej zapełnieniu zapis jest odrzucany, a obowiązuje najnowszy poprawny rekord.

Zanik zasilania

Zanik zasilania

Zasilanie może zaniknąć w dowolnej chwili, a PDB obsługuje każdy z trzech przypadków:

  • Przy zapisie rekordu: rekord nie ma CRC i przy odczycie jest pomijany.
  • Przy kasowaniu strony: strona nie ma nagłówka i przed zapisem jest kasowana od nowa.
  • Na samym początku zapisu: miejsce wygląda na puste, choć nie jest, więc pierwszy zapis po każdym starcie zeruje pierwsze wolne miejsce, a rekord trafia do następnego.

Odczyt niczego nie zapisuje, a PDB nigdy nie kasuje całej bazy z powodu błędu.

Wykorzystanie

Wykorzystanie PDB

Każde wykorzystanie to zwykła baza PDB z własnym rekordem i trybem:

  • Mailbox: bootloader i aplikacja zapisują historię slotów na dwóch stronach w pierścieniu.
  • Dziennik zdarzeń: aplikacja dopisuje zdarzenia na dwóch stronach w pierścieniu.
  • Dane fabryczne: jedna strona bez pierścienia.

Znaczenie rekordu określa jego użytkownik, a PDB obsługuje każdy rekord tak samo.

Konfiguracja

Rekord o stałym rozmiarze: pierwsze 4 bajty to numer, a ostatnie 4 bajty to CRC, oba uzupełnia PDB. Baza zajmuje dwie strony w pierścieniu, a jej rodzaj odróżnia ją od innej bazy na tych stronach.

typedef struct {
  uint32_t number; // first 4 bytes: the number PDB gives the record
  uint32_t time;
  uint16_t code;
  uint16_t value;
  uint32_t crc; // last 4 bytes: the CRC PDB writes
} Event_t;

// Two pages outside the program, a ring; `.no_wrap = true` stops when they are full
static PDB_t events = { .page_start = 48, .page_count = 2,
  .record_size = sizeof(Event_t), .kind = 0x5645 };

Użycie

Po każdym starcie najpierw PDB_Init; rekord dopisuje się w całości, a odczyt przechodzi po rekordach pasujących do zapytania.

void events_init(void)
{
  PDB_Init(&events); // reads the headers and finds where to write, writes nothing
}

void event_add(uint16_t code, uint16_t value)
{
  Event_t event = { .time = (uint32_t)RTC_Timestamp(), .code = code, .value = value };
  PDB_Insert(&events, &event); // PDB fills in the number and the CRC
}

void events_print(void)
{
  PDB_Query_t query = { .limit = 10, .dir = PDB_Desc }; // the newest ten
  PDB_Iter_t iter;
  Event_t event;
  PDB_IterInit(&events, &iter, &query);
  while(PDB_IterNext(&iter, &event) == OK) {
    LOG_INF("%u time:%u code:%u value:%u", event.number, event.time, event.code, event.value);
  }
}

Clone this wiki locally