RFM69 Class -> Recall init Class

Started by Charly86, August 28, 2014, 05:51:49 AM

Charly86

Hi guys,

I'm going there to try to ask help to C++ gurus, I know perfectly C but not C++. My code use RFM69 library and I usually create the object on the form

RFM69 radio69(RF69_CS, RF69_IRQ, false);


I've so much different boards that use different CS and IRQ that each time I compile I need to set the current constant  RF69_CS RF69_IRQ using some #define in my code and lot of #ifdef depending on the board. So I decided to put the configuration in EEPROM like that, I can compile same code for various board not dealing which type of board and connections are physically made to the RF Module. I do it just one time at first setup of the board and then forgot it.

So my question is : is there a way to call again radio69(RF69_CS, RF69_IRQ, false) is setup() for example ?
Or better create new method of RFM69 class in my own code (such as setCS() and setIRQ()) so leaving the library untouched ?

Of course I can change the library to add func, but I've done this for severals other libs and the deal is that each time the author do modifications, I need to report back in the one I modified, and using about 10 others libs, it's just a mess to report author modifications in your own, that's why I would like to leave RFM69 lib untouched.

Any help will be very much appreciated.

Thanks



Felix

Hey Charly,
You could do something like what I've done for SwitchMote. I used a CONFIG sketch to load the essential hardware settings in EEPROM once. Then the SwitchMote sketches just read that back so the code doesn't have to change settings for each SwitchMote depending on the radio hardware.
In any case I would setup the parameters before calling init.

Charly86

Felix,

Thanks for your response, this is actually what I'm doing, all configuration is stored in EEP, but there is no method for changing IRQ pin in RFM69 library such as setCS() so for this I needed to tweak the RFM69 Library and  it's working fine.
For information here the method I created :
void RFM69::setIRQ(byte newIRQ) {

  // start to remove old IRQ Handler to be safe
  detachInterrupt(_interruptNum);
  
  #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__)
    //  External IRQ authorized are D2 (INT0) or D3 (INT1)
    _interruptPin = newIRQ;
    _interruptNum = newIRQ-2;
  #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)
    //  IRQ authorized are D10 (INT0), D11 (INT1) or D2 (INT2)
    if (newIRQ==10 || newIRQ==11 || newIRQ==2)
    {
      _interruptPin = newIRQ;
      _interruptNum = newIRQ==2?3:newIRQ-10;
    }
  #else
    #error Target not supported for external Interrupts
  #endif
}


But it's not sufficient for my needs, let me explain in detail, I've got a board on which I can have 2 modules of choice, for example :
- 1 RFM12B + 1 RFM69
- 2 RFM12B (2 differents speed or 2 differents frequencies whatever, ...)
- 2 RFM69 (2 differents speed or 2 differents frequencies whatever, ...)
All configuration is stored into EEP but at init I need to instantiate the correct modules, so today the solution is to instantiate at compile time 4 modules (2 RFM12 + 2 RFM69) but this is memory consuming and I would like to instantiate only the module needed by creating something like :

radio1 = new RFM12(...);
radio2 = new RFM69(....);

into C++ code but I do not know how to do this and even if it's doable.

Just tell me if I'm not clear in my explanations.

Felix

I think I understand what you are looking for.
Unfortunately the two RFM libraries are not interfaced together and hence they are different in function calls. If RFM12B was a more interesting module I might have invested the time to do that, but it's not and I don't think it's worth the time to do it at this point since almost nobody is sourcing RFM12B any more.

But anyway, to do what you want, you can just create the radio variables without instantiating them, as pointers, then conditionally create the instances.

RFM69* radio69;
RFM12B* radio12;

void setup() {
  if (EEPROM_RFM69)
  {
    RFM69 radio;
    radio.initialize(FREQUENCY,NODEID,NETWORKID);
    radio69 = &radio;
  }
  else if (EEPROM_RFM12B)
  {
    RFM12B radio;
    radio.Initialize(FREQUENCY,NODEID,NETWORKID);
    radio12 = &radio;
  }
}


After that you will have to keep two lines of code whenever you make calls to differentiate between the different function call names. If the libraries were behind an interface they would have the same calls and variables, with RFM12B having less functionality than RFM69 (perhaps dummy function calls and variables in place).

Charly86

Felix,

This is exactly what I needed, thanks.

Supid question, but the radio var will not be freed after the if since it's declared into if { } and should not exist after that ?

correct I want to create high level funct which call the correct function depending of the module type.

Thank you very much for your help


Felix

The variable will not exist any more but the instance will exist until you explicitly free it. The pointer var will point to it.
You could create a wrapper class with pointer variables of type RFM69 and RFM12B and then create some wrapper functions that call to the two different libraries. Just an idea... I imagine it can be a lot of effort. Maybe it's worth to wrap everything in an interface instead.

Charly86

Felix,

Well, I rewrited all my code to conform to your suggestion and as far as I tested for RFM12B it works partially (did not tested yet for RFM69). Let me explain

My code crash as soon as I try to send a packet, so I tought it was in my code since I've done a major rewrite, but after investigation it's not that. So I deep under the ground and found the solution.

The problem is coming from the cypt func (that I do not use) but it appears that when I call radio12->send() method, then the code after (in the lib) call SendStart() and the crash happens on the following line of Sendstart()
if (crypter != 0) 
  crypter(true);

why ? because when called crypter in not NULL and point certainly to nowhere but certainly not to CryptFunction (I Serial.print in it and got nothing). So I tried several things without success
radio12->Encrypt(0); // this should set crypter to 0 but does not at 0 when I calling send just after
radio12->send(....)

Also tried in Initialize funct of RFM12 lib
crypter = 0; // does not work 
Encrypt(0); // does not work either


The only way to fix it is to add the Encrypt(0); into the Send method
void RFM12B::Send(uint8_t toNodeID, const void* sendBuf, uint8_t sendLen, bool requestACK, uint8_t waitMode)
{
  while (!CanSend()) 
    ReceiveComplete();
    
  Encrypt(0);
  SendStart(toNodeID, sendBuf, sendLen, requestACK, false, waitMode);
}


Like this, all is working (except encryption of course) but why it does not work when I do on Initialize func that I call before) ???

This is some magic voodo of C++  certainly and dynamic memory allocation on the heap or pseudo dynamic instantation of RFM12 object that does not zeroe the data, I really don't know , I fixed it but not really confident because I'm not sure I will not have some board effects on other things.

Felix

Not to sound ignorant or trying to sell something, but if you think of how many hours are spent trying to beautify or featurize RFM12B (and how much $ every hour is worth) it would be more economical to just upgrade to RFM69 which is a much nicer radio.