📜 ⬆️ ⬇️

Sound card as a console device

Poul-Henning Kamp on the freebsd-arch mailing list showed an example of code that allows console I / O via sound card. The original of his letter is here , and I offer my, as close as possible to the original, translation. I could not translate some words, so I leave it in the original and in brackets I give my assumptions.

Yesterday, when I suffered from garbage, working with my new laptop and ACPI suspend / resume functions, I again found myself cursing the crazy one who removed our serial ports.

I thought a little and it suddenly dawned on me: all modern devices have built-in support for AC97 audio equipment, which provides fairly good bandwidth.

This morning I started a simple experiment. The result makes it clear that the idea is working, although it works from userland (Google’s definitions perhaps? Google’s definition gives exactly this answer - approx. Transl.).
')
I used the following format for transmission: sending a short-term negative differential for the beginning of a character, and then N discretes, then a positive differential. N is the ASCII value of the character + small constant.

I am attaching a proof of concept code ( proof-of-concept in the original - approx. Transl.) That uses two stereo channels on a differential pair (not sure if this is a good idea).

In the first attempt, I was able to transmit about 320 characters per second with 1% errors.

What is left to do:

* optimize the transmission scheme.

This can be done with two computers, a jack-in-jack cable and some C code.

The difference in discrete frequency on two computers results in an underreporting error or an overestimate by one. I do not know whether the interpolation peak detector can solve this problem, or we will have to use sampling with frequency margin ( oversampling ) in the receiver.

Two pulses can have different polarities, i.e. we can transmit two bits, which can increase the transmission speed by a factor of four (if the factor of four most likely means just that) if we find a way to properly synchronize.

Two stereo channels can be used independently, doubling the speed.

* write a kernel level console draver that works with audio equipment without using interrupts.

I don’t know what the interface to the sound card looks like, but I suspect it's pretty simple.

Even if the connection is unidirectional, kernel hackers, like me, will be honored by anyone who finishes this job.

Fly!

Poul-hening

/* 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); } 

Source: https://habr.com/ru/post/13736/


All Articles