• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

[JAVA ANDROID] wysyłanie tablicy bajtów przez USB po wypełnieniu jej elementami

Object Storage Arubacloud
+2 głosów
274 wizyt
pytanie zadane 1 lipca 2021 w Java przez matej1410 Nowicjusz (180 p.)

Witam serdecznie szanownych Kolegów.

 

Piszę kod w Android Studio w którym to wysyłam bajty po USB do mikrokontrolera.

Używam do tego metody przyjmującej takie argumenty:

public int write(final byte[] src, final int timeout) throws IOException;

Samo wysyłanie odbywa się tak:

port.write(tablica_czas,1000);

Gdy deklaruję i wypełniam tablicę w taki sposób:

static byte[] tablica_czas = {1,2,3,4,5,6,7,8,9};

i wysyłam ją poprzez metodę port.write to odbiera się bardzo dobrze w mikrokontrolerze pod drugiej stronie USB, natomiast kiedy wypełnie tablicę poprzez metodę klasy którą sam sobie wymyśliłem to:

tablica_czas=MojaKlasa.wypełnijTablice();

po tej operacji gdy sprawdzę tablice to co prawda znajdę tam wartości poprawne (poprawne, wpisane przez klasę), ale gdy robię:

port.write(tablica_czas,1000);

to w mikrokontrolerze dostaje tablice z samymi zerami.

Dlaczego tak się dzieje, czy ktoś podpowie? :-)

 

1
komentarz 1 lipca 2021 przez Oscar Nałogowiec (29,290 p.)

Obawiam się, że jeśli nie pokażesz tej funkcji/metody MojaKlasa.wypełnijTablice() wiele nie da się pomóc. Jeśli jest to duża funkcja lub nie chcesz ujawniać szczegółów to spróbuj stworzyć najprostszy program, w którym występuje taki sam błąd. Najprościej poprzez usuwanie kolejnych fragmentów oryginalnego programu.

Na razie dziwnie wygląda nazwa - wypełnijTablicę a nie przekazujesz tablicy do wypełnienia, natomiast podmieniasz oryginalną referencję.

2 odpowiedzi

+2 głosów
odpowiedź 1 lipca 2021 przez Wiciorny Ekspert (269,710 p.)
Bez wglądu do implementacji nie da się powiedzieć. Pamiętaj jedno o ile tego nie wiesz java - przyjmuje jedynie PARAMETRY PRZEZ WARTOŚĆ, nigdy nie jest to referencja, jeśli przyjmuje typ obiektowy jest to WARTOŚĆ REFERENCJI, A NIE CZYSTO REFERENCJA, stąd jest to kopia :)
0 głosów
odpowiedź 1 lipca 2021 przez matej1410 Nowicjusz (180 p.)

public class UstawCzas {

    public byte[] getTablicaCzasow() {
        return tablicaCzasow;
    }

    public byte[] tablicaCzasow = new byte[9];

    public UstawCzas() {}

