*** empty log message ***

svn path=/trunk/externals/iem/comport/; revision=5282
This commit is contained in:
Martin Peach 2006-06-21 23:42:00 +00:00
parent 5b5d56d168
commit dd962bf7d8

View file

@ -6,7 +6,9 @@
V 1.0
MP 20060603 memset and memcpy arguments were backwards for Windows version. close_serial doesn't crash now.
MP 20060618 make sure name is set up in comport_new (x->serial_device = test.serial_device) so help message works.
MP 20060619 implemented status outlet
MP 20060620 Add DTR and RTS control, add outputs to reflect CTS and DSR states.
MP 20060621 Do all the above for Windows too.
*/
#include "m_pd.h"
@ -22,7 +24,8 @@ MP 20060618 make sure name is set up in comport_new (x->serial_device = test.ser
#else
#include <sys/time.h>
#include <fcntl.h>
#include <termios.h> /* for TERMIO ioctl calls */
#include <sys/ioctl.h> /* for ioctl DTR */
#include <termios.h> /* for TERMIO ioctl calls */
#include <unistd.h>
#include <glob.h>
#define HANDLE int
@ -50,6 +53,9 @@ typedef struct comport
t_symbol *serial_device;
char serial_device_name[FILENAME_MAX];
short comport; /* holds the comport # */
short last_comport; /* the last comport that was output on x_status_outlet */
short last_dsr;/* last dsr input state */
short last_cts;/* last cts input state */
t_float baud; /* holds the current baud rate */
short rxerrors; /* holds the rx line errors */
t_clock *x_clock;
@ -58,6 +64,8 @@ typedef struct comport
int verbose;
t_outlet *x_data_outlet;
t_outlet *x_status_outlet;
t_outlet *x_dsr_outlet;
t_outlet *x_cts_outlet;
} t_comport;
#ifndef TRUE
@ -169,7 +177,7 @@ static long baudratetable[] =
t_class *comport_class;
/* --------- sys independend serial setup helpers ---------------- */
/* --------- sys independent serial setup helpers ---------------- */
static long get_baud_ratebits(t_float *baud)
{
@ -189,7 +197,7 @@ static long get_baud_ratebits(t_float *baud)
}
/* ------------ sys dependend serial setup helpers ---------------- */
/* ------------ sys dependent serial setup helpers ---------------- */
/* --------------------- NT ------------------------------------ */
@ -261,6 +269,32 @@ static int set_ctsrts(t_comport *x, int nr)
return 0;
}
static int set_dtr(t_comport *x, int nr)
{
HANDLE fd = x->comhandle;
BOOL status;
DWORD dwFunc = (nr==0)?CLRDTR:SETDTR;
if (fd == INVALID_HANDLE_VALUE) return -1;
status = EscapeCommFunction(fd, dwFunc);
if (status != 0) return nr;
return -1; /* didn't work, GetLastError tells why */
}
static int set_rts(t_comport *x, int nr)
{
HANDLE fd = x->comhandle;
BOOL status;
DWORD dwFunc = (nr==0)?CLRRTS:SETRTS;
if (fd == INVALID_HANDLE_VALUE) return -1;
status = EscapeCommFunction(fd, dwFunc);
if (status != 0) return nr;
return -1; /* didn't work, GetLastError tells why */
}
static int set_xonxoff(t_comport *x, int nr)
{
/* x->dcb.fTXContinueOnXoff = FALSE; XOFF continues Tx */
@ -291,7 +325,7 @@ static HANDLE open_serial(unsigned int com_num, t_comport *x)
if(com_num < 1 || com_num >= COMPORT_MAX)
{
post("comport open %d, baud %d not valid (args: [portnum] [baud])",com_num,*baud);
post("comport number %d out of range (0-%d)", com_num, COMPORT_MAX);
return INVALID_HANDLE_VALUE;
}
@ -388,13 +422,11 @@ static HANDLE open_serial(unsigned int com_num, t_comport *x)
if (!SetCommTimeouts(fd, &timeouts))
{
post("Couldnt set timeouts for serial device");
post("Couldn't set timeouts for serial device");
return INVALID_HANDLE_VALUE;
}
// this causes a segfault... WHY?!?
// outlet_float(x->x_status_outlet, (t_float)com_num);
x->comport = com_num;/* output on next tick */
return fd;
}
@ -404,7 +436,7 @@ static HANDLE close_serial(t_comport *x)
{
if (!SetCommState(x->comhandle, &(x->dcb_old)))
{
post("[comport] ** ERROR ** could not reset params to DCB of device %s\n",
post("[comport] ** ERROR ** couldn't reset params to DCB of device %s\n",
x->serial_device->s_name);
}
if (!SetCommTimeouts(x->comhandle, &(x->old_timeouts)))
@ -412,11 +444,8 @@ static HANDLE close_serial(t_comport *x)
post("[comport] Couldn't reset old_timeouts for serial device");
}
CloseHandle(x->comhandle);
// for some reason, this causes a segfault...
// post("[comport] closed %s",x->serial_device->s_name);
post("[comport] closed %s",x->serial_device->s_name);
}
// this causes a segfault... WHY?!?
// outlet_float(x->x_status_outlet, 0);
return INVALID_HANDLE_VALUE;
}
@ -529,6 +558,38 @@ static int set_ctsrts(t_comport *x, int nr)
return 0;
}
static int set_dtr(t_comport *x, int nr)
{
int fd = x->comhandle;
int status;
if (fd == INVALID_HANDLE_VALUE) return -1;
ioctl(fd, TIOCMGET, &status);
if (nr == 0)
status &= ~TIOCM_DTR;
else
status |= TIOCM_DTR;
ioctl(fd, TIOCMSET, &status);
return (nr !=0);
}
static int set_rts(t_comport *x, int nr)
{
int fd = x->comhandle;
int status;
if (fd == INVALID_HANDLE_VALUE) return -1;
ioctl(fd, TIOCMGET, &status);
if (nr == 0)
status &= ~TIOCM_RTS;
else
status |= TIOCM_RTS;
ioctl(fd, TIOCMSET, &status);
return (nr !=0);
}
static int set_xonxoff(t_comport *x, int nr)
{
struct termios *tio = &(x->com_termio);
@ -551,7 +612,7 @@ static int open_serial(unsigned int com_num, t_comport *x)
float *baud = &(x->baud);
glob_t glob_buffer;
/* if com_num == 9999, use device name directly, else try port # */
/* if com_num == 9999, use device name directly, else try port # */
if(com_num != 9999)
{
if(com_num >= COMPORT_MAX)
@ -560,7 +621,7 @@ static int open_serial(unsigned int com_num, t_comport *x)
com_num, COMPORT_MAX - 1);
return INVALID_HANDLE_VALUE;
}
// post("[comport] globbing %s",x->serial_device_name);
/* post("[comport] globbing %s",x->serial_device_name);*/
/* get the device path based on the port# and the glob pattern */
switch( glob( x->serial_device_name, 0, NULL, &glob_buffer ) )
{
@ -637,8 +698,6 @@ static int open_serial(unsigned int com_num, t_comport *x)
{
post("[comport] opened serial line device %d (%s)\n",
com_num,x->serial_device->s_name);
// this causes a segfault... WHY?!?
// outlet_float(x->x_status_outlet, (t_float)com_num);
}
else
{
@ -647,6 +706,10 @@ static int open_serial(unsigned int com_num, t_comport *x)
close(fd);
return INVALID_HANDLE_VALUE;
}
x->comport = com_num; /* output at next comport_tick */
x->last_comport = 777; /* a wrong number to force ouput at next comport_tick */
x->last_dsr = -1; /* a wrong number so state will be output at next comport_tick */
x->last_cts = -1; /* a wrong number so state will be output at next comport_tick */
return fd;
}
@ -659,10 +722,7 @@ static int close_serial(t_comport *x)
{
tcsetattr(fd, TCSANOW, tios);
close(fd);
// for some reason, this causes a segfault...
// post("[comport] closed %s",x->serial_device->s_name);
// this causes a segfault... WHY?!?
// outlet_float(x->x_status_outlet, 0);
post("[comport] closed %s",x->serial_device->s_name);
}
return INVALID_HANDLE_VALUE;
}
@ -676,8 +736,10 @@ static int set_serial(t_comport *x)
static int write_serial(t_comport *x, unsigned char serial_byte)
{
return write(x->comhandle,(char *) &serial_byte,1);
int result = write(x->comhandle,(char *) &serial_byte,1);
if (result != 1)
post ("[comport] write returned %d, errno is %d", result, errno);
return result;
/* flush pending I/O chars */
/* but nowadays discards them ;-(
else
@ -698,11 +760,52 @@ static void comport_pollintervall(t_comport *x, t_floatarg g)
static void comport_tick(t_comport *x)
{
int err;
HANDLE fd = x->comhandle;
int err;
HANDLE fd = x->comhandle;
short newdsr, newcts;
#ifdef _WIN32
{
DWORD modemStat;
/* get the DSR input state and if it's changed, output it */
BOOL status = GetCommModemStatus( fd, &modemStat);
if (status)
{
newdsr = ((modemStat&MS_DSR_ON)!=0);/* read the DSR input line */
newcts = ((modemStat&MS_CTS_ON)!=0);/* read the CTS input line */
}
else
{
;/* call GetLastError, only once so as not to hang pd */
}
}
#else
{
int status;/*dsr outlet*/
/* get the DSR input state and if it's changed, output it */
ioctl(fd, TIOCMGET, &status);/*dsr outlet*/
newdsr = ((status&TIOCM_LE)!=0);/* read the DSR input line */
newcts = ((status&TIOCM_CTS)!=0);/* read the CTS input line */
}
#endif
if (newdsr != x->last_dsr)
{
x->last_dsr = newdsr;
if(x->x_dsr_outlet!=NULL) outlet_float(x->x_dsr_outlet, (float)(x->last_dsr));/*dsr outlet*/
}
if (newcts != x->last_cts)
{
x->last_cts = newcts;
if(x->x_cts_outlet!=NULL) outlet_float(x->x_cts_outlet, (float)(x->last_cts));/*cts outlet*/
}
x->x_hit = 0;
if(x->last_comport != x->comport)
{
x->last_comport = x->comport;
if (x->x_status_outlet != NULL) outlet_float(x->x_status_outlet, (float)x->comport);
}
if(fd == INVALID_HANDLE_VALUE) return;
/* while there are bytes, read them and send them out, ignore errors */
@ -791,16 +894,18 @@ static void *comport_new(t_floatarg com_num, t_floatarg fbaud)
/* Open the Comport for RD and WR and get a handle */
strncpy(test.serial_device_name,serial_device_name,strlen(serial_device_name)+1);
strncpy(test.serial_device_name, serial_device_name, strlen(serial_device_name)+1);
test.baud = fbaud;
fd = open_serial((unsigned int)com_num,&test);
fd = open_serial((unsigned int)com_num, &test);
/* Now nothing really bad could happen so we create the class */
x = (t_comport *)pd_new(comport_class);
x->comport = (short)com_num;
x->comport = test.comport;/* com_num */
x->last_comport = 777; /* no known comport to force output at comport_tick */
strncpy(x->serial_device_name,serial_device_name,strlen(serial_device_name)+1);
x->serial_device = test.serial_device; /* MP: we need this so 'help' doesn't crash */
x->serial_device = test.serial_device; /* we need this so 'help' doesn't crash */
x->baud = test.baud;
x->comhandle = fd; /* holds the comport handle */
@ -823,9 +928,10 @@ static void *comport_new(t_floatarg com_num, t_floatarg fbaud)
x->rxerrors = 0; /* holds the rx line errors */
x->x_data_outlet = (t_outlet *)outlet_new(&x->x_obj, &s_float);
// for some unknown reason, outputting on this outlet causes segfaults...
// x->x_status_outlet = (t_outlet *)outlet_new(&x->x_obj, &s_float);
x->x_data_outlet = outlet_new(&x->x_obj, &s_float);
x->x_status_outlet = outlet_new(&x->x_obj, &s_float);
x->x_dsr_outlet = outlet_new(&x->x_obj, &s_float);
x->x_cts_outlet = outlet_new(&x->x_obj, &s_float);
x->x_hit = 0;
x->x_deltime = 1;
@ -931,6 +1037,36 @@ static void comport_rtscts(t_comport *x,t_floatarg f)
post("[comport] set rts-cts of %s to %f\n",x->serial_device->s_name,f);
}
static void comport_dtr(t_comport *x,t_floatarg f)
{
f = set_dtr(x,f);
if(x->comhandle == INVALID_HANDLE_VALUE)return;
if(f < 0)
{
error("[comport] ** ERROR ** could not set dtr of device %s\n",
x->serial_device->s_name);
}
else if(x->verbose > 0)
post("[comport] set dtr of %s to %f\n",x->serial_device->s_name,f);
}
static void comport_rts(t_comport *x,t_floatarg f)
{
f = set_rts(x,f);
if(x->comhandle == INVALID_HANDLE_VALUE)return;
if(f < 0)
{
error("[comport] ** ERROR ** could not set rts of device %s\n",
x->serial_device->s_name);
}
else if(x->verbose > 0)
post("[comport] set rts of %s to %f\n",x->serial_device->s_name,f);
}
static void comport_xonxoff(t_comport *x,t_floatarg f)
{
f = set_xonxoff(x,f);
@ -951,6 +1087,9 @@ static void comport_close(t_comport *x)
clock_unset(x->x_clock);
x->x_hit = 1;
x->comhandle = close_serial(x);
x->comport = -1; /* none */
if (x->x_status_outlet != NULL) outlet_float(x->x_status_outlet, (float)x->comport);
x->last_comport = x->comport;
}
static void comport_open(t_comport *x, t_floatarg f)
@ -1014,6 +1153,8 @@ static void comport_help(t_comport *x)
" rtscts <0|1> ... set rts/cts off|on\n"
" parity <0|1> ... set parity off|on\n"
" xonxoff <0|1> ... set xon/xoff off|on\n"
" dtr <0|1> ... set dtr off|on\n"
" rts <0|1> ... set rts off|on\n"
" close ... close device\n"
" open <num> ... open device number num\n"
" devicename <d> ... set device name to s (eg. /dev/ttyS8)\n"
@ -1024,9 +1165,6 @@ static void comport_help(t_comport *x)
}
/* ---------------- SETUP OBJECTS ------------------ */
#ifdef _WIN32
__declspec(dllexport)
#endif
void comport_setup(void)
{
comport_class = class_new(gensym("comport"), (t_newmethod)comport_new,
@ -1043,6 +1181,8 @@ void comport_setup(void)
class_addmethod(comport_class, (t_method)comport_bits, gensym("bits"), A_FLOAT, 0);
class_addmethod(comport_class, (t_method)comport_stopbit, gensym("stopbit"), A_FLOAT, 0);
class_addmethod(comport_class, (t_method)comport_rtscts, gensym("rtscts"), A_FLOAT, 0);
class_addmethod(comport_class, (t_method)comport_dtr, gensym("dtr"), A_FLOAT, 0);
class_addmethod(comport_class, (t_method)comport_rts, gensym("rts"), A_FLOAT, 0);
class_addmethod(comport_class, (t_method)comport_parity, gensym("parity"), A_FLOAT, 0);
class_addmethod(comport_class, (t_method)comport_xonxoff, gensym("xonxoff"), A_FLOAT, 0);
class_addmethod(comport_class, (t_method)comport_close, gensym("close"), 0);