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

[Delphi + Tcomport] Błędny odbiór paczki danych

wicy 19 Feb 2011 11:26 1664 9
  • #1
    wicy
    Level 22  
    Niby prosta sprawa, ale mam problem, z którym sam nie mogę sobie poradzić.

    Urządzenie zewnętrzne przesyła po RS232 5 bajtów danych odbieranych przez Tcomport w zdarzeniu OnRxChar.
    W OnRxChar wypełniam danymi tablicę poprzez comport.Read(din,count) i dalej w tym samym zdarzeniu przetwarzam sobie dane z tablicy.
    Problem w tym, że czasem przesłana 5 bajtowa paczka danych wywołuje dwa razy zdarzenie OnRxChar - raz z count=3 a drugi raz z count=2. Ostatnie zdarzenie nadpisuje mi 2 pierwsze bajty tablicy danych i psuje dalszą obsługę.
    Jak sobie z tym poradzić? Jak zapobiec wywoływaniu zdarzenia dwukrotnie albo zmusić program by przy drugim (może nawet trzecim) zdarzeniu uzupełnił tablicę danych a nie nadpisywał ją od początku?

    Dodam, że urządzenie z każdym razem wysyła paczkę 5 bajtów "ciurkiem" nie robiąc przerw w nadawaniu, więc wina leży po stronie programu.
  • #2
    User removed account
    User removed account  
  • #3
    wicy
    Level 22  
    Nie wiem czemu tak się dzieje, ale paczki zazwyczaj odbierane są przez program:
    - w jednym wywołaniu OnRxChar z count=5
    - w dwóch wywołaniach z count=3 za pierwszym razem i count=2 za drugim.

    Warunek
    Code: pascal
    Log in, to see the code

    jest spełniany za każdym razem jeśli paczka jest odebrana prawidłowo. Jeśli zaś przychodzi "podzielona" tracę ją a chciałbym ją posklejać.
  • #4
    User removed account
    User removed account  
  • #5
    wicy
    Level 22  
    No nie wiem bo....
    Przy obsłudze odbioru pozbawionej warunków, przyjście przykładowej paczki danych 112,3,8,1,18 wywołuje dwukrotnie procedurę odczytu. I mam:
    1) przy count=3 za pierwszym razem 112,3,8,x,x - pierwsze 3 bajty prawidłowe na prawidłowym miejscu. Dwa ostatnie x to pozostałość po prawidłowo odebranej poprzedniej paczce
    2) za drugim razem, count=2 dostaję 1,18,8,x,x

    Czyli za drugim razem w buforze nie ma już 112,3,8 odebranego przy pierwszym wywołaniu OnRxChar.
  • #6
    User removed account
    User removed account  
  • #7
    wicy
    Level 22  
    Nie napisałem, że za każdym razem paczka odbierana jest źle.
    Zdarza się (w 90% przypadków), że paczka odbierana jest jednym wywołaniem OnRxChar z prawidłową wartością count=5. Wtedy wypełnia tablicę din prawidłowo pięcioma bajtami np. 112,4,10,9,19.
    Jeśli kolejna transmisja jest błędna i program (nie wiem czemu) wywoła dwa razy OnRxChar, nadpisuje tablice danych od początku. Dlatego w pierwszym błędnym wywołaniu z count=3 nadpisze pierwsze 3 pozycje, pozostawiając x,x,x,9,19 na końcu tablicy. W kolejnym wywołaniu dobierze sobie te brakujące dwa bajty, ale już z count=2 i znów nadpisze tablice danych od początku, pozostawiając ostatnie 3 bajty tablicy bez zmian.

    Poradziłem sobie tymczasowo czymś takim
    Code: pascal
    Log in, to see the code

    ale nie jest to najbardziej eleganckie rozwiązanie, bo działa tylko jeśli program odbierze paczkę prawidłowo (5 bajtów) lub podzieli ją 3/2.

    Zastanawia mnie czemu to zdarzenie w ogóle odpalane jest czasem dwukrotnie?
  • #8
    krru
    Level 33  
    wicy wrote:
    Jeśli kolejna transmisja jest błędna i program (nie wiem czemu) wywoła dwa razy OnRxChar,


    To nie jest błedna transmisja.

    wicy wrote:

    nadpisuje tablice danych od początku. Dlatego w pierwszym błędnym wywołaniu z count=3 nadpisze pierwsze 3 pozycje, pozostawiając x,x,x,9,19 na końcu tablicy. W kolejnym wywołaniu dobierze sobie te brakujące dwa bajty, ale już z count=2 i znów nadpisze tablice danych od początku, pozostawiając ostatnie 3 bajty tablicy bez zmian.

    Poradziłem sobie tymczasowo czymś takim

    <ciach kod bez sensu>

    ale nie jest to najbardziej eleganckie rozwiązanie, bo działa tylko jeśli program odbierze paczkę prawidłowo (5 bajtów) lub podzieli ją 3/2.

    Zastanawia mnie czemu to zdarzenie w ogóle odpalane jest czasem dwukrotnie?



    Bo RS to transmisja znakowa. Nie istnieją tam żadne ramki. Dostajesz zdarzenie jak coś przyszło i akurat komputer ma trochę czasu. Musisz być przygotowanym na odebranie dowolnej liczby bajtów - od pojedynczych znaków do nawet kilku 'ramek' jednocześnie (chyba, że nadajnik nie nada następnej ramki bez potwierdzenia poprzedniej, ale i w takiej sytuacji stosuje się timeouty, powtórzenia itp.).
    Elegenckim rozwiązaniem jest automat stanowy, dla którego zdarzeniem jest odebranie pojedynczego znaku. Jeśli odbierzesz więcej wywołujesz ten automat kilkakrotnie, dla każdego odebranego znaku oddzielnie. A sam automat może być banalny - po prostu licznik do 5 z buforem na 5 znakow.
  • Helpful post
    #9
    User removed account
    User removed account  
  • #10
    wicy
    Level 22  
    Myślę, że problemem był zbyt długi czas obsługi zdarzenia. W tym wypadku akurat dopisane było więcej poleceń dla pewnych konkretnych danych i tylko po ich 'przyjściu' i tylko przy ich 'odczycie' OnRxChar dzielił pakiet na 2 części.

    Zastosowałem warunek
    Code: pascal
    Log in, to see the code

    i wyrzuciłem całe przetwarzanie odebranych danych do obsługi timera. Teraz wydaje się być OK. Obsługa zdarzenia trwa teraz tyle samo czasu dla każdej 'paczki' przychodzących danych i myślę, że na tyle krótko, że count zawsze będzie 5.

    Wiem, że zamiast uruchamiania timera i obróbki danych w jego przerwaniu lepiej byłoby zastosować inny wątek, ale wątków nie umiem i to już oddzielna bajka.
    Póki co dziękuję. Jeszcze będę robić testy.