#include "flash_iface_spidev.h"
#include "flash_sendrecv.h"
#include "spi_port.h"
#include <string.h>

static t_flash_errs f_send(struct st_flash_iface *iface,
                           const unsigned char* vals, size_t *psize) {
    const t_spi_dev *dev = (const t_spi_dev *)iface->port_data;
    size_t snd_size = *psize;
    while ((snd_size > 0) && spi_port_tx_rdy(dev)) {
        spi_port_tx_word(dev, *vals++);
        snd_size--;
    }
    *psize = snd_size;
    return 0;
}



static t_flash_errs f_recv(struct st_flash_iface *iface,
                           unsigned char* vals, size_t *psize) {
    const t_spi_dev *dev = (const t_spi_dev *)iface->port_data;
    size_t rcv_size = *psize;

    while ((rcv_size > 0) && spi_port_rx_rdy(dev)) {
        volatile uint8_t ret = spi_port_rx_word(dev) & 0xFF;
        chip_wdt_reset();
        if (vals != NULL) {
            *vals++ = ret;
        }
        rcv_size--;
    }
    *psize = rcv_size;
    return 0;
}



static t_flash_errs f_select(t_flash_iface *iface, size_t total_size) {
    (void)total_size;
    const t_spi_dev *dev = (const t_spi_dev *)iface->port_data;
    spi_exchange_start(dev);
    return 0;
}

static t_flash_errs f_unselect(t_flash_iface *iface) {
    const t_spi_dev *dev = (const t_spi_dev *)iface->port_data;
    spi_exchange_finish(dev);
    return 0;
}

static const t_flash_sendrecv_iface f_sendrecv_iface = {
    f_send,
    f_recv,
    f_select,
    f_unselect
};


t_flash_errs flash_iface_spidev_init(t_flash_iface *iface, const t_spi_dev *dev) {
    t_flash_errs err = ((iface == NULL) || (dev == NULL) ||
                        (dev->wrdlen != FLASH_IFACE_SPIDEV_WRDLEN)) ?
                FLASH_ERR_INVALID_PARAMS : FLASH_ERR_OK;
    if (!err) {
        spi_dev_init(dev);
        memset(iface, 0, sizeof(t_flash_iface));
        iface->port_exec_tout_ms = 2;
        flash_sendrecv_init(iface, &f_sendrecv_iface);
        iface->flush = NULL;
        iface->port_data = (void*)dev;
    }
    return err;
}


t_flash_errs flash_iface_spidev_close(t_flash_iface *iface) {
    const t_spi_dev *dev = (const t_spi_dev *)iface->port_data;
    spi_dev_close(dev);
    return FLASH_ERR_OK;
}
