You are on page 1of 8

/****************************************************************************

Module
DisplayService

Revision
1.1

Description
* This module sends data to Processing (on desktop computer) through UART1 in
* order to draw a map of ships and allow for weapons aiming.
Author:
* Emma Morgan (clearScreen, addShip, updateWeapons functions)
* Ethan Kurteff (init, post, run, updateShip, updateWeapons functions)

Revised:
* Ethan Kurteff 5-27-21
*/
#include "DisplayService.h"
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "math.h"

// Hardware
#include <xc.h>
#include <proc/p32mx170f256b.h>
#include <sys/attribs.h> // for ISR macors
#include "Hardware_Configure.h"

//LED Bar Graph Driver


#include "BarGraphService.h"

//Hardware Abstraction Layer


#include "DigitalIO.h"

//SPI
#include "spi.h"

//UART
#include "UARTrx.h"

//Screen Updates
#define TICK_TIME 100 //Time between screen updates (mS) (10Hz)
#define ALIVE_TIME 100 //Time in mS btwn incrementing alive cntrs for ships
#define MAX_ALIVE_TICKS 10 //# intervals of ALIVE_TIME before ship is dead

//Gameplay
//How many teams (MAX) will be playing? Note that Team 0 is a ghost (does not
exist))
#define NUM_TEAMS 10//6+1
#define OUR_TEAM 4 //What's our team #?

//Formatting
#define clearTag 3
#define shipTag 2
1
#define weaponsTag 1
#define LR_X 512000
#define LR_Y 256000
#define HALF_LR_X 256000
#define HALF_LR_Y 128000
#define RANGE 128000
#define PI 3.14159265
#define MAX_DIFF 16384//max distance between ships in scaled value
128000/7.8125

/*Uncomment the following to add two fake static ships to our display*/
//#define FAKESHIP1
//#define FAKE_X1 32768
//#define FAKE_Y1 16384
//#define FAKESHIP2
//#define FAKE_X2 7812
//#define FAKE_Y2 7812

/*---------------------------- Module Variables ---------------------------*/


static uint8_t MyPriority;//What's the number of this service?

////Contains human-readable values from 0-10 that will be displayed on each


graph
//static uint8_t graphArray [NUM_GRAPHS] = {2,4,6,8};

//Contains the location and team number of all the ships:


static struct ship ships[NUM_TEAMS];//Generate ships (one for each team)
static struct weapons myWeapon; //Holds the range + angle of our weapon

static uint8_t aimArray[AIM_LENGTH]; //Holds joystick + range data

static uint8_t shipArray[SHIP_LENGTH]; //Holds ship position data

/*---------------------------- Module Functions ---------------------------*/


/*Clears processing screen of all ships*/
static void clearScreen(void);

/*Draw a ship relative to our ship (syntax: otherShip, ourShip)*/


static void addShip(struct ship, struct ship);

/*Draws updates to aiming vector and range circle*/


static void updateWeapons(struct weapons);

/*Draw all the ships to the screen*/


static void drawShips(void);

/*Update the parameters of a ship from the UART2 data*/


static void updateShip(void);

/*Update our ship with aiming & location from SPI1 data*/
static void updateOurShip(void);

//volatile uint8_t RX_Buffer;//Message we received via UART2 from ESP32


2
//volatile uint16_t TX_Buffer;//Message to send out via UART2 to PIC B
//volatile uint8_t switchState;//Bits 0-2 hold states for switches 1-3

/*------------------------------ Module Code ------------------------------*/


/***************************** INIT
*****************************************/
bool InitDisplayService(uint8_t Priority)
{
ES_Event_t ThisEvent;
MyPriority = Priority;

//Wait to start up system to give game PIC time to prepare:


ES_Timer_InitTimer(INIT_TMR, INIT_TIME);

return true;//Assume success


}

/***************************** POST
*****************************************/
bool PostDisplayService(ES_Event_t ThisEvent)
{
return ES_PostToService(MyPriority, ThisEvent);
}

