Dwa podejścia do nadawania wiadomości z CAPL w CANoe

Cześć!

Mam na imię Wojtek i jestem inżynierem od testowania Systemów Wbudowanych.

Właśnie trwa przedsprzeaż mojego kursu Wszystko o magistrali CAN – polecam!

Wstęp

Jedną z podstawowych rzeczy, które chcemy robić w CANoe z poziomu kodu CAPL jest nadawanie ramek. W odniesieniu do magistrali CAN i podobnych, producent oprogramowania wyróżnił dwa podejścia do tematu, można wręcz powiedzieć – dwie filozofie:

Message-oriented CAPL oraz Signal-oriented CAPL

Same nazwy nie są na tyle intuicyjne, by wywnioskować z nich o co chodzi – wszak sygnał to element składowy ramki… o co więc chodzi?

Główną różnicą jest odpowiedź na pytanie gdzie i jak przechowywane są bufory danych.

Wciąż niejasne? Nic nie szkodzi. Zaraz omówię to w praktyce.

Message-oriented CAPL

Czyli nadawanie oparte na wiadomościach.

Wewnątrz każdego modułu CAPLowego (czyli Network Node) tworzymy obiekty, którymi możemy manipulować a następnie wysłać je na magistralę.

Przykład

przykładowy kod, który po wciśnięciu przycisku “s” na klawiaturze spowoduje wysłanie na magistralę ramki:

on key 's' {
  message LeverState my_mesage_buffer;  // utowrzenie obiektu 
  my_message_buffer.position = 3;       //przypisanie wartości 
  output(my_message_buffer);            //wysłanie wiadomości na magistralę
}

Wewnątrz zdarzenia “wciśnięcie przycisku [s]” robimy następujące rzeczy:

  • Tworzymy obiekt typu message (ramka). Zakładam, że wcześniej zdefiniowaliśmy sobie bazę danych .DBC i zaciągamy stamtąd definicję ramki typu LeverState wraz z jej strukturą. Nazwa “my_message_buffer” jest dowolnie wybraną nazwą utworzonego obiektu, jak nazwa zmiennej.
  • Przypisuję wartość do elementu składowego ramki, tzn. do sygnału o nazwie “position”. Zakładam tutaj ponownie, że sygnał o takiej nazwie znalazł się w definicji, które zaciągamy z pliku DBC. Tak więc nowo utworzony obiekt będzie zawierał wszystkie elementy składowe, które zawiera definicja ramki typu LeverState
  • Nadaję ręcznie wiadomość na magistralę dosłownie “wyrzucając” cały obiekt my_mesage_buffer na magistralę przy pomocy polecenia output()

Wizualizacja

Możemy sobie te kroki zwizualizować za pomocą poniższych grafik (nazwy mogą się nieznacznie różnić):

Utworzenie obiektu message typu LeverState o wymyślonej nazwie
Przypisanie wartości sygnału do istniejącego obiektu
“Wyrzucenie” obiektu na magistralę.
Uwaga: obiekt nie znika z pamięci po wysłaniu

Można więc zauważyć, że operujemy tutaj na buforze: Najpierw go tworzymy, potem możemy dowolnie modyfikować, a następnie w dowolnie wybranym przez siebie miejscu wysłać jego zawartość na magistralę CAN.

Równie dobrze mógłbym sobie stworzyć kilka buforów odnoszących się do takiego samego rodzaju ramki (podobnie jak mogę stworzyć sobie kilka zmiennych typu int) i przechowywać w nich różne wartości:

Ważna uwaga:

Jedynym sposobem na wysłanie ramki na magistralę w podejściu Message-oriented CAPL jest skorzystanie z funkcji output(), która wysyła wcześniej utworzony obiekt na magistralę.

Ma to swoje plusy i minusy.

Plusy

Jeśli chodzi o plusy, jest to oczywiście pełna kontrola nad wysyłaniem ramki. Jeśli zauważymy, że przygotowana przez nas symulacja nie działa poprawnie i ramki są nadawane na magistralę w sposób inny niż zamierzony, wiemy dokładnie gdzie szukać przyczyny błędu – odnajdujemy fragmenty w kodzie CAPL, które zmieniają wartość naszych buforów lub je wysyłają.

Minusy

Jeśli chodzi o minusy, dostęp do tych obiektów możliwy jest tylko z poziomu danego pliku CAPL.

Komunikacja z panelem

Jeśli więc chcielibyśmy sterować wartościami nadawanymi w ramce z poziomu panelu, musielibyśmy zrobić następującą konstrukcję:

Wartości z panelu do pliku CAPL moglibyśmy przekazywać za pomocą zmiennych systemowych (SysVars). Tzn. kontrolki na panelu związać do konkretnych zmiennych, zaś z poziomu CAPLa odczytywać wartość tych zmiennych. Jest to nieoczywiste, ale takie właśnie podejście należy przyjąć, jeśli wybraliśmy filozofię “message-oriented CAPL”.

Nadawanie cykliczne

Jak już wspomniałem wcześniej, jeśli chcemy wysłać wiadomość, za każdym razem trzeba skorzystać z funkcji output(). Mówiąc za każdym razem, mam na prawdę na myśli “za każdym”

Jeśli chcemy np. nadawać ramkę cykliczną co 100ms, musimy stworzyć timer dla tej ramki, który z każdym przejściem będzie wykonywał funkcję output(). Najprostsza możliwa implementacja takiego kodu wygląda następująco:

