Shop OBEX P1 Docs P2 Docs Learn Events
Serial comm review — Parallax Forums

Serial comm review

RsadeikaRsadeika Posts: 3,837
edited 2012-10-07 03:56 in Propeller 1
This is a rehash of serial I/O. The program below works sort of as expected, the problem is, in the while loop I am expecting to have a char "A" displayed on the external terminal screen, every second, instead I get eight "A"s displayed at one time, maybe every eight seconds, a buffer issue? I think this was discussed a couple years ago, but I do not think that there was a satisfactory resolution. Since there has been some minimal discussion in another thread, I thought maybe it could get expanded here.

Ray
/**
 * @file PPred0.c
 * This is the main PPred0 program start point.
 */
#include <propeller.h>
#include <stdlib.h>
#include <stdio.h>
#include <driver.h>


extern _Driver _SimpleSerialDriver;
extern _Driver _FullDuplexSerialDriver;


_Driver *_driverlist[] = {
    &_FullDuplexSerialDriver,
    NULL
};

/**
 * Main program function.
 */
int main(void)
{

/*                          Baud    Rx  Tx        */
    FILE *term = fopen("FDS:115200, 27, 26", "r+");
    
    waitcnt(CLKFREQ + CNT);
    printf("Start of program\n");

    fprintf(term,"This is on the terminal screen.\n");        
    while(1)
    {
        fputs("A",term);
        sleep(1);    
    }
    fclose(term);
    return 0;
}

