Skip to content
Snippets Groups Projects
microcart_cli.c 8.69 KiB
Newer Older
burneykb's avatar
burneykb committed
/* Author: Kris Burney
 *
 * BlueTooth socket program for passing vrpn data to quad.
 */
//system includes
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>
#include <pthread.h>

//user created includes
#include "communication.h"
#include "parse_packet.h"
#include "vrpn_tracker.hpp"
#include "type_def.h"
#include "commands.h"
#include "logger.h"

#define QUAD_BT_ADDR  "00:06:66:64:61:D6"
#define QUAD_BT_CHANNEL  0x01
#define CMD_MAX_LENGTH 1024

// function prototypes
void killHandler(int);
void readAndPrint(void);
void sendVrpnPacket(struct ucart_vrpn_TrackerData *);
void sendStartPacket(void);
void getVRPNPacket(struct ucart_vrpn_TrackerData *);
void printVrpnData(struct ucart_vrpn_TrackerData *);
int connectToZybo();
void *handleQuadResponse();
void *handleCliInput();

static void cb(struct ucart_vrpn_TrackerData *);


// global variables
static volatile int keepRunning = 1;
const char *TRACKER_IP = "UAV@192.168.0.120:3883";
int quadlog_file;
int zyboSocket, status, bytes_read;
struct ucart_vrpn_tracker * tracker = NULL;
const char *logHeader = "";//"#\n#\tDefault log header\n#\tEverything after '#'`s will be printed as is in the processed logs.\n#\n\0";

pthread_mutex_t quadResponseMutex, cliInputMutex ;
unsigned char *respBuf, *commandBuf;
int newQuadResponse = 0, newCliInput = 0;




// Callback to be ran whenever the tracker receives data.
// Currently doing much more than it should. It will be slimmed down 
// 		in the future.
static void cb(struct ucart_vrpn_TrackerData * td)
{
	static int count = 0;

	if(!(count % 10)) {
		sendVrpnPacket(td);
		updateLogFile(td);
	}

	count++;

	// This will print the vrpn data to the terminal if necissary.
	// Commented out because the callback will cover quad log data
	//   at the end of flight.
	/**if(!(count % 100)) {
	 	printVrpnData(td);
	 	printf("[Info] Received %d tracker updates.\n", count);
	}**/
}

void *handleQuadResponse() {
	unsigned char buffer[255];

	while(keepRunning) {
		printf("in quad response thread\n"); fflush(0);
		// Clear the buffer and read the message from the socket (from the server)
		memset(buffer, 0, 255);

		// If there was an error reading from the socket, throw an error
		if(read(zyboSocket, buffer, 255) <= 0) {
			fprintf(stderr, "CLI QUAD: ERROR reading from quad.\n");
			fflush(stderr);
			continue;
		}

		pthread_mutex_lock(&quadResponseMutex);
		newQuadResponse = 1;
		memcpy(respBuf, buffer, 255);
		pthread_mutex_unlock(&quadResponseMutex);


		//parse_packet(buffer, &respBuf, &metadata);
		printf("CLI QUAD: %s\n", buffer);
	}

	pthread_exit(NULL);
}

void *handleCliInput() {
	while(keepRunning)
	{
		printf("in cli input thread\n"); fflush(0);
		char userCommand[CMD_MAX_LENGTH] = {};
		fprintf(stderr, "$microcart> ");

		while(fgets(userCommand, sizeof(userCommand), stdin) != NULL && keepRunning) {
			
			// if the user simply hit enter then let them try again
			if((userCommand[0] == '\n') || (userCommand[0] == '\r'))
			{
				fprintf(stderr, "$microcart> ");

				memset(userCommand, 0, CMD_MAX_LENGTH);

				continue;
			}

			pthread_mutex_lock(&cliInputMutex);
			newCliInput = 1;
			memcpy(commandBuf, &userCommand, CMD_MAX_LENGTH);
			pthread_mutex_unlock(&cliInputMutex);

			
			fprintf(stderr, "$microcart> ");

			memset(userCommand, 0, CMD_MAX_LENGTH);
		}
	}

	pthread_exit(NULL);
}

int main(int argc, char **argv)
{
	pthread_t quadResponse, cliInput;
	respBuf = malloc(1024);
	commandBuf = malloc(CMD_MAX_LENGTH);
	


	signal(SIGINT, killHandler);

//	if ((zyboSocket = connectToZybo()) < 0)
//	{
//		perror("Error connecting to Zybo...");
//		exit(1);
//	}
	
	// create vrpnTracker instance
//	tracker = ucart_vrpn_tracker_createInstance(TRACKER_IP);

	// Retrieve VRPN data from the control loop
	fprintf(stderr, "CLI: Starting quad receiving thread...\n");
	pthread_create(&quadResponse, NULL, handleQuadResponse, NULL);
	fprintf(stderr, "CLI: Thread quad receiving started.\n");

	fprintf(stderr, "CLI: Starting cli input thread...\n");
	pthread_create(&cliInput, NULL, handleCliInput, NULL);
	fprintf(stderr, "CLI: Thread Cli input started.\n");


	// open the log file
//	if( (status = createLogFile(argc, argv[1])) < 0)
//	{
//		perror("Error creating log file...");
//		exit(1);
//	}
//	writeLogHeader(logHeader);

	//tell the quad we are ready to send it vrpn data
//	printf("sending Start Packet...\n");
//	sendStartPacket();

	// this function will be called whenever tracker receives data
//	ucart_vrpn_tracker_addCallback(tracker, cb);
	while(1)
	{
burneykb's avatar
burneykb committed
		char tmpRespBuf[1024];
		char tmpCommandBuf[CMD_MAX_LENGTH];
burneykb's avatar
burneykb committed
		//check for user input via cli
		if(newCliInput)
		{
			pthread_mutex_lock(&cliInputMutex);
			newCliInput = 0;
			memcpy(tmpCommandBuf, commandBuf, CMD_MAX_LENGTH);
			pthread_mutex_unlock(&cliInputMutex);

			// I can use printf becuase the command was gathered using fgets.
			printf("\nINPUT FOUND via CLI: '%s'\n", tmpCommandBuf); fflush(0);
		}

		//check for update/response from quad
		if(newQuadResponse)
		{
			pthread_mutex_lock(&quadResponseMutex);
			newQuadResponse = 0;
			memcpy(tmpRespBuf, respBuf, 1024);
			pthread_mutex_unlock(&quadResponseMutex);

			printf("\nINPUT FOUND via QUAD: '"); fflush(0);
			fwrite(tmpRespBuf, 1024, 1, stdout);
			printf("'\n"); fflush(0);
		}
burneykb's avatar
burneykb committed
		usleep(10000);
burneykb's avatar
burneykb committed
	}

	

	ucart_vrpn_tracker_freeInstance(tracker);
	//free(vrpnData);
	free(respBuf);
	free(commandBuf);
	pthread_mutex_destroy(&cliInputMutex);
	pthread_mutex_destroy(&quadResponseMutex);
	close(zyboSocket);
	close(quadlog_file);
	return 0;
}

