Teensy 3 and c string functions

Status
Not open for further replies.

Dawnmist

Well-known member
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.
 
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:
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:
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 :(
 
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.
 
vsnprintf() also has these problems

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.
 
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.
 
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:
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:
View attachment 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 ([url]http://hallard.me[/url])
              Modified to use with Arduipi board [url]http://hallard.me/arduipi[/url]
						  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
 
Status
Not open for further replies.
Back
Top