/******************************************************************************
g++ -o pbm2 pbm2.cpp -Wall -Werror -ansi -pedantic -lgpiod -lpthread -std=c++20

sudo killall pbm2
sudo /home/pi/pbm2 
sudo nice -n -20 sudo /home/pi/pbm2 
taskset 0x08 sudo nice -n -20 sudo /home/pi/pbm2    (to assign to last of 4 processor cores) (recommended run method)
* 
 *** reserve core 3 for application
sudo nano /boot/cmdline.txt
isolcpus=3   (isolates 4th core)  kernel parameter must be in boot loader (boot/cmdline.txt) or GRUB configuration
before change
console=serial0,115200 console=tty1 root=PARTUUID=a664261b-02 rootfstype=ext4 fsck.repair=yes rootwait quiet splash plymouth.ignore-serial-consoles
after change
console=serial0,115200 console=tty1 root=PARTUUID=4f3bf2b0-02 rootfstype=ext4 fsck.repair=yes rootwait quiet splash plymouth.ignore-serial-consoles isolcpus=3 
*
*  
sudo apt-get install gpiod libgpiod-dev         [FOR GPIOD TO REPLACE WIRINGPI]    
sudo apt-get install libboost-dev -y            [ADD BOOST Library]
sudo apt-get install libcurl4-openssl-dev -y    [ADD CURL LIBRARY for C++]

* This program uses the Raspberry Pi SPI interace in Master mode to communicate with an Accelerometer
 
P2.1 from mcu goes to pin 31, GPIO 6
touch sensor goes to GPIO 5 (pin29)

******************************************************************************/

#include <sys/ioctl.h>
#include <linux/spi/spidev.h>	//for spidev library
#include <gpiod.h>				//for libgpiod library
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <curl/curl.h>
#include <boost/lexical_cast.hpp>  // for converting string to double 
#include <ctime>         //time of day information
#include <chrono>
#include <thread>    	//for sleep_for
#include <cmath>		//math library for power function ^
#include <vector>		//for trilateration calculation

#include <sys/types.h>  //for checking if program already running
#include <dirent.h>		//for checking if program already running
#include <errno.h>		//for checking if program already running
#include <stdint.h>		// for using uint32_t

using namespace std;  // includes declarations of std (iostream?) removes prefix need std::

#include <sstream>
#include <string>
#include <iostream>
#include <fstream>       // for writing to file

#include <thread>		//for using threads


// ****** for libgpiod and spidev
const char *chipname = "gpiochip0";
struct gpiod_chip *chip;
struct gpiod_line *iMCU;    	//gpio 6, for MSP mcu
struct gpiod_line *itouch;    	//gpio 5, for touch sensor
struct gpiod_line *csA;    		//gpio 13, for CS for accelerometer

static const char *device = "/dev/spidev0.0";	//"/dev/spidev0.0"
uint8_t smode=SPI_MODE_0;
uint8_t bitsPerWord=8;
uint32_t speed = 1000000;	//3MHz SPI speed: valid rates are 0.5,1,2,4,8,16 MHz (other values seem OK too, like 2.5 MHz)
//uint32_t speed = 500000;	//3MHz SPI speed: valid rates are 0.5,1,2,4,8,16 MHz (other values seem OK too, like 2.5 MHz)

#define spiReadBit	0x80
#define spiReadBurstbits	0xC0								
int spifd = -1;

//

// *********************** global variables  *********************
uint8_t		z, j;			//loop
uint16_t	k, x, y;		//larger loops
uint16_t	i;			//index

ostringstream  stmp, stmp2;			//temporary string
string tmpstr, tmpstr2;				//temporary string, date-time string

uint16_t loopTime=0, ltMin=9999, ltMax=0;	//looptime: min,max + bins loop time (ms) of IPS program
uint16_t tLoop, tLoopmin=999, tLoopmax=0;  //total loop time recordings
int32_t	dlLoop;				//calculated delay loop time in ms

// if 1344hz sample rate, the 30 sec would have 40,320 samples
int16_t aX[65534], aY[65534], aZ[65534];   //signed 12 bit data stored in 16 bit signed

clock_t t[65000];    		//used for getting clock cycles
clock_t rts[9], rtf[9];		// clock pulse for timing response
uint32_t rtd[9];			//responce time difference

