Bom dia a todos.
Conforme prometido e promessa é dívida, vai aí abaixo o codigo do gerenciamento de ecf com xHarbour usando a HbComm para comunicação direta com impressoras fiscais.
Ps: Agradeço aqui a todos que me ajudaram neste empenho.
Demorei muito para mandar, devido a leitura dos retornos da impressora fiscal, não estava conseguindo obter resultados, mas agora já estou usando em térmica e em matricial BEMATECH.
ps: Se alguém tiver alguma idéia para melhorar a mais, sinta-se a vontade, mas peço-lhes que postem a melhoria no fórum.
:{
Código: Selecionar todos
/// fun‡oes gerais de ecfs (inicio)
Static Function IBE_PREP_BUFFER() // Calcula CheckSum de acordo com o
// protocolo da Impressora. Retorna String com o BUFFER para ser enviado
Local iSoma,iConta,c_LENCMD,c_NBL,c_NBH,c_CSL,c_CSH,a_CMD
If !Empty(c_CMD)
a_CMD :=CHR(27) + c_CMD
iSoma :=SOMAASC( a_CMD )
c_LENCMD:=Len( a_CMD ) + 2 // + 2 = CSL + CSH
c_NBL :=CHR( Mod ( c_LENCMD , 256) )
c_NBH :=CHR( Int ( c_LENCMD / 256) )
c_CSL :=CHR( Mod ( iSoma, 256 ) )
c_CSH :=CHR( Int ( iSoma / 256 ) )
c_CMD :=c_STX + c_NBL + c_NBH + a_CMD + c_CSL + c_CSH
EndIf
Return .T.
//*
Function SOMAASC(CMD)
a_SOMA:=0
For i:=1 To Len(CMD)
a_SOMA:=a_SOMA+Asc(SubStr(CMD,i,1))
Next
Return a_SOMA
//*
Function IBE_BCD_ASC(DADOS) // Converte String BCD para ASC
local RET := "",A,BH,BL,ASC_CHAR,BCD_CHAR
For A := 1 To Len( DADOS )
BCD_CHAR :=ASC( SubStr( DADOS, A, 1 ) )
BH :=StrZero( Int( BCD_CHAR / 16 ), 1, 0 )
BL :=StrZero( Mod( BCD_CHAR, 16 ), 1, 0 )
ASC_CHAR :=BH + BL
RET += ASC_CHAR
Next
Return RET
// Estas funções acima foi ajuda que recebi do grupo, a minha tinha ficado mais extensa, heheh.
//**********************************************************
Function ECF_DIRETA(a_CMD,a_TXT) //cria os comandos
Local lRet:=.F.
Private c_CMD:=""
Private c_TRD:=3 //Tamanho Retorno Dados em bytes num‚ricos
a_CMD:=UPPER(a_CMD)
a_TXT:=If(a_TXT=NIL,"",a_TXT)
/////////////transforma o cmd
If a_CMD=="ABRE CUPOM"
If wECF_MODELO=="B"
c_CMD:=CHR(0) //correto
c_TRD:=c_TRD+0
EndIf
ElseIf a_CMD=="REDUCAO Z"
If wECF_MODELO=="B"
c_CMD:=CHR(5) // correto
c_TRD:=c_TRD+0
EndIf
ElseIf a_CMD=="ABRE CAIXA"
If wECF_MODELO=="B"
c_CMD:=CHR(6) //correto
c_TRD:=c_TRD+0
EndIf
ElseIf a_CMD=="PDV" //retorna o numero do caixa
If wECF_MODELO=="B"
c_CMD:=CHR(35)+CHR(14) //correto
c_TRD:=c_TRD+2
EndIf
ElseIf a_CMD=="UNIDADE DE MEDIDA"
If wECF_MODELO=="B"
c_CMD:=CHR(62)+CHR(51) //correto
c_TRD:=c_TRD+0
EndIf
ElseIf a_CMD=="AUMENTA DESCRICAO"
If wECF_MODELO=="B"
c_CMD:=CHR(62)+CHR(52) //correto
c_TRD:=c_TRD+0
EndIf
ElseIf a_CMD=="VENDA ITEM DECIMAIS 2"
If wECF_MODELO=="B"
c_CMD:=CHR(9) //correto
c_TRD:=c_TRD+0
EndIf
ElseIf a_CMD=="VENDA ITEM DECIMAIS 3"
If wECF_MODELO=="B"
c_CMD:=CHR(56) //correto
c_TRD:=c_TRD+0
EndIf
ElseIf a_CMD=="VENDA ITEM DEPARTAMENTO"
If wECF_MODELO=="B"
c_CMD:=CHR(63) //correto
c_TRD:=c_TRD+0
EndIf
ElseIf a_CMD=="INICIA FECHAMENTO CUPOM"
If wECF_MODELO=="B"
c_CMD:=CHR(32) //correto
c_TRD:=c_TRD+0
EndIf
ElseIf a_CMD=="PROGRAMA FORMA PAGAMENTO"
If wECF_MODELO=="B"
c_CMD:=CHR(71) //correto
c_TRD:=c_TRD+0
EndIf
ElseIf a_CMD=="EFETUA FORMA PAGAMENTO"
If wECF_MODELO=="B"
c_CMD:=CHR(72) //correto
c_TRD:=c_TRD+0
EndIf
ElseIf a_CMD=="PROGRAMA VARIAS FORMAS PAGAMENTO"
If wECF_MODELO=="B"
c_CMD:=CHR(73) //correto
c_TRD:=c_TRD+0
EndIf
ElseIf a_CMD=="FINALIZA FECHAMENTO CUPOM"
If wECF_MODELO=="B"
c_CMD:=CHR(34) //correto
c_TRD:=c_TRD+0
EndIf
ElseIf a_CMD=="LEITURA X"
If wECF_MODELO=="B"
c_CMD:=CHR(6) //correto
c_TRD:=c_TRD+0
EndIf
ElseIf a_CMD=="ADCIONA ALIQUOTA"
If wECF_MODELO=="B"
c_CMD:=CHR(7) //correto
c_TRD:=c_TRD+0
EndIf
ElseIf a_CMD=="NUMERO CUPOM"
If wECF_MODELO=="B"
c_CMD:=CHR(30) //correto
c_TRD:=c_TRD+3
EndIf
ElseIf a_CMD=="SUBTOTAL"
If wECF_MODELO=="B"
c_CMD:=CHR(29) //correto
c_TRD:=c_TRD+7
EndIf
ElseIf a_CMD=="CANCELA CUPOM"
If wECF_MODELO=="B"
c_CMD:=CHR(14) //correto
c_TRD:=c_TRD+0
EndIf
EndIf
////////////////executa
If c_ECF_TIPO=="DIRETA"
If wECF_MODELO=="B"
c_CMD:=c_CMD+a_TXT
EndIf
IBE_PREP_BUFFER() //calcula o checksun e passa para c_CMD
If ECF_OpenDoor() //abre a porta = Init_Port()
lRet:=ECF_Processo(a_CMD) //executa=outchr() e fecha=UnInt_port()
EndIf
EndIf
Return lRet
//*
Function ECF_CHKPDV
Local aRet:=.F.
If ECF_DIRETA("PDV")
wECF_PDV:=Right(c_ECF_DADOS,3)
If Val(wECF_PDV)>=1
aRet:=.T.
EndIf
EndIf
Return aRet
//
Function ECF_OpenDoor() // abre a porta serial
Local lRet:=.F.
//fun‡Æo:
//nPorta recebe o handle e a funcao ECF_OpenDoor retorna .t. ou .f.. para validar o sistema para uso
//Init_Port( cPort, nBaudrate, nDatabits, nParity, nStopbits, nBuffersize ) --> nHandle
//Bematech:
//cport (porta) = COM[1-9]
//nbaudrate (velocidade) = 9.600 , 38.400
//ndatabist (bits grava‡ao) = 8 ,
//nParity (paridade) = 0 ,
//nStopBits (bits parada) = 1 ,
//nBufferSize (tamanho a/cv)= 256 , 8.000
If (nPorta:=Init_Port(wECF_Porta,9600,8,0,1,256))>0
//abre a porta inicializo a porta
//se maior que zero a porta ‚ iniciada
OutBufClr(nPorta) //limpa a porta saida hbcomm se iniciada
lRet:=IsWorking(nPorta) //retorna a leitura da porta hbcomm se esta apta ao trabalho
EndIf
Return lRet
//*
Function ECF_Processo(a_CMD) // FAZ A VARREDURA NA PORTA
Local aRet:=.F.,cBuffer:="",nBytes:=0
If c_ECF_TIPO=="DIRETA"
nBytes :=INBUFSIZE(nPorta) //pega o tamanho do buffer
cBuffer:=Space(nBytes) //cria o tamanho do buffer
INCHR(nPorta,@cBuffer,nBytes) //compara o tamanho do buffer com a leitura atual
If nBytes = Len(cBuffer) //InChr(nPorta,@cBuffer,nBytes) //compara o tamanho do buffer com a leitura atual
OUTBUFCLR(nPorta) //limpa a porta saida hbcomm
If OUTCHR(nPorta,c_CMD,Len(c_CMD)) //emite o comando compara a leitura
// tive problemas daqui pra baixo, como aguardar a leitura da porta até que cheguei nas linhas abaixo, TESTADAS E FUNCIONANDO.
nTOut :=0 //tempo limite time out = 0
nTDec :=0 //tempo decorrido = time decorrido
nTIni :=Seconds() //tempo iniciado = time inicio
nBytes:=0 //byte a byte atualizado
nUByte:=0 //ultimo byte atualizado
While nBytes < c_TRD //fa‡a enquanto os bytes sÆo menores que o total retorno
ShowWaitProc() //indica o processamento
Inkey(0.1) //fraciona em d‚cima parte de 1 minuto = 6 segundos
nTDec :=Seconds()-nTIni //encrementa o tempo decorrido
nBytes:=INBUFSIZE(nPorta) //pega o tamanho do buffer
If nBytes>0 //se recebeu no primeiro instante o ack
If nTOut=0 //e o time out for igual a zero
nTOut:=90 //90 segundos, recebe o time out
EndIf //com time out de 90 segundos para garantia, visto que as matriciais sÆo mais lerdas que as termicas.
ElseIf nBytes=0 //se nÆo conseguiu ler, houve algo errado
nTOut:=1 //1 segundo, saia em um segundo
EndIf
If nBytes>nUByte //se nBytes for maior que o ultimo bytes, atualize
nTIni :=Seconds() //iguala o tempo parado com tempo decorrido time out = 0 (esta em captura)
nUByte:=nBytes //iguala os bytes
EndIf
If nTDec > nTOut //S¢ sair se o tempo ocioso for maior que nTOut
Exit
EndIf
End
// até aqui faz a leitura da porta para descobrir o tamanho dos bytes em comparação com o total a ser retornado.
If nBytes > 0
cBuffer :=Space(nBytes) //cria o tamanho do buffer
INCHR(nPorta,nBytes,@cBuffer) //le a porta serial compara a leitura do buffer
cBuffer :=AllTrim(cBuffer) //compacta o retorno
cBuffer :=IBE_BCD_ASC(cBuffer) //decodifica o retorno
c_ACK :=Val(Left(cBuffer,2)) //pega o ACK
c_ST1 :=Val(SubStr(Right(cBuffer,4),1,2)) //pega o ST1
c_ST2 :=Val(SubStr(Right(cBuffer,4),3,2)) //pega o ST2
c_ECF_DADOS:=SubStr(cBuffer,3,Len(cBuffer)-6) //pega os DADOS
aRet :=ECF_Status() //trata o retorno ST1 e ST2
EndIf
OUTBUFCLR(nPorta) //limpa a porta saida hbcomm
Else
ShowMessage(,,"Erro na verifica‡Æo dos dados.",2)
EndIf
Else
ShowMessage(,,"Erro na igualdade do buffer.",2)
EndIf
ECF_CloseDoor(nPorta) // FECHA A PORTA se verdadeiro
EndIf
Return aRet
//
Function ECF_CloseDoor()
UnInt_Port(nPorta) // FECHA A PORTA se verdadeiro
nPorta:=0
Return .T.
//
Function ECF_Status
Local lRet:=.T.
ShowWait(,,"Analisando o retorno da impressora fiscal...")
wECF_MeST1:=wECF_MeST2:=""
If c_ACK=6.And.(c_ST1>0.Or.c_ST2>0) //mostra o status
If c_ST1>=80
wECF_MeST1:="Acabou o Papel Da Impressora Fiscal."
c_ST1:=c_ST1-80
lRet:=.F.
EndIf
If c_ST1>=40
wECF_MeST1:="H Pouco Papel Na Impressora Fiscal."
c_ST1:=c_ST1-40
EndIf
If c_ST1>=20
wECF_MeST1:="Erro No Rel¢gio Da Impressora Fiscal."
c_ST1:=c_ST1-20
lRet:=.F.
EndIf
If c_ST1>=10
wECF_MeST1:="Erro Na Impressora Fiscal."
c_ST1:=c_ST1-10
lRet:=.F.
EndIf
If c_ST1>=8
wECF_MeST1:="Primeiro Dado De CMD NÆo Foi ESC (1Bh)."
c_ST1:=c_ST1-8
lRet:=.F.
EndIf
If c_ST1>=4
wECF_MeST1:="Comando Inexistente."
c_ST1:=c_ST1-4
lRet:=.F.
EndIf
If c_ST1>=2
wECF_MeST1:="Cupom Aberto."
c_ST1:=c_ST1-2
EndIf
If c_ST1>=1
wECF_MeST1:="N£mero De Parƒmetros De CMD Inv lido."
c_ST1:=c_ST1-1
lRet:=.F.
EndIf
If c_ST2>=80
wECF_MeST2:="Tipo De Parƒmetro De CMD Inv lido."
c_ST2:=c_ST2-80
lRet:=.F.
EndIf
If c_ST2>=40
wECF_MeST2:="Mem¢ria Fiscal Lotada."
c_ST2:=c_ST2-40
lRet:=.F.
EndIf
If c_ST2>=20
wECF_MeST2:="Erro Na Mem¢ria RAM CMOS NÆo Vol til."
c_ST2:=c_ST2-20
lRet:=.F.
EndIf
If c_ST2>=10
wECF_MeST2:="Al¡quota NÆo Programada."
c_ST2:=c_ST2-10
lRet:=.F.
EndIf
If c_ST2>=8
wECF_MeST2:="Capacidade De Al¡quotas Program veis Lotada."
c_ST2:=c_ST2-8
lRet:=.F.
EndIf
If c_ST2>=4
wECF_MeST2:="Cancelamento NÆo Permitido."
c_ST2:=c_ST2-4
lRet:=.F.
EndIf
If c_ST2>=2
wECF_MeST2:="CNPJ/IE Do Propriet rio NÆo Programados."
c_ST2:=c_ST2-2
lRet:=.F.
EndIf
If c_ST2>=1
wECF_MeST2:="Comando NÆo Executado."
c_ST2:=c_ST2-1
lRet:=.F.
EndIf
If !Empty(wECF_MeST1).Or.!Empty(wECF_MeST2)
ShowMessage(,,{wECF_MeST1+"",""+wECF_MeST2},0)
// lRet:=If(Empty(wECF_MeST2),lRet,.F.)
EndIf
EndIf
CloseWindow()
Return lRet
//////////////fim do ecf
Um abraço a todos usuários do fórum.
:xau
