#include <linux/spi/spidev.h>
#include <sys/ioctl.h>
#include <stdint.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

#define SPEED 2000000

int fd;
int ret;

int open_spi() {
	uint8_t mode=0;
	uint32_t speed = SPEED;


	// open spibus device
	fd = open("/dev/spidev0.0", O_RDWR);
	if(fd < 0) {
		return 1;
	}

	//set spi mode
	if(ioctl(fd, SPI_IOC_WR_MODE, &mode) == -1) {
		return 2;
	}

	// SPI clock speed (Hz)
	if(ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) == -1) {
		return 3;
	}

	return 0;
}

void print_cmd(uint16_t cmd) {
	printf("[ ");
	printf("%02x ", (cmd & 0xff00)>>8);
	printf("%02x ", cmd & 0x00ff);
	printf("]\n");
}

uint16_t send_command16(uint16_t cmd) {
	uint8_t tx[2];
	uint8_t *buf = (uint8_t *)&cmd;
	tx[0] = buf[1];
	tx[1] = buf[0];
	uint16_t res;

	uint8_t rx[2] = {0, 0};

	printf("cmd: ");
	print_cmd(cmd);

	struct spi_ioc_transfer tr = {
		.tx_buf = (unsigned long)tx,
		.rx_buf = (unsigned long)rx,
		.len = 2,
		.delay_usecs = 0,
		.speed_hz = SPEED,
		.bits_per_word = 8,
	};
	ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
	if(ret < 0) {
		printf("could not send SPI command\n");
		return 0;
	}

	res = (((uint16_t)rx[0]) << 8) + rx[1];

	printf("res: ");
	print_cmd(res);

	return res;
}

uint8_t read_fifo() {
	uint8_t tx[3] = {0,0,0};
	uint8_t rx[3] = {0,0,0};

	struct spi_ioc_transfer tr = {
		.tx_buf = (unsigned long)tx,
		.rx_buf = (unsigned long)rx,
		.len = 3,
		.delay_usecs = 0,
		.speed_hz = 1000000,
		.bits_per_word = 8,
	};
	ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
	if(ret < 0) {
		printf("could not send SPI command\n");
		return 0;
	}

	return rx[2];
}

void request_status() {
	uint16_t rx;
	rx = send_command16(0x0000);

	printf("OFFS6:   %d\n", rx & 0x003f);
	rx = rx >>6;
	printf("ASAME:   %d\n", rx & 0x0001);
	rx = rx >> 1;
	printf("ATGL:    %d\n", rx & 0x0001);
	rx = rx >> 1;
	printf("CRL:     %d\n", rx & 0x0001);
	rx = rx >> 1;
	printf("DQD:     %d\n", rx & 0x0001);
	rx = rx >> 1;
	printf("DRSSI:   %d\n", rx & 0x0001);
	rx = rx >> 1;
	printf("FFEM:    %d\n", rx & 0x0001);
	rx = rx >> 1;
	printf("LBD:     %d\n", rx & 0x0001);
	rx = rx >> 1;
	printf("WK-UP:   %d\n", rx & 0x0001);
	rx = rx >> 1;
	printf("FFOV:    %d\n", rx & 0x0001);
	rx = rx >> 1;
	printf("FIFO IT: %d\n", rx & 0x0001);
}

int main(int argc, char *argv[]) {

	uint8_t mode;
	int i;

	ret = open_spi();
	if(ret > 0) {
		printf("Cannot open device\n");
		return 1;
	}

	//read spi mode
	ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
	if(ret < 0) {
		printf("cannot read mode\n");
	} else {
		printf("mode is %d\n", mode);
	}


	// original frequency with fifo buffer
	send_command16(0x0000); //cleanup
	send_command16(0x887a); //433 Mhz band, 200 khz bandwith
	send_command16(0xa620); //for 433.92 Mhz exactly
	send_command16(0xc8aa); //set data rate
	send_command16(0xc460); //data filter
	send_command16(0xc627); //AFC setting
	send_command16(0xce81); // with fifo 1 byte buffer
	send_command16(0xc005); //enable receiver -91 dba RSSI + ENABLE


	usleep(10000);

	for(i=0;i<10000;i++) {
		//request_status();
		printf("fifo: %02x\n", read_fifo());
		usleep(200000);
	}

	close(fd);
}