    public void PrzypiszCzasy()
    {
        DateTime czasTerazniejszy = new DateTime();

        tablicaCzasow[0]= 0; //
        tablicaCzasow[1]= 0; // 001 to kod zapisu godziny
        tablicaCzasow[2]= 1; //

        byte rok = (byte) (czasTerazniejszy.getYear()-2000);
        byte jednostka = (byte) (rok%10);
        byte dziesiatka = (byte) ((byte) ((rok-(rok%10)))/10);
        byte heks=0;
        heks = (byte) (dziesiatka << 4);
        heks = (byte) (heks | jednostka);
        tablicaCzasow[3]= heks;

        byte miesiac = (byte) czasTerazniejszy.getMonthOfYear();
        jednostka = (byte) (miesiac%10);
        dziesiatka = (byte) ((byte) ((miesiac-(miesiac%10)))/10);
        heks=0;
        heks = (byte) (dziesiatka << 4);
        heks = (byte) (heks | jednostka);
        tablicaCzasow[4]= heks;

        byte dzien = (byte) czasTerazniejszy.getDayOfMonth();
        jednostka = (byte) (dzien%10);
        dziesiatka = (byte) ((byte) ((dzien-(dzien%10)))/10);
        heks=0;
        heks = (byte) (dziesiatka << 4);
        heks = (byte) (heks | jednostka);
        tablicaCzasow[5]= heks;

        byte godzina = (byte) czasTerazniejszy.getHourOfDay();
        jednostka = (byte) (godzina%10);
        dziesiatka = (byte) ((byte) ((godzina-(godzina%10)))/10);
        heks=0;
        heks = (byte) (dziesiatka << 4);
        heks = (byte) (heks | jednostka);
        tablicaCzasow[6]= heks;

        byte minuta = (byte) czasTerazniejszy.getMinuteOfHour();
        jednostka = (byte) (minuta%10);
        dziesiatka = (byte) ((byte) ((minuta-(minuta%10)))/10);
        heks=0;
        heks = (byte) (dziesiatka << 4);
        heks = (byte) (heks | jednostka);
        tablicaCzasow[7]= heks;

        byte sekunda = (byte) czasTerazniejszy.getSecondOfMinute();
        jednostka = (byte) (sekunda%10);
        dziesiatka = (byte) ((byte) ((sekunda-(sekunda%10)))/10);
        heks=0;
        heks = (byte) (dziesiatka << 4);
        heks = (byte) (heks | jednostka);
        tablicaCzasow[8]= heks;
    }


}

 

tu jest wypełnianie tablicy:

UstawCzas ustawCzas = new UstawCzas();
ustawCzas.PrzypiszCzasy();
tablica_czas=ustawCzas.getTablicaCzasow();

w tym miejscu gdy podglądam tablice to mam w niej wartości sensowne, natomiast w mikrokontrolerze przy wysyłaniu dostaję już zera.

i jeszcze na koniec to:

try {
       port.write(tablica_czas,1000);

         } catch (IOException e) {
            e.printStackTrace();
         }

Dziękuję Wam za zainteresowanie tematem.

 

1
komentarz 1 lipca 2021 przez Wiciorny Ekspert (269,710 p.)

nadal nie widzę ale przy okazji 

Używając tablicy, traktowanej jako parametr lub nie, należy wziąć pod uwagę, że arr[i]jest to wskaźnik do jakiegoś miejsca w pamięci. Następnie, otrzymując tablicę jako parametr, otrzymujesz nowe odniesienie wskazujące na ten sam obiekt tablicy. Oznacza to, że w Twojej metodzie instrukcje takie jak :

myParameterArray = new int[5];

nie zmodyfikuje tablicy wejściowej, ponieważ zmieniasz tylko wartość referencji, a nie wskazaną przez nią wartość. Niemniej jednak instrukcje takie jak:

myParameterArray[i] = 5;

bezpośrednio zmodyfikują tablicę wejściową.

komentarz 2 lipca 2021 przez matej1410 Nowicjusz (180 p.)

Czegoś tu nie rozumiem.

Sprawdzam zawartość tablicy przed samym wysłaniem tablicy:

Log.d("TAGCZASID1",tablica_czas[0]+"");
Log.d("TAGCZASID2",tablica_czas[1]+"");
Log.d("TAGCZASID3",tablica_czas[2]+"");
Log.d("TAGCZASrok",tablica_czas[3]+"");
Log.d("TAGCZASmiesiac",tablica_czas[4]+"");
Log.d("TAGCZASdzien",tablica_czas[5]+"");
Log.d("TAGCZASgodzina",tablica_czas[6]+"");
Log.d("TAGCZASminuta",tablica_czas[7]+"");
Log.d("TAGCZASsekunda",tablica_czas[8]+"");


try {
       port.write(tablica_czas,1000);
         } catch (IOException e) {
            e.printStackTrace();
         }

i w LOGCAT mam poprawne wartości:

