/* Limited serial port extension build c executable with... gcc -Wall serial.c After connecting tx to rx (eg, pin 2 to pin 3), test with... ./a.out "/dev/tty.USA19H181P1.1" 9600 "some text" bulid extension with... ./mzc --cc ++ccf -Wall schemeterface.c serial.c ./mzc --ld ser-ext.so serial.o schemeterface.o test with... (load-extension "ser-ext.so") ; above should show: ; "extension includes: open-tty write-tty read-tty close-tty" (define (o) (open-tty "/dev/tty.USA19H181P1.1" 9600)) ; driver varies (define (c) (close-tty)) ;; Keyspan: (o) should make green light solid (ie, stop blinking) ;; Keyspan: (c) should make green light blink again ;; (t "text to loop back") should loop back text if ;; tx & rx pins are connected ;; (t integer) should send only that character (eg, 3 is cntl-c) (define (t text-to-loop-back) ; multiple reads prove destructive behavior (list (read-tty) (write-tty text-to-loop-back) (sleep 0.1) (read-tty) (read-tty))) */ #include /* Standard input/output definitions */ #include /* String function definitions */ #include /* UNIX standard function definitions */ #include /* File control definitions */ #include /* Error number definitions */ #include /* POSIX terminal control definitions */ #include /* for atoi in main */ #include "schemeterface.h" static int s_fd = -1; static char message[ 256 ] = ""; void set_some_options( int baud_const, int on, int off ) { struct termios options; tcgetattr( s_fd, &options); cfsetispeed( &options, baud_const); cfsetospeed( &options, baud_const); /* Enable the receiver, set local mode, disable hw flow control */ options.c_cflag |= on; // yuck. rewrite all of this options.c_cflag &= ~off; options.c_cflag |= PARODD; options.c_cflag |= PARENB; options.c_cflag &= ~CSTOPB; options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; tcsetattr( s_fd, TCSANOW, &options); } char *close_port( void ) { close( s_fd ); return ""; } char *open_port( char *pPath, int baud ) // warning: limited mapping between baud constants and integer parameter { char* pReply = ""; s_fd = open( pPath, O_RDWR | O_NOCTTY | O_NDELAY ); //O_NDELAY is O_NONBLOCK in posixland if( s_fd == -1 ) { sprintf( message, "Error in open_port: Couldn't open %s", pPath ); pReply = message; } else { if( baud == 9600 ) { baud = B9600; } else if( baud == 19200 ) { baud = B19200; } else if( baud == 115200 ) { baud = B115200; } else if( baud == 230400 ) { baud = B230400; } else if( baud == 38400 ) { baud = B38400; } else { baud = B9600; pReply = "Error in open-port: baud set to 9600"; } set_some_options( baud, CLOCAL | CREAD, CRTSCTS ); } return pReply; } char *write_bytes( char *text ) { // warning: static buffer #define MAX 1023 char *pReply = ""; int len = strlen( text ); if( len > MAX ) { len = MAX; printf( message, "Wrote first %d characters.", MAX ); } write( s_fd, text, len ); return pReply; } char *write_n_chars( int n, char *chars ) { char *pReply = ""; write( s_fd, chars, n ); return pReply; } char *write_val( int val ) { char* pReply = ""; if( val > 0xFF ) { sprintf( message, "Error in write_val: %d > 255", val ); pReply = message; } else { char val8 = val; write( s_fd, &val8, 1 ); } return pReply; } char *read_bytes( void ) { #define MAX 1023 static char buf[ MAX + 1 ] = ""; char *pReply = ""; int n_rx = read( s_fd, buf, MAX ); if( n_rx > 0 ) { if( n_rx > MAX ) { pReply = "err in read-bytes: n_rx is wrong!"; } else { buf[ n_rx ] = '\0'; pReply = buf; } } return pReply; } int main( int argc, char **argv ) #define NEED "Need 3 params: driver-path baud text-to-loop-back\n" // Connect tx to rx (eg: pin 3 to pin 2) // This test will block w/o a connection, or print the message { if( argc == 4 ) { char *pReply = open_port( argv[1], atoi( argv[2] ) ); if( pReply != "" ) { printf( pReply ); printf( "\n" ); } else { char *pText; printf( "writ: %s\n", argv[3] ); fflush( stdout ); write_bytes( argv[3] ); sleep( 1 ); // allow time for loop back for( pText = ""; pText == ""; pText = read_bytes() ); printf( "read: %s\n", pText ); close_port(); } } else { printf( NEED ); } fflush( stdout ); return 0; }