Categorias
dicas ip microterminal rede tcp windows

Comunicando com microterminal em ASP.NET

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:

  1. Criar uma ??nica aplica????o que ir?? receber e enviar os dados;
  2. 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!”

15 respostas em “Comunicando com microterminal em ASP.NET”

Eli,

Como disse, tentei fazer a struct para o TTABSOCK contudo ela n??o funcionou quando referenciado pela DLL. Como n??o tive tempo de dar continuidade e fazer uma an??lise mais detalhada, parei o artigo nessa parte. Mesmo que a estrutura esteja certa pode ser algum detalhe que n??o estamos vendo que pode estar dando erro na hora de fazer a convers??o da mesma estrutura que est?? na DLL com a que desenvolvemos. Se tiver sorte na gera????o dessa estrutura, nos envie para que publiquemos aqui.

Muito bom post! Gostei da solu????o.
Mas tenho uma d??vida: se eu tenho mais de 1 terminal tem alguma ideia de como posso fazer pra evitar conflitos e separar os dados vindos de cada um?

Estevam

Estevam, para mais de um voc?? tem duas solu????es:
1) usar lock para bloquear o acesso individualmente
2) conhecendo o ip, adicionar ifs para trabalhar com seus dados separados
Veja tamb??m que h?? um loop at?? 255 na implementa????o onde percorro toda a faixa de ips na rede localizando os terminais. Na fun????o mt_getkey(i, rntStr), por exemplo, o i corresponde ?? posi????o que um terminal est?? naquele momento. Logo s?? irei trabalhar com ele.
Essa ?? uma forma de trabalhar separada. N??o sei como ?? seu neg??cio mas creio que a fun????o, como est??, j?? pode lhe ajudar.

Valeu. Obrigado pela resposta. Estou seguindo sua sugest??o e usando um timer pra cada terminal, filtrando pelo id (ou pelo ip). Acho que vai dar certo.

Obs.: tamb??m estou tendo problemas com o TTABSOCK – usado por mt_connectlist. Como tem mais gente tendo problemas com isso, segue o que consegui at?? o momento:

[declara????es]

[DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern IntPtr mt_connectlist();

[StructLayout(LayoutKind.Auto)]
public struct TTABSOCK
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 255)]
public byte[] TSOCK;
}
public TTABSOCK tabcon;

[…]
[execu????o]:

IntPtr ptr;
terminaisListBox.Items.Clear();
ptr = mt_connectlist();
tabcon = (TTABSOCK)Marshal.PtrToStructure(ptr, typeof(byte[]));

Mas ainda estou com erro de AccessViolationException. Alguma ideia?

Estevam

Estevam, j?? me relataram v??rios problemas quando utilizada essa classe. Tamb??m tive alguns probleminhas com ela. Cheguei a utiliz??-la mas de forma simpl??ria. Esse erro ?? quando tenta ler ou gravar em mem??ria que n??o foi alocada/n??o tem acesso.
No caso deve ser quando tenta invocar a estrutura vinda da DLL na qual s??o "diferentes" (seu uso), ou seja, a estrutura da TTABSOCK.
Veja mais detalhes do erro no link: http://msdn.microsoft.com/pt-br/library/system.accessviolationexception.aspx

Caso algu??m mais tenha problemas com TTABSOCK e alguns m??todos da DLL pmtg da Gertec:

Usando a ferramenta P/Invoke Interop Assistant (dispon??vel na internet), consegui gerar as assinaturas corretas:

public partial class NativeMethods
{
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct TTABSOCK
{
/// DWORD[255]
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 255, ArraySubType = System.Runtime.InteropServices.UnmanagedType.U4)]
public uint[] ip;
}

/// Return Type: int
///ID: int
///String: BYTE*
///OnOff: BOOL->int
///PassWord: BOOL->int
[System.Runtime.InteropServices.DllImportAttribute("pmtg.dll", EntryPoint = "mt_seteditstring", CallingConvention = System.Runtime.InteropServices.CallingConvention.StdCall)]
public static extern int mt_seteditstring(int ID,
ref byte String,
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)] bool OnOff,
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)] bool PassWord);
[System.Runtime.InteropServices.DllImportAttribute("pmtg.dll", EntryPoint = "mt_connectlist", CallingConvention = System.Runtime.InteropServices.CallingConvention.StdCall)]
public static extern void mt_connectlist(ref TTABSOCK tab);

/// Return Type: char*
///oip: DWORD->unsigned int
[System.Runtime.InteropServices.DllImportAttribute("pmtg.dll", EntryPoint = "mt_inet_ntoa_inv", CallingConvention = System.Runtime.InteropServices.CallingConvention.StdCall)]
public static extern System.IntPtr mt_inet_ntoa_inv(uint oip);
}

Aqui funcionou!

Amigo, seu post foi de suma import??ncia para varias pessoas, gostaria de saber se voc?? n??o quer fazer essa mesma coisa com um outro modelo de microterminal da marca Willtech, pois o produto n??o tem dll e trabalha com protocolo VT-100.

Ol?? An??nimo, que bom que o post serviu. Para implementa????o do modelo da Willtech, h?? dois exemplos no site http://www.willtech.com.br/downloads/ mas que ?? em Delphi. Na comunica????o usa-se TCP/IP para envio das mensagens e usa Socket para isso. Poderia implementar nas escuras mas n??o teria como testar pois precisaria adquirir o produto. Nesse artigo, fiz a implementa????o pois o cliente forneceu o aparelho.
Ent??o veja se consegue converter a implementa????o em Delphi para C#. N??o parece ser dificil, pois Delphi ?? semelhante a Pascal e com VB. S?? s??o chatinhas algumas fun????es nesse meio…

Deixe um comentário para An??nimo Cancelar resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *