2

I'm trying to flash some code to my Nordic Semiconductor nRF52832 32-bit MCU which is integrated on an DWM1001 UWB module. The module sends formatted (MAVLink v1 protocol with a message size of 101 bytes) position data as unsigned chars to its serial port using printf(). The problem is, whenever a new line (\n) command is sent to the port there always is a carriage return (\r) put in front of \n. Now, sometimes one of the bytes in the message can have the same value as the \n command, which is 0x0A as HEX or 10 as a decimal. In this case, an additional \r byte is sent automatically to the port, which screws up my protocol. How can I get rid of this?

As an example, I attached a picture that shows the output of the serial port of the module. It’s just a uint8_t type counter counting from 0 to 254 and then resets itself (see code below). The function on_dwm_evt is regularly called by a loop in the main function. When the counter reaches 10 (decimal for \n) it puts a \r (= 13 as decimal, 0x0D in HEX) in front of it and I don't want that. Any help is appreciated.

I should note that the custom code is "embedded" into the firmware environment (namely PANS) provided by the manufacturer Decawave.

I'm using the SEGGER Embedded Studio IDE on Windows 10 and the GNU Arm Embedded Toolchain Version 10.3-2021.10 to compile my code.

uint8_t sq = 0;
unsigned char count;

void on_dwm_evt(dwm_evt_t *p_evt) {
    
    /* convert byte. (My actual message consists of multiple char arrays) */        
    count = sq & 0xFF;

    /* print counter to serial */        
    printf("%c", count);

    /* Increase sq counter +1 */
    if (sq < 254) {
        sq = sq + 1;
    } else {
        sq = 0;
    }
}

enter image description here

chqrlie
  • 131,814
  • 10
  • 121
  • 189
