USB Serial - crashes

Status
Not open for further replies.

BIade

Member
Hello all!
First I wanted to thank you for this wonderful forum!
I am a reader since years, but never dared to join.

Im having a problem since years, but first some details:
Im using a TEENSY 1.0 with the attached code.
A 433,92MHz transmitter is connected to PIN C6, and I can successfully control my low-budget-home-automation :)
A Fritz!Box with the modded Freetz-FW serves a Webserver for a CGI-Perl-script which communicates with teensy.
CGI-CODE:
Code:
#!/bin/sh

FC=`echo "$QUERY_STRING" | sed -n 's/^.*FC=\([^&]*\).*$/\1/p' | sed "s/%20/ /g"`
FC1="$FC\r\n"
echo "$FC1" > /dev/ttyACM0
Now I can successfully send my commands via http. Then I wrote an android app with "AppInventor" and now I can control my home via voice commands. :cool:

The Problem:
When I send too many commands too fast, the teensy hangs up. Only way to get it back is to plug out the teensy and replug it :/
[For a workaround I used a 2nd teensy with 2 relays for an automated plug-out-plug-in-function]

Tried to slim down the code to a minimum, but I cant figure out how to solve the "crash".
Sorry for beeing such a noob <3

Complete Code:
Code:
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <stdint.h>
#include <util/delay.h>
#include <usb_serial.h>
#include <stdlib.h>
#include <string.h>

#define OUTPUT_ON	(PORTC |= (1<<6))
#define OUTPUT_OFF	(PORTC &= ~(1<<6))
#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n))


char* kompletterCode="1234567890123";

void send_str(const char *s);
uint8_t recv_str(char *buf, uint8_t size);
void parse_and_execute_command(const char *buf, uint8_t num);
void sendeCodes( char* code );


#if 0
// Very simple character echo test
int main(void)
{
	CPU_PRESCALE(0);
	usb_init();
	while (1) {
		int n = usb_serial_getchar();
		if (n >= 0) usb_serial_putchar(n);
	}
}

#else

// Basic command interpreter for controlling port pins
int main(void)
{
	char buf[16];
	uint8_t n;

	// set for 16 MHz clock, and turn on the LED
	CPU_PRESCALE(0);

	// initialize the USB, and then wait for the host
	// to set configuration.  If the Teensy is powered
	// without a PC connected to the USB port, this 
	// will wait forever.
	usb_init();
	while (!usb_configured()) /* wait */ ;
	_delay_ms(1000);

	while (1) {
		while (1) {
			n = recv_str(buf, sizeof(buf));
			if (n == 255) break;
			parse_and_execute_command(buf, n);
		}
	}
}
#endif

void send_str(const char *s)
{
	char c;
	while (1) {
		c = pgm_read_byte(s++);
		if (!c) break;
		usb_serial_putchar(c);
	}
}

void sender(int state) {
   if (state == '0') {
			*(uint8_t *)(0x21 + ('C' - 'A') * 3) |= (1 << 6);
			
			*(uint8_t *)(0x22 + ('C' - 'A') * 3) &= ~(1 << 6);
			return;
		} 
	else if (state == '1') {

			*(uint8_t *)(0x21 + ('C' - 'A') * 3) |= (1 << 6);

			*(uint8_t *)(0x22 + ('C' - 'A') * 3) |= (1 << 6); 
	
			return;
		} else {
			return;}
}


uint8_t recv_str(char *buf, uint8_t size)
{
	int16_t r;
	uint8_t count=0;

	while (count < size) {
		r = usb_serial_getchar();
		if (r != -1) {
			if (r == '\r' || r == '\n') return count;
			if (r >= ' ' && r <= '~') {
				*buf++ = r;
				usb_serial_putchar(r);
				count++;
			}
		} else {
			if (!usb_configured() ||
			  !(usb_serial_get_control() & USB_SERIAL_DTR)) {
				// user no longer connected
				return 255;
			}
			// just a normal timeout, keep waiting
		}
	}
	return count;
}
  
