/*
 * Copyright (c) 2011 University of Utah. 
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:  
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the
 *   distribution.
 * - Neither the name of the copyright holder nor the names of
 *   its contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * COPYRIGHT HOLDER OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 *
 *
 * @author Thomas Schmid
 */

#ifndef __CC2520XDRIVERLAYER_H__
#define __CC2520XDRIVERLAYER_H__

typedef nx_struct cc2520_header_t
{
	nxle_uint8_t length;
} cc2520_header_t;


typedef struct cc2520_metadata_t
{
	uint8_t lqi;
	union
	{
		uint8_t power;
	  uint8_t ack;
		uint8_t rssi;
	};
} cc2520_metadata_t;

enum cc2520_reg_access_enums {
    CC2520_FREG_MASK      = 0x3F,    // highest address in FREG
    CC2520_SREG_MASK      = 0x7F,    // highest address in SREG
    CC2520_CMD_TXRAM_WRITE	  = 0x80, // FIXME: not sure... might need to change
};

typedef union cc2520_status {
	uint16_t value;
	struct {
	  unsigned  rx_active    :1;
	  unsigned  tx_active    :1;
	  unsigned  dpu_l_active :1;
	  unsigned  dpu_h_active :1;

	  unsigned  exception_b  :1;
	  unsigned  exception_a  :1;
	  unsigned  rssi_valid   :1;
	  unsigned  xosc_stable  :1;
	};
} cc2520_status_t;

typedef union cc2520_frmctrl0 {
    uint8_t value;
    struct {
        unsigned tx_mode          : 2;
        unsigned rx_mode          : 2;
        unsigned energy_scan      : 1;
        unsigned autoack          : 1;
        unsigned autocrc          : 1;
        unsigned append_data_mode : 1;
    } f;
} cc2520_frmctrl0_t;

static cc2520_frmctrl0_t cc2520_frmctrl0_default = {.f.autocrc = 1};

typedef union cc2520_txpower {
    uint8_t value;
    struct {
        unsigned pa_power: 8;
    } f;
} cc2520_txpower_t;

// Set 0dBm output power
static cc2520_txpower_t cc2520_txpower_default = { .f.pa_power = 0x32 };

typedef union cc2520_ccactrl0 {
    uint8_t value;
    struct {
        unsigned cca_thr: 8;
    } f;
} cc2520_ccactrl0_t;

// Raises CCA threshold from -108dBm to -8 - 76 = -84dBm
//static cc2520_ccactrl0_t cc2520_ccactrl0_default = { .f.cca_thr = 0xF8 };
// FIXME: This might be a problem in the EK devkit. But the threshold has to
// be really high!
// Raises CCA threshold from -108dBm to 10 - 76dBm
static cc2520_ccactrl0_t cc2520_ccactrl0_default = { .f.cca_thr = 0x1A };

typedef union cc2520_mdmctrl0 {
    uint8_t value;
    struct {
        unsigned tx_filter       : 1;
        unsigned preamble_length : 4;
        unsigned demod_avg_mode  : 1;
        unsigned dem_num_zeros   : 2;
    } f;
} cc2520_mdmctrl0_t;

// Makes sync word detection less likely by requiring two zero symbols before
// the sync word
static cc2520_mdmctrl0_t cc2520_mdmctrl0_default = {.f.tx_filter = 1, .f.preamble_length = 2, .f.demod_avg_mode = 0, .f.dem_num_zeros = 2};

typedef union cc2520_mdmctrl1 {
    uint8_t value;
    struct {
        unsigned corr_thr     : 5;
        unsigned corr_thr_sfd : 1;
        unsigned reserved0    : 2;
    } f;
} cc2520_mdmctrl1_t;

// Only one SFD symbol must be above threshold, and raise correlation
// threshold
static cc2520_mdmctrl1_t cc2520_mdmctrl1_default = {.f.corr_thr = 0x14, .f.corr_thr_sfd = 0};

typedef union cc2520_freqctrl {
    uint8_t value;
    struct {
        unsigned freq       : 7;
        unsigned reserved0  : 1;
    } f;
} cc2520_freqctrl_t;

