Wireless paper, BLE and LORA parallel clients

Hello,
I have like 2 weeks trying to solve a problem with the wireless paper

I’m unable to run the BLE client and the LoRa client at the same time,
I have also tried to run the LoRa at core0 using the xTaskCreatePinnedToCore and leave the ble interface running at core1
At some point both worked but one was blocking the other, in this case I need to receive 200sps from the ble server and 1sps from the lora server.

I need to run them in parallel and perform a data stream to my cloud server.

Any help is highly appreciated
Thank you
Martin

What is the reason & use case that requires such a high-performance data streaming? LoRa is not a streaming protocol (dutycycle, dwell time, laws and the likes) - and missing a few BLE packets during a LoRa transmission shouldn’t be too much of a problem, right?
And if you can show us what you have done so far, we might be able to comment on a possible improvement. Please paste your code, formatted within the code blocks in your post.

Ok, I have simplified my original sketch to a much shorter and readable version, this is what I’m currently trying on, both interfaces gets connected the ble streams the data and I can also receive from lora, but they got blocked by each one.

#include "BLEDevice.h"
#include "BLERemoteCharacteristic.h"
#include <Arduino.h>
#include "LoRaWan_APP.h"
TaskHandle_t lora_task1;
TaskHandle_t lora_task2;
TaskHandle_t ble_task;

/*
LORA CONFIGURATION
*/

#define RF_FREQUENCY                                915000000 // Hz

#define TX_OUTPUT_POWER                             14        // dBm

#define LORA_BANDWIDTH                              0         // [0: 125 kHz,
                                                              //  1: 250 kHz,
                                                              //  2: 500 kHz,
                                                              //  3: Reserved]
#define LORA_SPREADING_FACTOR                       7         // [SF7..SF12]
#define LORA_CODINGRATE                             1         // [1: 4/5,
                                                              //  2: 4/6,
                                                              //  3: 4/7,
                                                              //  4: 4/8]
#define LORA_PREAMBLE_LENGTH                        8         // Same for Tx and Rx
#define LORA_SYMBOL_TIMEOUT                         0         // Symbols
#define LORA_FIX_LENGTH_PAYLOAD_ON                  false
#define LORA_IQ_INVERSION_ON                        false


#define RX_TIMEOUT_VALUE                            1000
#define BUFFER_SIZE                                 30 // Define the payload size here

char txpacket[BUFFER_SIZE];
char rxpacket[BUFFER_SIZE];


static RadioEvents_t RadioEvents;

int16_t txNumber;

int16_t rssi,rxSize;

bool lora_idle = true;

/*
LORA CONFIGURATION END
*/

#define ppgData
#define BLE_server "PPG"  // starts with PPG


// the sensor service UUID
static BLEUUID FFserviceUUID("0000f0f0-0000-1000-8000-008000000000");
// The characteristic of the remote service we are interested in.
static BLEUUID FFcharUUID("0000f0f1-0000-1000-8000-00805f9b34fb");


static boolean doConnect = false;
static boolean connected = false;

//static BLEAddress* pServerAddress;
static BLEAdvertisedDevice* pServerAddress;
// last time we scanned for devices
static uint32_t last_scan = 0;

static void notifyCallback(
    BLERemoteCharacteristic * pBLERemoteCharacteristic,
    uint8_t * pData,
    size_t length,
    bool isNotify) {
    String string_data;


    for (size_t i = 0; i < length; i++) {
        if (pData[i] < 0x10) {
            string_data += "0";
        }
        string_data += String(pData[i], HEX);

    }
    // print the string_data
    Serial.print(string_data);
    Serial.println("");
}

