Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some tiny fixes #463

Merged
merged 5 commits into from
Oct 20, 2023
Merged

Some tiny fixes #463

merged 5 commits into from
Oct 20, 2023

Conversation

rbergen
Copy link
Collaborator

@rbergen rbergen commented Oct 17, 2023

Description

This implements a small number of tiny fixes that were triggered by recent changes or conversations.
Concretely:

  • It changes the way effects calculate the memory they need to reserve to serialize themselves to JSON.
  • It fixes an invalid NUM_INFO_PAGES define for TTGO.
  • It removes defines of ONSCREEN_SPECTRUM_PAGE from globals.h, because it is no longer used anywhere.
  • It sanitizes the value of NUM_INFO_PAGES down to the values that are actually valid for screen.cpp (1 or 2).
  • It replaces an index-based for loop in webserver.cpp by a range-based one, which makes more sense at that spot.

Contributing requirements

  • I read the contribution guidelines in CONTRIBUTING.md.
  • I understand the BlinkenPerBit metric, and maximized it in this PR.
  • I selected main as the target branch.
  • All code herein is subjected to the license terms in COPYING.txt.

Copy link
Contributor

@robertlipe robertlipe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice cleanups, but I'm still troubled by sprinkling happy little numbers around for sizing JsonDocument. Is there a way to make it more self evident why you replaced one 256 with a +128 and anodther with a +64 ? It'll help other effect creators get it right if you can point to guidance where these numbers came from.

@@ -91,7 +91,7 @@ class BouncingBallEffect : public LEDStripEffect

bool SerializeToJSON(JsonObject& jsonObject) override
{
StaticJsonDocument<256> jsonDoc;
StaticJsonDocument<LEDStripEffect::_jsonSize + 128> jsonDoc;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't seem as meaningful when you replace most occurrences of magic numbers with named constants (yay!) when you then turn around and immediately add more magic numbers.
Please consider a class enum or something not as much for constraining the values (is 132 more meaningful than 128?) that at least gives some hint why some classes get different values. "JsonSize:ThreeToFiveMembers" or something else to hint why they're different would be really helpful.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand the plea, but the answer is that this is just a massive oddity of how ArduinoJson works, and it goes too far to replicate half their documentation throughout half our codebase to try to explain how and why this works the way it does.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@robertlipe

I've extended the documentation about JSON (de)serialization in the main README a little (it even has its own section now!)
That's as far I think we can take this - and should want to. It is and remains a guessing game, and that's never an exact science.

auto effectsList = effectManager.EffectsList();

for (int i = 0; i < effectManager.EffectCount(); i++)
for (auto effect : effectManager.EffectsList())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The three called methods look like they should be const if they aren't. As such, can effect be a const& ? (I wish "auto" were more "auto" in this regard, but here we are.)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe? But if I'm honest then I feel we're splitting hairs a bit, considering it's a local loop variable that goes out of scope 15 lines further down. Also, the comment you make is one that one could make about many similar loop variables throughout the codebase. You're welcome to own consistently implementing this change throughout the project if you want, but I'd recommend spending your time and energy on other things. :)

@robertlipe
Copy link
Contributor

robertlipe commented Oct 19, 2023 via email

@rbergen
Copy link
Collaborator Author

rbergen commented Oct 19, 2023

This is all effectively single threaded, right? We can't have multiple effects writing to the Jason at once. Instead of a dozen buffers that are designed to be barely big enough could we use one big one (followed by a hard throw if too big) that's safe?

No, for a reason that's also very peculiar. There's only a few ArduinoJson functions that indicate if they run out of buffer memory or not, and they're the ones that effectively add a smaller JSON document to a bigger one. That basically forces one to use the approach we use here: use small documents for individual objects (but not too small) and check for buffer overflow when adding them to the "master document", if one wants any insight into how things are progressing.

Should we be looking for a streaming serializer that doesn't need to keep a complete copy on core until we can write it?

ArduinoJson is the library to handle JSON for this platform, and I'm comfortable assuming they structure things this way for a reason.

Should we be thinking about template voodoo to find the size of the thing we're about to serialize (which is a constant, right?)

No, it depends on the contents of the serialized properties as well. Which obviously varies when strings are involved, but not only then: bigger numbers require more characters in the JSON that's created, so more buffer memory too. You could maybe cut up the guesswork into smaller chunks, but you'd still be guessing in the end. And I think the benefit gained wouldn't justify the work involved with that exercise; it seems more balanced to me to guess the "magic number" based on the collection of object properties one needs to serialize, of which there don't tend to be that many anyway in any individual case.

@robertlipe
Copy link
Contributor

robertlipe commented Oct 19, 2023 via email

@rbergen
Copy link
Collaborator Author

rbergen commented Oct 20, 2023

These objects don't really leave the device and into a web interface, do they?

Quite a few do. This applies to the JSON that's generated for consumption by the web UI as well, like device and effect settings, the effect summary list, and effectively everything any of the web API endpoints returns.

If we could safely move these into JsonAllocatableBuffers if we had another few KB of space on the heap o something, I'm willing to help find those dozens of KB somewhere.

You'd still need to guess the buffer size even if it was allocated on the heap - the documentation update I'm about to merge describes this. ArduinoJson just doesn't implement "dynamic allocation as/when needed", and actually explicitly stopped supporting that at some point in the past. The exact reason why I can't remember, but is discussed somewhere in their documentation.

In short, if you want to get rid of the guesswork, you'll have to replace ArduinoJson across the board. And you're right: I'm not going to go down that route. You're welcome to do so, but I'd only consider a change that implements the replacement comprehensively. If you consider pursuing that, do realize the "pick your buffer size before you start" pattern extends to the web server library we use as well, as it also uses ArduinoJson for the JSON handling it does.

Is there something architecturally I can do do help or should I just shut the hell up? :-)

It's not my style to tell people to shut up, but there is an expression that recommends one to "choose your battles". If you ask me, I'd let this one go.

@robertlipe
Copy link
Contributor

robertlipe commented Oct 20, 2023 via email

@rbergen
Copy link
Collaborator Author

rbergen commented Oct 20, 2023

This is actually not a bad find on your part, because that documentation concerns ArduinoJson version 7, which is so new it hasn't even propagated to the Arduino library manager yet. We're using version 6.

Of course, version 7 comes with its own warning, being that it's a lot bigger than earlier versions. That's something we'd have to look into, in the sense that the projects we now have still need to fit on the devices we support, at least in principle. Also, we'd have to wait for ESPAsyncWebServer to be ported to ArduinoJson version 7, because including two ArduinoJson versions is the road to madness.

To be continued, at some point.

@rbergen
Copy link
Collaborator Author

rbergen commented Oct 20, 2023

Merging after confirmed working on Spectrum.

@rbergen rbergen merged commit 4b14c1c into PlummersSoftwareLLC:main Oct 20, 2023
35 checks passed
@rbergen rbergen mentioned this pull request Oct 21, 2023
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants