Soru Android: BLE tarafından veri gönderme> 20 bayt


Harici bir BLE cihazına bağlayarak 20 bayta kadar veri gönderebiliyorum. 20 bayttan daha büyük verileri nasıl gönderirim. Verileri parçalara ayırmamızı veya gerekli parçaları parçalara ayırmamızı okudum. Verilerimin 32 bayt olduğunu varsayarsam, bu çalışma için kodumda yapmam gereken değişiklikleri söyleyebilir misiniz? Aşağıdaki kodları kodumdan takip edebilirsiniz:

public boolean send(byte[] data) {
    if (mBluetoothGatt == null || mBluetoothGattService == null) {
        Log.w(TAG, "BluetoothGatt not initialized");
        return false;
    }

    BluetoothGattCharacteristic characteristic =
            mBluetoothGattService.getCharacteristic(UUID_SEND);

    if (characteristic == null) {
        Log.w(TAG, "Send characteristic not found");
        return false;
    }

    characteristic.setValue(data);
    characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
    return mBluetoothGatt.writeCharacteristic(characteristic);
}

Bu, verileri göndermek için kullandığım kod. "Gönder" işlevi aşağıdaki onclick olayında kullanılır.

sendValueButton = (Button) findViewById(R.id.sendValue);
    sendValueButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            String text = dataEdit.getText().toString();                           
            yableeService.send(text.getBytes());
        }
    });

Ne zaman String text 20 bayttan daha büyükse, sadece ilk 20 bayt alınır. Bu nasıl düzeltilir?

Birden çok özellik göndermeyi test etmek için şunu denedim:

sendValueButton = (Button) findViewById(R.id.sendValue);
sendValueButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        String text = "Test1";                           
        yableeService.send(text.getBytes());

        text = "Test2";                           
        yableeService.send(text.getBytes());

        text = "Test3";                           
        yableeService.send(text.getBytes());
    }
});

Ama sadece "Test3", yani son karakteristik aldım. Ne hata yaptım? BLE'ye yeni geldim, lütfen herhangi bir naifliği göz ardı edin

Düzenle:

Cevap kabul ettikten sonra Bunu daha sonra gören herkes için.

Var iki Bunu gerçekleştirmenin yolları. 1. Verilerinizi bölün ve seçilen cevapta olduğu gibi bir döngü halinde yazın. 2. Verilerinizi bölün ve geri arama özelliğini kullanarak yazabilirsiniz. onCharacterisitcWrite(). Bu, yazma sırasında herhangi bir sorun olsaydı sizi hatalardan kurtaracak.

Fakat en önemli yazarlar arasında Thread.sleep(200) eğer sadece yazıyor ve firmware'den bir cevap beklemiyorsanız. Bu, tüm verilerinizin ulaşmasını sağlayacaktır. Olmadan sleep Her zaman en son paketi aldım. Kabul ettiği cevabı görürseniz, o da kullandı sleep arasında.


36
2018-06-10 07:53


Menşei


Ayrılmayı denedin mi data 20 baytlık yığınlar halinde oluşturup birden çok oluşturup gönderebilirsiniz BluetoothGattCharacteristic her yığın için bir döngüde? - Smutje
Ayrı ayrı denediğim şey onclick'te metni üç kez değiştirdim (önceden tanımlanmış bazı sabitler) ve yableeService.send(text.getBytes()); üç kere. Ama bu sadece ilk özelliği gönderdi, bundan sonra hiçbir şey yoktu. Eğer yanlış yaparsam ne yapmam gerektiğini söyleyebilir misin? - Ankit Aggarwal
@Smutje: Düzenlenmiş cevabımı görün. Başka ne yapabilirim? - Ankit Aggarwal
Tam kodunuzu paylaşabilir misiniz? - User Android
Bir MTU güncellemesi talep edebilir ve daha sonra tüm veri paketini bir kerede gönderebilirsiniz. Şu anda en fazla 512 bayt gönderebileceğinizi düşünüyorum (bir pakette). Bundan bahseden 2 veya daha fazla cevap olduğuna inanıyorum. - FoxDonut