uint8_t tp[65000];			//touch plate value 0 or 1
int cnt=0;					//count of taps
uint8_t cntScale=0;
uint8_t tcount=0;
uint8_t lockout=0;
uint8_t flgScale[65000];  	//scale of accelerometer
uint32_t lht[255];			//low to high transistion timing, index is tap count
uint32_t hlt[255];			//high to low transistion timing, index is tap count
uint32_t lpt[255];			//low pulse time interval
uint32_t hpt[255];			//low pulse time interval
uint32_t tpt[255];			//low pulse time interval
uint32_t lpts=0, lpta=0, hpts=0, hpta=0, tpts=0, tpta=0; //sum and average for pulse times



// ********************************************************************
// ***************************** SUBROUTINES **************************
// ********************************************************************
int GPIOinit();
int GPIOclose();
void delayMicroseconds (int delay_us);
int spiOpen();
int spiClose();
int spiWriteRead(unsigned char *data, int length); 
#define numSamples	21000	//number of samples 21000 for 15 seconds

// Get current date/time, format is YYYY-MM-DD.HH:mm:ss
const std::string currentDateTime() {
    time_t     now = time(0);
    struct tm  tstruct;
    char       buf[80];
    tstruct = *localtime(&now);
    // Visit http://en.cppreference.com/w/cpp/chrono/c/strftime
    // for more information about date/time format
    strftime(buf, sizeof(buf), "%Y-%m-%d_%H-%M-%S", &tstruct);

    return buf;
}




// *******************************************************************
// ***********************  main *************************************
// *******************************************************************

int main (int argc, char *argv[])
{
	uint8_t aR[8];			//acellerometer registers for spi
	uint16_t size;			//size of spi transfer

	//put CPU in performance mode so the SPI clock is stable and consistant
	system("sudo sh -c 'echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor'");
	
	GPIOinit();					//initilize the GPIO for the Raspberry Pi	
	spiOpen();					//open spi interface
	std::this_thread::sleep_for(std::chrono::milliseconds(1000)); //wait 
	
	// provide a seed value for random number generation based on time
	srand((unsigned) time(NULL)); 

	size=6; aR[4]=0x08; 
	spiWriteRead (aR, size);	//fill display
	
	//1st test is a pure reaction time test
	// when the finger is resting on the plate are ready to start
	// random time intervals are used from 1 to 3 seconds, done 3 times
	cout << "Random responce time test: waiting for finger to be on plate" << endl;
	cout << "The objective is to raise our finger (as fast as you can) each time the 8 appears" << endl;
	while (gpiod_line_get_value(itouch)==1) {		
		delayMicroseconds(32000);  //32ms delay
	}
	//finger is now on the plate
	size=6; aR[4]=11; 
	spiWriteRead (aR, size);	//blanks the display
	//now generate random time interval
	stmp2 << currentDateTime() << ";Trial#;usec;;;;;;" << endl;
	for (i=5; i>0; --i) {
		int random = 1000 + (rand() %2000);   //random # 1000 to 3000 ms
		cout << "R#=" << random << endl;
		this_thread::sleep_for(chrono::milliseconds(random));
		//finger must stay down and not be raised before the digit is displayed
		//if raised ahead of time, the respond will indicate about 11us, so it will be known as invalid
		size=6; aR[4]=0x08; 
		spiWriteRead (aR, size);	//fill display
		rts[i] = clock();   			//save the clock cycles
		//wait fill finger is raised
		while (gpiod_line_get_value(itouch)==0) {}
		rtf[i] = clock();  			//save the clock cycles
		delayMicroseconds(5000);  //5ms delay to test if valid (debounce)
		if (gpiod_line_get_value(itouch)==0) {
			//problem as finger is still down, best to try again
			while (gpiod_line_get_value(itouch)==0) {}
			rtf[i] = clock();  			//save the clock cycles
			delayMicroseconds(5000);  //5ms delay to test if valid (debounce)
			if (gpiod_line_get_value(itouch)==0) {
				//invalid, stamp time as zero
				cout << "Invalid measurement finger not making proper contact with plate" << endl;
				rtf[i] = rts[i];
			}
		}
		rtd[i] = rtf[i]-rts[i];     //compute the difference
		cout << "Responce time=" << dec << rtd[i] << endl;
		stmp2 << ";" << dec << i << ";" << dec << rtd[i] << ";;;;;;" << endl;
		if (i!=1) {
			//wait fill finger is lowered
			while (gpiod_line_get_value(itouch)==1) {}
			size=6; aR[4]=11; 
			spiWriteRead (aR, size);	//blanks the display
		} else {
			size=6; aR[4]=11; 
			spiWriteRead (aR, size);	//blanks the display
		}
	}
	stmp2 << ";;;;;;;;" << endl;   //blank spacer line
	
	cout << "Done : raise the finger" << endl;
	sleep(4);
	while (gpiod_line_get_value(itouch)==0) {}


	//wait for 1st touch
	cout << "Rapid Finger Tapping Test: waiting for 1st touch" << endl;
	cout << "Objective: Tap your finger as fast as you can for 15 seconds (until told to stop)" << endl;
	size=6;  //one write and six reads (total)
	aR[0]=0x01;	aR[1]=0x00;	//default
	//aR[4] is the one the controlls the LED
	while (gpiod_line_get_value(itouch)==1) {
			// in the mean time check the iMCU line to see if high (wait to send data)
			// if it is high just get the information and ignor information
			if (gpiod_line_get_value(iMCU)==1) {
				aR[4]=0x11;	//blank LED
				spiWriteRead (aR, size);	//read xyz axis
			}
	}
	cout << "starting" << endl;

	// *************************************************************************
	// **************************** WHILE LOOP *********************************
	// *************************************************************************
	for (i=numSamples; i>0; --i) {

		//wait for MCU interrupt line to go high (iMCU)
		while (gpiod_line_get_value(iMCU)==0) {}
		
		t[i] = clock();   					//save the clock cycles
		tp[i] = gpiod_line_get_value(itouch);	//save the touch plate value

		// code to change the display with touches
		if (lockout) {
			lockout--;
		}
		else {
			if ((tp[i]==0) & (tp[i+1]==1)) {  //detect finger touch
				//change detected, increment count but also provide lockout time period before next allowed increment
				tcount++;
				if (tcount>=10) tcount=0;   // auto wrap counter
				lockout=130;  //100ms
			}
		}
		aR[4] = tcount;

		//read the xyz axis 
		// for 2MHz SPI, clk takes 32us, but CS is busy for 100 to 150us (to read all axis)
		//   1344Hz sample rate would be every 744us  (49 seconds for a count of 65500)  (30.1339s for 40,500)
		size=6;  //one write and six reads (total)
		//gpiod_line_set_value(csA,0);  //enable CS
		//aR[4]=0x04;	//set the LED value
		spiWriteRead (aR, size);	//read xyz axis
		//gpiod_line_set_value(csA,1);  //disable CS
		 //12 bit resolution, 2s complement left justified from accelerometer
		 //  computer 16 bit signed integer is also 2s complement, but need to ensure all 16 bits are 1's instead of just 12 (for negative numbers)
		 aX[i]=(aR[1]<<8) | (aR[0]);   			//12 bits
		 aX[i]=aX[i]/16;						// bottom 4 bits zeros (becuase left justified) so /16 to remove
		 aY[i]=(aR[3]<<8) | (aR[2]);   			//12 bits
		 aY[i]=aY[i]/16;
		 aZ[i]=(aR[5]<<8) | (aR[4]);   			//12 bits
		 aZ[i]=aZ[i]/16;
		//cout << "Z:" << hex << int(aR[6]) << ":" << int(aR[5]) << "  " << dec << aZ[i] << endl; 
		//cout << dec << "X:" << int(aX[i]) << " Y:" << int(aY[i]) << " Z:" << int(aZ[i]) << endl;
	}//loop
	

	//compute number of taps
	//  debounce looks at 14*744us=10.4ms.  Seems safe as no one should be able to tap that fast normally
	//  tp[] is the tap pulse array holding 0 (down) or 1 (up) indicating finger position
	//*find the 1st high (finger lifted)
	x=numSamples;	  //start at beginning	
	while (tp[x]==0) {x--;}   //advance to 1st high
	//*find last low to high transistion
	y=1;			//start at end
	while (!((tp[y]==1) & (tp[y+1]==0))) {y++;}  //goes backward to find transistion
	//*tag and count all the low-high transistions (lht) and high to low (hlt) transisions
	for (i=x+2; i>=y; --i) {
		//find low to high transistion: note forward in time is negative numbers
		if ((tp[i]==0) & (tp[i-1]==1)&(tp[i-2]==1)&(tp[i-3]==1)&(tp[i-4]==1)&(tp[i-5]==1)&(tp[i-6]==1)&(tp[i-7]==1)&(tp[i-8]==1)&(tp[i-9]==1)&(tp[i-10]==1)&(tp[i-11]==1)&(tp[i-12]==1)&(tp[i-13]==1)&(tp[i-14]==1)) {  //includes debouncing
			cnt++;				// increment count(also index to array) if finger touch leaves panel
			lht[cnt]=t[i-1];		//save the usec timing value
		}
		//find the follow up high to low transision
		//   found case of only 11 zeros for a low time period (also a case of only 3 low time periods!!) (also seen 000001011111)
		//      so test for 3 high, then 3 low
		if ((tp[i]==1) & (tp[i-1]==0)&(tp[i-2]==0)&(tp[i-3]==0)) {  //includes debouncing
			hlt[cnt]=t[i-1];		//save the usec timing value
		}
	}
	lht[cnt+1]=t[y];   //manually fill in the last rising edge
	
	//perform validation of test to ensure finger was being raised enough, and not vibrating on plate
	for (i=1; i<=(cnt-1); ++i) {
		if (lht[i]==0) {
			cout << "TEST FAILED lht=0: Redo the test, ensure finger is raised about 1cm for tapping" << endl;
			exit(1);
		}
		if (hlt[i]==0) {
			cout << "TEST FAILED hlt=0: Redo the test, ensure finger is raised about 1cm for tapping" << endl;
			exit(1);
		}
		
	}	
	
	//cout << "Total taps=" << dec << int(cnt) << "  Total time=" << dec << (int(t[1]) - ((float)t[numSamples]))/CLOCKS_PER_SEC << endl;	//not accurate
	//next compute the delta time of each pulse
	stmp << "lht; hlt; Total Pulse; High; Low" << endl;
	for (i=1; i<=(cnt-1); ++i) {
		hpt[i]=hlt[i]-lht[i];		//high pulse time
		lpt[i]=lht[i+1]-hlt[i];		//low pulse time (would be hl then lh delta)
		
		tpt[i]=lpt[i]+hpt[i];		//total pulse time
		stmp << dec << lht[i]<< ";"  <<  hlt[i]<< ";"  << tpt[i]<< ";"  <<  hpt[i]<< ";"  <<  lpt[i] << endl;
		lpts=lpts+lpt[i];			//low pulse time sum
		hpts=hpts+hpt[i];			//high pulse time sum
		tpts=tpts+tpt[i];			//total pulse time sum
	}
	//cout  << "cnt=" << cnt-1 << "  lht[cnt+1]=" << lht[cnt+1] << endl;	
	

	
	//compute the averages from the sums
	lpta=lpts/(cnt-1);		//low pulse time average
	hpta=hpts/(cnt-1);		//high pulse time average
	tpta=tpts/(cnt-1);		//total pulse time average
	stmp << "Total taps:V; Total time:V; vs Pulse Period Sum:V" << endl;
	stmp <<  dec << cnt-1<< ";"  << int(lht[cnt+1]-lht[1])<< ";"  << int(tpts) << endl << endl;
	
	stmp << "lpts:V;  hpts:V; Summed:V" << endl;
	stmp << int(lpts)<< ";" << int(hpts)<< ";" << int(lpts+hpts) << endl << endl;
	
	stmp << "Average Total Pulse time:V; AvLow:V; AvHigh:V" << endl;
	stmp <<  dec << int(tpta) << ";"  << int(lpta) << ";"  << int(hpta) << endl << endl;
	
	//compute standard deviation Total Pulse time
	double mean = (double)tpta;
    double sum2 = 0.0;
    for(int i=1;i<=(cnt-1);i++)  sum2 = sum2 + (tpt[i]-mean)*(tpt[i]-mean);
    double variance = (double)sum2/(cnt-1);			// give variance
    double standardDeviation = sqrt(variance);		//sqrt for standard deviation
    //stmp<<"TOTAL PULSE: Mean: " << mean <<" Variance: " << variance << " SD: " << standardDeviation << endl;
    stmp2<<";Mean(ms);SD(ms);;;;;;"<<endl;
    stmp2<<"TOTAL PULSE(ms):;" << mean/1000 << ";" << standardDeviation/1000 << ";;;;;" << endl;
    
    //compute standard deviation HIGH Pulse time
	mean = (double)hpta;
    sum2 = 0.0;
    for(int i=1;i<=(cnt-1);i++)  sum2 = sum2 + (hpt[i]-mean)*(hpt[i]-mean);
    variance = (double)sum2/(cnt-1);			// give variance
    standardDeviation = sqrt(variance);		//sqrt for standard deviation
    //stmp<<"HIGH PULSE: Mean: " << mean <<" Variance: " << variance << " SD: " << standardDeviation << endl;
    stmp2<<"HIGH PULSE(ms):;" << mean/1000 << ";" << standardDeviation/1000 << ";;;;;" << endl;
    
    //compute standard deviation LOW Pulse time
	mean = (double)lpta;
    sum2 = 0.0;
    for(int i=1;i<=(cnt-1);i++)  sum2 = sum2 + (lpt[i]-mean)*(lpt[i]-mean);
    variance = (double)sum2/(cnt-1);			// give variance
    standardDeviation = sqrt(variance);		//sqrt for standard deviation
    //stmp<<"LOW PULSE: Mean: " << mean <<" Variance: " << variance << " SD: " << standardDeviation << endl;
    stmp2<<"LOW PULSE(ms):;" << mean/1000 << ";" << standardDeviation/1000 << ";;;;;" << endl;
	
	stmp2 << "Total Count=;" << cnt-1 << "; Total Time(s);" << (float)(tpts)/1000000.0 << ";;;;"<< endl;
	tmpstr2 = stmp2.str(); //reassign to string variable
	
	tmpstr = stmp.str(); //reassign to string variable
	cout << tmpstr;  //display to screen
	
	cout << tmpstr2 << endl;  //summary to display
	
	cout << "currentDateTime()=" << currentDateTime()<< endl;	
	
	//write results to csv file	
	char csvName[50];
	char csvFile[100];
	cout << "Enter file name prefix: ";
	cin.getline(csvName,50);
	strcpy(csvFile,"/home/pi/");
	strcat(csvFile,csvName);
	strcat(csvFile,currentDateTime().c_str());  //time stamp the file name
	strcat(csvFile,".csv");
	
	ofstream fp;	// used for logging 
	fp.open (csvFile);
	//add summary for pulses at the top		
	
	fp << tmpstr2;
	fp << "Xaxis; Yaxis; Zaxis; Scale; Time(us); Touch; Touch*;" << endl;
	stmp2.str(""); //clear stringstream for reuse
	k=14;  //starting line on spread sheet	
	for (i=numSamples; i>0; --i) {
		fp << dec << int(aX[i]) << ";" << int(aY[i]) << ";" << int(aZ[i]) << ";" << int(flgScale[i]) << ";" << int(t[i]) << ";" << int(tp[i]) << ";";	
		fp << "=F"<<int(k)<<"*-500" << ";" << int(aX[i]) << endl;
		tmpstr2 = stmp2.str(); //reassign to string variable
		fp << tmpstr2;	//add spreadsheet formula to G and H columns
		k++;
	}		
	fp << tmpstr;	// add notes	
	fp.close();		// close the data file
	
	spiClose();
	GPIOclose();


}//main










// ***************************************************************************************************
// **************************************** SUBROUTINES **********************************************
// ***************************************************************************************************

//***************************************************************** 
//**************** initialize GPIO (libgpiod) *********************
//*****************************************************************
int GPIOinit()
{
    chip = gpiod_chip_open_by_name(chipname);	// Open GPIO chip    
	
	iMCU = gpiod_chip_get_line(chip, 6);			// Open GPIO 6, for mcu interrupt	
	itouch = gpiod_chip_get_line(chip, 5);			// Open GPIO 5, for touch sensor
	csA = gpiod_chip_get_line(chip, 13);		// Open GPIO 13, for CS of Accelerometer

	gpiod_line_request_input(iMCU, "example2");		// Open interupt for input
	gpiod_line_request_input(itouch, "example3");		// Open interupt for input
	gpiod_line_request_output(csA, "example1", 0);		// Open CS line for output
	
	gpiod_line_set_value(csA,1);  		//default CS off

	return 0;
}


//************************************************************ 
//**************** Close GPIO (libgpiod) *********************
//************************************************************ 
int GPIOclose()
{

	gpiod_line_release(iMCU);		// Release line
	gpiod_line_release(itouch);		// Release line
	gpiod_line_release(csA);	// Release line
	
	gpiod_chip_close(chip);			// Release chip
	return 0;
} 


