Dias atrás alguém me pediu para desvendar o SIGAACD. Mas o que (…) é o SIGAACD? Descobri que nada mais é do que um módulo do Protheus para o gerenciamento de microterminais através do protocolo TELNET usando VT100.
Bem, desafio aceito.
Em busca de material…. humpf… não encontrei…. vou usar a metodologia иαldσ dj (fuça..fuça.. fuça.. fuça… _VTOUT() humm… isso é interessante… fuça… fuça… fuça.. _VTREADBYTES( NR , NR , NR ) hum isso não entendi…. fuça.. fuça.. fuça.. fuça.. _VTGETBYTE(), opa, isso eu entendi…).
Bem, já tenho o fragmento do material mínimo necessário para programar um emulador. Vamos entender o que é TELNET e VT100 e, depois, ao nosso exemplo:
“Telnet é um protocolo cliente-servidor usado para permitir a comunicação entre computadores ligados numa rede (exemplos: rede local / LAN, Internet), baseado em TCP.” (fonte:
Wikipédia)
O Protheus, emula um terminal no padrão VT100.
Para habilitar o protocolo TELNET no Protheus é bem simples. Basta incluir as chaves abaixo no arquivo ini.
[TELNET] Enable=1 Environment=<Environment a ser utilizado> Main=<Funcao a ser executada> NPARAMS=<Numeros de Paramentros da Funcao. Habilita Param1, Param2, ParamN…> port=<Numero da porta de escuta. Padrao 23> |
Feito isso, basta reiniciar o server Protheus que o TELNET Server será habilitado. Observe:
As funções passíveis a MAIN são: SIGAACDM, SIGAACDT e SIGAACD
Para SIGAACDM teremos a seguinte saída:
[TELNET] Enable=1 Environment=ndj_01 Main=SIGAACDM NPARAMS=0 ;port=24 |
usando o TELNET da Microsoft teremos:
Para SIGAACDT teremos:
[TELNET] Enable=1 Environment=ndj_01 Main=SIGAACDT NPARAMS=0 |
e, para SIGAACD
[TELNET] Enable=1 Environment=ndj_01 Main=SIGAACD NPARAMS=0 |
Legal. Mas como é que o Protheus faz isso?
Simples, quando recebe uma conexão via TELNET ele “desperta” 3 funções:
-
_VTOUT() :: Envia as mensagens para o terminal;
-
_VTREADBYTES( NR , NR , NR ) : Faz a leitura Buferizada das informações digitadas no Terminal; e
-
_VTGETBYTE() : Faz a leitura byte a byte do que foi digitado no Terminal
No exemplo de código que vou apresentar utilizarei a Primeira e a última, uma vez que ainda não compreendi totalmente os parâmetros da _VTREADBYTES. Ela possui 3 parâmetros formais do tipo numérico: n1, n2, n3 (mas o que fazer com eles ainda me é uma incógnita);
Para entender o que enviar para o Terminal TELNET pesquisei:
-
-
-
-
-
-
-
E, para o exemplo de programa, peguei emprestado o código do jogo “Guess” implementado no Harbour por Eddie Runia (
Harbour Project: $Id: guess.prg 14676 2010-06-03 16:23:36Z vszakats $).
Para o nosso Emulador TELNET do jogo Guess, teremos as seguintes configurações:
[TELNET] Enable=1 Environment=ndj_01 Main=U_MAINGUESS NPARAMS=0 ;port=24 |
e, para joga-lo:
… depois de algum tempo
Usando
PuTTY: A Free Telnet/SSH Client:
… depois de algumas tentativas…:
O Código? ei-lo:
#INCLUDE "INKEY.CH" #INCLUDE "PROTHEUS.CH"
#DEFINE OPC_GUESS 1
Static __cESC := Chr(K_ESC) //27 Static __lForceExit := .F.
/*( Procedure: U_MAINGUESS Autor: Marinaldo de Jesus Data: 15/11/2011 Descricao: Exemplo de emulador TELNET Sintaxe: U_MAINGUES
[TELNET] Enable=1 Environment=ndj_01 Main=U_MAINGUES NPARAMS=0 ;port=24 ;//DEFAULT 23 )*/ Procedure U_MAINGUESS()
Local nOpc := Val( Read( 0 , 0 , "Iniciar o Jogo? 0-Nao; 1-Sim <enter>: " ) )
DO CASE CASE ( nOpc == OPC_GUESS ) Guess() OTHERWISE IKillApp(.T.) ENDCASE
/*( Guess a number Date : 1999/04/22 My first application (big word) written in Harbour Written by Eddie Runia <eddie@runia.com> www - http://harbour-project.org
Placed in the public domain )*/ Static Function Guess() Local cPick := "" Local cAttempts := "" Local nSeed := Randomize( 1 , 256 ) Local nPick := 0 Local nAttempts := 0
Local nflGuessed
Local lContinue := .T. Clear()
Say( 0 , 0 , "Welcome to guess a number...." ) Say( 1 , 0 , "You have to guess a number between 0 and 255 [ press <esc> <enter> to exit ]" )
While !( IKillApp() ) While ( lContinue ) nSeed := Randomize( 1 , 256 ) nflGuessed := 0 nAttempts := 0 While ( nflGuessed == 0 ) Clear(3,0,3) nPick := Val( Read( 3 , 0 , "Value <enter>: " ) ) IKillApp() cPick := AllTrim( Str( nPick , 3 , 0 ) ) cAttempts := AllTrim( Str( ++nAttempts , 4 , 0 ) ) DO CASE CASE ( nPick > 255 ) Clear(5,0) Say(5,0,cPick + " More than 255" ) CASE ( nPick < 0 ) Clear(5,0) Say(5,0,cPick + " Less than 0") CASE ( nPick > nSeed ) Clear(5,0) Say(5,0,"Try lower: " + cPick ) CASE ( nPick < nSeed ) Clear(5,0) Say(5,0,"Try higher: " + cPick ) OTHERWISE Say(5,0,"Congratulations, you've, AFTER " + cAttempts + " ATTEMPTS, guessed the number " + cPick ) Sleep(300) nflGuessed := 1 ENDCASE End While Clear(7,0) lContinue := ( Upper( Read( 7 , 0 , "Continue Y/N <enter> : " ) ) == "Y" ) Clear(5,0) IF !( lContinue ) IKillApp(.T.) EndIF End While End While
Return( .T. )
/*( Function: Say Autor: Marinaldo de Jesus Data: 15/11/2011 Descricao: Direciona Saida para o Terminal TELNET Sintaxe: Say(nRow,nCol,cOut) )*/ Static Function Say(nRow,nCol,cOut) DEFAULT cOut := "" SetPos(nRow,nCol) Return(_QQOut(@cOut))
/*( Function: Clear Autor: Marinaldo de Jesus Data: 15/11/2011 Descricao: Limpa o Console do Terminal TELNET Sintaxe: Clear(nTop,nLeft,nBottom,nRight) )*/ Static Function Clear(nTop,nLeft,nBottom,nRight) DEFAULT nTop := 0 DEFAULT nLeft := 0 DEFAULT nBottom := 300 DEFAULT nRight := 80 Return(Scrool(nTop,nLeft,nBottom,nRight))
/*( Function: Scrool Autor: Marinaldo de Jesus Data: 15/11/2011 Descricao: Limpa o Console do Terminal TELNET Sintaxe: Scrool(nTop,nLeft,nBottom,nRight) )*/ Static Function Scrool(nTop,nLeft,nBottom,nRight) Local nT Local cSPC := Space(nRight-nLeft) For nT := nTop To nBottom Say(nT,nLeft,cSPC) Next nT Return(SetPos(nTop,nLeft))
/*( Function: _QQOut Autor: Marinaldo de Jesus Data: 15/11/2011 Descricao: Direciona Saida para o Terminal TELNET Sintaxe: _QQOut(cOut) )*/ Static Function _QQOut(cOut) Local cVTFun := "_VTOUT" Return(&cVTFun.(cOut,))
/*( Function: SetPos Autor: Marinaldo de Jesus Data: 15/11/2011 Descricao: Define o Posicionamento da Linha/Coluna para a Mensagem Sintaxe: SetPos(nRow,nCol)
)*/ Static Function SetPos(nRow,nCol) Local cR Local cC Local cSetPos DEFAULT nRow := 0 DEFAULT nCol := 0 cR := Alltrim( Str( nRow , 4 , 0 ) ) cC := Alltrim( Str( nCol , 4 , 0 ) ) cSetPos := __cESC cSetPos += "[" cSetPos += cR cSetPos += ";" cSetPos += cC cSetPos += "H" Return(_QQOut(cSetPos))
/*( Function: Read Autor: Marinaldo de Jesus Data: 15/11/2011 Descricao: Le Byte a Byte o Conteudo Digitado no Terminal Sintaxe: Read( nRow , nCol , cOut ) )*/ Static Function Read( nRow , nCol , cOut ) Local cVTFun := "_VTGETBYTE" Local cByte := "" Local cBuffer := "" Local lExit := .F. Say( nRow , nCol , cOut + cBuffer ) While !( lExit ) cByte := &cVTFun.(,) lExit := ( Asc(cByte) == K_ENTER ) IF ( cByte == __cESC ) __lForceExit := .T. EndIF IF !( lExit ) IF ChkAsc( cByte , .F. ) cBuffer += cByte EndIF EndIF End While Return( cBuffer )
/*( Function: IKillApp Autor: Marinaldo de Jesus Data: 15/11/2011 Descricao: Verifica se deve finalizar a aplicacao Sintaxe: IKillApp(lKillApp) )*/ Static Function IKillApp(lKillApp) Local cMsg := "bye bye. Exiting..." Local lKilled := .F. DEFAULT lKillApp := .F. IF (; ( lKillApp ); .or.; ( __lForceExit ); ) lKilled := .T. lKillApp := .T. Clear(0,0) IF ( __lForceExit ) cMsg := "<esc> " + cMsg EndIF Say( 5 , 0 , cMsg ) Sleep(800) KillApp(lKillApp) EndIF Return( lKilled )
Return |
Quer o original? Siga o link:
totvs-advpl-naldodj
[]s
иαldσ dj
P.S.:
1 ) Obviamente que o exemplo é bem simples. Para ter um microterminal completo terá que programar um bucado. As funções básicas estão descritas acima. Basta, agora, pesquisar, estudar, praticar, estudar mais um pouco, praticar, praticar e praticar. Uma dica, tente converter o código manklala.prg ($Id: mankala.prg 14676 2010-06-03 16:23:36Z vszakats $) também de Eddie Runia para o Harbour-Projetct, para ser jogado via TELNET.
Muito chato (pra nao falar outra coisa), programar para esse VT100. Prefiro fazer 50 telas modelo3, 15 relatórios em TReport e 5 WebServices, do que pegar outro desenvolvimento desse.
ResponderExcluirFicadica!
...mas parabéns!
[Funcao VTMODELO()]
ResponderExcluirAcesse o link http://tdn.totvs.com/kbm#24886
e veja o conteudo colaborativo..
Valeu pela dica. Mas preferi não usar as funções em ADVPL para o modelo e sim funções da API (que não estou documentadas no TDN ou, se estão, são de acesso restrito). Temos que conhecer o "cerne" para dominar.
ResponderExcluir[]s
иαldσ dj
Certamente!
ResponderExcluirHehehee.. testei a parada mestrao Lee!!!! E "funfou"... hehehe! Grande abraço e parabens Mestrao!!!!
ResponderExcluir...enfim, resumindo a cena... VT100 ou caso queriam SIGAACD, é um terreno onde você irá fazer muita, aliás, MUUUUUUUUITA.. gambiarra para chegar ao resultado esperado.
ResponderExcluirAinda é uma tecnologia bem falha, incompleta que deve ter sido abandonada pela Totvs. O desenvolvimento é indicado para casos simples, com uma complexidade muito baixa... se seu 'amigo' consultor prometer uma FERRARI ao cliente no SIGAACD.. prepare-se por que você tera de construi-la com um chiclete, um grampo e uma linha de costura.
Para ajudar ainda tem a função VTDEBUG que monta a tela do cliente vt100 no formato advpl como no putty,teraterm ou telnet, mas para facilitar o debug dos programas linha a linha.
ResponderExcluirO vt100 é mais utilizado com telas pequenas como de coletores de dados e microterminais, com interface simples e tráfego de dados minimo.
Eu fiz um programa usando as funções VT100, como faço para emular ele em tela de ADVPL?
ResponderExcluirTem que emular via TelNet. conforme exemplo.
ExcluirNaldo,
Excluirquando tento emular via Telnet não consigo utilizar as setas direcionais do teclado, fica aparecendo uns códigos (^[[A, ^[[B...). Não sei como resolver isso.
poderia me ajudar?
Obrigado!
Conseguiu solucao?
ExcluirTeste o VTDEBUG , este é o simulador do ACD
ResponderExcluirSrs. o Haldo me conhece, já fizemos curso de C# juntos e também trabalhamos na TOTVS. Porém a diferença é que eu trabalhei diretamente no desenvolvimento padrão ACD. Pois bem, o VTDEBUG não era uma solução oficial para permitir debugar programas padrão vt100, porém como a tecnologia da TOTVS na época não criou uma soluções, nós da equipe resolvemos criar o VTDEBUG temporariamente, que pelo que percebi permanece até hoje. Eu sei que existem diversas deficiências, mas peço que todos entendam que isso era somente uma ferramenta interna para permitir a equipe debugar e infelizmente isso ficou como padrão. Eu tenho versões POWER do VTDEBUG, mas é claro não é oficial. É importante informar que o Alex Sandro Valário também esta trabalhando comigo na iMind, caso tenha dúvida acesse: http://imind.com.br.
ResponderExcluirOlá Erike Yuri,
ResponderExcluirEstou tentando usar um VT100 (putty, terminator e outros) no Linux, porém as setas direcionais do teclado não funcionam, fica aparecendo uns códigos (^[[A, ^[[B...). Não sei como resolver isso.
poderia me ajudar?
Obrigado!
conseguiu alguma solucao?
ExcluirOlá Naldo, boa tarde! Tudo bem? Então, desculpe-me a ousadia, mas estou quebrando a cuca com um bug no uso dos terminais VT100, que temos espalhados na área de produção. Pois bem, existe a rotina padrão de apontamento da produção, T_ACDA020, executando normalmente. Resolvi customizar uma rotina, tendo como base o T_ACDA020.PRG, criei uma cópia do mesmo, cuja finalidade é aceitar a digitação/captura do peso da balança, para um produto que possui duas unidades de medida em que a 1ª está em metro e a 2ª está em KG. Acontece que a peça é grande, em forma de rolo, o usuário não tem como medir a peça, nesse caso resolvemos capturar o peso que etá relacionado à 2ª unidade, convertendo para a 1ª unidade em metros (MT). Realizamos testes via VTDEBUG e a rotina executou perfeitamente e acompanhamos as movimentações geradas, tudo ok e validado com o usuário. No entanto, na hora de colocar em produção, o programa não executa no microterminal VT100. Caso tenhas alguma solução aplicada para algum caso semelhante, poderias compartilhar?
ResponderExcluirQue bacana saber que até hoje usam o VTDEBUG... Eu criei o VTDEBUG, que permite debugar programas do ACD e também desenvolver sem a necessidade de ter um coletor portatil (embora isso já se conseguisse com o TELNET). Também criei o TERDEBUG que permite debugar e desenvolver sem a necessidade de um microterminal. Na época, quando me colocaram pra desenvolver algo com microterminal só dava pra desenvolver com um instalado e não tinha como debugar, o código de desenvolvimento era muito complexo. Muito bacana saber que 17 anos depois ainda está em uso.
ResponderExcluirJunto com a equipe do ACD, na época gerenciado pelo Alfredo e coordenado pelo Alex Sandro, desenvolvemos praticamente todas as rotinas das telas apresentadas acima e através daquelas três funcoes basicas VTOUT, VTREADBYTES e VTGET fizemos as GETS, SAYS, ACHOICE e mais praticamente todas as funcoes equivalentes do CLIPPER que eram necessárias pra tornar o código fonte o mais próximo possivel do ADVPL... Fizemos o mesmo para microterminal também... Fiquei contente de encontrar esse post...
abraços
Eduardo Motta
eduardo@emotta.com.br
ola pessoal ,obrigado pelo post.. deu uma certa luz. Estou tendo muito problema no SIGAACD + TELNET em que as setas nao funcionam ou em outros programas aparecem ^b ou algo assim. Tem alguma forma de corrigir esse parametro?
ResponderExcluirPara navergar no TelNet do Windows para o VT100, com as teclas direcionais do teclado (setas).
ResponderExcluir- Acessar no menu horizontal:
-- Terminal;
-- Preferences;
-- Marcar o checkbox "VT100 Arrows".