> For the complete documentation index, see [llms.txt](https://sandbox-docs.verifone.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://sandbox-docs.verifone.com/adk-5.0-programmers-guide/readme/system_overview/pg_all_components/pg_mdb_users_guide.md).

# MDB API Programmers Guide

libmdb provides a C++ client API for using the MDB interface in the Neo K81 firmware.

## General MDB Information <a href="#mdb_info" id="mdb_info"></a>

MDB is a communication protocol used in vending machines (VMC). The vending machine itself is master on a bus and communicates with different slaves, each of them uses an own address. Payment terminals are mentioned as cashless devices in MDB spec, its default slave address is 0x10. Other slaves are Coin Acceptors (0x08), Bill Validators (0x30), Communication Devices (0x18) and others. Based on this address, a slave supports up to 8 main commands, starting with the base address. So VMC can send the command 0x10 to 0x17 to a cashless payment terminal. These commands are 0x10 = RESET, 0x11 = SETUP, 0x12 = POLL, 0x13 = VEND, 0x14 = READER, 0x15 = REVALUE and 0x17 = EXPANSION. 0x16 is not used for now. Details about these commands and their subcommand can be found in chapter 7 of MDB specification.

VMC has to send a POLL command to each slave on MBD bus approx every 20-200ms. If a slave wants to send back data to the VMC, the slave device can only responde to one of these POLL commands. Handling of POLL commands and send back data to the VMC is completly handled by libmdb, but it needs to be configured on which slave address it should listen.

Default address is 0x10, but to be able to connect two cashless devices to the same vending machine, an alternative address 0x60 is available. This may be used if a VMC supports a closed payment system which is realized by a cashless device with address 0x10. In this case, our terminal may be configured to use 0x60 as slave address to coexist with the other one.

## Function Groups <a href="#mdb_func" id="mdb_func"></a>

There are 5 groups of functions:

* Connection setup: mdb\_setup. For most users MDB::DefaultLink() should be a good starting point.
* I/O functions for sending and receiving data: mdb\_io
* "get" functions that can be used to extract data from received messages: mdb\_data
* "send" functions that prepare MDB messages based on parameters and send them to the VMC: mdb\_send
* FTL functions for implementing file transfer: mdb\_ftl

## Getting Started <a href="#mdb_start" id="mdb_start"></a>

Before being able to use the MDB interface, libmdb needs to be connected to the secure processor and MDB needs to be activated. Connecting uses the MDB::connect method. An alternative is to use MDB::DefaultLink, which returns a reference to a connected MDB object using the default link, which should be OK for most users.

The next step is to start the MDB protocol on secure processor side using MDB::start. This also tells the secure processor on which MDB addresses to accept data. libmdb can accept data for the addresses of the cashless devices 1 and 2 and for the age verification device or a combination of one of he cashless devices and the age verification device.

After starting MDB, the application can poll the secure processor for received data using MDB::receive or MDB::peek. Unlike receive peek reads the data without removing it from the input queue.

The first byte of the received message contains the MDB address in the upper 5 bits. If two addresses have been selected in MDB::start, this byte can be used to find out which address was used when receiving the command.

In the next step MDB::getCommand can be used to find out, which command was received. With this information one of the data extraction functions (mdb\_data) can be used to extract the data from the message using a function API.

If applicable the reply can be sent using one of the send functions (mdb\_send).

## Simplified code examples <a href="#mdb_example" id="mdb_example"></a>

The following examples are not intended to be used in real-world applications. It should only demonstrate how libmdb can be used. Please note, that different VMC may send additional MDB commands during initialization and/or during payment. It is recommended to test the final implementation against real VMCs.

### MDB main loop <a href="#mdb_mainloop" id="mdb_mainloop"></a>

```cpp
// This is a very limited rough example how to set up a main loop in a cashless payment device
// to communicate via ADK MDB with a vending machine. For simplification, it does not do any
// error handling, flow control, payment, cancellations, timeouts, malfunctions, ...
// Do not use this example for real implementations!
#include "mdb.h"
void mdbTest(void)
{
   unsigned char dummy_receipt[] =
   " -C-U-S-T-O-M-E-R- \n"
   " -R-E-C-E-I-P-T- \n"
   " \n"
   "Terminal ID 54026151\n"
   "TA No. 999190 RNo 0160\n"
   " \n"
   " Card payment \n"
   " Visa contactless \n"
   " Visa \n"
   " \n"
   " E U R 5 , 5 8 \n"
   " \n"
   "PAN ############1871\n"
   "EMV AID A0000000031010\n"
   "VU no 62850400000001\n"
   "Date 09.05.23 07:57 Time\n"
   " \n"
   "*** Payment approved ***\n";
   using namespace vfimdb;
   bool debug_port = false;
   bool sessionActive = false;
   MDB myMDB;
   MDB_Error r;
   myMDB.setTrace(mdbTraceFunc, (void *)myMDB);
   myMDB.setTimeout(2500);
   myMDB.connect(NULL);
   myMDB.start(MDB_CASHLESS_1, debug_port);
   // this loop will never end
   for(;;)
   {
   std::vector<unsigned char> cmd;
   // check every 100ms if a MDB command was received by low level functions
   mssleep(100);
   r = myMDB.receive(cmd);
   if ( cmd.size() > 0 )
   {
   // a command was received, get its type and handle it
   MDBCommand cmdType = myMDB.getCommand(cmd);
   if ( cmdType == MDB_RESET)
   {
   // MDB RESET may be answered by JUST RESET (see MDB hints)
   myMDB.sendJustReset(-1);
   sessionActive = false;
   }
   else if ( cmdType == MDB_SETUP_CONFIG_DATA)
   {
   // SETUP CONFIG Data received, informs about reader level and display of VMC
   // if necessary, get data sent by VMC
   unsigned int level, cols, rows, disptype;
   myMDB.getSetupConfigData(cmd, level, cols, rows, disptype);
   // answer the SETUP CONFIG with our configuration
   unsigned int currencyCodeUX700 = 0x1978,
   scaleFactorUX700 = 1,
   decimalPlacesUX700 = 2,
   maxResponseTimeUX700 = 10,
   capabilitiesUX700 = MDB_CAP_REFUND;
   bool batteryUX700 = false;
   myMDB.sendConfigData(level, currencyCodeUX700, scaleFactorUX700,
   decimalPlacesUX700, maxResponseTimeUX700,
   capabilitiesUX700, batteryUX700, -1);
   }
   else if ( cmdType == MDB_SETUP_PRICE )
   {
   // SETUP PRICE received, can be ignored
   ;
   }
   else if ( cmdType == MDB_REQUEST_ID)
   {
   // REQUEST ID received, gives data about VMC
   // if necessary, read data sent by VMC
   std::string manufCode, modelNumber, serialNumber;
   unsigned int softwareVersion;
   myMDB.getRequestID(cmd, manufCode, modelNumber, serialNumber, softwareVersion);
   // answer the REQUEST ID with our configuration
   char manufCodeUX700[3+1] = "VFI",
   modelNumberUX700[12+1] = "UX700 MDB ",
   serialNumberUX700[12+1] = "123-456-789 ";
   unsigned int softwareVersionUX700 = 0x0090,
   optFeaturesUX700 = MDB_FEAT_EXPANDED_CURRENCY |
   MDB_FEAT_MULTICUR | MDB_FEAT_FTL |
   MDB_FEAT_SELECTIONFIRST;
   myMDB.sendPeripheralId(manufCodeUX700, modelNumberUX700, serialNumberUX700,
   softwareVersionUX700, optFeaturesUX700, -1);
   }
   else if (cmdType == MDB_ENABLE)
   {
   // READER ENABLED received, allows us to accept payments
   // optional: show some welcome message
   myMDB.sendDisplayText("Verifone UX700 ready", 2000, -1);
   mssleep(1500);
   myMDB.sendDisplayText(" ", 2000, -1);
   }
   else if (cmdType == MDB_DISABLE)
   {
   // READER DISBALE received, we are no more allowed to accept cards
   ;
   }
   else if ( cmdType == MDB_REVALUE_LIMIT)
   {
   // REVALUE LIMIT received, some VMC want to know the limits
   myMDB.sendRevalueLimitAmount(0, -1);
   }
   else if (cmdType == MDB_VEND_REQUEST)
   {
   // VMC starts payment
   unsigned int amount, item;
   char cHlp[33] = {0x00};
   // determine the payment amount and (optional) item number
   myMDB.getVendRequest(cmd, amount, item);
   // optional: do some user messages on VMC display
   if ( cardPresent() )
   {
   // card is already inserted
   if (amount < 100)
   sprintf(cHlp, "Payment 0.%02dPlease wait", amount % 100);
   else
   sprintf(cHlp, "Payment %3d.%02dPlease wait", amount / 100, amount % 100);
   myMDB.sendDisplayText(cHlp, 2000, -1);
   }
   else
   {
   // no card available
   if (amount < 100)
   sprintf(cHlp, "Payment 0.%02dInsert card", amount % 100);
   else
   sprintf(cHlp, "payment %3d.%02dInsert card", amount / 100, amount % 100);
   myMDB.sendDisplayText(cHlp, 2000, -1);
   // wait for insert of card
   while ( cardPresent() );
   sessionActive = true;
   }
   // here the payment should be done, simulate it by a sleep
   mssleep(1000);
   // if payment is successful, answer with VEND APPROVED (else VEND DENIED)
   myMDB.sendVendApproved(amount, -1);
   }
   else if (cmdType == MDB_VEND_SUCCESS)
   {
   // VEND SUCCESS received, delivery of goods in VMC was successful
   // optional: do some user messages on VMC display
   myMDB.sendDisplayText("Purchase success", 2000, -1);
   // optional: send payment receipt (see MDB hints)
   std::vector<unsigned char> receipt;
   receipt.resize(sizeof(dummy_receipt));
   memcpy(&receipt[0], dummy_receipt, sizeof(dummy_receipt));
   myMDB.ftlSendData(0x00, 0xA0, receipt, -1);
   }
   else if (cmdType == MDB_VEND_FAILURE)
   {
   // VEND FAILURE received, delivery of goods in VMC was erronous
   // optional: do some user messages on VMC display
   myMDB.sendDisplayText("Purchase aborted", 2000, -1);
   // here a cancellation of the payment is necessary, simulate by a sleep
   mssleep(1000);
   // end the session
   myMDB.sendEndSession(-1);
   }
   else if ( cmdType == MDB_SESSION_COMPLETE)
   {
   // SESSION COMPLETE received, normally the last MDB command in a payment session
   // can be used to wait for card eject if not done before
   while ( cardPresent() )
   {
   myMDB.sendDisplayText("remove card", 2000, -1);
   mssleep(2000);
   }
   myMDB.sendDisplayText(" ", 2000, -1);
   myMDB.sendEndSession(-1);
   sessionActive = false;
   }
   else
   {
   // some other command is received, ....
   ;
   }
   }
   // actually no MDB command is received
   // check, if a card is present and send BEGIN SESSION if so
   if (!sessionActive && cardPresent())
   {
   // send BEGIN SESSSION with pseudo amount 20.00 (see MDB hints)
   myMDB.sendBeginSession(2000, 0, 0, 0, 0, 0, 0, -1);
   sessionActive = true;
   }
   // handle session_active flag
   if(sessionActive && cardPresent())
   sessionActive = false;
   }
   myMDB.setTrace(NULL, NULL);
   r = myMDB.stop();
   myMDB.disconnect();
}
```

### MDB tracer <a href="#mdb_trace" id="mdb_trace"></a>

The libmdb supports information about every command and response, that is sent and received via MDB interface. To use this information e.g. for traces, you can install a callback function to receive notifications. Information are given about send direction (from VMC to terminal or terminal to VMC) as well about all bytes (without checksum). Command and responses are included in a TLV structure, the raw bytes are part of tag DF03.

The following code examples shows how to install the callback, gives an example on how to format bytes and commands, and how to send it to logcat. Example does not include coding to extract DF03 from buffer.

```cpp
// callback function, called by ADK MDB to inform about send/received data by K81 from MDB port
void traceCallback(void *data, MDB::TraceType traceType, const void *buffer, unsigned size)
{
   static bool bDisableTrace = false;
   if (size> 0)
   {
   // Special handling for K81 peek() and receice(): Both will send RECEIVE_DATA, so
   // one received command will by traced twice. Solution: check SEND_HEADER to E005 (=peek())
   // and deactivate trace until a SEND_HEADER with different data is coming
   if ( traceType == MDB::SEND_HEADER && size >= 2)
   {
   if ( memcmp((char *)buffer+size-2, "\xE0\x05", 2) == 0 )
   bDisableTrace = true;
   else
   bDisableTrace = false;
   }
   if ( bDisableTrace )
   return;
   // Trace data are inside TAG DF03 in *buffer
   // so extract data and its size via TLV search ..
   unsigned char data = ...
   unsigned dataLen = ...
   if ( data != NULL && dataLen > 0)
   {
   // forward trace data to logcat
   if (traceType == MDB::SEND_DATA)
   {
   __android_log_print(ANDROID_LOG_INFO, LOGGING_TAG, "MDB to VMC : (%s)",
   resp2name(data));
   }
   else if (traceType == MDB::RECEIVE_DATA)
   {
   __android_log_print(ANDROID_LOG_INFO, LOGGING_TAG, "MDB from VMC: (%s)",
   cmd2name( (MDB)data->getCommand(data, dataLen)) );
   }
   }
   }
}
const char *resp2name(unsigned char *resp)
{
   switch(resp[0])
   {
   case 0x00: return "JUST_RESET"; break;
   case 0x01: return "READER_CONFIG_INFO"; break;
   case 0x02: return "DISPLAY_REQUEST"; break;
   case 0x03: return "BEGIN_SESSION"; break;
   case 0x04: return "SESSION_CANCEL_REQUEST"; break;
   case 0x05: return "VEND_APPROVED"; break;
   case 0x06: return "VEND_DENIED"; break;
   case 0x07: return "END_SESSION"; break;
   case 0x08: return "CANCELLED"; break;
   case 0x09: return "PERIPHERAL_ID"; break;
   case 0x0A: return "MALFUNCTION_ERROR"; break;
   case 0x0B: return "OUT_OF_SEQUENCE"; break;
   case 0x0D: return "REVALUE_APPROVED"; break;
   case 0x0E: return "REVALUE_DENIED"; break;
   case 0x0F: return "REVALUE_LIMIT_AMOUNT"; break;
   case 0x11: return "TIME_DATE_REQUEST"; break;
   case 0x12: return "DATA_ENTRY_REQUEST_RESPONSE"; break;
   case 0x13: return "DATA_ENTRY_CANCEL"; break;
   case 0x1B: return "FTL_REQ_TO_RCV"; break;
   case 0x1C: return "FTL_RETRY_DENY"; break;
   case 0x1D: return "FTL_SEND_BLOCK"; break;
   case 0x1E: return "FTL_OK_TO_SEND"; break;
   case 0x1F: return "FTL_REQ_TO_SEND"; break;
   case 0xFF: return "DIAGNOSTIC_RESPONSE"; break;
   default: return "unknown";
   }
}
const char *cmd2name(MDBCommand cmdType)
{
   switch(cmdType)
   {
   case MDB_RESET : return "RESET"; break;
   case MDB_SETUP_CONFIG_DATA : return "SETUP_CONFIG_DATA"; break;
   case MDB_SETUP_PRICE : return "SETUP_PRICE"; break;
   case MDB_POLL : return "POLL"; break;
   case MDB_VEND_REQUEST : return "VEND_REQUEST"; break;
   case MDB_VEND_CANCEL : return "VEND_CANCEL"; break;
   case MDB_VEND_SUCCESS : return "VEND_SUCCESS"; break;
   case MDB_VEND_FAILURE : return "VEND_FAILURE"; break;
   case MDB_SESSION_COMPLETE : return "SESSION_COMPLETE"; break;
   case MDB_CASH_SALE : return "CASH_SALE"; break;
   case MDB_NEGATIVE_VEND_REQUEST : return "NEGATIVE_VEND_REQUEST"; break;
   case MDB_DISABLE : return "DISABLE"; break;
   case MDB_ENABLE : return "ENABLE"; break;
   case MDB_CANCEL : return "CANCEL"; break;
   case MDB_DATA_ENTRY : return "DATA_ENTRY"; break;
   case MDB_REVALUE_AMOUNT : return "REVALUE_AMOUNT"; break;
   case MDB_REVALUE_LIMIT : return "REVALUE_LIMIT"; break;
   case MDB_REQUEST_ID : return "REQUEST_ID"; break;
   case MDB_DATE_TIME : return "DATE_TIME"; break;
   case MDB_FEATURE_OPTIONS : return "FEATURE_OPTIONS"; break;
   case MDB_FTL_REQUEST_TO_RECEIVE: return "FTL_REQUEST_TO_RECEIVE"; break;
   case MDB_FTL_RETRY_DENY : return "FTL_RETRY_DENY"; break;
   case MDB_FTL_BLOCK : return "FTL_BLOCK"; break;
   case MDB_FTL_OK_TO_SEND : return "FTL_OK_TO_SEND"; break;
   case MDB_FTL_REQUEST_TO_SEND : return "FTL_REQUEST_TO_SEND"; break;
   case MDB_EXP_DIAG : return "EXP_DIAG"; break;
   default : return "unknown"; break;
   }
}
```

## Implementation hints <a href="#mdb_hints" id="mdb_hints"></a>

### Pseudo card amount <a href="#pseudo_amount" id="pseudo_amount"></a>

Normally, a payment on MDB starts with inserting a smart card and informing the VMC about its balance. Only then, the VMC will allow selection of goods. Because it is not always possible to determine the card balance, the MDB spec defines the amount "not yet determined" (0xFFFF). But some VMC may not support this and will show 655,35 (=0xFFFF) as amount. To suppress this, it is a good idea to use a different, configurable amount as default card balance via a terminal menu, e.g. 20,00.

### Reset / Just Reset <a href="#mdb_reset" id="mdb_reset"></a>

The use case for RESET and JUST RESET is not described very clearly in MDB spec. JUST RESET may be an answer to RESET, or it may be the info, that the terminal has just restarted e.g. due to power cycle and wants to have new initialization sequence from VMC. If cashless system answers a RESET with JUST RESET it may possible that the VMC again sends an RESET and initialization may run in an endless loop. One solution may be to add a configuration function to switch on/off sending JUST RESET.

### Duration of the goods issue <a href="#mdb_goods" id="mdb_goods"></a>

There are many different VMCs selling different goods, some may take minutes to deliver. It is recommended to use a configurable, maximum waiting time after sending a VEND approved to the VMC to wait for the VEND success (or VEND failure) answer of the VMC.

### Contactless payment, Always idle mode <a href="#mdb_ctls" id="mdb_ctls"></a>

Normally, payment stars with inserting a card, sending its balance to the VMC and selecting a product on the VMC, followed by the request to make a payment. This works fine when the card is inserted, but is uncomfortable using a contactless card because you have to tap it twice. First tap is to inform the VMC about the card (and a default balance) and second tap to do the payment after customer selects the product. To prevent this, the "Always Idle" mode was introduced to MDB spec. In this case, payment is started by VMC by sending a VEND request without receiving a BEGIN session before. If contactless payment schemes should be supported, it is a good idea support the always idle mode, too. Sometimes, the "Always Idle" mode is named "Selection First", there is no difference, it's only a different name.

### 16 / 32 bit amount <a href="#mdb_amount" id="mdb_amount"></a>

By default, all card balances and payment amounts are 16 bit, allows up to 65535 "Cent". If greater amounts are necessary, the communication can be switch to use 32 bit (plus currency), known as expanded currency mode in MDB spec. Please note, that libmdb.so from ADK MDB automatically formats the amount in the correct way in MDB commands, depending on the commands exchanged during initialization sequence between VMC and terminal.

### Reader levels <a href="#mdb_level" id="mdb_level"></a>

MDB spec defines different reader levels. Please note, that the libmdb.so automatically formats the commands in the correct syntax, depending on the negotiated reader level during initialization sequence between VMC and terminal.

### Display messages <a href="#mdb_display" id="mdb_display"></a>

The MDB spec defines a "Display request" command to show messages on the VCMs display. Be aware, that this command can transport only up to 34 bytes, so normally a 2x16 char display can be addressed only. The libmdb.so limits the length of the message to the given number of rows and columns, transported from VMC to terminal in SETUP [Config](/adk-5.0-programmers-guide/readme/annotated/class_config.md) Data command.

### User interface <a href="#mdb_user" id="mdb_user"></a>

UX700 has an own display to inform customer about payment process and success of payment. May be the VMC has an own display, so it may make sense to send some short display messages like "Payment 5,58 EUR Insert card", "Payment, please wait", "Payment successful", to the VCs display (e.g. 2x16), too. But please consider, that VMC may display own messages on its own display, which will be overwritten by messages sent from cashless terminal. It may a good idea to send a "UX700 in service" or something else when VMC enables cashless-1 system with READER Enable after successful initialisation.

### Reader Enable and Disable <a href="#mdb_enable" id="mdb_enable"></a>

Cashless device is only allowed to accept cards for payment, when VMC sends a READER Enable command. If it sends a READER Disable, cashless is not allowed to accept cards. Please note, that VMC may enable the cashless device after power on and it is allowed to accept cards all the time. But VMC may send a READER Disable if someone put in a coin to the coin acceptor, followed by a READER Enable shortly after that, when the coin payment was done.

### Mode bit and MDB timing <a href="#mdb_modebit" id="mdb_modebit"></a>

MDB uses a so called Mode-Bit to differ between address and data bytes on the bus. In addition, it defines some timing on the bus. All is done and handled by libmdb.so from ADK MDB. No need to manage on application level. But calling the setTimeout() function with a value of approx. 2500ms is needed, otherwise libmdb.so will wait forever in case the VMC will not poll the terminal.

### Printing receipts <a href="#mdb_printing" id="mdb_printing"></a>

There are no special MDB commands to send a print receipt to the VMC. But MDB spec defines a possibility to transport a "file" to the VMC, so a preformatted receipt may be send to the VMC via this file transport layer (FTL). libmdb.so supports the function ftlSendData() to do so. Please note, that support of FTL functions has to be negotiated by VMC and terminal during initialize sequence. In addition, the used fileID for files containing a print receipt should be discussed with the VMC developer.

### Successful payment and cancellation <a href="#mdb_payment" id="mdb_payment"></a>

Please note, that the VMC will start delivery goods if terminal sends a VEND approved. So sending a VEND approved should only be done if it is guaranteed that the payment process will be successful. But please be prepared that the delivery of goods may be erroneous and you have to cancel the payment

## Example flows on MDB bus <a href="#mdb_traces" id="mdb_traces"></a>

This section will show some traces from successful initialsation and payment on MDB bus for a cashless device byte by byte. More expamples (but without byte by byte) can be found in chap 7.7 of MDB spec.

### Initialisation (MDB Reader Level 2) <a href="#mdb_init_level2" id="mdb_init_level2"></a>

```cpp
MDB from VMC: 10 (RESET)
MDB to VMC : 00 (JUST_RESET)
MDB from VMC: 110002100201 (SETUP_CONFIG_DATA)
MDB to VMC : 0102197801020A01 (READER_CONFIG_INFO)
MDB from VMC: 1101FFFF0000 (SETUP_PRICE)
MDB from VMC: 17005445540000000000000000000000000000000000000000000000000000 (REQUEST_ID)
MDB to VMC : 095646493132332D3435362D373839205558373030204D44422020209999 (PERIPHERAL_ID)
MDB from VMC: 1401 (ENABLE)
MDB to VMC : 02142056657269666F6E652055583730302020626574726965627362657265697420 (DISPLAY_REQUEST)
MDB to VMC : 02002020202020202020202020202020202020202020202020202020202020202020 (DISPLAY_REQUEST)
```

### Payment (MDB Reader Level 2, contact, "standard") <a href="#mdb_pay_level2std" id="mdb_pay_level2std"></a>

```cpp
MDB to VMC : 03FFFF00000000000000 (BEGIN_SESSION)
MDB from VMC: 1300022EFFFF (VEND_REQUEST)
MDB to VMC : 05022E (VEND_APPROVED)
MDB from VMC: 1302FFFF (VEND_SUCCESS)
MDB from VMC: 1304 (SESSION_COMPLETE)
MDB to VMC : 07 (END_SESSION)
```

### Payment (MDB Reader Level 2, contact, "always idle") <a href="#mdb_pay_level2idle" id="mdb_pay_level2idle"></a>

```cpp
MDB from VMC: 1300022EFFFF (VEND_REQUEST)
MDB to VMC : 05022E (VEND_APPROVED)
MDB from VMC: 1302FFFF (VEND_SUCCESS)
MDB from VMC: 1304 (SESSION_COMPLETE)
MDB to VMC : 07 (END_SESSION)
```

### Initialisation (MDB Reader Level 3) <a href="#mdb_init_level3" id="mdb_init_level3"></a>

```cpp
MDB from VMC: 10 (RESET)
MDB to VMC : 00 (JUST_RESET)
MDB from VMC: 110003100201 (SETUP_CONFIG_DATA)
MDB to VMC : 0103197801020A01 (READER_CONFIG_INFO)
MDB from VMC: 1101FFFF0000 (SETUP_PRICE)
MDB from VMC: 17005445540000000000000000000000000000000000000000000000000000 (REQUEST_ID)
MDB to VMC : 095646493132332D3435362D373839205558373030204D4442202020999900000027 (PERIPHERAL_ID)
MDB from VMC: 17FF030B230511134335FFFFFFFFFF (EXP_DIAG)
MDB to VMC : FF030B230511054335FFFFFFFFFF (DIAGNOSTIC_RESPONSE)
MDB from VMC: 1401 (ENABLE)
MDB to VMC : 02142056657269666F6E652055583730302020626574726965627362657265697420 (DISPLAY_REQUEST)
MDB to VMC : 02002020202020202020202020202020202020202020202020202020202020202020 (DISPLAY_REQUEST)
```

### Payment (MDB Reader Level 3, Expanded Currency Mode) <a href="#mdb_pay_level3" id="mdb_pay_level3"></a>

```cpp
MDB to VMC : 03FFFFFFFF000000000000006465197800 (BEGIN_SESSION)
MDB from VMC: 13000000022EFFFF (VEND_REQUEST)
MDB to VMC : 050000022E (VEND_APPROVED)
MDB from VMC: 1302FFFF (VEND_SUCCESS)
MDB from VMC: 1304 (SESSION_COMPLETE)
MDB to VMC : 07 (END_SESSION)
```

## Using third party tools for trace and VMC simulation <a href="#tools" id="tools"></a>

### General info <a href="#tools-1" id="tools-1"></a>

Besides using the trace callback function supported by ADK MDB, it is possible to use an external MDB trace tool. One of them is offered by third party Qiba, [www.qiba.pt](https://www.qiba.pt). They provide a MDB-USB box, which can be connected and controlled via USB from PC (Windows, Linux, ...). UX700 can be connected to that box via its original MDB plug.

There are three different MDB-USB boxes, it seems to be enough to use the "standard" one. With this box and a corresponding software license from Qiba it is possible to trace communication between a real vending machine and the UX700. Trace software is Java based and should run on different operating systems.

Besides tracing, the box provides a VMC master mode. In this mode the box works as a real vending machine, sending polls and other commands to the UX700. This can be used to test own developed MDB software on UX700.

### What to buy <a href="#tools-2" id="tools-2"></a>

The box: [MDB USB Standard](https://www.shop.qiba.pt/de_CH/shop/p0037q-mdb-usb-standard-1#attr=) (\~ 150,00 EUR) The licence: [MDB Toolchest License](https://www.shop.qiba.pt/de_CH/shop/toolchest-mdb-toolchest-license-52#attr=) (\~ 395,00 EUR) Short cable [MDB Harness Cable](https://www.shop.qiba.pt/de_CH/shop/c0006q-mdb-harness-cable-33#attr=) (\~ 19,00 EUR) Longer cable [MDB Harness Cable OEM 150cm](https://www.shop.qiba.pt/de_CH/shop/c0013q-mdb-harness-cable-oem-150cm-108#attr=) (\~ 29,00 EUR)

It is sufficient to buy one of the cables, they only differ in length. Prices are examples from 2023, check Qiba homepage for actual prices and conditions.

### How to connect box and UX700 and PC: <a href="#tools-3" id="tools-3"></a>

Please check [Qiba homepage](https://docs.qibixx.com/mdb-products/mdb-usb-interface) for details, there are a lot of information and tools The following is only to simplify first usage of MDB USB box.

#### Use box as tracer <a href="#tools-4" id="tools-4"></a>

Connect the box via USB cable to PC, a serial comport should appear (e.g. in windows). Use the provided MDB cable, connect one single end with UX700, other single end with vending machine. UX700 is powered by the VMC via this cable. The third end, which combines the two other single ends, should be connected with the "VMC" connector of the box. The jumpers outside the box must be both set horizontally, the internal jumper must not be set. On PC, you can start the MDB toolchest from Qiba, it's a Java application. Select connect and do some traces, details about [MDB Toolchest](https://docs.qibixx.com/mdb-products/mdb-toolchest) can be found on Qiba homepage.

#### Use box as vending machine simulator <a href="#tools-5" id="tools-5"></a>

The box can be used in a mode, where it works as MDB master. Connect box via USB cable to PC. Use the provided MDB cable, connect one single end with UX700, connect the UX700 power supply to the other single end of the cable. UX700 is powered by its power supply via the MDB cable. The third end has to be connected to "VMC" connector of the box. The jumpers outside the box must be both set horizontally, the internal jumper must not be set.

On PC, open a serial communication program with 115200 baud, e.g. Putty (more examples see Qiba homepage). In Putty, you can send some commands to the box, e.g. the "V" command to shows it's software version. Actual version in 2023 is 4.0.0.2, software and update tools are available at Qiba homepage. You may activate "Implicit CR in every LF", "Implicit LF in every CR" and "Force on" local echo in Putty.

Simulation supports a full function MDB Master, it can be activated by a "D,2" command, after which the box send the MDB init commands to the UX700. Followed by a "D,READER,1" command, the box send a REDAER ENABLE command and the UX700 should be ready to accept smart cards for payment. With "D,REQ,5.58,10" a payment with payment amount 5,58 for item 10 is started. "D,END" simulates a successful delivery of goods and ends the payment. There are additional commands like "D,SETCONF,vmc-reader-level=3" to configure the MDB master simulation. (hint: try to input commands without typing errors, even correct it by backspace will lead to "unknown command" error. Occurs while using Putty, may differ in other tools).

Summarize:

```cpp
D,2 (to enable the VMC simulation)
D,READER,1 (to send a READER Enable to UX700)
D,REQ,5.58,10 (to start a payment with 5.58 for item 10)
... wait until UX700 sends a VEND approved ...
D,END (to signal successful goods delivery and ends the session)
```

The box supports a so called "generic master mode", too. In that mode, it is possible to send commands byte by byte from Putty via USB to box, which then transfer it via MDB to UX700. See Qiba homepage for more details.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://sandbox-docs.verifone.com/adk-5.0-programmers-guide/readme/system_overview/pg_all_components/pg_mdb_users_guide.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