// signal handler to exit while loop of main function
void killHandler(int dummy) {
	keepRunning = 0;
	printf("\nleaving Bluetooth module\n");
}

void readAndPrint() {
	// read data from the server
	// this is a blocking call.
	//TODO: Implement a non blocking version of this.
	bytes_read = read(zyboSocket, respBuf, sizeof(respBuf) -1);
	if( bytes_read > 0)
	{
		respBuf[bytes_read] = '\0';
		printf("%s", respBuf);
	}
}

void sendStartPacket() {
	unsigned char packet[8] = {0};

	metadata_t metadata = 
	{
		BEGIN_CHAR,
		0x04,
		0x01,
		0x01,
		0
	};

	packet[0] = metadata.begin_char; // BEGIN					//PACKET_START_BYTE;
	packet[1] = metadata.msg_type;	// UPDATE				//'U'; // U for vrpn camera update, C for command
	packet[2] = metadata.msg_subtype; // BEGIN UPDATE
	packet[3] = 1; 			// MSG ID(1)
	packet[4] =	0; // MSG ID(2)
	packet[5] = 0; 			// DATALEN(1)
	packet[6] = 0; 	// DATALEN(2)
	
	char checksum = 0;
	int i;
	for(i=0; i < metadata.data_len + 7; i++)
		checksum ^= packet[i];

	packet[metadata.data_len + 7] = checksum; //PACKET_END_BYTE;
	status = write(zyboSocket, &packet, metadata.data_len + 8);
	if (status != 8)
	{
		perror("Error sending start packet...\n");
		keepRunning = 0;
	}else
	{
		printf("Start packet successfuly sent...\n");
	}
}

void sendVrpnPacket(struct ucart_vrpn_TrackerData *info) {
	int pSize = sizeof(info) + 8;
	int n;
	char packet[pSize];
	packet[0] = 0xBE; // BEGIN					//PACKET_START_BYTE;
	packet[1] = 0x04;	// UPDATE				//'U'; // U for vrpn camera update, C for command
	packet[2] = 0x00; // N/A
	//TODO Figure out Packet ID with this new ucar_vrpn_TrackerData struct
	packet[3] = (0x00 & 0x000000ff); 			// MSG ID(1)
	packet[4] =	((0x00 >> 8) & 0x000000ff); // MSG ID(2)
	packet[5] = (sizeof(info) & 0x000000ff); 			// DATALEN(1)
	packet[6] = ((sizeof(info) >> 8) & 0x00000ff); 	// DATALEN(2)
	memcpy(&packet[7], &info, sizeof(info));

	char checksum = 0;
	int i;
	for(i=0; i < pSize - 1; i++)
		checksum ^= packet[i];

	packet[pSize - 1] = checksum; //PACKET_END_BYTE;

	n = write(zyboSocket, packet, pSize);
	if(n < 0) {	
		perror("vrpnhandler: ERROR writing to socket");
		keepRunning = 0;
	}
}

void getVRPNPacket(struct ucart_vrpn_TrackerData *td) {
	int status;
	if((status = ucart_vrpn_tracker_getData(tracker, td)) < 0)
	{
		perror("Error receiving VRPN data from tracker...");
		keepRunning = 0;
	}
}

void printVrpnData(struct ucart_vrpn_TrackerData * td) {
	printf("FPS: %lf Pos (xyz): (%lf %lf %lf) Att (pry): (%lf %lf %lf)\n",
		td->fps, td->x, td->y, td->z, td->pitch, td->roll, td->yaw);
}

int connectToZybo() {
	int sock;
	struct sockaddr_rc addr = { -1 };

	// allocate a socket	
	sock = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);

	//set the connection params ie. who to connect to	
	addr.rc_family = AF_BLUETOOTH;
	addr.rc_channel = (uint8_t) QUAD_BT_CHANNEL;
	str2ba( QUAD_BT_ADDR, &addr.rc_bdaddr );
	
	printf("Attempting to connect to zybo. Please be patient...\n");
	// blocking call to connect to socket sock ie. zybo board
	status = connect(sock, (struct sockaddr *)&addr, sizeof(addr));

	// connection failed
	if(status < 0)
	{
		close(sock);
		printf("Connection failed!...\n");
		return -1;
	} 
	else
	{
		printf("connection successful!...\n");
		return sock;
	}
}