Csound Csound-dev Csound-tekno Search About

[Cs-dev] serial opcodes code

Date2011-09-04 22:11
Frommatt ingalls
Subject[Cs-dev] serial opcodes code
not too long so i'm posting here, hope that's ok
in case anyone wanted to try it out (QA, etc), esp. on other platforms than mac..

it's been a while since ive done any csound dev so wouldn't be surprised if
there were bugs... :)
-m


#include  
#include    /* Standard types */
#include    /* String function definitions */
#include    /* UNIX standard function definitions */
#include     /* File control definitions */
#include     /* Error number definitions */
#include   /* POSIX terminal control definitions */
#include 
#include 

#include "csdl.h"
#include "csound.h"

/*****************************************************
 
			CSOUND SERIAL PORT OPCODES
			  ma++ ingalls, 2011/9/4
 
 * based on "Arduino-serial"
 * Copyleft (c) 2006, Tod E. Kurt, tod@todbot.com
 * http://todbot.com/blog/
 

open a port.  baudRate defaults to 9600
	iPort  serialBegin         SPortName [, baudRate ]
 
close a port
			serialEnd           iPort

write byte(s) to the port, at i or k rate
			serialWrite_i       iPort, iByte
			serialWrite_i       iPort, kByte
			serialWrite_i       iPort, Sbytes
			serialWrite         iPort, iByte
			serialWrite         iPort, kByte
			serialWrite         iPort, Sbytes

read the next byte from the input buffer
returned value will be in the range of 0-255
	kByte	serialRead          iPort
    
print to screen any bytes (up to 32k) in input buffer
note that these bytes will be cleared from the buffer.
use this opcode mainly for debugging messages.
if you want to mix debugging and other communication 
messages over the same port, you will need to manually
parse the data with the serialRead opcode.
			serialPrint			iPort
 
clear the input buffer
			serialFlush         iPort

 
TODO: (might need some kind of threaded buffer-read?)
 
 kNum   serialAvailable    iPort
 returns number of bytes available to read
 
 kByte   serialPeekByte      iPort
 returns the next byte in the input buffer
 does not remove the byte from the buffer
 
*****************************************************/

typedef struct {
    OPDS  h;
    MYFLT *returnedPort, *portName, *baudRate;
} SERIALBEGIN;
int serialBegin(CSOUND *csound, SERIALBEGIN *p);

typedef struct {
    OPDS  h;
    MYFLT *port;
} SERIALEND;
int serialEnd(CSOUND *csound, SERIALEND *p);

typedef struct {
    OPDS  h;
    MYFLT *port, *toWrite;
} SERIALWRITE;
int serialWrite(CSOUND *csound, SERIALWRITE *p);

typedef struct {
    OPDS  h;
    MYFLT *rChar, *port;
} SERIALREAD;
int serialRead(CSOUND *csound, SERIALREAD *p);

typedef struct {
    OPDS  h;
    MYFLT *port;
} SERIALPRINT;
int serialPrint(CSOUND *csound, SERIALPRINT *p);

typedef struct {
    OPDS  h;
    MYFLT *port;
} SERIALFLUSH;
int serialFlush(CSOUND *csound, SERIALFLUSH *p);


///-----------TODO
typedef struct {
    OPDS  h;
    MYFLT *retVal, *port;
} SERIALAVAIL;
int serialAvailable(CSOUND *csound, SERIALAVAIL *p);

typedef struct {
    OPDS  h;
    MYFLT *retChar, *port;
} SERIALPEEK;
int serialPeekByte(CSOUND *csound, SERIALPEEK *p);
//------------------


// takes the string name of the serial port (e.g. "/dev/tty.usbserial","COM1")
// and a baud rate (bps) and connects to that port at that speed and 8N1.
// opens the port in fully raw mode so you can send binary data.
// returns valid fd, or -1 on error
int serialport_init(const char* serialport, int baud)
{
    struct termios toptions;
    int fd;
    
    fprintf(stderr,"init_serialport: opening port %s @ %d bps\n",
            serialport,baud);
	
    fd = open(serialport, O_RDWR | O_NOCTTY | O_NDELAY);
    if (fd == -1)  {
        perror("init_serialport: Unable to open port ");
        return -1;
    }
    
    if (tcgetattr(fd, &toptions) < 0) {
        perror("init_serialport: Couldn't get term attributes");
        return -1;
    }
    //speed_t brate = baud; // let you override switch below if needed
    speed_t brate = B9600;  // ma++ changed to always default to 9600
    switch(baud) {
		case 4800:   brate=B4800;   break;
		case 9600:   brate=B9600;   break;
#ifdef B14400
		case 14400:  brate=B14400;  break;
#endif
		case 19200:  brate=B19200;  break;
#ifdef B28800
		case 28800:  brate=B28800;  break;
#endif
		case 38400:  brate=B38400;  break;
		case 57600:  brate=B57600;  break;
		case 115200: brate=B115200; break;
    }
    cfsetispeed(&toptions, brate);
    cfsetospeed(&toptions, brate);
	
    // 8N1
    toptions.c_cflag &= ~PARENB;
    toptions.c_cflag &= ~CSTOPB;
    toptions.c_cflag &= ~CSIZE;
    toptions.c_cflag |= CS8;
    // no flow control
    toptions.c_cflag &= ~CRTSCTS;
	
    toptions.c_cflag |= CREAD | CLOCAL;  // turn on READ & ignore ctrl lines
    toptions.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl
	
    toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw
    toptions.c_oflag &= ~OPOST; // make raw
	
    // see: http://unixwiz.net/techtips/termios-vmin-vtime.html
    toptions.c_cc[VMIN]  = 0;
    toptions.c_cc[VTIME] = 20;
    
    if( tcsetattr(fd, TCSANOW, &toptions) < 0) {
        perror("init_serialport: Couldn't set term attributes");
        return -1;
    }
	
    return fd;
}