Cevaplar:


BLE en fazla 20 bayt aktarmanıza izin verir.

Daha fazla 20 bayt göndermek isterseniz, dizi baytını [] tanımlamanız gerekir, kaç paket istediğinizi içerir.

Örnek <160 karakter (160 bayt) göndermek istiyorsanız iyi çalıştı.

p / s: Düzenlemeyi istediğiniz gibi takip edelim. Beni tam olarak takip etmedim.

Aslında, BLE kullandığımızda, mobil tarafın ve ürün yazılımı tarafının her iki taraftaki bağlantı kapısını tanımlamak için Anahtarı (örn. 0x03 ...) oluşturması gerekir.

Fikir şu:

  • Hala transfer paketlerine devam ettiğimizde, sonuncusu değil. Kapı byte[1] = 0x01.

  • Sonuncuyu gönderirsek, kapı byte[1] = 0x00.

Veri yapısı (20 bayt):

1 - Byte 1 - Tanımla Gate ID : örn. Mesaj kapısı kimliği byte[0] = 0x03.

2 - Byte 2 - Tanımla recognization : Son paket mi 0x00 veya paket göndermeye devam etmek 0x01.

3 - Byte 3 (Eksi sonra 18 bayt olmalı Byte 1 & Byte 2) - Mesaj içeriğini buraya ekleyin.

Aşağıdaki kodu okumadan önce mantığımı anlamalı lütfen.

Aşağıda, birçok paketle, her bir pakette: byte [20] mesajıyla ilgili örnek verilmiştir.

private void sendMessage(BluetoothGattCharacteristic characteristic, String CHARACTERS){
        byte[] initial_packet = new byte[3];
        /**
         * Indicate byte
         */
        initial_packet[0] = BLE.INITIAL_MESSAGE_PACKET;
        if (Long.valueOf(
                String.valueOf(CHARACTERS.length() + initial_packet.length))
                > BLE.DEFAULT_BYTES_VIA_BLE) {
            sendingContinuePacket(characteristic, initial_packet, CHARACTERS);
        } else {
            sendingLastPacket(characteristic, initial_packet, CHARACTERS);
        }
    }

