/*
 * lora_port.c
 *
 *  Created on: Oct 8, 2018
 *      Author: zgh
 */

#include "lora_port.h"
#include "radio.h"
/***************HEADER FILES****************/
#include <string.h>
#include <syslog.h>
#include "ipc_session.h"
#include "lnxall_list.h"
#include "dy_utils/dy_common.h"
#include "dy_utils/dy_ds.h"
#include "dy_utils/kv_array.h"
#include "dy_utils/dy_ipc.h"
/******************************************/

#define COLWIDTH 8
#define OFFSET(r, c) ((r * COLWIDTH) + c)
#define REMAINING(r, c, l) ((int) l - OFFSET(r, c))

#define SPI_DEV_RX    "/dev/spidev0.0"

#define MAXEPOLLSIZE 2

int DEBUG_INFO = 0;

radiodev *rfdev=NULL;

//static int lora_rf_mode = 0;
//static int lora_rf_ch = 0;


/* pkt struct */
static struct pkt_rx_s pktrx[QUEUESIZE]; /* allocat queuesize struct of pkt_rx_s */

static int pt = 0;

//const char *mode[]={"Debug","Test","Release"};
const uint32_t frq_table[3][16] =
{
{
    420000000,  /* 0x69, 0x00, 0x00 */
    421000000,  /* 0x69, 0x40, 0x00 */
    422000000,  /* 0x69, 0x80, 0x00 */
    423000000,  /* 0x69, 0xC0, 0x00 */
    424000000,  /* 0x6A, 0x00, 0x00 */
    425000000,  /* 0x6A, 0x40, 0x00 */
    426000000,  /* 0x6A, 0x80, 0x00 */
    427000000,  /* 0x6A, 0xC0, 0x00 */
    428000000,  /* 0x6B, 0x00, 0x00 */
    429000000,  /* 0x6B, 0x40, 0x00 */
    430000000,  /* 0x6B, 0x80, 0x00 */
    436000000,  /* 0x6D, 0x00, 0x00 */
    437000000,  /* 0x6D, 0x40, 0x00 */
    443000000,  /* 0x6E, 0xC0, 0x00 */
    444000000,  /* 0x6F, 0x00, 0x00 */
    445000000,  /* 0x6F, 0x40, 0x00 */
},
{
    453000000,  /* 0x71, 0x40, 0x00 */
    454000000,  /* 0x71, 0x80, 0x00 */
    455000000,  /* 0x71, 0xC0, 0x00 */
    456000000,  /* 0x72, 0x00, 0x00 */
    457000000,  /* 0x72, 0x40, 0x00 */
    458000000,  /* 0x72, 0x80, 0x00 */
    459000000,  /* 0x72, 0xC0, 0x00 */
    460000000,  /* 0x73, 0x00, 0x00 */
    461000000,  /* 0x73, 0x40, 0x00 */
    462000000,  /* 0x73, 0x80, 0x00 */
    463000000,  /* 0x73, 0xC0, 0x00 */
    464000000,  /* 0x74, 0x00, 0x00 */
    465000000,  /* 0x74, 0x40, 0x00 */
    466000000,  /* 0x74, 0x80, 0x00 */
    467000000,  /* 0x74, 0xC0, 0x00 */
    468000000,  /* 0x75, 0x00, 0x00 */
},
{
    469000000,  /* 0x75, 0x40, 0x00 */
    470000000,  /* 0x75, 0x80, 0x00 */
    471000000,  /* 0x75, 0xC0, 0x00 */
    472000000,  /* 0x76, 0x00, 0x00 */
    473000000,  /* 0x76, 0x40, 0x00 */
    474000000,  /* 0x76, 0x80, 0x00 */
    475000000,  /* 0x76, 0xC0, 0x00 */
    476000000,  /* 0x77, 0x00, 0x00 */
    477000000,  /* 0x77, 0x40, 0x00 */
    488000000,  /* 0x7A, 0x00, 0x00 */
    489000000,  /* 0x7A, 0x40, 0x00 */
    490000000,  /* 0x7A, 0x80, 0x00 */
    491000000,  /* 0x7A, 0xC0, 0x00 */
    492000000,  /* 0x7B, 0x00, 0x00 */
    493000000,  /* 0x7B, 0x40, 0x00 */
    494000000,  /* 0x7B, 0x80, 0x00 */
},
};

