Goto page 1, 2, 3 Next
Andrzej Ekiert
Guest
Sun May 06, 2012 11:09 am
Przedstawię najpierw scenariusz oraz problem:
Mamy bibliotekę modułów kodu źródłowego, które są używane w wielu
projektach. Każdy z modułów ma swoje parametry konfiguracyjne, którymi
można go "dostroić" dla potrzeb konkretnej aplikacji i płytki - np. moduł
będący driverem do scalaka radiowego ma m.in. parametry określające do
jakich pinów procesora scalak jest podpięty, moduł będący driverem do
pamięci na I2C ma parametry mówiące którym interfejsem I2C mikrokontrolera
należy z tą pamięcią rozmawiać, jaki jest rozmiar pamięci i który pin
procesora to CS, itp.
Problem:
W każdym projekcie, który korzysta z danego modułu, ustawiamy odpowiednio
wszystkie parametry. Następnie, z dowolnej przyczyny, w bibliotece
zmieniamy zestaw parametrów konfiguracyjnych oferowanych przez moduł. W
efekcie musimy poprawić pliki konfiguracyjne w każdym z projektów, co przy
rosnącej liczbie tych projektów po chwili staje się boleśnie pracochłonne.
Szukam mądrej metody radzenia sobie z tą niepotrzebną pracą. Metody
aplikowalnej do kodu w C i assemblerze (choć bardzo chętnie usłyszę, jeśli
w C++ da się to zrobić jakoś lepiej). Ważne, aby metoda nie powodowała
skutków run-time (np. zamiast ustalać rozmiar pamięci w konfiguracji, mogę
mieć zmienną ustawianą w funkcji inicjalizującej, do pinów mogę mieć
callbacki włącz/wyłącz, też ustawiane przez API, a do sprzętowego modułu
I2C mogę mieć dodatkową warstwę abstrakcji, ale wszystko to kosztuje
pamięć lub cykle, a w przypadku niektórych parametrów jest praktycznie
niewykonalne - poza tym tylko to przesuwa problem ze zmian konfiguracji,
na zmianę API).
Jestem blisko rozpoczęcia pisania programu, który będzie mi zarządzał tą
konfiguracją, tzn. za jednym klikiem porówna konfiguracje wszystkich
zarządzanych projektów, pokaże gdzie są nieustawione parametry, gdzie są
ustawione już nieistniejące parametry, gdzie wartość parametrów różni się
od domyślnej, a następnie umożliwi wybranie akcji, ustawienie właściwych
wartości i uaktualni zarządzane pliki konfiguracyjne. Ale trochę mam
nadzieję, że istnieje jakiś inteligentny sposób, na który nie wpadłem.
ae
Zbych
Guest
Sun May 06, 2012 12:19 pm
W dniu 06.05.2012 13:09, Andrzej Ekiert pisze:
Quote:
Problem:
W każdym projekcie, który korzysta z danego modułu, ustawiamy
odpowiednio wszystkie parametry. Następnie, z dowolnej przyczyny, w
bibliotece zmieniamy zestaw parametrów konfiguracyjnych oferowanych
przez moduł. W efekcie musimy poprawić pliki konfiguracyjne w każdym z
projektów, co przy rosnącej liczbie tych projektów po chwili staje się
boleśnie pracochłonne.
Na to nic nie poradzisz. Skoro biblioteka zmienia swoje
parametry/interface to musisz dostosować do niej programy.
W c++ od biedy można zastosować parametry domyślne albo przeciążyć
funkcje. Wtedy stare programy mogą korzystać ze starego interfejsu.
Quote:
Szukam mądrej metody radzenia sobie z tą niepotrzebną pracą. Metody
aplikowalnej do kodu w C i assemblerze (choć bardzo chętnie usłyszę,
jeśli w C++ da się to zrobić jakoś lepiej). Ważne, aby metoda nie
powodowała skutków run-time (np. zamiast ustalać rozmiar pamięci w
konfiguracji, mogę mieć zmienną ustawianą w funkcji inicjalizującej, do
pinów mogę mieć callbacki włącz/wyłącz,
A to już zwykłe makra, definy, funkcje inline, specjalizacje szablonów
nie wystarczą do ukrycia fizycznego położenia pinów?
Quote:
sprzętowego modułu I2C mogę mieć dodatkową warstwę abstrakcji, ale
wszystko to kosztuje pamięć lub cykle, a w przypadku niektórych
parametrów jest praktycznie niewykonalne - poza tym tylko to przesuwa
problem ze zmian konfiguracji, na zmianę API).
Jeśli do wszystkich modułów I2C z różnych procesorów jesteś w stanie
opracować jeden interface to nie ma problemu. Dodajesz do projektu plik
ze swoją obsługą I2C od danego procka i już. Moduł radiowy wykorzysta te
funkcje, które dołączy linker. Zero narzutu.
Ja raczej unikami używania tej samej kopii biblioteki do różnych
projektów. Dasz sobie głowę uciąć, że zmiana w bibliotece pod bieżący
projekt x nie spowoduje jakiś anomalii w projekcie x-10, który pisała
inna osoba?
Wolę zrobić kopię biblioteki z projektu x-1 i nanieść poprawki.
Jacek DomaĹski
Guest
Sun May 06, 2012 12:21 pm
Ja osobiście jestem na początku drogi - tj. jeszcze nie powstały te
dziesiatki modulow do dziesiatek aplikacji, ale zaczynam już dostrzegać
problem, stąd moje zainteresowanie tą problematyką - tak, aby zawczasu
coś ustalić i pisać dalej w/g ustalonej, optymalnej metody.
Jednym z pomysłów jest wykorzystanie programów do zarządzania wersjami
typu: SVN, GIT, Mercurial.
Innym pomysłem, który mnie zainteresował, jest wykorzystanie linków do
plików zamiast kopii plików (pod Linuxem) - w ten sposób mamy tylko
jeden plik, widziany przez dowolnie wiele projektow i zmiana w nim
przenosi się automatycznie na wszystkie projekty.
Najprosciej byłoby nie zmieniać parametrow konfiguracyjnych w bibliotece
A może zostawić stare jako 'deprecated', a dodac do nich nowe?
--
Jado
W dniu 06.05.2012 13:09, Andrzej Ekiert pisze:
Quote:
Przedstawię najpierw scenariusz oraz problem:
Mamy bibliotekę modułów kodu źródłowego, które są używane w wielu
projektach. Każdy z modułów ma swoje parametry konfiguracyjne, którymi
można go "dostroić" dla potrzeb konkretnej aplikacji i płytki - np.
moduł będący driverem do scalaka radiowego ma m.in. parametry
określające do jakich pinów procesora scalak jest podpięty, moduł będący
driverem do pamięci na I2C ma parametry mówiące którym interfejsem I2C
mikrokontrolera należy z tą pamięcią rozmawiać, jaki jest rozmiar
pamięci i który pin procesora to CS, itp.
Problem:
W każdym projekcie, który korzysta z danego modułu, ustawiamy
odpowiednio wszystkie parametry. Następnie, z dowolnej przyczyny, w
bibliotece zmieniamy zestaw parametrów konfiguracyjnych oferowanych
przez moduł. W efekcie musimy poprawić pliki konfiguracyjne w każdym z
projektów, co przy rosnącej liczbie tych projektów po chwili staje się
boleśnie pracochłonne.
Szukam mądrej metody radzenia sobie z tą niepotrzebną pracą. Metody
aplikowalnej do kodu w C i assemblerze (choć bardzo chętnie usłyszę,
jeśli w C++ da się to zrobić jakoś lepiej). Ważne, aby metoda nie
powodowała skutków run-time (np. zamiast ustalać rozmiar pamięci w
konfiguracji, mogę mieć zmienną ustawianą w funkcji inicjalizującej, do
pinów mogę mieć callbacki włącz/wyłącz, też ustawiane przez API, a do
sprzętowego modułu I2C mogę mieć dodatkową warstwę abstrakcji, ale
wszystko to kosztuje pamięć lub cykle, a w przypadku niektórych
parametrów jest praktycznie niewykonalne - poza tym tylko to przesuwa
problem ze zmian konfiguracji, na zmianę API).
Jestem blisko rozpoczęcia pisania programu, który będzie mi zarządzał tą
konfiguracją, tzn. za jednym klikiem porówna konfiguracje wszystkich
zarządzanych projektów, pokaże gdzie są nieustawione parametry, gdzie są
ustawione już nieistniejące parametry, gdzie wartość parametrów różni
się od domyślnej, a następnie umożliwi wybranie akcji, ustawienie
właściwych wartości i uaktualni zarządzane pliki konfiguracyjne. Ale
trochę mam nadzieję, że istnieje jakiś inteligentny sposób, na który nie
wpadłem.
ae
Andrzej Ekiert
Guest
Sun May 06, 2012 12:44 pm
Dnia 06-05-2012 o 14:21:22 Jacek Domański <jado@nospamchello.pl>
napisał(a):
Quote:
Jednym z pomysłów jest wykorzystanie programów do zarządzania wersjami
typu: SVN, GIT, Mercurial.
Ależ ja to wszystko mam pod Mercurialem, tyle że to tego problemu akurat
nie rozwiązuje.
Quote:
Innym pomysłem, który mnie zainteresował, jest wykorzystanie linków do
plików zamiast kopii plików (pod Linuxem) - w ten sposób mamy tylko
jeden plik, widziany przez dowolnie wiele projektow i zmiana w nim
przenosi się automatycznie na wszystkie projekty.
Chodzi o to, że dla każdego projektu mam te same parametry ustawione w
inny sposób. Więc też nie rozwiązuje problemu.
Quote:
Najprosciej byłoby nie zmieniać parametrow konfiguracyjnych w bibliotece
No rzeczywiście :-)
ae
Andrzej Ekiert
Guest
Sun May 06, 2012 12:55 pm
Dnia 06-05-2012 o 14:19:08 Zbych <zbych@onet.pl> napisał(a):
Quote:
A to już zwykłe makra, definy, funkcje inline, specjalizacje szablonów
nie wystarczą do ukrycia fizycznego położenia pinów?
Wystarczą, ale dla każdego projektu trzeba te define'y inaczej ustawić -
ta sama nazwa, inna wartość.
Quote:
Jeśli do wszystkich modułów I2C z różnych procesorów jesteś w stanie
opracować jeden interface to nie ma problemu. Dodajesz do projektu plik
ze swoją obsługą I2C od danego procka i już. Moduł radiowy wykorzysta te
funkcje, które dołączy linker. Zero narzutu.
Przy wielu architekturach, to akurat nie mam wyjścia i muszę zrobić
takiego HALa, ale narzut jest. W przypadku jednej architektury, to zamiast
po prostu się odwołać do rejestru sprzętowego modułu, muszę przekazać
mojemu driverowi do chipu jakąś strukturę drivera do modułu I2C, która
będzie mieć np. callbacki do funkcji pośredniczących.. Narzut jak diabli,
choć czasem trzeba się na niego zgodzić (np. wspódzielony dostęp kilku
"driverów" do jednego sprzętowego I2C).
Quote:
Ja raczej unikami używania tej samej kopii biblioteki do różnych
projektów. Dasz sobie głowę uciąć, że zmiana w bibliotece pod bieżący
projekt x nie spowoduje jakiś anomalii w projekcie x-10, który pisała
inna osoba?
Staram się tak modularyzować kod i dawać takie API, żeby zmiany nie
wywoływały efektów ubocznych. Oczywiście przetestować to zawsze trzeba i
nie dam sobie uciąć nawet paznokcia.
Quote:
Wolę zrobić kopię biblioteki z projektu x-1 i nanieść poprawki.
Wykrywasz błąd albo robisz usprawnienie w x-1 i dopiero masz poprawianie
wszędzie gdzie ta kopia jest. Brrr...
ae
Sebastian BiaĹy
Guest
Sun May 06, 2012 1:15 pm
On 2012-05-06 13:09, Andrzej Ekiert wrote:
Quote:
że istnieje jakiś inteligentny sposób, na który nie
wpadłem.
Zapropnuje sposób trywialny, być może akurat będzie w sam raz:
*** i2cdriver.c ***
#include "i2cconfiguration.h"
#include "../lib/i2c/i2ccore.c"
#include "../lib/i2c/i2chardware.c"
*** i2cdriver.h ***
#include "i2cconfiguration.h"
#include "../lib/i2c/i2cinterface.h"
Plik i2cconfiguration.h jest częscią konkretnego projektu, podobnie jak
i2cdriver.c.
I tyle. W i2cconfiguratiion stado #define per projekt. W plikach lib/i2c
(h i c) od groma #ifdef na każdy wariant.
Powinno być najmniej intruzywne i najłatwiejsze w utrzymaniu przez
programistę C. Żadnych zmian w bibliotece. Wada: kompilujesz wszystko za
pierwszym razem. ALE. Dzieki make potem kompilujesz tylko zmiany, więc
narzut jest jednorazowy.
Zbych
Guest
Sun May 06, 2012 1:23 pm
W dniu 06.05.2012 14:55, Andrzej Ekiert pisze:
Quote:
Dnia 06-05-2012 o 14:19:08 Zbych <zbych@onet.pl> napisał(a):
A to już zwykłe makra, definy, funkcje inline, specjalizacje szablonów
nie wystarczą do ukrycia fizycznego położenia pinów?
Wystarczą, ale dla każdego projektu trzeba te define'y inaczej ustawić -
ta sama nazwa, inna wartość.
Zgadza się i zakładam, że rzeczy specyficzne dla projektu trzymasz w
osobnym pliku, który leży sobie w katalogu z projektem i jest przez
bibliotekę tylko includowany. Zgadza się?
Quote:
Jeśli do wszystkich modułów I2C z różnych procesorów jesteś w stanie
opracować jeden interface to nie ma problemu. Dodajesz do projektu
plik ze swoją obsługą I2C od danego procka i już. Moduł radiowy
wykorzysta te funkcje, które dołączy linker. Zero narzutu.
Przy wielu architekturach, to akurat nie mam wyjścia i muszę zrobić
takiego HALa, ale narzut jest. W przypadku jednej architektury, to
zamiast po prostu się odwołać do rejestru sprzętowego modułu, muszę
przekazać mojemu driverowi do chipu jakąś strukturę drivera do modułu
I2C, która będzie mieć np. callbacki do funkcji pośredniczących. Narzut
jak diabli, choć czasem trzeba się na niego zgodzić (np. wspódzielony
dostęp kilku "driverów" do jednego sprzętowego I2C).
Ja jak na razie na I2c wieszałem jakieś pamięci, RTC itp. badziewie. Do
jego obsługi wystarczały mi 3 funkcje typu wyślij blok danych, odbierz
blok danych, sprawdź gotowość. Współdzielenie zabezpieczałem mutexami.
Funkcje RTC czy obsługa pamięci wprost wołały te funkcje. W innym procku
dodawałem tylko inną bibliotekę do I2c. Interface zostawał ten sam. Zero
narzutu.
Quote:
Ja raczej unikami używania tej samej kopii biblioteki do różnych
projektów. Dasz sobie głowę uciąć, że zmiana w bibliotece pod bieżący
projekt x nie spowoduje jakiś anomalii w projekcie x-10, który pisała
inna osoba?
Staram się tak modularyzować kod i dawać takie API, żeby zmiany nie
wywoływały efektów ubocznych. Oczywiście przetestować to zawsze trzeba i
nie dam sobie uciąć nawet paznokcia.
Wolę zrobić kopię biblioteki z projektu x-1 i nanieść poprawki.
Wykrywasz błąd albo robisz usprawnienie w x-1 i dopiero masz poprawianie
wszędzie gdzie ta kopia jest. Brrr...
To jest niewątpliwie wada. Ale powiedzmy sobie szczerze, ile można
spieprzyć w kodzie obsługi I2C, uarta itp?
A teraz weź projekt sprzed kilku lat (bo klient chce drobną poprawkę) i
skompiluj go z nową biblioteką. Jaką masz gwarancję, że nie wyjdą jakieś
wredne bugi związane np. z zależnościami czasowymi?
Andrzej Ekiert
Guest
Sun May 06, 2012 1:30 pm
Dnia 06-05-2012 o 15:15:04 Sebastian Biały <heby@poczta.onet.pl>
napisał(a):
Quote:
Zapropnuje sposób trywialny, być może akurat będzie w sam raz:
*** i2cdriver.c ***
#include "i2cconfiguration.h"
#include "../lib/i2c/i2ccore.c"
#include "../lib/i2c/i2chardware.c"
*** i2cdriver.h ***
#include "i2cconfiguration.h"
#include "../lib/i2c/i2cinterface.h"
Plik i2cconfiguration.h jest częscią konkretnego projektu, podobnie jak
i2cdriver.c.
I tyle. W i2cconfiguratiion stado #define per projekt. W plikach lib/i2c
(h i c) od groma #ifdef na każdy wariant.
Ale to mi w żaden sposób nie dotyka mojego problemu. Jeśli odwołam się w
"../lib/i2c/i2ccore.c" do nowego parametru konfiguracyjnego C_I2C_SHMOO,
to muszę go ręcznie zdefiniować w każdym i2cconfiguration.h w każdym
projekcie. Jeśli zmienię nazwę i trochę funkcje parametru C_I2C_FOO na
C_I2C_BAR, to znowu zmiana w każdym projekcie. Chodzi mi o sposób lub
narzędzie do automatyzacji takich zmian: wykrywanie niedodanych definicji,
eliminację przestarzałych definicji, itp.
Samo definiowanie konfiguracji per-projekt i jej #include w plikach
biblioteki to mam rozwiązane w miarę elegancko. Boli mnie tylko potrzeba
ręcznego czyszczenia konfiguracji per-projekt w wypadku zmian w opcjach
oferowanych przez bibliotekę.
ae
Andrzej Ekiert
Guest
Sun May 06, 2012 1:44 pm
Dnia 06-05-2012 o 15:23:06 Zbych <zbych@onet.pl> napisał(a):
Quote:
A to już zwykłe makra, definy, funkcje inline, specjalizacje szablonów
nie wystarczą do ukrycia fizycznego położenia pinów?
Wystarczą, ale dla każdego projektu trzeba te define'y inaczej ustawić -
ta sama nazwa, inna wartość.
Zgadza się i zakładam, że rzeczy specyficzne dla projektu trzymasz w
osobnym pliku, który leży sobie w katalogu z projektem i jest przez
bibliotekę tylko includowany. Zgadza się?
Tak.
Quote:
Ja jak na razie na I2c wieszałem jakieś pamięci, RTC itp. badziewie. Do
jego obsługi wystarczały mi 3 funkcje typu wyślij blok danych, odbierz
blok danych, sprawdź gotowość. Współdzielenie zabezpieczałem mutexami.
Funkcje RTC czy obsługa pamięci wprost wołały te funkcje. W innym procku
dodawałem tylko inną bibliotekę do I2c. Interface zostawał ten sam. Zero
narzutu.
Masz driver do RTC w bibliotece. Procesor ma 2 moduły sprzętowe I2C1 i
I2C2. Musisz przekazać driverowi RTC informację, funkcje dotyczące którego
modułu ma wywołać: odbierz_blok_danych_z_I2C1() czy
odbierz_blok_danych_z_I2C2(). Albo to robisz na poziomie #define, albo
definiując "driver" do I2C i przekazując modułowi I2C handle do tego
drivera (jest narzut). Ja chcę na poziomie #define, ale pragnę sobie
usprawnić zarządzanie takimi #define.
Quote:
Wolę zrobić kopię biblioteki z projektu x-1 i nanieść poprawki.
Wykrywasz błąd albo robisz usprawnienie w x-1 i dopiero masz poprawianie
wszędzie gdzie ta kopia jest. Brrr...
To jest niewątpliwie wada. Ale powiedzmy sobie szczerze, ile można
spieprzyć w kodzie obsługi I2C, uarta itp?
Spieprzyć zawsze można. Poza tym moduł może być czymś bardziej złożonym.
Np. implementacją protokołu sieciowego.
Quote:
A teraz weź projekt sprzed kilku lat (bo klient chce drobną poprawkę) i
skompiluj go z nową biblioteką. Jaką masz gwarancję, że nie wyjdą jakieś
wredne bugi związane np. z zależnościami czasowymi?
Gwarancji nie mam, choć moja ciągła dbałość o to, by kawałek kodu, w
którym zależności czasowe występują, nie mógł być zakłócony przez inne
niezwiązane z nim moduły wykonywane równolegle, daje mi spore szanse.
Generalnie uważam, że zysk ze współdzielonych bibliotek znacznie
przewyższa koszty.
ae
Sebastian BiaĹy
Guest
Sun May 06, 2012 1:49 pm
On 2012-05-06 15:30, Andrzej Ekiert wrote:
Quote:
Ale to mi w żaden sposób nie dotyka mojego problemu. Jeśli odwołam się w
"../lib/i2c/i2ccore.c" do nowego parametru konfiguracyjnego C_I2C_SHMOO,
to muszę go ręcznie zdefiniować w każdym i2cconfiguration.h w każdym
projekcie.
#include "../lib/i2c/defaultconfiguration.h"
#include "i2cconfiguration.h"
To powinno zadzialać jak gdyby dziedziczenie parametrów. Możesz też uzyć
#ifndef FOO, #define FOO DEFAULR_FOO.
Ewentualnie, znacznie bezpieczniej, #ifndef FOO, #error "FOO not set"
Quote:
Jeśli zmienię nazwę i trochę funkcje parametru C_I2C_FOO na
C_I2C_BAR, to znowu zmiana w każdym projekcie. Chodzi mi o sposób lub
narzędzie do automatyzacji takich zmian: wykrywanie niedodanych
definicji, eliminację przestarzałych definicji, itp.
Najlepiej, gdybys tego nie robił w ogóle. takie narzędzie jest
niebezpieczne. Wydaje mi się, że najbezpieczniej jest zdać się na
kompilator. Czyli raz na jakiś czas budujesz wszystkie swoje żywe
projekty w całości i poprawiasz tam gdzie padła kompilacja.
Podobnie do tego pomysłu działa konfigurator opcji kompilacji linuxa
(kernela). Możesz sobie wyobrazić że tak jest ich dużo i że pojawia się
niedostrzegana wcześniej warstwa - zależności. W dodatku są ustalane
ręcznie. Np. sterownik do foobar można kompilowac tylko wtedy gdy jest
scsi itp. Takie zalezności są cieżkie w utrzymaniu bo nie wynikają
wprost z kodu tylko z jakieś metawiedzy poza.
Quote:
Samo definiowanie konfiguracji per-projekt i jej #include w plikach
biblioteki to mam rozwiązane w miarę elegancko. Boli mnie tylko potrzeba
ręcznego czyszczenia konfiguracji per-projekt w wypadku zmian w opcjach
oferowanych przez bibliotekę.
Tego nie unikniesz w przypadku ogólnym. Jesli i2cdriver_init przyjmie 2
parametry a nie jeden to i tak musisz zmienić *wszystkie* projekty.
Wielu programistów C wpada tutaj na genialny pomysł uzycia makr albo
domyslnych parametrów, ale do ślepa uliczka. Tak czy inaczej refaktoring
bibliteki generuje zmiany po stronie klientów.
Jesli masz klienta martwego, ale mimo to chcesz utrzymać kompilację, to
czasami wystarczy kod forkować, czyli #include
"../lib/i2c/v2/i2ccode.c". Nie jest to eleganckie, ale w przypadku
embedded pozwala projekt zamrozić. Problemem jest backportowanie poprawek.
Ten sposob jest uzywany też na linuxie, wystarczy zobaczyć katalog /lib
żeby zauważyć wiele róznych wersji bibliotek. Głównie dla supportu
starych klientów.
Michoo
Guest
Sun May 06, 2012 1:54 pm
On 06.05.2012 14:55, Andrzej Ekiert wrote:
Quote:
Przy wielu architekturach, to akurat nie mam wyjścia i muszę zrobić
takiego HALa, ale narzut jest. W przypadku jednej architektury, to
zamiast po prostu się odwołać do rejestru sprzętowego modułu, muszę
przekazać mojemu driverowi do chipu jakąś strukturę drivera do modułu
I2C, która będzie mieć np. callbacki do funkcji pośredniczących. Narzut
jak diabli, choć czasem trzeba się na niego zgodzić (np. wspódzielony
dostęp kilku "driverów" do jednego sprzętowego I2C).
Ja właśnie rzeźbię powolutku coś takiego w C++, tylko zamiast callbacków
traits przekazywane do szablonów, żeby nie było żadnego narzutu w runtime.
Kompilator odwala całkiem niezłą robotę z funkcjami inline, np
HW::uart<0>::send_char(buf[i]);
zamienia na pojedynczy mov do rejestru.
--
Pozdrawiam
Michoo
Zbych
Guest
Sun May 06, 2012 1:59 pm
W dniu 06.05.2012 15:44, Andrzej Ekiert pisze:
Quote:
Dnia 06-05-2012 o 15:23:06 Zbych <zbych@onet.pl> napisał(a):
A to już zwykłe makra, definy, funkcje inline, specjalizacje szablonów
nie wystarczą do ukrycia fizycznego położenia pinów?
Wystarczą, ale dla każdego projektu trzeba te define'y inaczej ustawić -
ta sama nazwa, inna wartość.
Zgadza się i zakładam, że rzeczy specyficzne dla projektu trzymasz w
osobnym pliku, który leży sobie w katalogu z projektem i jest przez
bibliotekę tylko includowany. Zgadza się?
Tak.
No to dużo więcej już nie wymyślisz. Co najwyżej możesz w przypadku
dokładania nowych stałych/parametrów napisać:
#ifndef XYZ
#define XYZ 12345
#endif
Wtedy biblioteka ze starym programem nie będzie krzyczała, że nie ma
zdefiniowanych parametrów.
Quote:
Ja jak na razie na I2c wieszałem jakieś pamięci, RTC itp. badziewie.
Do jego obsługi wystarczały mi 3 funkcje typu wyślij blok danych,
odbierz blok danych, sprawdź gotowość. Współdzielenie zabezpieczałem
mutexami.
Funkcje RTC czy obsługa pamięci wprost wołały te funkcje. W innym
procku dodawałem tylko inną bibliotekę do I2c. Interface zostawał ten
sam. Zero narzutu.
Masz driver do RTC w bibliotece. Procesor ma 2 moduły sprzętowe I2C1 i
I2C2. Musisz przekazać driverowi RTC informację, funkcje dotyczące
którego modułu ma wywołać: odbierz_blok_danych_z_I2C1() czy
odbierz_blok_danych_z_I2C2(). Albo to robisz na poziomie #define, albo
definiując "driver" do I2C i przekazując modułowi I2C handle do tego
drivera (jest narzut). Ja chcę na poziomie #define, ale pragnę sobie
usprawnić zarządzanie takimi #define.
No to użyj tego define. I tak jak podałem wyżej możesz zrobić domyślną
definicję dla starych programów.
Quote:
Wolę zrobić kopię biblioteki z projektu x-1 i nanieść poprawki.
Wykrywasz błąd albo robisz usprawnienie w x-1 i dopiero masz poprawianie
wszędzie gdzie ta kopia jest. Brrr...
To jest niewątpliwie wada. Ale powiedzmy sobie szczerze, ile można
spieprzyć w kodzie obsługi I2C, uarta itp?
Spieprzyć zawsze można. Poza tym moduł może być czymś bardziej złożonym.
Np. implementacją protokołu sieciowego.
Takie rzeczy jak protokół to już dla mnie warstwa wyższa