private void sendingContinuePacket(BluetoothGattCharacteristic characteristic,
            byte[] initial_packet, String CHARACTERS){
        /**
         * TODO If data length > Default data can sent via BLE : 20 bytes
         */
        // Check the data length is large how many times with Default Data (BLE)
        int times = Byte.valueOf(String.valueOf(
                CHARACTERS.length() / BLE.DEFAULT_BYTES_IN_CONTINUE_PACKET));

        Log.i(TAG, "CHARACTERS.length() " + CHARACTERS.length());
        Log.i(TAG, "times " + times);

        // TODO
        // 100 : Success
        // 101 : Error
        byte[] sending_continue_hex = new byte[BLE.DEFAULT_BYTES_IN_CONTINUE_PACKET];
        for (int time = 0; time <= times; time++) {
            /**
             * Wait second before sending continue packet 
             */
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if (time == times) {
                Log.i(TAG, "LAST PACKET ");

                /**
                 * If can not have enough characters to send continue packet,
                 * This is the last packet will be sent to the band
                 */

                /**
                 * Packet length byte :
                 */
                /**
                 * Length of last packet
                 */
                int character_length = CHARACTERS.length()
                        - BLE.DEFAULT_BYTES_IN_CONTINUE_PACKET*times;

                initial_packet[1] = Byte.valueOf(String.valueOf(character_length
                        + BLE.INITIAL_MESSAGE_PACKET_LENGTH));
                initial_packet[2] = BLE.SENDING_LAST_PACKET;

                Log.i(TAG, "character_length " + character_length);

                /**
                 * Message
                 */
                // Hex file
                byte[] sending_last_hex = new byte[character_length];

                // Hex file : Get next bytes
                for (int i = 0; i < sending_last_hex.length; i++) {
                    sending_last_hex[i] = 
                            CHARACTERS.getBytes()[sending_continue_hex.length*time + i];
                }

                // Merge byte[]
                byte[] last_packet = 
                        new byte[character_length + BLE.INITIAL_MESSAGE_PACKET_LENGTH];
                System.arraycopy(initial_packet, 0, last_packet,
                        0, initial_packet.length);
                System.arraycopy(sending_last_hex, 0, last_packet, 
                        initial_packet.length, sending_last_hex.length);

                // Set value for characteristic
                characteristic.setValue(last_packet);
            } else {
                Log.i(TAG, "CONTINUE PACKET ");
                /**
                 * If have enough characters to send continue packet,
                 * This is the continue packet will be sent to the band
                 */
                /**
                 * Packet length byte
                 */
                int character_length = sending_continue_hex.length;

                /**
                 * TODO Default Length : 20 Bytes
                 */
                initial_packet[1] = Byte.valueOf(String.valueOf(
                        character_length + BLE.INITIAL_MESSAGE_PACKET_LENGTH));

                /**
                 * If sent data length > 20 bytes (Default : BLE allow send 20 bytes one time)
                 * -> set 01 : continue sending next packet
                 * else or if after sent until data length < 20 bytes
                 * -> set 00 : last packet
                 */
                initial_packet[2] = BLE.SENDING_CONTINUE_PACKET;
                /**
                 * Message
                 */
                // Hex file : Get first 17 bytes
                for (int i = 0; i < sending_continue_hex.length; i++) {
                    Log.i(TAG, "Send stt : " 
                            + (sending_continue_hex.length*time + i));

                    // Get next bytes
                    sending_continue_hex[i] = 
                            CHARACTERS.getBytes()[sending_continue_hex.length*time + i];
                }

                // Merge byte[]
                byte[] sending_continue_packet = 
                        new byte[character_length + BLE.INITIAL_MESSAGE_PACKET_LENGTH];
                System.arraycopy(initial_packet, 0, sending_continue_packet, 
                        0, initial_packet.length);
                System.arraycopy(sending_continue_hex, 0, sending_continue_packet, 
                        initial_packet.length, sending_continue_hex.length);

                // Set value for characteristic
                characteristic.setValue(sending_continue_packet);
            }

            // Write characteristic via BLE
            mBluetoothGatt.writeCharacteristic(characteristic);
        }
    }

public boolean writeCharacteristic(BluetoothGattCharacteristic characteristic,
            String data) {
        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
            Log.w(TAG, "BluetoothAdapter not initialized");
            return false;
        }

        if (ActivityBLEController.IS_FIRST_TIME) {
            /**
             * In the first time, 
             * should send the Title
             */
            byte[] merge_title = sendTitle(data);

            // Set value for characteristic
            characteristic.setValue(merge_title);

            // Write characteristic via BLE
            mBluetoothGatt.writeCharacteristic(characteristic);

            // Reset
            ActivityBLEController.IS_FIRST_TIME = false;

            return true;
        } else {
            /**
             * In the second time, 
             * should send the Message
             */
            if (data.length() <= BLE.LIMIT_CHARACTERS) {
                sendMessage(characteristic, data);

                // Reset
                ActivityBLEController.IS_FIRST_TIME = true; 

                return true;
            } else {
                // Typed character
                typed_character = data.length();

                return false;
            }
        }
    }

22
2018-06-12 07:07



