Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/external/serialport/serialport.c
Views: 11701
/* Ruby/SerialPort $Id: serialport.c,v 1.1.1.1 2004/05/25 20:41:09 vjt Exp $1* Guillaume Pierronnet <[email protected]>2* Alan Stern <[email protected]>3*4* This code is hereby licensed for public consumption under either the5* GNU GPL v2 or greater.6*7* You should have received a copy of the GNU General Public License8* along with this program; if not, write to the Free Software9* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.10*11* For documentation on serial programming, see the excellent:12* "Serial Programming Guide for POSIX Operating Systems"13* written Michael R. Sweet.14* http://www.easysw.com/~mike/serial/15*/1617#define VERSION "0.6.1-msf"1819#include <ruby.h> /* ruby inclusion */20#include <rubyio.h> /* ruby io inclusion */2122struct modem_params {23int data_rate;24int data_bits;25int stop_bits;26int parity;27};2829struct line_signals {30int rts;31int dtr;32int cts;33int dsr;34int dcd;35int ri;36};3738VALUE cSerialPort; /* serial port class */3940static VALUE sBaud, sDataBits, sStopBits, sParity; /* strings */41static VALUE sRts, sDtr, sCts, sDsr, sDcd, sRi;424344#if defined(mswin) || defined(bccwin)454647#include <stdio.h> /* Standard input/output definitions */48#include <io.h> /* Low-level I/O definitions */49#include <fcntl.h> /* File control definitions */50#include <windows.h> /* Windows standard function definitions */5152#define NONE 053#define HARD 154#define SOFT 25556#define SPACE SPACEPARITY57#define MARK MARKPARITY58#define EVEN EVENPARITY59#define ODD ODDPARITY6061static char sGetCommState[] = "GetCommState";62static char sSetCommState[] = "SetCommState";63static char sGetCommTimeouts[] = "GetCommTimeouts";64static char sSetCommTimeouts[] = "SetCommTimeouts";656667static HANDLE sp_get_handle(obj)68VALUE obj;69{70OpenFile *fptr;7172GetOpenFile(obj, fptr);73return (HANDLE) _get_osfhandle(fileno(fptr->f));74}7576static VALUE sp_create(class, _port)77VALUE class, _port;78{79OpenFile *fp;80int fd;81HANDLE fh;82int num_port;83char *port;84char *ports[] = {85"COM1", "COM2", "COM3", "COM4",86"COM5", "COM6", "COM7", "COM8"87};88DCB dcb;8990NEWOBJ(sp, struct RFile);91rb_secure(4);92OBJSETUP(sp, class, T_FILE);93MakeOpenFile(sp, fp);9495switch(TYPE(_port)) {96case T_FIXNUM:97num_port = FIX2INT(_port);98if (num_port < 0 || num_port > sizeof(ports) / sizeof(ports[0]))99rb_raise(rb_eArgError, "illegal port number");100port = ports[num_port];101break;102103case T_STRING:104Check_SafeStr(_port);105port = RSTRING(_port)->ptr;106break;107108default:109rb_raise(rb_eTypeError, "wrong argument type");110break;111}112113fd = open(port, O_BINARY | O_RDWR);114if (fd == -1)115rb_sys_fail(port);116fh = (HANDLE) _get_osfhandle(fd);117if (SetupComm(fh, 1024, 1024) == 0) {118close(fd);119rb_raise(rb_eArgError, "not a serial port");120}121122dcb.DCBlength = sizeof(dcb);123if (GetCommState(fh, &dcb) == 0) {124close(fd);125rb_sys_fail(sGetCommState);126}127dcb.fBinary = TRUE;128dcb.fParity = FALSE;129dcb.fOutxDsrFlow = FALSE;130dcb.fDtrControl = DTR_CONTROL_ENABLE;131dcb.fDsrSensitivity = FALSE;132dcb.fTXContinueOnXoff = FALSE;133dcb.fErrorChar = FALSE;134dcb.fNull = FALSE;135dcb.fAbortOnError = FALSE;136dcb.XonChar = 17;137dcb.XoffChar = 19;138if (SetCommState(fh, &dcb) == 0) {139close(fd);140rb_sys_fail(sSetCommState);141}142143fp->f = rb_fdopen(fd, "rb+");144fp->mode = FMODE_READWRITE | FMODE_BINMODE | FMODE_SYNC;145return (VALUE) sp;146}147148static VALUE sp_set_modem_params(argc, argv, self)149int argc;150VALUE *argv, self;151{152HANDLE fh;153DCB dcb;154VALUE _data_rate = 0, _data_bits = 0, _parity = NONE, _stop_bits = 0;155int use_hash = 0;156int data_rate, data_bits, parity;157158if (argc == 0)159return self;160if (argc == 1 && T_HASH == TYPE(argv[0])) {161use_hash = 1;162_data_rate = rb_hash_aref(argv[0], sBaud);163_data_bits = rb_hash_aref(argv[0], sDataBits);164_stop_bits = rb_hash_aref(argv[0], sStopBits);165_parity = rb_hash_aref(argv[0], sParity);166}167168fh = sp_get_handle(self);169dcb.DCBlength = sizeof(dcb);170if (GetCommState(fh, &dcb) == 0)171rb_sys_fail(sGetCommState);172173if (!use_hash)174_data_rate = argv[0];175if (NIL_P(_data_rate))176goto SkipDataRate;177Check_Type(_data_rate, T_FIXNUM);178179data_rate = FIX2INT(_data_rate);180switch (data_rate) {181case 110:182case 300:183case 600:184case 1200:185case 2400:186case 4800:187case 9600:188case 14400:189case 19200:190case 38400:191case 56000:192case 57600:193case 115200:194case 128000:195case 256000:196dcb.BaudRate = data_rate;197break;198199default:200rb_raise(rb_eArgError, "unknown baud rate");201break;202}203SkipDataRate:204205if (!use_hash)206_data_bits = (argc >= 2 ? argv[1] : INT2FIX(8));207if (NIL_P(_data_bits))208goto SkipDataBits;209Check_Type(_data_bits, T_FIXNUM);210211data_bits = FIX2INT(_data_bits);212if (4 <= data_bits && data_bits <= 8)213dcb.ByteSize = data_bits;214else215rb_raise(rb_eArgError, "unknown character size");216SkipDataBits:217218if (!use_hash)219_stop_bits = (argc >= 3 ? argv[2] : INT2FIX(1));220if (NIL_P(_stop_bits))221goto SkipStopBits;222Check_Type(_stop_bits, T_FIXNUM);223224switch (FIX2INT(_stop_bits)) {225case 1:226dcb.StopBits = ONESTOPBIT;227break;228case 2:229dcb.StopBits = TWOSTOPBITS;230break;231default:232rb_raise(rb_eArgError, "unknown number of stop bits");233break;234}235SkipStopBits:236237if (!use_hash)238_parity = (argc >= 4 ? argv[3] : (dcb.ByteSize == 8 ?239INT2FIX(NOPARITY) : INT2FIX(EVENPARITY)));240if (NIL_P(_parity))241goto SkipParity;242Check_Type(_parity, T_FIXNUM);243244parity = FIX2INT(_parity);245switch (parity) {246case EVENPARITY:247case ODDPARITY:248case MARKPARITY:249case SPACEPARITY:250case NOPARITY:251dcb.Parity = parity;252break;253254default:255rb_raise(rb_eArgError, "unknown parity");256break;257}258SkipParity:259260if (SetCommState(fh, &dcb) == 0)261rb_sys_fail(sSetCommState);262return self;263}264265static void get_modem_params(self, mp)266VALUE self;267struct modem_params *mp;268{269HANDLE fh;270DCB dcb;271272fh = sp_get_handle(self);273dcb.DCBlength = sizeof(dcb);274if (GetCommState(fh, &dcb) == 0)275rb_sys_fail(sGetCommState);276277mp->data_rate = dcb.BaudRate;278mp->data_bits = dcb.ByteSize;279mp->stop_bits = (dcb.StopBits == ONESTOPBIT ? 1 : 2);280mp->parity = dcb.Parity;281}282283static VALUE sp_set_flow_control(self, val)284VALUE self, val;285{286HANDLE fh;287int flowc;288DCB dcb;289290Check_Type(val, T_FIXNUM);291292fh = sp_get_handle(self);293dcb.DCBlength = sizeof(dcb);294if (GetCommState(fh, &dcb) == 0)295rb_sys_fail(sGetCommState);296297flowc = FIX2INT(val);298if (flowc & HARD) {299dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;300dcb.fOutxCtsFlow = TRUE;301} else {302dcb.fRtsControl = RTS_CONTROL_ENABLE;303dcb.fOutxCtsFlow = FALSE;304}305if (flowc & SOFT)306dcb.fOutX = dcb.fInX = TRUE;307else308dcb.fOutX = dcb.fInX = FALSE;309310if (SetCommState(fh, &dcb) == 0)311rb_sys_fail(sSetCommState);312return self;313}314315static VALUE sp_get_flow_control(self)316VALUE self;317{318HANDLE fh;319int ret;320DCB dcb;321322fh = sp_get_handle(self);323dcb.DCBlength = sizeof(dcb);324if (GetCommState(fh, &dcb) == 0)325rb_sys_fail(sGetCommState);326327ret = 0;328if (dcb.fOutxCtsFlow)329ret += HARD;330if (dcb.fOutX)331ret += SOFT;332333return INT2FIX(ret);334}335336static VALUE sp_set_input_type(self, val)337{338rb_notimplement();339return self;340}341342static VALUE sp_get_input_type(self)343{344rb_notimplement();345return self;346}347348static VALUE sp_set_output_type(self, val)349{350rb_notimplement();351return self;352}353354static VALUE sp_get_output_type(self)355{356rb_notimplement();357return self;358}359360static VALUE sp_set_nonblock(self, val)361{362rb_notimplement();363return self;364}365366static VALUE sp_get_nonblock(self)367{368rb_notimplement();369return self;370}371372static VALUE sp_set_read_timeout(self, val)373VALUE self, val;374{375int timeout;376HANDLE fh;377COMMTIMEOUTS ctout;378379Check_Type(val, T_FIXNUM);380timeout = FIX2INT(val);381382fh = sp_get_handle(self);383if (GetCommTimeouts(fh, &ctout) == 0)384rb_sys_fail(sGetCommTimeouts);385386if (timeout < 0) {387ctout.ReadIntervalTimeout = MAXDWORD;388ctout.ReadTotalTimeoutMultiplier = 0;389ctout.ReadTotalTimeoutConstant = 0;390} else if (timeout == 0) {391ctout.ReadIntervalTimeout = MAXDWORD;392ctout.ReadTotalTimeoutMultiplier = MAXDWORD;393ctout.ReadTotalTimeoutConstant = MAXDWORD - 1;394} else {395ctout.ReadIntervalTimeout = timeout;396ctout.ReadTotalTimeoutMultiplier = 0;397ctout.ReadTotalTimeoutConstant = timeout;398}399400if (SetCommTimeouts(fh, &ctout) == 0)401rb_sys_fail(sSetCommTimeouts);402return self;403}404405static VALUE sp_get_read_timeout(self)406VALUE self;407{408HANDLE fh;409COMMTIMEOUTS ctout;410411fh = sp_get_handle(self);412if (GetCommTimeouts(fh, &ctout) == 0)413rb_sys_fail(sGetCommTimeouts);414switch (ctout.ReadTotalTimeoutConstant) {415case 0:416return INT2FIX(-1);417case MAXDWORD:418return INT2FIX(0);419}420return INT2FIX(ctout.ReadTotalTimeoutConstant);421}422423static VALUE sp_set_write_timeout(self, val)424VALUE self, val;425{426int timeout;427HANDLE fh;428COMMTIMEOUTS ctout;429430Check_Type(val, T_FIXNUM);431timeout = FIX2INT(val);432433fh = sp_get_handle(self);434if (GetCommTimeouts(fh, &ctout) == 0)435rb_sys_fail(sGetCommTimeouts);436437if (timeout <= 0) {438ctout.WriteTotalTimeoutMultiplier = 0;439ctout.WriteTotalTimeoutConstant = 0;440} else {441ctout.WriteTotalTimeoutMultiplier = timeout;442ctout.WriteTotalTimeoutConstant = 0;443}444445if (SetCommTimeouts(fh, &ctout) == 0)446rb_sys_fail(sSetCommTimeouts);447return self;448}449450static VALUE sp_get_write_timeout(self)451VALUE self;452{453HANDLE fh;454COMMTIMEOUTS ctout;455456fh = sp_get_handle(self);457if (GetCommTimeouts(fh, &ctout) == 0)458rb_sys_fail(sGetCommTimeouts);459return INT2FIX(ctout.WriteTotalTimeoutMultiplier);460}461462static void delay_ms(time)463int time;464{465HANDLE ev;466467ev = CreateEvent(NULL, FALSE, FALSE, NULL);468if (!ev)469rb_sys_fail("CreateEvent");470if (WaitForSingleObject(ev, time) == WAIT_FAILED)471rb_sys_fail("WaitForSingleObject");472CloseHandle(ev);473}474475static VALUE sp_break(self, time)476VALUE self, time;477{478HANDLE fh;479480Check_Type(time, T_FIXNUM);481482fh = sp_get_handle(self);483if (SetCommBreak(fh) == 0)484rb_sys_fail("SetCommBreak");485delay_ms(FIX2INT(time) * 100);486ClearCommBreak(fh);487return Qnil;488}489490static void get_line_signals(obj, ls)491VALUE obj;492struct line_signals *ls;493{494HANDLE fh;495int status;496497fh = sp_get_handle(obj);498if (GetCommModemStatus(fh, &status) == 0)499rb_sys_fail("GetCommModemStatus");500501ls->cts = (status & MS_CTS_ON ? 1 : 0);502ls->dsr = (status & MS_DSR_ON ? 1 : 0);503ls->dcd = (status & MS_RLSD_ON ? 1 : 0);504ls->ri = (status & MS_RING_ON ? 1 : 0);505}506507static VALUE set_signal(obj, val, sigoff, sigon)508VALUE obj,val;509int sigoff, sigon;510{511HANDLE fh;512int set, sig;513514Check_Type(val, T_FIXNUM);515fh = sp_get_handle(obj);516517set = FIX2INT(val);518if (set == 0)519sig = sigoff;520else if (set == 1)521sig = sigon;522else523rb_raise(rb_eArgError, "invalid value");524525if (EscapeCommFunction(fh, sig) == 0)526rb_sys_fail("EscapeCommFunction");527return obj;528}529530static VALUE sp_set_rts(self, val)531VALUE self, val;532{533return set_signal(self, val, CLRRTS, SETRTS);534}535536static VALUE sp_set_dtr(self, val)537VALUE self, val;538{539return set_signal(self, val, CLRDTR, SETDTR);540}541542static VALUE sp_get_rts(self)543VALUE self;544{545rb_notimplement();546return self;547}548549static VALUE sp_get_dtr(self)550VALUE self;551{552rb_notimplement();553return self;554}555556557#else /* defined(mswin) || defined(bccwin) */558559560#include <stdio.h> /* Standard input/output definitions */561#include <unistd.h> /* UNIX standard function definitions */562#include <fcntl.h> /* File control definitions */563#include <errno.h> /* Error number definitions */564#include <termios.h> /* POSIX terminal control definitions */565#include <sys/ioctl.h>566567#ifdef CRTSCTS568#define HAVE_FLOWCONTROL_HARD 1569#else570#undef HAVE_FLOWCONTROL_HARD571#endif572573#define NONE 0574#define HARD 1575#define SOFT 2576577#define SPACE 0578#define MARK 0579#define EVEN 1580#define ODD 2581582#define PROCESSED 1583#define RAW 2584585static char sTcgetattr[] = "tcgetattr";586static char sTcsetattr[] = "tcsetattr";587static char sIoctl[] = "ioctl";588static char sFcntl[] = "fcntl";589590591static int sp_get_fd(obj)592VALUE obj;593{594OpenFile *fptr;595596GetOpenFile(obj, fptr);597return (fileno(fptr->f));598}599600static VALUE sp_create(class, _port)601VALUE class, _port;602{603OpenFile *fp;604int fd;605int num_port;606char *port;607char *ports[] = {608#if defined(linux) || defined(cygwin)609"/dev/ttyS0", "/dev/ttyS1", "/dev/ttyS2", "/dev/ttyS3",610"/dev/ttyS4", "/dev/ttyS5", "/dev/ttyS6", "/dev/ttyS7"611#elif defined(freebsd) || defined(netbsd) || defined(openbsd)612"/dev/cuaa0", "/dev/cuaa1", "/dev/cuaa2", "/dev/cuaa3",613"/dev/cuaa4", "/dev/cuaa5", "/dev/cuaa6", "/dev/cuaa7"614#elif defined(solaris)615"/dev/ttya", "/dev/ttyb", "/dev/ttyc", "/dev/ttyd",616"/dev/ttye", "/dev/ttyf", "/dev/ttyg", "/dev/ttyh"617#elif defined(aix)618"/dev/tty0", "/dev/tty1", "/dev/tty2", "/dev/tty3",619"/dev/tty4", "/dev/tty5", "/dev/tty6", "/dev/tty7"620#elif defined(irix)621"/dev/ttyf1", "/dev/ttyf2", "/dev/ttyf3", "/dev/ttyf4",622"/dev/ttyf5", "/dev/ttyf6", "/dev/ttyf7", "/dev/ttyf8"623#endif624};625struct termios params;626627NEWOBJ(sp, struct RFile);628rb_secure(4);629OBJSETUP(sp, class, T_FILE);630MakeOpenFile((VALUE)sp, fp);631632switch(TYPE(_port)) {633case T_FIXNUM:634num_port = FIX2INT(_port);635if (num_port < 0 || num_port > sizeof(ports) / sizeof(ports[0]))636rb_raise(rb_eArgError, "illegal port number");637port = ports[num_port];638break;639640case T_STRING:641Check_SafeStr(_port);642port = RSTRING(_port)->ptr;643break;644645default:646rb_raise(rb_eTypeError, "wrong argument type");647break;648}649650fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY);651if (fd == -1)652rb_sys_fail(port);653if (!isatty(fd)) {654close(fd);655rb_raise(rb_eArgError, "not a serial port");656}657658if (tcgetattr(fd, ¶ms) == -1) {659close(fd);660rb_sys_fail(sTcgetattr);661}662params.c_oflag = 0;663params.c_lflag = 0;664params.c_iflag &= (IXON | IXOFF | IXANY);665params.c_cflag |= CLOCAL | CREAD;666params.c_cflag &= ~HUPCL;667if (tcsetattr(fd, TCSANOW, ¶ms) == -1) {668close(fd);669rb_sys_fail(sTcsetattr);670}671672fp->f = rb_fdopen(fd, "r+");673fp->mode = FMODE_READWRITE | FMODE_SYNC;674return (VALUE) sp;675}676677static VALUE sp_set_modem_params(argc, argv, self)678int argc;679VALUE *argv, self;680{681int fd;682struct termios params;683VALUE _data_rate = 0, _data_bits = 0, _parity = NONE, _stop_bits = 0;684int use_hash = 0;685int data_rate, data_bits;686687if (argc == 0)688return self;689if (argc == 1 && T_HASH == TYPE(argv[0])) {690use_hash = 1;691_data_rate = rb_hash_aref(argv[0], sBaud);692_data_bits = rb_hash_aref(argv[0], sDataBits);693_stop_bits = rb_hash_aref(argv[0], sStopBits);694_parity = rb_hash_aref(argv[0], sParity);695}696697fd = sp_get_fd(self);698if (tcgetattr(fd, ¶ms) == -1)699rb_sys_fail(sTcgetattr);700701if (!use_hash)702_data_rate = argv[0];703if (NIL_P(_data_rate))704goto SkipDataRate;705Check_Type(_data_rate, T_FIXNUM);706707switch(FIX2INT(_data_rate)) {708case 50: data_rate = B50; break;709case 75: data_rate = B75; break;710case 110: data_rate = B110; break;711case 134: data_rate = B134; break;712case 150: data_rate = B150; break;713case 200: data_rate = B200; break;714case 300: data_rate = B300; break;715case 600: data_rate = B600; break;716case 1200: data_rate = B1200; break;717case 1800: data_rate = B1800; break;718case 2400: data_rate = B2400; break;719case 4800: data_rate = B4800; break;720case 9600: data_rate = B9600; break;721case 19200: data_rate = B19200; break;722case 38400: data_rate = B38400; break;723#ifdef B57600724case 57600: data_rate = B57600; break;725#endif726#ifdef B76800727case 76800: data_rate = B76800; break;728#endif729#ifdef B115200730case 115200: data_rate = B115200; break;731#endif732#ifdef B230400733case 230400: data_rate = B230400; break;734#endif735736default:737rb_raise(rb_eArgError, "unknown baud rate");738break;739}740cfsetispeed(¶ms, data_rate);741cfsetospeed(¶ms, data_rate);742SkipDataRate:743744if (!use_hash)745_data_bits = (argc >= 2 ? argv[1] : INT2FIX(8));746if (NIL_P(_data_bits))747goto SkipDataBits;748Check_Type(_data_bits, T_FIXNUM);749750switch(FIX2INT(_data_bits)) {751case 5:752data_bits = CS5;753break;754case 6:755data_bits = CS6;756break;757case 7:758data_bits = CS7;759break;760case 8:761data_bits = CS8;762break;763default:764rb_raise(rb_eArgError, "unknown character size");765break;766}767params.c_cflag &= ~CSIZE;768params.c_cflag |= data_bits;769SkipDataBits:770771if (!use_hash)772_stop_bits = (argc >= 3 ? argv[2] : INT2FIX(1));773if (NIL_P(_stop_bits))774goto SkipStopBits;775Check_Type(_stop_bits, T_FIXNUM);776777switch(FIX2INT(_stop_bits)) {778case 1:779params.c_cflag &= ~CSTOPB;780break;781case 2:782params.c_cflag |= CSTOPB;783break;784default:785rb_raise(rb_eArgError, "unknown number of stop bits");786break;787}788SkipStopBits:789790if (!use_hash)791_parity = (argc >= 4 ? argv[3] : ((params.c_cflag & CSIZE) == CS8 ?792INT2FIX(NONE) : INT2FIX(EVEN)));793if (NIL_P(_parity))794goto SkipParity;795Check_Type(_parity, T_FIXNUM);796797switch(FIX2INT(_parity)) {798case EVEN:799params.c_cflag |= PARENB;800params.c_cflag &= ~PARODD;801break;802803case ODD:804params.c_cflag |= PARENB;805params.c_cflag |= PARODD;806break;807808case NONE:809params.c_cflag &= ~PARENB;810break;811812default:813rb_raise(rb_eArgError, "unknown parity");814break;815}816SkipParity:817818if (tcsetattr(fd, TCSANOW, ¶ms) == -1)819rb_sys_fail(sTcsetattr);820return self;821}822823static void get_modem_params(self, mp)824VALUE self;825struct modem_params *mp;826{827int fd;828struct termios params;829830fd = sp_get_fd(self);831if (tcgetattr(fd, ¶ms) == -1)832rb_sys_fail(sTcgetattr);833834switch (cfgetospeed(¶ms)) {835case B50: mp->data_rate = 50; break;836case B75: mp->data_rate = 75; break;837case B110: mp->data_rate = 110; break;838case B134: mp->data_rate = 134; break;839case B150: mp->data_rate = 150; break;840case B200: mp->data_rate = 200; break;841case B300: mp->data_rate = 300; break;842case B600: mp->data_rate = 600; break;843case B1200: mp->data_rate = 1200; break;844case B1800: mp->data_rate = 1800; break;845case B2400: mp->data_rate = 2400; break;846case B4800: mp->data_rate = 4800; break;847case B9600: mp->data_rate = 9600; break;848case B19200: mp->data_rate = 19200; break;849case B38400: mp->data_rate = 38400; break;850#ifdef B57600851case B57600: mp->data_rate = 57600; break;852#endif853#ifdef B76800854case B76800: mp->data_rate = 76800; break;855#endif856#ifdef B115200857case B115200: mp->data_rate = 115200; break;858#endif859#ifdef B230400860case B230400: mp->data_rate = 230400; break;861#endif862}863864switch(params.c_cflag & CSIZE) {865case CS5:866mp->data_bits = 5;867break;868case CS6:869mp->data_bits = 6;870break;871case CS7:872mp->data_bits = 7;873break;874case CS8:875mp->data_bits = 8;876break;877default:878mp->data_bits = 0;879break;880}881882mp->stop_bits = (params.c_cflag & CSTOPB ? 2 : 1);883884if (!(params.c_cflag & PARENB))885mp->parity = NONE;886else if (params.c_cflag & PARODD)887mp->parity = ODD;888else889mp->parity = EVEN;890}891892static VALUE sp_set_flow_control(self, val)893VALUE self, val;894{895int fd;896int flowc;897struct termios params;898899Check_Type(val, T_FIXNUM);900901fd = sp_get_fd(self);902if (tcgetattr(fd, ¶ms) == -1)903rb_sys_fail(sTcgetattr);904905flowc = FIX2INT(val);906if (flowc & HARD)907#ifdef HAVE_FLOWCONTROL_HARD908params.c_cflag |= CRTSCTS;909else910params.c_cflag &= ~CRTSCTS;911#else912rb_raise(rb_eIOError, "Hardware flow control not supported");913#endif914if (flowc & SOFT)915params.c_iflag |= (IXON | IXOFF | IXANY);916else917params.c_iflag &= ~(IXON | IXOFF | IXANY);918919if (tcsetattr(fd, TCSANOW, ¶ms) == -1)920rb_sys_fail(sTcsetattr);921return self;922}923924static VALUE sp_get_flow_control(self)925VALUE self;926{927int ret;928int fd;929struct termios params;930931fd = sp_get_fd(self);932if (tcgetattr(fd, ¶ms) == -1)933rb_sys_fail(sTcgetattr);934935ret = 0;936#ifdef HAVE_FLOWCONTROL_HARD937if (params.c_cflag & CRTSCTS)938ret += HARD;939#endif940if (params.c_iflag & (IXON | IXOFF | IXANY))941ret += SOFT;942943return INT2FIX(ret);944}945946static VALUE sp_set_input_type(self, val)947VALUE self, val;948{949int fd;950int type;951struct termios params;952953Check_Type(val, T_FIXNUM);954955fd = sp_get_fd(self);956if (tcgetattr(fd, ¶ms) == -1)957rb_sys_fail(sTcgetattr);958959type = FIX2INT(val);960if (type == PROCESSED)961params.c_lflag |= ICANON;962else963params.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);964965if (tcsetattr(fd, TCSANOW, ¶ms) == -1)966rb_sys_fail(sTcsetattr);967968return self;969}970971static VALUE sp_get_input_type(self)972VALUE self;973{974int ret;975int fd;976struct termios params;977978fd = sp_get_fd(self);979if (tcgetattr(fd, ¶ms) == -1)980rb_sys_fail(sTcgetattr);981982ret = 0;983if (params.c_lflag & ICANON)984ret = PROCESSED;985else986ret = RAW;987988return INT2FIX(ret);989}990991static VALUE sp_set_output_type(self, val)992VALUE self, val;993{994int fd;995int type;996struct termios params;997998Check_Type(val, T_FIXNUM);9991000fd = sp_get_fd(self);1001if (tcgetattr(fd, ¶ms) == -1)1002rb_sys_fail(sTcgetattr);10031004type = FIX2INT(val);1005if (type == PROCESSED)1006params.c_oflag |= OPOST;1007else1008params.c_oflag &= ~OPOST;10091010if (tcsetattr(fd, TCSANOW, ¶ms) == -1)1011rb_sys_fail(sTcsetattr);10121013return self;1014}10151016static VALUE sp_get_output_type(self)1017VALUE self;1018{1019int ret;1020int fd;1021struct termios params;10221023fd = sp_get_fd(self);1024if (tcgetattr(fd, ¶ms) == -1)1025rb_sys_fail(sTcgetattr);10261027ret = 0;1028if (params.c_oflag & OPOST)1029ret = PROCESSED;1030else1031ret = RAW;10321033return INT2FIX(ret);1034}10351036static VALUE sp_set_nonblock(self, val)1037VALUE self, val;1038{1039int fd;1040int flags;10411042fd = sp_get_fd(self);10431044flags = fcntl(fd, F_GETFL, 0);1045if(flags == -1)1046rb_sys_fail(sFcntl);10471048if (val == Qtrue) {1049if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)1050rb_sys_fail(sFcntl);1051}1052else if (val == Qfalse) {1053if(fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) == -1)1054rb_sys_fail(sFcntl);1055}1056else1057rb_raise(rb_eArgError, "invalid value");10581059return self;1060}10611062static VALUE sp_get_nonblock(self)1063VALUE self;1064{1065int fd;1066int flags;10671068fd = sp_get_fd(self);1069flags = fcntl(fd, F_GETFL, 0);1070if(flags == -1)1071rb_sys_fail(sFcntl);10721073return (flags & O_NONBLOCK) ? Qtrue : Qfalse;1074}10751076static VALUE sp_set_read_timeout(self, val)1077VALUE self, val;1078{1079int timeout;1080int fd;1081struct termios params;10821083Check_Type(val, T_FIXNUM);1084timeout = FIX2INT(val);10851086fd = sp_get_fd(self);1087if (tcgetattr(fd, ¶ms) == -1)1088rb_sys_fail(sTcgetattr);10891090if (timeout < 0) {1091params.c_cc[VTIME] = 0;1092params.c_cc[VMIN] = 0;1093} else if (timeout == 0) {1094params.c_cc[VTIME] = 0;1095params.c_cc[VMIN] = 1;1096} else {1097params.c_cc[VTIME] = (timeout + 50) / 100;1098params.c_cc[VMIN] = 0;1099}11001101if (tcsetattr(fd, TCSANOW, ¶ms) == -1)1102rb_sys_fail(sTcsetattr);1103return self;1104}11051106static VALUE sp_get_read_timeout(self)1107VALUE self;1108{1109int fd;1110struct termios params;11111112fd = sp_get_fd(self);1113if (tcgetattr(fd, ¶ms) == -1)1114rb_sys_fail(sTcgetattr);1115if (params.c_cc[VTIME] == 0 && params.c_cc[VMIN] == 0)1116return INT2FIX(-1);1117return INT2FIX(params.c_cc[VTIME] * 100);1118}11191120static VALUE sp_set_write_timeout(self, val)1121VALUE self, val;1122{1123rb_notimplement();1124return self;1125}11261127static VALUE sp_get_write_timeout(self)1128VALUE self;1129{1130rb_notimplement();1131return self;1132}11331134static VALUE sp_break(self, time)1135VALUE self, time;1136{1137int fd;11381139Check_Type(time, T_FIXNUM);11401141fd = sp_get_fd(self);1142if (tcsendbreak(fd, FIX2INT(time) / 3) == -1)1143rb_sys_fail("tcsendbreak");1144return Qnil;1145}11461147static void get_line_signals(obj, ls)1148VALUE obj;1149struct line_signals *ls;1150{1151int fd, status;11521153fd = sp_get_fd(obj);1154if (ioctl(fd, TIOCMGET, &status) == -1)1155rb_sys_fail(sIoctl);11561157ls->rts = (status & TIOCM_RTS ? 1 : 0);1158ls->dtr = (status & TIOCM_DTR ? 1 : 0);1159ls->cts = (status & TIOCM_CTS ? 1 : 0);1160ls->dsr = (status & TIOCM_DSR ? 1 : 0);1161ls->dcd = (status & TIOCM_CD ? 1 : 0);1162ls->ri = (status & TIOCM_RI ? 1 : 0);1163}11641165static VALUE set_signal(obj, val, sig)1166VALUE obj,val;1167int sig;1168{1169int status;1170int fd;1171int set;11721173Check_Type(val, T_FIXNUM);1174fd = sp_get_fd(obj);1175if (ioctl(fd, TIOCMGET, &status) == -1)1176rb_sys_fail(sIoctl);11771178set = FIX2INT(val);1179if (set == 0)1180status &= ~sig;1181else if (set == 1)1182status |= sig;1183else1184rb_raise(rb_eArgError, "invalid value");11851186if (ioctl(fd, TIOCMSET, &status) == -1)1187rb_sys_fail(sIoctl);1188return obj;1189}11901191static VALUE sp_set_rts(self, val)1192VALUE self, val;1193{1194return set_signal(self, val, TIOCM_RTS);1195}11961197static VALUE sp_set_dtr(self, val)1198VALUE self, val;1199{1200return set_signal(self, val, TIOCM_DTR);1201}12021203static VALUE sp_get_rts(self)1204VALUE self;1205{1206struct line_signals ls;12071208get_line_signals(self, &ls);1209return INT2FIX(ls.rts);1210}12111212static VALUE sp_get_dtr(self)1213VALUE self;1214{1215struct line_signals ls;12161217get_line_signals(self, &ls);1218return INT2FIX(ls.dtr);1219}122012211222#endif /* defined(mswin) || defined(bccwin) */122312241225static VALUE sp_set_data_rate(self, data_rate)1226VALUE self, data_rate;1227{1228VALUE argv[4];12291230argv[0] = data_rate;1231argv[1] = argv[2] = argv[3] = Qnil;1232return sp_set_modem_params(4, argv, self);1233}12341235static VALUE sp_set_data_bits(self, data_bits)1236VALUE self, data_bits;1237{1238VALUE argv[4];12391240argv[1] = data_bits;1241argv[0] = argv[2] = argv[3] = Qnil;1242return sp_set_modem_params(4, argv, self);1243}12441245static VALUE sp_set_stop_bits(self, stop_bits)1246VALUE self, stop_bits;1247{1248VALUE argv[4];12491250argv[2] = stop_bits;1251argv[0] = argv[1] = argv[3] = Qnil;1252return sp_set_modem_params(4, argv, self);1253}12541255static VALUE sp_set_parity(self, parity)1256VALUE self, parity;1257{1258VALUE argv[4];12591260argv[3] = parity;1261argv[0] = argv[1] = argv[2] = Qnil;1262return sp_set_modem_params(4, argv, self);1263}12641265static VALUE sp_get_data_rate(self)1266VALUE self;1267{1268struct modem_params mp;12691270get_modem_params(self, &mp);1271return INT2FIX(mp.data_rate);1272}12731274static VALUE sp_get_data_bits(self)1275VALUE self;1276{1277struct modem_params mp;12781279get_modem_params(self, &mp);1280return INT2FIX(mp.data_bits);1281}12821283static VALUE sp_get_stop_bits(self)1284VALUE self;1285{1286struct modem_params mp;12871288get_modem_params(self, &mp);1289return INT2FIX(mp.stop_bits);1290}12911292static VALUE sp_get_parity(self)1293VALUE self;1294{1295struct modem_params mp;12961297get_modem_params(self, &mp);1298return INT2FIX(mp.parity);1299}13001301static VALUE sp_get_modem_params(self)1302VALUE self;1303{1304struct modem_params mp;1305VALUE hash;13061307get_modem_params(self, &mp);1308hash = rb_hash_new();1309rb_hash_aset(hash, sBaud, INT2FIX(mp.data_rate));1310rb_hash_aset(hash, sDataBits, INT2FIX(mp.data_bits));1311rb_hash_aset(hash, sStopBits, INT2FIX(mp.stop_bits));1312rb_hash_aset(hash, sParity, INT2FIX(mp.parity));1313return hash;1314}13151316static VALUE sp_get_cts(self)1317VALUE self;1318{1319struct line_signals ls;13201321get_line_signals(self, &ls);1322return INT2FIX(ls.cts);1323}13241325static VALUE sp_get_dsr(self)1326VALUE self;1327{1328struct line_signals ls;13291330get_line_signals(self, &ls);1331return INT2FIX(ls.dsr);1332}13331334static VALUE sp_get_dcd(self)1335VALUE self;1336{1337struct line_signals ls;13381339get_line_signals(self, &ls);1340return INT2FIX(ls.dcd);1341}13421343static VALUE sp_get_ri(self)1344VALUE self;1345{1346struct line_signals ls;13471348get_line_signals(self, &ls);1349return INT2FIX(ls.ri);1350}13511352static VALUE1353sp_signals(self)1354VALUE self;1355{1356struct line_signals ls;1357VALUE hash;13581359get_line_signals(self, &ls);1360hash = rb_hash_new();1361#if !(defined(mswin) || defined(bccwin))1362rb_hash_aset(hash, sRts, INT2FIX(ls.rts));1363rb_hash_aset(hash, sDtr, INT2FIX(ls.dtr));1364#endif1365rb_hash_aset(hash, sCts, INT2FIX(ls.cts));1366rb_hash_aset(hash, sDsr, INT2FIX(ls.dsr));1367rb_hash_aset(hash, sDcd, INT2FIX(ls.dcd));1368rb_hash_aset(hash, sRi, INT2FIX(ls.ri));1369return hash;1370}13711372void Init_serialport() {1373sBaud = rb_str_new2("baud");1374sDataBits = rb_str_new2("data_bits");1375sStopBits = rb_str_new2("stop_bits");1376sParity = rb_str_new2("parity");1377sRts = rb_str_new2("rts");1378sDtr = rb_str_new2("dtr");1379sCts = rb_str_new2("cts");1380sDsr = rb_str_new2("dsr");1381sDcd = rb_str_new2("dcd");1382sRi = rb_str_new2("ri");13831384rb_gc_register_address(&sBaud);1385rb_gc_register_address(&sDataBits);1386rb_gc_register_address(&sStopBits);1387rb_gc_register_address(&sParity);1388rb_gc_register_address(&sRts);1389rb_gc_register_address(&sDtr);1390rb_gc_register_address(&sCts);1391rb_gc_register_address(&sDsr);1392rb_gc_register_address(&sDcd);1393rb_gc_register_address(&sRi);13941395cSerialPort = rb_define_class("SerialPort", rb_cIO);1396rb_define_singleton_method(cSerialPort, "create", sp_create, 1);13971398rb_define_method(cSerialPort, "get_modem_params", sp_get_modem_params, 0);1399rb_define_method(cSerialPort, "set_modem_params", sp_set_modem_params, -1);1400rb_define_method(cSerialPort, "modem_params", sp_get_modem_params, 0);1401rb_define_method(cSerialPort, "modem_params=", sp_set_modem_params, -1);1402rb_define_method(cSerialPort, "baud", sp_get_data_rate, 0);1403rb_define_method(cSerialPort, "baud=", sp_set_data_rate, 1);1404rb_define_method(cSerialPort, "data_bits", sp_get_data_bits, 0);1405rb_define_method(cSerialPort, "data_bits=", sp_set_data_bits, 1);1406rb_define_method(cSerialPort, "stop_bits", sp_get_stop_bits, 0);1407rb_define_method(cSerialPort, "stop_bits=", sp_set_stop_bits, 1);1408rb_define_method(cSerialPort, "parity", sp_get_parity, 0);1409rb_define_method(cSerialPort, "parity=", sp_set_parity, 1);14101411rb_define_method(cSerialPort, "flow_control=", sp_set_flow_control, 1);1412rb_define_method(cSerialPort, "flow_control", sp_get_flow_control, 0);1413rb_define_method(cSerialPort, "input_type=", sp_set_input_type, 1);1414rb_define_method(cSerialPort, "input_type", sp_get_input_type, 0);1415rb_define_method(cSerialPort, "output_type=", sp_set_output_type, 1);1416rb_define_method(cSerialPort, "output_type", sp_get_output_type, 0);14171418rb_define_method(cSerialPort, "nonblock=", sp_set_nonblock, 1);1419rb_define_method(cSerialPort, "nonblock", sp_get_nonblock, 0);14201421rb_define_method(cSerialPort, "read_timeout", sp_get_read_timeout, 0);1422rb_define_method(cSerialPort, "read_timeout=", sp_set_read_timeout, 1);1423rb_define_method(cSerialPort, "write_timeout", sp_get_write_timeout, 0);1424rb_define_method(cSerialPort, "write_timeout=", sp_set_write_timeout, 1);14251426rb_define_method(cSerialPort, "break", sp_break, 1);14271428rb_define_method(cSerialPort, "signals", sp_signals, 0);1429rb_define_method(cSerialPort, "get_signals", sp_signals, 0);1430rb_define_method(cSerialPort, "rts", sp_get_rts, 0);1431rb_define_method(cSerialPort, "rts=", sp_set_rts, 1);1432rb_define_method(cSerialPort, "dtr", sp_get_dtr, 0);1433rb_define_method(cSerialPort, "dtr=", sp_set_dtr, 1);1434rb_define_method(cSerialPort, "cts", sp_get_cts, 0);1435rb_define_method(cSerialPort, "dsr", sp_get_dsr, 0);1436rb_define_method(cSerialPort, "dcd", sp_get_dcd, 0);1437rb_define_method(cSerialPort, "ri", sp_get_ri, 0);14381439rb_define_const(cSerialPort, "NONE", INT2FIX(NONE));1440rb_define_const(cSerialPort, "HARD", INT2FIX(HARD));1441rb_define_const(cSerialPort, "SOFT", INT2FIX(SOFT));14421443rb_define_const(cSerialPort, "SPACE", INT2FIX(SPACE));1444rb_define_const(cSerialPort, "MARK", INT2FIX(MARK));1445rb_define_const(cSerialPort, "EVEN", INT2FIX(EVEN));1446rb_define_const(cSerialPort, "ODD", INT2FIX(ODD));14471448rb_define_const(cSerialPort, "PROCESSED", INT2FIX(PROCESSED));1449rb_define_const(cSerialPort, "RAW", INT2FIX(RAW));14501451rb_define_const(cSerialPort, "VERSION", rb_str_new2(VERSION));14521453/* The following definitions are more easily carried out in Ruby */1454rb_eval_string(1455"class SerialPort\n"14561457"def self.new(port, *params)\n"1458"sp = create(port)\n"1459"begin\n"1460"sp.set_modem_params(*params)\n"1461"rescue\n"1462"sp.close\n"1463"raise\n"1464"end\n"1465"return sp\n"1466"end\n"14671468"def self.open(port, *params)\n"1469"sp = create(port)\n"1470"begin\n"1471"sp.set_modem_params(*params)\n"1472"if (block_given?)\n"1473"yield sp\n"1474"sp.close\n"1475"return nil\n"1476"end\n"1477"rescue\n"1478"sp.close\n"1479"raise\n"1480"end\n"1481"return sp\n"1482"end\n"14831484"end\n"1485);1486}148714881489