Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

C# - Odbieranie danych z COM'a, przepełnienie bufora?

party_pok_er 30 Lip 2012 13:54 4518 31
  • #1 30 Lip 2012 13:54
    party_pok_er
    Poziom 7  

    Witam mam taki problem z którym muszę się uporać. Mianowicie odbieram dane po RS-232 taką funkcją:

    Kod: csharp
    Zaloguj się, aby zobaczyć kod

    Zastanawiam się czy istnieje jakieś ograniczenie przesyłanych danych tzn. wysyłam np 42 znaki przez COM'a i jak chcę to wyświetlić w różnych textboxach to wyskakuje błąd że index wykracza poza granicę tablicy. gdy wysyłam znaków max 32 jest ok jak więcej to się sypie. czy ktoś wie jak to rozwiązać ?

    0 29
  • #2 30 Lip 2012 22:43
    gaskoin
    Poziom 38  

    A mógłbyś pokazać kod wstawiania tego w różne textboxy ? Nie pokazałeś kodu który sprawia problemy, nie ma tu żadnej tablicy, poza której indeks mógłby wyjechać :) Btw masz delegata MethodInvoker, ma właściwie taką samą konstrukcję jak EventHandler ale jakoś ładniej wygląda przy invoku.

    0
  • #3 31 Lip 2012 16:56
    party_pok_er
    Poziom 7  

    No więc

    Kod: csharp
    Zaloguj się, aby zobaczyć kod

    program do odbierania po RS'ie mam stąd:
    http://csharp.simpleserial.com/

    Raczej nie chodzi tu jednak o RxString tylko to moje tab_str[]. Do jednego texboxa odbieram elegancko wszystko dowolną ilość znaków ale jak to tu podzielę na te textboxy czy to 8 czy 4 to w sumie nie może w nich razem być więcej niż 32 znaki (razem ze znakiem "spacji ")

    0
  • #4 31 Lip 2012 17:10
    gaskoin
    Poziom 38  

    Pomijam fakt bezsensowności 90% kodu jaki napisałeś i skupię się na problemie:

    party_pok_er napisał:

    Kod: csharp
    Zaloguj się, aby zobaczyć kod


    Ten kod jest zapewne wzięty z innego tematu (nawet domyślam się którego) i on nie zadziała tak jak chcesz. Skąd pewność, że po splicie tablica będzie miała 8 elementów ? Nie ma znaczenia to, że ją zadeklarowałeś jako tablica 8 elementowa, ponieważ Split zwróci nowy obiekt tablicy, który równie dobrze może mieć rozmiar 0 albo i 100000. Nie ma znaczenia też to, że do kompa wysyłasz ciąg 1 12 123 1234 12345 123456 78 91011, bo on czym będzie dłuższy, tym większe prawdopodobieństwo, że przyjdzie pocięty na kawałki, np w co gorsza takiej postaci: 1 12 12|3 1234 1234|5 12345|6 78 9|10|11. U Ciebie właśnie tak się dzieje, tyle, że odbierasz którąś jego tylko część, która nie ma 8 elementów. Jak w przykładzie - odbierasz 1 12 12, robisz Splita, który zwraca 3 elementy i odwołujesz się do 8 elementu.

    Jeśli ramka ma stałą długość możesz ustawić property ReceivedBytesThreshold na wartość równą długości ramki w bajtach. Jak nie ma stałej długość, to zajrzyj do tematu z którego wziąłeś ten przegienialny kod i zastosuj się do moich wskazówek.

    PS - dlaczego nie używasz debugera ? Gdybyś go użył, to byś od razu zobaczył co się dzieje.

    0
  • #5 31 Lip 2012 17:19
    party_pok_er
    Poziom 7  

    kod sam "wymyśliłem" bo skoro wysyłam jakiś strumień i są tam spacje separujące to sobie splitem mogę podzielić. Ktoś mi sugerował zastosowanie tablic dynamicznych to jest dobry kierunek ? Dlaczego aż 90% jest bez sensu. ramka jest różna raz może przyjść 20znaków raz 80. Dobrze to działało mi na początku nie potrzebowałem powyżej 32 znaków ale się plan zmienił i nie działa tak jak trzeba.

    0
  • #6 31 Lip 2012 17:25
    gaskoin
    Poziom 38  

    No to zobacz tutaj:

    https://www.elektroda.pl/rtvforum/viewtopic.php?p=11117601#11117601

    Co warto by zmienić - metodę Clear, po grzyba czyścić tak te textboxy ? Jak zastosujesz się do porady nr 1 z postu podlinkowanego to możesz to zrobić w pętli. Można to też zrobić inaczej bardzo elegancko, ale wymaga to trochę gimnastyki, opis znajduje się tutaj: https://www.elektroda.pl/rtvforum/viewtopic.php?p=10822786#10822786 . Jest tam trochę inny przykład ale można tutaj zrobić podobnie. Robisz sobie obiekt do zbindowania, w którym masz stringi (czy wartości liczbowe, cokolwiek). Podpinasz je do textboxów, i zamiast czyścić wszystkie textboxy, wkładasz "świeży" obiekt do binding source. Możesz też zrobić w takim widoku metodę, która wypełni dane, wpiszą się one magicznie same wtedy do tekstboxów. Generalnie warto to znać i używać :)

    To co jeszcze jest takie sobie - RXString. Można go przekazać w parametrze zamiast przez pole.

    I jeszcze ciekawostka, o której mało kto pewnie wie :)

    Kod: csharp
    Zaloguj się, aby zobaczyć kod


    Po takim zabiegu, property IsOpen zawsze będzie false, bo ono nie wskazuje faktycznego stanu portu, tylko wskazuje, czy wcześniej nie wywołałeś na obiekcie SerialPort metody Open() . Tak więc jak coś innego w międzyczasie zajmie port to niestety nie zostanie to wykryte. Jak uruchomisz równolegle dwa takie programy i w jednym otworzysz port, to drugi i tak będzie wskazywał, że port nie jest otwarty. No i btw takie rzeczy jak numer portu i szybkość transmisji można wrzucić do pliku konfiguracyjnego zamiast zaszywać to w kodzie. Jak nie wiesz jak, to też mogę to opisać.

    0
  • #7 31 Lip 2012 18:15
    party_pok_er
    Poziom 7  

    Ok bardzo fajnie że chcesz pomóc. Ale mi nie zależy tak bardzo na tym żeby było ładnie i full profesjonalnie tylko na tym żeby działało po najmniejszej linii oporu. Z tego co tam widziałem to jest to trochę wymagające a nie o to mi chodzi żebym się zawiesił na próbie napisania jakiegoś kodu. Wszystko powoli bez pośpiechu (jeśli chodzi o zawiłość kodu) ale oczywiście doceniam Twoją pomoc będzie na przyszłość.
    Wracając do tematu jak ten swój problem rozwiązać najprościej? Kolekcją? to są właśnie tablice dynamiczne? Jeżeli nie ma innej drogi prócz tej którą napisałeś w tamtych postach to czy mógłbyś poprowadzić mnie tak krok po kroku bardziej szczegółowo?

    0
  • #8 31 Lip 2012 18:36
    gaskoin
    Poziom 38  

    Najprościej to rozwiązać tak jak napisałem w podlinkowanym temacie. Cały problem polega na tym, że jeśli wyślesz liczbę 123 to nie masz pewności, że przyjdzie ona w całości, możesz to odebrać jako dwie liczby - 12 i 3. Wszystkie tablice w c# są dynamiczne. Jeśli chodzi o zmienianie rozmiaru to tak, właśnie chodzi o kolekcje, ale one nie rozwiążą Twojego problemu, bo trzeba zmienić podejście do problemu. Tak jak napisałem zajrzyj tutaj:

    gaskoin napisał:


    party_pok_er napisał:
    Jeżeli nie ma innej drogi prócz tej którą napisałeś w tamtych postach to czy mógłbyś poprowadzić mnie tak krok po kroku bardziej szczegółowo?


    W powyższym temacie opis jest bardziej szczegółowy, jak zaczniesz go realizować to się zorientujesz, że jest to w istocie dość proste. Idea jest taka, że buforujesz ramki (splitując) tak długo, aż nie będziesz miał wszystkich danych do wyświetlenia. Trochę gimnastyki jest z tego względu, że dane właśnie jak u Ciebie mogą przyjść w kawałkach.

    Można to zrobić wiele prościej, ale z tego co piszesz, to wolisz się męczyć niż napisać trochę kodu więcej i mieć spokój. Generalnie podejść może być kilka, ale nie mam tyle czasu żeby pisać artykuły na forum, do których i tak nikt nie zajrzy :) Wiem, że dopiero pewnie raczkujesz, ale jeśli będziesz się dłużej zajmował programowaniem, to Ciebie też niektóre rzeczy będą raziły w oczy.


    Gwoli wyjaśnienia:

    1. i 2. - to zwykłe dodanie dwóch kolekcji, tablic, czy czegotam sobie chcesz.

    3. Split (tak jak masz teraz), ale zamiast wpisywania do textboxów robisz kilka rzeczy jeszcze w międzyczasie, tzn - zapisujesz go w tablicy, trzeba tu sprawdzić warunek który napisałem w poście i go zapisać do jakiegoś boola (mówi on o tym czy dane się pocięły). No i na koniec sprawdzenie warunku czy mamy wystarczającą ilość danych żeby je wpisać w textboxy. Jeśli tak to wpisujemy.

    Nie wydaje mi się to skomplikowane. Krokowo spokojnie do tego dojdziesz.

    0
  • #9 31 Lip 2012 19:33
    party_pok_er
    Poziom 7  

    Cytat:
    aż nie będziesz miał wszystkich danych do wyświetlenia

    ale tu chodzi o to że te dane przychodzą bez przerwy i tu nie ma określonego końca transmisji, zbieram 8 danych(np.ab2 2e 0 21s 24sw 5ac 0 0) wypisuję je potem znowu zbieram 8 wypisuję itd. dobrze to rozumie? zakładasz że po 8 danych jest koniec?

    0
  • #10 31 Lip 2012 19:43
    gaskoin
    Poziom 38  

    Nie koniec, tylko po 8 danych wciskam je do text boxów i czekam na kolejne 8. Przecież nigdzie nie napisałem, że kod się wykonuje raz, tym bardziej, że jest w handlerze, którego przecież nigdzie Ci nie każę usuwać. Można to przerobić też na kod, który wpisuje na bieżąco, ale trzeba trzymać w pamięci indeks textboxa do którego wpisaliśmy/wpisujemy ale jest tu trochę więcej gimnastyki. Tak jak opisałem jest trochę prościej i skoro wysyłasz dane bez przerwy to i tak nie zobaczysz różnicy. Zamiast się zastanawiać to już dawno byś to napisał. Najwyżej potem sobie to przerobisz na wpisywanie na bieżąco, przerobienie będzie raczej bezbolesne.

    0
  • #11 31 Lip 2012 20:00
    party_pok_er
    Poziom 7  

    Zainteresowałem się kolekcją ArrayList. Tego należy użyć?
    Stworzyłem coś takiego ale kompletnie intuicyjnie z Twojego postu z linku oraz msdn

    Kod: csharp
    Zaloguj się, aby zobaczyć kod

    ewentualnie to i to też się kompiluje (oczywiście):
    Kod: csharp
    Zaloguj się, aby zobaczyć kod


    Więc użyję tego kodu w pełni od Ciebie. Ale z ciekawości czy to z ArrayList jest ok?

    0
  • #12 31 Lip 2012 20:20
    gaskoin
    Poziom 38  

    Lepiej użyć typów generycznych. Chodzi o to, że do ArrayList pakujesz cokolwiek i wyciągasz obiekt typu object. Możesz użyć obiektu List<string> lub Collection<string> (dla textboxów odpowiednio List<TextBox> lub Collection<TextBox>), implementują te same interfejsy więc można je używać zamiennie. Wtedy zamiast męczyć się z objectem, wyciągasz z kolekcji od razu rzecz o typie jaki tam jest wpakowany. Kod napisany w minute:

    Kod: csharp
    Zaloguj się, aby zobaczyć kod


    Mniej więcej tak to powinno wyglądać. Zauważ, że rozwiązanie jest o tyle fajne, że jeśli odczujesz potrzebę dodania sobie textboxa, to nie musisz zmieniać pół kodu, tylko wystarczy ten textbox dodać do kolekcji. Między innymi po to zalecałem Ci trzymanie porządku w kodzie :) Przy okazji jak masz m_TextBoxes, to możesz kod metody Clear napisać tak:

    Kod: csharp
    Zaloguj się, aby zobaczyć kod

    0
  • #13 31 Lip 2012 21:03
    party_pok_er
    Poziom 7  

    O tak... minuta powiadasz...;]
    Więc

    Cytat:
    foreach(string data in dane_ktore_przyszly.Split(' '))
    m_Buffer.Add(data);
    if(m_DataSplitted) // jesli dane byly pociete to połącz rozcięte stringi
    m_Buffer[lastItemIndex] = m_Buffer[lastItemIndex] + m_Buffer[lastItemIndex + 1];

    dane_ktore_przyszly zamienilem na ten RxString ale co to jest to m_DataSplitted? zmienna typu bool ? bo nie wiem jak ją w ogóle odnieść do pociętego RxString.

    0
  • #14 31 Lip 2012 21:07
    gaskoin
    Poziom 38  

    Tak, to jest bool.

    Popatrz sobie tego ifa poniżej. Jak przyjdą dane, ze spacją na końcu, tzn że się dane nie pocięły. Jak wtedy zrobisz splita, to ostatnim elementem będzie pusty string - stąd ten if. Jak się dane potną to na końcu będzie liczba - wtedy ustawiamy flagę, że się pocięły.

    I analogicznie w ifie zacytowanym - jeśli dane były wcześniej pocięte, to sklej ostatnią daną z poprzedniego odbioru i pierwszą z obecnego.

    0
  • #15 31 Lip 2012 21:11
    party_pok_er
    Poziom 7  

    ;] Zainicjować ją na początek na true racja ?

    0
  • #16 31 Lip 2012 21:24
    gaskoin
    Poziom 38  

    na false lub nieinicjalizować w ogóle (czyli na false :D) ;]

    0
  • #17 31 Lip 2012 21:26
    party_pok_er
    Poziom 7  

    ale bez nie rusza :]

    0
  • #18 31 Lip 2012 21:37
    gaskoin
    Poziom 38  

    A gdzie Ty to inicjalizujesz/deklarujesz ?

    0
  • #19 31 Lip 2012 21:42
    party_pok_er
    Poziom 7  

    a jako globalną na początku.

    Kod: csharp
    Zaloguj się, aby zobaczyć kod

    0
  • #20 31 Lip 2012 21:44
    gaskoin
    Poziom 38  

    A co znaczy "nie rusza" bo jakby mało mi to mówi o występowaniu problemu :)

    BTW - są pewne zasady określane przez standard języka. Jedną z nich jest na przykład to, że jak boolowskiej zmiennej globalnej nie nadasz wartości to domyślnie ma false.

    0
  • #21 31 Lip 2012 22:14
    party_pok_er
    Poziom 7  

    Nie no jest elegancko bez inicjalizacji. Zaraz sprawdzę jak śmiga tylko jeszcze invoka ogarnę.

    Dodano po 25 [minuty]:

    Jak na razie odpaliłem program bez invoke i jak wysyłam coś np. w stylu "abc 234 0 0 0 0 0 0" to powinno być ciągle w textbox1 abc w textbox2 234 itd. a tu to przelatuje przez wszystkie boxy. Nie bardzo obczaiłem jeszcze tego invoke nie wiem jak się go stosuje.
    Ogólnie to w tym miałbym go umieścić?

    Kod: csharp
    Zaloguj się, aby zobaczyć kod

    Po DataDeceived(); czy wewnątrz DataReceived(); po ShowData();

    0
  • #22 31 Lip 2012 22:20
    gaskoin
    Poziom 38  

    Zapewne DisplayText wywołujesz już invokiem, więc na grzyba Ci on drugi raz.

    Niepotrzebnie robisz tyle metod. Wystarczy 1 handler + ShowData wywołane invokiem tak samo jak jest teraz wywołany DisplayText.

    Nie możesz wysłać ramki w formacie:

    "1 2 3 4 5 6 7 8"

    Załóżmy, że wysyłasz dwie takie ramki i przychodzi Ci coś takiego:

    "1 2 3 4 5 6 7 81 2 3 4 5 6 7 8" dodaj spację po ostatnim elemencie (mój kod to zakłada) w przeciwnym przypadku nie będzie się dało rozróżnić już w ogóle co kiedy przychodzi. Wtedy nawet jak wyślesz dwie po sobie i przyjdą jako jedna (bo taki przypadek też może być) to odbierzesz "1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 ". Nie możesz na ramkę jaką wysyłasz patrzeć jako jedna całość. Musisz przyjąć, że to wszystko tak naprawdę przychodzi porozwalane i nie wiadomo kiedy, bo nie ma żadnego protokołu który nad tym panuje.

    0
  • #23 31 Lip 2012 22:37
    party_pok_er
    Poziom 7  

    Fakt ale to mój błąd, po ostatnim elemencie jest spacja a ja tego nie napisałem w poprzednim poście. Więc tak zostawiłem:

    Kod: csharp
    Zaloguj się, aby zobaczyć kod


    Ale tak jak poprzednio przelatują dane po boxach hmm .
    zmieniłem żeby wysyłało tylko "0 1 2 3 4 5 6 7 " no i spodziewamy się że każda cyfra w innym boxie będzie no ale na stałe a tu zmienia się w każdym boxie każda cyfra oczywiście pojedynczo

    0
  • #24 31 Lip 2012 22:54
    gaskoin
    Poziom 38  

    Sprecyzuj co się dzieje bo jakoś przelatywanie cyft po textboxach dziwnie mnie się kojarzy. Poza tym masz debuger więc warto go używać.

    0
  • #25 31 Lip 2012 23:03
    party_pok_er
    Poziom 7  

    C# - Odbieranie danych z COM'a, przepełnienie bufora?

    takie coś dostaje w czasie transmisji. pierwsze zdjęcie jest po pierwszym zatrzymaniu a po drugim drugie zdjęcie i jak widać w tych samych boxach są różne wartości.
    A chciałoby się uzyskać coś w tym stylu :
    box1 box3 box5 box7
    0 2 4 6
    box2 box4 box6 box8
    1 3 5 7

    0
  • #26 31 Lip 2012 23:12
    gaskoin
    Poziom 38  

    ok

    Kod: csharp
    Zaloguj się, aby zobaczyć kod


    zamień na

    Kod: csharp
    Zaloguj się, aby zobaczyć kod


    Możesz też rozszerzyć dla bezpieczeństwa warunek:

    Kod: csharp
    Zaloguj się, aby zobaczyć kod


    na:

    Kod: csharp
    Zaloguj się, aby zobaczyć kod


    I powinno śmigać jak ta lala :D

    0
  • #27 31 Lip 2012 23:19
    party_pok_er
    Poziom 7  

    :) ok rewelacja jak na razie jest ok. Zaraz sprawdzę czy ostateczny efekt jest taki jak być powinien czyli czy nie wywali błędu jak dam ponad 32 znaki .;)

    0
  • #28 31 Lip 2012 23:25
    gaskoin
    Poziom 38  

    Jeszcze jedno: zamień

    Kod: csharp
    Zaloguj się, aby zobaczyć kod


    na

    Kod: csharp
    Zaloguj się, aby zobaczyć kod

    0
  • #29 31 Lip 2012 23:27
    party_pok_er
    Poziom 7  

    C# - Odbieranie danych z COM'a, przepełnienie bufora?

    Taki efekt jest. W tym samym momencie co przed dzisiejszą ofensywą;]

    0
  • #30 31 Lip 2012 23:40
    gaskoin
    Poziom 38  

    Postaw breakpointa w tej metodzie i zobacz dlaczego tak się dzieje. U mnie wsio działa.

    0