0
<< предыдущая заметкаследующая заметка >>
18 мая 2009
вопрос знатокам программирования драйверов на С под FreeBSD :)

UPD: Спасибо, проблема решена! Можно дальше не читать. Но кому интересно — в комментариях много дельных предложений.

Вечная проблема, которую я пытаюсь побороть уже два года. Есть устройство — сканер отпечатка пальца:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>

#define GETN    (256*384 + 128) // размер данных (кадр + заголовок в 128 байт)

char *dev = "/dev/ugen0.1"; // устройство

char code0[] = { 0x00 }; // байт "0" для записи в устройство
char code1[] = { 0x01 }; // байт "1" для записи в устройство

unsigned char bufin[GETN]; // буфер для чтения данных
unsigned char *bufer = bufin+128; // буфер без первых 128 байт (так надо)
int uh; // handler для работы с устройством

// полезная процедурка аварийного завершения с сообщением
void die(char *s) { printf(" %s\nBye!\n ",s); exit(0); }

int main(void) { int i,e,k=0;

// открыть сканер
if(-1 == (uh=open(dev, O_RDWR|O_NONBLOCK, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) )
die(" Device error ");

while(1) {
      // 1) записать в сканер "1"
      if(1 != (write(uh, code1, 1)) ) die(" error1 ");

      // 2) считать из сканера массив данных
      if( GETN != read(uh, bufin, GETN) ) die(" Error read data ");

      // 3) записать в сканер "0"
      if(1 != (write(uh, code0, 1)) ) die(" error0 ");

      // изучить данные: был там отпечаток?
      for(e=0,i=0;i<(256*384);i++) if(bufer[i]<210) e++; // вычисление
      printf(" Read(%d) = %d\n ",k++,e);
      if(e > 1000) break; // был отпечаток — выйти из бесконечного цикла
}

// закрыть сканер
close(uh);

// сохранить данные в файле
FILE *fc; fc=fopen('finger.dat','wb'); fwrite(bufer, 1, 256*384, fc); fclose(fc);
}

Проблема вот в чем: сканер иногда виснет во время передачи данных. И тогда read навсегда зависает — ожидает поступления данных до бесконечности, а сканер их уже никогда не даст, потому что думает, что уже дал, или просто не расслышал команду. Надо прекратить read, и заново записать 0, затем 1 — и начать заново. Как это сделать? Например подглядывать как-то не блокируя, есть ли данные. Либо вышибать read через 2 секунды, если завис. Пробовал select — но не осилил, не понимаю формата. Пробовал через библиотеки асинхронного чтения aio.h — не осилил.

Я специально вылизал вышеприведенную программу, в ней нет лишнего, она работает, только изредка виснет. Пожалуйста, кто мудр в этом, напишите мне, как ее исправить. Только очень прошу: конкретные строчки для копипаста, чтоб все сразу заработало. Потому что я идиот, не знаю английского и путаюсь в мнемониках C, и советы типа «копай в направлении NONBLOCK» или «select(тырыпыры), затем read» мне не помогут, помогут только полностью написанные строчки. Заранее спасибо. Да: gcc, Freebsd 6.2, если это имеет значение.

Также буду благодарен за совет, какой командой (не на C, из консоли) можно "перевоткнуть" /dev/ugen0.1, как если бы выдернул из usb и воткнул заново. Иногда это нужно тоже.

<< предыдущая заметка следующая заметка >>
пожаловаться на эту публикацию администрации портала
архив понравившихся мне ссылок

Комментарии к этой заметке автоматически отключились, потому что прошло больше 7 дней или число посещений превысило 20000. Но если что-то важное, вы всегда можете написать мне письмо: lleo@lleo.me