================================================================================
EPSON FISCAL PRINTER HOST DOS DEVICE DRIVER
================================================================================

Introduccin:
-------------
   1.1 Descripcin.
   1.2 Requerimientos.
   1.3 Instalacin.
   1.4 Uso.
   1.5 Errores.
   1.6 Ejemplos.
    
   
* 1.1 Descripcin
-----------------
EFPHOST.SYS es un DEVICE DRIVER para DOS que permite controlar desde cualquier 
entorno de desarrollo DOS una impresora fiscal EPSON. 

* 1.2 Requerimientos
--------------------
. Requerimientos de software: Sistema operativo DOS 3.3 o mejor.
. Requerimientos de hardware: IBM PC compatible ms un puerto serie 
  disponible.

Notas:
 EFPHOST.SYS fue diseado y probado exclusivamente para ser utilizado con el 
 sistema operativo DOS.
 Para un mejor aprovechamiento de la mxima velocidad de comunicacin de
 la impresora fiscal EPSON ( 38400 baudios ) es recomendable utilizar un 
 puerto serial que posea una UART 16C550A, esta posee un buffer tipo FIFO, que
 optimiza el uso de las comunicaciones sin perdida de informacin.
 
* 1.3 Instalacin
-----------------
La instalacin es semejante a cualquier otro driver DOS, es decir modificando 
el archivo CONFIG.SYS dentro del directorio raz del disco de arranque. Se 
detallan los parmetros necesarios:

CONFIG.SYS
==========
DEVICE=EFPHOST.SYS /COM=1 /BAUD=38400 /PROTOCOL=COMPATIBLE /DEBUG

El parmetro COM puede tomar los siguientes valores: 1, 2, 3 o 4 y especifica
el puerto serie donde se encuentra conectada la impresora fiscal EPSON. 
Consulte al manual de su PC para establecer el correcto valor de este 
parmetro.

El parmetro BAUD puede tomar los siguientes valores: 1200, 2400, 4800,
9600, 19200, 38400 y especifica cual va a ser la velocidad de comunicacin 
entre EFPHOST.SYS y la impresora fiscal EPSON. Consulte al manual de 
especificaciones tcnicas de la impresora fiscal EPSON para establecer el 
correcto valor de este parmetro.

El parmetro PROTOCOL puede tomar los siguientes valores: COMPATIBLE y EXTENDED
y especifica el protocolo de comunicacin que ser utilizado para el envo y 
recepcin de comandos desde y hacia la impresora fiscal EPSON. Consulte al 
manual de especificaciones tcnicas de su impresora fiscal EPSON para asignar 
el correcto valor del mismo.

El parmetro DEBUG tiene como finalidad monitorear la informacin recibida por 
el driver. Toda la informacin recibida por el driver es mostrada en pantalla en 
el siguiente formato.

WRITE REQUEST
Buffer: XXXX:XXXX
Buffer length: XX
XX XX XX XX XX XX XX XX ...

READ REQUEST
Buffer: XXXX:XXXX
Buffer length: XX
XX XX XX XX XX XX XX XX ...

Los mensajes READ y WRITE son mostrados cuando se realiza una operacin de 
lectura o escritura al driver respectivamente. Buffer es la direccin de memoria 
donde reside el buffer de la aplicacin cuando el driver es invocado. Buffer 
length es el tamao de dicho buffer, y el resto de la informacin es un volcado 
en hexadecimal de todos los datos del buffer. La utilizacin de este modo tiene 
como objetivo verificar que sea correcta la informacin suministrada por la 
aplicacin al driver, pero solo debe ser utilizado en la etapas iniciales de 
desarrollo.

Durante el proceso de instalacin EFPHOST.SYS verifica la correcta presencia 
de los parmetros, si estos no existen, o son invlidos la instalacin es 
cancelada. Si el parmetro PROTOCOL no es ingresado EFPHOST.SYS asume por 
defecto el protocolo tipo "extendido". 
Adems EFPHOST.SYS verifica que realmente exista una UART en el COM 
especificado, si esta no existe, la instalacin tambin es cancelada.

