Ir para conteúdo
  • Cadastre-se

dev botao

Balança Saturno - Dúvida - Retorno com caracteres/texto "[CR]" e "[LF]" na mensagem de Leitura de Peso.


Ver Solução Respondido por EMBarbosa,
  • Este tópico foi criado há 710 dias atrás.
  • Talvez seja melhor você criar um NOVO TÓPICO do que postar uma resposta aqui.

Recommended Posts

Boa tarde.

Estou realizando a integração do nosso sistema com uma balança da marca Saturno.

O padrão de resposta é composto juntamente com os indicadores de peso (Estabilidade do Peso e Estado da Balança) <CR>, PPPPPP, “E”/“O”, “L”/“B”, “_”, “ ”, <LF> (Conforme manual de integração), por exemplo: 023060EL_.
Onde: <CR> = Carriage Return (#13), PPPPPP = Peso na Balança, E/O = Estado do Peso, L/B = Estado da Balança, <LF> = Line Feed.

Testando o retorno por um outro software (Hercules SETUP utility) o retorno vem da seguinte forma no próprio Hercules utility006320OL_.
Copiando esse valor e informando no "Exemplo de Emulador de Balanças do ACBr" e enviando, o retorno é interpretado corretamente pela classe TACBrBALSaturno da Unit ACBrBALSaturno no nosso sistema e peso é exibido de forma correta.

Porém, ao realizar a leitura diretamente pela porta COM, o peso recebido fica zerado sempre, e observei que conforme o log de pesagem, ao que parece os textos [CR] e [LF] estão sendo recebidos de forma literal diretamente na resposta.

Realizei o tratamento no método InterpretarRepostaPeso, também removendo esses textos (CR e LF) e ao que parece, classe passou a interpretar corretamente nesse caso.

Obs.: Sei que CR = Carriage Return e LF = Line Feed, ambos sendo representados por #13 e #10 consecutivamente.

Segue abaixo onde foi modificado (duas últimas linhas).

if wAchouE or wAchouO then
  begin
    if wAchouE then
      wPosEO := Pos('E', UpperCase(aResposta))
    else
      wPosEO := Pos('O', UpperCase(aResposta));

    wResposta := Copy(aResposta, 0, wPosEO - 1);

    { Removendo caracteres especiais, caso encontre algum }
    wResposta := StringReplace(wResposta, '°', '0', [rfReplaceAll]);
    wResposta := StringReplace(wResposta, '±', '1', [rfReplaceAll]);
    wResposta := StringReplace(wResposta, '²', '2', [rfReplaceAll]);
    wResposta := StringReplace(wResposta, '³', '3', [rfReplaceAll]);
    wResposta := StringReplace(wResposta, '´', '4', [rfReplaceAll]);
    wResposta := StringReplace(wResposta, 'µ', '5', [rfReplaceAll]);
    wResposta := StringReplace(wResposta, '¶', '6', [rfReplaceAll]);
    wResposta := StringReplace(wResposta, '·', '7', [rfReplaceAll]);
    wResposta := StringReplace(wResposta, '¸', '8', [rfReplaceAll]);
    wResposta := StringReplace(wResposta, '¹', '9', [rfReplaceAll]);
    wResposta := StringReplace(wResposta, '[CR]', '', [rfReplaceAll]); // Modificado: Remover [CR]
    wResposta := StringReplace(wResposta, '[LF]', '', [rfReplaceAll]); // Modificado: Remover [LF]
  end

Segue um trecho do log de pesagem:

--------------------------------------------------------------------------------
ATIVAR - 04/04/22 14:22:34:841 - Modelo: Saturno - Porta: COM4         Device: BAUD=9600 DATA=8 PARITY=N STOP=1 HANDSHAKE= MAXBANDWIDTH=0 SENDBYTESCOUNT=0 SENDBYTESINTERVAL=0
--------------------------------------------------------------------------------

 - 14:22:35:862 RX <- [CR]023060EL_ [LF][CR]023060EL_ [LF][CR]023060EL_ [LF][CR]023060EL_ [LF][CR]023060EL_ [LF]
              UltimoPesoLido: 0 - Resposta: [CR]023060EL_ [LF][CR]023060EL_ [LF][CR]023060EL_ [LF][CR]023060EL_ [LF][CR]023060EL_ [LF]

O cliente ainda não informou o modelo em específico, mas assim que informar eu posto aqui.

Gostaria de saber se alguém já passou por isso, se pode ser alguma particularidade do módulo que envia os pacotes de dados (alguma configuração como ele envia a resposta de peso), ou se realmente a alteração que eu fiz faz sentido e pode ser incluída no trunk do ACBr?

Existe algum motivo do log gravar com esse [CR] e [LF] de forma literal?

Seguem em anexo o código fonte modificado e o log de pesagem.

Obrigado.

ACBrBALSaturno.pas Log-Pesagem.log Teste-Balanca-Saturno-HerculesUtility.txt

Editado por Leandro Araújo

Leandro Araújo, Analista de Sistemas.

Link para o comentário
Compartilhar em outros sites

Bom dia...

Consegui a informação referente ao Indicador de Pesagem (Marca: WEIGHTECH Modelo: WT27).

Na página oficial (https://www.weightech.com.br/indicador-de-pesagem-wt27) não consegui baixar o manual técnico, tive que encontrar em outra fonte.

Até onde entendi, era o que eu suspeitava, é possível personalizar um protocolo para envio dos dados.
No caso a mensagem de leitura respeita o protocolo da Saturno, mas parece que incluíram os textos [CR] e [LF] em forma literal ou então o ACBrBALClass está gravando dessa forma no log.

Estou analisando melhor os manuais obtidos, para ver se a modificação na interpretação da resposta de pesagem pode ser mantida na ACBrBALSaturno mesmo ou se é o necessário a criação de uma nova unit (caso os administradores aceitem a alteração).

Nos manuais que encontrei a mensagem de resposta parece ser no formato: 

Seguem as fontes de onde consegui os manuais:

WT27:
https://www.yumpu.com/pt/document/read/49558520/indicador-digital-wt27-manualpdf-weightech

WT27R
http://primaxbalancas.com.br/wp-content/uploads/Manual-técnico-WT-27-R.pdf
https://www.balancasrr.com.br/indicadoresweightech
https://drive.google.com/file/d/1rtKlOvnztysnJHhVMcvyqTVrlY8_-U1o/view

Obrigado.

Leandro Araújo, Analista de Sistemas.

Link para o comentário
Compartilhar em outros sites

Boa tarde...

Consegui identificar o que estava acontecendo.

O retorno recebido da balança continha CarriageReturn (#13) que não eram tratados quando entrava na primeira condição do if wAchouE or wAchouO then da função InterpretarRepostaPeso da unit ACBrBALSaturno, já que a remoção de caracteres especiais não estava tratando os caracteres #13 e #10, e no else estavam sendo tratados, fazendo que com dependendo do tamanho do pacote a conversão da resposta pela função StrToFloat sempre caísse no bloco Except.

Trecho anterior (Condição if da função InterpretarRepostaPeso:

if wAchouE then
      wPosEO := Pos('E', UpperCase(aResposta))
    else
      wPosEO := Pos('O', UpperCase(aResposta));

    wResposta := Copy(aResposta, 0, wPosEO - 1);

    { Removendo caracteres especiais, caso encontre algum }
    wResposta := StringReplace(wResposta, '°', '0', [rfReplaceAll]);
    wResposta := StringReplace(wResposta, '±', '1', [rfReplaceAll]);
    wResposta := StringReplace(wResposta, '²', '2', [rfReplaceAll]);
    wResposta := StringReplace(wResposta, '³', '3', [rfReplaceAll]);
    wResposta := StringReplace(wResposta, '´', '4', [rfReplaceAll]);
    wResposta := StringReplace(wResposta, 'µ', '5', [rfReplaceAll]);
    wResposta := StringReplace(wResposta, '¶', '6', [rfReplaceAll]);
    wResposta := StringReplace(wResposta, '·', '7', [rfReplaceAll]);
    wResposta := StringReplace(wResposta, '¸', '8', [rfReplaceAll]);
    wResposta := StringReplace(wResposta, '¹', '9', [rfReplaceAll]);
	// Sem tratamento para #13 e #10
  end

 

Acabei unificando a remoção dos caracteres especiais em uma function  interna SanitizarRespostaPeso(const aResposta: AnsiString) : AnsiString; e deixando nela também o tratamento para #13 e #10 (igual estava condição else) independente se na reposta de peso forem encontrados os indicadores de Estado do Peso (Caracteres "E" ou "O").

Também passei para remover os valores inválidos antes de tentar localizar os indicadores de Estado do Peso, pois imagino que de qualquer forma os caracteres especiais devem ser removidos nos dois casos (de ter localizado indicador de Estado do Peso ou não), caso isso estiver errado posso corrigir.

Modifiquei também para ler o valor do parâmetro aResposta somente no início, passando para a variável wResposta, para a partir disso o método somente trabalhar com o valor de wResposta já sanitizado.

Segue abaixo o trecho modificado de InterpretarRepostaPeso na unit ACBrBALSaturno:

function TACBrBALSaturno.InterpretarRepostaPeso(const aResposta: AnsiString): Double;
var
  wAchouE, wAchouO: Boolean;
  wPosEO: Integer;
  wResposta: AnsiString;

  function SanitizarRespostaPeso(const aResposta: AnsiString) : AnsiString;
  begin
    Result := Trim(aResposta);

    if Result = EmptyStr then
      Exit;

    Result := StringReplace(Result, '°', '0', [rfReplaceAll]);
    Result := StringReplace(Result, '±', '1', [rfReplaceAll]);
    Result := StringReplace(Result, '²', '2', [rfReplaceAll]);
    Result := StringReplace(Result, '³', '3', [rfReplaceAll]);
    Result := StringReplace(Result, '´', '4', [rfReplaceAll]);
    Result := StringReplace(Result, 'µ', '5', [rfReplaceAll]);
    Result := StringReplace(Result, '¶', '6', [rfReplaceAll]);
    Result := StringReplace(Result, '·', '7', [rfReplaceAll]);
    Result := StringReplace(Result, '¸', '8', [rfReplaceAll]);
    Result := StringReplace(Result, '¹', '9', [rfReplaceAll]);
    Result := StringReplace(Result, #13, '', [rfReplaceAll]);
    Result := StringReplace(Result, #10, '', [rfReplaceAll]);
    Result := StringReplace(Result, '[CR]', '', [rfReplaceAll]);
    Result := StringReplace(Result, '[LF]', '', [rfReplaceAll]);
  end;

begin
  Result := 0;
  wAchouE := False;
  wAchouO := False;
  wPosEO := -1;
  wResposta := EmptyStr;

  { Removendo caracteres especiais, caso encontre algum }
  wResposta := SanitizarRespostaPeso(aResposta);

  if (Trim(wResposta) = EmptyStr) then
    Exit;

  wAchouE := (Pos('E', UpperCase(wResposta)) > 0);
  wAchouO := (Pos('O', UpperCase(wResposta)) > 0);

  // Se encontrar a letra 'E' (Estável) ou 'O' (Oscilante), captura o peso da
  // posição 1 a 7 da string
  if wAchouE or wAchouO then
  begin
    if wAchouE then
      wPosEO := Pos('E', UpperCase(wResposta))
    else
      wPosEO := Pos('O', UpperCase(wResposta));

    wResposta := Copy(wResposta, 0, wPosEO - 1);
  end
  else
  begin
    wResposta := Copy(wResposta, 1, 9);
  end;

  if (Length(wResposta) > 0) then
  begin
    try
      Result := StrToFloat(wResposta);
    except
      case PadLeft(Trim(wResposta),1)[1] of
        'I': Result := -1;   { Instavel }
        'N': Result := -2;   { Peso Negativo }
        'S': Result := -10;  { Sobrecarga de Peso }
      else
        Result := 0;
      end;
    end;
  end
  else
    Result := 0;
end;

 

Segue em anexo o código-fonte completo alterado, caso puder ser analisado por algum committer do projeto ACBr e ser ou não adicionado no trunk.

Ainda com relação a gravação do log de pesagem, desculpem o equívoco, acredito que o componente está gravando correto, favor desconsiderar essa questão.

Qualquer dúvida ou erro estou a disposição.

Obrigado.

 

ACBrBALSaturno.pas

Editado por Leandro Araújo
Algumas informações eram desnecessárias e deixariam o post longo demais.
  • Curtir 1

Leandro Araújo, Analista de Sistemas.

Link para o comentário
Compartilhar em outros sites

  • Administradores

Obrigado pela contribuição, em breve será validada para possível inclusão ao svn

TK-2553

  • Curtir 1
Consultora SAC ACBr

Juliana Tamizou

Gerente de Projetos ACBr / Diretora de Marketing AFRAC
Ajude o Projeto ACBr crescer - Seja Pro

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.  Discord

Projeto ACBr - A maior comunidade Open Source de Automação Comercial do Brasil


Participe de nosso canal no Discord e fique ainda mais próximo da Comunidade !!

Link para o comentário
Compartilhar em outros sites

30 minutos atrás, Juliana Tamizou disse:

Obrigado pela contribuição, em breve será validada para possível inclusão ao svn

TK-2553

Bom dia..

Observei que o problema possivelmente poderia ser resolvido também alterando o valor das propriedades PosIni e PosFim do componente ACBrBAL e trabalhar com isso dentro da unit ACBrBALSaturno (que não deixa de ser inválido para uma implementação futura), mas ainda assim ficariam margens para erros inesperados, sem garantias de que o retorno possa vir no tamanho esperado/especificado, porém, conforme as alterações acima, agora a resposta de peso está sendo sanitizada (limpada) por completo, então no meu ver acredito que as melhorias possam ajudar de alguma forma.

Caso eu possa marcar o post como resolvido ou tenha que aguardar, me avisem por favor.

Obrigado!

Editado por Leandro Araújo
Tinha faltando uma informação.

Leandro Araújo, Analista de Sistemas.

Link para o comentário
Compartilhar em outros sites

  • 4 semanas depois ...
  • Consultores
  • Solution
Em 07/04/2022 at 16:31, Leandro Araújo disse:

Boa tarde...

Consegui identificar o que estava acontecendo.

O retorno recebido da balança continha CarriageReturn (#13) que não eram tratados quando entrava na primeira condição do if wAchouE or wAchouO then da função InterpretarRepostaPeso da unit ACBrBALSaturno, já que a remoção de caracteres especiais não estava tratando os caracteres #13 e #10, e no else estavam sendo tratados, fazendo que com dependendo do tamanho do pacote a conversão da resposta pela função StrToFloat sempre caísse no bloco Except.

Trecho anterior (Condição if da função InterpretarRepostaPeso:

if wAchouE then
      wPosEO := Pos('E', UpperCase(aResposta))
    else
      wPosEO := Pos('O', UpperCase(aResposta));

    wResposta := Copy(aResposta, 0, wPosEO - 1);

    { Removendo caracteres especiais, caso encontre algum }
    wResposta := StringReplace(wResposta, '°', '0', [rfReplaceAll]);
    wResposta := StringReplace(wResposta, '±', '1', [rfReplaceAll]);
    wResposta := StringReplace(wResposta, '²', '2', [rfReplaceAll]);
    wResposta := StringReplace(wResposta, '³', '3', [rfReplaceAll]);
    wResposta := StringReplace(wResposta, '´', '4', [rfReplaceAll]);
    wResposta := StringReplace(wResposta, 'µ', '5', [rfReplaceAll]);
    wResposta := StringReplace(wResposta, '¶', '6', [rfReplaceAll]);
    wResposta := StringReplace(wResposta, '·', '7', [rfReplaceAll]);
    wResposta := StringReplace(wResposta, '¸', '8', [rfReplaceAll]);
    wResposta := StringReplace(wResposta, '¹', '9', [rfReplaceAll]);
	// Sem tratamento para #13 e #10
  end

 

Acabei unificando a remoção dos caracteres especiais em uma function  interna SanitizarRespostaPeso(const aResposta: AnsiString) : AnsiString; e deixando nela também o tratamento para #13 e #10 (igual estava condição else) independente se na reposta de peso forem encontrados os indicadores de Estado do Peso (Caracteres "E" ou "O").

Também passei para remover os valores inválidos antes de tentar localizar os indicadores de Estado do Peso, pois imagino que de qualquer forma os caracteres especiais devem ser removidos nos dois casos (de ter localizado indicador de Estado do Peso ou não), caso isso estiver errado posso corrigir.

Modifiquei também para ler o valor do parâmetro aResposta somente no início, passando para a variável wResposta, para a partir disso o método somente trabalhar com o valor de wResposta já sanitizado.

Segue abaixo o trecho modificado de InterpretarRepostaPeso na unit ACBrBALSaturno:

function TACBrBALSaturno.InterpretarRepostaPeso(const aResposta: AnsiString): Double;
var
  wAchouE, wAchouO: Boolean;
  wPosEO: Integer;
  wResposta: AnsiString;

  function SanitizarRespostaPeso(const aResposta: AnsiString) : AnsiString;
  begin
    Result := Trim(aResposta);

    if Result = EmptyStr then
      Exit;

    Result := StringReplace(Result, '°', '0', [rfReplaceAll]);
    Result := StringReplace(Result, '±', '1', [rfReplaceAll]);
    Result := StringReplace(Result, '²', '2', [rfReplaceAll]);
    Result := StringReplace(Result, '³', '3', [rfReplaceAll]);
    Result := StringReplace(Result, '´', '4', [rfReplaceAll]);
    Result := StringReplace(Result, 'µ', '5', [rfReplaceAll]);
    Result := StringReplace(Result, '¶', '6', [rfReplaceAll]);
    Result := StringReplace(Result, '·', '7', [rfReplaceAll]);
    Result := StringReplace(Result, '¸', '8', [rfReplaceAll]);
    Result := StringReplace(Result, '¹', '9', [rfReplaceAll]);
    Result := StringReplace(Result, #13, '', [rfReplaceAll]);
    Result := StringReplace(Result, #10, '', [rfReplaceAll]);
    Result := StringReplace(Result, '[CR]', '', [rfReplaceAll]);
    Result := StringReplace(Result, '[LF]', '', [rfReplaceAll]);
  end;

begin
  Result := 0;
  wAchouE := False;
  wAchouO := False;
  wPosEO := -1;
  wResposta := EmptyStr;

  { Removendo caracteres especiais, caso encontre algum }
  wResposta := SanitizarRespostaPeso(aResposta);

  if (Trim(wResposta) = EmptyStr) then
    Exit;

  wAchouE := (Pos('E', UpperCase(wResposta)) > 0);
  wAchouO := (Pos('O', UpperCase(wResposta)) > 0);

  // Se encontrar a letra 'E' (Estável) ou 'O' (Oscilante), captura o peso da
  // posição 1 a 7 da string
  if wAchouE or wAchouO then
  begin
    if wAchouE then
      wPosEO := Pos('E', UpperCase(wResposta))
    else
      wPosEO := Pos('O', UpperCase(wResposta));

    wResposta := Copy(wResposta, 0, wPosEO - 1);
  end
  else
  begin
    wResposta := Copy(wResposta, 1, 9);
  end;

  if (Length(wResposta) > 0) then
  begin
    try
      Result := StrToFloat(wResposta);
    except
      case PadLeft(Trim(wResposta),1)[1] of
        'I': Result := -1;   { Instavel }
        'N': Result := -2;   { Peso Negativo }
        'S': Result := -10;  { Sobrecarga de Peso }
      else
        Result := 0;
      end;
    end;
  end
  else
    Result := 0;
end;

 

Segue em anexo o código-fonte completo alterado, caso puder ser analisado por algum committer do projeto ACBr e ser ou não adicionado no trunk.

Ainda com relação a gravação do log de pesagem, desculpem o equívoco, acredito que o componente está gravando correto, favor desconsiderar essa questão.

Qualquer dúvida ou erro estou a disposição.

Obrigado.

 

ACBrBALSaturno.pas 5 kB · 1 download

Muito obrigado pela contribuição.
Fiz a implementação baseada nela.
Subi as alterações para o SVN na Revisão  25444.
Pelo que vi está tudo certo.
Queira por favor atualizar, testar e reportar qualquer problema.

Mais uma vez obrigado.

  • Obrigado 1

[]'s

Consultor SAC ACBr

Elton
Profissionalize o ACBr na sua empresa, conheça o ACBr Pro.

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.

Um engenheiro de Controle de Qualidade(QA) entra num bar. Pede uma cerveja. Pede zero cervejas.
Pede 99999999 cervejas. Pede -1 cervejas. Pede um jacaré. Pede asdfdhklçkh.
Link para o comentário
Compartilhar em outros sites

1 hora atrás, EMBarbosa disse:

Muito obrigado pela contribuição.
Fiz a implementação baseada nela.
Subi as alterações para o SVN na Revisão  25444.
Pelo que vi está tudo certo.
Queira por favor atualizar, testar e reportar qualquer problema.

Mais uma vez obrigado.

Obrigado @EMBarbosa
Assim que possível vou atualizar pelo svn e realizo os testes, e informo novamente aqui.

Leandro Araújo, Analista de Sistemas.

Link para o comentário
Compartilhar em outros sites

Em 06/05/2022 at 14:52, EMBarbosa disse:

Muito obrigado pela contribuição.
Fiz a implementação baseada nela.
Subi as alterações para o SVN na Revisão  25444.
Pelo que vi está tudo certo.
Queira por favor atualizar, testar e reportar qualquer problema.

Mais uma vez obrigado.

Bom dia!

Testado e validado com sucesso aqui.

Obrigado @EMBarbosa

Leandro Araújo, Analista de Sistemas.

Link para o comentário
Compartilhar em outros sites

  • Este tópico foi criado há 710 dias atrás.
  • Talvez seja melhor você criar um NOVO TÓPICO do que postar uma resposta aqui.
Visitante
Este tópico está agora fechado para novas respostas
×
×
  • Criar Novo...

Informação Importante

Colocamos cookies em seu dispositivo para ajudar a tornar este site melhor. Você pode ajustar suas configurações de cookies, caso contrário, assumiremos que você está bem para continuar.

The popup will be closed in 10 segundos...