Very long string formating

what was printed as output wasn't understood, i'd post a screenshot. BTW, i found that i could use getBytes() to read byte by byte and then copy into a char array. I'd see if it gives me a different result. Also, ble with ESP32 is quite easy, you can setup within minutes. If you have one laying around, maybe i could send you my code, flash it and download an app to send the token. Let me know if you'd be willing to try. But in all, i appreciate your help so far.

Ok, here's a chunk of code based on what you PM'd me. There are huge caveats attached to the code in that I have almost no experience with BLE and it is purely a demonstration of receiving and decoding a JSON Web Token (without the final decryption stage).

The encoded data doesn't end with a NULL char as far as I can see, so I had to put together a basic timeout so that I could assume that the whole encoded token had been received after a period of no data being received. Maybe there's some clever BLE code that does this already - I don't know (see caveat above!).

Compiled for an ESP32-CAM and tried out using the token from post #90.

/*
  Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp
  Ported to Arduino ESP32 by Evandro Copercini
  updated by chegewara and MoThunderz
*/
#include "base64.hpp"

#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

// Initialize all pointers
BLEServer* pServer = NULL;                        // Pointer to the server
BLECharacteristic* pCharacteristic = NULL;      // Pointer to Characteristic 1

// Some variables to keep track on device connected
bool deviceConnected = false;
bool oldDeviceConnected = false;

// BLE timeout (2 seconds) used to detect end of transmission
const uint32_t bleMillisTimeout = 2000;

const uint16_t maxEncBuffSize = 1700;
volatile char encDataBuff[ maxEncBuffSize ];

volatile uint16_t encBuffPtr = 0;
volatile bool bleReceiveInProgress = false;
volatile uint32_t bleCommsMillis = 0;

uint32_t currentMillis = 0;
bool tokenReceived = false;

// these arrays hold the BASE64 decoded data
char headerStr[128];
char payloadStr[2000];
uint8_t encryptedSig[128];

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
// UUIDs used in this example:
#define SERVICE_UUID          "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID_1 "0ceb186c-853a-460a-a743-8d07fd6ff031"

// Callback function that is called whenever a client is connected or disconnected
class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
    };

    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
    }
};

class CharacteristicCallBack: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic *pChar) override {
      std::string rxValue = pChar -> getValue();

      if (rxValue.length() > 0) {
        bleCommsMillis = millis();
        bleReceiveInProgress = true;

        // transfer the received data into our big encoded data array
        for (uint16_t i = 0; i < rxValue.length(); i++) {
          if ( encBuffPtr < maxEncBuffSize-1 ) {
            encDataBuff[ encBuffPtr++ ] = rxValue[i];
            // make sure it's always NULL terminated
            encDataBuff[ encBuffPtr ] = 0;
          }
        }
        Serial.println(encBuffPtr);
      }
    }
};


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

  // Create the BLE Device
  BLEDevice::init("ESP32");

  // Create the BLE Server
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  // Create the BLE Service
  BLEService *pService = pServer->createService(SERVICE_UUID);

  // Create a BLE Characteristic
  pCharacteristic = pService->createCharacteristic(
                      CHARACTERISTIC_UUID_1,
                      BLECharacteristic::PROPERTY_WRITE  |
                      BLECharacteristic::PROPERTY_NOTIFY

                    );

  // add callback functions here:
  pCharacteristic->setCallbacks(new CharacteristicCallBack());

  // Start the service
  pService->start();

  // Start advertising
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(false);
  pAdvertising->setMinPreferred(0x0);  // set value to 0x00 to not advertise this parameter
  BLEDevice::startAdvertising();
}


void loop() {
  uint16_t delimCounter = 0;
  uint16_t idx;
  char *ch;
  
  // The code below keeps the connection status uptodate:
  // Disconnecting
  if (!deviceConnected && oldDeviceConnected) {
    delay(500); // give the bluetooth stack the chance to get things ready
    pServer->startAdvertising(); // restart advertising
    //Serial.println("start advertising");
    oldDeviceConnected = deviceConnected;
  }
  // Connecting
  if (deviceConnected && !oldDeviceConnected) {
    // do stuff here on connecting
    oldDeviceConnected = deviceConnected;
  }

  // try and figure out when we may have received a complete JSON Web Token packet
  // by assuming BLE comms has finished if no activity for 2 seconds (a guess!!)
  // as there doesn't appear to be any indication from the sending device that
  // a transmission has finished.
  currentMillis = millis();
  if ( bleReceiveInProgress == true ) {
    if (( currentMillis - bleCommsMillis ) > bleMillisTimeout ) {
      Serial.println("ble token received - maybe?");
      bleReceiveInProgress = false;
      tokenReceived = true;
    }
  }

  // finshed receiving some data? - lets see if it's a JSON Web Token
  if ( tokenReceived == true ) {
    delimCounter = 0;
    // simple check to see if the received token has 2 dots - i.e. '.'
    // and replace the BASE64URL chars with standard BASE64 chars
    for (idx=0; idx<encBuffPtr; idx++) {
      if ( encDataBuff[idx] == '.' ) delimCounter++;
      if ( encDataBuff[idx] == '-' ) encDataBuff[idx] = '+';
      if ( encDataBuff[idx] == '_' ) encDataBuff[idx] = '/';
    }

    if ( delimCounter != 2 ) {
      // didn't get 2 dots so not the whole packet
      Serial.println("ERR: Didn't get 2 dots.");
      tokenReceived = false;
      encBuffPtr = 0;
    }
    else
    {
      // might have an encoded JWT so try and decode it
      ch = strtok( (char *)encDataBuff, "." );
      BASE64::decode( ch, (uint8_t*) headerStr );
      ch = strtok( NULL, "." );
      BASE64::decode( ch, (uint8_t*) payloadStr );
      ch = strtok( NULL, "." );
      BASE64::decode( ch, encryptedSig );
      

      Serial.print("\nDecoded Header: (");
      Serial.println( headerStr );
      
      Serial.print("\nDecoded Payload: (");
      Serial.println( payloadStr );
      
      Serial.print("\nDecoded Signature: (");
      for (idx=0; idx<BASE64::decodeLength(ch); idx++ ) {
        if ( encryptedSig[idx] < 0x10 ) Serial.print( '0' );
        Serial.print( encryptedSig[idx], HEX );
        Serial.print( ' ' );
        if ( idx%16 == 15 ) Serial.println();
      }
      Serial.println();
      
    }
    tokenReceived = false;
    encBuffPtr = 0;
  }
}

Wow!!!...gonna give this a try soon and revert....i knew i'd to give the packets sometime to fully arrive. Your code captured that well...Can't wait to try.

Ok so i gave it a try although with another token entirely and it worked to a large extent. With few tweaks here and there, it's now decoding just fine. Thanks again Mark.

Excellent - good luck with your project.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.