Uygulamanızı da yazabilir misiniz onCharacteristicWrite()? Nasıl uyguladın? Ayrıca yaptım characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE); ve sen bunu yapmadım. Bu yüzden, ble cihazından cevap bekler misin? Bir cihaz istemiyorsam ne yapmalıyım? - Ankit Aggarwal
cihaz değil ama cevap - Ankit Aggarwal
Bunun gibi bir şey için, iş parçacığına rastgele bir süre uyumadan {@ code} onCharacteristicWrite () {@ code} yoluyla yanıt almanız gerektiğini düşünüyorum. Yeterince uzun uyumadığınız (a) ve (b) çok uzun uyuma riskini ortadan kaldırırsınız, bu yüzden kodunuzu kaç bayta gönderiyorsanız verimsiz hale getirirsiniz. - AllDayAmazing
Bir başkası bunu başka bir şekilde ve belki de küçük bir örnekle açıklayabilir mi? BLE paketi nedir? Herhangi biri onu uyguladıysa, lütfen kod için bağlantı gönderin. - zed
transactionLastPacket () ve setTitle () nerede bulunur. - Dheerubhai Bansal


Lollipop'ta 512 bayta kadar gönderebilirsiniz. Kullanmalısın BluetoothGatt.requestMtu() 512'lik bir değere sahiptir. Ayrıca, @Devunwired'in bahsettiği gibi, bunu yapmadan önce herhangi bir önceki işlemin tamamlanmasını beklemeniz gerekir.


19
2017-07-10 06:33



Bu yalnızca sunucudaki aygıt MTU'yu değiştirmeyi destekliyorsa geçerlidir. - Mohammad Haseeb
@MohammadHaseeb değilse ne olur? MTU ile müzakere etmek için hala bir cevap var mı? - André Fratelli
@ AndréFratelli Hayır. Sunucu yanıt vermeyen MTU'yu desteklemediğini veya desteklemediğinden yanıt alamıyorsunuz. - Mohammad Haseeb
@MohammadHaseeb haklı, müzakere yok. Önceden gerçek bir cihazla test etmek gereklidir. Ayrıca, daha büyük MTU değerlerinin kararsız olduğuna inanıyorum. - ThomasW


BLE belirtiminin yazma işlemlerinin 20 bayttan fazla olmasına izin vermediğinden eminsiniz. Eğer yükünüzü birden fazla karakteristiğe göre alt bölümlere ayıramazsanız (ki bu mantıken bakımı daha kolay olacaktır), o zaman yığınlama mekanizmanız diğer bir yaklaşımdır.

Ancak, BLE yığınının farkında olun kinler Birden çok işlemi sıraya almaya çalıştığınızda. Her bir okuma / yazma eşzamansızdır; onCharacteristicRead() veya onCharacteristicWrite() üzerinde geri arama BluetoothGattCallback örneği. Yazdığınız kod, aralarında geri arama beklemeden üç karakteristik yazma işlemi göndermeye çalışır. Kodunuzun aşağıdaki gibi bir yolu takip etmesi gerekir:

send(Test1)
  -> Wait for onCharacteristicWrite()
  -> send(Test2)
    -> Wait for onCharacteristicWrite()
    -> send(Test3)
      -> Wait for onCharacteristicWrite()
Done!

8
2018-06-10 15:07



Peki onCharacteristicWrite () nasıl çalışır? Çok fazla kod snippet'i forCharacteristicWrite () ekleyebilir misiniz? Ve aynı zamanda birden fazla karakteristikle bir örnek verebilir misiniz? send yöntem doğru mu?). İşlerime uygun olanı görmek için hızları test etmek istiyorum. Teşekkürler! - Ankit Aggarwal
Bir sonraki işlevi çağırmadan önce bir geri arama için nasıl bekleyeceğiniz konusunda iyi bir fikir vermesi gereken örnek uygulama: github.com/devunwired/accessory-samples/blob/master/... - Devunwired
OnCharacteristicWrite () üzerinde uygulanmadım. Kodunuzu inceledim ve onCharacteristicWrite () 'dan sonra okuduğunuzu görüyorum. Bunu yapmak istemiyorum, bu yüzden de @Override public void onCharacteristicWrite (BluetoothGatt gatt, BluetoothGattCharacteristic karakteristiği, int durumu) alabilir miyim? // // Etkinleştir işaretini yazdıktan sonra, ilk değer geri dönüşünü okuyoruz; } - Ankit Aggarwal
Bu geri dönüşte ne istersen yapabilirsin. Senin durumunda, bir sonraki yazıyı göndermek olurdu. - Devunwired
@Devunwired Cevabınızdaki yaklaşım, tek bir karakteristeki bir seferde 20 bayt göndermekten daha mı hızlı olacak yoksa eşdeğer bir verim mi olacak? - Sean


