mcci-catena / arduino-lmic

LoraWAN-MAC-in-C library, adapted to run under the Arduino environment
https://forum.mcci.io/c/device-software/arduino-lmic/
MIT License
629 stars 207 forks source link

32u4 problems: Error compiling library from include, missing "scalbnf" #114

Closed EtoTen closed 5 years ago

EtoTen commented 5 years ago

I am getting an error, using master branch.

... C:\Users\x\Documents\Arduino\libraries\arduino-lmic-master\src\lmic/lmic_util.c:88: undefined reference to `scalbnf'

collect2.exe: error: ld returned 1 exit status

exit status 1 Error compiling for board LoRa32u4II (868-915MHz).

EtoTen commented 5 years ago

Tested master release 2.1.5, does not suffer from same error. I believe it has to do with the new code that converts data to sflt16. Not sure why my math.h does not have scalbnf defined. Using Arduino 1.8.7 IDE with a LoRa32u4II board.

terrillmoore commented 5 years ago

Yes, that makes sense. I don't have a regression test case for the AVRs. Very sorry. The quick workaround for you would be to delete the new lmic_util.c file as it's not used by the LMIC library but is provided for users. (I take it that the AVR compiler doesn't do as good a job of omitting unused code, or that is incomplete.)

terrillmoore commented 5 years ago

Hi again... I tested with the Adafruit 32u4 BSP without difficulty. So I can't repro this. I'm using 1.8.5 with Adafruit BSP; test ws ttn-otaa-feather-us915.ino (after editing to add || defined(ARDUINO_AVR_FEATHER32U4) at line 77). This looks like a BSP limitation. Can you give me the exact link to the BSP you're using?

EtoTen commented 5 years ago

I think I am using an older version of this https://github.com/BSFrance/BSFrance-avr so my board is defined as "BSFrance AVR Boards" -> "LoRa32u4II (868-915MHz)" Let me try and switch to https://github.com/adafruit/Adafruit_Arduino_Boards (feather32u4) and report back.

EtoTen commented 5 years ago

Ok switched it to feather32u4... still getting:

Linking everything together... "C:\Users\xx\AppData\Local\Arduino15\packages\arduino\tools\avr-gcc\4.9.2-atmel3.5.4-arduino2/bin/avr-gcc" -w -Os -g -flto -fuse-linker-plugin -Wl,--gc-sections -mmcu=atmega32u4 -o "C:\Users\xx\AppData\Local\Temp\arduino_build_117480/ttn-otaa-feather-us915-dht22.ino.elf" "C:\Users\xx\AppData\Local\Temp\arduino_build_117480\sketch\ttn-otaa-feather-us915-dht22.ino.cpp.o" "C:\Users\xx\AppData\Local\Temp\arduino_build_117480\libraries\arduino-lmic-2.2.0\aes\ideetron\AES-128_V10.cpp.o" "C:\Users\xx\AppData\Local\Temp\arduino_build_117480\libraries\arduino-lmic-2.2.0\aes\lmic.c.o" "C:\Users\xx\AppData\Local\Temp\arduino_build_117480\libraries\arduino-lmic-2.2.0\aes\other.c.o" "C:\Users\xx\AppData\Local\Temp\arduino_build_117480\libraries\arduino-lmic-2.2.0\hal\hal.cpp.o" "C:\Users\xx\AppData\Local\Temp\arduino_build_117480\libraries\arduino-lmic-2.2.0\lmic\lmic.c.o" "C:\Users\xx\AppData\Local\Temp\arduino_build_117480\libraries\arduino-lmic-2.2.0\lmic\lmic_as923.c.o" "C:\Users\xx\AppData\Local\Temp\arduino_build_117480\libraries\arduino-lmic-2.2.0\lmic\lmic_au921.c.o" "C:\Users\xx\AppData\Local\Temp\arduino_build_117480\libraries\arduino-lmic-2.2.0\lmic\lmic_eu868.c.o" "C:\Users\xx\AppData\Local\Temp\arduino_build_117480\libraries\arduino-lmic-2.2.0\lmic\lmic_eu_like.c.o" "C:\Users\xx\AppData\Local\Temp\arduino_build_117480\libraries\arduino-lmic-2.2.0\lmic\lmic_in866.c.o" "C:\Users\xx\AppData\Local\Temp\arduino_build_117480\libraries\arduino-lmic-2.2.0\lmic\lmic_us915.c.o" "C:\Users\xx\AppData\Local\Temp\arduino_build_117480\libraries\arduino-lmic-2.2.0\lmic\lmic_us_like.c.o" "C:\Users\xx\AppData\Local\Temp\arduino_build_117480\libraries\arduino-lmic-2.2.0\lmic\lmic_util.c.o" "C:\Users\xx\AppData\Local\Temp\arduino_build_117480\libraries\arduino-lmic-2.2.0\lmic\oslmic.c.o" "C:\Users\xx\AppData\Local\Temp\arduino_build_117480\libraries\arduino-lmic-2.2.0\lmic\radio.c.o" "C:\Users\xx\AppData\Local\Temp\arduino_build_117480\libraries\SPI\SPI.cpp.o" "C:\Users\xx\AppData\Local\Temp\arduino_build_117480\libraries\DHT_sensor_library\DHT.cpp.o" "C:\Users\xx\AppData\Local\Temp\arduino_build_117480\libraries\DHT_sensor_library\DHT_U.cpp.o" "C:\Users\xx\AppData\Local\Temp\arduino_build_117480/core\core.a" "-LC:\Users\xx\AppData\Local\Temp\arduino_build_117480" -lm C:\Users\xx\AppData\Local\Temp\ccvjOn3N.ltrans4.ltrans.o: In function `LMIC_f2sflt16.part.0.lto_priv.117':