Notas: 
 Es necesario respetar estrictamente la sintaxis anteriormente descripta, no 
 deben utilizarce espacios entre la especificacin del parmetro y su valor. 


* 1.4 Uso
---------
La forma de comunicarse con EFPHOST.SYS es a travs de operaciones de lectura 
y escritura a archivos, DOS trata a los drivers instalados de manera similar a 
un archivo convencional. EFPHOST.SYS determina que comando desea ejecutar el
usuario, en base a la informacin que es suministrada a las operaciones de 
lectura o escritura. 

1.4.1 Apertura
--------------
Para poder establecer comunicacin con EFPHOST.SYS primero es necesario 
realizar la apertura del mismo, esto se realiza con una operacin convencional 
de apertura de archivo. Los ejemplos siguientes demuestran como hacerlo:

LENGUAJE C
----------
.....
 int Handle;
 
 Handle = open( "EFPHOST", O_RDWR|O_BINARY );
 
 if ( Handle == -1 )
   printf( "Driver no instalado\n" );
 else
   printf( "Apertura satisfactoria\n" );
.....

QUICK BASIC
-----------
...
 
 OPEN "EFPHOST" FOR BINARY AS #1 
 
...
 
Es imprescindible que la funcin de apertura abra a EFPHOST.SYS en modo 
binario ya que de esta manera, el lenguaje, no har ninguna interpretacin 
de los caracteres escritos o ledos. Por otra parte es necesario que la funcin 
de apertura sea sin "bufferear" ya que esta trata al dispositivo de una manera 
incompatible con EFPHOST.SYS. Por ejemplo en lenguaje "C" no debe utilizarce la 
funcin "fopen".

1.4.2 Cierre
------------
EFPHOST.SYS no realiza ninguna tarea sobre una operacin de cierre, esta es 
necesaria nicamente para DOS, ya que libera el manejador de archivo 
previamente abierto.

1.4.3 Comandos disponibles
--------------------------
Los comandos disponibles de EFPHOST.SYS son los siguientes:

 1. AddDataField ( Escritura )
 2. SendCommand ( Escritura )
 3. Purge ( Escritura )
 4. GetFinalAnswer ( Lectura )
 5. GetExtraField ( Lectura )
 6. GetLogs( Lectura )

Nota:
Las aclaraciones entre parntesis indican que estas operaciones se realizan 
escribiendo sobre el EFPHOST.SYS o leyendo del mismo.
 
1.4.4 Operatoria de comandos
----------------------------
EFPHOST.SYS decide que comando se desea ejecutar en base a la informacin
provista en las operaciones de escritura o lectura. Esta informacin debe estar 
formateada para que pueda ser interpretada de manera correcta.
Normalmente la informacin provista es de entrada y salida ya que el usuario 
asigna valores a los campos correspondientes y EFPHOST.SYS devolver en la 
misma informacin de acuerdo al resultado del comando. 
Es importante destacar que 
Se detallan ejemplos explicativos:

LENGUAJE C
----------
.....
 typedef struct 
 {
   unsigned char Cmd;              /* Tamao 1 byte  */
   unsigned int LastError;         /* Tamao 2 bytes */
 }tRecord; 
.....  
 tRecord MyRecord;
 
 /* Especifico un "SendCommand" */
 MyRecord.Cmd = '1';
 
 write( Handle, &MyRecord, sizeof( tRecord ));
 
/* Despus de esta linea el valor de MyRecord.LastError contendra  
    el resultado de la operacin */
.....

QUICK BASIC
-----------
...
 TYPE tRecord
  Cmd AS STRING * 1             /* Tamao 1 byte  */ 
  LastError AS INTEGER          /* Tamao 2 bytes */ 
 END TYPE
...  
 DIM MyRecord AS tRecord
 'Especifico un "SendCommand"'
 MyRecord.Cmd = "1";
 PUT #1 ,, MyRecord
'Despues de esta linea el valor de MyRecord.LastError contendra  
 'el resultado de la operacin 
   
