supernova: fix for small audio vector sizes
[supercollider.git] / lang / LangPrimSource / PyrSerialPrim.cpp
blob43cb2ade8062dab3817b1d06e8aa70550b986106
1 /*
2 Serial port support.
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
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <stdint.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <sys/ioctl.h>
33 #include <sys/select.h>
34 #include <termios.h>
35 #include <unistd.h>
37 #include <stdexcept>
38 #include <sstream>
40 #include "GC.h"
41 #include "PyrKernel.h"
42 #include "PyrPrimitive.h"
43 #include "SC_LanguageClient.h"
44 #include "SCBase.h"
46 #include "SC_FIFO.h"
48 class SerialPort
50 public:
51 enum Parity
53 kNoParity,
54 kEvenParity,
55 kOddParity
58 struct Options
60 Options()
61 : exclusive(false),
62 baudrate(9600),
63 databits(8),
64 stopbit(true),
65 parity(kNoParity),
66 crtscts(false),
67 xonxoff(false)
68 { }
70 bool exclusive;
71 size_t baudrate;
72 size_t databits;
73 bool stopbit;
74 Parity parity;
75 bool crtscts;
76 bool xonxoff;
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)
89 { }
92 struct SysError : public Error
94 explicit SysError(int e=errno)
95 : Error(strerror(e))
96 { }
99 static PyrSymbol* s_dataAvailable;
100 static PyrSymbol* s_doneAction;
102 public:
103 SerialPort(PyrObject* obj, const char* serialport, const Options& options);
104 ~SerialPort();
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);
112 int rxErrors();
114 void stop();
115 void cleanup();
117 protected:
118 static void* threadFunc(void*);
119 void threadLoop();
121 void dataAvailable();
122 void doneAction();
124 private:
125 // language interface
126 PyrObject* m_obj;
128 volatile bool m_dodone;
130 // serial interface
131 Options m_options;
132 int m_fd;
133 volatile bool m_open;
134 struct termios m_termio;
135 struct termios m_oldtermio;
137 // rx buffers
138 int m_rxErrors[2];
139 FIFO m_rxfifo;
140 uint8_t m_rxbuffer[kBufferSize];
142 // rx thread
143 volatile bool m_running;
144 pthread_t m_thread;
147 PyrSymbol* SerialPort::s_dataAvailable = 0;
148 PyrSymbol* SerialPort::s_doneAction = 0;
150 SerialPort::SerialPort(PyrObject* obj, const char* serialport, const Options& options)
151 : m_obj(obj),
152 m_options(options),
153 m_fd(-1)
155 // open non blocking
156 m_fd = open(serialport, O_RDWR | O_NOCTTY | O_NDELAY);
157 if (m_fd == -1) {
158 throw SysError(errno);
161 // exclusiveness
162 #if defined(TIOCEXCL)
163 if (m_options.exclusive) {
164 if (ioctl(m_fd, TIOCEXCL) == -1) {
165 throw SysError(errno);
168 #endif // TIOCEXCL
170 if (fcntl(m_fd, F_SETFL, O_NONBLOCK) == -1) {
171 int e = errno;
172 close(m_fd);
173 throw SysError(e);
176 // initialize serial connection
178 // get current settings and remember them
179 struct termios toptions;
180 if (tcgetattr(m_fd, &toptions) < 0) {
181 int e = errno;
182 close(m_fd);
183 throw SysError(e);
185 memcpy(&m_oldtermio, &toptions, sizeof(toptions));
187 // baudrate
188 speed_t brate;
189 switch (m_options.baudrate) {
190 case 1200:
191 brate = B1200;
192 break;
193 case 1800:
194 brate = B1800;
195 break;
196 case 2400:
197 brate = B2400;
198 break;
199 case 4800:
200 brate = B4800;
201 break;
202 case 9600:
203 brate = B9600;
204 break;
205 case 19200:
206 brate = B19200;
207 break;
208 case 38400:
209 brate = B38400;
210 break;
211 // #ifndef _POSIX_C_SOURCE
212 #if defined(B7200)
213 case 7200:
214 brate = B7200;
215 break;
216 #endif
217 #if defined(B7200)
218 case 14400:
219 brate = B14400;
220 break;
221 #endif
222 #if defined(B28800)
223 case 28800:
224 brate = B28800;
225 break;
226 #endif
227 #if defined(B57600)
228 case 57600:
229 brate = B57600;
230 break;
231 #endif
232 #if defined(B76800)
233 case 76800:
234 brate = B76800;
235 break;
236 #endif
237 #if defined(B115200)
238 case 115200:
239 brate = B115200;
240 break;
241 #endif
242 #if defined(B230400)
243 case 230400:
244 brate = B230400;
245 break;
246 #endif
247 // #endif // !_POSIX_C_SOURCE
248 default:
249 close(m_fd);
250 throw Error("unsupported baudrate");
253 cfsetispeed(&toptions, brate);
254 cfsetospeed(&toptions, brate);
256 // data bits
257 toptions.c_cflag &= ~CSIZE;
258 switch (m_options.databits)
260 case 5:
261 toptions.c_cflag |= CS5;
262 break;
263 case 6:
264 toptions.c_cflag |= CS6;
265 break;
266 case 7:
267 toptions.c_cflag |= CS7;
268 break;
269 default:
270 m_options.databits = 8;
271 toptions.c_cflag |= CS8;
272 break;
275 // stop bit
276 if (m_options.stopbit) {
277 toptions.c_cflag |= CSTOPB;
278 } else {
279 toptions.c_cflag &= ~CSTOPB;
282 // parity
283 switch (m_options.parity)
285 case kNoParity:
286 toptions.c_cflag &= ~PARENB;
287 break;
288 case kEvenParity:
289 toptions.c_cflag |= PARENB;
290 toptions.c_cflag &= ~PARODD;
291 break;
292 case kOddParity:
293 toptions.c_cflag |= (PARENB | PARODD);
294 break;
297 // h/w flow control
298 #if !defined(_POSIX_C_SOURCE) || defined(__USE_MISC)
299 if (m_options.crtscts) {
300 toptions.c_cflag &= ~CRTSCTS;
301 } else {
302 toptions.c_cflag |= CRTSCTS;
304 #endif // !_POSIX_C_SOURCE || __USE_MISC
306 // s/w flow control
307 if (m_options.xonxoff) {
308 toptions.c_iflag |= (IXON | IXOFF | IXANY);
309 } else {
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) {
330 int e = errno;
331 close(m_fd);
332 throw SysError(e);
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);
339 if (e != 0) {
340 close(m_fd);
341 throw SysError(e);
344 m_open = true;
345 m_dodone = true;
348 SerialPort::~SerialPort()
350 m_running = false;
351 // m_open = false;
352 pthread_mutex_unlock (&gLangMutex);
353 if ( m_open ){
354 tcflush(m_fd, TCIOFLUSH);
355 tcsetattr(m_fd, TCSANOW, &m_oldtermio);
356 close(m_fd);
357 m_open = false;
359 pthread_join(m_thread, 0);
360 pthread_mutex_lock (&gLangMutex);
363 void SerialPort::stop(){
364 m_running = false;
367 void SerialPort::cleanup(){
368 m_running = false;
369 m_dodone = false;
370 if ( m_open ){
371 tcflush(m_fd, TCIOFLUSH);
372 tcsetattr(m_fd, TCSANOW, &m_oldtermio);
373 close(m_fd);
374 m_open = false;
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())
386 return false;
387 *byte = m_rxfifo.Get() & 0xFF;
388 return true;
391 int SerialPort::rxErrors()
393 // errors since last query
394 int x = m_rxErrors[1];
395 int res = x-m_rxErrors[0];
396 m_rxErrors[0] = x;
397 return res;
400 void* SerialPort::threadFunc(void* self)
402 ((SerialPort*)self)->threadLoop();
403 return 0;
406 void SerialPort::dataAvailable()
408 pthread_mutex_lock (&gLangMutex);
409 if (!m_running) {
410 pthread_mutex_unlock (&gLangMutex);
411 return;
413 PyrSymbol *method = s_dataAvailable;
414 if (m_obj) {
415 VMGlobals *g = gMainVMGlobals;
416 g->canCallOS = true;
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;
428 if (m_obj) {
429 VMGlobals *g = gMainVMGlobals;
430 g->canCallOS = true;
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()
440 const int fd = m_fd;
441 const int max_fd = fd+1;
443 m_running = true;
444 m_rxErrors[1] = 0;
446 while (true) {
447 fd_set rfds;
449 FD_ZERO( &rfds);
450 FD_SET(fd, &rfds);
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 );
459 if ( m_open ){
460 if ((n > 0) && FD_ISSET(fd, &rfds)) {
461 // printf("poll input\n");
462 int nr = 0;
463 // while (true) {
464 if ( m_open ){
465 int n2 = read(fd, m_rxbuffer, kBufferSize);
466 // printf("read %d, errno %i, errbadf %i, %i, %i\n", n2, errno, EBADF, EAGAIN, EIO);
467 if (n2 > 0) {
468 // write data to ringbuffer
469 for (int i=0; i < n2; ++i) {
470 if (!m_rxfifo.Put(m_rxbuffer[i])) {
471 m_rxErrors[1]++;
472 break;
475 nr += n2;
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" );
478 goto done;
479 } else if ((n2 == 0) || ((n2 == -1) && (errno == EAGAIN))) {
480 // printf( "break\n");
481 break;
482 } else {
483 #ifndef NDEBUG
484 printf("SerialPort HUP\n");
485 #endif
486 goto done;
490 if (!m_running) {
491 // close and cleanup
492 goto done;
494 if (nr > 0) {
495 dataAvailable();
497 } else if (n == -1) {
498 goto done;
501 if (!m_running) {
502 // close and cleanup
503 goto done;
507 done:
508 // doneAction();
509 if ( m_open ){
510 tcflush(fd, TCIOFLUSH);
511 tcsetattr(fd, TCSANOW, &m_oldtermio);
512 close(fd);
514 m_open = false;
515 m_running = false;
516 if ( m_dodone )
517 { doneAction(); }
518 #ifndef NDEBUG
519 printf("SerialPort closed\n");
520 #endif
523 // =====================================================================
524 // primitives
526 static SerialPort* getSerialPort(PyrSlot* slot)
528 if (NotPtr(&slotRawObject(slot)->slots[0]))
529 return NULL;
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;
537 int err;
539 PyrSlot* self = args+0;
541 if (getSerialPort(self) != 0)
542 return errFailed;
544 char portName[PATH_MAX];
545 err = slotStrVal(args+1, portName, sizeof(portName));
546 printf("portName %s\n", portName);
547 if (err) return err;
549 SerialPort::Options options;
550 SerialPort* port = 0;
552 options.exclusive = IsTrue(args+2);
554 int baudrate;
555 err = slotIntVal(args+3, &baudrate);
556 if (err) return err;
557 options.baudrate = baudrate;
559 int databits;
560 err = slotIntVal(args+4, &databits);
561 if (err) return err;
562 options.databits = databits;
564 options.stopbit = IsTrue(args+5);
566 int parity;
567 err = slotIntVal(args+6, &parity);
568 if (err) return err;
569 options.parity = (SerialPort::Parity)parity;
571 options.crtscts = IsTrue(args+7);
572 options.xonxoff = IsTrue(args+8);
574 try {
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());
580 return errFailed;
583 SetPtr(slotRawObject(self)->slots+0, port);
585 return errNone;
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;
593 port->stop();
594 return errNone;
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;
604 port->cleanup();
606 post("SerialPort Cleanup\n");
608 delete port;
609 SetNil(slotRawObject(self)->slots+0);
610 return errNone;
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;
620 uint8_t byte;
621 if (port->get(&byte)) {
622 SetInt(self, byte);
623 } else {
624 SetNil(self);
627 return errNone;
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;
640 int val;
641 if (IsChar(src)) {
642 val = slotRawChar(src);
643 } else {
644 int err = slotIntVal(src, &val);
645 if (err) return err;
648 bool res = port->put(val & 0xFF);
649 SetBool(self, res);
651 return errNone;
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());
660 return errNone;
663 void initSerialPrimitives()
665 int base, index;
667 base = nextPrimitiveIndex();
668 index = 0;
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");
681 // EOF