2021-07-02 17:23:10.842 25900-25900/pl.sty.usb_n D/TAGCZASID1: 0
2021-07-02 17:23:10.842 25900-25900/pl.sty.usb_n D/TAGCZASID2: 0
2021-07-02 17:23:10.842 25900-25900/pl.sty.usb_n D/TAGCZASID3: 1
2021-07-02 17:23:10.842 25900-25900/pl.sty.usb_n D/TAGCZASrok: 33
2021-07-02 17:23:10.842 25900-25900/ppl.sty.usb_n D/TAGCZASmiesiac: 7
2021-07-02 17:23:10.842 25900-25900/pl.sty.usb_n D/TAGCZASdzien: 2
2021-07-02 17:23:10.842 25900-25900/pl.sty.usb_n D/TAGCZASgodzina: 23
2021-07-02 17:23:10.842 25900-25900/pl.sty.usb_n D/TAGCZASminuta: 35
2021-07-02 17:23:10.842 25900-25900/pl.sty.usb_n D/TAGCZASsekunda: 16

 

 Czyli moja klasa wypełnia poprawnie tablicę tablica_czas. Czy źle to rozumiem?

To jakby funkcja port.write() nie przyjmowała poprawnie tablicy, jakby zerowała tę tablicę w momencie wysyłania.

1
komentarz 2 lipca 2021 przez Wiciorny Ekspert (269,710 p.)
edycja 2 lipca 2021 przez Wiciorny
port.write(tablica_czas,1000);

posyłasz referencje do tablicy, 

jesli tablice tę w metodzie uzupełniasz w ten sposób np. 

tablica_czas = nowa_tablica // lub inaczej 

to wtedy nic się nie stanie, ponieważ referencja - w metodzie JEST WARTOŚCIĄ, CZYLI KOPIĄ

Natomiast uzupełniając 

tablica_czas[i] = jakas_wartosc;
tablica_czas[i+1] = jakas_wartosc2;

wtedy poprawnie wypełniasz tablice, bo tablica_czas[i] jest odniesieniem- referencją do elementu w pamięci który znajduje się pod indeksem i w obiekcie tablicy i to jego modyfikujesz, i jemu przypisujesz wartość. 

I nie odpowiem Ci w pełni poprawnie czy robisz dobrze, jeśli nie wiem jak wygląda implementacjca metody write, albo jeśli ona jest biblioteczna to z jakiej biblioteki. 

 

To jakby funkcja port.write() nie przyjmowała poprawnie tablicy,

nie znam metody która przyjmuje tablice, wrtie jeśli jest to JAVA>NIO > FILE to przyjmuje strumień bajtów więc zwraca Ci tablcie bajtów, nie mozsz tak przekazac tablicy  z danymi jako byte... musisz sam to konwertować odpowiednio dana po danej 

 

1
komentarz 2 lipca 2021 przez Wiciorny Ekspert (269,710 p.)

jesli chciałbyś zapisać tablice jako strumień, najpierw polecam konwersje jej na strumień np poprzez wykorzystanie ByteArrayInputStream(byte[]) 
https://www.baeldung.com/convert-input-stream-to-array-of-bytes

komentarz 3 lipca 2021 przez matej1410 Nowicjusz (180 p.)

@Wiciorny, dziekuję za cenne uwagi. Jeszcze dziś zabieram się za implementację.

 @Override
    public int write(byte[] src, int timeoutMillis) throws IOException {
        int offset = 0;

        while (offset < src.length) {
            final int writeLength;
            final int amtWritten;

            synchronized (mWriteBufferLock) {
                final byte[] writeBuffer;

                writeLength = Math.min(src.length - offset, mWriteBuffer.length);
                if (offset == 0) {
                    writeBuffer = src;
                } else {
                    // bulkTransfer does not support offsets, make a copy.
                    System.arraycopy(src, offset, mWriteBuffer, 0, writeLength);
                    writeBuffer = mWriteBuffer;
                }

                amtWritten = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, writeLength,
                        timeoutMillis);
            }
            if (amtWritten <= 0) {
                throw new IOException("Error writing " + writeLength
                        + " bytes at offset " + offset + " length=" + src.length);
            }

            Log.d(TAG, "Wrote amt=" + amtWritten + " attempted=" + writeLength);
            offset += amtWritten;
        }
        return offset;
    }

