3

I am trying to write an I2C Communication layer for my PN532 NFC Module.

I have the Arduino code working fine, but I am trying to implement it for Android things. In Arduino my output is as follows:

WriteCommand
Write: 0
Write: 0
Write: 255
Write: 2
Write: 254
Write: 212
Write: 2
Write: 42
Write: 0
/WriteCommand
Read ack frame
Read 1
Read 0
Read 0
Read 255
Read 0
Read 255
Read 0
/Read ack frame

With the following code (copied and modified from a CPP library):

#include <Wire.h>

TwoWire* wire = &Wire;
uint8_t command;

uint8_t pn532_packetbuffer[64];

uint8_t write(uint8_t data) {
    Serial.println("    Write: " + String(data));
    return wire->write(data);
}

uint8_t read() {
    uint8_t value = wire->read();
    Serial.println("    Read " + String(value));
    return value;
}

uint8_t writeCommand(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0) {
    Serial.println("WriteCommand");
    command = header[0];
    wire->beginTransmission(PN532_I2C_ADDRESS);

    write(PN532_PREAMBLE);
    write(PN532_STARTCODE1);
    write(PN532_STARTCODE2);

    uint8_t length = hlen + blen + 1;   // length of data field: TFI + DATA
    write(length);
    write(~length + 1);                 // checksum of length

    write(PN532_HOSTTOPN532);
    uint8_t sum = PN532_HOSTTOPN532;    // sum of TFI + DATA

    for (uint8_t i = 0; i < hlen; i++) {
        if (write(header[i])) {
            sum += header[i];
        } else {
            return PN532_INVALID_FRAME;
        }
    }

    for (uint8_t i = 0; i < blen; i++) {
        if (write(body[i])) {
            sum += body[i];
        } else {
            return PN532_INVALID_FRAME;
        }
    }

    uint8_t checksum = ~sum + 1;            // checksum of TFI + DATA
    write(checksum);
    write(PN532_POSTAMBLE);

    wire->endTransmission();

    Serial.println("/WriteCommand");
    return readAckFrame();
}

uint8_t readAckFrame() {
    Serial.println("Read ack frame");
    const uint8_t PN532_ACK[] = {0, 0, 0xFF, 0, 0xFF, 0};
    uint8_t ackBuf[sizeof(PN532_ACK)];

    uint16_t time = 0;
    do {
        if (wire->requestFrom(PN532_I2C_ADDRESS,  sizeof(PN532_ACK) + 1)) {
            if (read() & 1) {  // check first byte --- status
                break;         // PN532 is ready
            }
        }

        delay(1);
        time++;
        if (time > PN532_ACK_WAIT_TIME) {
            return PN532_TIMEOUT;
        }
    } while (1);


    for (uint8_t i = 0; i < sizeof(PN532_ACK); i++) {
        ackBuf[i] = read();
    }

    if (memcmp(ackBuf, PN532_ACK, sizeof(PN532_ACK))) {
        return PN532_INVALID_ACK;
    }
    Serial.println("/Read ack frame");
    return 0;
}

int16_t getResponseLength(uint8_t buf[], uint8_t len, uint16_t timeout) {
    const uint8_t PN532_NACK[] = {0, 0, 0xFF, 0xFF, 0, 0};
    uint16_t time = 0;

    do {
        if (wire->requestFrom(PN532_I2C_ADDRESS, 6)) {
            if (read() & 1) {  // check first byte --- status
                break;         // PN532 is ready
            }
        }

        delay(1);
        time++;
        if ((0 != timeout) && (time > timeout)) {
            return -1;
        }
    } while (1);

    if (0x00 != read()  ||       // PREAMBLE
        0x00 != read()  ||       // STARTCODE1
        0xFF != read()           // STARTCODE2
    ) {
        return PN532_INVALID_FRAME;
    }

    uint8_t length = read();

    // request for last respond msg again
    wire->beginTransmission(PN532_I2C_ADDRESS);
    for (uint16_t i = 0; i < sizeof(PN532_NACK); ++i) {
        write(PN532_NACK[i]);
    }
    wire->endTransmission();

    return length;
}

