# Implementar los servicios de hardware

Esta guía muestra las llamadas exactas que la Middleware App y el Devkit hacen contra tu Manufacturer Service App, servicio por servicio. Úsala para confirmar que tu implementación responde como el software de Getnet espera.

## Cómo funciona

Todas las llamadas de abajo llegan a tu servicio a través de `mainService`, el stub `IMainService` que la Middleware App obtiene tras vincularse a tu servicio. Cada servicio — tarjeta, impresora, beeper, etc. — cuelga de `mainService` como una propiedad propia. La mayoría de las operaciones informan de su resultado mediante un callback, no mediante un valor de retorno.

## Antes de empezar

Completa la [configuración de la integración HAL](/es/pos-manufacturers/first-steps-pos-mfg/hal-integration-setup) para que tu servicio se vincule correctamente, y luego ejecuta el [Devkit](/es/pos-manufacturers/first-steps-pos-mfg/quick-start-devkit) para probar cada llamada a medida que la implementas.

## Beeper

El Devkit llama a `custom` con una duración en milisegundos:

```kotlin
mainService.beeper.custom(500) // 500 milliseconds
```

Tu implementación de `IBeeperService` también debe soportar cuatro sonidos con nombre, cada uno con una duración fija:

| Sonido | Duración |
| :--- | :--- |
| `success` | Pitido de 500 ms. |
| `error` | Pitido de 1000 ms. |
| `digit` | Pitido de 100 ms. |
| `nfc` | Pitido de 100 ms, pausa de 300 ms, pitido de 100 ms. |

## Tarjeta

Obtén el servicio de tarjeta una vez y luego llama al método de búsqueda que corresponda al tipo de lectura que necesita quien llama:

```kotlin
val cardService = mainService.card
```

Cada tipo de búsqueda usa una constante fija:

| Constante | Valor |
| :--- | :--- |
| `MAG` | `"1"` |
| `CHIP` | `"2"` |
| `NFC` | `"3"` |

Búsqueda por chip:

```kotlin
cardService.searchChip(1000, object : ICardCallback.Stub() {
    override fun onCard(cardResponse: CardResponse?) {
        val pan = cardResponse?.pan
        cardService.stopAllReaders()
    }
    override fun onMessage(message: String?) {
        cardService.stopAllReaders()
    }
    override fun onError(error: String?) {
        cardService.stopAllReaders()
    }
})
```

La búsqueda por banda magnética devuelve `track1`, `track2` y `track3` en `onCard` en lugar de `pan`. La búsqueda NFC devuelve la misma forma de `CardResponse` que la búsqueda por chip.

Ambas siguen el mismo patrón `onCard` / `onMessage` / `onError`, y ambas deben llamar a `stopAllReaders()` en cuanto llega un resultado.

## Mifare

`IMifareService` cubre la presencia de tarjeta, la autenticación y la lectura/escritura a nivel de bloque:

```kotlin
mainService.mifare.searchCard(object : IMifareCallback.Stub() {
    override fun onCard(type: Int) { /* card type detected */ }
    override fun onError(error: String?) { /* handle error */ }
})

mainService.mifare.searchCardAndActivate(object : IMifareActivateCallback.Stub() {
    override fun onActivate(key: ByteArray?) { /* card activated */ }
    override fun onError(error: String?) { /* handle error */ }
})
```

La autenticación de sector y de bloque toma una clave de 6 bytes:

```kotlin
val key = byteArrayOf(0xff.toByte(), 0xff.toByte(), 0xff.toByte(), 0xff.toByte(), 0xff.toByte(), 0xff.toByte())
mainService.mifare.authenticateSectorWithKeyA(sector = 2, key)
mainService.mifare.authenticateBlockWithKeyA(block = 10, key)
mainService.mifare.authenticateSectorWithKeyB(sector = 2, key)
mainService.mifare.authenticateBlockWithKeyB(block = 10, key)
```

