Skip to content
GitLab
Projects Groups Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in / Register
  • A ArduinoJson
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 24
    • Issues 24
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 0
    • Merge requests 0
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Packages and registries
    • Packages and registries
    • Package Registry
    • Infrastructure Registry
  • Monitor
    • Monitor
    • Incidents
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • Benoît Blanchon
  • ArduinoJson
  • Issues
  • #780
Closed
Open
Issue created Jul 12, 2018 by Administrator@rootContributor

How to pass JsonObject between functions of 2 separate classes?

Created by: vyruz1986

Hi everyone! I've been using ArduinoJson for a couple of years now (Thanks @bblanchon & contributors!) but find myself stuck with something seemingly simple. I was struggling with how to pass a JsonObject between 2 functions of 2 separate classes, but after reading through the documentation, I think I should take a step back and think about what I'm doing is correct or not. So here goes:

I have a WebHandlerClass and a SlaveHandlerClass, the SlaveHandlerClass sets up a websocket client connection which receives regular json messages from the remote host, depending on what the message is, the SlaveHandlerClass should discard the message, or pass it on to the WebHandlerClass. Since I need to check the type of message, I need/want to create a JsonObject in the SlaveHandlerClass in order to use ArduinoJson functionality to validate the json message format and content. So after validating a json message I have a JsonObject& which contains the message I need to pass to WebHandlerClass. What would be the appropriate way to pass this data to the other class?

  • use PrintTo() to print it to a String and send that string object to WebHandlerClass?
  • Pass pointer/reference (these still confuse after years of C++/Arduino coding...) to JsonObject* to WebHandlerClass?
  • Something else...?

I put this on gitter and @bblanchon mentioned to create this issue to further discuss, he already mentioned that passing the JsonObject from one class to the other will likely be the best solution, but the challenge will be to keep the DynamicJsonBuffer alive for this to work correctly.

I attempted to do this, but it's not working, the relevant code is below (just snippets of my bigger project, so likely won't compile. The full source code can found here), I'll try to briefly describe the sequence of relevant events:

  • SlaveHandlerClass::init() initializes the __jsonRaceDataBuffer with the bsRaceData global variable as size which is big enough to hold a RaceData json object. (calculated with helper tool on ArduinoJson.org)
  • SlaveHandlerClass establishes websocket connection to remote host, via the callback function SlaveHandlerClass::_wsEvent() it's informed when there's new data.
    • In case of WStype_TEXT, the function will create a temporary DynamicJsonBuffer and JsonObject& to validate json format, and check the type of message. If the message is a RaceData (request.containsKey("RaceData") then I use the protected class member _jsonRaceDataBuffer and _jsonRaceData objects to parse the payload from the websocket again, but now it should be kept alive since these objects are protected members, global to the `SlaveHandlerClass
  • WebHandlerClass::_SendRaceData() function will perform the following tasks:
    • Create a DynamicJsonBuffer object with the size of bsRaceDataArray (which should be big enough to hold an array of 2 RaceData objects), and initialize a JsonObject with a nested JsonArray
    • Create another DynamicJsonBuffer / JsonObject combination to store its own RaceData (jsonMasterRaceData )
    • If a slave is connected, create another DynamicJsonBuffer / JsonObject combination to store the slave data (jsonSlaveRaceData)
    • Fill the jsonMasterRaceData object with data, and add it to the jsonRaceData array object
    • If a slave is present, query the SlaveHandlerClass for the latest slave RaceData, and add it to the jsonRaceData object as well
    • Send the RaceData array (jsonRaceData) object (either with or without slave racedata) out to all connected websocket clients

The problem is I can't figure out how to correctly pass the data to the WebHandlerClass function. The JsonObject I get back from calling SlaveHandlerClass::getSlaveRaceData() is either empty, or contains rubbish, or the system crashes alltogether.

SlaveHandler.h

class SlaveHandlerClass
{
protected:
   DynamicJsonBuffer _jsonRaceDataBuffer(bsRaceData); //bsRaceData is a global variable that contains the size for a RaceData json object
   JsonObject& _jsonRaceData;
   WebSocketsClient _wsClient;
   void _WsEvent(WStype_t type, uint8_t * payload, size_t length);
public:
   void init();
   void loop();
   JsonObject* getSlaveRaceData();
}
extern SlaveHandlerClass SlaveHandler;

SlaveHandler.cpp

#include "SlaveHandler.h"
#include <WebSocketsClient.h>
#include <ArduinoJson.h>
void SlaveHandlerClass::init()
{
   this->_wsClient.begin(this->_RemoteIP.toString(), 80, "/ws");
   this->_wsClient.onEvent(std::bind(&SlaveHandlerClass::_WsEvent, this
      , std::placeholders::_1
      , std::placeholders::_2
      , std::placeholders::_3));
   DynamicJsonBuffer _jsonRaceDataBuffer(bsRaceData);
}

void SlaveHandlerClass::loop()
{
   this->_wsClient.loop();
}

void SlaveHandlerClass::_WsEvent(WStype_t type, uint8_t * payload, size_t length)
{
   switch (type) {
   case WStype_DISCONNECTED:
      this->_SetDisconnected();
      break;

   case WStype_CONNECTED:
      this->_bConnected = true;
      this->_bWSConnectionStarted = false;
      this->_AnnounceSlaveIfApplicable();
      Serial.printf("[WSc] Connected to url: %s\n", payload);

      // send message to server when Connected
      //this->_wsClient.sendTXT("Connected");
      break;

   case WStype_TEXT:
   {
      Serial.printf("[WSc] got text: %s\n", payload);
      DynamicJsonBuffer jsonBufferRequest;
      JsonObject& request = jsonBufferRequest.parseObject(payload);
      if (!request.success()) {
         syslog.logf_P(LOG_ERR, "Error parsing JSON!");
      }
      if (request.containsKey("RaceData")) {
         JsonObject& _jsonRaceData = _jsonRaceDataBuffer.parseObject(payload);
      }
      else if (request.containsKey("SystemData")) {

      }
      break;
   }

   case WStype_BIN:
      Serial.printf("[WSc] get binary length: %u\n", length);

      // send data to server
      // webSocket.sendBIN(payload, length);
      break;
   }
}

JsonObject* SlaveHandlerClass::getSlaveRaceData()
{
   return _jsonRaceData;
}

WebHandler.cpp

void WebHandlerClass::_SendRaceData(uint iRaceId)
{
   DynamicJsonBuffer JsonBuffer(bsRaceDataArray);
   JsonObject& JsonRoot = JsonBuffer.createObject();
   JsonArray& jsonRaceData = JsonRoot.createNestedArray("RaceData");

   DynamicJsonBuffer jsonMasterRaceDataBuffer(bsRaceData);
   JsonObject& jsonMasterRaceData = jsonMasterRaceDataBuffer.createObject();

   DynamicJsonBuffer jsonSlaveRaceDataBuffer(bsRaceData);
   JsonObject& jsonSlaveRaceData = jsonSlaveRaceDataBuffer.createObject();

   /* fill jsonMasterRaceData object with valid data from various other functions */

   jsonRaceData.add(jsonMasterRaceData);

   if (_bSlavePresent) {
      jsonRaceData.add(SlaveHandler.getSlaveRaceData());
   }

   size_t len = JsonRoot.measureLength();
   AsyncWebSocketMessageBuffer * wsBuffer = _ws->makeBuffer(len);
   if (wsBuffer)
   {
      JsonRoot.printTo((char *)wsBuffer->get(), len + 1);
      _ws->textAll(wsBuffer);
   }
Assignee
Assign to
Time tracking