/* Copyright (c) 2009 Nordic Semiconductor. All Rights Reserved.
 *
 * The information contained herein is property of Nordic Semiconductor ASA.
 * Terms and conditions of usage are described in detail in NORDIC
 * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
 *
 * Licensees are granted free, non-transferable use of the information. NO
 * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
 * the file.
 *
 */

/** @file
* @brief Example template project.
* @defgroup nrf_templates_example Example Template
*
*/
#include <device.h>
#include <zephyr.h>
#include <sys/printk.h>
#include <drivers/uart.h>
#include <drivers/spi.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "ADXL345_SPI.h"


#include <drivers/gpio.h>

#include <stdbool.h>

#define SPIM_CS_PIN 16 


static const struct spi_config spi_cfg = {
	.operation = SPI_WORD_SET(8) | SPI_TRANSFER_MSB |
		     SPI_MODE_CPOL | SPI_MODE_CPHA,
	.frequency = 400000,
	.slave = 0,
        //.cs = SPIM_CS_PIN
};
struct device *gpio_dev;
struct device * spi_dev;
static void spi_init(void)
{
	const char* const spiName = "SPI_3";
	spi_dev = device_get_binding(spiName);

	if (spi_dev == NULL) {
		printk("Could not get %s device\n", spiName);
		return;
	}
}
#define nrf_drv_spi_t spi_dev

/**@brief Handler for SPI0 master events.
 *
 * @param[in] event SPI master event.
 */
 
 /*
void spi_master_0_event_handler(nrf_drv_spi_event_t event)
{
      uint32_t err_code = NRF_SUCCESS;
   // bool result = false;

    switch (event)
    {
        case NRF_DRV_SPI_EVENT_DONE:
            // Process received data
            //nrf_gpio_pin_set(LED_1);
            spi_busy = 0;
            break;

        default:
            // No implementation needed.
            break;
    }
    APP_ERROR_CHECK(err_code);
}
*/
/**@brief Function for initializing a SPI master driver.
 *
 * @param[in] p_instance    Pointer to SPI master driver instance.
 * @param[in] lsb           Bits order LSB if true, MSB if false.
 */

void ADXL345_SPI_init()
{
    //p_spi_master_0 = spi_dev;
    
    // Set the SPI Chip Select pin as output and initial state to high
    gpio_pin_set(gpio_dev, SPIM_CS_PIN, true);
   
    // Set Data Output Rate to 100Hz (0x0A), see Table 6, p.10 in Datasheet
    ADXL345_SPI_setDataRate(0x0A);
    // Set the ADXL375 in measurement mode by setting the Power Control Register to 0x08 
    ADXL345_SPI_setPowerReg(0x08);
    // Set offset values 
    ADXL345_SPI_setOffsets(0x00,0x00,0x00);
}

/**@brief Function for reading to the ADXL375 registers over SPI.
 *
 * @param[in] address   ADXL375 Register adress    
 * @param[in] p_data    Pointer to rx buffer 
 * @param[in] bytes     Number of bytes to be read 
 *
 */

void ADXL345_SPI_readRegister(uint8_t address, uint8_t * p_data, uint8_t bytes)
{
    uint32_t err_code;
        
    uint8_t m_tx_data_spi;
    
        const struct spi_buf tx_buf = {
		.buf = m_tx_data_spi,
		.len = sizeof(m_tx_data_spi)
	};
	const struct spi_buf_set tx = {
		.buffers = &tx_buf,
		.count = 1
	};

	struct spi_buf rx_buf = {
		.buf = p_data,
		.len = sizeof(p_data),
	};
	const struct spi_buf_set rx = {
		.buffers = &rx_buf,
		.count = 1
	};





    if(bytes > 1)
    {
        m_tx_data_spi = (0x80|address)|0x40;
    }
    else
    {
        m_tx_data_spi = 0x80|address;
    }
    struct device *gpio_dev;
    // Pull Chip Select line low
    gpio_pin_set(gpio_dev, SPIM_CS_PIN, false);
    

     err_code = spi_transceive(spi_dev,&spi_cfg, &tx_buf, 
                         &rx_buf);
    
       if (err_code) {
		printk("SPI error: %d\n", err_code);
	} else {
		printk("TX sent: %x\n", &m_tx_data_spi);
		printk("RX recv: %x\n", &p_data);
		
	}	
    
     gpio_pin_set(gpio_dev, SPIM_CS_PIN, true);
}

