// Linux Raspberry Pi SPI WS2803_simple.c
// By Thomas Olson
// teo20130210.01
// WS2803 18 channel LED driver
// Raspberry Pi
// WS2803 pin4 CKI -> SCLK(GPIO10)
// WS2803 pin5 SDI -> MOSI(GPIO11)


#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>

#include <stdint.h>
#include <getopt.h>

#include <sys/ioctl.h>

#include <linux/types.h>
#include <linux/spi/spidev.h>

static void pabort(const char *s)
{
	perror(s);
	abort();
}

static const char *device = "/dev/spidev0.0";
static uint8_t mode;
static uint8_t bits = 8;
static uint32_t speed = 500000;
static uint16_t delay;

int fd_spi;

#define nLEDs 18
#define nBARs 2		// Number of WS2803 chained together

uint8_t ledBar[nBARs][nLEDs];

struct spi_ioc_transfer tr;


int init_spi(){
int ret = 0;

	fd_spi = open(device, O_RDWR);
	if (fd_spi < 0)
		pabort("can't open device");

	ret = ioctl(fd_spi, SPI_IOC_WR_MODE, &mode);
	if (ret == -1)
		pabort("can't set spi mode");

	ret = ioctl(fd_spi, SPI_IOC_RD_MODE, &mode);
	if (ret == -1)
		pabort("can't get spi mode");

	ret = ioctl(fd_spi, SPI_IOC_WR_BITS_PER_WORD, &bits);
	if (ret == -1)
		pabort("can't set bits per word");

	ret = ioctl(fd_spi, SPI_IOC_RD_BITS_PER_WORD, &bits);
	if (ret == -1)
		pabort("can't get bits per word");

	ret = ioctl(fd_spi, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
	if (ret == -1)
		pabort("can't set max speed hz");

	ret = ioctl(fd_spi, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
	if (ret == -1)
		pabort("can't get max speed hz");


	tr.tx_buf = (unsigned long)ledBar;
	tr.len = nBARs * nLEDs;
	tr.delay_usecs = delay;
	tr.speed_hz = speed;
	tr.bits_per_word = bits;

	return ret;
}

void loadWS2803(){
	if(ioctl(fd_spi, SPI_IOC_MESSAGE(1), &tr) < 1)
		pabort("can't send spi message");
	usleep(600);
}

void clearWS2803(){
int wsOut;

        for(wsOut = 0; wsOut < nLEDs; wsOut++){
		ledBar[0][wsOut] = ledBar[1][wsOut] = 0x00;
		loadWS2803();
	}
}


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

	if(init_spi() == -1)
		pabort("can't initialize ISP");


	for(;;){
		clearWS2803();
		sleep(2);

	// Chaser mode	
	for(iOut = 7; iOut < 256; iOut*=2){
		for(wsOut = 0; wsOut < nLEDs; wsOut++){
			ledBar[0][wsOut] = ledBar[1][wsOut] = (uint8_t)(0xFF & iOut);
			loadWS2803();
			clearWS2803();
		}
	}
	sleep(1);

	//parallel mode
	for(iOut = 7; iOut < 64; iOut*=4){
		for(wsOut = 0; wsOut < nLEDs; wsOut++){
			ledBar[0][wsOut] = ledBar[1][wsOut] = (uint8_t)(0xFF & iOut);
			loadWS2803();
			usleep(1000000);
		}
		usleep(10000);
	}


	}//for(;;)

	close(fd_spi);
}