1.4.5 AddDataField
------------------
* Descripcion: Suma un campo a la trama de datos interna.
* Tipo de acceso: Escritura
* Formato del comando: 

  Byte   Entrada  Salida    Tipo     Largo   Comentario
  -------------------------------------------------------------------------
     0         0            ASCII      1     Especifica el tipo de comando.
   1-2              NNNN    INTEGER    2     LastError.
   3-4      NNNN            INTEGER    2     Largo de los datos.
   5-N      ....            ASCII      N     Datos.

* Posibles valores de LastError al finalizar la ejecucion:
   EFP_Success              -> Operacin exitosa
   EFP_E_OutBufferFull      -> El buffer de comandos supera el mximo permitido
   EFP_E_InvalidDataInField -> El contenido de los datos a enviar contiene 
                               valores no permitidos para el tipo de protocolo 
                               seleccionado.

* Observaciones:
   Cada comando que recibe la impresora fiscal EPSON esta compuesto comnmente 
   por varios campos separados por un carcter especial que oficia de 
   separador. Cuando la impresora fiscal EPSON as lo requiera, ejecute tantas 
   veces este comando, para signar toda la informacin requerida.
   
1.4.6 SendCommand
-----------------
* Descripcin: Enva un trama completa a la impresora fiscal EPSON. 
* Tipo de acceso: Escritura
* Formato del comando: 

  Byte   Entrada  Salida    Tipo     Largo   Comentario
  -------------------------------------------------------------------------
     0         1            ASCII      1     Especifica el tipo de comando.
   1-2              NNNN    INTEGER    2     LastError.

* Posibles valores de LastError al finalizar la ejecucin:
   EFP_Success              -> Operacin exitosa
   EFP_E_WriteFail          -> Ocurri un fallo en el envo de datos hacia la 
                               impresora fiscal EPSON.
   EFP_E_ReadTimeOut        -> La impresora fiscal EPSON no respondi a un 
                               comando en el tiempo establecido.
   EFP_E_NackReceived       -> La impresora fiscal EPSON rechaz el comando 
                               enviado.
                              
* Observaciones:
   Una vez que fue establecida la trama de datos a enviar a la impresora 
   fiscal EPSON, utilice este comando para transmitirla. EFPHOSTS.SYS no 
   devuelve control a la aplicacin hasta que no finalice la transaccin con 
   la impresora fiscal EPSON debido a la naturaleza no reentrante del sistema                                               operativo

1.4.7 Purge
-----------
* Descripcin: Limpia toda la trama de datos y reinicializa el puerto de 
               comunicaciones.
* Tipo de acceso: Escritura
* Formato del comando: 
  
  Byte   Entrada  Salida    Tipo     Largo   Comentario
  -------------------------------------------------------------------------
     0         2            ASCII      1     Especifica el tipo de comando.
   1-2              NNNN    INTEGER    2     LastError.


* Posibles valores de LastError al finalizar la ejecucin:
   EFP_Success              -> Operacin exitosa
                              
* Observaciones:
   Utilice este comando si desea limpiar la trama de datos a enviar, previamente 
   establecido con el comando "AddDataField". O utilicelo si desde el momento 
   en que se inici DOS, fue cambiada la configuracin del puerto serial donde 
   se encuentra conectada la impresora fiscal EPSON.
  
1.4.8 GetFinalAnswer
--------------------
* Descripcin: Obtiene la ltima respuesta de la impresora fiscal EPSON 
* Tipo de acceso: Lectura
* Formato del comando: 


  Byte   Entrada  Salida    Tipo     Largo   Comentario
  -------------------------------------------------------------------------
     0         3            ASCII      1     Especifica el tipo de comando.
   1-2              NNNN    INTEGER    2     LastError.
   3-4              NNNN    INTEGER    2     Estado fiscal.
   5-6              NNNN    INTEGER    2     Estado de la impresora. 
   7-8              NNNN    INTEGER    2     Cdigo de retorno. 
  9-10              NNNN    INTEGER    2     Cantidad de campos extras.
   