/**@brief Function for writing to the ADXL375 registers over SPI.
 *
 * @param[in] address   ADXL375 Register adress    
 * @param[in] p_data    Pointer to tx buffer 
 * @param[in] bytes     Number of bytes to be written
 *
 */

void ADXL345_SPI_writeRegister(uint8_t reg_addr, uint8_t * p_data, uint8_t bytes)
{
        
    uint32_t err_code;
    
    uint8_t m_tx_data_spi[bytes+1];

      const struct spi_buf tx_buf = {
		.buf = m_tx_data_spi,
		.len = sizeof(m_tx_data_spi)
	};
	const struct spi_buf_set tx = {
		.buffers = &tx_buf,
		.count = 1
	};

	struct spi_buf data = {
		.buf = p_data,
		.len = sizeof(p_data),
	};
	const struct spi_buf_set rx = {
		.buffers = &data,
		.count = 1
	};






      
    memcpy(m_tx_data_spi+1,p_data,bytes);
    
    if(bytes > 1)
    {
        m_tx_data_spi[0] = (reg_addr|0x40);
    }
    else
    {
        m_tx_data_spi[0] = reg_addr;
    }
    struct device *gpio_dev;
    // Pull Chip Select line low
    gpio_pin_set(gpio_dev, SPIM_CS_PIN, false);
    
    err_code = spi_transceive(spi_dev,&spi_cfg, &tx_buf, 
                        NULL);
    
       if (err_code) {
		printk("SPI error: %d\n", err_code);
	} else {
		
		printk("TX sent: %x\n", &m_tx_data_spi);
		printk("RX recv:null\n");
	}
                
                err_code = spi_transceive(spi_dev,&spi_cfg, &data, 
                        NULL);
    
       if (err_code) {
		printk("SPI error: %d\n", err_code);
	} else {
		
		printk("TX sent: %x\n", &m_tx_data_spi);
		printk("RX recv:null\n");
	}
    
    // Set Chip Select line high 
    gpio_pin_set(gpio_dev, SPIM_CS_PIN, false);
}

/**@brief Function for setting the data rate of the ADXL375 .
 *
 * @param[in] rate      Data rate in hex (refer the ADXL375 datasheet for available rates)   
 *
 */

void ADXL345_SPI_setDataRate(uint8_t rate)
{
   // SEGGER_RTT_printf(0,"Setting Data Rate Register: %x \n", rate);
    
    uint8_t m_rx_data_spi[2];
    
    ADXL345_SPI_writeRegister(0x2C,&rate,1);
    
    // Read the register and check if it was set correctly
    ADXL345_SPI_readRegister(0x2C,m_rx_data_spi, sizeof(m_rx_data_spi));

   
     if(m_rx_data_spi[1] != rate)
    { 
        printk("Failed to set data rate!\n");
    }
    else
    {
        printk("Data rate set sucessful!\n");
    }
}

/**@brief Function for setting the POWER_CTL register of the ADXL375 .
 *
 * @param[in] reg_val       Value to be written the register   
 *
 */

void ADXL345_SPI_setPowerReg(uint8_t reg_val)
{    
    printk("Setting Power Control Register: %x \n", 0x8);
    
    uint8_t m_tx_data_spi =  reg_val;
    uint8_t m_rx_data_spi[2];
    
    ADXL345_SPI_writeRegister(0x2D, &m_tx_data_spi,1);
    
    ADXL345_SPI_readRegister(0x2D, m_rx_data_spi, sizeof(m_rx_data_spi));
    
     if(m_rx_data_spi[1] != reg_val)
    { 
        printk("Failed to set Power Control Register !\n");
    }
    else
    {
        printk("Power Control Register set sucessful!\n");
    }
}

/**@brief Function for reading the data registers of the ADXL375 .
 *
 * @param[in] rx_buffer     Pointer to rx buffer 
 * @param[in] rx_buf_size   Size of rx buffer  
 * @param[in] x_val         Pointer to x value  
 * @param[in] y_val         Pointer to y value    
 * @param[in] z_val         Pointer to z value    
 *
 */