static cc2520_freqctrl_t cc2520_freqctrl_default = {.f.freq = 0x0B };

typedef union cc2520_fifopctrl {
    uint8_t value;
    struct {
        unsigned fifop_thr : 7;
        unsigned reserved0 : 1;
    } f;
} cc2520_fifopctrl_t;

typedef union cc2520_frmfilt0 {
    uint8_t value;
    struct {
        unsigned frame_filter_en         : 1;
        unsigned pan_coordinator         : 1;
        unsigned max_frame_version       : 2;
        unsigned fcf_reserved_mask       : 3;
        unsigned reserved                : 1;
    } f;
} cc2520_frmfilt0_t;

static cc2520_frmfilt0_t cc2520_frmfilt0_default = {.f.max_frame_version = 2, .f.frame_filter_en = 1};

typedef union cc2520_frmfilt1 {
    uint8_t value;
    struct {
        unsigned reserved0               : 1;
        unsigned modify_ft_filter        : 2;
        unsigned accept_ft_0_beacon      : 1;
        unsigned accept_ft_1_data        : 1;
        unsigned accept_ft_2_ack         : 1;
        unsigned accept_ft_3_mac_cmd     : 1;
        unsigned accept_ft_4to7_reserved : 1;
    } f;
} cc2520_frmfilt1_t;

static cc2520_frmfilt1_t cc2520_frmfilt1_default = {.f.accept_ft_0_beacon = 1, .f.accept_ft_1_data = 1, .f.accept_ft_2_ack = 1, .f.accept_ft_3_mac_cmd = 1};

typedef union cc2520_srcmatch {
    uint8_t value;
    struct {
        unsigned src_match_en      : 1;
        unsigned autopend          : 1;
        unsigned pend_datareq_only : 1;
        unsigned reserved          : 5;
    } f;
} cc2520_srcmatch_t;

static cc2520_srcmatch_t cc2520_srcmatch_default = {.f.src_match_en = 1, .f.autopend = 1, .f.pend_datareq_only = 1};

typedef union cc2520_rxctrl {
    uint8_t value;
} cc2520_rxctrl_t;

static cc2520_rxctrl_t cc2520_rxctrl_default = {.value = 0x3F};

typedef union cc2520_fsctrl {
    uint8_t value;
} cc2520_fsctrl_t;

static cc2520_fsctrl_t cc2520_fsctrl_default = {.value = 0x5A};

typedef union cc2520_fscal1 {
    uint8_t value;
} cc2520_fscal1_t;

static cc2520_fscal1_t cc2520_fscal1_default = {.value = 0x2B};

typedef union cc2520_agcctrl1 {
    uint8_t value;
} cc2520_agcctrl1_t;

static cc2520_agcctrl1_t cc2520_agcctrl1_default = {.value = 0x11};

typedef union cc2520_adctest0 {
    uint8_t value;
} cc2520_adctest0_t;

static cc2520_adctest0_t cc2520_adctest0_default = {.value = 0x10};

typedef union cc2520_adctest1 {
    uint8_t value;
} cc2520_adctest1_t;

static cc2520_adctest1_t cc2520_adctest1_default = {.value = 0x0E};

typedef union cc2520_adctest2 {
    uint8_t value;
} cc2520_adctest2_t;

static cc2520_adctest2_t cc2520_adctest2_default = {.value = 0x03};

#ifndef CC2520_DEF_CHANNEL
#define CC2520_DEF_CHANNEL 25
#endif

#ifndef CC2520_DEF_RFPOWER
#define CC2520_DEF_RFPOWER 0x32 // 0 dBm
#endif

enum {
    CC2520_TX_PWR_MASK  = 0xFF,
    CC2520_TX_PWR_0     = 0x03, // -18 dBm
    CC2520_TX_PWR_1     = 0x2C, //  -7 dBm
    CC2520_TX_PWR_2     = 0x88, //  -4 dBm
    CC2520_TX_PWR_3     = 0x81, //  -2 dBm
    CC2520_TX_PWR_4     = 0x32, //   0 dBm
    CC2520_TX_PWR_5     = 0x13, //   1 dBm
    CC2520_TX_PWR_6     = 0xAB, //   2 dBm
    CC2520_TX_PWR_7     = 0xF2, //   3 dBm
    CC2520_TX_PWR_8     = 0xF7, //   5 dBm
    CC2520_CHANNEL_MASK = 0x1F,
};

