Salve salve pessoal…
Hoje trago para vocês um exemplo de como fazer uma integração com balanças no Protheus.
Eu havia desenvolvido muito tempo atrás, um fonte que fazia integração com balanças, sendo que usei como referência um artigo disponível no advpl-protheus.blogspot.com.
Depois de um tempo, um amigo meu deu uma manutenção no código, e por último dei uma recauchutada no fonte e uma limpeza nele.
Nesse fonte é testado balanças da Jundiaí, Líder, Confiança e Toledo, mas a grande maioria a parametrização é igual, sendo que usamos parâmetros para pegar informações.
Abaixo o fonte completo (junto com a versão original de 2013, desculpem a lógica usada na época rs):
//Bibliotecas #Include "Protheus.ch" //Constantes #Define MAX_BUFFER 22 //Máximo de caracter por linha (buffer) #Define MSECONDS_WAIT 5000 //Tempo de espera /*/{Protheus.doc} zTstBalan Função para testar a integração com balanças @author Atilio @since 07/04/2018 @version 1.0 @type function /*/ User Function zTstBalan() Local nPesoRet := 0 nPesoRet := u_zLeBalanca("TOLEDO") Alert("Peso Lido: "+cValToChar(nPesoRet)) Return nPesoRet /*/{Protheus.doc} zLeBalanca Função para fazer uma integração com balança via AdvPL @author Atilio @since 07/04/2018 @version 1.0 @param cMarca, characters, Marca da balança que será lida @type function @obs O fonte original foi criado em 2013, depois foi adaptado por Wallace Freitas em 2015, e agora está sendo reescrito em 2018 As marcas testadas foram: - Toledo - Líder - Jundiaí - Confiança Foi usado como base, o artigo disponível em http://advpl-protheus.blogspot.com.br/2013/09/integracao-protheus-x-balanca-via.html @example u_zLeBalanca("TOLEDO") /*/ User Function zLeBalanca(cMarca) Local nPesoRet Local cPorta := "" Local cVelocid := "" Local cParidade := "" Local cBits := "" Local cStopBits := "" Local cFluxo := "" Local nTempo := "" Local cConfig := "" Local lRet := .T. Local nH := 0 Local cBuffer := "" Local nPosFim := 0 Local nPosIni := 0 Local nX := 0 Local cPesoLido := "" Default cMarca := "" //Se houver marca If ! Empty(cMarca) cMarca := Upper(Alltrim(cMarca)) //Pegando a porta padrão da balança cPorta := SuperGetMV("MV_X_PORTA",.F.,"COM1") //Modelo Confiança If (cMarca=="CONFIANCA") cVelocid := SuperGetMV("MV_X_VELOC", .F., "9600") //Velocidade cParidade := SuperGetMV("MV_X_PARID", .F., "n") //Paridade cBits := SuperGetMV("MV_X_BITS", .F., "8") //Bits cStopBits := SuperGetMV("MV_X_SBITS", .F., "1") //Stop Bit cFluxo := SuperGetMV("MV_X_FLUXO", .F., "") //Controle de Fluxo nTempo := SuperGetMV("MV_X_TEMPO", .F., 5) //Tempo //Jundiaí ElseIf (cMarca == "JUNDIAI") cVelocid := SuperGetMV("MV_X_VELOC", .F., "9600") //Velocidade cParidade := SuperGetMV("MV_X_PARID", .F., "n") //Paridade cBits := SuperGetMV("MV_X_BITS", .F., "8") //Bits cStopBits := SuperGetMV("MV_X_SBITS", .F., "0") //Stop Bit cFluxo := SuperGetMV("MV_X_FLUXO", .F., "") //Controle de Fluxo nTempo := SuperGetMV("MV_X_TEMPO", .F., 5) //Tempo //Toledo ElseIf (cMarca == "TOLEDO") cVelocid := SuperGetMV("MV_X_VELOC", .F.,"4800") //Velocidade cParidade := SuperGetMV("MV_X_PARID", .F.,"N") //Paridade cBits := SuperGetMV("MV_X_BITS", .F.,"8") //Bits cStopBits := SuperGetMV("MV_X_SBITS", .F.,"1") //Stop Bit cFluxo := SuperGetMV("MV_X_FLUXO", .F.,"") //Controle de Fluxo nTempo := SuperGetMV("MV_X_TEMPO", .F.,5) //Tempo //Líder ElseIf (cMarca == "LIDER") cVelocid := SuperGetMV("MV_X_VELOC", .F.,"4800") //Velocidade cParidade := SuperGetMV("MV_X_PARID", .F.,"N") //Paridade cBits := SuperGetMV("MV_X_BITS", .F.,"8") //Bits cStopBits := SuperGetMV("MV_X_SBITS", .F.,"1") //Stop Bit cFluxo := SuperGetMV("MV_X_FLUXO", .F.,"") //Controle de Fluxo nTempo := SuperGetMV("MV_X_TEMPO", .F.,5) //Tempo //Qualquer balança que utilize porta serial Else cVelocid := SuperGetMV("MV_X_VELOC", .F.,"9600") //Velocidade cParidade := SuperGetMV("MV_X_PARID", .F.,"n") //Paridade cBits := SuperGetMV("MV_X_BITS", .F.,"8") //Bits cStopBits := SuperGetMV("MV_X_SBITS", .F.,"1") //Stop Bit cFluxo := SuperGetMV("MV_X_FLUXO", .F.,"") //Controle de Fluxo nTempo := SuperGetMV("MV_X_TEMPO", .F.,5) //Tempo EndIf //Se a marca da balança for LIDER If cMarca == "LIDER" //Montando a configuração (Porta:Velocidade,Paridade,Bits,Stop) cConfig := cPorta+":"+cVelocid+","+cParidade+","+cBits+","+cStopBits //Guarda resultado se houve abertura da porta lRet := MSOpenPort(@nH,cConfig) //Se não conseguir abrir a porta, mostra mensagem e finaliza If !lRet MsgStop("<b>Falha</b> ao conectar com a porta serial. Detalhes:"+; "<br><b>Porta:</b> " +cPorta+; "<br><b>Velocidade:</b> " +cVelocid+; "<br><b>Paridade:</b> " +cParidade+; "<br><b>Bits:</b> " +cBits+; "<br><b>Stop Bits:</b> " +cStopBits,"Atenção") Else //Realiza a leitura For nX := 1 To 50 //Obtendo o tempo de espera antes de iniciar a leitura da balança Sleep(nTempo) MSRead(nH,@cBuffer) //Se a linha retornada for igual ao tamanho limite, encerra o laço If Len(AllTrim(cBuffer)) == MAX_BUFFER Exit EndIf Next nX //Verifica onde começa o "E" e diminui 1 caracter nPosFim := At("E", cBuffer) - 1 //Obtendo apenas o peso da balança cPesoLido := StrTran(AllTrim(SubStr(cBuffer,2,nPosFim)),".","") EndIf //Encerra a conexão com a porta MSClosePort(nH,cConfig) //Se for a Toledo ElseIf cMarca == "TOLEDO" //Montando a configuração (Porta:Velocidade,Paridade,Bits,Stop) cConfig := cPorta+":"+cVelocid+","+cParidade+","+cBits+","+cStopBits //Guarda resultado se houve abertura da porta lRet := MSOpenPort(@nH,cConfig) lOk := .T. //Se não conseguir abrir a porta, tenta mais uma vez, remapeando If ! lRet //Força o fechamento e abertura da porta novamente WaitRun("NET USE "+cPorta+": /DELETE") WaitRun("NET USE "+cPorta+" ") lOk := MSOpenPort(@nH,cConfig) If !lOk MsgStop("<b>Falha</b> ao conectar com a porta serial. Detalhes:"+; "<br><b>Porta:</b> " +cPorta+; "<br><b>Velocidade:</b> " +cVelocid+; "<br><b>Paridade:</b> " +cParidade+; "<br><b>Bits:</b> " +cBits+; "<br><b>Stop Bits:</b> " +cStopBits,"Atenção") EndIf EndIf If lOk //Inicializa balança MsWrite(nH,CHR(5)) nTaman := 16 //Realiza a leitura For nX := 1 To 50 //Obtendo o tempo de espera antes de iniciar a leitura da balança e realiza a leitura Sleep(nTempo) MSRead(nH,@cBuffer) //Obtendo os caracteres inciais cBuffer := AllTrim(SubStr(AllTrim(cBuffer),1,nTaman)) //Se a linha retornada for igual ao tamanho limite If Len(AllTrim(cBuffer)) >= nTaman Exit EndIf Next nX //Verifica onde começa o "q" e soma 2 espaços nPosIni := At("q",cBuffer)+2 //Obtendo apenas o peso da balança cPesoLido := SubStr(cBuffer,nPosIni,nPosIni+3) EndIf //Encerra a conexão com a porta MSClosePort(nH,cConfig) EndIf //Converte o peso obtido para inteiro e o atribui a variavel de retorno nPesoRet := Val(cPesoLido) //Outras balanças Else //Montando a configuração (Porta:Velocidade,Paridade,Bits,Stop) cConfig := cPorta+":"+cVelocid+","+cParidade+","+cBits+","+cStopBits //Guarda resultado se houve abertura da porta lRet := msOpenPort(@nH,cConfig) //Se não conseguir abrir a porta, mostra mensagem e finaliza If(!lRet) //Se for barra, tentar na confiança, depois na jundiai MsgStop("<b>Falha</b> ao conectar com a porta serial. Detalhes:"+; "<br><b>Porta:</b> " +cBPorta+; "<br><b>Velocidade:</b> " +cBVeloc+; "<br><b>Paridade:</b> " +cBParid+; "<br><b>Bits:</b> " +cBBits+; "<br><b>Stop Bits:</b> " +cBStop,"Atenção") cLido := 0 EndIf //Se estiver OK If lRet If (cMarca == "JUNDIAI" .Or. cMarca == "CONFIANCA") //Mandando mensagem para a porta COM msWrite(nH,Chr(5)) Sleep(nTempo) //Pegando o tempo final cSegNor:=Time() cSegAcr:=SubStr(Time(),1,5)+":"+cValToChar(Val(SubStr(Time(),7,2)) + nTempo) If (cMarca == "JUNDIAI") //Enquanto os tempos forem diferentes While(cSegNor != cSegAcr) //Lendo os dados msRead(nH,@cBuffer) //Se não estiver em branco if(!Empty(cBuffer)) cLido := Alltrim(cBuffer) EndIf //Atualizando o tempo cSegNor:=SubStr(cSegNor,1,5)+":"+cValToChar(Val(SubStr(cSegNor,7,2)) + 1) EndDo //Senão, se for confiança, enquanto o tamanho for menor, ler o conteúdo ElseIf (cMarca == "CONFIANCA") cLido := '' nCont := 1 //Enquanto os tempos forem diferentes While(Len(cLido) < 16) //Lendo os dados msRead(nH,@cBuffer) Sleep(200) //Somando o valor lido com o buffer cLido += cBuffer //Aumentando o contador nCont++ If nCont >= 30 If MsgYesNo('Houve <b>30 tentativas</b> de ler o peso, deseja parar?','Atenção') cLido:=Space(17) Exit Else nCont := 1 EndIf EndIf EndDo EndIf cLido := Upper(cLido) nPosFim := (At('K',cLido) - 1) //Pegando a Posição Inicial For nAux:=1 To Len(cLido) //Se o caracter atual estiver contido no intervalo de 0 a 9 e ponto If(SubStr(cLido,nAux,1) $ '0123456789.') nPosIni:=nAux Exit EndIf Next nPesoRet := Val(cLido) EndIf EndIf msClosePort(nH,cConfig) EndIf Return nPesoRet /* Abaixo o Fonte Original, escrito em 2013: /*---------------------------------------------------------------------------------------------* | Autor: Daniel Atilio | | Data: 01/10/2013 | | Desc: Função que lê a porta serial e retorna a string obtida | | Ref.: http://advpl-protheus.blogspot.com.br/2013/09/integracao-protheus-x-balanca-via.html | *---------------------------------------------------------------------------------------------* / //Bibliotecas #Include "Protheus.ch" #Include "RwMake.ch" //Funçãos que lê a porta serial e retorna a string lida //lTipo == .F. -> Irá retornar a string completa //lTipo == .T. -> Irá retornar somente o valor numérico //cBalanca == 'NOME_BALANCA' //cTipoVar == 'N' -> retorna apenas número (Val) //cCom == 'PORTA_CONEXAO' User Function LeSerial(lTipo,cBalanca,cTipoVar,cCom) Local cLido:="" Local cCfg :=""//"COM1:4800,n,8,1" Local nH:=0 Local lRet:=.F. Local cSegAcr:="" Local cSegNor:="" Local cBuffer:="" Local lTipo := .F. Local nPeso Private cBPorta := cCom //Porta Private cBVeloc //Velocidade Private cBParid //Paridade Private cBBits //Bits Private cBStop //Stop Bit Private cBContr //Controle de Fluxo Private cBTempo //Tempo Private cPeso := "" //Parâmetros, utilizados na Confiança (modelo 312-E) If (cBalanca=="CONFIANCA") If Empty(cBPorta) cBPorta := SuperGetMV("MV_X_CPOR",.F.,"COM1") //Porta EndIf cBVeloc := SuperGetMV("MV_X_CVEL",.F.,"9600") //Velocidade cBParid := SuperGetMV("MV_X_CPAR",.F.,"n") //Paridade cBBits := SuperGetMV("MV_X_CBIT",.F.,"8") //Bits cBStop := SuperGetMV("MV_X_CSTO",.F.,"1") //Stop Bit cBContr := SuperGetMV("MV_X_CCON",.F.,"") //Controle de Fluxo cBTempo := SuperGetMV("MV_X_CTEM",.F.,"5") //Tempo ElseIf (cBalanca == "JUNDIAI") If Empty(cBPorta) cBPorta := SuperGetMV("MV_X_JPOR",.F.,"COM4") //Porta EndIf cBVeloc := SuperGetMV("MV_X_JVEL",.F.,"9600") //Velocidade cBParid := SuperGetMV("MV_X_JPAR",.F.,"n") //Paridade cBBits := SuperGetMV("MV_X_JBIT",.F.,"8") //Bits cBStop := SuperGetMV("MV_X_JSTO",.F.,"0") //Stop Bit cBContr := SuperGetMV("MV_X_JCON",.F.,"") //Controle de Fluxo cBTempo := SuperGetMV("MV_X_JTEM",.F.,"5") //Tempo ElseIf (cBalanca == "TOLEDO") If Empty(cBPorta) cBPorta := SuperGetMV("MV_X_TPOR",.F.,"COM3") //Porta EndIf cBVeloc := SuperGetMV("MV_X_TVEL",.F.,"4800") //Velocidade cBParid := SuperGetMV("MV_X_TPAR",.F.,"S") //Paridade cBBits := SuperGetMV("MV_X_TBIT",.F.,"7") //Bits cBStop := SuperGetMV("MV_X_TSTO",.F.,"1") //Stop Bit cBContr := SuperGetMV("MV_X_TCON",.F.,"") //Controle de Fluxo cBTempo := SuperGetMV("MV_X_TTEM",.F.,"5") //Tempo //Qualquer balança que utilize porta serial Else If Empty(cBPorta) cBPorta := SuperGetMV("MV_X_BPOR",.F.,"COM1") //Porta EndIf cBVeloc := SuperGetMV("MV_X_BVEL",.F.,"9600") //Velocidade cBParid := SuperGetMV("MV_X_BPAR",.F.,"n") //Paridade cBBits := SuperGetMV("MV_X_BBIT",.F.,"8") //Bits cBStop := SuperGetMV("MV_X_BSTO",.F.,"1") //Stop Bit cBContr := SuperGetMV("MV_X_BCON",.F.,"") //Controle de Fluxo cBTempo := SuperGetMV("MV_X_BTEM",.F.,"5") //Tempo cLido := 0 lTipo := .T. //Não passa pela leitura EndIf //Montando a configuração (Porta:Velocidade,Paridade,Bits,Stop) cCfg:=cBPorta+":"+cBVeloc+","+cBParid+","+cBBits+","+cBStop //Guarda resultado se houve abertura da porta lRet := msOpenPort(@nH,cCfg) //Se não conseguir abrir a porta, mostra mensagem e finaliza If(!lRet) //Se for barra, tentar na confiança, depois na jundiai MsgStop("<b>Falha</b> ao conectar com a porta serial. Detalhes:"+; "<br><b>Porta:</b> " +cBPorta+; "<br><b>Velocidade:</b> " +cBVeloc+; "<br><b>Paridade:</b> " +cBParid+; "<br><b>Bits:</b> " +cBBits+; "<br><b>Stop Bits:</b> " +cBStop,"Atenção") cLido := 0 EndIf //Se estiver em branco o conteúdo If !lTipo .And. lRet If (cBalanca == "JUNDIAI" .Or. cBalanca == "CONFIANCA") //Mandando mensagem para a porta COM msWrite(nH,Chr(5)) If(cBalanca == "JUNDIAI") //Jundiai, 200 milissegundos. Confiança, 500 Sleep(200) ElseIf(cBalanca == "CONFIANCA") Sleep(500) EndIf //Pegando o tempo final cSegNor:=Time() cSegAcr:=SubStr(Time(),1,5)+":"+cValToChar(Val(SubStr(Time(),7,2)) + Val(cBTempo)) If (cBalanca == "JUNDIAI") //Enquanto os tempos forem diferentes While(cSegNor!=cSegAcr) //Lendo os dados msRead(nH,@cBuffer) //Se não estiver em branco if(!Empty(cBuffer)) cLido:=Alltrim(cBuffer) //Exit EndIf //Atualizando o tempo cSegNor:=SubStr(cSegNor,1,5)+":"+cValToChar(Val(SubStr(cSegNor,7,2)) + 1) EndDo //Senão, se for confiança, enquanto o tamanho for menor, ler o conteúdo ElseIf (cBalanca == "CONFIANCA") cLido := '' nCont := 1 //Enquanto os tempos forem diferentes While(Len(cLido) < 16) //Lendo os dados msRead(nH,@cBuffer) sleep(200) //Somando o valor lido com o buffer cLido+=cBuffer //Aumentando o contador nCont++ If nCont >= 30 If MsgYesNo('Houve <b>30 tentativas</b> de ler o peso, deseja parar?','Atenção') cLido:=Space(17) Exit Else nCont := 1 EndIf EndIf EndDo EndIf //Se for a Jundiai If (cBalanca == "JUNDIAI") SoPeso2(@cLido) ElseIf (cBalanca == "CONFIANCA") SoPeso(@cLido) //Alert(cLido) EndIf //Se estiver em branco, retorna erro If Empty(cLido) cLido="ERRO NA LEITURA" EndIf cLido:=StrTran(cLido,',','.') //Se o retorno for numérico If cTipoVar == 'N' cLido := Val(cLido) Else __nVal := Val(cLido) cLido := cValToChar(__nVal) EndIf cLido := Int(cLido) ElseIf (cBalanca == "TOLEDO") For nX := 1 To 50 Sleep(100) MSRead(nH,@cBuffer) //If(!Empty(cBuffer)) If(Len(cBuffer) == 16) cPeso += cValToChar(cBuffer) Exit EndIf Next nX nPosIni := At("`",cPeso) nPosIni := nPosIni+2 cPeso := SubStr(cPeso,nPosIni,6) MSClosePort(nH,cCfg) If !Empty(cPeso) nPeso := Val(cPeso)/100 nPeso := Round(nPeso,0) cLido := nPeso Else nPeso:=0 cLido := nPeso EndIf EndIf EndIf msClosePort(nH,cCfg) Return cLido //Função que retorna somente o peso lido da String Static Function SoPeso(cVar) Local nPosIni := 0 Local nPosFim := 0 Local nAux := 0 //Pegando a Posição Final, se tiver k minúsculo, será a posição, dele, senão o maiúsculo nPosFim:=Iif(('k' $ cVar),(At('k',cVar) - 1),(At('K',cVar) - 1)) //Pegando a Posição Inicial For nAux:=1 To Len(cVar) //Se o caracter atual estiver contido no intervalo de 0 a 9 e ponto If(SubStr(cVar,nAux,1) $ '0123456789.') nPosIni:=nAux Exit EndIf Next //Pegando somente o valor cVar:=SubStr(cVar,nPosIni,nPosFim-nPosIni) Return //Função que retorna somente o peso lido da String Static Function SoPeso2(cVar) Local nPosIni := 0 Local nPosFim := 0 Local nAux := 0 //Alert("'"+cVar+"'") //Pegando a Posição Final, se tiver k minúsculo, será a posição, dele, senão o maiúsculo nPosFim:=Iif(('k' $ cVar),(At('k',cVar) - 1),(At('K',cVar) - 1)) //Pegando a Posição Inicial For nAux:=1 To Len(cVar) //Se o caracter atual estiver contido no intervalo de 0 a 9 e ponto If(SubStr(cVar,nAux,1) $ '0123456789.') nPosIni:=nAux Exit EndIf Next //Pegando somente o valor cVar:=SubStr(cVar,nPosIni,nPosFim-nPosIni+1) //Alert("'"+cVar+"'") Return */
Bom pessoal, por hoje é só.
Abraços e até a próxima.
Excelente post. Por coincidência, tive meu primeiro contato com uma balança e uma integração em Delphi que não tava funcionando, daí vou fazer no Protheus. Muito obrigado pela ajuda!
Bom dia Fábio.
Eu que agradeço.
Um grande abraço jovem.
Que estranho, quando recém viramos para versão 12, nossos fontes que integravam com a balança toledo/alpha, pararam de funcionar, em chamado eles acusaram que descontinuaram a função MSOpenPort e tal, agora me deparo com isso, vou realizar os testes por aqui.
Boa noite João.
Bem estranho mesmo, pois conheço vários lugares com o Protheus 12 que ainda usam a MSOpenPort. Eles podem ter alegado que a função foi descontinuada (por questões de suporte), mas de funcionamento, acho que ela continua normalmente.
Um grande abraço jovem.
Excelente post! Congrats! Aqui a nossa balança é conectada na porta USB por meio de um adaptador que converte de serial para USB. Quando tento fazer a leitura do peso da balança ele retorna uns caracteres muito esquisitos. Sabe o que pode ser? Veja:
À†žÀ†ž‡À†žÀ†žÏÀ†žæàÀ†žùÀ†ž‡À†žÀÀ†ž‡À†žÀÀ†žùÀ†ž‡À†žƒÀÀ†ž‡À†žÀÀ†žÏÀ†ž‡À†ž‡À†ž‡fÀ†ž‡À†ž‡ÀÀ†ž‡À†ž‡ÀÀ†ž‡À†žÀÀ†ž‡À†žÀÀ†ž‡fÀ†žæàÀÀ†žÀ†žÏÀ†ž‡À†žÀ†ž‡À†žÀÀ†ž‡À†žÀÀ†ž‡À†ž‡À†žÀÀ†žÀ†žæàÀÀ†žùÀ†ž‡À†žÀÀ†ž‡À†žÀÀ†ž‡fÀ†žæàÀÀ†žÀ†žùÀ†žÀÀ†ž‡À†ž‡À†žÀ†žÏÀ†ž‡À†ž‡À†ž‡À†žÀÀ†žÀ†žÀÀ†ž‡fÀ†žæàÀÀ†žùÀ†ž‡À†žÀÀ†ž‡À†žÀÀ†žùÀ†ž‡À†žÀÀ†ž‡À†žÀÀ†žÏÀ†ž‡À†ž‡À†ž‡À†žÀ†žÏÀ†ž‡À†ž‡À†ž‡À†žÀ†ž‡À†ž‡À†ž‡À†ž‡À†žÀ†žÏ
Alguma ideia de como resolver?
Bom dia Marcos, tudo joia?
Opa, obrigado pelo feedback.
No caso, se você tentar ler direto pela porta serial (talvez usar um PC mais antigo, ou usar mesmo uma placa serial conectada na placa mãe do computador ao invés de conversor USB), a leitura funciona normalmente?
Uma forma de testar também, é que algumas fabricantes, disponibilizam um software de teste de leitura da porta serial, se a fabricante dessa balança disponibilizar, ai tenta fazer o teste direto por ela, pois pode ser que esse conversor USB esta embaralhando a mensagem.
Tenha uma ótima e abençoada terça feira.
Um grande abraço.