void wait(void){
_delay_us(345);
 return;
}

void sendeNull(void) 
{
 sender('1');
 wait();
 sender('0');
 wait();
 // sender('0')
 wait();
 // sender('0')
 wait();
 // die nächsten 4 Tasks
 sender('1');
 wait();
 sender('0');
 wait();
 // sender('0')
 wait();
 // sender('0')
 wait();
 return;   
}

void sendeFloat(void) 
{
 sender('1');
 wait();
 sender('0');
 wait();
 wait();
 wait();
 sender('1');
 wait();
 wait();
 wait();
 sender('0');
 wait();
 return;
}

void sendeEins(void) 
{
 sender('1');
 wait();
 sender('1');
 wait();
 sender('1');
 wait();
 sender('0');
 wait();
 // die nächsten 4 tasks
 sender('1');
 wait();
 sender('1');
 wait();
 sender('1');
 wait();
 sender('0');
 wait();
 return;
}


void sendeSync(void)
{
 // Gesamtlänge 32 Takte
 sender('1');
 wait();
 sender('0');
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 return;
}



void sendeCodes( char* code ) {
 char ch;
 for (int i=1; i<=5; i++) 
 {
  for(int i2=0; i2<=11; i2++) 
  {
   ch = code[i2];
   if (ch == '1') {
	   sendeEins();
	   
   } else if (ch == '0'){
	   sendeNull();
	 
   } else if (ch == 'F'){
	   sendeFloat();
	  
   }

  }
    sendeSync();
  }
  }


  
void parse_and_execute_command(const char *buf, uint8_t num)
{
	 if (buf[0] == 'a') {
		const char* from = buf;
		char *to = (char*) malloc(13);;
		strncpy(to, from+1, 12);
		kompletterCode=to;
		sendeCodes( kompletterCode );
		usb_serial_flush_input();		
	} else {
		usb_serial_flush_input();
		return;
	} 
	
}

Attempt to delete unnecessary functions:
Code:
#include <avr/io.h>
#include <util/delay.h>
#include <usb_serial.h>

#define OUTPUT_ON	(PORTC |= (1<<6))
#define OUTPUT_OFF	(PORTC &= ~(1<<6))
#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n))

char* kompletterCode="1234567890123";

uint8_t recv_str(char *buf, uint8_t size);
void parse_and_execute_command(const char *buf, uint8_t num);
void sendeCodes( char* code );

int main(void)
{
	char buf[13];
	uint8_t n;

	// set for 16 MHz clock, and turn on the LED
	CPU_PRESCALE(0);

	// initialize the USB, and then wait for the host
	// to set configuration.  If the Teensy is powered
	// without a PC connected to the USB port, this 
	// will wait forever.
	usb_init();
	while (!usb_configured()) /* wait */ ;
	_delay_ms(1000);

	while (1) {
		while (1) {
			n = recv_str(buf, sizeof(buf));
			if (n == 255) break;
			parse_and_execute_command(buf, n);
		}
	}
}



void sender(int state) {
   if (state == '0') {
			*(uint8_t *)(0x21 + ('C' - 'A') * 3) |= (1 << 6);
			
			*(uint8_t *)(0x22 + ('C' - 'A') * 3) &= ~(1 << 6);
			return;
		} 
	else if (state == '1') {

			*(uint8_t *)(0x21 + ('C' - 'A') * 3) |= (1 << 6);

			*(uint8_t *)(0x22 + ('C' - 'A') * 3) |= (1 << 6); 
	
			return;
		} else {
			return;}
}


