Sysprogs forums › Forums › VisualGDB › USB CDC project scanf() redirection fails
- This topic has 7 replies, 2 voices, and was last updated 6 years, 3 months ago by support.
-
AuthorPosts
-
August 11, 2018 at 01:12 #21644VladParticipant
Hi, I got USB CDC tutorial working fine up until a point of a full system IO redirection to include scanf(). I have my STM32F407 redirecting printf() to PC without semihosting. But after I made changes to redirect all “read” and “write” functions and then run it – terminal runs at full speed non-stop the same printout:
“Enter a number: 0 = 0x0”
……………………………………….
“Enter a number: 0 = 0x0”
making the terminal locked out. Apparently scanf() returns without waiting for input. Debugging is impossible because when debug session stops at the breakpoint, there is no terminal communication with target whence no input possible and that means USB CDC firmware does not even start -nothing to debug. Again printf() works fine but can somebody suggest what is wrong with “read” in scanf() ? Is the code provided in that tutorial enough for the CDC OUT communication ? I don’t understand how is it possible to run a debugger (F5) as the tutorial suggests, and still use terminal for communication with target when it is stopped at break?
Please help
August 11, 2018 at 23:53 #21651supportKeymasterHi,
It is hard to say why scanf() would not work with USB, but generally stepping through the _read() function shown in the tutorial should help.
Debugging the USB devices is a bit tricker than the regular embedded code, but is still totally possible. Windows will consider your device “not responding” if it fails to respond to USB requests within a certain time-out (usually in hundreds of milliseconds). Stopping at a breakpoint to examine the program state would trigger this, however adding and removing breakpoints while the program is running would not (it involves a very short stop that VisualGDB handles automatically).
Hence we would advise starting the debug session without breakpoints, getting to the point where the code loops indefinitely and then setting a breakpoint and stepping through it. Stepping through the code will likely time out the USB communication, but it should provide sufficient clues about the internal state of the USB-related logic. Once it breaks, simply disable/remove your breakpoints, restart the device, wait for Windows to discover it and set the breakpoint(s) again.
August 23, 2018 at 17:21 #21751VladParticipantHello, – why am I not getting replies to my posts in email? I don’t see a possibility of setup email in this forum…
Anyways, thank you for the advice how to debug USB code. I did this and here are my findings:
scanf() never calls redefined _read()
in fact _read() is indeed redefined in code and I did verified this fact but scanf() goes running without calling it.
I put breakpoint in _read() – it never triggered . Breakpoint put in redefined _write() indeed gets called when doing printf().
I did yet another test: I replaced scanf() with the followingchar val; _read(NULL, &val, sizeof(val));
this changed code works: waits for input and shows each character printed in dec and hex. Again – scanf() does not call any of redefined functions (neither those original) . Stepping into scanf() and following all commands is daunting task – steps forever into many functions inside scanf() never coming to _read()….
I see two probabilities here making my run different from yours: either you are not using newlib-nano “C” library or, if you do use newlib-nano, then some of your compilation flags are different from mine… for ex. my setup uses _STDC_ and _HAVE_STDC flags, do you ? In other words the “C” library string input functions (probably all input formatting functions) in my setup don’t use _read() and therefore they are not overwritten. Also another flag – I did not choose semihosting option for obvious reasons – I don’t use semihosting…. What other flags could be different and what function should be overwritten additionally to those provided in your code?
Can you please verify this?
- This reply was modified 6 years, 4 months ago by Vlad.
August 23, 2018 at 17:47 #21753VladParticipantInteresting thoughts brought about from stepping through inside scanf() function…
This function implementation is a huge bulk of the code, most of it has nothing to do with formatting or data transfer but rather with multitude of macros and #ifdef’s trying to reconcile different versions of “C”… (and “C++” just adds another layer on the top), making the code practically non-readable unless you dedicate many hours or days on just digging scanf() alone 🙂 And this makes setup compilation flags are kind of high art….
I wonder how much benefits programmers gain from introducing one more layer of compiler’s complexity when they choose “C++” compiler (to the weel overloaded versions of “C”)? Even considering the benefits of the OOP … Notice I am not even taking into consideration the additional complexity of correctly using “C++” to eliminate many bugs programmers get from messing with C++ peculiarities, I am only talking about possibility of messing with compilation flags and compiler-related code peculiarities while using both C and C++ ….
I doubt there are so many benefits to justify so many more chances to mess up… this is yet one more example how we, trying to make our lives easier, make it much harder instead 🙂
- This reply was modified 6 years, 4 months ago by Vlad.
August 25, 2018 at 05:43 #21766supportKeymasterHi,
Could it be that your implementation of _read() was not declared with extern “C” and hence would not replace the original one? We have done a quick test with newlib-nano and scanf() did call the redefined _read(). If nothing helps, please try checking if your version of _read() is actually compiled in (e.g. set a breakpoint in _read by function name and see whether it resolves to your function).
Regarding email notifications, unfortunately we had to disable it some email servers classified those notifications as spam and prevented the delivery of regular emails from our domain as well.
With C++, there are a few cases where it could be beneficial to embedded projects, (e.g. using RAII to avoid “forgot to call release() before return” errors, or using templates as a more IntelliSense- and debugger-friendly alternative to bulky plain C macros), although whether it pays off depends on the project size, style and many other factors. VisualGDB is designed to support both Plain C and C++ projects, so it should provide comfortable development experience for both languages.
August 27, 2018 at 17:26 #21802VladParticipantThank you for reply.
As I reported, when I replace scanf() with _read() , it calls my new version of _read() so it is compiled in (it cannot be that with the same compilation flags one function calls one version of _read and another function would call another version…) apparently _read() is not called by scanf() at all … but I could see from stepping through scanf() that it goes through different functions depending on the flags…. this I believe is different between our environments.
August 27, 2018 at 18:24 #21807VladParticipantCan you show your compiler properties entry with all C/C++ compiler flags ? What file is it in ?
For ex. I am curious to see “_STDC_” and similar flags related to the version of “C”… those define the actual flow of scanf() …
August 28, 2018 at 05:12 #21808supportKeymasterHi,
Our newlib-nano build (gcc-arm-none-eabi-6-2017-q2-update) is configured with the following flags:
../newlib/configure --target=arm-eabi --prefix=/q/gnu/newlib-nano/newlib-nano-install --disable-newlib-supplied-syscalls --enable-newlib-reent-small --disable-newlib-fvwrite-in-streamio --disable-newlib-fseek-optimization --disable-newlib-wide-orient --enable-newlib-nano-malloc --disable-newlib-unbuf-stream-opt --enable-lite-exit --enable-newlib-global-atexit --disable-nls --enable-newlib-nano-formatted-io
The configuration process creates many header files with generated flags, so it’s hard to give a definitive answer. If you would like to look deeper into it, please consider building it from sources on your side and verify which version of the code is built by injecting #error directives into the source files.
Another (easier) option would be to try setting breakpoints in other functions that should be called (see the call stack below) until you pinpoint the one that is not called:
> _read() C++ (gdb) _read_r() C++ (gdb) __sread() C++ (gdb) __srefill_r() C++ (gdb) __svfscanf_r() C++ (gdb) scanf() C++ (gdb)
Here’s the program we tested it with:
extern "C" int _read() { asm("bkpt 255"); } int main(void) { int x; scanf("%x", &x); }
-
AuthorPosts
- You must be logged in to reply to this topic.