* Posibles valores de LastError al finalizar la ejecucin:
   EFP_Success              -> Operacin exitosa
   EFP_E_BufferTooSmall     -> El tamao del buffer suministrado al comando es 
                               menor que el requerido.
   EFP_E_InvalidCommand     -> Se ejecuto este comando sin previamente haber 
                               ejecutado "SendComand"
  
* Observaciones:
   Ejecute este comando nicamente si el comando "SendCommand" finaliz
   exitosamente. Consulte al manual de especificaciones tcnicas de la 
   impresora fiscal EPSON para determinar el correcto significado de cada valor 
   retornado por este comando.
   

1.4.9 GetExtraField
-------------------
* Descripcin: Obtiene un campo de informacin extra.
* Tipo de acceso: Lectura
* Formato del comando: 

  Byte   Entrada  Salida    Tipo     Largo   Comentario
  --------------------------------------------------------------------------
     0         4            ASCII      1     Especifica el tipo de comando.
   1-2              NNNN    INTEGER    2     LastError.
   3-4      NNNN    NNNN    INTEGER    2     Campo nmero / Largo del campo.
   5-N              ....    ASCII    2048    Datos.

* Posibles valores de LastError al finalizar la ejecucin:
  EFP_Success              -> Operacin exitosa
  EFP_E_InvalidIndex       -> El ndice es invalido
  EFP_E_InvalidCommand     -> Se ejecuto este comando sin previamente haber 
                              ejecutado "SendComand"
  EFP_E_BufferTooSmall     -> El tamao del buffer suministrado al comando es 
                              menor que el requerido.

* Observaciones:
   Ejecute este comando nicamente si el comando "SendCommand" finaliz 
   exitosamente. Si el comando enviado a la impresora fiscal EPSON retorna 
   campos con informacin adicional, utilice este mtodo para recuperar la 
   informacin de los mismos. El ndice del primer campo es 1. El largo del 
   campo extra obtenido es colocado en el par metro correspondiente al nmero 
   de campo. El tamao del buffer de datos debe ser de 2048 bytes, esto es 
   debido a que es el valor mximo que puede tener un campo de datos. 

1.4.6 GetLogs
-------------
* Descripcion: Obtiene el log de comunicaciones de bajo nivel.
* Tipo de acceso: Lectura
* Formato del comando: 

  Byte   Entrada  Salida    Tipo     Largo   Comentario
  -------------------------------------------------------------------------
     0         5            ASCII      1     Especifica el tipo de comando.
   1-2              NNNN    INTEGER    2     LastError.
   3-4      NNNN            INTEGER    2     Largo de los buffer/datos.
   5-N      ....            ASCII      N     Datos.

* Posibles valores de LastError al finalizar la ejecucion:
   EFP_Success              -> Operacin exitosa
 
* Observaciones:
Este comando permite obtener toda la trama de comunicaciones de bajo nivel
entre el driver y la impresora fiscal Epson. Y unicamente debe ser invocado 
despues del comando "SendCommand". Toda la informacin devuelta por este debera 
se direccionada a un archivo, la finalidad de esto es solucionar problemas de 
comunicaciones. Este es un volcado tpico del comando:

HOST--> 02 93 08 01 1C 00 00 03 30 30 42 44 
FP  <-- ACK
FP  <-- 02 80 03 30 30 38 35 
FP  <-- 02 80 03 30 30 38 35 
FP  <-- 02 93 00 00 1C C0 00 1C 1C 00 00 1C 1C 37 37 03 30 32 35 32 
HOST--> ACK

   
1.5 Errores 
-----------
El valor del resultado de cada comando, "LastError", corresponde a la siguiente 
tabla de constantes
  
  EFP_Success               =  0,
  EFP_E_OutBufferFull       = -1,
  EFP_E_InvalidDataInField  = -2,
  EFP_E_WriteFail           = -3,
  EFP_E_ReadTimeOut         = -4,
  EFP_E_NackReceived        = -5,
  EFP_E_InvalidIndex        = -6,
  EFP_E_BufferTooSmall      = -7,
  EFP_E_InvalidCommand      = -8