//***************************************************************
//**************** DELAY uS WITHOUT SLEEPING ********************
//***************************************************************
// Delay in program without using Linux scheduler
void delayMicroseconds (int delay_us)
{
	long int start_time;
	long int time_difference;
	struct timespec gettime_now;

	clock_gettime(CLOCK_REALTIME, &gettime_now);
	start_time = gettime_now.tv_nsec;		//Get nS value
	while (1)
	{
		clock_gettime(CLOCK_REALTIME, &gettime_now);
		time_difference = gettime_now.tv_nsec - start_time;
		if (time_difference < 0)
			time_difference += 1000000000;				//(Rolls over every 1 second)
		if (time_difference > (delay_us * 1000))		//Delay for # nS
			break;
	}
}



//*************************************************************
//******************** spiOpen() ******************************
//*************************************************************
//It is responsible for opening the spidev device "devspi" and then setting up the spidev interface.
int spiOpen(){
    int statusVal = -1;
    spifd = open(device, O_RDWR);
    if(spifd < 0){
        perror("could not open SPI device");
        cout << "could not open SPI device" << endl;
        exit(1);
    }
 
    statusVal = ioctl (spifd, SPI_IOC_WR_MODE, &smode);
    if(statusVal < 0){
        perror("Could not set SPIMode (WR)...ioctl fail");
        cout << "Could not set SPIMode (WR)...ioctl fail" << endl;
        exit(1);
    }
 
    statusVal = ioctl (spifd, SPI_IOC_RD_MODE, &smode);
    if(statusVal < 0) {
      perror("Could not set SPIMode (RD)...ioctl fail");
      cout << "Could not set SPIMode (RD)...ioctl fail" << endl;
      exit(1);
    }
 
    statusVal = ioctl (spifd, SPI_IOC_WR_BITS_PER_WORD, &bitsPerWord);
    if(statusVal < 0) {
      perror("Could not set SPI bitsPerWord (WR)...ioctl fail");
      cout << "Could not set SPI bitsPerWord (WR)...ioctl fail" << endl;
      exit(1);
    }
 
    statusVal = ioctl (spifd, SPI_IOC_RD_BITS_PER_WORD, &bitsPerWord);
    if(statusVal < 0) {
      perror("Could not set SPI bitsPerWord(RD)...ioctl fail");
      cout << "Could not set SPI bitsPerWord(RD)...ioctl fail" << endl;
      exit(1);
    }  
 
    statusVal = ioctl (spifd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);    
    if(statusVal < 0) {
      perror("Could not set SPI speed (WR)...ioctl fail");
      cout << "Could not set SPI speed (WR)...ioctl fail" << endl;
      exit(1);
    }
 
    statusVal = ioctl (spifd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);    
    if(statusVal < 0) {
      perror("Could not set SPI speed (RD)...ioctl fail");
      cout << "Could not set SPI speed (RD)...ioctl fail" << endl;
      exit(1);
    }
    return statusVal;
}
 
