From: Marcelo B. <md...@ma...> - 2000-10-23 00:17:43
|
Hello Coders, I return today for the serial ports programming, after sometime... Well, I begin to re-run and re-test my routines, and then I found a problem... oh sux! My problem are relationship with: * BLOCKING or NOM_BLOCKING mode to read() in the serial port versus * effective control of timeouts in the serial port read(); O problema consiste no seguinte: * No modo BLOCKING, uma chamada a read() para N_BYTES na serial, só retornará quando todos os N_BYTES forem lidos; * Existem os elementos da estrutura termios c_cc[VTIME] e c_cc[VMIN] com os quais setaria-se: c_cc[VTIME] = tempo de timeout em 1/100s c_cc[VMIN] = número de caracteres para serem lidos O "Serial Programming Guide for POSIX Operating Systems" diz o seguinte: _____________________ Setting Read Timeouts UNIX serial interface drivers provide the ability to specify character and packet timeouts. Two elements of the c_cc array are used for timeouts: VMIN and VTIME. Timeouts are ignored in canonical input mode or when the NDELAY option is set on the file via open or fcntl. VMIN specifies the minimum number of characters to read. If it is set to 0, then the VTIME value specifies the time to wait for every character read. Note that this does not mean that a read call for N bytes will wait for N characters to come in. Rather, the timeout will apply to the first character and the read call will return the number of characters immediately available (up to the number you request). If VMIN is non-zero, VTIME specifies the time to wait for the first character read. If a character is read within the time given, any read will block (wait) until all VMIN characters are read. That is, once the first character is read, the serial interface driver expects to receive an entire packet of characters (VMIN bytes total). If no character is read within the time allowed, then the call to read returns 0. This method allows you to tell the serial driver you need exactly N bytes and any read call will return 0 or N bytes. However, the timeout only applies to the first character read, so if for some reason the driver misses one character inside the N byte packet then the read call could block forever waiting for additional input characters. VTIME specifies the amount of time to wait for incoming characters in tenths of seconds. If VTIME is set to 0 (the default), reads will block (wait) indefinitely unless the NDELAY option is set on the port with open or fcntl. -------------------------8<------------------------------ Bom, eu encontrei dois problemas para fazer isso funcionar do jeito que eu queria: * O tempo de timeout é considerado apenas para o primeiro caracter a ser recebido. Por exemplo, se voce setar o read para ler 20 bytes, e o VTIME para 10 (1 segundo), haveria um timeout de 1 segundo apenas para a leitura do primeiro caracter. Se esse caracter não fosse lido, read retorna erro após decorrido o timeout. Já se o primeiro byte for lido ok, antes de estourar o timeout, o read só retorna após ler TODOS os outros 19 bytes solicitados. Ou seja: se houver uma falha na transmissão, e alguns bytes forem perdidos, o read ficava preso forever..... :( * Não posso ter o read() bloqueando... Então, abro a porta em modo NOM BLOCKING, só que nesse modo acontece o seguinte: * o meu read() não fica bloqueado eternamente se não receber. :) * os tempos de timeout não são respeitados :( tipo: seto um timeout de 5 segundos pra ler um byte. mando o read() ler esse byte. se tem byte, ele me retorna esse byte. se nao tem byte, ele retorna imediatamente (não respeita timeout :( Bom, pesquisei sobre a função ioctl(), com a qual pode-se ler o fd da porta, e saber quantos bytes tem no buffer de rx. Ok, wow, beleza, se eu sei quantos bytes estão disponíveis antes de fazer a leitura, posso eu mesmo implementar meu controle de tempo de timeout. Seria algo do tipo time() da vida, eu leria o time, colocava numa variavel, loop pra ficar fazendo ioctl() na porta e lendo novamente o time, comparando com o de inicio, e estourando o timeout se for o caso. Minha duvida: com a funcao time() me parece que tenho resolução minima na ordem de segundos... Isso não me atende, preciso de algo para medir tempos da ordem de milisegundos ou microsegundos. Alguém conhece uma função para isso? Tou pesquisando aqui, mas se alguém ja souber o caminho das pedras é uma boa. Eu já tentei uns outros trecos malucos com tcsetattr() e fcntl() mas ainda não foi por ai.... A idéia é conseguir implementar um controle fino na operação da serial, timeouts e coisa e tal, de modo a evitar qualquer tipo de problema, pras rotinas de detecção e ATI's pro modem. Ah, coloquei o Serial Prog guide em: http://www.geocities.com/serialcoder/serial.html se alguem tiver a fim de dar uma olhada... Valeu ai pessoal, e desculpem pela aporrinhação. []s -- #=-=[ ser...@us... ]=-=+=#=--------------=# | Marcelo D. Beckmann --user[]="#173935"-- | | CL5 2.2.14 | md...@ma... UIN [53189692]----+ | Slack 7 2.2.13 # - =-#--=[ http://marcelobeckmann.cjb.net ]=--#-=======*======-# + `|' | 233MMX 32MB 8.4+3.2GB Quantum Fireball ] /V\ #------------------466.94----[ OPL3SAx TGUI9680 2MB 33600 ] /(.)\ "Estamos de volta aos tempos em que os homens eram homens ] ^`~´^ e programavam seus próprios drivers de dispositivo."L.T. ] #-====-#----=[ serialcoder ]=- + -=[ http://wm.themes.org ]=-----' RTS-[CTS]-DLE-STX-17-39-35-CRC-F6-66-DLE-ETX-/RTS-[/CTS-RTS]-CTS-[ACK] |