Tras la autenticación, tu servicio debe soportar `decrement`, `increment`, `readBlock`, `restore`, `transfer` y `writeBlock` sobre un índice de bloque dado. También debe soportar `close`, `isExist`, `activate` y `halt` para el control de sesión. `getCardSerialNo` devuelve el UID de la tarjeta como cadena hexadecimal.

## LED

`ILedService` expone un par encendido/apagado por color — rojo, azul, amarillo y verde:

```kotlin
mainService.led.turnOnRed()
mainService.led.turnOffRed()
```

Implementa el mismo par para azul, amarillo y verde.

## Impresora

Todos los métodos de `IPrinterService` deben lanzar `IllegalStateException` si tu servicio aún no ha inicializado la impresora:

```kotlin
mainService.printer?.init()
    ?: throw IllegalStateException("service isn't initiated")
```

Una vez inicializada, tu servicio construye un trabajo de impresión a partir de una secuencia de llamadas — `addText`, `addBarCode`, `addQrCode`, `addImageBitmap`, `addImageByteArray` — seguida de `print` o `printAndRemovePaper`:

```kotlin
mainService.printer?.addText(align, text)
mainService.printer?.print(object : IPrinterCallback.Stub() {
    override fun onSuccess() { /* job printed */ }
    override fun onError(cause: Int) { /* map cause to a status */ }
})
```

`setGray` fija el nivel de escala de grises, y `defineFontFormat` fija la fuente activa. Consulta la [referencia de interfaces de servicio](/es/pos-manufacturers/reference-pos-mfg/service-interfaces) para las especificaciones fijas de impresora — tamaño de imagen, límites de caracteres y el umbral de escala de grises que tu servicio debe aplicar.

## Cámara

`readFront` lee la cámara frontal con un tiempo de espera e informa del resultado mediante un callback:

```kotlin
mainService.camera.readFront(
    timeout = 2000,
    callback = object : ICameraCallback.Stub() {
        override fun onSuccess(code: String?) { /* code read */ }
        override fun onTimeout() { /* no result within timeout */ }
        override fun onCancel() { /* caller canceled the read */ }
        override fun onError(error: String?) { /* handle error */ }
    },
)
```

## Estadísticas del sistema

`IStatService` informa de los recuentos de éxito y de fallo por tipo de lectura, tanto a nivel de dispositivo como por aplicación llamante:

```kotlin
mainService.stats.getAllStatisticsByApp(object : IStatCallback.Stub() {
    override fun onStatistic(statResponse: StatResponse?) {
        val paperStatus = statResponse?.generalPaperStatus
        val mifareStatus = statResponse?.generalMifareStatus
    }
    override fun onError(error: String?) { /* handle error */ }
})
```

Algunos métodos HAL, como `print(userId, callback)` y `searchMag(userId, timeout, callback)`, reciben un parámetro `userId` que identifica a la aplicación llamante. Resuélvelo a un nombre de paquete con `packageManager.getNameForUid(userId)`. Usa ese nombre de paquete para atribuir las estadísticas a la aplicación correcta.

## Leer el resultado

Una implementación correcta informa siempre de los eventos de hardware por el callback de quien llama, nunca solo por un valor de retorno. También llama a `stopAllReaders()` cuando termina una lectura de tarjeta, tanto si tuvo éxito como si no.

Los métodos de impresora son la única excepción que merece mención propia: cualquiera de ellos llamado antes de `init()` debe lanzar `IllegalStateException` en lugar de fallar en silencio.

## Próximos pasos

* [Enviar tu integración para validación](/es/pos-manufacturers/how-to-guides-pos-mfg/submit-integration-for-validation) — cuando todas las llamadas anteriores respondan correctamente.
* [Referencia de interfaces de servicio](/es/pos-manufacturers/reference-pos-mfg/service-interfaces) — firmas completas de métodos, incluidas las interfaces que no aparecen aquí.
* [Máquina de estados EMV](/es/pos-manufacturers/core-concept-pos-mfg/emv-state-machine) — el flujo que sigue a una lectura de tarjeta por chip o contactless con éxito.