/***************************** RUN
*****************************************/
ES_Event_t RunDisplayService(ES_Event_t ThisEvent)
{
ES_Event_t ReturnEvent;
ReturnEvent.EventType = ES_NO_EVENT; // assume no errors

switch (ThisEvent.EventType)
{
case ES_TIMEOUT:
{
switch (ThisEvent.EventParam)
{
case INIT_TMR:
{
/*Initialization Code:*/
hardwareInit();
ES_Timer_InitTimer(TICK_TMR, TICK_TIME);
}
case TICK_TMR:
{
#ifndef SPI_DEBUG
/*Tell the Display Service to draw next frame*/
clearScreen(); //Delete all entities
updateWeapons(myWeapon);//Draw the aim + range
drawShips(); //Add all the ships
// printf("\n\r",myWeapon.DIST);
#endif //SPI_DEBUG

#ifdef FAKESHIP1
3
struct ship targetShip;
targetShip.X_LSB = FAKE_X1 & 255;
targetShip.X_MSB = (FAKE_X1 >> 8) & 255;
targetShip.Y_LSB = FAKE_Y1 & 255;
targetShip.Y_MSB = (FAKE_Y1 >> 8) & 255;
targetShip.TEAM = 1;
targetShip.ISALIVE = 1;
targetShip.ALIVE_TICKS = 1;
addShip(targetShip, ships[OUR_TEAM]);
#endif

#ifdef FAKESHIP2
struct ship targetShip2;
targetShip2.X_LSB = FAKE_X2 & 255;
targetShip2.X_MSB = (FAKE_X2 >> 8) & 255;
targetShip2.Y_LSB = FAKE_Y2 & 255;
targetShip2.Y_MSB = (FAKE_Y2 >> 8) & 255;
targetShip2.TEAM = 2;
targetShip2.ISALIVE = 1;
targetShip2.ALIVE_TICKS = 1;
addShip(targetShip2, ships[OUR_TEAM]);
#endif
//printf("\n\rTICK");
//Re-init the tick timer for next update
ES_Timer_InitTimer(TICK_TMR, TICK_TIME);
}break;
case ALIVE_TMR:
{
/*Iterate through each team's ship*/
for(uint8_t i = 0; i < NUM_TEAMS; i++){
if(ships[i].TEAM != OUR_TEAM){//If the ship is not ours
ships[i].ALIVE_TICKS++; //Increment the alive ticks
}

/*If ship hasn't responded in a while, we consider it


dead*/
if(ships[i].ALIVE_TICKS >= MAX_ALIVE_TICKS){
ships[i].ISALIVE = 0;//Kill the ship
}
}
//Re-init the alive timer for next update
ES_Timer_InitTimer(ALIVE_TMR, ALIVE_TIME);
}
}
}
break;
case ES_SHIP_UPDATE:
{
updateShip();

}
break;
case ES_OUR_SHIP_UPDATE:
{
4
updateOurShip();
}
break;

}
return ReturnEvent;
}

/***************************************************************************
Private Functions
***************************************************************************/

/***************************** CLEAR
****************************************/
void clearScreen(void){
printf("%c\n", clearTag);
}

/***************************** ADD
*****************************************/
static void addShip(struct ship targetShip, struct ship ourShip){
uint16_t targetX = targetShip.X_LSB | (targetShip.X_MSB << 8); //combine
into uint16_t
uint16_t ourX = ourShip.X_LSB | (ourShip.X_MSB << 8); //combine into
uint16_t
uint16_t targetY = targetShip.Y_LSB | (targetShip.Y_MSB << 8); //combine
into uint16_t
uint16_t ourY = ourShip.Y_LSB | (ourShip.Y_MSB << 8); //combine into
uint16_t
int32_t xInv = ourX - 65535;
int32_t yInv = ourY - 65535;
int16_t xDiff;
int16_t yDiff;
if((abs(ourX - targetX) < MAX_DIFF)){ // if closer than 128
xDiff = ourX - targetX;
if(abs(ourY - targetY) < MAX_DIFF){
yDiff = ourY - targetY;
}else if(abs(yInv - targetY) < MAX_DIFF) {
yDiff = yInv - targetY;
}else{
yDiff = 0;
xDiff = 0;
}
}else if(abs(xInv - targetX) < MAX_DIFF) {
xDiff = xInv - targetX;
if(abs(ourY - targetY) < MAX_DIFF){
yDiff = ourY - targetY;
}else if(abs(yInv - targetY) < MAX_DIFF){
yDiff = yInv - targetY;
}else{
yDiff = 0;
xDiff = 0;
}
}else{
5
xDiff = 0;
yDiff = 0;
}

uint8_t xDiffUpper = (xDiff >> 8) & 255;


uint8_t xDiffLower = xDiff & 255;
uint8_t yDiffUpper = (yDiff >> 8) & 255;
uint8_t yDiffLower = yDiff & 255;
printf("%c%c%c%c%c%c%c%c%c%c\n",shipTag, targetShip.TEAM,
targetShip.X_LSB, targetShip.X_MSB, targetShip.Y_LSB, targetShip.Y_MSB,
xDiffLower, xDiffUpper, yDiffLower, yDiffUpper);
}

/***************************** UPDATE WEAPS


*********************************/
static void updateWeapons(struct weapons w1){
printf("%c%c%c%c\n",weaponsTag, w1.DIST, w1.ANGLE_LSB, w1.ANGLE_MSB);
}

/***************************** DRAW SHIPS **********************************/