uint8_t recv_str(char *buf, uint8_t size)
{
	int16_t r;
	uint8_t count=0;
	while (count < size) {
		r = usb_serial_getchar();
		if (r != -1) {
			if (r == '\r' || r == '\n') return count;
			if (r >= ' ' && r <= '~') {
				*buf++ = r;
				count++;
			}
		} else {
			if (!usb_configured() ||
			  !(usb_serial_get_control() & USB_SERIAL_DTR)) {
				// user no longer connected
				return 255;
			}
			// just a normal timeout, keep waiting
		}
	}
	return count;
}
  
void wait(void){
_delay_us(345);
 return;
}

void sendeNull(void) 
{
 sender('1');
 wait();
 sender('0');
 wait();
 // sender('0')
 wait();
 // sender('0')
 wait();
 // die nächsten 4 Tasks
 sender('1');
 wait();
 sender('0');
 wait();
 // sender('0')
 wait();
 // sender('0')
 wait();
 return;   
}

void sendeFloat(void) 
{
 sender('1');
 wait();
 sender('0');
 wait();
 wait();
 wait();
 sender('1');
 wait();
 wait();
 wait();
 sender('0');
 wait();
 return;
}

void sendeEins(void) 
{
 sender('1');
 wait();
 sender('1');
 wait();
 sender('1');
 wait();
 sender('0');
 wait();
 // die nächsten 4 tasks
 sender('1');
 wait();
 sender('1');
 wait();
 sender('1');
 wait();
 sender('0');
 wait();
 return;
}

void sendeSync(void)
{
 // Gesamtlänge 32 Takte
 sender('1');
 wait();
 sender('0');
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 return;
}

void sendeCodes( char* code ) {
 char ch;
 for (int i=1; i<=3; i++) 
 {
  for(int i2=0; i2<=11; i2++) 
  {
   ch = code[i2];
   if (ch == '1') {
	   sendeEins();   
   } else if (ch == '0'){
	   sendeNull();	 
   } else if (ch == 'F'){
	   sendeFloat();  
   }
  }
    sendeSync();
  }
  }
  
void parse_and_execute_command(const char *buf, uint8_t num)
{
	 if (buf[0] == 'a') {
		const char* from = buf;
		char *to = (char*) malloc(13);;
		strncpy(to, from+1, 12);
		kompletterCode=to;
		sendeCodes( kompletterCode );
		usb_serial_flush_input();		
	} else {
		usb_serial_flush_input();
		return;
	} 
}

I know its a mess. Cherrypicked codesnippets and modified them. Felt like an 8th wonder, that it actually worked.

If anybody has got an idea how to optimize it, or even knows how to eliminate the hang-bug, I would be very happy.
Goal:
teensy gets a 13-chars command [First is identifier, other 12 is the Code to process]
Send processed code to the 433,92Mhz transmitter.

Since I don't need the teensy to answer on serial, I thought perhaps one could use the transmitting-usb-serial-buffer to double recieving-buffer?
But I don't know, if its even a buffer problem.

Gratefully
Blade
 
Teensy 1.0 is no longer supported.

If this board was purchased from PJRC, please contact Robin directly with info about your original purchase. If we can verify you purchased this from PJRC, we'll be happy to swap these ancient Teensy 1.0 boards for Teensy LC or Teensy 3.2.
 
OMG, before I joined this forum, I wanted to write you a PM, and now YOU are answering me :D <3
Thank you soo much Paul!!!

Teensy 1.0 is no longer supported.
Awww, thats sad to hear. I love them acient boards :)

If this board was purchased from PJRC, please contact Robin directly with info about your original purchase. If we can verify you purchased this from PJRC, we'll be happy to swap these ancient Teensy 1.0 boards for Teensy LC or Teensy 3.2.

Sadly my 4 Teensys 1.0 were a birthday present in 2012 and I've no proof they came from you :(
I have only got the box of my teensy 2.0++, which was a birthday present in 2013:
IMG_20150925_144408.jpg

If I can reproduce the problem with the teensy 2.0++, may I get your help with my code, or is it also unsupported and I need to buy a 3.2 ?
Thank you very much, for taking the time to answer such a nap like me <3

