Make ArduinoJSON Array globally available - c

I am wrapping my head around this problem quite a long time now.
I am opening a websocket Connection from my ESP32 to my NodeJS Backend. When receiving a message, the content gets parsed with ArduinoJSON.
I store the parsed content in global Variables so I can access them in my void loop(). Everytime a new message comes in they are overwritten. Thats how it should be.
The Variable Declaration:
uint8_t brightness = 10;
uint8_t lastMillis = 0;
int ArrayPointer = 0;
int interval = 2000;
bool immediate = true;
const size_t capacity = JSON_ARRAY_SIZE(32) + JSON_OBJECT_SIZE(1) + 290;
After the void Setup()
void onMessageCallback(WebsocketsMessage message) {
Serial.print("Got Message: ");
DynamicJsonBuffer jsonBuffer(capacity);
JsonObject & JSONResponse = jsonBuffer.parseObject(message);
JsonArray & PixelArray = JSONResponse["frame"];
brightness = JSONResponse["brightness"];
ArrayPointer = 0;
immediate = true;
}
void loop() {
client.poll();
if(millis() - lastMillis >= interval || immediate == true) {
// Here I would like to access the Variable PixelArray
lastMillis = millis();
}
}
Of course I cant access PixelArray in the void loop because its a different scope.
Now i Need a way to make PixelArray globally accessible.
What I tried:
Declared a global JsonArray before void Setup() but this threw an error ;(.
Assigning it to another (global) array didnt work properly because the size of the PixelArray varies.
Hopefully somebody can help me ;)
Thanks in advance ;)
PS: Currently I am using ArduinoJson 5 but an upgrade would be no problem.

Don't do it that way.
You should use ArduinoJson just to serialize and deserialize JSON objects, not to store program state. Its documentation makes that very clear.
The correct way to do this (the way that the ArduinoJSON package is designed to be used) is to maintain an internal data structure and serialize and deserialize your JSON objects to it.
So you'd have a global variable that would be your internal representation of PixelArray and then copy values from the JsonArray to it when you receive a JSON message. You're using brightness correctly here; you should do the same thing with PixelArray.

Related

In Objective-C (or C), how does this code with pointer to a bool work?

How does the stop mechanism work in this code?
#interface GifAnaimator()
#property BOOL stopping;
#end
#implementation GifAnaimator
- (void)startWithURL:(CFURLRef)imageURL {
__weak GifAnaimator *weakSelf = self;
CGAnimateImageAtURLWithBlock(imageURL, nil, ^(size_t index, CGImageRef image, bool* stop) {
// Some image handling code...
*stop = weakSelf.stopping;
});
}
- (void)stop {
self.stopping = YES;
}
#end
What's confusing me about this code is that the dereferenced stop is assigned a plain, non-pointed to, BOOL, stopping. Afterwards, when stopping is mutated, stop somehow gets the same mutation.
I tried capturing stop in a block, and calling the block later on to mutate it like so:
weakSelf.stopAnimation = ^{
*stop = YES;
};
This code makes more sense to me but it doesn't work.
What exactly is happening here?
The documentation comment for CGAnimateImageAtURLWithBlock says:
/* Animate the sequence of images contained in the file at `url'. Currently supported image
* formats are GIF and APNG. The `options' dictionary may be used to request additional playback
* options; see the list of keys above for more information. The block is called on the main queue
* at time intervals specified by the `delay time' of the image. The animation can be stopped by
* setting the boolean parameter of the block to false.
*/
If self.stopping is mutated and *stop later gets the same mutation I assume that's because the block is called after the value of self.stopping is changed and the block sets *stop to that value.
Capturing *stop won't work because in all likelihood it doesn't exist outside of the block.
NSDictionary has a method with a similar signature:
- (void)enumerateKeysAndObjectsWithOptions:(NSEnumerationOptions)opts
usingBlock:(void (^)(KeyType key, ObjectType obj, BOOL *stop))block
In pseudo code this does something like:
for (key, object) in storage {
BOOL stop = NO;
block(key, object, &stop);
if(stop) {
break;
}
}
So stop does not exist outside of the closure.

Using 'repeated' inside 'repeated' data in Nanopb

How to properly encode data with NanoPB when having several nested 'repeated' fields?
This is my schema:
message Report {
message SensorData {
required uint32 sensorid = 1;
required uint32 sample = 2;
}
message DeviceData {
required uint32 devid = 1;
repeated SensorData sensor_data = 2;
}
required uint32 reportnum = 1;
repeated DeviceData dev_data = 2;
}
I have already made a working version in which SensorData fields are embedded inside DeviceData message based on the server.c example from the NanoPB source. This way I have only one repeated field and everything works fine. However this way I have to repeat the 'devid' field for every sensorid and every 'sample', instead of giving it just one time and then loop through an array of SensorData messages. However I am struggling to encode this with NanoPB, the decoding part is in Python. Can someone give me an example how to properly encode data in this case?
For me the simplest way to do this was by statically defining the size of the array's using a nanopb options file. After that you can access each element just like an array.
report.dev_data[i].devid[j] = 1234;
report.dev_data[i].sensor_data[j] = 9876;

Solidity - initialize string array in struct

