#include <stdio.h>
#include <stdint.h>
#include <string.h>

#include "port.h"
#include "ot/crc.h"
#include "proto.h"
#include "tz_log.h"

#include "spi_framing.h"

#define min(a ,b) ((a) < (b) ? (a) : (b))

//#define DEBUG_FRAMES


uint16_t spi_build_frame(uint8_t pcb, uint16_t size, uint8_t *payload, uint8_t *frame) {
    uint16_t crc;
    frame[0] = pcb;
    frame[1] = size;
    /* copy payload */
    P_memcpy(frame + 2, payload, frame[1]);
    /* compute and add crc */
    crc = crc16_buf(frame, frame[1] + 2, 0xFFFF);
    frame[size+2] = crc & 0xFF;
    frame[size+3] = (crc >> 8) & 0xFF;
    //LOGD("payload size %x\n",(size + 4));
    return (size + 4);
}

uint16_t spi_check_frame(uint8_t *frame, uint16_t size) {
    uint16_t crc;
    crc = crc16_buf(frame, size-2, 0xFFFF);

    /* return error in case of a bad CRC*/
    if (frame[size-1] != ((crc >> 8) & 0xFF) || frame[size-2] != (crc & 0xFF)) {
        return 1;
    }

    return 0;
}

uint16_t next_frame(uint8_t *apdu, uint16_t size, uint16_t offset,
                    uint8_t *frame, uint8_t channel, uint8_t maxPayloadSize) {
    uint8_t pcb;
    uint16_t payload_size;

    if(maxPayloadSize == 0) {
        maxPayloadSize = SPI_MAX_PAYLOAD_SIZE;
    }

    /* compute header values */
    if ((size - offset) > maxPayloadSize) {
        pcb = ESE_MAKE_PCB(ESE_PCB_BLOCK_CHAINED, channel);
    } else {
        pcb = ESE_MAKE_PCB(ESE_PCB_BLOCK_LAST, channel);
    }

    payload_size = min(size - offset, maxPayloadSize);
//    LOGD("payload size %x\n", payload_size);
    return spi_build_frame(pcb, payload_size, apdu + offset, frame);
}