int16_t readResponse(uint8_t buf[], uint8_t len, uint16_t timeout) {
    uint16_t time = 0;
    uint8_t length;

    length = getResponseLength(buf, len, timeout);

    do {
        if (wire->requestFrom(PN532_I2C_ADDRESS, 6 + length + 2)) {
            if (read() & 1) {  // check first byte --- status
                break;         // PN532 is ready
            }
        }

        delay(1);
        time++;
        if ((0 != timeout) && (time > timeout)) {
            return -1;
        }
    } while (1);

    if (0x00 != read()  ||       // PREAMBLE
        0x00 != read()  ||       // STARTCODE1
        0xFF != read()           // STARTCODE2
    ) {
        return PN532_INVALID_FRAME;
    }

    length = read();

    if (0 != (uint8_t)(length + read())) {   // checksum of length
        return PN532_INVALID_FRAME;
    }

    uint8_t cmd = command + 1;               // response command
    if (PN532_PN532TOHOST != read() || (cmd) != read()) {
        return PN532_INVALID_FRAME;
    }

    length -= 2;
    if (length > len) {
        return PN532_NO_SPACE;  // not enough space
    }

    uint8_t sum = PN532_PN532TOHOST + cmd;
    for (uint8_t i = 0; i < length; i++) {
        buf[i] = read();
        sum += buf[i];
    }

    uint8_t checksum = read();
    if (0 != (uint8_t)(sum + checksum)) {
        return PN532_INVALID_FRAME;
    }
    read();         // POSTAMBLE

    return length;
}

uint32_t getFirmwareVersion(void) {
    uint32_t response;

    pn532_packetbuffer[0] = PN532_COMMAND_GETFIRMWAREVERSION;

    if (writeCommand(pn532_packetbuffer, 1, 0, 0)) {
        return 0;
    }

    Serial.println("Wrote the command and got a success acknowledge");
    // read data packet
    int16_t status = readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer), 0);
    if (0 > status) {
        return 0;
    }

    response = pn532_packetbuffer[0];
    response <<= 8;
    response |= pn532_packetbuffer[1];
    response <<= 8;
    response |= pn532_packetbuffer[2];
    response <<= 8;
    response |= pn532_packetbuffer[3];

    return response;
}

So in Kotlin I am trying to reproduce this, and while I am writing the correct values I am unable to read the correct values back:

fun Byte.toUnsigned(): Int = when {
    (toInt() < 0) -> 255 + toInt() + 1
    else -> toInt()
}

fun I2cDevice.read(data: ByteArray) {
    read(data, data.size)

    data.forEach {
        android.util.Log.d("I2C","    read: ${it.toUnsigned()}")
    }
}

fun I2cDevice.write(data: ByteArray) {
        write(data, data.size)

    android.util.Log.d("I2C","    write: ${data[0].toUnsigned()}")
}

fun I2cDevice.write(data: Byte) =
    write(ByteArray(1).apply { this[0] = data })

fun I2cDevice.writeCommand(header: ByteArray, body: ByteArray? = null): Int {
    android.util.Log.d("I2C","START")
    write(PN532_PREAMBLE)
    write(PN532_STARTCODE1)
    write(PN532_STARTCODE2)

    val len = (1+header.size + (body?.size?:0)).toByte()
    write(len)
    write((len.inv() + 1).toByte())                 // checksum of length

    write(PN532_HOSTTOPN532)
    var sum: Byte = PN532_HOSTTOPN532    // sum of TFI + DATA

    header.forEach {
        write(it)
        sum = (sum + it).toByte()
    }

    body?.forEach {
        write(it)
        sum = (sum + it).toByte()
    }

    write((sum.inv() + 1).toByte())
    write(PN532_POSTAMBLE)
    return readAckFrame()
}

fun I2cDevice.readAckFrame(): Int {
    val readyCheck = ByteArray(7).apply { this[0] = 0 }

    //while(readyCheck[0].toUnsigned() != 1) {
        read(readyCheck) // <-- will ALWAYS READ 0, 128, 128
    //}
    android.util.Log.d("I2C","Ack complete")
    return 0
}

The problem seems to be that I need to somehow request the data before reading it (wire->requestFrom(PN532_I2C_ADDRESS, sizeof(PN532_ACK) + 1) in the Arduino code). I am writing the correct values and my wiring is correct.

All the Kotlin code is able to read is 0, 128, 128, even though I am asking for 7 bytes.


Fritzing Diagram

3

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.