Skip to content

LED strip refactor #3158

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

Merged
merged 12 commits into from
Jan 6, 2021
Merged

LED strip refactor #3158

merged 12 commits into from
Jan 6, 2021

Conversation

nwf
Copy link
Member

@nwf nwf commented Jun 13, 2020

Addresses #2916 (mostly, anyway). Leaves #3122 to be done, and doesn't change any of the color utils libraries.

I've moved the so-called "ws2812" tests, which were really just tests of its buffer, over to the generic pixbuf and this now passes those tests. While the ws2812_effects library is ported to work with pixbuf objects and does compile, it is operationally untested (though I don't anticipate any real breakage).

I have not actually attempted to use this to drive LEDs yet (ha) but the drivers are only lightly modified to use the new data structure, so I hope it should work fine.

  • This PR is for the dev branch rather than for master.
  • This PR is compliant with the other contributing guidelines as well (if not, please describe why).
  • I have thoroughly tested my contribution.
  • The code changes are reflected in the documentation at docs/*.


buffer1:fill(10,22,54)
buffer2:fill(10,27,55)
buffer1:mix(-257,buffer1:dump(),255,buffer2:dump())
Copy link
Member

Choose a reason for hiding this comment

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

Did you remove the string capability from pixbuf?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, though perhaps for somewhat specious reasoning: it wasn't documented and the test was flirting with OOM.

Copy link
Member

Choose a reason for hiding this comment

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

True, Maybe we should document it rather and if necessary split the tests in even more parts. As string buffers are allowed everywhere else it would be inconsistent if it wasn't here.

Copy link
Member Author

Choose a reason for hiding this comment

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

"allowed everywhere else"?

Copy link
Member

Choose a reason for hiding this comment

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

like in ws2812.write(), ws2812.buffer:set(), buffer:replace()
not documented and not implemented for ws2812.buffer:fill(), __concat() mix()

Copy link
Member

Choose a reason for hiding this comment

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

Did I just write the mix des not support strings? Then why did this test ever run at all??


initBuffer(buffer1,7,8,9,12)
initBuffer(buffer2,0,0,7,8)
buffer1:shift(2)
ok(equalsBuffer(buffer1, buffer2), "shift right")
ok(buffer1 == buffer2, "shift right")
Copy link
Member

Choose a reason for hiding this comment

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

If we use our own == her we would need to add tests for == somewhere.
Else we test the operations with untested code (our ==)

Copy link
Member Author

Choose a reason for hiding this comment

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

Well, these are tests of our ==. But yes, maybe we should test for ~= sometimes. Here and elsewhere, more tests are welcome.

Copy link
Member

Choose a reason for hiding this comment

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

But still we should only test one aspect in one test and not use two untested components.

Copy link
Member Author

Choose a reason for hiding this comment

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

In black-box testing, it's often not possible to "only test one aspect" at a time. Previously, this test depended on fill (via initBuffer), shift, and dump; now it depends on fill, shift, and eq. I'm not opposed to having more tests, and even some that compare == on dump output, but I don't think the lack of orthogonality is new as of this diff.

Copy link
Member

Choose a reason for hiding this comment

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

True, but opposed to == there are tests for fill and shift.

Copy link
Member Author

@nwf nwf left a comment

Choose a reason for hiding this comment

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

Thanks for the review. Standby for incoming changes.


buffer1:fill(10,22,54)
buffer2:fill(10,27,55)
buffer1:mix(-257,buffer1:dump(),255,buffer2:dump())
Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, though perhaps for somewhat specious reasoning: it wasn't documented and the test was flirting with OOM.


initBuffer(buffer1,7,8,9,12)
initBuffer(buffer2,0,0,7,8)
buffer1:shift(2)
ok(equalsBuffer(buffer1, buffer2), "shift right")
ok(buffer1 == buffer2, "shift right")
Copy link
Member Author

Choose a reason for hiding this comment

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

Well, these are tests of our ==. But yes, maybe we should test for ~= sometimes. Here and elsewhere, more tests are welcome.

@nwf nwf force-pushed the led-strip-refactor branch from 037ddbe to fd8ef76 Compare June 21, 2020 13:32
LROT_FUNCENTRY( __concat, pixbuf_concat_lua )
LROT_FUNCENTRY( __tostring, pixbuf_tostring_lua )

LROT_FUNCENTRY( dump, pixbuf_dump_lua )
Copy link
Member

Choose a reason for hiding this comment

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

Do we need an RGB version here? Or is it good enough to treat string buffers as raw everywhere and leaving the details to the app developer.
Do we need conversion functions RGB <=> GBR
Should we allow for a format parameter whenever string buffers are used?
So many questions. Sorry. If you would prefer to postpone this to another PR that would be fine with me.
We should the include that PR into the next release though or have it without Lua code change requirements to users.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think dump is mostly a debugging function, not something we expect people to use day-to-day.

Copy link
Member

Choose a reason for hiding this comment

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

dump may also be used for persisting patterns (in a file)


buffer1:fill(10,22,54)
buffer2:fill(10,27,55)
buffer1:mix(-257,buffer1:dump(),255,buffer2:dump())
Copy link
Member

Choose a reason for hiding this comment

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

True, Maybe we should document it rather and if necessary split the tests in even more parts. As string buffers are allowed everywhere else it would be inconsistent if it wasn't here.


initBuffer(buffer1,7,8,9,12)
initBuffer(buffer2,0,0,7,8)
buffer1:shift(2)
ok(equalsBuffer(buffer1, buffer2), "shift right")
ok(buffer1 == buffer2, "shift right")
Copy link
Member

Choose a reason for hiding this comment

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

But still we should only test one aspect in one test and not use two untested components.

Copy link
Member

@HHHartmann HHHartmann left a comment

Choose a reason for hiding this comment

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

I just found an old open browser tab (I got tons of them) with the documentation of another led strip module: tm1829 led strips, which also should be adapted to use PixBuf as input.

@nwf
Copy link
Member Author

nwf commented Jun 28, 2020

I am deeply skeptical of the tm1829 code; it appears to be generating a very ws2812-style waveform in software, but it bounces interrupts per byte, rather than per packet, which suggests to me that some fraction of the time it gets the timing wrong and the strip glitches.

Also despite the documentation claiming that its input string is in RGB order, the code does not actually change the order of any bytes, so its claim of sending GRB is probably wrong. But the documentation may predate the conversion to not corrupt the input string, too, so...

Anyway, I took a stab at converting it.

@nwf nwf force-pushed the led-strip-refactor branch from fd8ef76 to f376a8e Compare June 28, 2020 13:47
@nwf nwf force-pushed the led-strip-refactor branch from f376a8e to c80fc3f Compare July 18, 2020 11:42
@nwf nwf removed this from the Next release milestone Sep 1, 2020
@nwf nwf added this to the Next release milestone Sep 23, 2020
@nwf nwf force-pushed the led-strip-refactor branch 2 times, most recently from dbbd0b6 to dce58ac Compare September 23, 2020 00:36
@nwf nwf requested a review from HHHartmann September 23, 2020 00:36
@nwf nwf force-pushed the led-strip-refactor branch from dce58ac to 55a4d83 Compare September 26, 2020 11:56
@nwf
Copy link
Member Author

nwf commented Sep 26, 2020

Blocking on #3230 since I want to be able to test pixbufs on the host.

@nwf nwf added blocked Waiting on another PR to land enhancement new module labels Sep 26, 2020
@nwf
Copy link
Member Author

nwf commented Sep 26, 2020

Eh, nevermind. I'll just carry the local bits for host testing in my tree for a bit; no reason to block this.

@nwf nwf removed the blocked Waiting on another PR to land label Sep 26, 2020
@nwf nwf force-pushed the led-strip-refactor branch 2 times, most recently from 21ff0d0 to 9890313 Compare September 26, 2020 14:34
@marcelstoer marcelstoer removed this from the Next release milestone Nov 3, 2020
Copy link
Member

@HHHartmann HHHartmann left a comment

Choose a reason for hiding this comment

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

Still would like to have C functions to adjust channel order.
Using :map will be around 8 to 10 times slower.

But will be left for another PR then

end)

N.test('mix with strings correctly ', function()
local buffer1 = pixbuf.newBuffer(1, 3)
Copy link
Member

Choose a reason for hiding this comment

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

this test should be removed as it does the same as the one above

ok(eq(buffer1:size(), 0), "sub empty")

buffer1 = pixbuf.newBuffer(4, 4)
initBuffer(buffer1,7,8,9,12)
Copy link
Member

Choose a reason for hiding this comment

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

One line missing here: test fails

Suggested change
initBuffer(buffer1,7,8,9,12)
buffer2 = ws2812.newBuffer(2, 4)
initBuffer(buffer1,7,8,9,12)

```
buffer:map(function(r,g,b) return g,r,b end) -- Change channel order
buffer:map(function(r,g,b) return g,r,b end, nil, 2, 5) -- Change channel order for a subset of pixels
outbuf:map(function(r,g,b) return b end, inbuf, 10, 20) -- Extract one channel for a subset of pixels
Copy link
Member

Choose a reason for hiding this comment

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

wouldn't this fail because there are less return values than channels? (unless outbuf only has 1 channel)

#### Returns
`buffer0`

#### Example
Copy link
Member

Choose a reason for hiding this comment

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

After looking at the code I understand, but from the examples and description I won't be able to use this with more than a function as param.
Especially the fact that the channels of the second buffer are also passed and can have a different number.

@nwf nwf force-pushed the led-strip-refactor branch from 51fa0a8 to 74a4051 Compare January 5, 2021 00:38
@nwf
Copy link
Member Author

nwf commented Jan 5, 2021

Thanks. Does 74a4051 address your concerns?

nwf added 7 commits January 5, 2021 11:12
The new pixbuf module has more functionality than the ws2812-specific
buffer it replaces.

This is work in progress towards
nodemcu#2916

While here, document the ws2812 UART-based overlapping with mainline
execution.  Fixes
nodemcu#3140

This includes some untested hackery to keep the deprecated
ws2812_effects compiling.  We anticipate this module going away soon,
however.  See nodemcu#3122
These were never really driving the actual LEDs, which would be tricky
to test.

Convert to NTest and update
We were heading down the path of being a generic graphics library, which
is not the goal.
@nwf
Copy link
Member Author

nwf commented Jan 5, 2021

Still would like to have C functions to adjust channel order.
Using :map will be around 8 to 10 times slower.

A pure-C byte-order-swizzling operation is probably straightforward... what do you imagine its API should be? That is, how do you want to specify the mapping function?

Copy link
Member

@HHHartmann HHHartmann left a comment

Choose a reason for hiding this comment

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

Still would like to have C functions to adjust channel order.
Using :map will be around 8 to 10 times slower.

A pure-C byte-order-swizzling operation is probably straightforward... what do you imagine its API should be? That is, how do you want to specify the mapping function?

Maybe the map method could take defined values instead of a function to select a C operation.
buf:map(RGBtoGRB, [buf1[, ilo[, ihi]]]) -- SwapRG or ToGRB might also be a naming. Base would always be RGB. Others have to use their brain to find the correct setting.

This would be nice if you have strips with different channels connected together. But it would require a second buffer which uses memory. It is also a rather exotic scenario, which leads me to
another solution. That would be to add the parameter to the write methods.
`ws2812.write(bug, SwapRG)

To be channel neutral we could also pass ints to determin the new position of the channels.
Either as separate values or as array.
{2,1,3} would be equivalent to the above RGBtoGRB. It would also allow for 3 and 4 channels

@@ -48,6 +48,9 @@ extern LROT_TABLE(co_funcs);
extern LROT_TABLE(mathlib);
extern LROT_TABLE(utf8);

extern LROT_TABLE(pixbuf_map);
extern int luaopen_pixbuf(lua_State *);

Copy link
Member

Choose a reason for hiding this comment

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

Please also see Terrys comment #3230 (comment)

Should we have this in one PR for Lua 5.1 and Lua 5.3?

See #3230

Copy link
Member Author

Choose a reason for hiding this comment

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

I'll back the changes to this file out and we can deal with host-side deltas later.

@nwf nwf force-pushed the led-strip-refactor branch from 74a4051 to bdd14f8 Compare January 5, 2021 21:20
@HHHartmann HHHartmann added this to the Next release milestone Jan 6, 2021
@nwf nwf merged commit 85df6b5 into nodemcu:dev Jan 6, 2021
@marcelstoer
Copy link
Member

marcelstoer commented Feb 3, 2021

Sorry for coming back to this but I'm confused.

I was expecting some "Attention! This requires the pixbuf module"-style hints in the documentation of the affected modules but found none. I see that they all (unconditionally) #include "pixbuf.h" even though we've got //#define LUA_USE_MODULES_PIXBUF in the user_modules.h. Then I realized we don't use this define anywhere.

@HHHartmann
Copy link
Member

There are several modules whose define is never used. Expect four the link magic which decides what goes on the firmware. If I'm not mistaken we always build all modules. Conditional include only is used if the behavior would change. But indeed some hints might make sense.

@nwf
Copy link
Member Author

nwf commented Feb 3, 2021

Ideally, such intermodule dependencies would be handled by Kconfig (#3130). I'm rather buried at work right now, so may I ask someone else to update the docs in the interim?

@HHHartmann
Copy link
Member

Thought about it again.
There should be #IFDEF around the usage of pixbuf.
The hardware modules can be used without as data can be presented as stirrings too.
Only the effects need pixbuf and ws2812

@marcelstoer
Copy link
Member

may I ask someone else to update the docs in the interim?

That was my initial intention when I realised those hints wrt pixbuf were missing. Then I noticed that pixbuf is always compiled into the firmware as LUA_USE_MODULES_PIXBUF isn't used to steer that (my conclusion).

Now I don't know what the real issue is here: missing docs or missing define guards.

@HHHartmann
Copy link
Member

The build will break if one of the other modules are enabled without LUA_USE_MODULES_PIXBUF.
So this has to be fixed.
The documentation should mention that you need to enable pixbuf of you want to use it. Except for the effects module which requires pixbuf

@marcelstoer
Copy link
Member

I think we're talking past each other, sorry.

The build will break if one of the other modules are enabled without LUA_USE_MODULES_PIXBUF.

It doesn't, that's my point 😉 I disabled pixbuf (i.e. use the default) but enabled apa102, ws2801, ws2812, and ws2812_effects as they import pixbuf.h. I was stunned when the build didn't fail.

There's only a single occurrence of LUA_USE_MODULES_PIXBUF - in the user_modules.h. Doesn't that mean it's always compiled into the firmware? That would explain why my build didn't fail.

@HHHartmann
Copy link
Member

Yes, also checked and was surprised that it worked. It seems that the linker just pulls in the parts it needs. So I would guess that half the pixbuf module is linked. But haven't checked yet. EDIT: it seems that the whole module is pulled in.

The trick is done in app/Makefile and the NODEMCU_MODULE macro in app/include/module.h
The macro generates a symbol which is the pulled in the firmware if enabled. Don't really understand this in detail.

I think the linker then also pulls in the required modules.

So what do we want?
The modules apa102, ws2801, ws2812 should work even when pixbuf is disabled. Just without the pixbuf interface.
Use #ifdef in the code + notes in the doc that it will work but only with strings.
The module ws2812_effects without pixbuf will not work however. So this should fail the build I think.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants