Revista Do Linux
 


 
EDIÇÃO DO MÊS
 CD do Mês


 Mensagem ao Leitor
 Capa
 Entrevista
 Estudo de Caso 1
 Estudo de Caso 2
 Documentação
 Hardware
 Software
 Programação
 Redes
 Ferramenta
 Desenvolvimento
 Segurança
assinantes
 

Automação Comercial e o Linux

A área de automação comercial espera ansiosamente a chegada do Linux, para oferecer preços menores ao cliente final

Estamos iniciando uma era de software livre, onde há uma maior integração entre programadores do mundo inteiro, onde há troca de informações essenciais, para o crescimento de todos.

Faremos uma pequena contribuição para esta era, escrevendo um HOW-TO para impressoras fiscais inicialmente, no qual pretendemos demonstrar o funcionamento com acesso direto à porta serial, depois daremos continuidade para outros periféricos de automação comercial, onde ainda não vimos nada de novo para Linux nessa área.

Pretendemos demonstrar alguns exemplos em C, usando o gcc 2.95.3 e o CL 7.0 kernel 2.2. Acreditamos que não haverá problemas com outras versões do kernel ou distribuições. Caso algo ocorra, nos avise.

Comunicação Serial RS-232

Impressoras Fiscais não funcionam tal como as impressoras normais ligadas a paralelas ou seriais. A comunicação com elas é um tanto quanto anormal. Todas as impressoras fiscais possuem um protocolo de comunicação do tipo serial, baseado na revisão C. Por isso, a interface usada é o padrão RS-232-C.

Os periféricos fiscais possuem um conjunto de comandos que interagem com a impressora executando ações.

Iniciando

Para começar a comunicação serial é necessário que, na abertura da porta, sejam feitas algumas configurações, pois a impressora trabalha com RTS/CTS, 8 bits de dados, sem paridade, um start bit e um stop bit (8N1).


#include <termios.h>

#include <sys/ioctl.h>

#include <fcntl.h>


#define DISPOSITIVO "/dev/ttyS0"

int porta;

struct termios opcoes[2]; /* Struct de armazena a configuração da porta de comunicação*/

int AbrePorta()

{

if ((porta = open( DISPOSITIVO, O_RDWR | O_NOCTTY | O_NDELAY)) == -1)

{

error("Não foi possível abrir a porta");

exit(1);

}

tcgetattr(porta, &opcoes[OLD]);  /* Vamos deixar tudo do jeito que encontramos vamos fazer uma cópia da configuração da porta atual*/

memcpy(&opcoes[NEW], &opcoes[OLD], sizeof( struct termio )); /* Feito a cópia*/


cfsetispeed(&opcoes[NEW], B9600);

cfsetospeed(&opcoes[NEW], B9600);


opcoes[NEW].c_iflag = IGNBRK;

opcoes[NEW].c_oflag = 0;

opcoes[NEW].c_cflag |= CS8;

opcoes[NEW].c_cflag |= B9600;

opcoes[NEW].c_cflag |= CRTSCTS;

opcoes[NEW].c_lflag |= NOFLUSH;

opcoes[NEW].c_line = 0;

opcoes[NEW].c_cc [VMIN] = 0;

opcoes[NEW].c_cc [VTIME] = 2;


tcsetattr(porta, TSCANOW, &opcoes[NEW]);


return(0);

}

Protocolo de comunicação da impressora

Neste exemplo, estamos utilizando a impressora Bematech MP-20 FI. O protocolo de comunicação desta impressora fiscal é estruturado em blocos e possui a seguinte forma:

Um comando de inicialização o STX constante 0x02(hex), que indica início de transmissão; logo em seguida, deve ser enviado um NBL, que é o byte menos significativo, da soma do número de bytes que serão enviados (soma de CMD + CSL + CSH); depois, seguindo a ordem, deve ser enviado um NBH, byte mais significativo, da soma do número de bytes que serão enviados (soma de CMD + CSL + CSH); logo em seguida, deve ser enviado o CMD, a seqüência de bytes que compõe o comando e seus parâmetros. Depois de enviado o comando, deve ser enviado o CSL, que é o byte menos significativo da soma dos valores dos bytes que compõem o comando e seus parâmetros e, por último, o CSH, byte mais significativo, da soma dos valores dos bytes que compõem o comando e seus parâmetros.

No exemplo, vamos enviar um comando que retorne vários bytes pela própria saída serial, um comando de Leitura X, que mostra dados de totalizadores parciais da impressora. Entre outros dados, é um bom comando para testes.Os comandos seguem a tabela:

STX NBL NBH CMD CSL CSH
HEX 0x02 0x04 0x00 1B 06 21 00

Enviando comandos

O envio de comandos pode ser feito facilmente.



int LeituraX[7] = {  0x02,  /* Set de comando   */

0x04,  /* para a leitura X */

0x00,

0x1b,

0x45,

0x60,

0x00

};


int EnvioDeComando( void )

{

int i = 0;

             for (; i <= 7; i++)

{

write(porta, LeituraX[i], 1);

}

fcntl(porta, F_SETFL, FNDELAY);

}

Leitura dos comandos

A leitura dos comandos funciona com o mesmo princípio da escrita (write - read), a impressora irá enviar um ACK (ok - a impressora entendeu o que você disse) seguido de dois outros bytes de status [ST1][ST2]. E começa a enviar os dados solicitados em formato ASCII até a ocorrência de um ETX(fim 0x03).



int LeDadosImpressora( void )

{

int valor = 0;

int erro;

while (valor != 0x03)

{

if ((erro = read(porta, &valor, 1)) == 1)

printf("%c", valor);

}

}

Middware Facilitadores

A Bematech disponibiliza no site um executável para facilitar a criação do protocolo de comunicação entre a impressora e o software. Funciona da seguinte forma: a aplicação deve escrever um arquivo texto com o nome de bemafilx.cmd, que será lido pelo executável bemafilx.out - isto ajuda muito na identificação dos bytes da impressora e formatação de números - alguns retornos de valores da impressora são em formato BCD, sendo que no bemafilx isto já vem formatado.

Com isso, é perfeitamente possível acessar a impressora fiscal sem perder muito tempo com configuração de porta, protocolo de comunicação, transformar 1 BCD em dois decimais, etc.. Até o monitoramento do HandShak da impressora é controlado por esta lib. No site da bematech você encontra um exemplo em C, completo e com fontes, para testes com a lib e entender seu funcionamento.

O uso do Linux deve aumentar muito no mercado de automação comercial, uma vez que falamos de software livre e baixo custo para o cliente final. As distribuições ainda não se deram conta deste novo nicho de mercado, e ainda não existe muita atenção para esta camada de desenvolvedores que se dedicam ao mercado de automação comercial. Segue abaixo o uso da lib.

LeituraX:



void UtilizandoBemafilx()

{

FILE *Handle

if ((Handle = fopen("bemafilx.cmd", "w")) == NULL)

{

printf("Erro ao criar o arquivo\n");

return;

}


fprintf( Handle, "\x1b|69|\x1b"); /*comando para

LeituraX na serial * ESC|69|ESC */

fclose( Handle);

system( "./bemafilx.out" );

return; //E o comando foi executado

}


Para saber mais


A Revista do Linux é editada pela Conectiva S/A
Todos os Direitos Reservados.

Política de Privacidade
Anuncie na Revista do Linux