Moteino keeps cycling through setup

Started by raenrfm, September 28, 2017, 11:10:24 PM

raenrfm

Thanks for the assistance Tom, much appreciated!  I will try your suggestions.

raenrfm

Tom, now that I sorted out my interrupt issues, I'm still having problems with I think the capabilities of the Moteino.  I think what I'm trying to do here with concatenating these converted floats together is just taxing the memory too much.  Is there a better way to do what I'm looking to do?  Essentially I have the following measurables that I gather from my sensors and some need to be calculated in the mote just because of speed in order to be accurate:

Temperature (will sample probably once a minute no more)
Humidity (same sample rate)
Windspeed and Direction (will be constantly updated, no sleeping here)
Rain (same as wind, needs to be monitored because we can't miss a bucket tip on the sensor)

Then of course I have to bundle all this into a nice tidy radio packet(s) to send to my gateway which is looking for the following format:

topic/label:value,label:value, etc... so in this case: weather/tempF:XX.X, outHumidity:XX.X....etc.

So, is using the dtostrf and strcat functions really the best way to do this?  Or is there a more efficient/tidy way to do this so that I'm not pushing up against the memory limits of the poor little Mote?

raenrfm

Forgot to mention that the windgust and windgust directions need to be calculated based on the 10 minute average, and should be done in the Mote before sending it to the gateway.  I could try to offload that to my gateway, but then it would really upset the generic mqtt nature of my gateway which I want to preserve.

TomWS

Quote from: raenrfm on October 09, 2017, 12:15:01 PM
So, is using the dtostrf and strcat functions really the best way to do this?  Or is there a more efficient/tidy way to do this so that I'm not pushing up against the memory limits of the poor little Mote?
I rarely use floats in embedded controllers.  I've used fixed point values for so long that you probably weren't even born... uh, never mind...

The temp/humidity sensor you're using is a good example of this - the accuracy of the humidity sensor is +/- 2%.  Do you REALLY need a float to represent this?  The temp sensor, IIRC is 1/16 degree C resolution.  Keep it at that value until you're ready to convert to 'float' Fahrenheit.  Then convert to 16bit integer and scale up by 10 or 100 so the LSBs aren't lost and do the math to convert to Fahrenheit hundreths.  Then the value you send is in two parts:  Integer part is temp/100.  Fractional part is temp%100 - easy peasy and much faster and MUCH less program/data memory than using floating point values.   When you move back to your ARM Cortex M4F, then you can use floats...

Also, I can't recall the last time I used strcat...  I think it was shortly after I moved away from PL/I.  In your case I'd use sprintf() (which you're using anyway), to move the label and value into a buffer, using sprintf's feature of returning the number of characters moved to update your buffer pointer.

For example:
int len;
uint8_t buffer[64];

len =sprintf(buffer,"weather/outtemp:%d.%02d",intTemp,fracTemp);
len+=sprintf(&buffer[len],",outHumidity:%d",humidity);
len+=sprintf(&buffer[len],",rain:%d.%02d",intRain,fracRain);
....

Note that only ONE buffer is used above.  And the label values only take up one location.  Uunfortunately sprintf won't use PROGMEM data conveniently, but I think you've saved enough with this approach...

Tom

perky

Quote from: TomWS on October 09, 2017, 07:59:19 PM
unfortunately sprintf won't use PROGMEM data conveniently, but I think you've saved enough with this approach...

Are you sure about that? There's sprintf_P and associated PSTR macro, I think the following will work:

len =sprintf_P(buffer,PSTR("weather/outtemp:%d.%02d"),intTemp,fracTemp);
len+=sprintf_P(&buffer[len],PSTR(",outHumidity:%d"),humidity);
len+=sprintf_P(&buffer[len],PSTR(",rain:%d.%02d"),intRain,fracRain);


Mark.

TomWS

Quote from: perky on October 10, 2017, 11:45:27 PM
Are you sure about that? There's sprintf_P and associated PSTR macro, I think the following will work:

len =sprintf_P(buffer,PSTR("weather/outtemp:%d.%02d"),intTemp,fracTemp);
len+=sprintf_P(&buffer[len],PSTR(",outHumidity:%d"),humidity);
len+=sprintf_P(&buffer[len],PSTR(",rain:%d.%02d"),intRain,fracRain);


Mark.
Thanks Mark, I hadn't used this version so didn't want to recommend it, especially since the technique in its first form is portable.  I found this while following up on your post:
https://forum.arduino.cc/index.php?topic=383898.msg2647013#msg2647013

Useful indeed, if you happen to be using a memory anemic AVR processor...  or is that redundant?

Tom

perky

Yeah, it's quite handy. The printf_P variant is also extremely useful if you have lots of degug code or menu options to print. I use that by default for printing any literal strings, it can save a lot of SRAM.

Mark.

raenrfm

Tom, so I tried this:

  // Get the sensor's humidity value.
  float humidity = am2315.readHumidity();  
  // Get the sensor's temperature value in Celsius and Fahrenheit.
  float tempC = am2315.readTemperature();
  float tempF = ((tempC * 9)/5)+32;
  //Get rid of float
  int16_t tempFscaled = tempF*100;
  int16_t intTemp = tempFscaled/100;
  int16_t fracTemp = tempFscaled%100;
  int16_t rainscaled = dailyrainin*1000;
  int16_t intRain = rainscaled/1000;
  int16_t fracRain = rainscaled%1000;
  Serial.println(tempF);
  Serial.println(intTemp);
  Serial.println(fracTemp);
  Serial.println(dailyrainin);
  Serial.println(intRain);
  Serial.println(fracRain);

  int len;
  uint8_t buffer[64];
  len =sprintf(buffer,"weather/outTemp:%d.%02d",intTemp,fracTemp);
  //len+=sprintf(&buffer[len],",outHumidity:%d",humidity);
  //len+=sprintf(&buffer[len],",rain:%d.%02d",intRain,fracRain);
  Serial.println(len);


and no matter what I'm getting "invalid conversion from 'uint8_t* {aka unsigned char*}' to 'char*' [-fpermissive].  Not sure what I'm doing wrong here?

raenrfm

I fixed it by declaring char buffer[64] instead.  Guess it didn't like the uint8_t.

perky

sprintf requires the buffer to be a char*. You could also fix it by casting buffer to uchar* in the sprintf, but if you have other functions that modify buffer and require it to be a uint8_t* you'll probably might want to do that instead. It's quite annoying that things typedef'd to exactly the same thing are flagged up as type errors.

Mark.

TomWS

Quote from: perky on October 14, 2017, 03:14:17 PM
It's quite annoying that things typedef'd to exactly the same thing are flagged up as type errors.
It's not the same, which is why it's getting flagged.  A 'char' is considered a signed 8 bit value (don't ask me why) whereas uint8_t, AKA unsigned char, is unsigned. 

Now we all know that sprintf doesn't care about the signedness of the contents of the buffer, but apparently sprintf not overloaded to take either.

Tom

perky

#26
I see what you're saying but it's not sign per se that's causing the error as whether a char is signed or not signed is compiler specific, it's not specified in C. So char, unsigned char and signed char are all different types. The default for gcc is to treat char as signed, but this can be overridden to unsigned. So even if sprintf were over-loaded to take char, unsigned char or signed char, using a uint8_t, which is typedef'd to unsigned char, will still have caused a type mismatch error.

Mark.