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

added support for ads1015 #2231

Merged
merged 6 commits into from Jan 29, 2018
Merged

added support for ads1015 #2231

merged 6 commits into from Jan 29, 2018

Conversation

paweljasinski
Copy link
Contributor

Fixes #2223.

  • 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/en/*.

This PR introduces support for ADS1015 based on the code for ADS1115.
In addition this PR includes:

  • support for up to 4 converters (hardware limit).
  • ads1115.setup() does not perform i2c general reset anymore. Reset is available as a separate function.

Due to formatting changes (removal of the tabs), it is probably good idea to use ?w=1 when looking at the diff.

@devsaurus
Copy link
Member

This appears to be a good extension of the current module, thanks a lot!

Apart from adding support for ADS1015 chips, it also enables having more than one converter attached to the ESP. I see that you arranged for a descriptor array which covers up to four of them. That caught my interest as your implementation is now very close to an object-oriented approach. Except for the API, which acquired complexity with the I2C address selection parameter for each command.

How about moving the API also towards objects, for example:

conv1 = ads1115.setup(<i2c_id>, ads1115.ADDR_GND, ads1115.ADS1115)
conv2 = ads1115.setup(<i2c_id>, ads1115.ADDR_VDD, ads1115.ADS1015)

conv1:setting(<gain>, <dr>, ...)
conv2:setting(<gain>, <dr>, ...)

conv1:startread()
...
conv1:read()

The <i2c_id> aims for future compatibility with the ESP32 which supports multiple I2C buses.

You could even differentiate between the sub-types with dedicated constructors instead of the generic setup():

conv1 = ads1115.ads1115(<i2c_id>, ads1115.ADDR_GND)
conv2 = ads1115.ads1015(<i2c_id>, ads1115.ADDR_VDD)

This would be very close to the approach we discussed in #2188.

What do you think?

@marcelstoer marcelstoer added this to the 2.2 milestone Jan 20, 2018
@paweljasinski
Copy link
Contributor Author

@devsaurus, yes, the oop API looks better, particularly when esp32 and multiple i2c buses are considered. Is there a mechanism to share module code between 8266 and 32 branches?

@marcelstoer
Copy link
Member

Is there a mechanism to share module code between 8266 and 32 branches?

There isn't, sorry.

@paweljasinski
Copy link
Contributor Author

I didn't squash to make move to oop API easier for review.

@paweljasinski
Copy link
Contributor Author

How about testing artifacts? I have a couple of scripts which together with a hardware schematics could be checked in.

@marcelstoer
Copy link
Member

I didn't squash to make move to oop API easier for review.

Good decision, thanks.

How about testing artifacts?

This is/was discussed in #2145 -> no established mechanism yet.

Copy link
Member

@devsaurus devsaurus left a comment

Choose a reason for hiding this comment

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

Very nice job, thank you so much!

Please clarify the potential memory leak when gc'ing the object and this one's ready for merging.

@@ -581,11 +557,23 @@ static const LUA_REG_TYPE ads1115_map[] = {
{ LSTRKEY( "COMP_1CONV" ), LNUMVAL(ADS1115_CQUE_1CONV) },
{ LSTRKEY( "COMP_2CONV" ), LNUMVAL(ADS1115_CQUE_2CONV) },
{ LSTRKEY( "COMP_4CONV" ), LNUMVAL(ADS1115_CQUE_4CONV) },
{ LSTRKEY( "ADS1015"), LNUMVAL(ADS1115_ADS1015) },
{ LSTRKEY( "ADS1115"), LNUMVAL(ADS1115_ADS1115) },
{ LSTRKEY( "CMODE_TRAD"), LNUMVAL(ADS1115_CMODE_TRAD) },
{ LSTRKEY( "CMODE_WINDOW"), LNUMVAL(ADS1115_CMODE_WINDOW) },
{ LNILKEY, LNILVAL }
Copy link
Member

Choose a reason for hiding this comment

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

The __gc index is not defined - I suspect memory leaks when the device object is disposed by the garbage collector while timer_ref still holds a reference to the callback. Similarly, an armed os_timer would need to be shut down gracefully.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Somehow I convinced myself that it will not happen, but on the second iteration I believe it will be worse than memory leak.

  1. Timer is armed.
  2. Device object is garbage collected.
  3. Timer fires, with ads_ctrl referencing user data which can be anything at this moment.

uint8_t i2c_addr = luaL_checkinteger(L, 1);
uint8_t i2c_id = luaL_checkinteger(L, 1);
if (i2c_id != 0) {
return luaL_error(L, "Invalid argument: i2c_id");
Copy link
Member

Choose a reason for hiding this comment

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

It's recommended to use luaL_argcheck() when checking arguments.
I understand that you follow the pattern in the existing code, but unfortunately that was already inconsistent.

ads_ctrl_ud_t *ads_ctrl = luaL_checkudata(L, 1, metatable_name);
if (ads_ctrl->timer_ref != LUA_NOREF) {
os_timer_disarm(&ads_ctrl->timer);
lua_rawgeti(L, LUA_REGISTRYINDEX, ads_ctrl->timer_ref);
Copy link
Member

Choose a reason for hiding this comment

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

Why push timer_ref onto the stack? It's redundant at least and might leak memory since the return below says 0 results (not sure, can't run the code without a chip).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

A bit of cargo on my side - I took a snipped out of readoutdone without fully understanding what it does. Fixing it explained some other anomaly I have seen.

@paweljasinski
Copy link
Contributor Author

I gave a try to mispec mentioned in #2145. Here is the result: https://github.com/paweljasinski/nodemcu-mispec/blob/master/nodemcu/mispec_ads1115.lua

@devsaurus devsaurus merged commit f87d68f into nodemcu:dev Jan 29, 2018
dnc40085 pushed a commit to dnc40085/nodemcu-firmware that referenced this pull request Mar 3, 2018
* ads1015 is supported, up to 4 devices can be connected at the same time

* removed debug, updated documentation

* changed to oop API

* added __gc to handle active timer cleanup

* reworked argument validation and error reporting

* stack is no longer messed up after __del
vsky279 pushed a commit to vsky279/nodemcu-firmware that referenced this pull request Mar 10, 2018
* ads1015 is supported, up to 4 devices can be connected at the same time

* removed debug, updated documentation

* changed to oop API

* added __gc to handle active timer cleanup

* reworked argument validation and error reporting

* stack is no longer messed up after __del
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.

None yet

3 participants