Solved

Serial communications

Posted on 2012-03-21
8
321 Views
Last Modified: 2012-06-27
This is a little C routine I use to read midi info from a keyboard.  I need an idea as to how I can get out of the loop that is reading the file.  Midi does not send an end of  file or end of string character so I need to do it somehow with the stroke of a key on the keyboard.  I remember in the old days using something like kbhit() but I can't find any of the h files needed.  Any Ideas?



#include <stdio.h>
#include <stdlib.h>
#include <sys/select.h>

int main() {
 
 const char FILE_NAME[] = "/dev/midi1";
 
int count = 0; /* number of characters seen */
FILE *in_file; /* input file */

int ch = 0;

in_file = fopen(FILE_NAME, "r");
if (in_file == NULL) {
  printf("Cannot open %s\n", FILE_NAME);
exit(8);
}

while (1) {
  ch = fgetc(in_file);
  if (ch != 248 ) {
    if ( ch != 254 ) {
      printf("%i ", ch);
      ++count;
      if (count == 40 ) {count=0; printf("\n\r"); break;}
    }
  }
}
//if (ch == EOF) {
//  break;
//}


printf("Number of characters in %s is %d\n",
FILE_NAME, count);

fclose(in_file);
return (0);
}
0
Comment
Question by:sargent240
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 4
8 Comments
 
LVL 7

Expert Comment

by:tampnic
ID: 37750447
If I remember correctly, though its twenty years since I looked at anything musical in depth, a MIDI byte is 10 bits long - how can you read the MIDI signals with fgetc() ? Is the hardware stripping the first and last bits out for you?

I wouldn't recommend keyboard polling in the same thread as a timing-critical section like responding to MIDI data - why not start another thread and wait for a key press in that? kbhit() comes from conio.h on Borland compilers.

Cheers,
   Chris
0
 

Author Comment

by:sargent240
ID: 37750468
Chris

I store the style, voice, tempo and transposition it a memory register on the keyboard.  When I select that register on the keyboard it transmits the same info that it sends to the instrument as though it were programming another keyboard.  I will pick up the data, which can have as many as 80 hex values, and store it in a data file.  I can then duplicate the settings in the keyboard from the computer at any time in the future.  The data comes in a matter of milliseconds but I never never know the number values being sent so I would like to send the values and a second or two later strike a key on the keyboard and break out of the loop.  I tried kbhit() but when I include conio.h it cannot be found.  I am using Linux and gcc.
0
 
LVL 7

Expert Comment

by:tampnic
ID: 37750603
OK - so its settings and not note messages.

I am assuming that your fgetc() call sits and waits while there is no data - and you can't tell when the data has stopped as an EOF is not sent. Why check for a keyboard hit - if you are *SURE* the data will be there within a couple of seconds one strategy could be

1) create a timer
2) fork a process to read the data (start the timer when the first byte gets read)
3) close files and kill the forked process when the timer reaches two seconds.

Alternatively

1) fork a process to read the data
2) wait for a key press in the parent process with fgetc(stdin) or getchar()
3) close files and kill the forked process when the key is hit

Alternatively

Use select() http://linux.die.net/man/2/select instead of fgetc() to read /dev/midi1. select() requires a file descriptor so use fileno(in_file) to get that. You can specify a timeout with select() so set it as two seconds and exit on the timeout once you have received data.

Cheers,
   Chris
0
Get 15 Days FREE Full-Featured Trial

Benefit from a mission critical IT monitoring with Monitis Premium or get it FREE for your entry level monitoring needs.
-Over 200,000 users
-More than 300,000 websites monitored
-Used in 197 countries
-Recommended by 98% of users

 

Author Comment

by:sargent240
ID: 37750664
Chris,

I added a timer I found but am having trouble compiling it.  The error I get is:

midiio.c:36:29: error: expected ‘;’, ‘,’ or ‘)’ before ‘&’ token
midiio.c:44:31: error: expected ‘;’, ‘,’ or ‘)’ before ‘&’ token

Line 36 and 44 are:

int SetTimer(struct timeval &tv, time_t sec)
int CheckTimer(struct timeval &tv, time_t sec)

The complete code follows.  Any help there? Thanks!


#include <stdio.h>
#include <stdlib.h>
#include <sys/select.h>
#include <sys/time.h>


/* Key pressed ? */
int count = 0;

