Proof of concept: soundcard as console device

Hans Petter Selasky hselasky at c2i.net
Fri Aug 31 04:58:18 PDT 2007


Hi,

This is really creative. Maybe you should add a simple N-tap FIR filter so 
that you limit the bandwidth used and don't destroy the soundcard :-)

BTW: Why can't you use an USB serial adapter connected to the PC ?

--HPS

On Friday 31 August 2007, Poul-Henning Kamp wrote:
> Yesterday while I was futzing with my new laptop and ACPI suspend/resume,
> I once again found myself cursing the nutjob who took away our serial
> ports.
>
> Then my mind wandered around a bit and suddenly it struck me: all
> modern hardware have built in AC97 sound hardware, and it offers a
> channel with a pretty decent bandwidth.
>
> This morning I ran a simple experiment, from userland, but the
> result show clearly that the idea is workable.
>
> The transmission format I used: send a negative transient to start
> a character and after N samples, send a positive transient, where
> N is the ASCII value of the character + a small constant.
>
> I have attached my proof-of-concept code, which uses the two stereo
> channels as a differential wire (not sure if this is a actually
> good idea).
>
> In my first attempt, I was able to transmit around 320 characters
> per second with something that looks like 1% error rate.
>
> What's left to do:
>
> 	* optimize transmission schema.
>
> 		This can be done with two computers, a jack-jack cable
> 		and a bit of C-coding.
>
> 		The difference in sample rate between the two machines
> 		causes off-by-one errors.  I don't know of a peak detector
> 		which interpolates can resolve this, of if we need use
> 		oversampling in the receiver.
>
> 		The two pulses can have two different polarities each,
> 		so we can transmit two bits just that way, this could speed
> 		up transmission by a factor of four, if we can find a way
> 		to synchronize properly.
>
> 		The two stereo channels can be used independently, offering
> 		a doubling in speed.
>
> 	* write a kernel console driver which talks to the sound hardware
> 	        without using interrupts.
>
> 		I don't know what the hardware interface to a sound card
> 		looks like, but I suspect this might be fairly easy.
>
> Even if the connection is one-way, kernel-hackers like me will worship
> any person who completes this task.
>
> Have at it...
>
> Poul-Henning
>
> -----------------------------------------------------------------------
> /* proof of concept transmission code */
> #include <stdio.h>
> #include <assert.h>
> #include <fcntl.h>
> #include <sys/soundcard.h>
>
> #define OFF 5
>
> static short int buf[2*128 + 2 * OFF];
>
> int
> main(int argc __unused, char **argv __unused)
> {
> 	int fd_dsp;
> 	int i, j, k, c;
>
> 	fd_dsp = open("/dev/dsp0.1", O_RDWR);
> 	if (fd_dsp < 0)
> 		err(1, "open /dev/dsp");
>
> 	i = ioctl(fd_dsp, SNDCTL_DSP_RESET, &j);
> 	assert(i == 0);
>
> 	j = 2;
> 	i = ioctl(fd_dsp, SNDCTL_DSP_CHANNELS, &j);
> 	assert(i == 0);
>
> 	j = 44100;
> 	i = ioctl(fd_dsp, SNDCTL_DSP_SPEED, &j);
> 	assert(i == 0);
>
> 	j = 16;
> 	i = ioctl(fd_dsp, SNDCTL_DSP_SETFMT, &j);
> 	assert(i == 0);
>
>
> 	while (1) {
> 		c = getchar();
> 		if (c == EOF)
> 			break;
> 		buf[OFF] =  32000;
> 		buf[OFF + 1] = -32000;
>
> 		buf[OFF + 2 * c] = -32000;
> 		buf[OFF + 2 * c + 1] =  32000;
>
> 		i = write(fd_dsp, buf, sizeof buf);
> 		assert(i == sizeof buf);
>
> 		buf[OFF + 2 * c] = 0;
> 		buf[OFF + 1 + 2 * c] = 0;
> 	}
>
> 	exit (0);
> }
> -----------------------------------------------------------------------
> /* proof of concept reception code */
> #include <assert.h>
> #include <stdio.h>
>
> static int
> sample(FILE *f, const char *p)
> {
>         short l, r;
>         int i, s;
>
>         i = fread(&l, sizeof l, 1, stdin);
>         assert(i == 1);
>         i = fread(&r, sizeof l, 1, stdin);
>         assert(i == 1);
>         s = l;
>         s -= r;
>         if (0 && p != NULL)
>                 printf("%6d %s\n", s, p);
>         return (s);
> }
>
> static void
> find_neg_peak(FILE *f)
> {
>         int s, sl;
>
>         while (1) {
>                 s = sample(stdin, "v");
>                 if (s < -10000)
>                         break;
>         }
>         sl = s;
>         while (1) {
>                 s = sample(stdin, "N");
>                 if (s > sl)
>                         return;
>                 sl = s;
>         }
> }
>
> static int
> find_pos_peak(FILE *f)
> {
>         int s, sl, k;
>
>         k = 0;
>         while (1) {
>                 k++;
>                 s = sample(stdin, "^");
>                 if (s > 10000)
>                         break;
>         }
>         sl = s;
>         while (1) {
>                 k++;
>                 s = sample(stdin, "P");
>                 if (s < sl)
>                         return (k);
>                 sl = s;
>         }
> }
>
>
> int
> main(int argc __unused, char **argv)
> {
>         short l, r;
>         int i, k, p, s, sl;
>
>         k = 0;
>         p = 0;
>         while (1) {
>                 find_neg_peak(stdin);
>                 k = find_pos_peak(stdin);
>                 if (k == 10)
>                         printf("\\n\n");
>                 else if (k >= ' ' && k <= '~')
>                         printf("%c", k);
>                 else
>                         printf("\\x%02x", k);
>         }
>         exit (0);
> }
> -----------------------------------------------------------------------




More information about the freebsd-arch mailing list