bool connect_ble_erver() {
    Serial.println("Connecting to server..");

    bool bt_status = false;

    BLEClient* pClient = BLEDevice::createClient();

    pClient->connect(pServerAddress);

    // If we are not connected to the server, return false
    // wait 5 seconds before exiting the loop
    for (int i = 0; i < 50; i++) {
        if (pClient->isConnected()) {
            bt_status = true;
            break;
        }
        delay(100);  // wait 100ms before checking again, so 50 checkings will be 5 seconds
    }

    if (!bt_status) {
        Serial.println("Failed to connect to the ble server!");

        return false;
    } else {

        Serial.println("Connected successfully to server");
        pClient->setMTU(28);  //set client to request maximum MTU from server (default is 23 otherwise)
        Serial.println("  MTU set");

        BLERemoteService* pRemoteServiceFF = pClient->getService(FFserviceUUID);

        Serial.println("  Services Found!");
        BLERemoteCharacteristic* ppgDataCharacteristicFF = pRemoteServiceFF->getCharacteristic(FFcharUUID);

        if (ppgDataCharacteristicFF == nullptr) {
            Serial.print("  Failed to find our characteristic UUID");
            return false;
        }

        Serial.println("  Characteristics Found!");

        std::string value = ppgDataCharacteristicFF -> toString().c_str();
        Serial.print("The FF characteristic value was: ");
        Serial.println(value.c_str());


        // ppgDataCharacteristic->registerForNotify(ppgDataNotifyCallback);
        ppgDataCharacteristicFF -> registerForNotify(notifyCallback);

        connected = true;
        return true;
    }
}


class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks {
    void onResult(BLEAdvertisedDevice advertisedDevice) {
        String name = advertisedDevice.getName().c_str();
        if (name.startsWith(BLE_server) && advertisedDevice.isAdvertisingService(FFserviceUUID)) {
            Serial.print("Found our device: " + name + ".. preparing tasks");
            ble_device_name = name.c_str();
            advertisedDevice.getScan()->stop();
            //pServerAddress = new BLEAddress(advertisedDevice.getAddress());
            pServerAddress = new BLEAdvertisedDevice(advertisedDevice);
            ble_device_found = true;
            doConnect = true;

            if (connect_to_ble_cloud_server){
                connect_cloud_ble_server();
            }
            Serial.println("Device found. Connecting to: "+ String(ble_device_name));
        } else {
            Serial.println("Detected unknown device: " + name);
        }
    }
};

void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr )
{
    rssi=rssi;
    rxSize=size;
    memcpy(rxpacket, payload, size );
    rxpacket[size]='\0';
    Radio.Sleep( );
    Serial.printf("\r\nreceived packet \"%s\" with rssi %d , length %d\r\n",rxpacket,rssi,rxSize);
    //postData(rxpacket);
    lora_idle = true;
}

void init_lora(void *dummy_param){
    txNumber=0;
    rssi=0;

    RadioEvents.RxDone = OnRxDone;
    Radio.Init( &RadioEvents );
    Radio.SetChannel( RF_FREQUENCY );
    Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR,
                    LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH,
                    LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON,
                    0, true, 0, 0, LORA_IQ_INVERSION_ON, true );
}

void handling_lora(void *dummy_param){
    while(1){
        if(lora_idle)
        {
            lora_idle = false;
            Serial.println("into RX mode");
            Radio.Rx(0);
        }
        Radio.IrqProcess();
    }
}

// scan for devices
void scan_ble_devices() {
    Serial.println("Scanning for ble devices...");

    /*
    if (ble_interface_initiated) {
        // deinit
        BLEDevice::deinit(false);
    }
    */

    BLEDevice::init("");
    BLEScan* pBLEScan = BLEDevice::getScan();
    pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
    // Serial.println("debug1");
    pBLEScan->setActiveScan(true);
    // Serial.println("debug2");
    pBLEScan->start(5, false);
    // Serial.println("debug3");
    // Serial.println("Client ready");
    last_scan = millis();
    ble_interface_initiated = true;
    Serial.println("Ble scanner active");

}