enum cc2520_register_enums
{
    // FREG Registers
    CC2520_FRMFILT0     = 0x00,
    CC2520_FRMFILT1     = 0x01,
    CC2520_SRCMATCH     = 0x02,
    CC2520_SRCSHORTEN0  = 0x04,
    CC2520_SRCSHORTEN1  = 0x05,
    CC2520_SRCSHORTEN2  = 0x06,
    CC2520_SRCEXTEN0    = 0x08,
    CC2520_SRCEXTEN1    = 0x09,
    CC2520_SRCEXTEN2    = 0x0A,
    CC2520_FRMCTRL0     = 0x0C,
    CC2520_FRMCTRL1     = 0x0D,
    CC2520_RXENABLE0    = 0x0E,
    CC2520_RXENABLE1    = 0x0F,
    CC2520_EXCFLAG0     = 0x10,
    CC2520_EXCFLAG1     = 0x11,
    CC2520_EXCFLAG2     = 0x12,
    CC2520_EXCMASKA0    = 0x14,
    CC2520_EXCMASKA1    = 0x15,
    CC2520_EXCMASKA2    = 0x16,
    CC2520_EXCMASKB0    = 0x18,
    CC2520_EXCMASKB1    = 0x19,
    CC2520_EXCMASKB2    = 0x1A,
    CC2520_EXCBINDX0    = 0x1C,
    CC2520_EXCBINDX1    = 0x1D,
    CC2520_EXCBINDY0    = 0x1E,
    CC2520_EXCBINDY1    = 0x1F,
    CC2520_GPIOCTRL0    = 0x20,
    CC2520_GPIOCTRL1    = 0x21,
    CC2520_GPIOCTRL2    = 0x22,
    CC2520_GPIOCTRL3    = 0x23,
    CC2520_GPIOCTRL4    = 0x24,
    CC2520_GPIOCTRL5    = 0x25,
    CC2520_GPIOPOLARITY = 0x26,
    CC2520_GPIOCTRL     = 0x28,
    CC2520_DPUCON       = 0x2A,
    CC2520_DPUSTAT      = 0x2C,
    CC2520_FREQCTRL     = 0x2E,
    CC2520_FREQTUNE     = 0x2F,
    CC2520_TXPOWER      = 0x30,
    CC2520_TXCTRL       = 0x31,
    CC2520_FSMSTAT0     = 0x32,
    CC2520_FSMSTAT1     = 0x33,
    CC2520_FIFOPCTRL    = 0x34,
    CC2520_FSMCTRL      = 0x35,
    CC2520_CCACTRL0     = 0x36,
    CC2520_CCACTRL1     = 0x37,
    CC2520_RSSI         = 0x38,
    CC2520_RSSISTAT     = 0x39,
    CC2520_RXFIRST      = 0x3C,
    CC2520_RXFIFOCNT    = 0x3E,
    CC2520_TXFIFOCNT    = 0x3F,