extern bool exit_sig;
radiodev * LoRa_dev_init(void)
{
    /* radio device init */
    struct epoll_event ev;
    const char *board_name = NULL;
    
    board_name = get_board_name();
    MSG_LOG(DEBUG_INFO, "board name is %s!!!\n", board_name);
    rfdev = (radiodev *) malloc(sizeof(radiodev));

    rfdev->nss = 108;
    rfdev->rst = 4;
    if (strcmp(board_name, BOARD_WOOLINK_MT7621) == 0)
    {
        rfdev->dio[0] = 4;
        rfdev->rst = 29;
    }
    else
    {
        rfdev->dio[0] = 1;
    }
    rfdev->dio[1] = 0;
    rfdev->dio[2] = 0;
    

    if (strcmp(board_name, BOARD_WOOLINK_MT7621) == 0)
    {
        rfdev->spiport = lgw_spi_open("/dev/spidev0.1");
    }
    else
    {
        rfdev->spiport = lgw_spi_open("/dev/spidev2.0");
    }
    if (rfdev->spiport < 0) {
        dy_syslog(LOG_ERR,"ERROR~ open spi_dev_tx error!\n");
        goto error;
    }
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
    rfdev->freq = frq_table[0][0];
    rfdev->sf = 7;
    rfdev->bw = 125000;
    rfdev->cr = 5;
    rfdev->nocrc = 0;  /* crc check */
    rfdev->prlen = 8;
    rfdev->invertio = 0;
    rfdev->power = 20;
    rfdev->syncword = 18;//DY LORA set 18 //lorawan set 52

    strcpy(rfdev->desc, "RF_RADIO");
    if(get_radio_version(rfdev) == false)
    {
        dy_syslog(LOG_WARNING,"radio version get error");
        goto error;
    }

    int i;
    int epollfd;
    int iofd;
    /* RX DIO 0 */
    epollfd = epoll_create(MAXEPOLLSIZE);
    if(epollfd <= 0)
    {
        dy_syslog(LOG_ERR,  "Epoll create error\n");
        exit(EXIT_FAILURE);
    }
    rfdev->efd = epollfd;
    iofd = digitalInputInit(rfdev->dio[0]);
    if(iofd <=0 )
    {
        dy_syslog(LOG_ERR,  "gpio[%d] create failed\n",rfdev->dio[0]);
        exit(EXIT_FAILURE);
    }
    rfdev->iofd = iofd;
    ev.events = EPOLLIN | EPOLLET;
    ev.data.fd = iofd;
    if(epoll_ctl(epollfd,EPOLL_CTL_ADD,iofd,&ev))
    {
        dy_syslog(LOG_ERR,  "epoll ctl failed\n");
        exit(EXIT_FAILURE);
    }
    for(i =0; i < QUEUESIZE; i++)
        pktrx[i].empty = 1;

    return rfdev;

    error:
    free(rfdev);
    rfdev=NULL;
    return rfdev;
}

int LoRa_set_frq(uint32_t frq_band,uint32_t frq_code)
{
    if(rfdev == NULL)return -1;
    if(frq_code >= LORA_CH_MAX && frq_band > 2)
	{
        dy_syslog(LOG_WARNING,"failed to set frq\n");
        frq_code = 0;
	}
    rfdev->freq = frq_table[frq_band][frq_code];
    setup_channel(rfdev);
    dy_syslog(LOG_INFO, "Listening at SF%i on %.6lf Mhz. syncword is 0x%02x on spiport%i\n", rfdev->sf, (double)(rfdev->freq)/1000000, rfdev->syncword, rfdev->spiport);

    return 0;
}


int LoRa_dev_close()
{
    if(!rfdev)return 0;
    close(rfdev->spiport);
    free(rfdev);
    rfdev = 0;
    return 0;
}

int LoRa_transfer(uint8_t *ptr,int size)
{
    if(rfdev == NULL)return -1;

    single_tx(rfdev, ptr, size);
    return 0;
}

void LoRa_WaitRx(void)
{
    rxlora(rfdev, RXMODE_SCAN);  /* reset lora continue receive mode */
}

bool LoRa_received(void)
{
    if (pktrx[pt].empty) {
        if (received(rfdev->spiport, &pktrx[pt]) == true)
        {
            if (++pt >= QUEUESIZE)
                pt = 0;
            return true;
        }

    }
    return false;
}


static void pktrx_clean(struct pkt_rx_s *rx) {
    rx->empty = 1;
    rx->size = 0;
    memset(rx->payload, 0, sizeof(rx->payload));
}

void LoRa_clean(int index)
{
    pktrx_clean(&pktrx[index]);
}


bool Lora_peek_and_compare(char *ptr,int len,int *index)
{
    if(ptr == NULL)return false;
    int i;
    for(i =0; i < QUEUESIZE; i++)
    {
        if (!pktrx[i].empty && memcmp(pktrx[i].payload,ptr,len) == 0)
        {
            *index = i;
            return true;
        }
    }
    return false;
}

int LoRa_get_index(uint8_t *ptr,int *size,int index,lora_pkt_info_t *pkt_info)
{
    if(rfdev == NULL)return -1;
    int i = index;
    if (!pktrx[i].empty)
    {

        if(pktrx[i].size <= 256)
        {

            *size = pktrx[i].size;
            memcpy(ptr,pktrx[i].payload,pktrx[i].size);
            if(pkt_info)
            {
                pkt_info->valid = true;
                pkt_info->rssi = (int8_t) pktrx[i].rssi;
                pkt_info->snr = (int8_t) pktrx[i].snr;
                pkt_info->time = time(NULL);
                pkt_info->crc = pktrx[i].crc;
            }

        }
        else
        {
            if(pkt_info)
            {
                pkt_info->valid = false;
                pkt_info->rssi = -999;
                pkt_info->snr = -999;
                pkt_info->crc = 0;
            }
        }
        pktrx_clean(&pktrx[i]);
        return 1;
    }
    return 0;
}

int LoRa_get_first(uint8_t *ptr,int *size,lora_pkt_info_t *pkt_info)
{
    if(rfdev == NULL)return -1;
    int i;
    for(i =0; i < QUEUESIZE; i++)
    {
        if(LoRa_get_index(ptr,size,i,pkt_info))return 1;
    }
    return 0;
}


/**
 *
 */
