Poul-Henning Kamp в списке рассылки freebsd-arch продемонстрировал пример кода, позволяющего осуществлять консольный ввод-вывод через звуковую карту. Оригинал его письма здесь, а я предлагаю свой, по возможности максимально близкий к оригиналу, перевод. Некоторые слова я перевести не смог, поэтому оставляю в оригинале и в скобках даю свои предположения.
Вчера, когда я страдал фигней, занимаясь со своим новым лэптопом и функциями приостановки/возобновления ACPI, я снова поймал себя на том, что проклинаю того чокнутого, который убрал (с лэптопов — прим. перев.) наши последовательные порты.
Я подумал немного и меня внезапно озарило: все современные устройства имеют встроенную поддержку звукового оборудования AC97, предоставляющего довольно хорошую пропускную способность.
Этим утром я начал простой эксперимент. Результат ясно дает понять, что идея рабочая, хотя и работает from userland (может быть, в пространстве пользователя? определен��я Google дают именно такой ответ — прим. перев.).
Я использовал следующий формат для передачи: посылка кратковременного отрицательного перепада для начала символа, а затем N дискрет, затем положительный перепад. N — ASCII-значение символа + маленькая константа.
Я прилагаю код, подтверждающий концепцию(proof-of-concept в оригинале — прим. перев.), который использует два стереоканала на дифференциальной паре (не уверен, что это хорошая идея).
В первой попытке, я был способен передавать около 320 символов в секунду с 1% ошибок.
Что осталось сделать:
* оптимизировать схему передачи.
Это может быть сделано с помощью двух компьютеров, кабеля jack-в-jack и немного кода на C.
Различие в частоте дискрет на у двух компьютеров приводит к ошибке занижения или завышения на единицу. Я не знаю, может ли детектор пиков с интерполяцией решить эту проблему, либо мы будем вынуждены использовать дискретизацию с запасом по частоте (oversampling — прим. перев.) в приемнике.
Два импульса могут иметь различные полярности, т.е. мы можем передавать два бита, что может повысить скорость передачи на множитель четырех (factor of four скорее всего означает именно это — прим. перев.), если найдем способ должным образом выполнить синхронизацию.
Два стереоканала могут быть использованы независимо, вдвое увеличивая скорость.
* написать дравер консоли уровня ядра, работающий со звуковым оборудованием без использования прерываний.
Я не знаю, как выглядит интерфейс к звуковой карте, но я подозреваю, что довольно просто.
Даже если соединение будет однонаправленное, хакеры ядра, вроде меня, будут почитать любого, который закончит эту работу.
Налетай!
Poul-Henning
Вчера, когда я страдал фигней, занимаясь со своим новым лэптопом и функциями приостановки/возобновления ACPI, я снова поймал себя на том, что проклинаю того чокнутого, который убрал (с лэптопов — прим. перев.) наши последовательные порты.
Я подумал немного и меня внезапно озарило: все современные устройства имеют встроенную поддержку звукового оборудования AC97, предоставляющего довольно хорошую пропускную способность.
Этим утром я начал простой эксперимент. Результат ясно дает понять, что идея рабочая, хотя и работает from userland (может быть, в пространстве пользователя? определен��я Google дают именно такой ответ — прим. перев.).
Я использовал следующий формат для передачи: посылка кратковременного отрицательного перепада для начала символа, а затем N дискрет, затем положительный перепад. N — ASCII-значение символа + маленькая константа.
Я прилагаю код, подтверждающий концепцию(proof-of-concept в оригинале — прим. перев.), который использует два стереоканала на дифференциальной паре (не уверен, что это хорошая идея).
В первой попытке, я был способен передавать около 320 символов в секунду с 1% ошибок.
Что осталось сделать:
* оптимизировать схему передачи.
Это может быть сделано с помощью двух компьютеров, кабеля jack-в-jack и немного кода на C.
Различие в частоте дискрет на у двух компьютеров приводит к ошибке занижения или завышения на единицу. Я не знаю, может ли детектор пиков с интерполяцией решить эту проблему, либо мы будем вынуждены использовать дискретизацию с запасом по частоте (oversampling — прим. перев.) в приемнике.
Два импульса могут иметь различные полярности, т.е. мы можем передавать два бита, что может повысить скорость передачи на множитель четырех (factor of four скорее всего означает именно это — прим. перев.), если найдем способ должным образом выполнить синхронизацию.
Два стереоканала могут быть использованы независимо, вдвое увеличивая скорость.
* написать дравер консоли уровня ядра, работающий со звуковым оборудованием без использования прерываний.
Я не знаю, как выглядит интерфейс к звуковой карте, но я подозреваю, что довольно просто.
Даже если соединение будет однонаправленное, хакеры ядра, вроде меня, будут почитать любого, который закончит эту работу.
Налетай!
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); }