Burada birçok yanıltıcı var.

BLE, 20'den fazla bayttan daha fazlasını gönderebilir ve androidde kolayca yapılabilir.

Değiştirmeniz gereken şey, varsayılan olarak 23'e ayarlanmış olan MTU bağlantısıdır (sadece 20 tanesi bir değer belirlemek için kullanılabilir). Android, gönderilecek paketin geçerli bağlantı MTU'sundan daha büyük olması durumunda parçalanma mekanizması sağlar (bu, ofset parametresinin amacıdır. onCharacteristicRead(...) API).

Böylece, MTU'yu merkezi kullanımdan gelen bir talep olarak büyütebilirsiniz: requestMtu(...) API. İkincisi bir geri arama çağrısına neden olacaktır onMtuChanged Yeni MTU'yu bilgilendirecek olan çevre tarafında. Bu işlem tamamlandıktan sonra Android parçalanma mekanizmasını yayınlamadan daha büyük paketler gönderebilirsiniz.

Alternatifler kendinize kendi parçalanma mekanizmanızı inşa etmeli ve MTU'dan daha büyük olan paketleri göndermemelidir. Ya da Android mekanizmasına güvenin ve 'ofset' parametresini kullanarak onunla çalışın.


7
2018-01-16 15:42



Bu sadece Lollipop'ta ve sadece MTU boyutunu değiştiren aygıtlarda (henüz çok yaygın değil) desteklenir. Ayrıca, ofset parametresinin kullanılmasının daha büyük parçalar göndermeyle ilgisi yoktur, sadece bu ofsette okunan karakteristiğin üzerine yazar. - zed
Elbette, demek istiyorsun BluetoothGattServerCallback.onCharacteristicReadRequest(), değil BluetoothGattCallback.onCharacteristicRead(). - Albus Dumbledore


Diğer ucundaki aygıt bunu destekliyorsa, BLE Long yazmayı gerçekten tetikleyebilirsiniz.

Yazılacak yazı tipini ayarlayarak bunu yapabilirsiniz. BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT

Bu durumda 20'den fazla bayt gönderebilirsiniz.


5
2018-04-08 16:36



Bu özellik hakkında herhangi bir resmi belge var mı? Uzun yazma sadece ATT yazma talebi ile desteklenir (akran cihazından onay)? - metch
Resmi bir belge yoktur, ancak AOSP projesindeki cihaz sürücü koduna bakarsanız, kabiliyetin desteklendiğini görebilirsiniz. - Zac Siegel
Bu kodu nereden bulabilirim? Cevabınıza bir link ekleyebilir misiniz lütfen? Teşekkür ederim! - Christopher


BLE üzerinde büyük veri kümeleri göndermek istiyorsanız, en iyi seçiminiz, biri diğerinizi göndermek için diğeri son segmenti göndermek için olmak üzere iki özellik kullanmaktır. Bu şekilde, WRITE_NO_RESPONSE'ye cevabı ayarlamanıza gerek yoktur ve son bölüme gelene kadar bir sonraki parçayı tüm yolla göndermek için geri aramayı kullanmanız gerekmez. Bu noktada, bu cihazı yazacağınız ikinci özelliğe yazacaksınız. Verileri yazmayı tamamladığınız ve tüm verileri bir arada büyük bir veri paketi oluşturacak şekilde birleştirebildiğiniz.


4
2018-06-10 14:50