int serialBegin(CSOUND *csound, SERIALBEGIN *p)
{
    *p->returnedPort = serialport_init((char *)p->portName, *p->baudRate);
	return OK;
}
int serialEnd(CSOUND *csound, SERIALEND *p)
{
	close(*p->port);
    return OK;
}
int serialWrite(CSOUND *csound, SERIALWRITE *p)
{
	if (p->XSTRCODE & 2)
		write(*p->port, p->toWrite, strlen((char *)p->toWrite));
	else {
		unsigned char b = *p->toWrite;
		write(*p->port, &b, 1);
	}

    return OK;
}
int serialRead(CSOUND *csound, SERIALREAD *p)
{
    unsigned char b = 0;
    ssize_t bytes = read(*p->port, &b, 1);
	if (bytes > 0)
        *p->rChar = b;
    else 
        *p->rChar = -1;
    
    return OK;
}
int serialPrint(CSOUND *csound, SERIALPRINT *p)
{
	char str[32768];
	ssize_t bytes = read(*p->port, str, 32768);
	if (bytes > 0) {
		str[bytes] = 0; // terminate
		csound->MessageS(csound, CSOUNDMSG_ORCH, "%s", str);
	}
    return OK;
}
int serialFlush(CSOUND *csound, SERIALFLUSH *p)
{
	tcflush(*p->port, TCIFLUSH); // who knows if this works...
    return OK;
}
int serialAvailable(CSOUND *csound, SERIALAVAIL *p)
{
	//TODO
    return OK;
}
int serialPeekByte(CSOUND *csound, SERIALPEEK *p)
{
	//TODO
    return OK;
}



#define S(x)    sizeof(x)

static OENTRY localops[] = {
    { (char *)"serialBegin", S(SERIALBEGIN), 1, (char *)"i", (char *)"So", (SUBR)serialBegin, (SUBR)NULL, (SUBR)NULL   },
    { (char *)"serialEnd", S(SERIALEND), 2, (char *)"", (char *)"i", (SUBR)NULL, (SUBR)serialEnd, (SUBR)NULL   },
	{ (char *)"serialWrite_i", S(SERIALWRITE), 1, (char *)"", (char *)"iT", (SUBR)serialWrite, (SUBR)NULL, (SUBR)NULL   },
	{ (char *)"serialWrite", S(SERIALWRITE), 2, (char *)"", (char *)"iU", (SUBR)NULL, (SUBR)serialWrite, (SUBR)NULL   },
    { (char *)"serialRead", S(SERIALREAD), 2, (char *)"k", (char *)"i", (SUBR)NULL, (SUBR)serialRead, (SUBR)NULL   },
    { (char *)"serialPrint", S(SERIALPRINT), 2, (char *)"", (char *)"i", (SUBR)NULL, (SUBR)serialPrint, (SUBR)NULL   },
	{ (char *)"serialFlush", S(SERIALFLUSH), 2, (char *)"", (char *)"i", (SUBR)NULL, (SUBR)serialFlush, (SUBR)NULL   },
	{ (char *)"serialAvailable", S(SERIALAVAIL), 2, (char *)"k", (char *)"i", (SUBR)NULL, (SUBR)serialAvailable, (SUBR)NULL   },
    { (char *)"serialPeekByte", S(SERIALPEEK), 2, (char *)"k", (char *)"i", (SUBR)NULL, (SUBR)serialPeekByte, (SUBR)NULL   }
};


------------------------------------------------------------------------------
Special Offer -- Download ArcSight Logger for FREE!
Finally, a world-class log management solution at an even better 
price-free! And you'll get a free "Love Thy Logs" t-shirt when you
download Logger. Secure your free ArcSight Logger TODAY!
http://p.sf.net/sfu/arcsisghtdev2dev
_______________________________________________
Csound-devel mailing list
Csound-devel@lists.sourceforge.net