QNX Real time application

Nicola,

  1. Raw/unraw are necessary for setting up the terminal to read from the keyboard and then putting it back the way it was before you changed it.

You don’t need to do the raw/unraw commands everytime you get a pulse. You only do the raw() once in your main program before you spawn off your timer and then do the unraw() at the end of the program (which is never reached in your case)

  1. I believe this is because you don’t have O_NONBLOCK set on the read(). I bet your code is ‘stuck’ on the read statement and never actually moves past that line. The A blocking read() is looking for CTRL-D or CTRL-Z (can’t remember which) to signal that the keyboard input is finished and return control to your code.

  2. Are you sure it isn’t locking? How do you know your code continues to run? In the code I tested with my programs stopped at the read() until I set to to non-blocking.

  3. I don’t know the answer. I think you need to get the read() working correctly and printing out keyboard input before working on the fork.

Tim

I just commented the line:

new_flags |= O_NONBLOCK;

and it’s still not locking.

What does it mean i don’t have O_NONBLOCK set on read()? I or the flag as you said and it’s shown in the code.
My code doesn’t stuck on the read() statement, it’s just that nothing is ever printed.
Could it be something related with c_lflag in the termios structure?
Then, could u please tell me why the infinite loop should be running at a lower priority, instead of a higher one?
With a higher priority it’s easier that the main program is preempted, beeing at a lower priority.

Thanx

with O_NONBLOCK, read will not block. You need to check the return value of read to determine if something was read or not and deal with that.

This is what I wrote:

if(read(STDIN_FILENO, &buffer, sizeof(buffer) == -1 && errno == EAGAIN))
{
	printf("Nothing to print\n");
	if(debug)
		fprintf(log_fp, "Nothing to print\n");
}
else
{
	printf("Buffer: %c\n", buffer);
	if(debug)
		fprintf(log_fp, "Buffer: %c\n", buffer);
}

I’m still getting nothing from the read() calling.

Most of the time you will get a size of 0 which you should handle properly because it means there is no data to read, which is what you would get most of the time if you are trying to read something from the keyboard.

Nicola,

This is your problem:

if(read(STDIN_FILENO, &buffer, sizeof(buffer) == -1 && errno == EAGAIN))

Take a look at where the ()'s are in this ‘if’ statement.

Tim

Nice catch!

yeah, what a stupid error…
Now I get ‘Nothing to print’ even though i press something, even commenting the line:

new_termios.c_lflag &= ~(ECHO | ICANON | ISIG | ECHOE | ECHOK | ECHONL);

Two things:

  • How can i solve the locked-fork() issue?
  • Why the infinite loop should be running at a lower priority insted of a higher priority?

Nicola87,

Maybe you still didn’t get the brackets in the right place because it worked for me :wink:

Here’s your original code that I copied and pasted in the raw/unraw functions plus the rewritten GotAPulse() to use the non-blocking read() command.

Mine lets the timer run for 100 times and prints out any keystrokes each time the timer expires. You’ll note that my example counts the number of bytes returned by read(). The reason is that its possible to get more than 1 key pressed if you type really fast. Your code would only return 1 key at most (and to do a %c you need to do buffer[0], not buffer).

#include <stdlib.h>       /* EXIT_SUCCESS, EXIT_FAILURE */ 
#include <stdio.h>        /* printf(), fprintf() */ 
#include <fcntl.h>
#include <unistd.h>
#include <termios.h> 
#include <sys/neutrino.h> /* struct _pulse, ChannelCreate(), ChannelDestroy(), ConnectAttach(), MsgReceivePulse */ 
#include <sys/siginfo.h>  /* struct sigevent, SIGEV_PULSE_INIT */ 
#include <string.h>       /* strerror() */ 
#include <errno.h>        /* extern int errno */ 
#include <time.h>         /* clock(), struct itimerspec, timer_create(), timer_delete(), timer_settime() */ 

#define CODE_TIMER    1 
#define FREQ          50  /* Hz */ 
#define FREQUENCY     ((long) (1000000000/FREQ)) 
#define DIM           255 /* Dimensione del buffer */ 