Cheers
Blade
 
Last edited:
Teensy 1.0 is no longer supported.

If this board was purchased from PJRC, please contact Robin directly with info about your original purchase. If we can verify you purchased this from PJRC, we'll be happy to swap these ancient Teensy 1.0 boards for Teensy LC or Teensy 3.2.

Same "Error" on the Teensy 2.0 ++, does it make it worthy? :)
 
Any chance you could implement this within Arduino and reproduce the problem on Teensy++ 2.0?

It's really tough to reproduce problems on avr-libc projects. If you can bring this code into Arduino (with the latest Teensyduino 1.25 version) and use Serial.print() instead of the raw functions, then reproducing the problem is just a matter of copying code into Arduino. Knowing it's a specific Teensyduino version means the toolchain and many other details are a perfectly known quantity.
 
Any chance you could implement this within Arduino and reproduce the problem on Teensy++ 2.0?

It's really tough to reproduce problems on avr-libc projects. If you can bring this code into Arduino (with the latest Teensyduino 1.25 version) and use Serial.print() instead of the raw functions, then reproducing the problem is just a matter of copying code into Arduino. Knowing it's a specific Teensyduino version means the toolchain and many other details are a perfectly known quantity.

OK, got it. here is the Arduino Code (Not a perfect duplicate, because it only works for the first time a command is send, but its a start)
Code:
void setup()   {  
  pinMode(PIN_B7, OUTPUT);              
  Serial.begin(9600);

}
char* kompletterCode;


void loop() {
  int count=0;
  char buf[13];
  while (count < 13) {
    if (Serial.available()) {  // receive all 13 bytes into "buf"
      buf[count++] = Serial.read();
    }
  }
  if (buf[0] == 'a') {     
    const char* from = buf;
    char *to = (char*) malloc(13);;
    strncpy(to, from+1, 12);
    kompletterCode=to;
    sendeCodes( kompletterCode );
    Serial.flush();
    return;   // return true if time message received
    }
  return;  //if no message return false
}


void sender(int state) {
   if (state == '0') {
        digitalWrite(PIN_B7, LOW);  
      return;
    } 
  else if (state == '1') {

        digitalWrite(PIN_B7, HIGH);  
  
      return;
    } else {
      return;}
}



  
void wait(void){
delayMicroseconds(345);
 return;
}

void sendeNull(void) 
{
 sender('1');
 wait();
 sender('0');
 wait();
 // sender('0')
 wait();
 // sender('0')
 wait();
 // die nächsten 4 Tasks
 sender('1');
 wait();
 sender('0');
 wait();
 // sender('0')
 wait();
 // sender('0')
 wait();
 return;   
}

void sendeFloat(void) 
{
 sender('1');
 wait();
 sender('0');
 wait();
 wait();
 wait();
 sender('1');
 wait();
 wait();
 wait();
 sender('0');
 wait();
 return;
}

void sendeEins(void) 
{
 sender('1');
 wait();
 sender('1');
 wait();
 sender('1');
 wait();
 sender('0');
 wait();
 // die nächsten 4 tasks
 sender('1');
 wait();
 sender('1');
 wait();
 sender('1');
 wait();
 sender('0');
 wait();
 return;
}


void sendeSync(void)
{
 // Gesamtlänge 32 Takte
 sender('1');
 wait();
 sender('0');
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 return;
}



void sendeCodes( char* code ) {
 char ch;
 for (int i=1; i<=5; i++) 
 {
  for(int i2=0; i2<=11; i2++) 
  {
   ch = code[i2];
   if (ch == '1') {
     sendeEins();
     
   } else if (ch == '0'){
     sendeNull();
   
   } else if (ch == 'F'){
     sendeFloat();
    
   }

  }
    sendeSync();
  }
  }