Comments

  • Dave HeinDave Hein Posts: 6,347
    edited 2012-09-27 08:43
    Yes, stdio is buffered by default. I use the following routine to make the stdin and stdout unbuffered and raw. You only need the one line that references stdout if you just want to make the output unbuffered.
    void makeraw()
    {
        setvbuf(stdin, NULL, _IONBF, 0);
        setvbuf(stdout, NULL, _IONBF, 0);
        stdin->_flag &= ~_IOCOOKED;
    }
    
  • ersmithersmith Posts: 6,054
    edited 2012-09-27 09:38
    There are three possible options for buffering in C: unbuffered (_IONBF), line buffered (_IOLBF) and fully buffered (_IOFBF). Terminals are by default line buffered, which means data is buffered until either the buffer is full or a newline is seen.

    Dave has shown how to make output unbuffered (although you'll have to change his example to use "term" instead of "stdout" for your program). The other option is to add an explicit fflush(term); after fputs("A",term);. This will force output to be printed to the terminal.
  • RsadeikaRsadeika Posts: 3,837
    edited 2012-09-27 09:49
    OK, that fflush(term) is doing what I want. Now I am trying to type a char on the remote terminal, and have the char shown on the console terminal. What is happening with the program below, is the char just gets shown on the remote terminal. I was expecting the printf() to display the char to the console terminal.

    Ray
    /**
     * @file PPred0.c
     * This is the main PPred0 program start point.
     */
    #include <propeller.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <driver.h>
    
    
    extern _Driver _SimpleSerialDriver;
    extern _Driver _FullDuplexSerialDriver;
    
    
    _Driver *_driverlist[] = {
        &_FullDuplexSerialDriver,
        NULL
    };
    
    
    
    /**
     * Main program function.
     */
    int main(void)
    {
    
    /*                          Baud    Rx  Tx        */
        FILE *term = fopen("FDS:115200, 27, 26", "r+");
    
    
                
        waitcnt(CLKFREQ + CNT);
        printf("Start of program\n");
    
        fprintf(term,"This is on the terminal screen.\n");        
        while(1)
        {
    
            fputs("A",term);
            fflush(term);
    //        sleep(1);
            int byte = fgetc(term);
            printf("%c",byte);    
        }
        fclose(term);
        return 0;
    }
    
    
  • ersmithersmith Posts: 6,054
    edited 2012-09-27 10:08
    Rsadeika wrote: »
    OK, that fflush(term) is doing what I want. Now I am trying to type a char on the remote terminal, and have the char shown on the console terminal. What is happening with the program below, is the char just gets shown on the remote terminal. I was expecting the printf() to display the char to the console terminal.
    Have you tried putting fflush(stdout); after the printf? (Or changing stdout to be unbuffered, as Dave showed),
  • jazzedjazzed Posts: 11,803
    edited 2012-09-27 12:21
    A variation Dave's original suggestion is the best way to handle this in my opinion.

    Read more about _IOCOOKED here: http://propgcc.googlecode.com/hg/doc/Library.html#cooked
  • ersmithersmith Posts: 6,054
    edited 2012-09-27 13:18
    jazzed wrote: »
    A variation Dave's original suggestion is the best way to handle this in my opinion.

    Read more about _IOCOOKED here: http://propgcc.googlecode.com/hg/doc/Library.html#cooked

    I'll also note that we've recently added an _IONONBLOCK flag that will allow for non-blocking reads (which return -1 immediately if no data is available); you'll see it in the document linked to above because that's in the current source tree, but _IONONBLOCK hasn't made it into a release yet.
  • jazzedjazzed Posts: 11,803
    edited 2012-09-27 13:33
    ersmith wrote: »
    I'll also note that we've recently added an _IONONBLOCK flag that will allow for non-blocking reads (which return -1 immediately if no data is available); you'll see it in the document linked to above because that's in the current source tree, but _IONONBLOCK hasn't made it into a release yet.

    Great! Thanks.
  • RsadeikaRsadeika Posts: 3,837
    edited 2012-09-28 04:05
    Below is my attempt at making a very, very basic terminal program. The attempt below does not quite work right, for some reason the key press on the remote terminal is not appearing on the console terminal. When I run the code segments as separate code items, it works, but when I combine the two, it does not work as expected.

    These baby steps are leading up to a program(s) that will work with an XBee attached to the console terminal unit, and one attached to a remote unit.

    Ray
    /**
     * @file PPred0.c
     * This is the main PPred0 program start point.
     */
    #include <propeller.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <driver.h>
    
    
    extern _Driver _SimpleSerialDriver;
    extern _Driver _FullDuplexSerialDriver;
    
    
    _Driver *_driverlist[] = {
        &_FullDuplexSerialDriver,
        NULL
    };
    
    
    /**
     * Main program function.
     */
    int main(void)
    {
    
    /*                          Baud    Rx  Tx        */
        FILE *term = fopen("FDS:115200, 27, 26", "r+");
    
        char outbyte[1];
               
        waitcnt(CLKFREQ + CNT);
        /* Prints to console terminal screen. */
        printf("Start of program\n");
    
        fprintf(term,"This is on the remote terminal screen.\n");        
        while(1)
        {
    /* If no keypress on console terminal ... */
            if (stdin == NULL) continue;       
            else /* Handle the console terminal keypress */
            {        
                scanf("%s",outbyte);
                fprintf(term,"%s\n",outbyte); /* Send out to remote terminal. */
                fflush(term);
            }
    /* Get and display to console terminal the remote terminal keypress. */
            int byte = fgetc(stdin); /* Get keypress on the remote terminal. */
            fprintf(stdin,"%c",byte); /* Display on the console terminal. */
            fflush(stdin);
        }
        fclose(term);
        return 0;
    }
    
    
  • ersmithersmith Posts: 6,054
    edited 2012-09-28 04:57
    Rsadeika wrote: »
    Below is my attempt at making a very, very basic terminal program. The attempt below does not quite work right, for some reason the key press on the remote terminal is not appearing on the console terminal.
    I don't think you're ever reading from the terminal. Did you mean to write "byte = fgetc(term);" instead of "byte = fgetc(stdin):"?

    Also, the comment /* If no keypress on console terminal */ is misleading; testing "if (stdin == NULL)" does not check to see if there is a keypress, it checks to see if stdin is initialized (which it always will be, so there's no need for that test).

    Currently there is no easy way to try to get a key without pausing, so the program as structured will probably not do what you want. In the next release there will be an _IONONBLOCK flag that you can set on a FILE to cause reads to return immediately if no data is available.
  • Dave HeinDave Hein Posts: 6,347
    edited 2012-09-28 06:03
    Here's the routine that I use to determine if a character is ready to be read from stdin. You must use the FullDuplexSerial driver with this because it cheats by looking at hardcoded areas in the FDS struct for the input head and tail indices.
    int kbhit()
    {
        volatile int *rx_ptr = (int *)stdin->drvarg[0];
        return (rx_ptr[0] != rx_ptr[1]);
    }
    
  • RsadeikaRsadeika Posts: 3,837
    edited 2012-10-07 03:56
    I have attached a working master and slave using XBee, it is a very simple application. I am still using a spin2cpp version of FullDuplexSerial and XBee, the experts might have to point out how to use the built in FullDuplexSerial, to reduce the size of the code.

    I also included a Spin version of the use of Sensirion, and XBee modules, this works as expected, so maybe someone can try doing a spin2cpp conversion to see if they can get better results than I did. Feedback would be appreciated, just to keep my sanity in check LOL.

    Ray
Sign In or Register to comment.