#include "chip.h"
#include "flash.h"

#include <string.h>



#define SSP_FIFO_SIZE 8






typedef struct {
    volatile LPC_SSP_T *SSP;
    unsigned cs_pin;
    unsigned onfly;
} t_flash_iface_ssp_data;

static t_flash_iface_ssp_data f_ssp_data;



static t_flash_errs f_send(struct st_flash_iface *iface,
                           const unsigned char* vals, size_t *psize) {
    t_flash_iface_ssp_data *ssp_data = (t_flash_iface_ssp_data *)iface->port_data;

    size_t snd_size = *psize;

    while (snd_size && (ssp_data->onfly < SSP_FIFO_SIZE)) {
        uint8_t put_val = vals == NULL ? 0xFF : *vals++;
        ssp_data->SSP->DR = put_val;
        snd_size--;
        ssp_data->onfly++;
    }

    *psize = snd_size;

    return 0;
}



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

    while ((rcv_size!=0) && (ssp_data->SSP->SR & SSP_STAT_RNE)) {
        volatile unsigned char ret;
        ret = ssp_data->SSP->DR;
        if (vals != NULL)
            *vals++ = ret;
        rcv_size--;
        ssp_data->onfly--;
    }
    *psize = rcv_size;
    return 0;
}


static t_flash_errs f_select(t_flash_iface *iface, size_t total_size) {
    t_flash_iface_ssp_data *ssp_data = (t_flash_iface_ssp_data *)iface->port_data;
    LPC_PIN_OUT(ssp_data->cs_pin, 0);
    ssp_data->onfly = 0;

    while (ssp_data->SSP->SR & SSP_STAT_RNE) {
        volatile unsigned char ret __attribute__((unused));
        ret = ssp_data->SSP->DR;
    }
    return 0;
}

static t_flash_errs f_unselect(t_flash_iface *iface) {
    t_flash_iface_ssp_data *ssp_data = (t_flash_iface_ssp_data *)iface->port_data;
    LPC_PIN_OUT(ssp_data->cs_pin, 1);
    return 0;
}


t_flash_errs flash_iface_init_lpc43xx_ssp(t_flash_iface *iface, int ssp_port, unsigned cs_pin) {
    int err = iface==NULL ? FLASH_ERR_INVALID_PARAMS : 0;
    if (!err) {
        t_flash_iface_ssp_data *ssp_data = &f_ssp_data;
        if (ssp_port==0) {
            ssp_data->SSP = LPC_SSP0;
        } else if (ssp_port==1)  {
            ssp_data->SSP = LPC_SSP1;
        } else {
            err = FLASH_ERR_INVALID_PARAMS;
        }

        if (!err) {
            memset(iface, 0, sizeof(t_flash_iface));
            ssp_data->cs_pin = cs_pin;
            iface->port_exec_tout = 2;
            iface->port_data = ssp_data;
            iface->select = f_select;
            iface->unselect = f_unselect;
            iface->send = f_send;
            iface->recv = f_recv;
            iface->flush = NULL;
        }
    }
    return err;
}