C:\Users\xx\Documents\Arduino\libraries\arduino-lmic-2.2.0\src\lmic/lmic_util.c:88: undefined reference to `scalbnf'

collect2.exe: error: ld returned 1 exit status

Using library arduino-lmic-2.2.0 at version 2.2.0 in folder: C:\Users\xx\Documents\Arduino\libraries\arduino-lmic-2.2.0 Using library SPI at version 1.0 in folder: C:\Users\xx\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\libraries\SPI Using library DHT_sensor_library at version 1.3.0 in folder: C:\Users\xx\Documents\Arduino\libraries\DHT_sensor_library Using library Adafruit_Unified_Sensor at version 1.0.2 in folder: C:\Users\xx\Documents\Arduino\libraries\Adafruit_Unified_Sensor exit status 1 Error compiling for board Adafruit Feather 32u4.

terrillmoore commented 5 years ago

Oh. I see you're compiling ttn-otaa-feather-us915-dht22.ino. That was the key missing bit of information. I regret to say that probably scalbnf() is not available in the AVR libraries. It is possible that ldexp() is available, and will work. I can't test, other than doing a compile test, but I'll check that.

terrillmoore commented 5 years ago

Yep. Please try this, since you can test (I can only compile):

  1. open libraries/arduino-lmic/src/lmic/lmic_util.c

  2. add (after #include <math.h>, line 18):

    #define scalbnf(x,e) ldexpf(x,e)
  3. Compile (works for me)

  4. See if you're able to send data.

In case you're finding strange results, you should do some experiments in a sketch:

#include <math.h>
...
for (int i = 0, i < 16; ++i)
   Serial.println(ldexpf(1.0, i));

You should get a table of powers of 2 (1, 2, 4, 8, 16, etc., up to 65536).

(It turns out that I really want ldexpf() anyway... I don't know why I chose scalbnf(), it happens to work but it's not strictly portable to strange machines with hexadecimal floating point, whereas ldexp() is. Asleep at the keyboard.)

EtoTen commented 5 years ago

It compiles/links now! Wohoo!

" for (int i=0; i<16; ++i) Serial.println(ldexpf(1.0, i));"

Results in:

1.00 2.00 4.00 8.00 16.00 32.00 64.00 128.00 256.00 512.00 1024.00 2048.00 4096.00 8192.00 16384.00 32768.00

For some reason I am getting a "0" result on thingsnetwork using that javascript decoder "function sflt162f(rawSflt16)".

terrillmoore commented 5 years ago

Please try for (int i=0; i < 16; ++i) Serial.println(ldexpf(1.0, -i)); -- make sure you get 1, 0.5, 0.25, etc.

Then look carefully at how you're feeding the decoder function. Remember that you have to pick up two bytes and combine them before calling the decoder. Brant transmitted the data low-order byte first, so you'll need to compute buf[i] + buf[i+1]*256, in this example, and pass that number to the decoder.

I'm going to merge my fix #128 to master now. No time for a release tonight.

EtoTen commented 5 years ago

NVM,

I did not have full decoder code as I did not realize that it worked in two byte pairs... just found this code:

function Decoder(bytes, port) {
  // Decode an uplink message from a buffer
  // (array) of bytes to an object of fields.
  var decoded = {};

  // temperature 

  rawTemp = bytes[0] + bytes[1] * 256;

  decoded.degreesC = sflt162f(rawTemp) * 100;

  // humidity 
  rawHumid = bytes[2] + bytes[3] * 256;
  decoded.humidity = sflt162f(rawHumid) * 100;

  return decoded;
}

function sflt162f(rawSflt16)
    {
    // rawSflt16 is the 2-byte number decoded from wherever;
    // it's in range 0..0xFFFF
    // bit 15 is the sign bit
    // bits 14..11 are the exponent
    // bits 10..0 are the the mantissa. Unlike IEEE format, 
    //  the msb is transmitted; this means that numbers
    //  might not be normalized, but makes coding for
    //  underflow easier.
    // As with IEEE format, negative zero is possible, so
    // we special-case that in hopes that JavaScript will
    // also cooperate.
    //
    // The result is a number in the open interval (-1.0, 1.0);
    // 

    // throw away high bits for repeatability.
    rawSflt16 &= 0xFFFF;

    // special case minus zero:
    if (rawSflt16 == 0x8000)
        return -0.0;

    // extract the sign.
    var sSign = ((rawSflt16 & 0x8000) != 0) ? -1 : 1;

    // extract the exponent
    var exp1 = (rawSflt16 >> 11) & 0xF;

    // extract the "mantissa" (the fractional part)
    var mant1 = (rawSflt16 & 0x7FF) / 2048.0;

    // convert back to a floating point number. We hope 
    // that Math.pow(2, k) is handled efficiently by
    // the JS interpreter! If this is time critical code,
    // you can replace by a suitable shift and divide.
    var f_unscaled = sSign * mant1 * Math.pow(2, exp1 - 15);

    return f_unscaled;
    }

from: https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/master/TheThingsNetwork_Feather/ttn_decoder.js

and it works fully now.

Thank you!!

terrillmoore commented 5 years ago

that's great. Will close this now. BTW: has Adafruit already published the Learning Center article? Or did you just stumble upon this?

EtoTen commented 5 years ago

Just stumbled on it from a google search of function sflt162f(rawSflt16) https://www.google.com/search?q=function+sflt162f%28rawSflt16%29&ie=utf-8&oe=utf-8&client=firefox-b-1-ab

"This guide was first published on Sep 21, 2018. It was last updated on Sep 21, 2018. This page (Arduino Code) was last updated on Sep 19, 2018. "

EtoTen commented 5 years ago

One other thing to note, probably should be a separate issue but I had to add LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100); in setup() for the AVR to be able to join. It failed otherwise. Probably not very accurate timing?

terrillmoore commented 5 years ago

Probably not very accurate timing?

Yup. There are things one can do in the board support package to make timing more accurate -- LoRaWAN is demanding. But usually opening the receive window tolerance (as you've done) takes care of things.

terrillmoore commented 5 years ago

Just stumbled on it from a google search of function sflt162f(rawSflt16)

I take it that you found this from the learning center article. Did Adafruit do some publicity on the learning center article (have I fallen down on my re-tweets?) or did you get notified through their news feed or some other mechanism. Have to keep the marketing people (me with another hat) on their toes and make sure we're following the right channels. Thanks for your patience and interest on this.