a to jest metoda write. 

Źródło: https://github.com/nightscout/android-uploader/blob/master/app/src/main/java/com/nightscout/android/drivers/USB/CdcAcmSerialDriver.java

 

komentarz 3 lipca 2021 przez matej1410 Nowicjusz (180 p.)
edycja 3 lipca 2021 przez matej1410

@Wiciorny, 

otworzyłem link, który podesłałeś.

Jeśli dobrze rozumiem to chodzi Ci o ten kawałek kodu:

InputStream is = new ByteArrayInputStream(new byte[] { 0, 1, 2 });
byte[] targetArray = new byte[is.available()];

Czyli jak w przykładzie:

1. Tworzymy sobie is (InputStream) z tablicy trzech bajtów.

2. Następnie tworzymy nową tablice bajtów i wpisujemy do niej bajty z InputStreama który stworzyliśmy wcześniej?

Spostrzeżenia: po wysłaniu targetArray z kawałka kodu wyżej odbieram znów same zera. To trochę masło maślane :-)

Co więcej ta funkcja:

@Override
   public int write(byte[] src, int timeoutMillis) throws IOException {
       int offset = 0;
 
       while (offset < src.length) {
           final int writeLength;
           final int amtWritten;
 
           synchronized (mWriteBufferLock) {
               final byte[] writeBuffer;
 
               writeLength = Math.min(src.length - offset, mWriteBuffer.length);
               if (offset == 0) {
                   writeBuffer = src;
               } else {
                   // bulkTransfer does not support offsets, make a copy.
                   System.arraycopy(src, offset, mWriteBuffer, 0, writeLength);
                   writeBuffer = mWriteBuffer;
               }
 
               amtWritten = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, writeLength,
                       timeoutMillis);
           }
           if (amtWritten <= 0) {
               throw new IOException("Error writing " + writeLength
                       + " bytes at offset " + offset + " length=" + src.length);
           }
 
           Log.d(TAG, "Wrote amt=" + amtWritten + " attempted=" + writeLength);
           offset += amtWritten;
       }
       return offset;
   }

przyjmuje jaką daną wejściową tablice bajtów, a o ile dobrze rozumiem zasugerowałeś aby moją tablicę bajtów przekonwertować na strumień po to, aby wysłać dzięki niemu bajty, ale funkcja wysyłająca dane nie przyjmuje jako argumentu InputStreama tylko tablice bajtów

1
komentarz 3 lipca 2021 przez Oscar Nałogowiec (29,290 p.)

Dwie uwagi do wszystkiego wyżej:

dziesiatka = (byte) ((byte) ((minuta-(minuta%10)))/10);

Jest trochę za bardzo rozbudowane. Wystarczy:

dziesiatka = (byte) (minuta/10);

Wynik będzie taki sam. Ciągle zastanawiam się czy tego kodowania BCD nie dałoby się zrobić prościej.

 

Z kolei:

InputStream is = new ByteArrayInputStream(new byte[] { 0, 1, 2 });
byte[] targetArray = new byte[is.available()];

Nie wypełni tabeli targetArray - będą same zera. Trzeba by jeszcze odczytać is.

 

komentarz 3 lipca 2021 przez matej1410 Nowicjusz (180 p.)

Oscar dziękuję za zainteresowanie tematem i zoptymalizowanie funkcji BCD.