1.6 Ejemplos
------------
Se procede a dar un ejemplo explicativo sobre como enviar un comando y 
analizar la respuesta obtenida desde la impresora fiscal EPSON. Los ejemplos 
se detallan en lenguaje "C", QuickBasic y en Clipper para permitir su fcil
migracin a otros lenguajes ( Cobol, Pascal, etc. ).
El ejemplo trata de establecer cual es la primera lnea de encabezado 
asignada en la memoria de trabajo de la impresora fiscal EPSON, consulte al 
manual de especificaciones tcnicas de la impresora fiscal EPSON para 
obtener ms detalles sobre este comando. Consulte a su distribuidor, ya que se 
realizaron 3 ejemplos explicativos para Borland C/C++, QuickBasic y Clipper.
  
1.6.1 Borland C/C++
-------------------
#include <stdio.h>
#include <fcntl.h>
#include <sys\stat.h>
#include <io.h>

/* Comandos del driver */
#define CMD_WRITE_ADD_FIELD     '0'
#define CMD_WRITE_SEND          '1'
#define CMD_WRITE_PURGE         '2'
#define CMD_READ_ANSWER         '3'
#define CMD_READ_EXTRA_FIELDS   '4'
/* Retornos */
#define EFP_Success               0
#define EFP_E_OutBufferFull      -1
#define EFP_E_InvalidDataInField -2
#define EFP_E_WriteFail          -3
#define EFP_E_ReadTimeOut        -4
#define EFP_E_NackReceived       -5
#define EFP_E_InvalidIndex       -6
#define EFP_E_BufferTooSmall     -7
#define EFP_E_InvalidCommand     -8

/* Tipos C no nativos */
typedef unsigned char byte;
typedef unsigned int word;

/* Registro comun a todos los comandos */
typedef struct 
{
  byte Cmd;              /* Tamao 1 byte  */
  word LastError;        /* Tamao 2 bytes */
}tHeader; 

/* Registro para el comando "AddDataField" */
typedef struct
{
  tHeader Header;
  word Length;
  byte Buffer[2048];    /* Mximo largo de datos que se puede enviar */
}tAddDataField;

typedef struct
{
  tHeader Header;
}tSendCommand;

/* Registro para el comando "GetFinalAnswer" */
typedef struct
{
  tHeader Header;
  word FiscalStatus;
  word PrinterStatus;
  word ReturnCode;
  word ExtraFieldsCount;
}tFinalAnswer;

/* Registro para el comando "GetExtraField" */
typedef struct
{
  tHeader Header;
  word IndexLength;
  byte Buffer[2048];
}tExtraField;

/* "Share" de todos los registros */
typedef union
{
  tSendCommand  SendCommand;
  tAddDataField AddDataField;
  tFinalAnswer  FinalAnswer;
  tExtraField   ExtraField;
}tRecord;

/* Funcin de manejo de errores */
void HandleError( void )
{
  /* Defina aqui su rutina de error */
}

