void ACSACR1222LLCDDisplay::setMessage(unsigned char rowid, std::string message)
    {
        std::vector<unsigned char> data;
        // The first character will not be displayed on the LCD screen :(
        data.push_back(' ');

        data.insert(data.end(), message.begin(), message.end());
        // Make sure we don't overflow the LCD line
        if (data.size() > 16)
        {
            data = std::vector<unsigned char>(data.begin(), data.begin() + 16);
        }
        else // or underflow it (resulting in potential garbage on screen)
        {
            while (data.size() < 16)
            {
                data.push_back(' ');
            }
        }

        // Always use fonts Set A, not bold.
        unsigned char option = 0x00;
        unsigned char position = (rowid ? 0x40 : 0x00);

        getPCSCReaderCardAdapter()->sendAPDUCommand(0xFF, option, 0x68, position, data);
    }
    void MifareUltralightPCSCCommands::writePage(int page, const std::vector<unsigned char>& buf)
    {
        if (buf.size() > 16)
        {
            THROW_EXCEPTION_WITH_LOG(std::invalid_argument, "Bad buffer parameter.");
        }

        getPCSCReaderCardAdapter()->sendAPDUCommand(0xFF, 0xD6, 0x00, static_cast<unsigned char>(page), static_cast<unsigned char>(buf.size()), buf);
    }
    void ACSACR1222LLCDDisplay::scroll(unsigned char x, unsigned char y, unsigned char xRange, unsigned char yRange, unsigned char speedPixel, LCDScrollPeriod speedPeriod, LCDScrollDirection direction)
    {
        std::vector<unsigned char> data;
        data.push_back(x);
        data.push_back(y);
        data.push_back(xRange);
        data.push_back(yRange);
        data.push_back(speedPixel | (speedPeriod << 4));
        data.push_back(direction);

        getPCSCReaderCardAdapter()->sendAPDUCommand(0xFF, 0x00, 0x6D, 0x00, data);
    }
    void MifareUltralightCOmnikeyXX22Commands::authenticate(std::shared_ptr<TripleDESKey> authkey)
    {
        if (!authkey)
        {
            authkey.reset(new TripleDESKey("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"));
        }

        EXCEPTION_ASSERT(authkey->getLength() >= 16, LibLogicalAccessException, "Invalid key length.");

        // Load key part1 to key slot 1
        getPCSCReaderCardAdapter()->sendAPDUCommand(0xFF, 0x82, 0x00, 0x00, 0x08, std::vector<unsigned char>(authkey->getData(), authkey->getData() + 8));
        // Load key part2 to key slot 2
        getPCSCReaderCardAdapter()->sendAPDUCommand(0xFF, 0x82, 0x00, 0x01, 0x08, std::vector<unsigned char>(authkey->getData() + 8, authkey->getData() + 16));

        // Authenticate with key 0
        std::vector<unsigned char> command;
        command.push_back(0x01);
        command.push_back(0x00);
        command.push_back(0x01);
        command.push_back(0x60);
        command.push_back(0x00);
        getPCSCReaderCardAdapter()->sendAPDUCommand(0xFF, 0x86, 0x00, 0x00, static_cast<unsigned char>(command.size()), command);
    }
    bool MifareCherryCommands::loadKey(unsigned char keyno, MifareKeyType /*keytype*/, const void* key, size_t keylen, bool /*vol*/)
    {
        bool r = false;

        // To check on Cherry documentation why key #0 failed.
        if (keyno == 0)
        {
            keyno = 1;
        }
        std::vector<unsigned char> vector_key((unsigned char*)key, (unsigned char*)key + keylen);
        getPCSCReaderCardAdapter()->sendAPDUCommand(0xFF, 0x82, 0x00, keyno, static_cast<unsigned char>(keylen), vector_key);
        r = true;

        return r;
    }
