Wed Nov 19 2008Author: burninYears ago I put together a small computer to play Ogg Vorbis encoded music files in my truck. Part of the project included a bit of a hack to incorporate a serial port button pad to control the XMMS player. The web site that hosted the article on the project is long gone but I thought there might be some interest in the hack that was used.

So you have a fancy little Ogg Vorbis player you've assembled with Mini-ITX hardware and a small LCD TV but you find the mouse touch pad is virtually useless as there is no way to jump around between songs without pulling over to the side of the road. The first thing that probably comes to mind is a micro-controller based button pad, but what if you don't have the hardware, software or knowledge needed to build a button pad based on a micro-controller? You hack together a button controller with what you have.
And so that is how this hack started, with the cord from a serial port mouse, some momentary pushbuttons and a hand full of circuit components.
The circuit is comprised of a 14 stage ripple counter tied to a 2.4576MHz crystal with the O8 pin used to provide a clock rate of 9.6KHz for the 9600 baud RS232 connection. A 74HC165 8 bit shift register provides a port for the pushbutton inputs and a serial output signal. The ripple counter provides the clock for the shift register to send the serial signal at 9600 baud. The trigger for the latch on the shift register is provided by an inverting schmitt trigger that is connected to all the buttons. An RC circuit on the trigger input ensures a delay to allow the shift register to latch before shifting starts. And with a 5.1V zener diode the entire circuit is powered from the DTR and RTS lines on the serial port.

A simple test on a bread board with three buttons verified the circuit operation. With additional buttons and diodes the circuit can be expanded to many more buttons, I eventually implemented a total of 9.

With a working button pad connected to the serial port on the Ogg Vorbis player it only needs a bit of code running in the background to monitor the serial port for button events and then send the appropriate signal to any running XMMS players for the given button signal.
#include < termios.h >
#include < stdio.h >
#include < unistd.h >
#include < fcntl.h >
#include < sys/signal.h >
#include < sys/types.h >
#include < sys/ioctl.h >
#include < xmms/xmmsctrl.h >
#define BAUDRATE B9600
#define MODEMDEVICE "/dev/ttyS1"
#define _POSIX_SOURCE 1 /* POSIX compliant source */
#define FALSE 0
#define TRUE 1
volatile int STOP=FALSE;
main()
{
int fd,c, res, linedata, mvol;
struct termios oldtio,newtio;
char buf[255];
/* open the device to be non-blocking (read will return immediatly) */
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd < 0) {perror(MODEMDEVICE); exit(-1); }
/* Make the file descriptor asynchronous (the manual page says only
O_APPEND and O_NONBLOCK, will work with F_SETFL...) */
// fcntl(fd, F_SETFL, FASYNC);
tcgetattr(fd,&oldtio); /* save current port settings */
tcgetattr(fd,&newtio);
/* set new port settings for canonical input processing */
//newtio.c_cflag = BAUDRATE | CS6 | CLOCAL | CREAD | CRTSCTS; // CRTSCTS
newtio.c_iflag = IGNBRK | IGNPAR | IGNCR;
//newtio.c_iflag = IGNPAR ;//| ICRNL;
newtio.c_oflag = 0;
newtio.c_cflag = B9600 | CS6 | CREAD | CLOCAL;
//newtio.c_lflag = ICANON;
newtio.c_lflag = 0;
newtio.c_cc[VMIN]=1;
newtio.c_cc[VTIME]=0;
tcflush(fd, TCIOFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
//ioctl(fd, TIOCMGET, &linedata);
//linedata |= ~TIOCM_DTR;
//ioctl(fd, TIOCMSET, &linedata);
/* loop while waiting for input. normally we would do something
useful here */
while (STOP == FALSE)
{
usleep(100000);
buf[0] = '\0';
res = read(fd,buf,5);
buf[res]=0;
printf("%d\n", buf[0]);
if ((int)buf[0] == 3)
{
if (xmms_remote_is_playing(0) ) xmms_remote_pause(0);
else xmms_remote_play(0);
}
if ((int)buf[0] == 2)
{
xmms_remote_playlist_next(0);
}
if((int)buf[0] == 1) xmms_remote_playlist_prev(0);
if((int)buf[0] == 7)
{
mvol = xmms_remote_get_main_volume(0);
mvol -= 5;
if( mvol < 0 ) mvol = 0;
xmms_remote_set_main_volume(0, mvol);
}
if((int)buf[0] == 8)
{
mvol = xmms_remote_get_main_volume(0);
mvol += 5;
if( mvol > 100) mvol = 100;
xmms_remote_set_main_volume(0, mvol);
}
//if ((int)buf[0] == 3) STOP=TRUE; /* stop loop if only a CR was input */
}
/* restore old port settings */
tcsetattr(fd,TCSANOW,&oldtio);
}
And the following is the schematic for the 9 button circuit. By adding diodes it is possible to implement up to 63 buttons. The circuit could be simplified by eliminating the under utilized hex inverter. But this is what I made with what I had on hand. Its also interesting to note the TxD pin 3 connected to the collector of the output transistor, for the life of me I cannot recall why I did that, for loop back testing?
Long after developing this hack I did finally break down and put together the hardware to program a micro-controller to do the same job, but I thought this hack was still worth mentioning.