void ADXL345_SPI_readAccelerometerData( uint8_t * rx_buffer, uint8_t rx_buf_size, int16_t *x_val, int16_t *y_val, int16_t *z_val)
{  
    
     ADXL345_SPI_readRegister(0x32,rx_buffer,rx_buf_size);
    
    for(int i = 0; i<7; i++)
    {
        printk("Data[%d]: %x \n",i, rx_buffer[i]);
    }    
    
    *x_val = (rx_buffer[2]<<8) | rx_buffer[1];
    *y_val = (rx_buffer[4]<<8) | rx_buffer[3];
    *z_val = (rx_buffer[6]<<8) | rx_buffer[5];
    
    printk("X:  %d  Y:  %d  Z:  %d  \n",*x_val,*y_val,*z_val );        
}


/**@brief Function for setting the OFSn register of the ADXL375, n = [X,Y,Z] .
 *
 * @param[in] x_offset       X-axis offset
 * @param[in] y_offset       Y-axis offset
 * @param[in] z_offset       Z-axis offset
 *
 */

void ADXL345_SPI_setOffsets(uint8_t x_offset, uint8_t y_offset, uint8_t z_offset )
{ 
    uint8_t m_tx_data_spi[3] = {x_offset, y_offset, z_offset};
    uint8_t m_rx_data_spi[4];
    
    ADXL345_SPI_writeRegister(0x1E,m_tx_data_spi,sizeof(m_tx_data_spi));
    
    ADXL345_SPI_readRegister(0x1E,m_rx_data_spi,sizeof(m_rx_data_spi));
    
 
    if(m_rx_data_spi[1] == x_offset &&
        m_rx_data_spi[2] == y_offset &&
        m_rx_data_spi[3] == z_offset)
    {
        printk("Offsets set sucessfully!  \n");
    }
    else
    {
        printk("Setting offsets failed! X: %u Y: %u Z: %u \n", m_rx_data_spi[1], m_rx_data_spi[2], m_rx_data_spi[3]);
    }
}


void spi_test_send(void)
{
	int err;
	static uint8_t tx_buffer[1];
	static uint8_t rx_buffer[1];

	const struct spi_buf tx_buf = {
		.buf = tx_buffer,
		.len = sizeof(tx_buffer)
	};
	const struct spi_buf_set tx = {
		.buffers = &tx_buf,
		.count = 1
	};

	struct spi_buf rx_buf = {
		.buf = rx_buffer,
		.len = sizeof(rx_buffer),
	};
	const struct spi_buf_set rx = {
		.buffers = &rx_buf,
		.count = 1
	};
       
	err = spi_transceive(spi_dev, &spi_cfg,&tx, &rx);
	if (err) {
		printk("SPI error: %d\n", err);
	} else {
		/* Connect MISO to MOSI for loopback */
		printk("TX sent: %x\n", tx_buffer[0]);
		printk("RX recv: %x\n", rx_buffer[0]);
		tx_buffer[0]++;
	}	
}

/**
 * @brief Function for application main entry.
 */
int main(void)
{  static uint8_t temp[1];
 struct device *gpio_dev; 
     gpio_dev =device_get_binding(DT_LABEL(DT_NODELABEL(gpio0)));
    gpio_pin_configure(gpio_dev, SPIM_CS_PIN, GPIO_OUTPUT_ACTIVE);
    gpio_pin_set(gpio_dev, SPIM_CS_PIN, true);
    // Initialize the SPI instance
    printk("SPIM Example\n");
    spi_init();
     spi_test_send();
   
     printk("SPIM initialized\n");
    // Initialize the ADXL375 SPI Driver 
    ADXL345_SPI_init();
     printk("adxl initialized\n");
    
    // Accelerometer Data Buffer
    uint8_t rx_buffer[7];
    
    // Sensor Values
    int16_t x_value;
    int16_t y_value;
    int16_t z_value;
    
    
    ADXL345_SPI_readAccelerometerData(rx_buffer,sizeof(rx_buffer),&x_value,&y_value,&z_value);
  
    while (true)
    {   
        // Read the data registers of the ADXL375 
        ADXL345_SPI_readAccelerometerData(rx_buffer,sizeof(rx_buffer),&x_value,&y_value,&z_value);
        // Delay for 1s
        k_msleep(1000);
    }
}
/** @} */