Üzgünüm ama havaya uçurmak için yeniyim. Fikrinizi daha önce yazdıklarımı kullanarak bir kod snippet'ini kullanarak açıklayabilir misiniz? Benim için daha net hale getirecek. - Ankit Aggarwal
Başka bir özellik yapmalı mıyım send yöntem? Pls koduyla açıklar. - Ankit Aggarwal
İkinci yöntemde başka bir özellik yapamazsınız, gönderdiğiniz aygıt, son veri segmentini dinlemek için kullandığı başka bir özelliğe sahip olmak zorundadır. Verilerin tamponlanması BLE cihaz tarafında gerçekleşmelidir. Verileri, büyük veri paketleriyle çalışmak üzere tasarlanmış olarak mı gönderiyorsunuz? - Zomb
Emin değilim. Bunu onaylamalıyım. Ama bu mümkün değilse, o zaman diğer cevap mümkün mü? Verileri sıraya mı koyuyor? - Ankit Aggarwal
Verileri sıraya alabilirsiniz, ancak cihazın birden çok yazma yoluyla çok büyük miktarda veri gönderiyor olduğunuzu anlaması gerekir. Eğer veriyi bölebiliyorsan, o zaman aşağıda @Devunwired gibi yazman gerekiyor. Nasıl çalıştığını anlamak için, Android'in sahip olduğu geri çağırma mekanizmasını, onCharacteristicWrite öğesinin nasıl çalıştığını da dahil etmelisiniz. Buradaki örnek üzerinden çalışmanızı tavsiye ederim: developer.android.com/guide/topics/connectivity/... - Zomb


Bir MTU güncellemesi talep etmeniz gerekiyor. Bu maksimum iletim ünitesidir. Şimdi olduğu gibi, BLE tek bir pakette 512 bayta kadar kabul eder. Ancak, bu MTU güncellemesini talep etmeden, cihazınız şu anda 23 baytlık bir paket göndermeyecektir (şu anda).


BluetoothGatt nesne çağrınızı kullanma requestMtu ()

Burada bir bağlantı geliştiricinin sayfasına

enter image description here


BluetoothGattCallback alacak onMtuChanged () Aşağıda gösterildiği gibi olay. Başarılı bir MTU güncellemesi üzerine, verileri bir paket olarak gönderebilirsiniz. Burada bir bağlantı Bu geliştirici sayfasına.

enter image description here


Genelde requestMtu () yöntemine bağlandıktan sonra karakteristik yazmak istediğim İyi şanslar.


1
2018-02-25 04:55





Bu, chunk yöntemini kullanarak uygulama örneğidir, ancak kullanmadan Thread.sleep Uygulamamın 20 bit veriden daha fazlasını göndermesinin daha iyi ve verimli olduğunu buldum.

Paketler sonra gönderilecekonCharacteristicWrite() tetiklemiştir. Ben sadece bu yöntem periferik cihazdan sonra otomatik olarak tetikleneceğini öğrendim (BluetoothGattServer) bir gönderir sendResponse() yöntem.

İlk olarak, paket işlevini bu işlevle yığın haline getirmek zorundayız:

public void sendData(byte [] data){
    int chunksize = 20; //20 byte chunk
    packetSize = (int) Math.ceil( data.length / (double)chunksize); //make this variable public so we can access it on the other function

    //this is use as header, so peripheral device know ho much packet will be received.
    characteristicData.setValue(packetSize.toString().getBytes());
    mGatt.writeCharacteristic(characteristicData);
    mGatt.executeReliableWrite();

    packets = new byte[packetSize][chunksize];
    packetInteration =0;
    Integer start = 0;
    for(int i = 0; i < packets.length; i++) {
        int end = start+chunksize;
        if(end>data.length){end = data.length;}
        packets[i] = Arrays.copyOfRange(data,start, end);
        start += chunksize;
    }

Verilerimiz hazırlandıktan sonra, yinelememi bu işleve koydum:

@Override
    public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        if(packetInteration<packetSize){
        characteristicData.setValue(packets[packetInteration]);
        mGatt.writeCharacteristic(characteristicData);
            packetInteration++;
        }
    }

0
2017-12-21 02:04