#include "mcp2521_hardware_handle.hpp"

#ifdef ESP_PLATFORM
#include "mcp2521_hardware_esp.hpp"

const uint8_t null_buffer[32] = {0};

void MCP2521_HardwareHandle_ESP::spi_transmit(spi_transaction_t *t) {
    xSemaphoreTake(spiMutex, portMAX_DELAY);
    spi_device_transmit(this->spi_device_handle, t);
    xSemaphoreGive(spiMutex);
}

void MCP2521_HardwareHandle_ESP::execute(uint8_t cmd) {
    spi_transaction_ext_t t = {
        .base = {
            .flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR,
            .cmd = cmd,
            .addr = 0,
            .length = 0,
            .rxlength = 0,
            .tx_buffer = NULL,
            .rx_buffer = NULL
        },
        .command_bits = 8,
        .address_bits = 0,
        .dummy_bits = 0,
    };

    spi_transmit((spi_transaction_t*)(&t));
}

void MCP2521_HardwareHandle_ESP::execute(uint8_t cmd, uint8_t address) {
    spi_transaction_ext_t t = {
        .base = {
            .flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR,
            .cmd = cmd,
            .addr = address,
            .length = 0,
            .rxlength = 0,
            .tx_buffer = NULL,
            .rx_buffer = NULL
        },
        .command_bits = 8,
        .address_bits = 8,
        .dummy_bits = 0,
    };

    spi_transmit((spi_transaction_t*)(&t));
}

void MCP2521_HardwareHandle_ESP::read(uint8_t cmd, uint8_t *data, size_t length, uint8_t address) {
    spi_transaction_ext_t t = {
        .base = {
            .flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR,
            .cmd = cmd,
            .addr = address,
            .length = 8*length,
            .rxlength = 8*length,
            .tx_buffer = null_buffer,
            .rx_buffer = data
        },
        .command_bits = 8,
        .address_bits = 8,
        .dummy_bits = 0,
    };

    spi_transmit((spi_transaction_t*)(&t));
}

void MCP2521_HardwareHandle_ESP::read(uint8_t cmd, uint8_t *data, size_t length) {
    spi_transaction_ext_t t = {
        .base = {
            .flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR,
            .cmd = cmd,
            .addr = 0,
            .length = 8*length,
            .rxlength = 8*length,
            .tx_buffer = null_buffer,
            .rx_buffer = data
        },
        .command_bits = 8,
        .address_bits = 0,
        .dummy_bits = 0,
    };

    spi_transmit((spi_transaction_t*)(&t));
}

uint8_t MCP2521_HardwareHandle_ESP::read(uint8_t cmd, uint8_t address) {
    uint8_t result = 0;
    spi_transaction_ext_t t = {
        .base = {
            .flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR,
            .cmd = cmd,
            .addr = address,
            .length = 8,
            .rxlength = 8,
            .tx_buffer = null_buffer,
            .rx_buffer = &result
        },
        .command_bits = 8,
        .address_bits = 8,
        .dummy_bits = 0,
    };

    spi_transmit((spi_transaction_t*)(&t));
    return result;
}

uint8_t MCP2521_HardwareHandle_ESP::read(uint8_t cmd) {
    uint8_t result;
    spi_transaction_ext_t t = {
        .base = {
            .flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR,
            .cmd = cmd,
            .addr = 0,
            .length = 8,
            .rxlength = 8,
            .tx_buffer = null_buffer,
            .rx_buffer = &result
        },
        .command_bits = 8,
        .address_bits = 0,
        .dummy_bits = 0,
    };

    spi_transmit((spi_transaction_t*)(&t));
    return result;
}

void MCP2521_HardwareHandle_ESP::write(uint8_t cmd, uint8_t *data, size_t length, uint8_t address) {
    uint8_t result;
    spi_transaction_ext_t t = {
        .base = {
            .flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR,
            .cmd = cmd,
            .addr = address,
            .length = 8*length,
            .rxlength = 0,
            .tx_buffer = data,
            .rx_buffer = NULL
        },
        .command_bits = 8,
        .address_bits = 8,
        .dummy_bits = 0,
    };

    spi_transmit((spi_transaction_t*)(&t));
}

void MCP2521_HardwareHandle_ESP::write(uint8_t cmd, uint8_t *data, size_t length) {
    spi_transaction_ext_t t = {
        .base = {
            .flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR,
            .cmd = cmd,
            .addr = 0,
            .length = 8*length,
            .rxlength = 0,
            .tx_buffer = data,
            .rx_buffer = NULL
        },
        .command_bits = 8,
        .address_bits = 0,
        .dummy_bits = 0,
    };

    spi_transmit((spi_transaction_t*)(&t));
}

void MCP2521_HardwareHandle_ESP::write(uint8_t cmd, uint8_t data, uint8_t address) {
    spi_transaction_ext_t t = {
        .base = {
            .flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR,
            .cmd = cmd,
            .addr = address,
            .length = 8,
            .rxlength = 0,
            .tx_buffer = &data,
            .rx_buffer = NULL
        },
        .command_bits = 8,
        .address_bits = 8,
        .dummy_bits = 0,
    };

    spi_transmit((spi_transaction_t*)(&t));
}

void MCP2521_HardwareHandle_ESP::write(uint8_t cmd, uint8_t data) {
    spi_transaction_ext_t t = {
        .base = {
            .flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR,
            .cmd = cmd,
            .addr = 0,
            .length = 8,
            .rxlength = 0,
            .tx_buffer = &data,
            .rx_buffer = NULL
        },
        .command_bits = 8,
        .address_bits = 0,
        .dummy_bits = 0,
    };

    spi_transmit((spi_transaction_t*)(&t));
}

#endif
