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>
41 #include "PyrKernel.h"
42 #include "PyrPrimitive.h"
43 #include "SC_LanguageClient.h"
79 static const int kNumOptions
= 7;
80 static const int kBufferSize
= 8192;
81 static const int kReadTimeoutMs
= 1000;
83 typedef SC_FIFO
<uint8_t,kBufferSize
> FIFO
;
85 struct Error
: std::runtime_error
87 explicit Error(const char* what
)
88 : std::runtime_error(what
)
92 struct SysError
: public Error
94 explicit SysError(int e
=errno
)
99 static PyrSymbol
* s_dataAvailable
;
100 static PyrSymbol
* s_doneAction
;
103 SerialPort(PyrObject
* obj
, const char* serialport
, const Options
& options
);
106 bool isRunning() const { return m_running
; }
107 int fd() const { return m_fd
; }
108 const Options
& options() const { return m_options
; }
110 bool put(uint8_t byte
);
111 bool get(uint8_t* byte
);
118 static void* threadFunc(void*);
121 void dataAvailable();
125 // language interface
128 volatile bool m_dodone
;
133 volatile bool m_open
;
134 struct termios m_termio
;
135 struct termios m_oldtermio
;
140 uint8_t m_rxbuffer
[kBufferSize
];
143 volatile bool m_running
;
147 PyrSymbol
* SerialPort::s_dataAvailable
= 0;
148 PyrSymbol
* SerialPort::s_doneAction
= 0;
150 SerialPort::SerialPort(PyrObject
* obj
, const char* serialport
, const Options
& options
)
156 m_fd
= open(serialport
, O_RDWR
| O_NOCTTY
| O_NDELAY
);
158 throw SysError(errno
);
162 #if defined(TIOCEXCL)
163 if (m_options
.exclusive
) {
164 if (ioctl(m_fd
, TIOCEXCL
) == -1) {
165 throw SysError(errno
);
170 if (fcntl(m_fd
, F_SETFL
, O_NONBLOCK
) == -1) {
176 // initialize serial connection
178 // get current settings and remember them
179 struct termios toptions
;
180 if (tcgetattr(m_fd
, &toptions
) < 0) {
185 memcpy(&m_oldtermio
, &toptions
, sizeof(toptions
));
189 switch (m_options
.baudrate
) {
211 // #ifndef _POSIX_C_SOURCE
247 // #endif // !_POSIX_C_SOURCE
250 throw Error("unsupported baudrate");
253 cfsetispeed(&toptions
, brate
);
254 cfsetospeed(&toptions
, brate
);
257 toptions
.c_cflag
&= ~CSIZE
;
258 switch (m_options
.databits
)
261 toptions
.c_cflag
|= CS5
;
264 toptions
.c_cflag
|= CS6
;
267 toptions
.c_cflag
|= CS7
;
270 m_options
.databits
= 8;
271 toptions
.c_cflag
|= CS8
;
276 if (m_options
.stopbit
) {
277 toptions
.c_cflag
|= CSTOPB
;
279 toptions
.c_cflag
&= ~CSTOPB
;
283 switch (m_options
.parity
)
286 toptions
.c_cflag
&= ~PARENB
;
289 toptions
.c_cflag
|= PARENB
;
290 toptions
.c_cflag
&= ~PARODD
;
293 toptions
.c_cflag
|= (PARENB
| PARODD
);
298 #if !defined(_POSIX_C_SOURCE) || defined(__USE_MISC)
299 if (m_options
.crtscts
) {
300 toptions
.c_cflag
&= ~CRTSCTS
;
302 toptions
.c_cflag
|= CRTSCTS
;
304 #endif // !_POSIX_C_SOURCE || __USE_MISC
307 if (m_options
.xonxoff
) {
308 toptions
.c_iflag
|= (IXON
| IXOFF
| IXANY
);
310 toptions
.c_iflag
&= ~(IXON
| IXOFF
| IXANY
);
313 // (nescivi) by default carriage returns are translated to line feeds,
314 // we don't want that
315 toptions
.c_iflag
&= ~ICRNL
;
317 // enable READ & ignore ctrl lines
318 toptions
.c_cflag
|= (CREAD
| CLOCAL
);
319 // non-canonical (raw) i/o
320 toptions
.c_lflag
&= ~(ICANON
| ECHO
| ECHOE
| ISIG
);
321 // disable post processing
322 toptions
.c_oflag
&= ~OPOST
;
324 // see: http://unixwiz.net/techtips/termios-vmin-vtime.html
325 // NOTE: unused for non-blocking reads
326 // toptions.c_cc[VMIN] = 0;
327 // toptions.c_cc[VTIME] = 20;
329 if (tcsetattr(m_fd
, TCSAFLUSH
, &toptions
) < 0) {
334 memcpy(&m_termio
, &toptions
, sizeof(toptions
));
336 m_rxErrors
[0] = m_rxErrors
[1] = 0;
338 int e
= pthread_create(&m_thread
, 0, threadFunc
, this);
348 SerialPort::~SerialPort()
352 pthread_mutex_unlock (&gLangMutex
);
354 tcflush(m_fd
, TCIOFLUSH
);
355 tcsetattr(m_fd
, TCSANOW
, &m_oldtermio
);
359 pthread_join(m_thread
, 0);
360 pthread_mutex_lock (&gLangMutex
);
363 void SerialPort::stop(){
367 void SerialPort::cleanup(){
371 tcflush(m_fd
, TCIOFLUSH
);
372 tcsetattr(m_fd
, TCSANOW
, &m_oldtermio
);
378 bool SerialPort::put(uint8_t byte
)
380 return write(m_fd
, &byte
, sizeof(byte
)) == sizeof(byte
);
383 bool SerialPort::get(uint8_t* byte
)
385 if (m_rxfifo
.IsEmpty())
387 *byte
= m_rxfifo
.Get() & 0xFF;
391 int SerialPort::rxErrors()
393 // errors since last query
394 int x
= m_rxErrors
[1];
395 int res
= x
-m_rxErrors
[0];
400 void* SerialPort::threadFunc(void* self
)
402 ((SerialPort
*)self
)->threadLoop();
406 void SerialPort::dataAvailable()
408 pthread_mutex_lock (&gLangMutex
);
410 pthread_mutex_unlock (&gLangMutex
);
413 PyrSymbol
*method
= s_dataAvailable
;
415 VMGlobals
*g
= gMainVMGlobals
;
417 ++g
->sp
; SetObject(g
->sp
, m_obj
);
418 runInterpreter(g
, method
, 1);
419 g
->canCallOS
= false;
421 pthread_mutex_unlock (&gLangMutex
);
424 void SerialPort::doneAction()
426 pthread_mutex_lock (&gLangMutex
);
427 PyrSymbol
*method
= s_doneAction
;
429 VMGlobals
*g
= gMainVMGlobals
;
431 ++g
->sp
; SetObject(g
->sp
, m_obj
);
432 runInterpreter(g
, method
, 1);
433 g
->canCallOS
= false;
435 pthread_mutex_unlock (&gLangMutex
);
438 void SerialPort::threadLoop()
441 const int max_fd
= fd
+1;
452 struct timeval timeout
;
453 timeout
.tv_sec
= kReadTimeoutMs
/1000;
454 timeout
.tv_usec
= (kReadTimeoutMs
%1000)*1000;
456 int n
= select(max_fd
, &rfds
, 0, 0, &timeout
);
457 // int fdset = FD_ISSET(fd, &rfds);
458 // printf( "fdset %i, n %i, errno %i\n", fdset, n, errno );
460 if ((n
> 0) && FD_ISSET(fd
, &rfds
)) {
461 // printf("poll input\n");
465 int n2
= read(fd
, m_rxbuffer
, kBufferSize
);
466 // printf("read %d, errno %i, errbadf %i, %i, %i\n", n2, errno, EBADF, EAGAIN, EIO);
468 // write data to ringbuffer
469 for (int i
=0; i
< n2
; ++i
) {
470 if (!m_rxfifo
.Put(m_rxbuffer
[i
])) {
476 } 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
477 // printf( "done\n" );
479 } else if ((n2
== 0) || ((n2
== -1) && (errno
== EAGAIN
))) {
480 // printf( "break\n");
484 printf("SerialPort HUP\n");
497 } else if (n
== -1) {
510 tcflush(fd
, TCIOFLUSH
);
511 tcsetattr(fd
, TCSANOW
, &m_oldtermio
);
519 printf("SerialPort closed\n");
523 // =====================================================================
526 static SerialPort
* getSerialPort(PyrSlot
* slot
)
528 if (NotPtr(&slotRawObject(slot
)->slots
[0]))
530 return (SerialPort
*)slotRawPtr(&slotRawObject(slot
)->slots
[0]);
533 static int prSerialPort_Open(struct VMGlobals
*g
, int numArgsPushed
)
535 PyrSlot
*args
= g
->sp
- 1 - SerialPort::kNumOptions
;
539 PyrSlot
* self
= args
+0;
541 if (getSerialPort(self
) != 0)
544 char portName
[PATH_MAX
];
545 err
= slotStrVal(args
+1, portName
, sizeof(portName
));
546 printf("portName %s\n", portName
);
549 SerialPort::Options options
;
550 SerialPort
* port
= 0;
552 options
.exclusive
= IsTrue(args
+2);
555 err
= slotIntVal(args
+3, &baudrate
);
557 options
.baudrate
= baudrate
;
560 err
= slotIntVal(args
+4, &databits
);
562 options
.databits
= databits
;
564 options
.stopbit
= IsTrue(args
+5);
567 err
= slotIntVal(args
+6, &parity
);
569 options
.parity
= (SerialPort::Parity
)parity
;
571 options
.crtscts
= IsTrue(args
+7);
572 options
.xonxoff
= IsTrue(args
+8);
575 port
= new SerialPort(slotRawObject(self
), portName
, options
);
576 } catch (SerialPort::Error
& e
) {
577 std::ostringstream os
;
578 os
<< "SerialPort Error: " << e
.what();
579 post(os
.str().c_str());
583 SetPtr(slotRawObject(self
)->slots
+0, port
);
588 static int prSerialPort_Close(struct VMGlobals
*g
, int numArgsPushed
)
590 PyrSlot
* self
= g
->sp
;
591 SerialPort
* port
= (SerialPort
*)getSerialPort(self
);
592 if (port
== 0) return errFailed
;
597 static int prSerialPort_Cleanup(struct VMGlobals
*g
, int numArgsPushed
)
599 PyrSlot
* self
= g
->sp
;
600 SerialPort
* port
= (SerialPort
*)getSerialPort(self
);
602 if (port
== 0) return errFailed
;
606 post("SerialPort Cleanup\n");
609 SetNil(slotRawObject(self
)->slots
+0);
613 static int prSerialPort_Next(struct VMGlobals
*g
, int numArgsPushed
)
615 PyrSlot
* self
= g
->sp
;
616 SerialPort
* port
= (SerialPort
*)getSerialPort(self
);
617 // printf( "port %i", port );
618 if (port
== 0) return errFailed
;
621 if (port
->get(&byte
)) {
630 static int prSerialPort_Put(struct VMGlobals
*g
, int numArgsPushed
)
632 PyrSlot
*args
= g
->sp
- 1;
634 PyrSlot
* self
= args
+0;
635 SerialPort
* port
= (SerialPort
*)getSerialPort(self
);
636 if (port
== 0) return errFailed
;
638 PyrSlot
* src
= args
+1;
642 val
= slotRawChar(src
);
644 int err
= slotIntVal(src
, &val
);
648 bool res
= port
->put(val
& 0xFF);
654 static int prSerialPort_RXErrors(struct VMGlobals
*g
, int numArgsPushed
)
656 PyrSlot
* self
= g
->sp
;
657 SerialPort
* port
= (SerialPort
*)getSerialPort(self
);
658 if (port
== 0) return errFailed
;
659 SetInt(self
, port
->rxErrors());
663 void initSerialPrimitives()
667 base
= nextPrimitiveIndex();
670 definePrimitive(base
, index
++, "_SerialPort_Open", prSerialPort_Open
, 2+SerialPort::kNumOptions
, 0);
671 definePrimitive(base
, index
++, "_SerialPort_Close", prSerialPort_Close
, 1, 0);
672 definePrimitive(base
, index
++, "_SerialPort_Next", prSerialPort_Next
, 1, 0);
673 definePrimitive(base
, index
++, "_SerialPort_Put", prSerialPort_Put
, 2, 0);
674 definePrimitive(base
, index
++, "_SerialPort_RXErrors", prSerialPort_RXErrors
, 1, 0);
675 definePrimitive(base
, index
++, "_SerialPort_Cleanup", prSerialPort_Cleanup
, 1, 0);
677 SerialPort::s_dataAvailable
= getsym("prDataAvailable");
678 SerialPort::s_doneAction
= getsym("prDoneAction");