void setup() {
    Serial.begin(115200);
    delay(5000);

    Mcu.begin(HELTEC_BOARD,SLOW_CLK_TPYE);


    // if (ssid != "" || password != ""){
    if (setup_mode == false) {
        // working lora at core 1
        init_lora(NULL);
        xTaskCreatePinnedToCore(
                        handling_lora,
                        "handling_lora",
                        10000,
                        NULL,
                        1,
                        &lora_task2,
                        0);
        //*/

        scan_ble_devices();

    }
}


void loop() {
    if (! setup_mode){

        ///*
        if (doConnect == true) {
            if (connect_ble_erver()) {
                Serial.println("We are now connected to the BLE Server.");
                Serial.println("Streaming BLE Device: " + String(ble_device_name));
                connected = true;
            } else {
                Serial.println("Failed to connect to the BLE server!");
            }
            doConnect = false;
        } else {
            // if 10 seconds has passed since the last scan, scan again
            if (millis() - last_scan > 10000) {
                scan_ble_devices();
            }
        }
    }
}

You didn’t answer my other question yet :wink:

Do you mean that LoRa & BLE connect to their appropriate end points?

In your code it prints it to the serial port, it’s not sent anywhere ‘useful’. Is this the intention or are you trying to send it out over LoRa?

I can’t see a LoRa send function or the handling_lora task code.

I suspect that this won’t compile as there doesn’t appear to be a connect_to_ble_cloud_server variable/flag/#define or a connect_cloud_ble_server() function either, so it’s hard to see the the flow of code.

The double spacing in the pasted code makes it hard to read on ageing voluntary eyeballs.

How can you tell? What does that look like on the serial log?

Why is this needed but not used?

I’m not using the lora as a streaming protocol, from lora I just need 1 message per second, for ble I do need 200 messages per second

correct, they does

each, the ble and the lora sends the data to the cloud server, that part works well, but I removed it because I just need help trying to get both interfaces running in parallel at the moment

I have edited the code, sorry, missed to add it

Do you want a version that compiles? I just simplified my original sketch because it is like 700 lines of code, I can make a clean and compilable version for your testing, but at this moment the code posted here is almost the same that I use to make my tests, just removed a bunch of unuseful blocks of code

Fixed it, sorry

it is very rare to see on the serial port the ble messages from the server, but I do see the lora messages every second, so, my conclusion is, the ble it’s getting blocked by the lora for some reason

because I forget to remove it in the simplified version, it is removed now

It’s so very hard to advise when there are obviously other things going on - two LoRa tasks and a BLE task handler but not used and we have no idea what the BLE & LoRa devices that are being listened to are & actually what the update frequency is of the unknown sensors or the payload size etc etc.

And for a radio gateway you are using a Wireless Paper module - does that come in to the mix?

The best way to debug this is to create totally separate apps for each radio you want to listen with, without complicating things with the tasks as both BLE & LoRa use callbacks, see how they perform and then bring them together.

That said, getting BLE and a WiFi client running simultaneously isn’t trivial - one radio, one antenna, only one can work at a time, so you are going to have to disconnect from the BLE service to send anything out over WiFi. And when LoRa wants to send a packet, it will need to organise itself with the BLE service to disconnect and send. Maybe a queue for payload sends via WiFi is indicated.

that is the answer I was waiting for, I already know this, but I was looking for a confirmation or any other idea that was beyond my knowledge, the code is dirty, it is just in my testing stage, in the end it will look different

Thank you
Martin

I’m still trying to figure it out.

The WiFi and the BLE uses the same antenna, but the lora uses a different one, the SX1262 chip transceiver.
The problem are the callbacks, they are being executed by the same core, and got blocked by each one.
That’s my understanding in my limited electronics knowledge.
Please advice.

Thank you

Callbacks are entirely software and can’t block each other. The electronics aren’t an issue - they will do as they are told, you just have to write code to consider that BLE & WiFi are using the same radio.

You’ve not said which callbacks are being blocked so super very extra hard to comment. Can you show how you know they are being blocked.