void main( void )
{
  tRecord MyRecord;
  int Handle;

  /* Abre EFPHOST.SYS */
  Handle = open( "EFPHOST", O_RDWR | O_BINARY ); 

  if ( Handle == -1 )
  {
    printf( "Driver no instalado.\n" );
    return;
  }

  /*------------------------------------------------------------------- 
  La sintaxis para el envo del comando es la siguiente :
    Campo1 
          Cmd           = 0x0509 
    Campo2
          Cmd Extension = 0x0000
    Campo3 
          Nmero        = '1' // Nmero de cabecera que deseo obtener 
  --------------------------------------------------------------------*/
          
  /* Tipo de comando para EFPHOST.SYS */
  MyRecord.AddDataField.Header.Cmd = CMD_WRITE_ADD_FIELD;
  
  /* Largo de los datos a enviar */
  MyRecord.AddDataField.Length     = 2;
  
  /* Cmd */
  MyRecord.AddDataField.Buffer[0]  = 0x05;
  MyRecord.AddDataField.Buffer[1]  = 0x09;

  /* Se envia el primer campo a EFPHOST.SYS */
  write( Handle, &MyRecord, sizeof( tRecord ));

  /* Se analiza "LastError" */
  if ( MyRecord.AddDataField.Header.LastError != EFP_Success )
  {
    /* Manejar el error */
    HandleError();
  }

  /* CmdExtension */
  MyRecord.AddDataField.Buffer[0]  = 0x00;
  MyRecord.AddDataField.Buffer[1]  = 0x00;

  /* Se enva el segundo campo a EFPHOST.SYS */
  write( Handle, &MyRecord, sizeof( tRecord ));

  /* Se analiza "LastError" */
  if ( MyRecord.AddDataField.Header.LastError != EFP_Success )
  {
    /* Manejar el error */
    HandleError();
  }

  /* Largo de los datos a enviar */
  MyRecord.AddDataField.Length     = 1;
  /* Lnea de cabecera deseada */
  MyRecord.AddDataField.Buffer[0]  = '1';

  /* Se enva el tercer campo a EFPHOST.SYS */
  write( Handle, &MyRecord, sizeof( tRecord ));

  /* Se analiza "LastError" */
  if ( MyRecord.AddDataField.Header.LastError != EFP_Success )
  {
    /* Manejar el error */
    HandleError();
  }

  /* Se enva todo a la impresora fiscal */
  MyRecord.SendCommand.Header.Cmd = CMD_WRITE_SEND;
  write( Handle, &MyRecord, sizeof( tHeader ));

  /* Se analiza "LastError" */
  if ( MyRecord.SendCommand.Header.LastError != EFP_Success )
  {
    /* Manejar el error */
    HandleError();
  }

  /* Se puede obtener la respuesta final */
  MyRecord.FinalAnswer.Header.Cmd = CMD_READ_ANSWER;
  read( Handle, &MyRecord, sizeof( tFinalAnswer ));

  if ( MyRecord.FinalAnswer.Header.LastError != EFP_Success )
  {
    /* Manejar el error */
    HandleError();
  }

  /* Verifica que se devolvieron al menos un campo de informacin extra */
  if ( MyRecord.FinalAnswer.ExtraFieldsCount != 0 )
  {
    /* Obtiene el campo de informacin extra */
    MyRecord.ExtraField.Header.Cmd = CMD_READ_EXTRA_FIELDS;
    MyRecord.ExtraField.IndexLength = 1; /* El campo buscado */
    
    read( Handle, &MyRecord, sizeof( tExtraField ));


    if ( MyRecord.ExtraField.Header.LastError != EFP_Success )
    {
      /* Manejar el error */
      HandleError();
    }

    /* El campo buscado se encuentra en MyRecord.ExtraField.Buffer y el
       largo del mismo en MyRecord.ExtraField.IndexLength */
  }
}

1.6.2 QuickBasic
----------------

DECLARE SUB HandleError ()
DECLARE SUB Main ()

'Comandos del driver'
CONST CMDWRITEADDFIELD = "0"
CONST CMDWRITESEND = "1"
CONST CMDWRITEPURGE = "2"
CONST CMDREADANSWER = "3"
CONST CMDREADEXTRAFIELDS = "4"
'Retornos'
CONST EFPSuccess = 0
CONST EFPEOutBufferFull = -1
CONST EFPEInvalidDataInField = -2
CONST EFPEWriteFail = -3
CONST EFPEReadTimeOut = -4
CONST EFPENackReceived = -5
CONST EFPEInvalidIndex = -6
CONST EFPEBufferTooSmall = -7
CONST EFPEInvalidCommand = -8

'Registro comn a todos los comandos'
TYPE tHeader
  Cmd AS STRING * 1      'Tamanio 1 byte'
  LastError AS INTEGER   'Tamanio 2 bytes'
END TYPE                                

'Registro para el comando "AddDataField"'
TYPE tAddDataField
  Header AS tHeader
  Length AS INTEGER
Buffer AS STRING * 2048 'Maximo largo de datos que se puede enviar'
END TYPE

'Registro para el comando "SendCommand"'
TYPE tSendCommand
  Header AS tHeader
END TYPE
  
