Hogwarts Wand Docs: ../server/ac_serialio.c

Wand Sourcecode: ../server/ac_serialio.c

//
// ac_serialio.c - serial port functions
//
// Copyright (C) 2006  Nathan (Acorn) Pooley
// 
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// version 2 as published by the Free Software Foundation.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License (gpl.txt) for more details. 
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
// 
// You can contact the author, Nathan (Acorn) Pooley, by writing
// to Nathan (Acorn) Pooley, 949 Buckeye Drive, Sunnyvale, CA  94086, USA
// or through the form at http://www.rawbw.com/~acorn/wand/feedback.html
//
//
// Thanks to Gary Frerking for writing the Serial Programming HOWTO at
//    http://www.tldp.org/HOWTO/Serial-Programming-HOWTO
// Much of this is based on his descriptions and examples.
//

//#@DOC@ serial port functions

//###########################################################################
//############################### INCLUDES ##################################
//###########################################################################

#include "ac_serialio.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>


//###########################################################################
//############################### TYPEDEFS ##################################
//###########################################################################

//===========================================================================
// AcSerial
//===========================================================================
struct AcSerialRec {
    char *device;
    int baudrate;
    int baudenum;
    int fd;

    struct termios oldtio;
    struct termios newtio;

};

//###########################################################################
//############################### GLOBALS ###################################
//###########################################################################

//###########################################################################
//############################### CODE ######################################
//###########################################################################

//===========================================================================
// acSerialDestroy()
//===========================================================================
void acSerialDestroy(AcSerial *sio)
{
    acSerialClose(sio);
    if (sio->device) {
        free(sio->device);
    }
    free(sio);
}

//===========================================================================
// acSerialCreate()
//===========================================================================
AcSerial *acSerialCreate(const char *device, int baudrate)
{
    AcSerial *sio = calloc(1,sizeof(AcSerial));
    if (!sio) return 0;

    sio->device = strdup(device);
    sio->fd = -1;
    sio->baudrate = 9600;
    acSerialSetBaud(sio,baudrate);
    sio->newtio.c_cflag = 0
                    | CS8       // 8N1 (b8 bit, no parity, 1 stop
                    | CLOCAL    // local (not modem)
                    | CREAD     // enable rx
                    | CSTOPB    // 2 stop bits
                    //| CRTSCTS // HW flow control
                    ;
    sio->newtio.c_iflag = 0
                    | IGNPAR    // ignore parity errors
                    | ICRNL     // map CR to NL
                    ;
    sio->newtio.c_oflag = 0;        // Raw output


    //sio->newtio.c_oflag |= CSTOPB;    // 2 stop bits on output

    sio->newtio.c_lflag = ICANON;   // canonical output

    sio->newtio.c_cc[VINTR]    = 0;     /* Ctrl-c */ 
    sio->newtio.c_cc[VQUIT]    = 0;     /* Ctrl-\ */
    sio->newtio.c_cc[VERASE]   = 0;     /* del */
    sio->newtio.c_cc[VKILL]    = 0;     /* @ */
    sio->newtio.c_cc[VEOF]     = 4;     /* Ctrl-d */
    sio->newtio.c_cc[VTIME]    = 0;     /* inter-character timer unused */
    sio->newtio.c_cc[VMIN]     = 1;     /* blocking read until 1 char arrives */
    sio->newtio.c_cc[VSWTC]    = 0;     /* '\0' */
    sio->newtio.c_cc[VSTART]   = 0;     /* Ctrl-q */ 
    sio->newtio.c_cc[VSTOP]    = 0;     /* Ctrl-s */
    sio->newtio.c_cc[VSUSP]    = 0;     /* Ctrl-z */
    sio->newtio.c_cc[VEOL]     = 0;     /* '\0' */
    sio->newtio.c_cc[VREPRINT] = 0;     /* Ctrl-r */
    sio->newtio.c_cc[VDISCARD] = 0;     /* Ctrl-u */
    sio->newtio.c_cc[VWERASE]  = 0;     /* Ctrl-w */
    sio->newtio.c_cc[VLNEXT]   = 0;     /* Ctrl-v */
    sio->newtio.c_cc[VEOL2]    = 0;     /* '\0' */
                    
    return sio;
}