//***********************************************************
// ********************** spiClose()******************
//*********************************************************
// Responsible for closing the spidev interface. 
int spiClose(){
    int statusVal = -1;
    statusVal = close(spifd);
    if(statusVal < 0) {
      perror("Could not close SPI device");
      cout << "Could not close SPI device" << endl;
      exit(1);
    }
    return statusVal;
}



//********************************************************************
//************************* spiWriteRead *****************************
//********************************************************************
//This function writes data "data" of length "length" to the spidev device.
//Data shifted in from the spidev device is saved back into "data".
int spiWriteRead(unsigned char *data, int length)
{
	struct spi_ioc_transfer tr;
	memset(&tr, 0, sizeof(tr));
	tr.tx_buf = (unsigned long)data; //transmit from data
	tr.rx_buf = (unsigned long)data; //recieve into data
	tr.len = length;				 //num of bytes to send
	tr.speed_hz = speed; 			 //spi speed
	tr.delay_usecs = 0;
	tr.bits_per_word = bitsPerWord;
	tr.cs_change = 0;

	int ret;
	ret = ioctl(spifd, SPI_IOC_MESSAGE(1), &tr);
	if(ret < 0){
		perror("Problem transmitting spi data..ioctl");
		cout << "Problem transmitting spi data..ioctl" << endl;
		exit(1);
	} 

	return ret;
}