    // SREG registers
    CC2520_CHIPID       = 0x40,
    CC2520_VERSION      = 0x42,
    CC2520_EXTCLOCK     = 0x44,
    CC2520_MDMCTRL0     = 0x46,
    CC2520_MDMCTRL1     = 0x47,
    CC2520_FREQEST      = 0x48,
    CC2520_RXCTRL       = 0x4A,
    CC2520_FSCTRL       = 0x4C,
    CC2520_FSCAL0       = 0x4E,
    CC2520_FSCAL1       = 0x4F,
    CC2520_FSCAL2       = 0x50,
    CC2520_FSCAL3       = 0x51,
    CC2520_AGCCTRL0     = 0x52,
    CC2520_AGCCTRL1     = 0x53,
    CC2520_AGCCTRL2     = 0x54,
    CC2520_AGCCTRL3     = 0x55,
    CC2520_ADCTEST0     = 0x56,
    CC2520_ADCTEST1     = 0x57,
    CC2520_ADCTEST2     = 0x58,
    CC2520_MDMTEST0     = 0x5A,
    CC2520_MDMTEST1     = 0x5B,
    CC2520_DACTEST0     = 0x5C,
    CC2520_DACTEST1     = 0x5D,
    CC2520_ATEST        = 0x5E,
    CC2520_DACTEST2     = 0x5F,
    CC2520_PTEST0       = 0x60,
    CC2520_PTEST1       = 0x61,
    CC2520_RESERVED     = 0x62,
    CC2520_DPUBIST      = 0x7A,
    CC2520_ACTBIST      = 0x7C,
    CC2520_RAMBIST      = 0x7E,
};

enum cc2520_spi_command_enums
{
    CC2520_CMD_SNOP           = 0x00, //
    CC2520_CMD_IBUFLD         = 0x02, //
    CC2520_CMD_SIBUFEX        = 0x03, //
    CC2520_CMD_SSAMPLECCA     = 0x04, //
    CC2520_CMD_SRES           = 0x0f, //
    CC2520_CMD_MEMORY_MASK    = 0x0f, //
    CC2520_CMD_MEMORY_READ    = 0x10, // MEMRD
    CC2520_CMD_MEMORY_WRITE   = 0x20, // MEMWR
    CC2520_CMD_RXBUF          = 0x30, //
    CC2520_CMD_RXBUFCP        = 0x38, //
    CC2520_CMD_RXBUFMOV       = 0x32, //
    CC2520_CMD_TXBUF          = 0x3A, //
    CC2520_CMD_TXBUFCP        = 0x3E, //
    CC2520_CMD_RANDOM         = 0x3C, //
    CC2520_CMD_SXOSCON        = 0x40, //
    CC2520_CMD_STXCAL         = 0x41, //
    CC2520_CMD_SRXON          = 0x42, //
    CC2520_CMD_STXON          = 0x43, //
    CC2520_CMD_STXONCCA       = 0x44, //
    CC2520_CMD_SRFOFF         = 0x45, //
    CC2520_CMD_SXOSCOFF        = 0x46, //
    CC2520_CMD_SFLUSHRX       = 0x47, //
    CC2520_CMD_SFLUSHTX       = 0x48, //
    CC2520_CMD_SACK           = 0x49, //
    CC2520_CMD_SACKPEND       = 0x4A, //
    CC2520_CMD_SNACK          = 0x4B, //
    CC2520_CMD_SRXMASKBITSET  = 0x4C, //
    CC2520_CMD_SRXMASKBITCLR  = 0x4D, //
    CC2520_CMD_RXMASKAND      = 0x4E, //
    CC2520_CMD_RXMASKOR       = 0x4F, //
    CC2520_CMD_MEMCP          = 0x50, //
    CC2520_CMD_MEMCPR         = 0x52, //
    CC2520_CMD_MEMXCP         = 0x54, //
    CC2520_CMD_MEMXWR         = 0x56, //
    CC2520_CMD_BCLR           = 0x58, //
    CC2520_CMD_BSET           = 0x59, //
    CC2520_CMD_CTR_UCTR       = 0x60, //
    CC2520_CMD_CBCMAC         = 0x64, //
    CC2520_CMD_UCBCMAC        = 0x66, //
    CC2520_CMD_CCM            = 0x68, //
    CC2520_CMD_UCCM           = 0x6A, //
    CC2520_CMD_ECB            = 0x70, //
    CC2520_CMD_ECBO           = 0x72, //
    CC2520_CMD_ECBX           = 0x74, //
    CC2520_CMD_INC            = 0x78, //
    CC2520_CMD_ABORT          = 0x7F, //
    CC2520_CMD_REGISTER_READ  = 0x80, //
    CC2520_CMD_REGISTER_WRITE = 0xC0, //
};

#endif // __CC2520XDRIVERLAYER_H__
