Яндекс.Метрика

    Ни о чём

    Звуковая карта в качестве консольного устройства

    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

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

    Лицензия Creative Commons
    Это произведение доступно по лицензии Creative Commons Attribution-ShareAlike (Атрибуция — С сохранением условий) 3.0 Непортированная.