//extern int errno; 
struct termios old_termios_p; 
int chid;             /* Channel ID */ 
int start_time; 
char * progname = "My_Project.c"; 
char * file = "/dev/kbd"; 
timer_t SetupPulseAndTimer (long); 
int GotAPulse (void); 
int Delete_Timer (timer_t); 

int raw()
{ 

	struct termios termios_p; 

	if(tcgetattr(STDIN_FILENO, &termios_p ) )
	{ 
		return(0); 
	} 

	old_termios_p = termios_p; 

	termios_p.c_lflag &= ~( ECHO|ICANON|ISIG| ECHOE|ECHOK|ECHONL ); 

	return tcsetattr(STDIN_FILENO, TCSADRAIN, &termios_p ); 
} 

int unraw()
{ 

	return tcsetattr(STDIN_FILENO, TCSADRAIN, &old_termios_p ); 

} 

int main(void) 
{ 
   start_time = time(NULL); 
   int count, rcvid;       //PID del mittente 
   struct _pulse pulse;    //Il nostro pulse 
   timer_t t_id; 
	int flags;

   raw(); 
   flags = fcntl(STDIN_FILENO, F_GETFL);
   flags |= O_NONBLOCK;	
   flags = fcntl(STDIN_FILENO, F_SETFL, flags);

   if((chid = ChannelCreate(0)) == - 1) 
   { 
      fprintf(stderr, "%s: couldn't create channel. Error: %s\n", progname, strerror(errno)); 
      exit(EXIT_FAILURE); 
   } 
    
   //Prepariamo pulse e timer 
   t_id = SetupPulseAndTimer(FREQUENCY); 
    
   for(count = 1; ;count++) 
   { 
      rcvid = MsgReceivePulse (chid, (void *) &pulse, sizeof(pulse), NULL); 
      printf("%d - \n", count); 
      GotAPulse(); 
	  if (count == 100) break;
   } 
    
   /* Never reached */ 
    
   //Distruggiamo il canale 
   if(ChannelDestroy(chid) == -1) 
   { 
      fprintf(stderr, "%s: couldn't destroy channel. Error: %s\n", progname, strerror(errno)); 
      exit(EXIT_FAILURE); 
   } 
    
   //Distruggiamo il timer 
   if(timer_delete(t_id) == -1) 
   { 
      fprintf(stderr, "%s: couldn't destroy timer. Error: %s\n", progname, strerror(errno)); 
      exit(EXIT_FAILURE); 
   } 
   
   unraw(); 
   
   return EXIT_SUCCESS; 
} 

timer_t SetupPulseAndTimer (long freq) 
{ 
   timer_t              timer_id;   //ID del timer 
   struct sigevent      event;      //evento da lanciare 
   struct itimerspec    timer;      //Struttura dati del timer 
   int                  coid;       //Connection ID 
    
   //Creiamo una connessione 
   coid = ConnectAttach (0, 0, chid, 0, 0); 
    
   if(coid == -1) 
   { 
      fprintf(stderr, "%s: couldn't ConnectAttach to self. Error: %s\n", progname, strerror(errno)); 
      exit(EXIT_FAILURE); 
   } 
    
   SIGEV_PULSE_INIT (&event, coid, SIGEV_PULSE_PRIO_INHERIT, CODE_TIMER, 0); 
    
   if(timer_create (CLOCK_REALTIME, &event, &timer_id) == -1) 
   { 
      fprintf(stderr, "%s: couldn't create timer. Error: %s (%d)\n", progname, strerror(errno), errno); 
      exit(EXIT_FAILURE); 
   } 
    
   //Impostiamo il timer alla frequenza prestabilita 
   timer.it_value.tv_sec     = 1; 
   timer.it_value.tv_nsec    = 0; 
   timer.it_interval.tv_sec  = 0; 
   timer.it_interval.tv_nsec = freq; 
    
   timer_settime (timer_id, 0, &timer, NULL); 
    
   return timer_id; 
} 

