3 Copyright (c) 2006 stefan kersten.
5 ====================================================================
7 SuperCollider real time audio synthesis system
8 Copyright (c) 2002 James McCartney. All rights reserved.
9 http://www.audiosynth.com
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
32 #include <sys/ioctl.h>
33 #include <sys/select.h>
36 #include <boost/atomic.hpp>
42 #include "PyrKernel.h"
43 #include "PyrPrimitive.h"
44 #include "SC_LanguageClient.h"
80 static const int kNumOptions
= 7;
81 static const int kBufferSize
= 8192;
82 static const int kReadTimeoutMs
= 1000;
84 typedef SC_FIFO
<uint8_t,kBufferSize
> FIFO
;
86 struct Error
: std::runtime_error
88 explicit Error(const char* what
)
89 : std::runtime_error(what
)
93 struct SysError
: public Error
95 explicit SysError(int e
=errno
)
100 static PyrSymbol
* s_dataAvailable
;
101 static PyrSymbol
* s_doneAction
;
104 SerialPort(PyrObject
* obj
, const char* serialport
, const Options
& options
);
107 bool isRunning() const { return m_running
; }
108 int fd() const { return m_fd
; }
109 const Options
& options() const { return m_options
; }
111 bool put(uint8_t byte
);
112 bool get(uint8_t* byte
);
119 static void* threadFunc(void*);
122 void dataAvailable();
126 // language interface
129 boost::atomic
<bool> m_dodone
;
134 boost::atomic
<bool> m_open
;
135 struct termios m_termio
;
136 struct termios m_oldtermio
;
141 uint8_t m_rxbuffer
[kBufferSize
];
144 boost::atomic
<bool> m_running
;
148 PyrSymbol
* SerialPort::s_dataAvailable
= 0;
149 PyrSymbol
* SerialPort::s_doneAction
= 0;
151 SerialPort::SerialPort(PyrObject
* obj
, const char* serialport
, const Options
& options
)
157 m_fd
= open(serialport
, O_RDWR
| O_NOCTTY
| O_NDELAY
);
159 throw SysError(errno
);
163 #if defined(TIOCEXCL)
164 if (m_options
.exclusive
) {
165 if (ioctl(m_fd
, TIOCEXCL
) == -1) {
166 throw SysError(errno
);
171 if (fcntl(m_fd
, F_SETFL
, O_NONBLOCK
) == -1) {
177 // initialize serial connection
179 // get current settings and remember them
180 struct termios toptions
;
181 if (tcgetattr(m_fd
, &toptions
) < 0) {
186 memcpy(&m_oldtermio
, &toptions
, sizeof(toptions
));
190 switch (m_options
.baudrate
) {
212 // #ifndef _POSIX_C_SOURCE
248 // #endif // !_POSIX_C_SOURCE
251 throw Error("unsupported baudrate");
254 cfsetispeed(&toptions
, brate
);
255 cfsetospeed(&toptions
, brate
);
258 toptions
.c_cflag
&= ~CSIZE
;
259 switch (m_options
.databits
)
262 toptions
.c_cflag
|= CS5
;
265 toptions
.c_cflag
|= CS6
;
268 toptions
.c_cflag
|= CS7
;
271 m_options
.databits
= 8;
272 toptions
.c_cflag
|= CS8
;
277 if (m_options
.stopbit
) {
278 toptions
.c_cflag
|= CSTOPB
;
280 toptions
.c_cflag
&= ~CSTOPB
;
284 switch (m_options
.parity
)
287 toptions
.c_cflag
&= ~PARENB
;
290 toptions
.c_cflag
|= PARENB
;
291 toptions
.c_cflag
&= ~PARODD
;
294 toptions
.c_cflag
|= (PARENB
| PARODD
);
299 #if !defined(_POSIX_C_SOURCE) || defined(__USE_MISC)
300 if (m_options
.crtscts
) {
301 toptions
.c_cflag
&= ~CRTSCTS
;
303 toptions
.c_cflag
|= CRTSCTS
;
305 #endif // !_POSIX_C_SOURCE || __USE_MISC
308 if (m_options
.xonxoff
) {
309 toptions
.c_iflag
|= (IXON
| IXOFF
| IXANY
);
311 toptions
.c_iflag
&= ~(IXON
| IXOFF
| IXANY
);
314 // (nescivi) by default carriage returns are translated to line feeds,
315 // we don't want that
316 toptions
.c_iflag
&= ~ICRNL
;
318 // enable READ & ignore ctrl lines
319 toptions
.c_cflag
|= (CREAD
| CLOCAL
);
320 // non-canonical (raw) i/o
321 toptions
.c_lflag
&= ~(ICANON
| ECHO
| ECHOE
| ISIG
);
322 // disable post processing
323 toptions
.c_oflag
&= ~OPOST
;
325 // see: http://unixwiz.net/techtips/termios-vmin-vtime.html
326 // NOTE: unused for non-blocking reads
327 // toptions.c_cc[VMIN] = 0;
328 // toptions.c_cc[VTIME] = 20;
330 if (tcsetattr(m_fd
, TCSAFLUSH
, &toptions
) < 0) {
335 memcpy(&m_termio
, &toptions
, sizeof(toptions
));
337 m_rxErrors
[0] = m_rxErrors
[1] = 0;
339 int e
= pthread_create(&m_thread
, 0, threadFunc
, this);
349 SerialPort::~SerialPort()
354 tcflush(m_fd
, TCIOFLUSH
);
355 tcsetattr(m_fd
, TCSANOW
, &m_oldtermio
);
359 pthread_join(m_thread
, 0);
362 void SerialPort::stop(){
366 void SerialPort::cleanup(){
370 tcflush(m_fd
, TCIOFLUSH
);
371 tcsetattr(m_fd
, TCSANOW
, &m_oldtermio
);
377 bool SerialPort::put(uint8_t byte
)
379 return write(m_fd
, &byte
, sizeof(byte
)) == sizeof(byte
);
382 bool SerialPort::get(uint8_t* byte
)
384 if (m_rxfifo
.IsEmpty())
386 *byte
= m_rxfifo
.Get() & 0xFF;
390 int SerialPort::rxErrors()
392 // errors since last query
393 int x
= m_rxErrors
[1];
394 int res
= x
-m_rxErrors
[0];
399 void* SerialPort::threadFunc(void* self
)
401 ((SerialPort
*)self
)->threadLoop();
405 void SerialPort::dataAvailable()
407 int status
= lockLanguageOrQuit(m_running
);
411 postfl("error when locking language (%d)\n", status
);
415 PyrSymbol
*method
= s_dataAvailable
;
417 VMGlobals
*g
= gMainVMGlobals
;
419 ++g
->sp
; SetObject(g
->sp
, m_obj
);
420 runInterpreter(g
, method
, 1);
421 g
->canCallOS
= false;
423 pthread_mutex_unlock (&gLangMutex
);
426 void SerialPort::doneAction()
428 int status
= lockLanguageOrQuit(m_running
);
432 postfl("error when locking language (%d)\n", status
);
436 PyrSymbol
*method
= s_doneAction
;
438 VMGlobals
*g
= gMainVMGlobals
;
440 ++g
->sp
; SetObject(g
->sp
, m_obj
);
441 runInterpreter(g
, method
, 1);
442 g
->canCallOS
= false;
444 pthread_mutex_unlock (&gLangMutex
);
447 void SerialPort::threadLoop()
450 const int max_fd
= fd
+1;
461 struct timeval timeout
;
462 timeout
.tv_sec
= kReadTimeoutMs
/1000;
463 timeout
.tv_usec
= (kReadTimeoutMs
%1000)*1000;
465 int n
= select(max_fd
, &rfds
, 0, 0, &timeout
);
466 // int fdset = FD_ISSET(fd, &rfds);
467 // printf( "fdset %i, n %i, errno %i\n", fdset, n, errno );
469 if ((n
> 0) && FD_ISSET(fd
, &rfds
)) {
470 // printf("poll input\n");
474 int n2
= read(fd
, m_rxbuffer
, kBufferSize
);
475 // printf("read %d, errno %i, errbadf %i, %i, %i\n", n2, errno, EBADF, EAGAIN, EIO);
477 // write data to ringbuffer
478 for (int i
=0; i
< n2
; ++i
) {
479 if (!m_rxfifo
.Put(m_rxbuffer
[i
])) {
485 } else if ((n2
== 0) && (n
== 1) ) { // added by nescivi, to check for disconnected device. In this case the read is 0 all the time and otherwise eats up the CPU
486 // printf( "done\n" );
488 } else if ((n2
== 0) || ((n2
== -1) && (errno
== EAGAIN
))) {
489 // printf( "break\n");
493 printf("SerialPort HUP\n");
506 } else if (n
== -1) {
519 tcflush(fd
, TCIOFLUSH
);
520 tcsetattr(fd
, TCSANOW
, &m_oldtermio
);
528 printf("SerialPort closed\n");
532 // =====================================================================
535 static SerialPort
* getSerialPort(PyrSlot
* slot
)
537 if (NotPtr(&slotRawObject(slot
)->slots
[0]))
539 return (SerialPort
*)slotRawPtr(&slotRawObject(slot
)->slots
[0]);
542 static int prSerialPort_Open(struct VMGlobals
*g
, int numArgsPushed
)
544 PyrSlot
*args
= g
->sp
- 1 - SerialPort::kNumOptions
;
548 PyrSlot
* self
= args
+0;
550 if (getSerialPort(self
) != 0)
553 char portName
[PATH_MAX
];
554 err
= slotStrVal(args
+1, portName
, sizeof(portName
));
555 printf("portName %s\n", portName
);
558 SerialPort::Options options
;
559 SerialPort
* port
= 0;
561 options
.exclusive
= IsTrue(args
+2);
564 err
= slotIntVal(args
+3, &baudrate
);
566 options
.baudrate
= baudrate
;
569 err
= slotIntVal(args
+4, &databits
);
571 options
.databits
= databits
;
573 options
.stopbit
= IsTrue(args
+5);
576 err
= slotIntVal(args
+6, &parity
);
578 options
.parity
= (SerialPort::Parity
)parity
;
580 options
.crtscts
= IsTrue(args
+7);
581 options
.xonxoff
= IsTrue(args
+8);
584 port
= new SerialPort(slotRawObject(self
), portName
, options
);
585 } catch (SerialPort::Error
& e
) {
586 std::ostringstream os
;
587 os
<< "SerialPort Error: " << e
.what();
588 post(os
.str().c_str());
592 SetPtr(slotRawObject(self
)->slots
+0, port
);
597 static int prSerialPort_Close(struct VMGlobals
*g
, int numArgsPushed
)
599 PyrSlot
* self
= g
->sp
;
600 SerialPort
* port
= (SerialPort
*)getSerialPort(self
);
601 if (port
== 0) return errFailed
;
606 static int prSerialPort_Cleanup(struct VMGlobals
*g
, int numArgsPushed
)
608 PyrSlot
* self
= g
->sp
;
609 SerialPort
* port
= (SerialPort
*)getSerialPort(self
);
611 if (port
== 0) return errFailed
;
615 post("SerialPort Cleanup\n");
618 SetNil(slotRawObject(self
)->slots
+0);
622 static int prSerialPort_Next(struct VMGlobals
*g
, int numArgsPushed
)
624 PyrSlot
* self
= g
->sp
;
625 SerialPort
* port
= (SerialPort
*)getSerialPort(self
);
626 // printf( "port %i", port );
627 if (port
== 0) return errFailed
;
630 if (port
->get(&byte
)) {
639 static int prSerialPort_Put(struct VMGlobals
*g
, int numArgsPushed
)
641 PyrSlot
*args
= g
->sp
- 1;
643 PyrSlot
* self
= args
+0;
644 SerialPort
* port
= (SerialPort
*)getSerialPort(self
);
645 if (port
== 0) return errFailed
;
647 PyrSlot
* src
= args
+1;
651 val
= slotRawChar(src
);
653 int err
= slotIntVal(src
, &val
);
657 bool res
= port
->put(val
& 0xFF);
663 static int prSerialPort_RXErrors(struct VMGlobals
*g
, int numArgsPushed
)
665 PyrSlot
* self
= g
->sp
;
666 SerialPort
* port
= (SerialPort
*)getSerialPort(self
);
667 if (port
== 0) return errFailed
;
668 SetInt(self
, port
->rxErrors());
672 void initSerialPrimitives()
676 base
= nextPrimitiveIndex();
679 definePrimitive(base
, index
++, "_SerialPort_Open", prSerialPort_Open
, 2+SerialPort::kNumOptions
, 0);
680 definePrimitive(base
, index
++, "_SerialPort_Close", prSerialPort_Close
, 1, 0);
681 definePrimitive(base
, index
++, "_SerialPort_Next", prSerialPort_Next
, 1, 0);
682 definePrimitive(base
, index
++, "_SerialPort_Put", prSerialPort_Put
, 2, 0);
683 definePrimitive(base
, index
++, "_SerialPort_RXErrors", prSerialPort_RXErrors
, 1, 0);
684 definePrimitive(base
, index
++, "_SerialPort_Cleanup", prSerialPort_Cleanup
, 1, 0);
686 SerialPort::s_dataAvailable
= getsym("prDataAvailable");
687 SerialPort::s_doneAction
= getsym("prDoneAction");