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