size_t MifarePCSCCommands::updateBinary(unsigned char blockno, const void* buf, size_t buflen)
{
    if ((buflen >= 256) || (!buf))
    {
        THROW_EXCEPTION_WITH_LOG(std::invalid_argument, "Bad buffer parameter.");
    }

    size_t r = 0;

    unsigned char result[256];
    size_t resultlen = sizeof(result);

    getPCSCReaderCardAdapter()->sendAPDUCommand(0xFF, 0xD6, 0x00, blockno, static_cast<unsigned char>(buflen), reinterpret_cast<const unsigned char*>(buf), buflen, result, &resultlen);
    r = buflen;

    return r;
}
bool MifarePCSCCommands::authenticate(unsigned char blockno, unsigned char keyno, MifareKeyType keytype)
{
    bool r = false;

    unsigned char command[2];
    size_t commandlen = sizeof(command);

    command[0] = static_cast<unsigned char>(keytype);
    command[1] = keyno;

    unsigned char result[256];
    size_t resultlen = 256;

    getPCSCReaderCardAdapter()->sendAPDUCommand(0xFF, 0x88, 0x00, blockno, command, commandlen, result, &resultlen);
    r = true;

    return r;
}
    void MifareCherryCommands::authenticate(unsigned char blockno, unsigned char keyno, MifareKeyType keytype)
    {
        std::vector<unsigned char> command;

        // To check on Cherry documentation why key #0 failed.
        if (keyno == 0)
        {
            keyno = 1;
        }

        command.push_back(0x01);
        command.push_back(0x00);
        command.push_back(blockno);
        command.push_back(static_cast<unsigned char>(keytype));
        command.push_back(keyno);

        getPCSCReaderCardAdapter()->sendAPDUCommand(0xFF, 0x86, 0x00, 0x00, static_cast<unsigned char>(command.size()), command);
    }
bool MifarePCSCCommands::loadKey(unsigned char keyno, MifareKeyType keytype, const void* key, size_t keylen, bool vol)
{
    bool r = false;

    unsigned char result[256];
    size_t resultlen = 256;

    getPCSCReaderCardAdapter()->sendAPDUCommand(0xFF, 0x82, (vol ? 0x00 : 0x20), static_cast<char>(keyno), static_cast<unsigned char>(keylen), reinterpret_cast<const unsigned char*>(key), keylen, result, &resultlen);
    if (!vol && (result[resultlen - 2] == 0x63) && (result[resultlen - 1] == 0x86))
    {
        if (keyno == 0)
        {
            r = loadKey(keyno, keytype, key, keylen, true);
        }
    }
    else
    {
        r = true;
    }

    return r;
}
size_t MifarePCSCCommands::readBinary(unsigned char blockno, size_t len, void* buf, size_t buflen)
{
    if ((len >= 256) || (len > buflen) || (!buf))
    {
        THROW_EXCEPTION_WITH_LOG(std::invalid_argument, "Bad buffer parameter.");
    }

    size_t r = 0;

    unsigned char result[256];
    size_t resultlen = 256;

    getPCSCReaderCardAdapter()->sendAPDUCommand(0xFF, 0xB0, 0x00, blockno, static_cast<unsigned char>(len), result, &resultlen);

    r = resultlen - 2;
    if (r > buflen)
    {
        r = buflen;
    }
    memcpy(buf, result, r);

    return r;
}
 void ACSACR1222LLCDDisplay::stopScrolling()
 {
     getPCSCReaderCardAdapter()->sendAPDUCommand(0xFF, 0x00, 0x6F, 0x00, 0x00);
 }
	void MifareUltralightCSpringCardCommands::startGenericSession()
	{
		// Suspend card tracking
		getPCSCReaderCardAdapter()->sendAPDUCommand(0xFF, 0xFB, 0x01, 0x00);
	}
	void MifareUltralightCSpringCardCommands::stopGenericSession()
	{
		// Resume card tracking
		getPCSCReaderCardAdapter()->sendAPDUCommand(0xFF, 0xFB, 0x00, 0x00);
	}
    std::vector<unsigned char> MifareUltralightPCSCCommands::readPage(int page)
    {
        std::vector<unsigned char> result = getPCSCReaderCardAdapter()->sendAPDUCommand(0xFF, 0xB0, 0x00, static_cast<unsigned char>(page), 16);

		return std::vector<unsigned char>(result.begin(), result.end() - 2);
    }
 void ACSACR1222LLCDDisplay::setBacklight(bool enable)
 {
     getPCSCReaderCardAdapter()->sendAPDUCommand(0xFF, 0x00, 0x64, (enable ? 0xff : 0x00), 0x00);
 }
 void ACSACR1222LLCDDisplay::setContrast(unsigned char value)
 {
     getPCSCReaderCardAdapter()->sendAPDUCommand(0xFF, 0x00, 0x6C, value, 0x00);
 }
 std::vector<unsigned char> MifareUltralightCSpringCardCommands::sendGenericCommand(const std::vector<unsigned char>& data)
 {
     return getPCSCReaderCardAdapter()->sendAPDUCommand(0xFF, 0xFE, 0x01, 0x08, static_cast<unsigned char>(data.size()), data);
 }
 void ACSACR1222LLCDDisplay::clear()
 {
     LLA_LOG_CTX("ACS_ACR_1222L Clearing LCD screen ");
     getPCSCReaderCardAdapter()->sendAPDUCommand(0xFF, 0x00, 0x60, 0x00, 0x00);
 }