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

Compile error when adding LMIC_PRINTF_TO to project_config - Feather M0 #549

Open pomplesiegel opened 4 years ago

pomplesiegel commented 4 years ago

When compiling the example code "ttn-otaa-feather-us915.ino" for an Adafruit Feather M0 and adding the following line to lmic_project_config.h, a compiler error occurs.

Line added: #define LMIC_PRINTF_TO Serial Compiler error

/Users/<myhomedirectory>/Documents/Arduino/libraries/arduino-lmic/src/hal/hal.cpp:350:8: error: 'cookie_io_functions_t' does not name a type
 static cookie_io_functions_t functions =
        ^~~~~~~~~~~~~~~~~~~~~
/Users/<myhomedirectory>/Documents/Arduino/libraries/arduino-lmic/src/hal/hal.cpp: In function 'void hal_printf_init()':
/Users/<myhomedirectory>/Documents/Arduino/libraries/arduino-lmic/src/hal/hal.cpp:359:37: error: 'functions' was not declared in this scope
     stdout = fopencookie(NULL, "w", functions);
                                     ^~~~~~~~~
/Users/<myhomedirectory>/Documents/Arduino/libraries/arduino-lmic/src/hal/hal.cpp:359:37: note: suggested alternative: 'union'
     stdout = fopencookie(NULL, "w", functions);
                                     ^~~~~~~~~
                                     union
/Users/<myhomedirectory>/Documents/Arduino/libraries/arduino-lmic/src/hal/hal.cpp:359:14: error: 'fopencookie' was not declared in this scope
     stdout = fopencookie(NULL, "w", functions);
              ^~~~~~~~~~~

Important detail: This error happens for both v3.1.0 and v2.3.2, so I believe it's just a board compatibility thing, now that the board info has changed. Full environment info listed below.

FYI: I normally use "Serial1" UART at 115000, but it's the same compiler error when using the onboard 9600 baud "Serial" output from the Feather M0.

Environment LMIC = v.3.1.0 Arduino IDE 1.8.12 Adafruit SAMD board v1.5.11 + Arduino SAMD board 1.8.5 (installed using Arduino IDE) TTN US915 Adafruit Feather M0 LORA (includes radio)

terrillmoore commented 4 years ago

LMIC_PRINTF_TO ruins timing, and so has to be used with extreme care. The extreme care I exercise, in fact, is never to use it.

I suppose I should formally deprecate it, or come up with a less timing-sensitive variant. Or get a community contribution that has CI tests, etc..

For now, since I don't use it and it uses non-portable features of the BSPs, it's basically "use it if it works, apologies if it doesn't". Sorry...

The LMIC now has an event logging system that works much better, but the only example for using it is the compliance sketch. That said, it may be easier to debug "it doesn't work" problems by firing up (or modifying) the compliance sketch as your starting point. You have to enable the outcalls at compile time; see config.h for the variables.

pomplesiegel commented 4 years ago

Good to know! I can certainly live without it. Thank you

matthijskooijman commented 3 years ago

The non-AVR implementation using fopencookie requires _GNU_SOURCE to be defined before including stdio.h. See e.g. my original LMIC implementation:

https://github.com/matthijskooijman/arduino-lmic/blob/54bc51df00de18d7dd236fafac6b48e2597957f1/src/hal/hal.cpp#L15

Maybe you could try that and see if adding that line helps?

matthijskooijman commented 3 years ago

As for deprecating the debug logging, I've found the debug logging very convenient to diagnose problems. It does influence timing, but I suspect that's just problematic for the RX window timing, and could be easily worked around. How would a less timing-sensitive version look? Debug printing inherently influences timing, right?

The LMIC now has an event logging system that works much better, but the only example for using it is the compliance sketch. That said, it may be easier to debug "it doesn't work" problems by firing up (or modifying) the compliance sketch as your starting point. You have to enable the outcalls at compile time; see config.h for the variables.

I haven't looked at the event logging system yet, but wouldn't logging to serial in an event handler have identical problems? It's more configurable of course, since you could do less time-intensive queuing of events and logging them later, which I think the compliance example does indeed.

terrillmoore commented 3 years ago

HI @matthijskooijman -- I found that for most of the critical timing investigations, printf was a problem. At this point, the LMIC is stable enough that we know the code basically works; the problems are generally more subtle. As indicated, I'm happy to fix printfs, but since I don't use them, and don't have a regression test, I'm afraid that I'll just be creating more support problems. (I really want to discourage most people from using printfs, because you really need to know the code to distinguish between bugs and psuedo-problems from timing -- but I certainly can accept that others would like to use them, and so, given help, I'll accept it.)

wouldn't logging to serial in an event handler have identical problems?

Not in my experience. I've used this technique for 25 years in our USB software, which has exactly the same kinds of problems -- hard real-time response, but need for debug output. If there's memory, you can easily just divert the print stream to a ring buffer; that's fast enough, as long as you don't block when the buffer gets full. Then print at a lower priority. But on the very small systems for the LMIC, there's not enough memory, and then a fixed-size event logging ring buffer helps. (We also use the fixed-size event log in our USB products to debug low-level issues with host controller drivers and device controller drivers; we can record every write, and selected reads. With broken/dodgy hardware, it's the only thing that works. I first saw the technique used in 1977 by an experienced senior engineer who was debugging a problem in a driver for a mainframe -- memory was very small, but the system had a very fast tape drive with an I/O processor, and so he could capture the log buffers while running the test. Things only failed when dozens of terminals were active. It was a very hard problem to track down. Turned out the coder -- me -- had written r14 instead of r13 in a key place. It didn't matter most of the time....)

That said, logging adds overhead for writing the delogging routines. So most people don't want to do it. That's why I'd like it to be part of the library.