variables
{
  message 0x100 message_0x100_buffer;  //utworzenie obiektu
  msTimer message_0x100_timer;         //utworzenie timera
}

on start {
 setTimerCyclic(message_0x100_timer, 100);  //uruchomienia timera cyklicznie na starcie
}

on timer message_0x100_timer {
 output(message_0x100_buffer);        //wyslanie ramki
}

Signal-oriented CAPL

Tutaj sytuacja jest zgoła inna.

Dla każdej ramki, którą chcemy nadawać lub/i odbierać zdefiniowany jest dokładnie jeden globalny bufor, do którego dostęp mają wszystkie moduły CANoe. Taka warstwa zawierająca w sobie wszystkie bufory nazywana jest Interactive Layer – w skrócie IL.

Ten skrót jest o tyle ważny, że przewija się on w różnych miejscach w CANoe i przykładowo z poziomu CAPLa mamy dostęp do wielu funkcji odnoszących się właśnie do Interactive Layer:

Wizualizacja

Podejście oparte na Interactive Layer możemy zobrazować następująco:

Jak widać, bezpośrednio z warstwą IL komunikować może się każdy moduł, każde “okienko” w CANoe: Network Node’y, panele, okienka do analizy itd.

Wewnątrz IL przechowywane są bufory dla każdego rodzaju wiadomości:

Zapis jest tutaj dwukierunkowy:

Za każdym razem, gdy na magistralę przychodzi ramka, jej zawartość kopiowana jest do bufora. W ten sposób bufor zawsze przechowuje tylko ostatnią wpisaną do niego wartość.

Jeśli zaś chcemy ramkę nadawać, jedynie wpisujemy wartość konkretnego sygnału lub konkretnych bajtów do bufora. Robimy to przy użyciu znaku dolara – odnosimy się do konkretnego sygnału w IL:

Jednak ważna uwaga:

Nie mamy jednak kontroli nad tym kiedy IL ją nada na magistralę.

Dzieje się tak, ponieważ IL sam nadaje ramki na magistralę zgodnie ze swoimi określonymi czasami nadawania. Wszystko co my możemy zrobić to po prostu wpisać wartość do bufora i czekać aż zostanie nadany na magistralę.

Równie dobrze możemy zmienić wartość bufora np. z okienka Data:

Włączenie i konfiguracja Interactive Layer

Aby włączyć Interactive Layer musimy najpierw zaznaczyć odpowiednią opcję w ustawieniach głównych programu CANoe:

Przy podejściu Signal-Oriented CAPL należy przypisać nasze Network Nodes do konkretnych węzłów zdefiniowanych w debeceku:

Następnie możemy albo edytować ramki dla konkrentego węzła:

… albo zbiorczo dla całej magistali:

Pokaże nam się takie okno:

Plusy

Plusem takiego podejście jest niewątpliwie prostota tworzenia projektu:

  • Nie musimy ustawiać timerów do nadawania cyklicznego ramek
  • Nie musimy bawić się w zmienne systemowe do komunikacji z panelami
  • Nie musimy tworzyć obiektów typu message – po prostu wpisujemy wartość do $sygnału
  • Możemy wygodnie modyfikować wartości buforów z każdego miejsca CANoe

Minusy

  • Brak ścisłej kontroli nad wysyłaniem ramek
  • Możliwe rejsy (race-conditions) jeśli dopuszczamy zapis do zmiennej bez ograniczeń z wielu miejsc
  • … a co za tym idzie trudny debug, jeśli próbujemy dojść do tego kto i czemu wpisał coś dziwnego do ramki

Co robić, jak żyć?

i jakie podejście przyjąć?

Oto moja rada:

  • Jeśli masz do stworzenia prosty projekt, w którym będziesz mieć panele do sterowania urządzeniem z poziomu CANoe
  • Czas ustawienia się sygnału nie jest krytyczny (nie boli jeśli będzie to 120ms zamiast 20ms)
  • Nie spodziewasz się Race-Conditions, a jeśli się pojawią to nie będzie to duży problem

… wybierz podejście Signal-Oriented

a jeśli:

  • Tworzysz projekt do celu zaawansowanych testów urządzenia,
  • Czasówki mają duże znaczenie,
  • Będzie robiony debug
  • Będziesz robił dokładne sekwencje ramka po ramce, np. trzy kolejne ramki, w których kolejno zmienia się wartość sygnału

… wybierz Message-Oriented CAPL.

A jeśli pracujesz z CANoe, napisz mi w komentarzu z jakiego podejścia korzystasz i dlaczego 🙂


Opublikowano

w

przez

Tagi:

Komentarze

Jedna odpowiedź do „Dwa podejścia do nadawania wiadomości z CAPL w CANoe”

  1. Awatar Slawek
    Slawek

    Cześć, używam message-oriented. Powód nr.1 to nigdy nie praktykowałem signal-oriented i ten artykuł porządnie wyprał mi mózg 🙂 Powód nr.2 zawsze wolę mieć kontrolę nad tym co robie nawet kosztem przerzucania zmiennych przez sysvar. Powód nr.3 głównie testuje w dużych projektach i tak jak napisałeś konkretne wymagania do konkretnych czasówek wszystko ma “tykać” jak w zegarku i sprawdzać czy rzeczywiście tak jest.
    Tak więc dobrze wiedzieć że jest alternatywne podejście ale jednak kontrola nad wszytskim zwycięża więc message-oriented.
    pozdrawiam

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *