Shop OBEX P1 Docs P2 Docs Learn Events
Getting characters without blocking — Parallax Forums

Getting characters without blocking

greybeardgreybeard Posts: 65
edited 2012-08-06 18:45 in Propeller 1
I frequently use a round-robin approach to data acq and control apps. In this approach I break down a series of tasks into discrete tasks and do a little of each task in each loop. Nothing really new or fancy here. It is fairly easy to implement as long as the number of tasks don't get out of and and there isn't anything that is really time critical.

Anyway... One task always has to do with getting one or more characters asynchronisly from a serial stream without blocking until the complete set of data to arrive.

I am aware that a flag can be set in the FILE structure that will allow data being returned BEFORE a carriage return is entered. This works but the input character routines DO block until at least one character is in the buffer. Puts a halt to the round robin handling of tasks.

I have tried fgets, fgetc,fread, getchar, getch, etc. Don't think I left anything out, but perhaps I did.

The FILE structure defined stdin.h has a variable '_cnt' that has a comment indicated it contains the number of characters in the buffer. This would suffice but the statment stdin->_cnt always returns zero. So..this doesn't help.

I have been using spin communication routines that have a routine that return -1 if there is no character in the buffer, or a value > 0 which is the data in the buffer.

What have I misssed or Any suggestions??

Comments

  • ersmithersmith Posts: 6,096
    edited 2012-08-03 18:43
    You haven't missed anything -- unfortunately there is no standard C way to get a character without blocking.

    The easiest ways to do this in propgcc are:

    (1) Use a separate thread for the reads, allowing it to block.

    (2) Use the C FdSerial driver, and call into it directly (note that the default simple serial driver has no non-blocking read at all):
       FdSerial_t *data = (FdSerial_t *)file->drvarg[0];
       int maybechar = _FdSerial_rxcheck(data);
       if (maybechar >= 0) {
          /* process character */
       }
    

    (3) Use the FullDuplexSerial.spin driver, or some similar spin driver, converted via spin2cpp (http://code.google.com/p/spin2cpp). spin2cpp isn't very good at recognizing when variables have to be volatile, so you may have to drop optimization down to -O instead of -Os or -O2, but otherwise it's worked fine on the serial drivers I've tried it on.

    Eric
  • jazzedjazzed Posts: 11,803
    edited 2012-08-03 21:19
    greybeard wrote: »
    I have been using spin communication routines that have a routine that return -1 if there is no character in the buffer, or a value > 0 which is the data in the buffer.

    The stdio console support is good for basic printing and blocking console input, but a version of FullDuplexSerial would probably serve your purpose better. I'll pull out an example for you if you want to try it. Let me know if you want that. The spin2cpp program is pretty good, so that's definitely worth a try.
  • Dave HeinDave Hein Posts: 6,347
    edited 2012-08-04 17:54
    I have used the following code to do console I/O without blocking and buffering. It has been a few months since I've used it, and I haven't tested it with the latest PropGCC code, so I hope it still works OK. Call makeraw() to make the input and output unbuffered, and call kbhit() to determine if a character is available on the standard input.
    #include <stdio.h>
    #include <unistd.h>
    #include <propeller.h>
    
    extern _Driver _FullDuplexSerialDriver;
    
    _Driver *_driverlist[] = {
      &_FullDuplexSerialDriver,
      NULL
    };
    
    int kbhit()
    {
        volatile int *rx_ptr = (int *)stdin->drvarg[0];
        return (rx_ptr[0] != rx_ptr[1]);
    }
    
    void makeraw()
    {
        setvbuf(stdin, NULL, _IONBF, 0);
        setvbuf(stdout, NULL, _IONBF, 0);
        stdin->_flag &= ~_IOCOOKED;
    }
    
    #if 1
    int main(void)
    {
        int byte;
    
        makeraw();
    
        fprintf(stdout, "Start echo.\n");
    
    
        while(1)
        {
            if (kbhit())
            {
                byte = fgetc(stdin);
                fputc(toupper(byte), stdout);
            }
        }
        return 0;
    }
    #endif
    
  • greybeardgreybeard Posts: 65
    edited 2012-08-06 18:45
    thanks. I'll look into it. console I/O is good for debug but I'll eventuall want to do serial data transfer(binary) via the port. This is a good start and perhaps will work with that also.


    thanks for the feedback
Sign In or Register to comment.