Zmodyfikowałem kod w ten sposób:

  InputStream is = new ByteArrayInputStream(tablica_czas);
                        try {
                            targetArray = new byte[is.available()];
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        try {
                            is.read(targetArray);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }

Ale dzieje się coś dziwnego.

Jeśli przesyłam tablicę bajtów, w których żaden z elementów nie jest zerem to odbieram wszystkie bajty poprawnie jeśli natomiast wyślę coś takiego, taką tablicę:

{1,2,3,4,0,6,7,8,9} to dostaję w odbiorniku {1,2,3,4,0,0,0,0,0} albo np.:

{1,2,3,4,5,6,0,8,9} to w odbiorniku {1,2,3,4,5,6,0,0,0}

a jak wysyłam {0,2,3,4,5,6,7,8,9} to dostaje same zera {0,0,0,0,0,0,0,0,0}

czyli wszystko co po zerze jest zawsze zerowane.

 

1
komentarz 3 lipca 2021 przez Wiciorny Ekspert (269,710 p.)
https://stackoverflow.com/questions/28154369/why-dropping-leading-all-zeros-byte-in-a-java-byte-array-before-hashing
Dlatego, żę jeśli pierwsze idzie 0, traktowane jest to jako unasigned - > wiodące zero , traktowane jest pewnie jako "bajt znaku "
komentarz 3 lipca 2021 przez matej1410 Nowicjusz (180 p.)
czy to oznacza, że nie można zer przesyłać ponieważ to ucina część danych?

Jedyne co mi przychodzi do głowy to to, żeby sprawdzać tablice przed wysłaniem i w miejsce zer wpisywać ściśle określoną liczbę którą w odbiorniku traktować jako zero no i podmieniać ją po odebraniu na zero.
1
komentarz 3 lipca 2021 przez Oscar Nałogowiec (29,290 p.)
edycja 3 lipca 2021 przez Oscar

@matej1410,
 ciekawe spostrzeżenie z tymi zerami. W sumie to ten najpierwszy przykład, który podałeś na początku jako działający, nie wysyłał żadnych zer, więc nie wiadomo czy to dlatego działał, czy z powodu braku zabawy zmiennymi. Stawiam na to pierwsze. Trzeba sprawdzić w dokumentacji libUSB czy ten bulk transfer nie ma jakiś ograniczeń, choć w to wątpię, to podstawowy transfer po USB.

Czy jesteś pewny, że do tego urządzenia USB nie ma drivera od razu w kernelu i ten driver tam nie grzebie? Oglądałem przykłady użycia libUSB na komputerach destopowych i używają tam takiej konstrukcji (C).

    if(libusb_kernel_driver_active(handle, 0) == 1)    

Nie ma podobnej funkcji/metody w tej bibliotece androidowej?

 

Mam jeszcze jeden pomysł - czy możesz przedebuggować wykonanie tej funkcji write() - czy ona wysyła całość w jednym wywołaniu bulkTransfer, czy wysyła to kawałkami, jakie są wyniki poszczególnych bulkTransferów itp?

1
komentarz 3 lipca 2021 przez Wiciorny Ekspert (269,710 p.)
ja podejrzewam, że traktuje 0, jako znak zmiany "pinu" sygnału albo właśnei znak kontrolny i zeruje - robiąc odcięcie pozostałych bitow
komentarz 6 lipca 2021 przez matej1410 Nowicjusz (180 p.)

@Oscar, przepraszam za opóźnienie w odpisaniu. 

Wysyła całość w jednym wywołaniu. 

Kolejna obserwacja jest taka, że gdy wysyłam dane w drugą stronę czyli z STM32 do Smartfona to nie ma problemu z zerami.

Jeśli chodzi o wcześniej poruszany problem to rozwiązałem go tak, że zastępuję zera danym znakiem i następnie w odbiorniku wychwytuję je  i zamieniam na zera z powrotem. Pozwalam sobie na to, ponieważ w tę (problematyczną) stronę wysyłam tylko 8 bajtów natomiast w drugą aż 8kB (można wysyłać zera i odbierać je poprawnie), ale na moje szczęście jak już wspomniałem  tu problemu nie ma.

Bardzo Wam dziękuję za wszystkie cenne uwagi!

Podobne pytania

0 głosów
1 odpowiedź 123 wizyt
0 głosów
0 odpowiedzi 114 wizyt
0 głosów
0 odpowiedzi 19 wizyt

92,552 zapytań

141,399 odpowiedzi

319,534 komentarzy

61,938 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...