i tu nie
mam obaw o współdzielenie.
Andrzej Ekiert
Guest
Sun May 06, 2012 2:10 pm
Dnia 06-05-2012 o 15:49:54 Sebastian Biały <heby@poczta.onet.pl>
napisał(a):
Quote:
On 2012-05-06 15:30, Andrzej Ekiert wrote:
Ale to mi w żaden sposób nie dotyka mojego problemu. Jeśli odwołam się w
"../lib/i2c/i2ccore.c" do nowego parametru konfiguracyjnego C_I2C_SHMOO,
to muszę go ręcznie zdefiniować w każdym i2cconfiguration.h w każdym
projekcie.
#include "../lib/i2c/defaultconfiguration.h"
#include "i2cconfiguration.h"
To powinno zadzialać jak gdyby dziedziczenie parametrów.
Mam to dość podobnie zrobione. Samo dziedziczenie defaultu to nie jest
najlepszy pomysł, bo nowo dodany parametr może przejść niezauważony. Więc
albo dziedziczę całą konfigurację modułu, albo wszystkie parametry muszą
być w projekcie przedefiniowane.
Quote:
Możesz też uzyć #ifndef FOO, #define FOO DEFAULR_FOO.
Ewentualnie, znacznie bezpieczniej, #ifndef FOO, #error "FOO not set"
To już w zasadzie mam wbudowane: zawsze kompiluję z -Wundef i zamiast
#ifdef do włączania opcji używam "#if C_FOOBAR == ENABLED". Mam wtedy
warning gdy coś nie jest ustawione.
Quote:
Jeśli zmienię nazwę i trochę funkcje parametru C_I2C_FOO na
C_I2C_BAR, to znowu zmiana w każdym projekcie. Chodzi mi o sposób lub
narzędzie do automatyzacji takich zmian: wykrywanie niedodanych
definicji, eliminację przestarzałych definicji, itp.
Najlepiej, gdybys tego nie robił w ogóle. takie narzędzie jest
niebezpieczne. Wydaje mi się, że najbezpieczniej jest zdać się na
kompilator. Czyli raz na jakiś czas budujesz wszystkie swoje żywe
projekty w całości i poprawiasz tam gdzie padła kompilacja.
Skłaniam się ku użyciu narzędzia, żeby zamiast otwierać 20 plików (a za
parę lat może 100?) i wszędzie robić 'paste' nowego parametru, móc kliknąć
"update". Oczywiście kompilacja potem i tak jest nieodzowna (nie mówiąc o
teście).
Quote:
Podobnie do tego pomysłu działa konfigurator opcji kompilacji linuxa
(kernela).
Nawet zaglądałem mu w źródła, czy by się nie dało czegoś wykorzystać, ale
trochę mnie odrzuciło. Poza tym w menuconfig jednak niezbyt dobrze widać
nowe parametry, a usunięte po prostu po cichu znikają (jeśli się nic nie
zmieniło od ostatniego razu, jak kompilowałem kernel).
Miałem po prostu nadzieję, że kogoś już to uwierało i jakieś narzędzie
istnieje. No nic, napiszę sobie sam.
ae
Jacek DomaĹski
Guest
Sun May 06, 2012 2:24 pm
W dniu 06.05.2012 16:10, Andrzej Ekiert pisze:
Quote:
Skłaniam się ku użyciu narzędzia, żeby zamiast otwierać 20 plików (a za
parę lat może 100?) i wszędzie robić 'paste' nowego parametru, móc
kliknąć "update". Oczywiście kompilacja potem i tak jest nieodzowna (nie
mówiąc o teście).
Podobnie do tego pomysłu działa konfigurator opcji kompilacji linuxa
(kernela).
Nawet zaglądałem mu w źródła, czy by się nie dało czegoś wykorzystać,
ale trochę mnie odrzuciło. Poza tym w menuconfig jednak niezbyt dobrze
widać nowe parametry, a usunięte po prostu po cichu znikają (jeśli się
nic nie zmieniło od ostatniego razu, jak kompilowałem kernel).
Miałem po prostu nadzieję, że kogoś już to uwierało i jakieś narzędzie
istnieje. No nic, napiszę sobie sam.
ae
Przy okazji tematu nasuwa się pytanie: "Jak długo należy utrzymywać
stare projekty w stanie zaktualizowanym" Czy po prostu nie umrą one
śmiercią naturalną i zatrzymają się na jakimś etapie ich rozwoju, a
łatwiej będzie stworzyć nowy projekt, na nowy procesor, w/g nowych
bibliotek, itp....
--
Jado
Zbych
Guest
Sun May 06, 2012 2:28 pm
W dniu 06.05.2012 15:54, Michoo pisze:
Quote:
On 06.05.2012 14:55, Andrzej Ekiert wrote:
Przy wielu architekturach, to akurat nie mam wyjścia i muszę zrobić
takiego HALa, ale narzut jest. W przypadku jednej architektury, to
zamiast po prostu się odwołać do rejestru sprzętowego modułu, muszę
przekazać mojemu driverowi do chipu jakąś strukturę drivera do modułu
I2C, która będzie mieć np. callbacki do funkcji pośredniczących. Narzut
jak diabli, choć czasem trzeba się na niego zgodzić (np. wspódzielony
dostęp kilku "driverów" do jednego sprzętowego I2C).
Ja właśnie rzeźbię powolutku coś takiego w C++, tylko zamiast callbacków
traits przekazywane do szablonów, żeby nie było żadnego narzutu w runtime.
Kompilator odwala całkiem niezłą robotę z funkcjami inline, np
HW::uart<0>::send_char(buf[i]);
zamienia na pojedynczy mov do rejestru.
A jakie będą tego zalety w stosunku do wersji z define?
Goto page 1, 2, 3 Next