int  kbhit  (void)  {
  struct timeval  tv;
  fd_set          read_fd;
  /* Do not wait at all, not even a microsecond */
  tv.tv_sec  = 0;
  tv.tv_usec = 0;

  /* Must be done first to initialize read_fd */
  FD_ZERO(&read_fd);

  /* Makes select() ask if input is ready;  0 is file descriptor for stdin */
  FD_SET(0, &read_fd);

  /* The first parameter is the number of the largest fd to check + 1 */
  if  (select(1, &read_fd,
                 NULL,         /* No writes        */
                 NULL,         /* No exceptions    */
                 &tv)  == -1)
    return(0);                 /* an error occured */

  /* read_fd now holds a bit map of files that are readable. */
  /* We test the entry for the standard input (file 0).      */
  return(FD_ISSET(0, &read_fd)  ?  1  :  0);
}

 
int SetTimer(struct timeval &tv, time_t sec)
{
    gettimeofday(&tv,NULL);
    tv.tv_sec+=sec;
 
    return 1;
}
 
int CheckTimer(struct timeval &tv, time_t sec)
{
    struct timeval ctv;
    gettimeofday(&ctv,NULL);
 
    if( (ctv.tv_sec &gt; tv.tv_sec) )
    {
        gettimeofday(&tv,NULL);
        tv.tv_sec+=sec;
        return 1;
    }
    else
        return 0;
}


int main() {

    struct timeval tv;
    SetTimer(tv,5); //set up a delay timer
 
 const char FILE_NAME[] = "/dev/midi1";
 char str[500];
//int count = 0; /* number of characters seen */
FILE *in_file; /* input file */

int ch = 0;

in_file = fopen(FILE_NAME, "r");
if (in_file == NULL) {
  printf("Cannot open %s\n", FILE_NAME);
exit(8);
}

while (1) {
  if (CheckTimer(tv,5)==1) break;
  ch = fgetc(in_file);
  if (ch != 248 ) {
    if ( ch != 254 ) {
      printf("%i ", ch);
      ++count;
    }
  }
//        if  (kbhit()) { printf("count = %i ", count ); break; }

}

printf("Number of characters in %s is %d\n",
FILE_NAME, count);

fclose(in_file);
return (0);
}
0
 

Author Comment

by:sargent240
ID: 37750708
Oh, I messed up!  the code in my last post has some c++ code in it and that is most likely where the problem is.  I have been looking around for some timer code for c but can't seem to put my hand on some.  Having not messed around with c for about 17 years I'm struggling a bit.  Can you direct me to a timer routine or can you suggest how to change what I have.

Thanks! - Al
0
 
LVL 7

Accepted Solution

by:
tampnic earned 500 total points
ID: 37751867
timer_create() http://linux.die.net/man/3/timer_create is a POSIX function for creating timers. It sends a signal to the process when the timer expires so you have to write a signal handler. I'm not sure if the signal handler will be called while fgetc() is blocking though, so YMMV with this function.

Here is a link to a little ANSI C code snippet showing some simple timing using time() and difftime() to check elapsed. http://www.tek-tips.com/viewthread.cfm?qid=72974

I also found this  ... http://ubuntuforums.org/showthread.php?t=936816 The last code snippet shows use of select() with a timeout of zero to replace an fgetc() call which blocks. The issues are applicable to your situation I think.

Cheers,
   Chris
0
 

Author Closing Comment

by:sargent240
ID: 37758239
Timer is not going to work.  Going another direction.  However thanks
0
 
LVL 7

Expert Comment

by:tampnic
ID: 37758607
I gave you some timer functions because that's what you asked for - I should have said that personally I would be writing the app to use select() to read from the port.

Cheers,
   Chris
0

Featured Post

Transaction Monitoring Vs. Real User Monitoring

Synthetic Transaction Monitoring Vs. Real User Monitoring: When To Use Each Approach? In this article, we will discuss two major monitoring approaches: Synthetic Transaction and Real User Monitoring.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This is an explanation of a simple data model to help parse a JSON feed
Examines three attack vectors, specifically, the different types of malware used in malicious attacks, web application attacks, and finally, network based attacks.  Concludes by examining the means of securing and protecting critical systems and inf…
With the power of JIRA, there's an unlimited number of ways you can customize it, use it and benefit from it. With that in mind, there's bound to be things that I wasn't able to cover in this course. With this summary we'll look at some places to go…
Simple Linear Regression

717 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question