Quem já foi em supermercado e nunca viu aquelas
maquininhas que o operador fica digitando? Pois é... estamos falando dela mesma. Parece ser fácil seu uso, mas quem começa a trabalhar com elas é de perder os cabelos.
Nesse artigo veremos como comunicar com um microterminal via TCP/IP e trocar informações (ida e volta). Para isso vamos utilizar o modelo da
Gertec MT 720. Uma breve descrição do aparelho e seu uso (retirado
daqui):
"O MT 720 é um excelente microterminal que opera em rede Ethernet com protocolos TCP-IP. Seu teclado com 20 teclas programáveis pode ser utilizado com funções específicas de atalhos para agilizar a operação.
As teclas re-legendáveis permitem a identificação da função de cada tecla. O display com back light (iluminado), com 20 caracteres por 2 linhas, permite facilmente a visualização da informação, principalmente em ambientes que possuem pouca iluminação, como bares noturnos, por exemplo.
Através de uma porta de teclado (AT/PS2) e mais 3 portas Seriais (RS-232) é possível a conexão de periféricos como: Leitor de Código de Barras, Display de Cliente, Balança, Impressora, etc.
O MT 720 é ideal para aplicações de Cartão de Consumo, soluções para Bares, Lanchonetes, Restaurantes Self-Service, Livrarias, Papelarias, apontamento de produção em Indústrias."
Na própria página do dispositivo (citada acima) tem alguns
downloads de arquivos, dentre eles alguns códigos-fontes com exemplos de como fazer a comunicação bem como realizar as operações pelas quais foi criado. Um porém: só tem disponíveis nas linguagens C++, Delphi e VB (não é VB.NET).
Daí pensamos:
"sem problemas! é só converter pra VB.NET a partir do VB"... Também pensei nisso e não consegui! Dando uma olhada de perto no código-fonte dá para saber que as proezas encontradas são só possíveis por artifícios que a linguagem oferece: por exemplo, ponteiros. Quem já programou em VB via a grande flexibilidade da linguagem de fazer tudo o que quer e do jeito que era mais conveniente. Maravilha! Pena que tenhamos que seguir certos padrões. Fica a dica: se não quiser perder tempo, pegue logo o código prontinho lá na página do fabricante (vem também no CD quando compra o aparelho) e utilize. De preferência use o Delphi e em seguida em VB. Se quiser aventurar vamos com C#...
Se escolheu C# siga lendo pois, em diante, veremos como fazer... Teremos os seguintes objetivos na implementação:
- Criar uma única aplicação que irá receber e enviar os dados;
- Exibir o que foi digitado tanto no microterminal quanto no monitor.
Instalação
Leia o manual do usuário
aqui.
Em resumo: ligue o microterminal na rede elétrica e conecte na porta traseira um cabo RJ-45 no dispositivo e a rede. Em seguida configure, no microterminal, o IP do Servidor (no meu caso, considerei minha máquina local com o IP 192.168.1.100, por exemplo). Demais configurações a seu gosto...
Implementação
Criemos um
Windows Form. Coloquei alguns controles para embelezar a aplicação...
O mais importante é adicionar um objeto
Timer. Os demais coloquei para gerar a aplicação final (que ficará no
tray - perto do relógio - e outras coisas
fru-frus). Configure seu
Timer com
Interval de 50. Pegue a DLL
pmtg.dll e copie para sua aplicação. Eu disse copie! Você não conseguirá aplicar
Reference sobre ela. Clique com o botão direito sobre a DLL e escolha
Properties. Em
Copy to Output Directory coloque
Copy Always.
Agora vamos ao código! Clique sobre o
WinForm e escolha
View Code. Cole os códigos abaixo para que possamos usá-las no form:
// VARIÁVEIS
IntPtr v_Hwnd;
int statusCard;
int statusSerial;
int MsgReceiveData = 1;
string[] dados = new string[255];
// INICIALIZAÇÃO DE FUNÇÕES EXTERNAS
[DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern int mt_startserver(IntPtr mywhnd, int conecmsg, int commumsg);
[DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern void mt_finishserver();
[DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern int mt_getkey(int id, StringBuilder str);
[DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern int mt_backspace(int id);
[DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern int mt_dispstr(int id, string str);
[DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern int mt_dispch(int id, char ch);
[DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern int mt_dispclrln(int id, int lin);
[DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]]
public static extern int mt_gotoxy(int id, int lin, int col);
Em seguida adicionamos as duas funções primordiais: início (quando carregar o formulário) e término (quando fechar o formulário):
private void MicroTerminal_Load(object sender, EventArgs e)
{
v_Hwnd = this.Handle;
statusCard = 0;
statusSerial = 0;
if (mt_startserver(v_Hwnd, 0, MsgReceiveData) == 1)
{
temporizadorLista.Enabled = true;
}
else
MessageBox.Show("Não foi possível carregar os módulos de conexão à leitora!");
}
private void MicroTerminal_FormClosed(object sender, FormClosedEventArgs e)
{
temporizadorLista.Enabled = false;
mt_finishserver();
}
Lembrando que esses eventos devem estar configurados (não é apenas copiar e colar o código, lembra? deve-se indicar lá em
Events do
Form). Com isso, ao fazer o primeiro teste, sua aplicação já estará recebendo dados do microterminal. Em seguida devemos adicionar um evento
Tick ao
Timer. Ou seja, a cada 50 milisegundos (lembra que colocamos com esse valor) irá ser executado um determinado método.
Antes disso vamos criar um método que irá limpar a tela do microterminal e reiniciar os dados de entrada:
private void ReiniciaEntrada(int i)
{
// Limpa as duas linhas e o que foi armazenado
dados[i] = "";
mt_dispclrln(i, 1);
mt_dispclrln(i, 2);
// Coloca o cursor na primeira linha e prepara o display
mt_gotoxy(i, 1, 0);
mt_dispstr(i, "Numero: ");
mt_gotoxy(i, 2, 0);
}
Enfim adicionamos o código que irá ler temporariamente cada leitora conectada à rede e coletar/processar os dados de acordo com o que desejar. No meu caso deixei o seguinte:
private void temporizadorLista_Tick(object sender, EventArgs e)
{
StringBuilder rntStr = new StringBuilder();
int i = 0;
// Loop em toda faixa de Ips úteis: cada leitora conectada na rede
while (i < 255)
{
// Captura algo do teclado
if (mt_getkey(i, rntStr) == 1)
{
string chrAsHex = ((int)rntStr[0]).ToString("x");
// Entrada do display caso seja um número
if ((chrAsHex == "3030") || (chrAsHex == "30") || (chrAsHex == "31") || (chrAsHex == "32") || (chrAsHex == "33") || (chrAsHex == "34") || (chrAsHex == "35") || (chrAsHex == "36") || (chrAsHex == "37") || (chrAsHex == "38") || (chrAsHex == "39"))
{
if (dados[i].Length >= 20)
dados[i] = dados[i].Substring(0, 19) + rntStr[0];
else
dados[i] += rntStr[0];
mt_dispch(i, rntStr[0]);
}
// Se for um ENTER, dá a entrada na tela para mostrar
else if (chrAsHex == "d")
{
// Captura e trata a entrada
if (dados[i] != "")
{
// Faz o processamento do que desejar em dados[i]
}
// Limpa tela
ReiniciaEntrada(i);
}
// Se for um ESC, apaga tudo
else if (chrAsHex == "1b")
{
// Limpa tela
ReiniciaEntrada(i);
}
// Se for backspace apaga último caractere do display
else if (chrAsHex == "8")
{
if (dados[i].Length > 0)
dados[i] = dados[i].Substring(0, dados[i].Length - 1);
mt_backspace(i);
}
// Se apertar * toca o som
else if (chrAsHex == "2a")
{
// Toca um sonzinho... depois publico o código de tocar som!
}
}
i++;
}
}
Feito! Rode sua aplicação e digite algo no teclado do microterminal e verá que o que está sendo digitado está indo tanto para a aplicação quanto para o display (no microterminal). A saída seria algo do tipo:
Se precisar de saída na tela crie um outro
WinForm que ocupe toda tela (sua) e captura o que está no display do microterminal. Assim é mais fácil! Ou faça do jeito que sua imaginação mandar! O mais difícil já passou...
Para quem quiser capturar os IPs de cada microterminal, utilize os métodos:
[DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern TTABSOCK mt_connectlist();
ou
[DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern StringBuilder mt_ipfromid(int id);
Nessas funções tem algumas particularidades muito chatinhas de se trabalhar (veja no manual das funções) por isso deixei de lado. Principalmente a classe:
[StructLayout(LayoutKind.Sequential)]
public struct TTABSOCK
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 255)]
public UInt32[] TSOCK;
}
Quem quiser se aventurar nela, fica aí a dica. Esse artigo merecia até uma vídeo-aula, mas a preguiça às vezes é muito forte! É até legalzinho ter esses desafios, mas às vezes se torna muito chato quando não consegue. Enfim, quanto menos se estressar, melhor! Então tente usar as implementações que já a
Gertec já disponibilizou, caso não queira aventurar, a menos que precise de algo mais específico.
Falar que nem
Marcoratti:
"eu sei, é apenas ASP.NET, mas eu gosto!"