Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 11 of 11

Thread: Teensy 3 and c string functions

  1. #1
    Member Dawnmist's Avatar
    Join Date
    Nov 2012
    Location
    Australia
    Posts
    51

    Teensy 3 and c string functions

    I'm working on a personal project to do a programmable right-handed game keyboard (I use the mouse in my left hand), which loads/saves keymaps from/to SD card and outputs the current keymap & menus to change it to a tft screen (using UTFT, SdFat and IniFile libraries). My first version is working nicely using a teensy 2++, GLCD and saving to eeprom - but I keep losing the keymaps when I make incompatible changes *grins*.

    I'm running into issues on the Teensy 3 with several c string functions being disabled/not available at compile time. Things like sprintf, snprintf, strcasecmp, etc are being commented out by defines while being built (according to string.h and stdio.h, they're only available if the compilation is not defined as Strict ANSI or portable).

    Given that this is for personal use, I only need to use standard ASCII characters (not Unicode). Is there a reason other than lack of wide-character support for them being disabled for the Teensy 3 build? If not, is there a way to renable these functions - or should I be looking at replacing them entirely?

    Particularly when it comes to combining "string+int+string" information on the tft it's easier to do if the string buffer is prepared in advance, but I wasn't sure about the memory overhead of using String instead of char[] buffers. I was a little surprised to find that this stuff seems to be disabled by default, and wasn't sure how (or whether) to re-enable it or whether I should move to PString or String instead.

  2. #2
    Senior Member
    Join Date
    Oct 2012
    Location
    Portland OR
    Posts
    678

    sprintf() works for me

    The below example code using sprintf() compiles without error and works as expected on my Teensy 3. I wonder what is different in our environments. I am using Teensy 3 beta 7 on WinXP, and I am using the basic USB type Serial (not keyboard, etc.)

    Code:
    int ledPin=13;
    int n=1;
    
    char buf[10];
    
    void setup()
    {
        pinMode(ledPin, OUTPUT);
        Serial.begin(115200);
        delay(5000);
    }
    
    void loop()
    {
        digitalWrite(ledPin, HIGH);
        sprintf(buf, "Hello!%d", n);
        Serial.println(buf);
        delay(500);
        digitalWrite(ledPin, LOW);
        delay(500);
    
        n++;
    }
    Last edited by JBeale; 11-19-2012 at 05:42 PM.

  3. #3
    Member Dawnmist's Avatar
    Join Date
    Nov 2012
    Location
    Australia
    Posts
    51
    I gave that a try on it's own, and the above code compiles. Windows 7 Pro 64 bit, beta 8, Usb Serial. I thought I'd tried sprintf as well as snprintf, so I apologize for that one.

    Modifying it to use snprintf instead of sprintf, and I receive "error: 'snprintf' was not declared in this scope":
    Code:
    #include <stdio.h>
    int ledPin=13;
    int n=1;
    
    char buf[10];
    
    void setup()
    {
        pinMode(ledPin, OUTPUT);
        Serial.begin(115200);
        delay(5000);
    }
    
    void loop()
    {
        digitalWrite(ledPin, HIGH);
        snprintf(buf, 10, "Hello!%d", n);
        Serial.println(buf);
        delay(500);
        digitalWrite(ledPin, LOW);
        delay(500);
    
        n++;
    }
    This at least gives me something I can use for the moment (sprintf instead of snprintf). I'd misread the guard around sprintf - the one I thought it was wrapped in ends about 10 lines earlier. But I am curious as to why the others are unavailable.

    Edit: Further testing: if I undefine "__STRICT_ANSI__" before the stdio.h include, snprintf is available. So the following does compile:
    Code:
    #ifdef __STRICT_ANSI__
    #undef __STRICT_ANSI__
    #endif
    
    #include <stdio.h>
    
    int ledPin=13;
    int n=1;
    
    char buf[10];
    
    void setup()
    {
        pinMode(ledPin, OUTPUT);
        Serial.begin(115200);
        delay(5000);
    }
    
    void loop()
    {
        digitalWrite(ledPin, HIGH);
        snprintf(buf, 10, "Hello!%d", n);
        Serial.println(buf);
        delay(500);
        digitalWrite(ledPin, LOW);
        delay(500);
    
        n++;
    }
    and runs as expected.

    So it appears (if I've understood that correctly) that the issue is that the compilation appears to be restricting the range of functions to only those that were part of the original 1989 standard.

    Is that restriction intentional - is there a reason for why the "__STRICT_ANSI__" define has been set? I don't want to turn it off in my stuff if there was a good reason for it being on in the first place...I'm just unsure whether it was intentional or accidental, and interested in finding out whether there are likely to be any issues/side-effects if I did disable it.
    Last edited by Dawnmist; 11-20-2012 at 08:37 AM. Reason: further testing results

  4. #4
    Junior Member
    Join Date
    Oct 2012
    Posts
    3
    This is a serious shortcoming of the Teensy 3.0 toolchain vs. the Arduino AVR. There are even string functions that doesn't exist at all in the Teensy 3.0 toolchain

  5. #5
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    21,473
    I'm looking into these problems. It seems the __STRICT_ANSI__ is coming from my use of the "-std=c++0x" option to the compiler.

    This option turns on some language features that allow the String objects to be implemented much more efficiently (mainly rvalue refs, a new C++ feature). On AVR it's never caused a problem, other than causing warning on some horribly broken code to turn into errors. The AVR C library doesn't look at __STRICT_ANSI__ at all, it seems. But newlib on ARM does.

    It looks like changing to -std=gnu++0x solves this problem. I'm not sure if it creates any others, but I'm going to give it a try for beta #10.

    I know this thread is somewhat old.... just wanted to let you know I'm (finally) working on solving this problem.

  6. #6
    Junior Member
    Join Date
    Nov 2012
    Posts
    17

    vsnprintf() also has these problems

    Quote Originally Posted by PaulStoffregen View Post
    I'm looking into these problems. It seems the __STRICT_ANSI__ is coming from my use of the "-std=c++0x" option to the compiler.
    Just thought I'd report I'm seeing problems with vsnprintf() as well.

    Before the #undef __STRICT_ANSI__ trick, I'm getting:

    Code:
     error: 'vsnprintf' was not declared in this scope
    and after I do the #undef __STRICT_ANSI__ trick, I get the _close, _lseek, _fstat and _isatty problems:

    Code:
    c:/teensy3/arduino-1.0.2-teensy3-beta8-windows/arduino-1.0.2/hardware/tools/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/4.4.1/../../../../arm-none-eabi/lib/thumb2\libc.a(lib_a-closer.o): In function `_close_r':
    closer.c:(.text+0x12): undefined reference to `_close'
    c:/teensy3/arduino-1.0.2-teensy3-beta8-windows/arduino-1.0.2/hardware/tools/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/4.4.1/../../../../arm-none-eabi/lib/thumb2\libc.a(lib_a-fstatr.o): In function `_fstat_r':
    fstatr.c:(.text+0x14): undefined reference to `_fstat'
    c:/teensy3/arduino-1.0.2-teensy3-beta8-windows/arduino-1.0.2/hardware/tools/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/4.4.1/../../../../arm-none-eabi/lib/thumb2\libc.a(lib_a-isattyr.o): In function `_isatty_r':
    isattyr.c:(.text+0x12): undefined reference to `_isatty'
    c:/teensy3/arduino-1.0.2-teensy3-beta8-windows/arduino-1.0.2/hardware/tools/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/4.4.1/../../../../arm-none-eabi/lib/thumb2\libc.a(lib_a-lseekr.o): In function `_lseek_r':
    lseekr.c:(.text+0x16): undefined reference to `_lseek'
    collect2: ld returned 1 exit status
    Same results using beta#8 and #9.

  7. #7
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    21,473
    I'm working on wrapping up beta #10. It's supposed to fix this.

    If you'll post a complete test program for vsnprintf() quickly, I'll test it to make sure this is fixed on beta 10.

  8. #8
    Junior Member
    Join Date
    Nov 2012
    Posts
    17
    vsnprintf() test sketch for Teensy (tested to compile and run OK on Due.)

    Note: This updated version compiles and runs on Teensy3 beta #9 with #undef __STRICT_ANSI__ trick.

    Code:
    /* 
    vsnprintf() test sketch for Teensy3
    Jan 2, 2013
     */
    
    #undef  __STRICT_ANSI__
    
    #ifdef ARDUINO
    #if (ARDUINO >= 100)
    #include <Arduino.h>
    #else
    #include <WProgram.h>
    #endif
    #endif
    
    #include<stdio.h>
    #include<stdarg.h>
    
    #define FPRINTF_BUFSZE 256
    
    void serial_out_len(int len,char* b)
    {
      b[len] = 0; // null terminate string
      Serial.print(b);
    }
    
    int test_vsnprintf(const char format[],...)
    {
      // program memory version of printf - copy of format string and result share a buffer
      // so as to avoid too much memory use
      char buf[FPRINTF_BUFSZE];
      char *fptr, *rptr;
      int rlen = sizeof(buf);
    
      // buf just used for result string
      fptr = (char *)&format[0];
      rptr = &buf[0];
    
      va_list args;
      va_start (args,format);
    
      int len = vsnprintf(rptr, rlen, fptr, args );
    
      va_end (args);
    
      serial_out_len(len,rptr);
    
      return len;
    }
    
    void setup() 
    {
      Serial.begin(115200);
    }
    
    void loop() 
    {
      static int i = 0; 
      test_vsnprintf("This is an int: %d\n",i++);
      if (i == 100) i = 0;
    }
    Edit: Not sure why, but I found the #undef __STRICT_ANSI__ trick worked on this test sketch after I wrote it -- no link errors for _fstat etc.

    I don't know if this is a difference between beta #8 and #9, or there is something else that was going on with my environment that has somehow been reset.

    Anyway, thought I'd update for completeness. The sketch still exhibits the basic #include problem if the #undef __STRICT_ANSI__ trick isn't employed though.
    Last edited by pico; 01-03-2013 at 01:55 AM.

  9. #9
    Junior Member
    Join Date
    Nov 2012
    Posts
    17
    Just tested Beta #10, everything I've looked at so far seems fixed. Good job, Paul!

  10. #10
    I don't want to bring bad news, but I'm using printf and all I get is:

    Arduino: 1.0.5 (Linux), Board: "Teensy 3.0"
    pongtest.cpp.o: In function `__static_initialization_and_destruction_0':
    /home/nonono/arduino-1.0.5/hardware/tools/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/include/c++/4.7.2/iostream:75: undefined reference to `std::ios_base::Init::Init()'
    pongtest.cpp.o: In function `__static_initialization_and_destruction_0':
    /home/nonono/arduino-1.0.5/pongtest.ino:34: undefined reference to `std::ios_base::Init::~Init()'
    /home/nonono/arduino-1.0.5/hardware/tools/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib/thumb2/libc.a(lib_a-fstatr.o): In function `_fstat_r':
    fstatr.c.text+0x14): undefined reference to `_fstat'
    /home/nonono/arduino-1.0.5/hardware/tools/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib/thumb2/libc.a(lib_a-isattyr.o): In function `_isatty_r':
    isattyr.c.text+0x12): undefined reference to `_isatty'
    collect2: error: ld returned 1 exit status


    It only happens with Teensy 3. Teensy 2.0 compiles just fine.

    Here is the code if someone wants to give it a try:

    You need the RF24 library from matheusbrat:
    RF24.zip

    (I just zipped it to make it easier to install in arduino 1.0.5)


    Code:
    /*
     Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
    
     This program is free software; you can redistribute it and/or
     modify it under the terms of the GNU General Public License
     version 2 as published by the Free Software Foundation.
     
     03/17/2013 : Charles-Henri Hallard (http://hallard.me)
                  Modified to use with Arduipi board http://hallard.me/arduipi
    						  Changed to use modified bcm2835 and RF24 library 
    
     */
    
    /**
     * Example RF Radio Ping Pair
     *
     * This is an example of how to use the RF24 class.  Write this sketch to two different nodes,
     * connect the role_pin to ground on one.  The ping node sends the current time to the pong node,
     * which responds by sending the value back.  The ping node can then see how long the whole cycle
     * took.
     */
    
    #include <cstdlib>
    #include <iostream>
    #include <RF24.h>
    #include <SPI.h>
    
    //
    // Hardware configuration
    //
    
    // CE Pin, CSN Pin
    RF24 radio(9, 10); 
    
    
    
    //
    // Topology
    //
    
    // Radio pipe addresses for the 2 nodes to communicate.
    const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };
    
    //
    // Role management
    //
    // Set up role.  This sketch uses the same software for all the nodes
    // in this system.  Doing so greatly simplifies testing.  The hardware itself specifies
    // which node it is.
    //
    // This is done through the role_pin
    //
    
    // The various roles supported by this sketch
    typedef enum { role_ping_out = 1, role_pong_back } role_e;
    
    // The debug-friendly names of those roles
    const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"};
    
    // The role of the current running sketch
    role_e role;
    
    
    void setup() {
      // Role
      role = role_pong_back;
    
      //
      // Print preamble:
      //
    
      //Serial.begin(115200);
      //printf_begin();
      printf("RF24/examples/pongtest/\n");
      printf("ROLE: %s\n",role_friendly_name[role]);
    
      //
      // Setup and configure rf radio
      //
      radio.begin();
    
      // optionally, increase the delay between retries & # of retries
      radio.setRetries(15,15);
    
      // optionally, reduce the payload size.  seems to
      // improve reliability
    //  radio.setPayloadSize(8);
    radio.setChannel(0x4c);
      //radio.setPALevel(RF24_PA_LOW);
    
      //
      // Open pipes to other nodes for communication
      //
    
      // This simple sketch opens two pipes for these two nodes to communicate
      // back and forth.
      // Open 'our' pipe for writing
      // Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading)
      if ( role == role_ping_out )
      {
        radio.openWritingPipe(pipes[0]);
        radio.openReadingPipe(1,pipes[1]);
      }
      else
      {
        radio.openWritingPipe(pipes[1]);
        radio.openReadingPipe(1,pipes[0]);
      }
    
      //
      // Start listening
      //
      radio.startListening();
    
      //
      // Dump the configuration of the rf unit for debugging
      //
      radio.printDetails();
      
    }
    
    void loop(){
      //
      // Ping out role.  Repeatedly send the current time
      //
    		if (role == role_ping_out)
    		{
    			// First, stop listening so we can talk.
    			radio.stopListening();
    
    			// Take the time, and send it.  This will block until complete
    			unsigned long time = millis();
    			printf("Now sending %lu...",time);
    			bool ok = radio.write( &time, sizeof(unsigned long) );
    			
    			if (ok)
    				printf("ok...");
    			else
    				printf("failed.\n");
    
    			// Now, continue listening
    			radio.startListening();
    
    			// Wait here until we get a response, or timeout (250ms)
    			unsigned long started_waiting_at = millis();
    			bool timeout = false;
    			while ( ! radio.available() && ! timeout ) {
    					// by bcatalin  Thu Feb 14, 2013 11:26 am
    					delay(5); //add a small delay to let radio.available to check payload
    				if (millis() - started_waiting_at > 200 )
    					timeout = true;
    			}
    
    
    			// Describe the results
    			if ( timeout )
    			{
    				printf("Failed, response timed out.\n");
    			}
    			else
    			{
    				// Grab the response, compare, and send to debugging spew
    				unsigned long got_time;
    				radio.read( &got_time, sizeof(unsigned long) );
    
    				// Spew it
    				printf("Got response %lu, round-trip delay: %lu\n",got_time,millis()-got_time);
    			}
    
    			// Try again 1s later
    			delay(1000);
    			
    		}
    
    		//
    		// Pong back role.  Receive each packet, dump it out, and send it back
    		//
    
    		if ( role == role_pong_back )
    		{
    			// if there is data ready
    			//printf("Check available...\n");
    			if ( radio.available() )
    			{
    				// Dump the payloads until we've gotten everything
    				unsigned long got_time;
    				bool done = false;
    				
    				while (!done)
    				{
    					// Fetch the payload, and see if this was the last one.
    					done = radio.read( &got_time, sizeof(unsigned long) );
    
    					// Spew it
    					printf("Got payload(%d) %lu...\n",sizeof(unsigned long), got_time);
    
    					// Delay just a little bit to let the other unit
    					// make the transition to receiver
    					delay(20);
    				}
    
    				// First, stop listening so we can talk
    				radio.stopListening();
    
    				// Send the final one back.
    				radio.write( &got_time, sizeof(unsigned long) );
    
    				// Now, resume listening so we catch the next packets.
    				radio.startListening();
    			}
    		}
    	} // forever loop

    I'm using Teensyduino 1.16. It compiles when I remove printf calls

  11. #11
    Senior Member
    Join Date
    Jun 2013
    Location
    So. Calif
    Posts
    2,828
    Re printf... the first 3 or so posts in thread
    http://forum.pjrc.com/threads/23874-...r-printf%28%29

    may be useful - on how to use printf on Teensy 3.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •