-
Notifications
You must be signed in to change notification settings - Fork 3.1k
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
add wiegand module #3203
add wiegand module #3203
Conversation
luaL_unref(L, LUA_REGISTRYINDEX, wiegand_cb_ref); | ||
wiegand_cb_ref = LUA_NOREF; | ||
} | ||
return 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suspect that you ought to release the interrupt hook here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was trying to figure out how to do that. AFAICT, the softuart module doesn't ever unregister its hook. The rotary module does, but using a lower level function. I can't figure out the the gpio module explicitly registers their hook - it seems it's just uses an even lower level function to create a fallback hook. Any tips on the recommended way to do it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If there isn't an easy way to do this, just make sure that nothing bad happens if the interrupt hook is called when the device is closed. Also, if the device is reopened, then don't reregister the hook (or maybe the hook registration code already takes care of it). Please add a comment to say what strategy you are following in the close function.
I think that you probably want to handle the timer somewhat differently -- there can be significant delays between posting the task and when it gets to run. You might want to save the value of Also, try not to post tasks if the previous one has not yet been scheduled. The queues are not very large and posting 30 tasks will certainly overflow the queue -- and could cause other tasks to be dropped as well. |
I'll definitely adjust the task posting. In terms of the timeout, I wasn't really concerned about being precise. It just needs to not try to collect the message until at least that long as passed. I wanted to avoid dealing with clock wraparounds because I know they can be pitfalls. The amount of time between individual bits in a message (< 20ms) is microscopic compared to the amount of time between separate messages (I can't get my keypad to send faster than 1 message/s when I'm mashing it, and with an actual RFID card it's nearly 2s. |
tools/luacheck_config.lua
Outdated
setup = empty, | ||
close = empty | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if you noticed but the CI build failed.
Critical error: Couldn't load configuration from tools/luacheck_config.lua: syntax error (line 726: '}' expected (to close '{' at line 5) near 'wifi')
Ah, the Wiegand protocol. Thank you for taking a stab at doing it in Lua, but yea, this one is very timing sensitive and probably needs to be in C. However, be advised that the progenitor library, https://github.com/monkeyboard/Wiegand-Protocol-Library-for-Arduino, says in its README that
I have no issue with (L)GPL (in fact, much prefer it for my own work), but the NodeMCU tree is mostly MIT. We should perhaps have a mechanism to permit clearly documented exceptions that may change the distribution requirements for the resulting binaries (in this case, by adding an obligation to provide the wiegand module source). |
Good point. I copied the license lines into the top of my |
If you don't mind, I'd like to mark this PR as blocked and raise a separate issue for the governance question? |
The more I think about it, the more I believe I should probably just start over from scratch. The module gets statically linked in, so technically even the LGPL would require infecting the rest of the code base with the license. |
That's not enough unfortunately. Unless the source can be at least dual-licensed (which wouldn't make much sense in this case) we can't accept that, sorry. I remember we have had two similar cases in the past. In one case the original author was willing to change the license of his project to something compatible with MIT. In the other case the developer contributing to NodeMCU was determined to add the new module and rewrote it "without" the source of original lib to stay clear of licensing issues. |
ok, PR updated. the Wiegand/gpio code has been completely re-written from scratch, so no more (L)GPL code. This means losing support for things besides 4 bit and 26 bit (the two types the keypad I have can send). I refactored things while I was doing it so that multiple instances can exist at the same time. While doing this, I figured out how to properly de-register my interrupt hooks (just "re-register" with a mask of 0; when registering for multiple instances it has to register a single hook for all pins at once). I also tweaked the timer code while I was in there to only delay the remaining time to get to 25ms in case the posted task takes a while to execute. Oh yeah, and another task isn't posted until the prior one runs. Phew! I learned quite a bit about the interrupt system and dbg_print while I was getting this one to work :). |
f18752c
to
a556a68
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for not reviewing sooner. I've one nit and some questions arising from ignorance, but this looks like it could land.
app/modules/wiegand.c
Outdated
continue; | ||
} | ||
|
||
++w->bit_count; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whitespace nit
if ((gpio_bits & 1) == 0) | ||
continue; | ||
// find the struct registered for this pin | ||
volatile wiegand_t w = pins_to_wiegand_state[i]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't believe there's need for this to be volatile?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pins_to_wiegand_state is volatile, so to assign it to another variable (it's a pointer) you'd have to cast the volatile away.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm familiar with the C type system, yes. I mean more "what is volatile
accomplishing here"? Is the interrupt racing some mainline code such that the compiler using a cached value rather than rereading wouldn't work out? (Presumably the interrupt can't be using volatile
to defend against concurrent mutation by mainline code?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, okay. I'm not an expert at volatile and interrupts. assuming the compiler would only cache within the interrupt routine, we'd be fine. but if it caches across multiple calls to the interrupt, we would not - the same array can be updated by mainline code if you instantiate multiple instances of the wiegand object (to handle multiple card readers)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, all value reuse is within routines like that. The C abstract machine (a PDP-11, essentially!) is single-threaded, which is why the compiler can cache memory values in registers: if we don't change it, surely it's not changed. This is also the origin of the "strict aliasing" rules: how do we know that a pointer doesn't alias the pointer we used to read a value? (We rely on the C type system, of all things, to answer that question.)
app/modules/wiegand.c
Outdated
{ | ||
lua_State *L = lua_getstate(); | ||
|
||
volatile wiegand_t w = (wiegand_t) param; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similarly, might not need to be volatile.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you're right on this one.
* fix a whitespace error (tabs!!!!) * remove an unnecessary volatile qualifier
w->last_bit_time = system_get_time(); | ||
|
||
if (!w->task_posted) { | ||
task_post_medium(tasknumber, (os_param_t)w); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm; forgive another naive question: what happens if you task_post
the same task twice? If nothing bad (that is, if they don't queue up but instead posting is idempotent) I think you could replace this with if (!w->timer_running)
?
@nwf are you ready to merge this? |
Sure; let's get it some hopefully wider testing. I, sadly, lack the hardware to do so. |
* add wiegand module * minor tweaks to wiegand module * fix a whitespace error (tabs!!!!) * remove an unnecessary volatile qualifier
* add wiegand module * minor tweaks to wiegand module * fix a whitespace error (tabs!!!!) * remove an unnecessary volatile qualifier
dev
branch rather than formaster
.docs/*
.Add a module to support Wiegand keycard readers. I first tried using the gpio module, but quickly realized that doing it in Lua was too slow to properly capture the protocol. All the bits got through, but because there are multiple data lines, and they were fast, they got lumped together and you couldn't fix the original order of the bits