# Implement the Hardware Services

This guide shows the exact calls the Middleware App and the Devkit make against your Manufacturer Service App, service by service. Use it to confirm your implementation responds the way Getnet's software expects.

## How it works

Every call below reaches your service through `mainService`, the `IMainService` stub the Middleware App gets after binding to your service. Each service — card, printer, beeper, and so on — hangs off `mainService` as its own property. Most operations report their result through a callback rather than a return value.

## Before you begin

Complete [HAL integration setup](/en/pos-manufacturers/first-steps-pos-mfg/hal-integration-setup) so your service binds successfully, then run the [Devkit](/en/pos-manufacturers/first-steps-pos-mfg/quick-start-devkit) to test each call as you implement it.

## Beeper

The Devkit calls `custom` with a duration in milliseconds:

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

Your `IBeeperService` implementation must also support four named sounds, each with a fixed duration:

| Sound | Duration |
| :--- | :--- |
| `success` | 500 ms beep. |
| `error` | 1000 ms beep. |
| `digit` | 100 ms beep. |
| `nfc` | 100 ms beep, 300 ms pause, 100 ms beep. |

## Card

Get the card service once, then call the search method matching the read type your caller needs:

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

Each search type uses a fixed constant:

| Constant | Value |
| :--- | :--- |
| `MAG` | `"1"` |
| `CHIP` | `"2"` |
| `NFC` | `"3"` |

Chip search:

```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()
    }
})
```

Magnetic stripe search returns `track1`, `track2`, and `track3` on `onCard` instead of `pan`. NFC search returns the same `CardResponse` shape as chip search.

Both follow the same `onCard` / `onMessage` / `onError` pattern, and both must call `stopAllReaders()` once a result arrives.

## Mifare

`IMifareService` covers card presence, authentication, and block-level read/write:

```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 */ }
})
```

Sector and block authentication take a 6-byte key:

```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)
```

After authentication, your service must support `decrement`, `increment`, `readBlock`, `restore`, `transfer`, and `writeBlock` on a given block index. It must also support `close`, `isExist`, `activate`, and `halt` for session control. `getCardSerialNo` returns the card's UID as a hex string.

## LED

`ILedService` exposes an on/off pair per color — red, blue, yellow, and green:

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

Implement the same pair for blue, yellow, and green.

## Printer

Every `IPrinterService` method must throw `IllegalStateException` if your service hasn't initialized the printer yet:

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

Once initialized, your service builds a print job from a sequence of calls — `addText`, `addBarCode`, `addQrCode`, `addImageBitmap`, `addImageByteArray` — followed by `print` or `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` sets the grayscale level, and `defineFontFormat` sets the active font. See the [service interfaces reference](/en/pos-manufacturers/reference-pos-mfg/service-interfaces) for the fixed printer specifications — image size, character limits, and the grayscale threshold your service must apply.

## Camera

`readFront` reads the front camera with a timeout and reports the result through a 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 */ }
    },
)
```

## System statistics

`IStatService` reports success and failure counts per read type, both device-wide and per calling app:

```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 */ }
})
```

Some HAL methods, such as `print(userId, callback)` and `searchMag(userId, timeout, callback)`, receive a `userId` parameter identifying the calling app. Resolve it to a package name with `packageManager.getNameForUid(userId)`. Use that package name to attribute statistics to the correct app.

## Read the result

A correct implementation always reports hardware events through the caller's callback, never through a return value alone. It also calls `stopAllReaders()` after a card read completes, whether it succeeded or not.

Printer methods are the one exception worth calling out on its own: any of them called before `init()` must throw `IllegalStateException` rather than fail silently.

## Next steps

* [Submit your integration for validation](/en/pos-manufacturers/how-to-guides-pos-mfg/submit-integration-for-validation) — once every call above responds correctly.
* [Service interfaces reference](/en/pos-manufacturers/reference-pos-mfg/service-interfaces) — full method signatures, including the interfaces not shown here.
* [EMV state machine](/en/pos-manufacturers/core-concept-pos-mfg/emv-state-machine) — the flow that follows a successful chip or contactless card read.