static void drawShips(void){
uint8_t i;
/*Iterate through each team, drawing the ship*/
for(i = 1; i < NUM_TEAMS; i++){//Skip ship # 0
if(ships[i].ISALIVE){//If the ship is not dead
addShip(ships[i], ships[OUR_TEAM]);//Add it to the screen
}
}
}

/***************************** UPDATE SHIP


**********************************/
static void updateShip(void){
struct ship thisShip;
thisShip = getShip(); //Pull ship data from SPI service
uint8_t teamNum = thisShip.TEAM;//Figure out which team this ship is from

if(thisShip.TEAM == OUR_TEAM){ //If this is our ship


//Ignore updates b/c we get our ship data thru SPI
}
else{ //If this isn't our ship
/*Update the parameters of this team's ship.*/
ships[teamNum].X_LSB = thisShip.X_LSB;
ships[teamNum].X_MSB = thisShip.X_MSB;
ships[teamNum].Y_LSB = thisShip.Y_LSB;
ships[teamNum].Y_MSB = thisShip.Y_MSB;
ships[teamNum].ISALIVE = thisShip.ISALIVE;
ships[teamNum].ALIVE_TICKS = 0;//Reset timeout for ship death/ disconnect
}

/***************************** UPDATE Weapons


*******************************/
6
static void updateOurShip(void){
static double theta;//Used in aim angle calculation

/*Grab position values from SPI Service*/


uint8_t * shipPointer = getShipVals();
for(uint8_t i = 0; i < SHIP_LENGTH; i++){//For each element of shipArray
//Copy the element from SPI Service to aimArray
shipArray[i] = *(shipPointer + i);
}
ships[OUR_TEAM].TEAM = OUR_TEAM;
ships[OUR_TEAM].X_MSB = shipArray[0];
ships[OUR_TEAM].X_LSB = shipArray[1];
ships[OUR_TEAM].Y_MSB = shipArray[2];
ships[OUR_TEAM].Y_LSB = shipArray[3];
ships[OUR_TEAM].ISALIVE = shipArray[4];

/*Grab aim values from SPI Service*/


uint8_t * aimPointer = getAimVals();
for(uint8_t i = 0; i < AIM_LENGTH; i++){//For each element of aimArray
//Copy the element from SPI Service to aimArray
aimArray[i] = *(aimPointer + i);
}

/*Combine MSB and LSB data for joystick values (0-1024)*/


int16_t xVal = (aimArray[0]) << 8 | aimArray[1];
int16_t yVal = (aimArray[2]) << 8 | aimArray[3];

/*Create signed coordinates for x and y*/


int16_t xCoord = xVal-JOY_MID;
int16_t yCoord = yVal-JOY_MID;

/*If we're not too close to the joystick center location*/


if(xCoord > DEAD_ZONE || xCoord < -DEAD_ZONE ||
yCoord > DEAD_ZONE || yCoord < -DEAD_ZONE){
/*Calculate joystick angle in degrees (-180 to 180 output)*/
theta = atan2(yCoord, xCoord)*180/PI;
}

if(theta < 0) theta += 360;//Adjust output to be 0-360 degrees

/*Map joystick angle from 0-360 to 0-65535*/


uint16_t theta16 = (uint16_t)(theta*(65535/360.0));

/*Update MSB and LSB for weapon angle*/


myWeapon.ANGLE_MSB = (uint8_t)(theta16 >> 8);
myWeapon.ANGLE_LSB = (uint8_t)(theta16);

/*Grab the distance for myWeapon*/


myWeapon.DIST = aimArray[AIM_LENGTH-1];

//#ifdef SPI_DEBUG

//printf("%f",theta);
// printf(" %d",aimArray[0]);
7
// printf(" %d",aimArray[1]);
// printf(" %d",aimArray[2]);
// printf(" %d",aimArray[3]);
// uint16_t xC = ships[OUR_TEAM].X_MSB << 8 | ships[OUR_TEAM].X_LSB;
// uint16_t yC = (uint16_t)shipArray[2] << 8 | shipArray[3];

// // if(xC!=0 && yC!=0){


// printf("\n\r");
////// printf(" %d", shipArray[0]);
////// printf(" %d", shipArray[1]);
// printf(" %d", xC);
//printf(" %d", yC);
// }

// printf(" %d",shipArray[0]);
// printf(" %d",shipArray[1]);
// printf(" %d",shipArray[2]);
// printf(" %d",shipArray[3]);
// printf(" %d",shipArray[4]);
//#endif //SPI_DEBUG
////
// printf(" %d",xCoord);
// printf(" %d",yCoord);
//printf(" %d",theta16);

// printf(" %d",myWeapon.ANGLE_MSB << 8 | myWeapon.ANGLE_LSB);


// printf(" %d",myWeapon.DIST);
}
/***************************************************************************
Public Functions
***************************************************************************/

You might also like