'Registro para el comando "GetFinalAnswer"'
TYPE tFinalAnswer
  Header AS tHeader
  FiscalStatus AS INTEGER
  PrinterStatus AS INTEGER
  ReturnCode AS INTEGER
  ExtraFieldsCount AS INTEGER
END TYPE

'Registro para el comando "GetExtraField"'
TYPE tExtraField
  Header AS tHeader
  IndexLength AS INTEGER
  Buffer AS STRING * 2048
END TYPE

'Instancia variables'                                          
DIM SHARED AddDataField AS tAddDataField
DIM SHARED SendCommand AS tSendCommand
DIM SHARED FinalAnswer AS tFinalAnswer
DIM SHARED FinalStatus AS tFinalAnswer
DIM SHARED ExtraField AS tExtraField

'------------------' 
' Rutina principal '
'------------------' 
CALL Main


'----------------------------------------------------------------------------' 
SUB Main
  
  'Abre EFPHOST.SYS'
  OPEN "EFPHOST" FOR BINARY AS #1

  '--------------------------------------------------------------------'
  ' La sintaxis para el envo del comando es la siguiente :            '
  '  Campo1                                                            '
  '        Cmd           = 0x0509                                      '
  '  Campo2                                                            '
  '       Cmd Extension  = 0x0000                                      '
  '  Campo3                                                            '
  '       Nmero         = '1'     Nmero de cabecera que deseo obtener'
  '--------------------------------------------------------------------'
          
  'Tipo de comando para EFPHOST.SYS'
  AddDataField.Header.Cmd = CMDWRITEADDFIELD

  'Largo de los datos a enviar'
  AddDataField.Length = 2
  
  'Cmd'
  AddDataField.Buffer = CHR$(&H5) + CHR$(&H9)

  'Se enva el primer campo a EFPHOST.SYS'
  PUT #1, , AddDataField

  'Se analiza "LastError"'
  IF AddDataField.Header.LastError <> EFPSuccess THEN
    'Manejar el error'
    CALL HandleError
  END IF
  
  'CmdExtension'
  AddDataField.Buffer = CHR$(0) + CHR$(0)

  'Se enva el segundo campo a EFPHOST.SYS'
  PUT #1, , AddDataField

  'Se analiza "LastError"'
  IF AddDataField.Header.LastError <> EFPSuccess THEN
    'Manejar el error'
    CALL HandleError
  END IF

  'Largo de los datos a enviar'
  AddDataField.Length = 1
  
  'Lnea de cabecera deseada'
  AddDataField.Buffer = "1"

  'Se enva el tercer campo a EFPHOST.SYS'
  PUT #1, , AddDataField

  'Se analiza "LastError"'
  IF AddDataField.Header.LastError <> EFPSuccess THEN
    'Manejar el error'
    CALL HandleError
  END IF

  'Se enva todo a la impresora fiscal'
  SendCommand.Header.Cmd = CMDWRITESEND
  PUT #1, , SendCommand

  'Se analiza "LastError"'
  IF SendCommand.Header.LastError <> EFPSuccess THEN
    'Manejar el error'
    CALL HandleError
  END IF

  'Se puede obtener la respuesta final'
  FinalAnswer.Header.Cmd = CMDREADANSWER
  GET #1, , FinalAnswer

  IF FinalAnswer.Header.LastError <> EFPSuccess THEN
    'Manejar el error'
    CALL HandleError
  END IF

  'Verifica que se devolvieron al menos un campo de informacin extra'
  IF FinalAnswer.ExtraFieldsCount <> 0 THEN
    'Obtiene el campo de informacin extra'
    ExtraField.Header.Cmd = CMDREADEXTRAFIELDS
    ExtraField.IndexLength = 1 'El campo buscado'
    
    GET #1, , ExtraField

    IF ExtraField.Header.LastError <> EFPSuccess THEN
      'Manejar el error'
      CALL HandleError
    END IF

    'El campo buscado se encuentra en ExtraField.Buffer y el '
    'largo del mismo en ExtraField.IndexLength               '
  END IF
END SUB

SUB HandleError
END SUB