EDIT:
Ahhh :)
Its not only working for the first time. But if the sent string is not exactly 13 characters long, i.e. 17, I need to send a dummy-message with 9 chars to make them together be X*13 long. (In this case 26)
So as soon as I can make the recieve-string-function like it should be, I can test if the "error" still exists...
 
Last edited:
Hey Paul :)
Here is the 1:1 Version for arduino:
Platine: Teensy++ 2.0
USB-Type: Serial
CPU Speed: 8MHz

Code:
void setup()   {  
  pinMode(PIN_B7, OUTPUT);              
  Serial.begin(9600);

}

char* kompletterCode;
uint8_t recv_str(char *buf, uint8_t size);
void parse_and_execute_command(const char *buf, uint8_t num);
void sendeCodes( char* code );


void loop() {
  char buf[13];
uint8_t n;
  while (1) {
      n = recv_str(buf, sizeof(buf));
      if (n == 255) break;
      parse_and_execute_command(buf, n);
    }
}

uint8_t recv_str(char *buf, uint8_t size)
{
  int16_t r;
  uint8_t count=0;
  while (count < size) {
    r = Serial.read();
    if (r != -1) {
      if (r == '\r' || r == '\n') return count;
      if (r >= ' ' && r <= '~') {
        *buf++ = r;
        count++;
      }
    } else {
      
      // just a normal timeout, keep waiting
    }
  }
  return count;
}

void sender(int state) {
   if (state == '0') {
        digitalWrite(PIN_B7, LOW);  
      return;
    } 
  else if (state == '1') {

        digitalWrite(PIN_B7, HIGH);  
  
      return;
    } else {
      return;}
}



  
void wait(void){
delayMicroseconds(345);
 return;
}

void sendeNull(void) 
{
 sender('1');
 wait();
 sender('0');
 wait();
 wait();
 wait();
 sender('1');
 wait();
 sender('0');
 wait();
 wait();
 wait();
 return;   
}

void sendeFloat(void) 
{
 sender('1');
 wait();
 sender('0');
 wait();
 wait();
 wait();
 sender('1');
 wait();
 wait();
 wait();
 sender('0');
 wait();
 return;
}

void sendeEins(void) 
{
 sender('1');
 wait();
 sender('1');
 wait();
 sender('1');
 wait();
 sender('0');
 wait();
 sender('1');
 wait();
 sender('1');
 wait();
 sender('1');
 wait();
 sender('0');
 wait();
 return;
}


void sendeSync(void)
{

 sender('1');
 wait();
 sender('0');
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 wait();
 return;
}



void sendeCodes( char* code ) {
 char ch;
 for (int i=1; i<=5; i++) 
 {
  for(int i2=0; i2<=11; i2++) 
  {
   ch = code[i2];
   if (ch == '1') {
     sendeEins();
     
   } else if (ch == '0'){
     sendeNull();
   
   } else if (ch == 'F'){
     sendeFloat();
    
   }

  }
    sendeSync();
  }
  }

    void parse_and_execute_command(const char *buf, uint8_t num)
{
   if (buf[0] == 'a') {
    const char* from = buf;
    char *to = (char*) malloc(13);;
    strncpy(to, from+1, 12);
    kompletterCode=to;
    sendeCodes( kompletterCode );
    free(to);
      
  } else {
    
    return;
  } 
}

Same behavior - "bug" still exsists :/

To easily replicate the bug, you can use my CGI-script and send commands via browser like:
http://link-to-webserver/cgi-bin/test.cgi?FC=aF0F0F0F0F0F0F
I set up a dummy html with a toggle button, which loads the cgi-command in an hidden iframe toggeleing between i.e.:
http://link-to-webserver/cgi-bin/test.cgi?FC=aF0F0F0F0F0F0F
and
http://link-to-webserver/cgi-bin/test.cgi?FC=aF0F0F0F0F0FF0

Thanks soo much in advance :)
 
Last edited:
Status
Not open for further replies.
Back
Top