-
-
Notifications
You must be signed in to change notification settings - Fork 3.2k
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
Fetch supported LED types from Bus #4056
Conversation
This is great! Thank you. |
|
PROGMEM is a storage specifier. It directs compiler (and linker) to store variable in flash instead of RAM (and hence |
Change made to the strings @blazoncek |
Hang fire on the merge, I'm seeing an issue with 8266 oappend() buffer overflow. Cannot append 1127 bytes |
Fixed |
@netmindz the issue with |
I cannot push directly to this branch, please edit PR to allow push. |
Actually, if this really is a constant thing that you're building at
compile time and you're not later adding or removing members, maybe this
shouldn't be a std::vector at all, but rather a std::array. Then you can
definitely make that compile-time initializaed and all that code that
handles calling constructors adding to the end and reallocating the vector
as you push_back and such will all just decay away.
I'm on a phone, but I'll try to pull the branch and see if I can help
later. I think a Std:array will help with the code size.
Is esp32 under platdoemio with a modern g++ a reasonable development place
or is this like FastLED that cares about univac and 8 bit hosts? (For all
those 8266s that can drive six HUB75 panels, you know...)
…On Wed, Jul 17, 2024 at 9:15 AM netmindz ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In wled00/bus_manager.cpp
<#4056 (comment)>:
> @@ -377,6 +377,86 @@ void BusDigital::cleanup() {
pinManager.deallocatePin(_pins[0], PinOwner::BusDigital);
}
+std::vector<LEDType> BusDigital::getLEDTypes() {
That's way over the head of my C++ knowledge sorry
—
Reply to this email directly, view it on GitHub
<#4056 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/ACCSD3253OIU2TQSVVL4FATZMZ36ZAVCNFSM6AAAAABK3KHH4WVHI2DSMVQWIX3LMV43YUDVNRWFEZLROVSXG5CSMV3GSZLXHMZDCOBTGA3DMOJYG4>
.
You are receiving this because you commented.Message ID:
***@***.***>
|
permission has already been granted what error are you getting when you try to push @blazoncek ? |
I welcome any refactoring that helps reduce the code, the work so far was a bit of a transposition from HTML to C++ where my main focus was on the accuracy of conversion rather than optimisation |
It says "You don't have permissions to push to "netmindz/WLED" on GitHub. Would you like to create a fork and push to it instead?" and I usually have no issues when modifying PR branches like that in other repositories:
|
@robertlipe you are right all this is compile time operation and does not need vectors per se. I've modified code and will provide links to my Dropbox if you PM me on Discord until @netmindz fixes the push issue. |
Thinking of it, it may really be unnecessary to extend BusXXX classes with String BusManager::getLEDTypes() {
std::array<LEDType, 27> types = {{
{TYPE_WS2812_RGB, "D", PSTR("WS281x")},
{TYPE_SK6812_RGBW, "D", PSTR("SK6812/WS2814 RGBW")},
{TYPE_TM1814, "D", PSTR("TM1814")},
{TYPE_WS2811_400KHZ, "D", PSTR("400kHz")},
{TYPE_TM1829, "D", PSTR("TM1829")},
{TYPE_UCS8903, "D", PSTR("UCS8903")},
{TYPE_APA106, "D", PSTR("APA106/PL9823")},
{TYPE_TM1914, "D", PSTR("TM1914")},
{TYPE_FW1906, "D", PSTR("FW1906 GRBCW")},
{TYPE_UCS8904, "D", PSTR("UCS8904 RGBW")},
{TYPE_WS2805, "D", PSTR("WS2805 RGBCW")},
{TYPE_WS2812_1CH_X3, "D", PSTR("WS2811 White")},
//{TYPE_WS2812_2CH_X3, "D", PSTR("WS2811 CCT")},
//{TYPE_WS2812_WWA, "D", PSTR("WS2811 WWA")},
{TYPE_WS2801, "2P", PSTR("WS2801")},
{TYPE_APA102, "2P", PSTR("APA102")},
{TYPE_LPD8806, "2P", PSTR("LPD8806")},
{TYPE_LPD6803, "2P", PSTR("LPD6803")},
{TYPE_P9813, "2P", PSTR("PP9813")},
{TYPE_ONOFF, "", PSTR("On/Off")},
{TYPE_ANALOG_1CH, "A", PSTR("PWM White")},
{TYPE_ANALOG_2CH, PSTR("AA"), PSTR("PWM CCT")},
{TYPE_ANALOG_3CH, PSTR("AAA"), PSTR("PWM RGB")},
{TYPE_ANALOG_4CH, PSTR("AAAA"), PSTR("PWM RGBW")},
{TYPE_ANALOG_5CH, PSTR("AAAAA"), PSTR("PWM RGB+CCT")},
//{TYPE_ANALOG_6CH, PSTR("AAAAAA"), PSTR("PWM RGB+DCCT")},
{TYPE_NET_DDP_RGB, "V", PSTR("DDP RGB (network)")},
{TYPE_NET_ARTNET_RGB, "V", PSTR("Art-Net RGB (network)")},
{TYPE_NET_DDP_RGBW, "V", PSTR("DDP RGBW (network)")},
{TYPE_NET_ARTNET_RGBW, "V", PSTR("Art-Net RGBW (network)")}
}};
String json = "[";
for (const auto &type : types) {
String id = String(type.id);
json += "{i:" + id + F(",t:\"") + FPSTR(type.type) + F("\",n:\"") + FPSTR(type.name) + F("\"},");
}
json.setCharAt(json.length()-1, ']'); // replace last comma with bracket
return json;
} (or moved outside to be static) @netmindz what was your driving force for I played with this PR yesterday and it is the step in the right direction, unfortunately |
The motivation for the change is that if you look at the hub75 branch, you will see how the list of LEDTypes is dependent on which Bus classes you include in the build, so you can use a hard-coded list of LED types directly in the BusManager::getLEDTypes, the bus manager must always delegate to the individual Bus classes. We can perhaps use an array within the specific Bus classes as the size of the number of LED types it supports is fixed |
I'd like to invite @Aircoookie into discussion as he still has a Settings pages rewrite in mind. 😄 |
Isn't that a "build time" decision? So the array can be built the same. |
Sorry I've not had any time to look at this properly over the last few weeks. I think the point we had got to was that some of the suggested optimisations made sense for the first stage of these related PRs, but then would face issues when they try and take further, so premature optimisation in the first PR would then cause issues later so I was going to try and sit down and see what improvements we can make to this PR that don't compromise the later ones |
It sounds like there had been quite a lot of discussion about this and I'm very much a novice with C++ so would it perhaps make sense for perhaps @robertlipe to create a new PR with the same goal where the bus manager to return the details from all the bus implementations. Take my idea, but not my code? |
I'd be happy to help with the editor exercise of pushing the bits around,
but my WLED internal mojo is weak. (I'm a regular contributor on a very
similar project, so it's not alien.) I can build/run on a variety of ESP32
platforms. Can you give me some guidance on how to appropriately exercise
this PR? e.g. "build and run this on native to confirm absence of memory
leaks and build and run on ESP32 with configuration X and confirm that
saved JSON files before doing X and Y are identical" or that the web
interface works or whatever.
I have no idea what a BusManager in this context actually IS, though I seem
to have strong opinions about how to spell it internally. :-)
…On Mon, Aug 5, 2024 at 4:16 PM netmindz ***@***.***> wrote:
It sounds like there had been quite a lot of discussion about this and I'm
very much a novice with C++ so would it perhaps make sense for perhaps
@robertlipe <https://github.com/robertlipe> to create a new PR with the
same goal where the bus manager to return the details from all the bus
implementations. Take my idea, but not my code?
—
Reply to this email directly, view it on GitHub
<#4056 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ACCSD35XES7PJ5ZAPAE4N5LZP7TSBAVCNFSM6AAAAABK3KHH4WVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENRZHEZTEOJWGU>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Actually, honestly, the meat of this is so mechanical that I can probably
just take a swing at it and we can work on making it work together.
ISTR that WLED has strong opinions about branch management and doesn't like
PRs against the trunk. What's the preferred delivery branch to base it on?
CONTRIbzUTING.md says "Please make all PRs against the 0_15 branch." but I
also know that doc (including my own) sometimes fibs or this may be
targeted to a different branch or entwined with some other work or
something.
I can't even remember if I got here because I expressed an interest in the
HUB75 work or if it was just random nerd-sniping drive-by in the open PR
queue. I sometimes read open issues and help coach (some people call that
"butting in" and "running off his mouth where it wasn't welcome" :-) )
others just to randomly help projects I care about.
…On Mon, Aug 5, 2024 at 5:36 PM Robert Lipe ***@***.***> wrote:
I'd be happy to help with the editor exercise of pushing the bits around,
but my WLED internal mojo is weak. (I'm a regular contributor on a very
similar project, so it's not alien.) I can build/run on a variety of ESP32
platforms. Can you give me some guidance on how to appropriately exercise
this PR? e.g. "build and run this on native to confirm absence of memory
leaks and build and run on ESP32 with configuration X and confirm that
saved JSON files before doing X and Y are identical" or that the web
interface works or whatever.
I have no idea what a BusManager in this context actually IS, though I
seem to have strong opinions about how to spell it internally. :-)
On Mon, Aug 5, 2024 at 4:16 PM netmindz ***@***.***> wrote:
> It sounds like there had been quite a lot of discussion about this and
> I'm very much a novice with C++ so would it perhaps make sense for perhaps
> @robertlipe <https://github.com/robertlipe> to create a new PR with the
> same goal where the bus manager to return the details from all the bus
> implementations. Take my idea, but not my code?
>
> —
> Reply to this email directly, view it on GitHub
> <#4056 (comment)>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/ACCSD35XES7PJ5ZAPAE4N5LZP7TSBAVCNFSM6AAAAABK3KHH4WVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENRZHEZTEOJWGU>
> .
> You are receiving this because you were mentioned.Message ID:
> ***@***.***>
>
|
@robertlipe modified @netmindz 's files are here. |
Thanx. Those contain a lot of changes beyond what's in this pr. I'm pretty
happy with that structure creation and iteration. I might tinker with an
std::stdstream (and a .reserve since we'll know the approximate size)
instead of the Arduino String bashing in that loop as those are known to be
brutal on heap fragmentation and abuse, but that's mostly me hating
Arduino. :-)
Is my value add here to extract just what @netmindz changes from that and
produce a pr against 0_15? I'm happy to do that if that's the assignment.
P.S. not to get off into tangents upon tangents, but I just went through
this in another code review and now see this new hunk struggling with the
same issue. Compilers are starting to get smart/wise/fussy about implicit
narrowing and in our embedded parts, that explicit mask with an 0xff to
make it a uint8 when it's really a loop index and just needs to be ...
something, that's often spelled int_fast8_t. That'll pick the appropriate
type whether you're on RISC-V, Xtensa, or x86 that'll hold at least 8 bits,
and lets the compiler pick "best".
But really, in most of the places you changed it, Blaz, you can avoid the
type completely, probably get better code out of it, and less likely to get
into trouble with bounds violations on the edges. For example:
getTotalLength() could just be a call to std::accumulate. Then if you're on
RISC-V with Vector or similar hardware, it's easy for the optimizer to see
your intent and give you vectorization.
This basic idiom happens a lot in your pending change:
- for (uint8_t i = 0; i < numBusses; i++) {
+ for (unsigned i = 0; i < numBusses; i++) {
Just let loop type induction work this out. Maybe
for (const auto& bus : busses) {
if bus.canShow() return false;
}
Now you've left the iteration to the optimizer. If busses later becomes,
oh, a std::map (I have no idea why in this example, but we all know data
types change...) and it's no longer an array, it'll still
iterate correctly.
- uint8_t numPins = NUM_PWM_PINS(_type);
- for (uint8_t i = 0; i < numPins; i++) {
+ unsigned numPins = NUM_PWM_PINS(_type);
+ for (unsigned i = 0; i < numPins; i++) {
Same idiom:
for (const auto& pin : pins) {
do the thing with pin.
}
Is keeping numPins as a separate thing wise? Could pinArray be a vector (or
array) and just have size() used on it when needed? Those things always
get out of sync over the years somewhere.
I won't say that C-style loops should never be written, but using
range-based for ("new" in C++11, but available well before that) is almost
always more readable, avoids the kind of issues that you're running into in
this very PR. Optimizers don't have to worry about crazy thing like what if
some store through a pointer inside the loop modifies the loop counter via
a store (!!) which might force it to keep reloading.
I think range-based maps were c++17, but here in embedded-land, most of us
have access to really recent toolchains. Range-for is just a better
contract between the author and the consumer of the source.
Also, if you put this in your .vimrc, youll see the random whitespaces
you've accidentally added:
:highlight ExtraWhitespace ctermbg=red guibg=red
:match ExtraWhitespace /\s\+$/
I also totally get that you didn't ask for my opinion on any of this and
have the right to not care. :-)
Back on topic: do I understand the assignment? Shall I extract the parts of
this PR that we discussed and that appeared in the original PR and make a
new one based on that?
Thanx!
…On Tue, Aug 6, 2024 at 5:09 AM Blaž Kristan ***@***.***> wrote:
@robertlipe <https://github.com/robertlipe> modified @netmindz
<https://github.com/netmindz> 's files are here
<https://www.dropbox.com/scl/fo/1ud3z7gvkpgypchspxfpr/ALf3CU2zd66jUtmgHANSOAo?rlkey=lfvwawfyu7qyesxnqix6qqnp9&dl=0>
.
I've employed what was said above and it seems to work.
—
Reply to this email directly, view it on GitHub
<#4056 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ACCSD33GPUI6I7R3QBL7KO3ZQCOFJAVCNFSM6AAAAABK3KHH4WVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENZQHEYDGMRYGQ>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
@robertlipe you will need to start using simpler English. I have hard time following. 😄 A lot of WLED code is now 2 or 3 years old and would benefit greatly if it could be modernised. But that is a huge task. And BTW I do appreciate any and every feedback. Thank you. |
These changes fail to delegate the list of types to the specific bus classes so fails the requirement of "to be fetched from the various Bus classes" as stated in the description |
In modern C++, we can load a vector with brace initialized list of values. Use this to speed up the list assembly. Saves about 1kb of code space.
We don't really need to bother building the whole list, just the string. Saves about 300 bytes of code.
I put some suggestions in https://github.com/willmmiles/WLED/tree/pr/netmindz/4056-1 .
I agree with @robertlipe that using std::vector feels a bit dirty as the contents for each bus classification are static and known at compile time, so we don't really need to copy them in to heap memory every time. Unfortunately, as far as I'm aware, there's no good stdlib solution that doesn't require the API to expose the list length as part of each return type until C++20 when we get std::span, essentially a pointer+length pair with the C++ stdlib container API. The best I think we could do there with the current build tools is something like: std::pair<const LEDType*, size_t> BusXXX::getLEDTypes() {
const static LEDType[] myTypes = {...};
return {myTypes, std::extent<decltype(myTypes)>::value};
} Less C++-flavored, but faster and probably smaller still. |
The solution I proposed avoids memory manipulations and its only drawback is the removal of fetching LED types from different buses (no abstraction). I hope I understand @netmindz correctly that he wants to include additional information like required pins, etc. into LEDtype array to provide dynamic settings UI in next iteration of this PR but I still do not see that as an obstacle as all that is a compile time operation and LEDType array can be constructed in the same way with enhanced content within |
Thanks for these, I have pulled these changes into my branch
Regarding this, I really think we are making way too heavy weather of this. If this were used in normal operations then I could understand the need to optimise within an inch of its life, but for something that is only used to fetch the info needed to render the LED preferences page, which is used for setup and then rarely touched again ..... Surely for the nice new LEDTypesToJson method that relies on having a common parameter type - which surely an array with size would not be? The alternative would to just change each bus class to return JSON as a string, then the bus manager just wraps them into a single JSON response |
That lack of abstraction will prevent what I want to do with later PRs, but yes it should be BusManager that returns the data, not direct calls from xml.cpp to specific drivers
Due to the fixed size issue of an array, this causes problems, as mentioned in my comment regarding LEDTypesToJson To put it the other way, I see no added value to have each BusXXX provide We could change the return type to be a vector for both, but then we need to put the serialization to json elsewhere, so that's why I was trying to keep xml.cpp neat and without memory-hungry json documents where not required. With regards to later changes, I still need to work out the details of how to give the BusXXX the most flexibility of what options they return, without making the UI code overly complex and also how to manage any migration from the current really hacky use/abuse of the pins array into something a little better. |
I'm way behind. Sorry.
I'll catch up tomorrow, but I think that
https://en.cppreference.com/w/cpp/container/array/to_array is the missing
piece here.
Unknown size at compile time, they turn into a std::array so they're in
flash, and we can iterate like containers.
…On Wed, Aug 21, 2024 at 5:28 AM netmindz ***@***.***> wrote:
The solution I proposed avoids memory manipulations and its only drawback
is the removal of fetching LED types from different buses (no abstraction).
I know I am not a very good (C++) reference but BusManager is the one
outside world communicates with and is the one to handle all LED types so
IMO it is still the place to provide the functionality for getLEDTypes().
That lack of abstraction will prevent what I want to do with later PRs,
but yes it should be BusManager that returns the data, not direct calls
from xml.cpp to specific drivers
I hope I understand @netmindz <https://github.com/netmindz> correctly
that he wants to include additional information like required pins, etc.
into LEDtype array to provide dynamic settings UI in next iteration of this
PR but I still do not see that as an obstacle as all that is a compile time
operation and LEDType array can be constructed in the same way with
enhanced content within BusManager.
Due to the fixed size issue of an array, this causes problems, as
mentioned in my comment regarding LEDTypesToJson
To put it the other way, I see no added value to have each BusXXX provide
getLEDTypes(). And having different return type for Bus::getLEDTypes()
and BusManager::getLEDTypes() is confusing. But that is just my opinion.
We could change the return type to be a vector for both, but then we need
to put the serialization to json elsewhere, so that's why I was trying to
keep xml.cpp neat and without memory-hungry json documents where not
required.
Alternatively, change both to string, but then we lose the option to do
anything like sorting by name on the combined list before retuning. This
could be done in the UI code however if required
With regards to later changes, I still need to work out the details of how
to give the BusXXX the most flexibility of what options they return,
without making the UI code overly complex and also how to manage any
migration from the current really hacky use/abuse of the pins array into
something a little better.
—
Reply to this email directly, view it on GitHub
<#4056 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ACCSD3ZTSZEAYA7F7PFA3FTZSRTVZAVCNFSM6AAAAABK3KHH4WVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGMBRG4YDOOJYHA>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
OK, It's 11am so I should just give up on sleeping "last night" and power
through.
The feature I was thinking of does seem to be in C++ 20, but it can
actually be implemented in about a half dozen lines of templating.
cat /tmp/w.cc
#include <array>
#include <iostream>
typedef struct {int x; const char b; const char* c;} s;
auto a = std::to_array<s>(
{
{0, 'V', "DDP RGB"},
{1, 'V', "Artnet"},
{2, 'V', "DDP RGBW"}
});
int main() {
std::cout << std::size(a) << "elements" << std::endl;
}
➜ nightdriverstrip git:(fixincs) ✗ g++ --std=c++20 /tmp/w.cc && ./a.out
3elements
....and it barfs at c++17. The boilerplate is google-able if you need a
to_array() in a world before c++20. It was beyond dumb that the official
way until the required both an initializer list AND a count - totally dumb.
…On Wed, Aug 21, 2024 at 6:06 AM Robert Lipe ***@***.***> wrote:
I'm way behind. Sorry.
I'll catch up tomorrow, but I think that
https://en.cppreference.com/w/cpp/container/array/to_array is the missing
piece here.
Unknown size at compile time, they turn into a std::array so they're in
flash, and we can iterate like containers.
On Wed, Aug 21, 2024 at 5:28 AM netmindz ***@***.***> wrote:
> The solution I proposed avoids memory manipulations and its only drawback
> is the removal of fetching LED types from different buses (no abstraction).
> I know I am not a very good (C++) reference but BusManager is the one
> outside world communicates with and is the one to handle all LED types so
> IMO it is still the place to provide the functionality for getLEDTypes().
>
> That lack of abstraction will prevent what I want to do with later PRs,
> but yes it should be BusManager that returns the data, not direct calls
> from xml.cpp to specific drivers
>
> I hope I understand @netmindz <https://github.com/netmindz> correctly
> that he wants to include additional information like required pins, etc.
> into LEDtype array to provide dynamic settings UI in next iteration of this
> PR but I still do not see that as an obstacle as all that is a compile time
> operation and LEDType array can be constructed in the same way with
> enhanced content within BusManager.
>
> Due to the fixed size issue of an array, this causes problems, as
> mentioned in my comment regarding LEDTypesToJson
>
> To put it the other way, I see no added value to have each BusXXX provide
> getLEDTypes(). And having different return type for Bus::getLEDTypes()
> and BusManager::getLEDTypes() is confusing. But that is just my opinion.
>
> We could change the return type to be a vector for both, but then we need
> to put the serialization to json elsewhere, so that's why I was trying to
> keep xml.cpp neat and without memory-hungry json documents where not
> required.
> Alternatively, change both to string, but then we lose the option to do
> anything like sorting by name on the combined list before retuning. This
> could be done in the UI code however if required
>
> With regards to later changes, I still need to work out the details of
> how to give the BusXXX the most flexibility of what options they return,
> without making the UI code overly complex and also how to manage any
> migration from the current really hacky use/abuse of the pins array into
> something a little better.
>
> —
> Reply to this email directly, view it on GitHub
> <#4056 (comment)>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/ACCSD3ZTSZEAYA7F7PFA3FTZSRTVZAVCNFSM6AAAAABK3KHH4WVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGMBRG4YDOOJYHA>
> .
> You are receiving this because you were mentioned.Message ID:
> ***@***.***>
>
|
I've made simpler variant of the same here. |
@netmindz if you are willing to undo changes in xml.cpp and led_settings.html and change destination branch to bus-config I am willing to merge the latest incarnation of this PR. |
Hi @blazoncek , I'll try and find some time over the next few days to have a look at the two branches |
I've implemented all of the discussions from above while keeping your (extensible) approach. |
Shall I close this one then as it looks like you already have add the changes you want to keep into your own branch? @blazoncek |
Yes I did, thought of it and figured out it would be much more hassle otherwise. I hope you are ok with the credit in the comments. |
First of 2 different PRs to move the hard coding of all the different LED output types and their config from the current settings_led.htm to be fetched from the various Bus classes
This is so that when you add a new Bus, you do not need to edit the settings_led.htm, which is a neater workflow that also allows for easier use of compile-time flags for which output types are available
See the motivation for this change - #3777