int GotAPulse (void) 
{ 
   int numRead = 0;
   char outbuffer[DIM]; 
   char buffer[DIM]; 
//   FILE * file_p = fopen(file, "r"); 
//   int file_p = open(file, O_RDONLY | O_NONBLOCK); 
    
//   if(file_p == NULL) 
//   { 
//      fprintf(stderr, "Unable to open \"%s\". Error: %s\n", file, strerror(errno)); 
//      return EXIT_FAILURE; 
//   } 
    
//   if (fread( buffer, sizeof(buffer), 1, file_p) == 0) 
//   numRead = read( file_p, buffer, sizeof(buffer));
   numRead = read(STDIN_FILENO, &buffer, sizeof (buffer)); 


   if (numRead == 0) 
   { 
      fprintf(stderr, "Unable to read from \"%s\". Error: %s\n", file, strerror(errno)); 
      return EXIT_FAILURE; 
   } 
   else if (numRead == -1)
   {
//	   if (errno == EAGAIN) printf("Nothing to read\n"); 
   }
   else
   { 
	   memset(outbuffer, 0, DIM);
	   memcpy(&outbuffer, &buffer, numRead);
	   printf("Buffer: %s\n", outbuffer); 
   }
    
//   fclose(file_p); 
//   close(file_p); 
    
   return EXIT_SUCCESS; 
} 

I don’t know as I didn’t spend time on this. I assume you’ll eventually figure it out on your own. Or do as I suggested and use a complete seperate program. The seperate program will make it MUCH easier to use the system profiler to determine what process ran when as opposed to working out which thread ran when.

You should be able to answer than question yourself if you think about it for a minute. A real-time system doesn’t mean all processes get CPU time. Remember it’s a priority driven operating system so why would a lower priority process get CPU time over a higher priority one?

Note: You can run both programs at the same priority if you want to as you will get basically the same result as running one at a lower priority.

Tim

Or if you use some function keys ( F1…)

I’m really sorry, I copied and pasted your code, ran it, but nothing was printed when pressing keys.
I always get a “Nothing to print”.
You said that the while(1) should be running at a lower priority than the main program is.
This way, the main program has more chances of being scheduled, I guess.
I think it should be the other way around.
I think I proved my point if, despite the fact that the main program is executing at a lower priority and has less chances of getting the CPU,
it is able to respect its deadlines (50 Hz).

Thanx for all your support

What makes you say that?

What you call proof is actually misunderstanding. 50Hz is too easy :wink: Plus unless a high priority process takes the CPU away for a lower one, the lower one will be able to respect deadlines. It has nothing do to with chance -)

Trying creating the log_file/channel/timer after doing the fork. By the way why not start a thread instead. When doing a fork all resources are duplicated, like the file descriptor for fopen, the channel etc.

I see you didn`t read the documentation. Higher means more important, if a “more important process” is using all of the CPU, it leaves no CPU for less important stuff.

Writer a program that does only while(1); Then start it at high priority with on -P100, that will basically lock up your computer because all the rest of the programs are running at 10-22 (from memory) Unless it has multiple core.

Nicola,

Where are you running the program?

Are you running it from within Momentics or are you copying the program to your QNX VM and then switching to the VM and running manually from there?

I do not think you can get ANY keyboard presses to work by running inside Momentics.

Tim

By moving the creation of log_file, channel and timer, it worked. Thanx.
This is how I’m running my project.

VM side:
QNX is up and qconn is running.

Win 7 - Momentics IDE:
Target is reachable. New QNX C Project. Write the project, build it and run it as a qnx c/c++ application

I think i misunderstood a bit. In my mind I was thinking:

“OK, I’m the main program, you are the infinite loop and you’re more important than me because of your higher priority.
Even though i’m running at a lower priority, i can satisfy my deadlines and QNX scheduler is doing a real great job,
because i’m getting as much CPU as I need”.

A bit twisted thinking, you may be thinking, I guess.

To make it simple, the infinite loop should execute at a lower priority because the main program is more “important”,
and it needs to respect its deadlines.

Thanx and Marry Xmas

I googled a bit more, and found something that seems to be good.
I found some pxc samples for a grabbing application.
There’s a source sample (pxc2/console_samples/grab.c), a library (pxc2/lib/pxc200.a) and some header files (pxc2/include).
I created the project, added source and headers, copied pxc200.a into /usr/lib, added pxc200 to the linker arguments and build it.
When I try to run it, it complains for lack of binaries.

How can I make this thing work?

and this is another one