Felix_95
  • 21
  • 2
  • 5
    Because `stdout` is, by default, a *text* mode stream and your environment translates `"\n"` to `"\r\n"`. Maybe try `freopen(NULL, "ab", stdout);` to stop the translating (I haven't tested this *kludge*). – pmg Dec 17 '21 at 11:10
  • 2
    @pmg Or [this answer](https://stackoverflow.com/a/33157113/3150802): `FILE *const out = fdopen(dup(fileno(stdout)), "wb");`. The "b" in "wb" (or your "ab") is key. That would, I assume, preserve stdout the way it is, which may be useful. – Peter - Reinstate Monica Dec 17 '21 at 11:16
  • 2
    Another question entirely is whether using printf (intended for buffered, formatted text output) is the proper way to write bytes to hardware. It's probably best to assemble the bytes in a buffer and then send the buffer in one binary [`write`](https://man7.org/linux/man-pages/man2/write.2.html) or equivalent. Potentially some attention must be payed to incomplete writes but that's digressing. – Peter - Reinstate Monica Dec 17 '21 at 11:19
  • As an aside, is it true that sq cannot become 255? (Maybe; in the protocol 255 is often reserved...) Because if 255 is a legit value you can just increment away and it will wrap around by itself, being unsigned. Also, the count temporary and the 0xff AND are superfluous: Arguments to variadic functions like printf ["undergo additional conversions known as default argument promotions"](https://en.cppreference.com/w/cpp/language/variadic_arguments) anyway which turn chars to ints, and sp is an 8 bit value which makes masking with 0xff a NOP. – Peter - Reinstate Monica Dec 17 '21 at 11:33
  • `I'm using the SEGGER Embedded Studio IDE` what else can you tell? What exactly libraries are you using in your code? `The module sends formatted (MAVLink v1 protocol with a message size of 101 bytes) position data as unsigned chars to its serial port using printf()` What code is connecting "printf" -> ... -> serial? Where and how do you open and configure the serial port? Which serial port? Do you implement `write()` or `write_r()` function from newlib? Etc.. – KamilCuk Dec 17 '21 at 12:45
  • 1
    Is your data sent to a tty device? If so, its CR/LF translation mode may be set to insert those carriage returns - check with `stty` or equivalent. – Toby Speight Dec 18 '21 at 16:03
  • Hey guys, Thanks for all the answers! @pmg I tried both approaches with freopen() and fdopen(), but unfortunately neither changed the output. I also replaced fprint() with write() and also tried to send whole byte arrays using fwrite(), but always a \r is sent before \n. – Felix_95 Dec 20 '21 at 10:40
  • @Peter-ReinstateMonica yes, you are right. The range of sq is actually defined by the MAVLink protocol to be 0-255 (which is legit for an uint8)...don't know, why I limited it to 254, but it should'nt really make a difference for my problem. Also, thanks for the comment about masking my int with 0xff being unnecessary. I got rid of it. – Felix_95 Dec 20 '21 at 10:43
  • @KamilCuk The serial configuration is done in the PANS firmware and can not be edited, since there is no source code available. That means that - for example - I can not change the baudrate (set to 115200 by the firmware). The custom code snippet, which is also provided by the manufacturer and can be flashed "on top" of the actual firmware, uses fprint() to send data to the serial port, but write() also works. Libraries included: stdio.h, stdint.h, unistd.h – Felix_95 Dec 20 '21 at 10:51
  • @TobySpeight I'm reading data from the UART port of my module using a 3.3V-level FTDI, which is connected to my Windows PC. I also tried to get data with an Arduino Nano connected to my module. Both approaches give me the same result. I read data from the FTDI using several terminals (e.g. hterm, CoolTerm, TeraTerm). I'm not familiar with using the ftty (Linux?) command in Windows. Is there an equivalent for Windows? – Felix_95 Dec 20 '21 at 10:59
  • 1
    Just to be clear: If we assume that you write to a buffer where a pointer `p` points to the current write position (a buffer which you later `write`to the fd corresponding to the serial interface as a chunk); then the function boils down to `void on_dwm_evt(dwm_evt_t *p_evt) { *p++ = sq++; }`. – Peter - Reinstate Monica Dec 20 '21 at 10:59
  • 1
    Anyway, first, get [the cheap logic analyzer](https://www.ebay.co.uk/itm/154736789930?hash=item24070809aa:g:1aAAAOSwutpdmKNE&var=454828837300) and try with it. Just to be 100% sure it's not your PC - you can configure UART drivers for example on Linux that they will automatically add '\r'. Side note: `he PANS firmware` Omg, they finally released that. I was waiting like years for Decawave to finally make their firmware. If that is the case, and their firmware is implementing uart communicaiton (`printf()` callbacks), then most probably they are `if (c == '\n') send('\r'); send(c);` doing it. – KamilCuk Dec 20 '21 at 11:15
  • 2
    Are you 100% sure they do not provide the source code? It took mi minutes to get https://www.decawave.com/dwm1001-dw10001-dev-and-mdek1001-documents-source-code-android-application-firmware-image/ which they provide with NRF52 SDK. The `DWM1001/Source_Code/DWM1001_on_board_package/dwm/examples/dwm-uart/dwm-uart.c` seems to show how to change baudrate. But indeed `_write` callback from Newlib seems to be implemented in static library. Well, in either case, consult upstream - if you do not have the source code, then Decawave has so they should tell you how to fix it or they can fix it for a fee – KamilCuk Dec 20 '21 at 11:23
  • @KamilCuk I also used a RaspberryPi and a Linux computer to read the serial port. Both showed the same results as my Windows PC. Yes they released a pretty powerful firmware, which is doing most of the work. I found several software packages on Decawave's website (including the dwm-uart.c example) but no project file (as provided for the dwm-simple example) containing the source code of PANS. I wrote an E-Mail to Decawave and asked them to help me with my problem, but I have not received an answer, yet. I'll keep you updated in case there is some progress... – Felix_95 Dec 22 '21 at 08:07

0 Answers0