I am currently working on my first smart contract. After already reading a few topics out there I still don't have a clue on how to initialize the string array inside my struct.
The idea is that the customer can always choose from a variety of energysources on a homepage which then gets deployed on the smart contract if he's done choosing.
So what would be the best/efficient way to implement this idea onto the blockchain?
pragma solidity ^0.4.23; /* solhint-disable */
contract EnergyContract {
struct EnContract {
uint price;
uint amount;
string[] energysource;
address creator;
}
EnContract[] aContract;
function createContract(uint _price, uint _amount, address _creator) public {
aContract.length += 1;
EnContract storage _EnContract = aContract[aContract.length - 1];
_EnContract.price = _price;
_EnContract.amount = _amount;
_EnContract.creator = _creator;
}
}
The way you declare your array is correct. You don't need to do anything else. You can just start pushing data into the array.

SharedObject for Arrays of Object. Can't get correct data when restart flash

I have an array that stored some Object with its data, and I try to store it in my computer.
If I try to load for the data after I've save the data, I could get a correct data.
Exp: [Object Player]
But if I restart the flash, the data seems to be gone.
What is the problem?
private var sharedObject:SharedObject = SharedObject.getLocal("aquarium", "/");
public function save(n:String):void
{
/* player list will only handle the list of all the Players
* each player data will handle by Player class itself.
*/
registerClassAlias("Player", Player)
player = new Player()
player.newPlayer(n, LATEST_VERSION)
playerArray.push(player)
//saving as shared object
sharedObject.data.aquariumData = playerArray
sharedObject.flush()
load()
}
public function load():void
{
if (sharedObject.size > 0)
{
trace("loading player info")
playerArray = sharedObject.data.aquariumData
trace(playerArray)
}
else
{
trace("there's no record")
}
}
Can you please provide the code how you obtain the shared object ?
Do you use var sharedObject:SharedObject = SharedObject.getLocal("sharedObject"); or something like this ?
Apart from that when calling registerClassAlias("Player", Player) before serialization keep in mind that it must be called before extraction of the data also, so the de-serialization will work correctly and returns array of Player objects not array of Object objects.
And ofc closing the sharedObject is very nice practice after flushing :)
P.S. Your code works as far as i've tested it replacing your Player class with other custom class.

Windows Form code not executing?

Ok, I've got a weird one here. I'm trying to make a basic tile engine using a windows form, but some of my code is just...not happening. I'll post the chunks in question.
private void MapEditor_Load(object sender, EventArgs e)
{
LoadImageList();
FixScrollBarScales();
cboCodeValues.Items.Clear();
cboCodeValues.Items.Add("ENEMY");
cboCodeValues.Items.Add("CHEST");
cboCodeValues.Items.Add("NPC");
for (int x = 0; x < 100; x++)
cboMapNumber.Items.Add(x.ToString().PadLeft(3, '0'));
cboMapNumber.SelectedIndex = 0;
TileMap.EditorMode = true;
backgroundToolStripMenuItem.Checked = true;
}
This should be called when the form loads, right? The code dives into LoadImageList(), which contains:
private void LoadImageList()
{
string filepath = Application.StartupPath +
#"\Content\Textures\IndoorTileSet.png";
Bitmap tileSheet = new Bitmap(filepath);
int tilecount = 0;
for(int y = 0; y < tileSheet.Height / TileMap.TileHeight; y++)
{
for(int x = 0; x < tileSheet.Width / TileMap.TileWidth; x++)
{
Bitmap newBitmap = tileSheet.Clone(
new System.Drawing.Rectangle(
x * TileMap.TileWidth,
y * TileMap.TileHeight,
TileMap.TileWidth,
TileMap.TileHeight),
System.Drawing.Imaging.PixelFormat.DontCare);
imgListTiles.Images.Add(newBitmap);
string itemName = "";
if(tilecount == 0)
itemName = "Empty";
if(tilecount == 1)
itemName = "Floor";
listTiles.Items.Add(new ListViewItem(itemName, tilecount++));
}
}
}
The bitmap loads correctly, but then the entire MapEditor_Load method just stops working. tileCount seems to be a local variable in the debugger, and its value is 0, but the debugger never executes the breakpoint on the line which it is assigned. I have absolutely no idea why it would do this, and it's driving me nuts. Any help?
Oh, I put the bitmap load in a try/catch block just to see if it was handling an exception in a weird way, but I had no luck. It's not throwing an exception. I began having this problem immediately after replacing my IndoorTileSet with an updated version. I've tried a clean rebuild, with no success.
I read something about a person having a similar problem, who wound up having to declare something as an Instance of a class, but the post wasn't detailed enough for me to know if that's where I'm going wrong, or what I might have to declare as an Instance for it to work...or what an Instance even means, really.
I'm not sure about the code in LoadImageList() method but I suggest you to use BackgroundWorker or Control.Invoke to make your application more responsive.
Try this :
Bitmap tileSheet = (Bitmap)Bitmap.FromFile(filepath);
The problem is, superficially, that my Bitmap code is throwing an FileNotFound exception, which means I've got a bad filepath. I can handle that. The issue of the program not actually throwing exceptions, and seeming to ignore code, is an issue with 64-bit operating systems not being able to handle exception calls in all instances. The details, and a link to a hotfix to solve the issue, can be found at this site.

Resources