Elektroda.pl
Elektroda.pl
X
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[C++] RS232 - Odbieranie i interpretacja ramki w postaci binarnej.

Arkain 14 Feb 2012 08:00 9345 69
  • #31
    Arkain
    Level 10  
    LED5W wrote:
    Coś mi mówi, że znowu jakieś cuda się dzieją. :D Jeśli coś nie działa wklej błąd, kod (z edytora, nie z głowy), a nie tak, że "nie idzie". ;)

    Masz rację z mojego opisu niewiele wynika a kompilator się nie myli ;P

    Code: cpp
    Log in, to see the code


    Czyli operator "*" ma mniejszy priorytet niż "."?
  • #32
    LED5W
    Level 33  
    No jak widać. :P Widzę, że jednak zamiast kompilować to komplikujesz. W tym przypadku możesz użyć
    Code: cpp
    Log in, to see the code
    a jeszcze lepiej
    Code: cpp
    Log in, to see the code
    Po to zresztą zostały wymyślone [].
  • #33
    Arkain
    Level 10  
    LED5W wrote:
    No jak widać. :P Widzę, że jednak zamiast kompilować to komplikujesz...

    :/ No cóż mówiłem że jestem początkującym programistą... Ale dzięki za wskazówki bo użycie wsk[i].skladnik = 100 jakoś nie przyszłoby mi do głowy ;P
  • #34
    Arkain
    Level 10  
    Hmm... Jak w Borlandzie pozbyć się:

    [BCC32 Warning] W8060 Possibly incorrect assignment

    przy:

    Code: cpp
    Log in, to see the code


    Dałem dodatkowe nawiasy ale ostrzeżenie nie znika :/
    A wszystko jest ok bo chcę za jednym razem pobrać dane i zapisać do ile_danych liczbę zwracaną przez funkcję i jeżeli != od 0 to wykonać to co w if :/

    i jaszcze jedno:

    [BCC32 Warning] W8004 'ile_danych' is assigned a value that is never used

    gdzie:

    Code: cpp
    Log in, to see the code


    Czyli mówi że nie użyty a przecież jest no bo i wewnątrz warunku if i jeżeli >0 to w ciele if :/
  • #35
    LED5W
    Level 33  
    Jaki typ zwraca Read_Data? Zmienna tekst to int? Nie lepiej to nazwać np. suma?
  • #36
    Arkain
    Level 10  
    Read_Data zwraca int a tekst to string w którym mam kilka info a następnie wklejane jest to do Memo by w fazie testów mieć info co się dzieje ;]
  • #37
    LED5W
    Level 33  
    Takie coś
    Code: cpp
    Log in, to see the code
    potraktuje ile_danych jako char.
    To ma liczyć sumę, czy wyświetlać kolejne ilości pobranych danych?
  • #38
    Arkain
    Level 10  
    ile_danych traktuj jako int bo tak jest zdefiniowane.

    powiedzmy tak:

    Pętla nieskończona (wątek lub timer):

    w nim:

    Code: cpp
    Log in, to see the code


    Powiedzmy tak że jak przyjdą jakieś dane to funkcja Read_Data zwróci ilość (liczbę) odebranych danych i wykona się warunek if. Wewnątrz if do zmiennej tekst zapisywane są różne komunikaty i zmienne a na końcu całość jest wyświetlana w podglądzie/konsoli. Przy następnym obiegu jeżeli zostaną odebrane jakieś dane wszystko zaczyna się od nowa...


    Zastanawiam się nad kolejką FIFO w programie na pakiety odebrane i pakiety wysyłane. Na początku chciałem zrobić to na kolejce STL ale nie bardzo wiem jak zrobi kolejkę dynamicznych tablic (rozmiar pakietu określany w trakcie działania programu) i jak przed (w trakcie) usunięciu pierwszego elementu usunąć tą dynamiczną tablicę bo metoda pop przecież nie przyjmuje żadnych parametrów...

    Chodzi mi o jak najefektywniejsze wysyłanie i odbieranie pakietów i by ich rozmiar był znany dopiero po uruchomieniu programu... myślałem o std::vector ale tam muszę ręcznie robić pop_front i wydaje mi się że nie jest to eleganckie i efektywne. A dodatkowo czy da się robić coś takiego:

    Code: cpp
    Log in, to see the code
  • #39
    LED5W
    Level 33  
    Arkain wrote:
    ile_danych traktuj jako int bo tak jest zdefiniowane.
    Ja to mogę tak traktować, ale sprawdź co wyświetli kod
    Code: cpp
    Log in, to see the code
    ;)

    Piszesz o dynamicznej tablicy a w kodzie masz statyczną. Zrób tak:
    Code: cpp
    Log in, to see the code

    Przy dodawaniu do vector'a
    Code: cpp
    Log in, to see the code
    Chociaż wydaje mi się, że zerowanie jest zbędne.
  • #40
    Arkain
    Level 10  
    Dzięki serdeczne za odpowiedz ;D

    Czy moja obsługa tego rozwiązania jest prawidłowa?

    Code: cpp
    Log in, to see the code


    I kompilator przepuszcza wszystko bez zająknięcia program wydaje się działać.

    Czy przy:

    Code: cpp
    Log in, to see the code


    Przepisywana jest cała kolejka o ten jeden element czy tylko elementowi drugiemu mówi się że jest teraz pierwszym a trzeciemu drugim itd. - czyli bez przepisywania całej pamięci?

    Może tą kolejkę jakoś lepiej zorganizować?
  • #41
    LED5W
    Level 33  
    Arkain wrote:
    Czy moja obsługa tego rozwiązania jest prawidłowa?
    Po przeglądnięciu kodu, o ile to będzie w osobnych funkcjach, może być.

    Arkain wrote:
    Może tą kolejkę jakoś lepiej zorganizować?
    Zamiast vector'a możesz zastosować... kolejkę :D (queue).
  • #42
    Arkain
    Level 10  
    Zmieniłem na kolejkę i chodzi wydajniej ;D

    Ale mam dwa kolejne problemy:

    1. Program piszę na Win 7 Pro SP1 64bit w C++ Builder.
    Odnajdywanie aktywnych portów COM (poprzez użycie WinAPI) w systemie Win 7 działa a na XP nie :(
    Funkcja użyta do wykrywania to QueryDosDevice ale zwraca ona na XP 0 :/
    Nie wiem w czym może być problem użycie funkcji jest prawidłowe :/

    2. W TOkno_Glowne::FormClose zrobiłem takie oto usuwanie z kolejki pozostałych dynamicznych tablic:

    Code: cpp
    Log in, to see the code

    Pytanie czy da się to zrobić szybciej / efektywniej? Bo jeżeli w kolejce jest większa ilość tablic to na słabszym sprzęcie widać jak okno przy zamykaniu się przycina :/ (w ostateczności przed oczyszczaniem ukryć okno?)
  • Helpful post
    #43
    LED5W
    Level 33  
    1. Co zwraca GetLastError?
    2. Jaki rozmiar ma ta kolejka? U mnie usunięcie dopiero miliona tablic po 100 bajtów zajmuje 1-2s (w konfiguracji debug).
  • #44
    Arkain
    Level 10  
    Odp 1. Zwraca kod błędu 234:

    Quote:
    ERROR_MORE_DATA
    234 (0xEA)
    More data is available.

    Wykrywanie rozpoczynam od:

    Code: cpp
    Log in, to see the code

    Więc chodzi o rozmiar "bufSize"? Jest to chyba związane z tym iż ta wersja Borlanda wszystkie stringi traktuje jako Unicode :/

    Link

    Jak to rozwiązać... tylko chyba inna metoda tylko jaka? Taka jaką stosuje Menadżer Urządzeń a może taką jaka jest w Terminal by Br@y++ 1.9b 20111230 z możliwością wykrycia adapterów USB<->RS232:

    Quote:
    Available COM ports on system:
    COM4
    USB->COM adapters:
    FTDIBUS\VID_0403+PID_6001+A800enatA\0000


    lub zewnętrzna biblioteka FTDI - jak pamiętam to ona ma wykrywanie COM-ów prawda? Ehhh...

    Odp 2. Okazało się że system kompilatora nadzorujący obsługę pamięci sprawdzał czy nie następuje jej wyciek... jak dałem na "Release" i wyłączyłem to, to jest ok ;]
  • #45
    LED5W
    Level 33  
    Jeżeli nie ma błędu przy kompilacji to raczej char jest traktowany jak jednobajtowy znak ANSI, a QueryDosDevice w wersji A. Próbowałeś utworzyć bufor o znacznie większym rozmiarze?
  • #46
    Arkain
    Level 10  
    Gdy bufor jest rozmiaru:

    Code: cpp
    Log in, to see the code


    Jak to rozwiązać? Da się QueryDosDevice zamiast pierwszego parametru NULL podać by zwracała do bufora tylko COM-y?

    I dodatkowa ciekawostka czemu gdy umieszcze GetLastError w void __fastcall TOkno_Glowne::FormCreate(TObject *Sender) zaraz jako pierwszą instrukcję to ona zwraca:

    Quote:
    ERROR_ACCESS_DENIED
    5 (0x5)
    Access is denied.


    Przecież ja jeszcze w tym miejscu nic nie robię :/ tylko Borland ma wcześniej swoje instrukcje odnośnie okna :/
  • #47
    JmL(TM)
    Level 24  
    najprosciej jak sie da...

    Code: cpp
    Log in, to see the code


    wynik:

    [C++] RS232 - Odbieranie i interpretacja ramki w postaci binarnej.

    Oczywiscie w petli wyswietli aktywne porty 1-24 [jesli takowe sa dostepne]
    O to chodzi?

    PS: Smiga na XP bo wlasnie w tym systemie to teraz sklecilem :boss:
  • #48
    Arkain
    Level 10  
    Wróciłem z wjazdu służbowego i wieczorem (jeżeli moja żona da mi szanse ;P bo dziś dzień kobiet) to sprawdzę jak to się sprawuje. Jedynie nie podoba mi się to że deklaruje jakąś liczbę comów. Wola bym by kod był uniwersalny - by nie było limitu na ilość portów.
  • #49
    JmL(TM)
    Level 24  
    Arkain wrote:
    Jedynie nie podoba mi się to że deklaruje jakąś liczbę comów. Wola bym by kod był uniwersalny - by nie było limitu na ilość portów.


    Jednak liczba portow COM i tak zawsze bedzie ograniczona wiec mozesz np. zwiekszyc liczbe w petli. W sumie to tak jak napisalem wczesniej jest to najprostsza werja kodu z uzyciem QueryDosDevice(); Oczywiscie mozna zrobic to inaczej ale wg mnie niepotrzebnie bedzie to komplikowac kod...
  • #50
    Arkain
    Level 10  
    Po bardzo długiej przerwie na forum wracam ;]

    Program świetnie działa na kolejce STL-a

    Teraz zmagam się z wątkami i ich synchronizacją...
    Chciałbym by:

    - jeden wątek był odpowiedzialny za odbiór z COM
    - drugi wątek był odpowiedzialny za wysyłanie do COM
    - trzeci wątek główny za interfejs.

    W tej chwili wszystko działa na timerach :/ bo to było najprostsze do testów.
    Kolejka nadawania i kolejka odbierania są globalnie dostępne.

    Pytanie do ekspertów ;] (czyli was doświadczeni programiści) co lepiej wykorzystać do tego celu wątki z WINAPI czy boost::thread.

    Na co zwrócić uwagę przy obsłudze RS232 przez wątki.

    Przykładowy szablon działania/zastosowania mile widziany ;D
  • #51
    JmL(TM)
    Level 24  
    Arkain wrote:
    Teraz zmagam się z wątkami i ich synchronizacją...
    Chciałbym by:

    - jeden wątek był odpowiedzialny za odbiór z COM
    - drugi wątek był odpowiedzialny za wysyłanie do COM
    - trzeci wątek główny za interfejs.


    Wysylasnie i odbieranie mozna smialo zrobic na watkach zeby program sie nie "podwieszal" ale watek pod interfejs? Do klikniecia w przycisk i moze wybranie jakiejs opcji z menu mozesz sobie darowac i ulatwic zycie nie stosujac zadnego watku w tym celu...
  • #52
    Arkain
    Level 10  
    Tak tak wiem ;] Źle mnie zrozumiałeś wątek do interfejsu jest wątkiem głównym czyli tym który tworzony jest wraz z uruchomieniem programu (a nie osobnym stworzonym przeze mnie) ;]

    Jaką bibliotekę w tym celu najlepiej wykorzystać i na co zwrócić uwagę jeżeli oba wątki mają dostęp do RS232 (jeden do jego zapisu a drugi do jego odczytu). A może w czystym WinAPI?
  • #53
    LED5W
    Level 33  
    Jeśli już piszesz w WinAPI to czemu by tego nie kontynuować? Ale Twój wybór.

    Chyba nie ma przeszkód w równoczesnym wysyłaniu i odbieraniu danych. Tylko, żebyś napisał tak program, żeby się nie pogubił/zapętlił.
  • #54
    Arkain
    Level 10  
    Pytanie natury technicznej ;]

    Program zaczyna rozrastać się tak bardzo że jego przeglądanie zaczyna być kłopotliwe... Funkcje są już w osobnych bibliotekach *.h i *.cpp ale zaczyna mi przeszkadzać fakt że w głównym pliku źródłowym okna (ogno_g.cpp) jest zbyt wiele funkcji zdarzeń np. void __fastcall TOkno_Glowne::B_EEPRO_WczytClick(TObject *Sender);. Jednak w tym pliku są definicje stałych i zmiennych globalnych z których te funkcje korzystają... Jak powinno się budować takie programy okienkowe zbudowane z modułów, jak tworzyć takie moduły? Jak dzielić taki kod? Proszę o wyjaśnienie lub nakierowanie na jakiś temat/link... Dzięki.
  • #55
    JmL(TM)
    Level 24  
    Wstaw moze kod zrodlowy to bedzie latwiej "cos" z tym zrobic... :D
  • #56
    Arkain
    Level 10  
    Powróciłem do projektu więc prace znowu ruszają ;D

    Napotkałem problem związany z wątkami... Jak sprawić by wątek odnosił się do pola Edit na formatce? Słyszałem że w jednym czasie nie mogą do niego odnosić się dwa wątki... Sprawdzałem ale Edit nie posiada invoice tak jak jest to chyba w C#.

    Dokładnie to problem wygląda tak:

    Uruchamiam program jest wyświetlana pierwsza strona PageControl na której są wykresy. Wybieram port COM i wątek odczytu z RS-232 rusza do akcji. Wątek chodzi w nieskończoność i wewnątrz swojej pętli ma:

    Code: cpp
    Log in, to see the code



    I jak jestem na stronie na której niema tego pola Edit to wszystko działa. Jak zmienię PageControl na stronę z kontrolką to wyskakuje:

    Quote:
    First chance exception at $771B17B0. Exception class $C0000005 with message 'access violation at 0x771b17b0: read of address 0xffffffff'.


    I odnosi się to tylko do pola Edit które wskazałem oba niżej które również są na tej samej stronie co poprzedni ale one nie powodują błędów.

    Jeżeli jednak po uruchomieniu programu najpierw zmienię stronę i Edit się narysuje i wrócę do głównej i włączę wątek to problemu niema :/

    Jak to rozwiązać bo nie mam już posłów.

    I czy znacie jakieś tutoriale o wątkach najlepiej pl w których wytłumaczone jest jak wątek ma "rozmawiać" z kontrolkami?
  • #57
    LED5W
    Level 33  
    Jaki typ mają Okno_Glowne->E_Ile_w_Kol_Pak_wys->Text, wys_pak, wys_pak_ble i jaki typ zwraca Pakiet_wys.size()?
  • #58
    Arkain
    Level 10  
    Zwykła kontrolka Edit E_Ile_w_Kol_Pak_wys->Text przyjmuje unicodestring,

    Pakiet_wys.size() zwraca _Container::size_type (normalna kolejka STL)

    wys_pak to int i wys_pak_ble tez int.

    Gdy wszystko było jeszcze kiedyś w Timerze to działało bez zająknięcia ale teraz nie umiem przenieść tego do wątku.
  • #59
    LED5W
    Level 33  
    Nie było pytania.

    Z tymi kolejnymi liniami na pewno nie ma problemu, czy może po prostu Pakiet_wys.size() zwraca 0 i się nie wykonują? Która zmienna miała adres 0x771b17b0?

    Generalnie obsługa całego interfejsu powinna być w jednym (głównym) wątku, a reszta w oddzielnych. Pozwoli to uniknąć kłopotów. Możesz uruchomić timer i sprawdzać postęp wątku, albo wyślij WM_USER (o ile nie będzie ich zbyt dużo). Bo i tak nic nie da odświeżanie stanu dziesiątki razy na sekundę.
  • #60
    Arkain
    Level 10  
    hmm a jak sprawdzić to jaka zmienna jest pod tym adresem? bo jedyne co udało mi się ustalić to przy tym adresie pisze: ntdll.dll a program się wykrzacza przy:

    Quote:
    771B17A8 FFFF db $ff $ff
    771B17AA 8B7D10 mov edi,[ebp+$10]
    771B17AD 8D47F8 lea eax,[edi-$08]
    771B17B0 80780705 cmp byte ptr [eax+$07],$05 <----tu
    771B17B4 7509 jnz $771b17bf
    771B17B6 0FB64806 movzx ecx,[eax+$06]
    771B17BA C1E103 shl ecx,$03


    gdzie EAX = FFFFFFF8

    A co do pozostałych to tak. One nie zawsze się wykonują ale jak kolejka jest pełna (symulacja). To nie zauważyłem by błąd się pojawiał.

    To jak mam postępować z wątkami i GUI? Chciałbym by w GUI na bieżąco była informacja w polu Edit ile zostało elementów w kolejce (z której wątek pobiera dane) i gdzie w takim razie w wątku głównym mam wstawić fragment za to odpowiedzialny? Czy może Timer który będzie aktualizował w GUI pole edit. Ale wtedy muszę chyba obsługę kolejki (odczyt i usuwanie z kolejki elementów) objąć sesją krytyczną by w wątku głównym timer mógł spokojnie sprawdzać rozmiar kolejki... Ale czy takie są właściwe sposoby postępowania jeżeli chodzi o wątki i GUI? Nie da się tego zrobić w bardziej eleganckim stylu?