//===========================================================================
// acSerialSetNonCanonical()
//===========================================================================
//
// By default, read entire line before returning it.
// After calling acSerialSetMode() wait as follows:
//
//    vtime  vmin   description
//    -----  ----   -----------
//     0      0      return immediately
//    >0      0      wait until 1 char received, or until timeout
//     0     >0      wait until vmin chars received
//    >0     >0      wait until vmin chars received, or until vtime elapsed 
//                                          since last char
//  vtime is in 1/10 second.
//
//
int acSerialSetNonCanonical(AcSerial *sio, int vtime, int vmin)
{
    sio->newtio.c_lflag = 0;
    sio->newtio.c_cc[VTIME] = vtime;
    sio->newtio.c_cc[VMIN]  = vmin; 
    if (vtime == 0 && vmin == 0) {
        fprintf(stderr,
            "WARNING: Non-Canonical mode with vtime==vmin==0 is broken!\n");
    }
    return 0;
}

//===========================================================================
// acSerialSetBaud()
//===========================================================================
int acSerialSetBaud(AcSerial *sio, int baudrate)
{
    switch(baudrate) {
        case 50:     sio->baudenum = B50; break;
        case 75:     sio->baudenum = B75; break;
        case 110:    sio->baudenum = B110; break;
        case 134:    sio->baudenum = B134; break;
        case 150:    sio->baudenum = B150; break;
        case 200:    sio->baudenum = B200; break;
        case 300:    sio->baudenum = B300; break;
        case 600:    sio->baudenum = B600; break;
        case 1200:   sio->baudenum = B1200; break;
        case 1800:   sio->baudenum = B1800; break;
        case 2400:   sio->baudenum = B2400; break;
        case 4800:   sio->baudenum = B4800; break;
        case 9600:   sio->baudenum = B9600; break;
        case 19200:  sio->baudenum = B19200; break;
        case 38400:  sio->baudenum = B38400; break;
        case 57600:  sio->baudenum = B57600; break;
        case 115200: sio->baudenum = B115200; break;
        case 230400: sio->baudenum = B230400; break;
        default:
            fprintf(stderr,"Error: bad baud rate: %d. \n", baudrate);
            if (baudrate != sio->baudrate) {
                fprintf(stderr,"Using %d.\n",sio->baudrate);
                acSerialSetBaud(sio,sio->baudrate);
            } else if (baudrate != 9600) {
                fprintf(stderr,"Using %d.\n",9600);
                acSerialSetBaud(sio,9600);
            }
            return -1;
    }

    cfsetispeed(&sio->newtio, sio->baudenum);
    cfsetospeed(&sio->newtio, sio->baudenum);

    sio->baudrate = baudrate;
    return 0;
}

//===========================================================================
// acSerialGetFD()
//===========================================================================
int acSerialGetFD(AcSerial *sio)
{
    return sio->fd;
}

//===========================================================================
// acSerialOpen()
//===========================================================================
int acSerialOpen(AcSerial *sio)
{
    sio->fd = open(sio->device, O_RDWR | O_NOCTTY);
    if (sio->fd < 0) {
        return -1;
    }

    //
    // save old settings
    //
    tcgetattr(sio->fd,&sio->oldtio);

    //
    // clear the line and activate settings
    //
    tcflush(sio->fd, TCIFLUSH);
    tcsetattr(sio->fd,TCSANOW, &sio->newtio);

    return 0;
}

//===========================================================================
// acSerialClose()
//===========================================================================
void acSerialClose(AcSerial *sio)
{
    if (sio->fd >= 0) {
        tcsetattr(sio->fd,TCSANOW,&sio->oldtio);
        close(sio->fd);
    }
    sio->fd = -1;
}


This file Copyright (C) 2006 by Nathan (Acorn) Pooley
Go to TOP Wand page
Go to Acorn's personal webpage
Go to Hogwarts website: www.gotohogwarts.com
Snout: www.snout.org/game
Gadgets of Justice Unlimited
Snout GC (Wiki)
Snout Wiki
File created by do_doc at Wed May 30 03:25:03 PDT 2007