Hi
First of all thank you for the good work.
I just have a feature request (I'm already coding it, but since it changes the interfaces of your library I'm asking here before trying to contribute with a PR).
Usually when you have callbacks in libraries you try to give the user possibility to share something custom, so that it can use it to, for instance, refer to the parent object. With callbacks I saw it being done with void pointers. So what I'm doing is:
- In the header:
- Redefine the
ResultHandler to accept a void pointer
- Make all functions accepting
ResultHandlers to accept also the pointer
- Of course store the pointer alongside
resultHandler in the class
- In the source file:
- Initialize
resultCtx in the constructor to nullptr
- Have the init function store the passed value in
resultCtx
- Every time the init function is called, pass also the new context
- Pass the value back in the callback
Code in the header file:
typedef void (*ResultHandler)(NonBlockingModbusMaster &mb, void *ctx);
[...]
bool readCoils(uint8_t slaveId, uint16_t address, uint16_t qty, ResultHandler handlerFn = NULL, void *ctx = nullptr);
// And all the other functions, including init
[...]
// context to be passed to the result handler
void *resultCtx;
Code in the source file:
resultCtx = nullptr;
[...]
resultCtx = ctx;
[...]
if (!init(_u8MBSlave, resultHandler, resultCtx)) {
[...]
if (!init(slaveId, handlerFn, ctx)) {
[...]
if (resultHandler) {
resultHandler(*this, resultCtx); // can start another cmd
}
Why bother to do all this? Because then in the callback I can process the custom object however I need. For instance, if I have an object managing the MODBUS communication, I can pass it to the function and then get it back in the callback:
void static_cb(NonBlockingModbusMaster &mb, void *ctx)
{
MyParser *obj = (MyParser *) ctx;
[...] // Collect the Response Buffer
obj->parse(stuff_from_response_buffer);
}
void MyParser::request()
{
this->_nbModbusMaster.readHoldingRegisters(slaveId, address, qty, static_cb, (void*) this);
}
void MyParser::parse(my_type something_from_response_buffer)
{
// Here I'm again in the parser
}
The alternative is to save MyParser instance in a static variable, but this is far less flexible
If you want to have a look at the complete code I wrote to modify the library I can share it on github and create a PR to you :)
Hi
First of all thank you for the good work.
I just have a feature request (I'm already coding it, but since it changes the interfaces of your library I'm asking here before trying to contribute with a PR).
Usually when you have callbacks in libraries you try to give the user possibility to share something custom, so that it can use it to, for instance, refer to the parent object. With callbacks I saw it being done with void pointers. So what I'm doing is:
ResultHandlerto accept avoidpointerResultHandlers to accept also the pointerresultHandlerin the classresultCtxin the constructor tonullptrresultCtxCode in the header file:
Code in the source file:
Why bother to do all this? Because then in the callback I can process the custom object however I need. For instance, if I have an object managing the MODBUS communication, I can pass it to the function and then get it back in the callback:
The alternative is to save MyParser instance in a static variable, but this is far less flexible
If you want to have a look at the complete code I wrote to modify the library I can share it on github and create a PR to you :)