/* * File: host.c * Author: falcod * * Created on November 10, 2015, 8:12 AM */ // ***************************************************************************** // Section: Included Files // ***************************************************************************** // graphics libraries #include "config.h" #include "tft_master.h" #include "tft_gfx.h" #include #include "adc_intf.h" #include "TouchScreen.h" //math library #include // threading library #include "pt_cornell_1_2.h" // standard library #include #include #include // BLE library #include "biscuit_central.h" #include "ble_hci.h" // ***************************************************************************** // Section: Global Data Definitions // ***************************************************************************** // config.h sets 40 MHz #define SYS_FREQ 40000000 //Definitions for debouncer #define NOPUSH 0 #define MAYBEPUSH 1 #define PUSHED 2 #define MAYBENOPUSH 3 // definitions for score counter #define ONEUP 1 #define TENUP 10 #define HUNDREDUP 100 #define ONEDOWN -1 #define TENDOWN -10 #define HUNDREDDOWN -100 // definitions for connection handles #define HOST 0xFFFE #define PLAYER1 0x0000 #define PLAYER2 0x0001 #define PLAYER3 0x0002 #define SS LATBbits.LATB13 #define dirSS TRISBbits.TRISB13 #define anSS ANSELBbits.ANSB13 // touch screen push "button" variables volatile int pushState = NOPUSH; bool send = false; bool clear = false; bool reset = false; bool playerSet = false; bool playerChanged = false; // play states bool start = false; bool playing = false; bool locked = false; volatile int score = 0; /*volatile*/ char oneBuf[2], tenBuf[2], hundBuf[2]; volatile bool updateScore = true; volatile int selectedPlayer = 0; volatile uint16 playerAddress = HOST; uint8_t found_address[6] = {0xBF, 0x9A, 0x5E, 0x84, 0xCB, 0xE1}; // Bluefruit uint8_t player1_address[6] = {0x23, 0x11, 0x7B, 0x4C, 0x99, 0xB4}; // Red Bear uint8_t player2_address[6] = {0xBA, 0x29, 0x7B, 0x4C, 0x99, 0xB4}; // Red Bear uint8_t player3_address[6] = {0x56, 0x19, 0x7B, 0x4c, 0x99, 0xB4}; // Red Bear: B4:99:4C:7B:19:56 uint8_t writeBuf[10]; ////scanf values //int target_address = 99; //int sender_address = 99; //char command = '?'; //int value =0; //unsigned char playerSelect = 'x', oldPlayerSelect = 'x'; // ***************************************************************************** // Section: User Functions // ***************************************************************************** //inline void __attribute__((always_inline)) UARTClrBits ( UART_MODULE id, UART_CONFIGURATION flags ) //{ // //playerSelect = uartReg[id]->rx.reg[7]; // //printf("%i ", sizeof(PT_term_buffer)); // // oldPlayerSelect = playerSelect; // playerSelect = PT_term_buffer[6] + 49; // if((playerSelect == '1' || playerSelect == '2') && playing){ // printf(" found player %c \n",playerSelect); // sprintf(writeBuf, "%c 0 f\r", playerSelect); // biscuit_central_write_bytes(playerSelect-49, writeBuf, sizeof(writeBuf) ); // locked = true; // } // else playerSelect = oldPlayerSelect; // // uartReg[id]->sta.clr = (flags); // Defined in uart.h //} // //inline void __attribute__((always_inline)) clrUARTRxBuffer( UART_MODULE UARTid ) //{ ////UART_OVERRUN_ERROR defined in uart.h //UARTClrBits( UARTid, UART_OVERRUN_ERROR | UART_FRAMING_ERROR ); //} //delays durin init void delay( unsigned t) { //uses internal timer 2 T2CON = 0x8000; // enable tmr1, Tcy, 1:1 while (t--) { TMR2 = 0; // while (TMR1<8000); while( TMR2< 8000); } } // function to handle send button push bool sendButtonPushed(int x, int y) { // toggle for testing if ((x > 250 && x < 312) && (y > 10 && y < 50)){ return true; } else { return false; } } // function to handle clear button push bool clearButtonPushed(int x, int y) { // toggle for testing if ((x > 250 && x < 312) && (y > 190 && y < 230)){ return true; } else { return false; } } // function to handle reset button push bool resetButtonPushed(int x, int y) { // toggle for testing if ((x > 10 && x < 72) && (y > 190 && y < 230)){ return true; } else { return false; } } // function to handle scoring buttons int scoreButtons(int x, int y) { if ((x > 190 && x < 250) && (y > 50 && y < 80)){ return ONEUP; } else if ((x > 190 && x < 250) && (y > 160 && y < 190)){ return ONEDOWN; } else if ((x > 120 && x < 180) && (y > 50 && y < 80)) { return TENUP; } else if ((x > 120 && x < 180) && (y > 160 && y < 190)){ return TENDOWN; } else if ((x > 50 && x < 110) && (y > 50 && y < 80)) { return HUNDREDUP; } else if ((x > 50 && x < 110) && (y > 160 && y < 190)){ return HUNDREDDOWN; } else { return 0; } } /** * Method to check which player selection button was pressed. * Returns the number of the player button pressed */ int playerSelection(int x, int y) { if ((x>5 && x<45) && (y>5 && y<45)) { return 1; } else if ((x>55 && x<95) && (y>5 && y<45)) { return 2; } else { return 0; } } /** * method to check whether the touchscreen's current location data overlaps * with the start button. */ bool isStart(int x, int y) { if ( (x>120 && x<200) && (y>100 && y<140) ) { return true; } else { return false; } } // inline function to update score inline void overwriteScore( void ) { // calc score digits int hundreds = abs(score/100); int tens = abs((score%100)/10); int ones = abs(score%10); // erase score if (score >= 0) { tft_setCursor(10, 92); tft_setTextColor(ILI9341_BLACK); tft_setTextSize(8); tft_writeString("-"); } tft_setCursor(60, 92); tft_setTextColor(ILI9341_BLACK); tft_setTextSize(8); tft_writeString(hundBuf); tft_setCursor(130, 92); tft_setTextColor(ILI9341_BLACK); tft_setTextSize(8); tft_writeString(tenBuf); tft_setCursor(200, 92); tft_setTextColor(ILI9341_BLACK); tft_setTextSize(8); tft_writeString(oneBuf); // write score if (score<0) { tft_setCursor(10, 92); tft_setTextColor(ILI9341_WHITE); tft_setTextSize(8); tft_writeString("-"); } tft_setCursor(60, 92); tft_setTextColor(ILI9341_WHITE); sprintf(hundBuf, "%i", hundreds ); tft_setTextSize(8); tft_writeString(hundBuf); tft_setCursor(130, 92); tft_setTextColor(ILI9341_WHITE); sprintf(tenBuf, "%i", tens ); tft_setTextSize(8); tft_writeString(tenBuf); tft_setCursor(200, 92); tft_setTextColor(ILI9341_WHITE); sprintf(oneBuf,"%i", ones ); tft_setTextSize(8); tft_writeString(oneBuf); } // === thread structures ============================================ // thread control structs static struct pt pt_screen, pt_touch /*, pt_input, pt_read, pt_clear*/; //// === UART Clear Thread ================================================= //// Clears the UART Rx buffer under certain conditons. //static PT_THREAD (protothread_clear(struct pt *pt)) { // PT_BEGIN(pt); // while(2) { // PT_YIELD_TIME_msec(1) ; // if(UARTGetLineStatus(UART2) & UART_FRAMING_ERROR){ // //printf("framing error\n"); // clrUARTRxBuffer(UART2); // } // if(UARTGetLineStatus(UART2) & UART_OVERRUN_ERROR ){ // //printf("overrun error\n"); // clrUARTRxBuffer(UART2); // } // if(UARTGetLineStatus(UART2) & UART_PARITY_ERROR){ // //printf("parity error\n"); // clrUARTRxBuffer(UART2); // } // // selectedPlayer = playerSelect - 48; // switch(selectedPlayer) { // case 1: playerAddress = PLAYER1; break; // case 2: playerAddress = PLAYER2; break; // case 3: playerAddress = PLAYER3; break; // default: playerAddress = HOST; break; // } // // // NEVER exit while // } // END WHILE(1) // PT_END(pt); //} // thread // //// === UART Read Thread ================================================= //// Reads a String from the UART channel into a buffer. //static PT_THREAD (protothread_read(struct pt *pt)) { // PT_BEGIN(pt); // while(1) { // PT_YIELD_TIME_msec(100) ; // // // // // test by circle draw // tft_fillCircle(125, 25, 15, ILI9341_RED); // PT_SPAWN(pt, &pt_input, PT_GetSerialBuffer(&pt_input) ); // // // // // test by circle draw // tft_fillCircle(140, 25, 15, ILI9341_GREEN); // printf("%s \n", PT_term_buffer); //// // scans UART terminal for specified format //// target_address = PT_term_buffer[11]; //99; //// sender_address = PT_term_buffer[13]; //99; //// command = PT_term_buffer[15]; //'?'; //// value = 0; //// sscanf( PT_term_buffer, "%i %i %c %i", &target_address, //// &sender_address ,&command, &value ); //// //reprints when entered //// printf("Host Found <%i> <%i> <%c> <%i> \n", target_address, sender_address ,command, value); // // // //// // sets values based on input //// if(target_address == 0){ //// if(command == 'p' && locked == false){ //// sprintf(writeBuf, "%i 0 f\r", selectedPlayer); //// biscuit_central_write_bytes(playerAddress, writeBuf, sizeof(writeBuf) ); //// locked = true; //// } //// } // // // NEVER exit while // } // END WHILE(1) // PT_END(pt); //} // thread // ==== Screen Thread ===================================================== // Displays information on the LCD Screen static PT_THREAD (protothread_screen(struct pt *pt)) { PT_BEGIN(pt); while(1) { PT_YIELD_TIME_msec(25); // if(UARTGetLineStatus(UART2) & UART_FRAMING_ERROR){ // //printf("framing error\n"); // clrUARTRxBuffer(UART2); // } // if(UARTGetLineStatus(UART2) & UART_OVERRUN_ERROR ){ // //printf("overrun error\n"); // clrUARTRxBuffer(UART2); // } // if(UARTGetLineStatus(UART2) & UART_PARITY_ERROR){ // //printf("parity error\n"); // clrUARTRxBuffer(UART2); // } // selectedPlayer = playerSelect - 48;//sender_address; // switch(selectedPlayer) { // case 1: playerAddress = PLAYER1; break; // case 2: playerAddress = PLAYER2; break; // case 3: playerAddress = PLAYER3; break; // default: playerAddress = HOST; break; // } // // // test by circle draw // tft_fillCircle(75, 25, 15, ILI9341_YELLOW); if (start) { start=false; playing=true; locked = false; //clears player modules sprintf( writeBuf, "1 0 r\r" ); PT_YIELD_TIME_msec(500); biscuit_central_write_bytes(PLAYER1, writeBuf, sizeof(writeBuf)); sprintf( writeBuf, "2 0 r\r" ); PT_YIELD_TIME_msec(500); biscuit_central_write_bytes(PLAYER2, writeBuf, sizeof(writeBuf)); //sprintf( writeBuf, "3 0 r\r", score ); PT_YIELD_TIME_msec(500); //biscuit_central_write_bytes(PLAYER3, writeBuf, sizeof(writeBuf)); // erases start button tft_fillRoundRect(120, 100, 80, 40, 10, ILI9341_BLACK); overwriteScore(); } else if (playing) { if (playerChanged==true && selectedPlayer==1) { playerAddress = PLAYER1; playerChanged=false; tft_drawRect(5,5,40,40,ILI9341_ORANGE); sprintf (writeBuf, "2 0 l\r"); PT_YIELD_TIME_msec(500); biscuit_central_write_bytes(PLAYER2, writeBuf, sizeof(writeBuf)); } else if (playerChanged==true && selectedPlayer==2) { playerAddress = PLAYER2; playerChanged=false; tft_drawRect(55,5,40,40,ILI9341_RED); sprintf (writeBuf, "1 0 l\r"); PT_YIELD_TIME_msec(500); biscuit_central_write_bytes(PLAYER1, writeBuf, sizeof(writeBuf)); } // Checks other buttons if (clear==true) { tft_setCursor(120, 200); tft_setTextSize(3); tft_setTextColor(ILI9341_WHITE); tft_writeString("Clear!"); sprintf( writeBuf, "1 0 c\r" ); PT_YIELD_TIME_msec(500); biscuit_central_write_bytes(PLAYER1, writeBuf, sizeof(writeBuf)); sprintf( writeBuf, "2 0 c\r" ); PT_YIELD_TIME_msec(500); biscuit_central_write_bytes(PLAYER2, writeBuf, sizeof(writeBuf)); // sprintf( writeBuf, "3 0 c\r", score ); PT_YIELD_TIME_msec(500); // biscuit_central_write_bytes(PLAYER3, writeBuf, sizeof(writeBuf)); score = 0; overwriteScore(); clear=false; locked = false; // clears selected player selectedPlayer = 0; playerSet = false; tft_drawRect(55,5,40,40,ILI9341_BLACK); tft_drawRect(5,5,40,40,ILI9341_BLACK); } else if (send==true && playerSet==true) { // playerAddress = PLAYER2; selectedPlayer = 2; tft_setCursor(120, 200); tft_setTextSize(3); tft_setTextColor(ILI9341_WHITE); tft_writeString("Send!"); if (score < 0) { sprintf(writeBuf,"%i 0 s %i\r", selectedPlayer, abs(score)); } else { sprintf(writeBuf, "%i 0 a %i\r", selectedPlayer, score ); } biscuit_central_write_bytes(playerAddress, writeBuf, sizeof(writeBuf) ); // clears lockout flags sprintf( writeBuf, "1 0 c\r" ); PT_YIELD_TIME_msec(500); biscuit_central_write_bytes(PLAYER1, writeBuf, sizeof(writeBuf)); sprintf( writeBuf, "2 0 c\r" ); PT_YIELD_TIME_msec(500); biscuit_central_write_bytes(PLAYER2, writeBuf, sizeof(writeBuf)); // sprintf( writeBuf, "3 0 c\r", score ); PT_YIELD_TIME_msec(500); // biscuit_central_write_bytes(PLAYER3, writeBuf, sizeof(writeBuf)); score = 0; overwriteScore(); send=false; locked = false; // clears selected player selectedPlayer = 0; playerSet = false; tft_drawRect(55,5,40,40,ILI9341_BLACK); tft_drawRect(5,5,40,40,ILI9341_BLACK); } else if (reset==true) { tft_setCursor(120, 200); tft_setTextSize(3); tft_setTextColor(ILI9341_WHITE); tft_writeString("Reset!"); // resets sprintf( writeBuf, "1 0 r\r" ); PT_YIELD_TIME_msec(500); biscuit_central_write_bytes(PLAYER1, writeBuf, sizeof(writeBuf)); sprintf( writeBuf, "2 0 r\r" ); PT_YIELD_TIME_msec(500); biscuit_central_write_bytes(PLAYER2, writeBuf, sizeof(writeBuf)); // sprintf( writeBuf, "3 0 r\r", score ); PT_YIELD_TIME_msec(500); // biscuit_central_write_bytes(PLAYER3, writeBuf, sizeof(writeBuf)); score = 0; reset=false; locked = false; playing = false; // clears selected player selectedPlayer = 0; playerSet = false; tft_drawRect(55,5,40,40,ILI9341_BLACK); tft_drawRect(5,5,40,40,ILI9341_BLACK); // erases score button tft_fillRect(10, 92, 310, 56, ILI9341_BLACK); tft_fillRect(120,200,100,40, ILI9341_BLACK); // display start button tft_fillRoundRect(120, 100, 80, 40, 10, ILI9341_GREENYELLOW); tft_setCursor(128, 112); tft_setTextColor(ILI9341_DARKGREEN); tft_setTextSize(2); tft_writeString("START!"); } else { tft_fillRect(120,200,100,40, ILI9341_BLACK); } if (updateScore==true) { // erase old score updateScore=false; overwriteScore(); } } } PT_END(pt); } // thread end char locBuf[60]; int x, y; // === Touch Data Thread ================================================= // Handles values from the touchscreen to determine whether a button has // been pressed. static PT_THREAD (protothread_touch(struct pt *pt)) { PT_BEGIN(pt); while(1) { PT_YIELD_TIME_msec(10); // // test by circle draw // tft_fillCircle(25, 25, 15, ILI9341_CYAN); // touchscreen's current location data struct TSPoint p; p.x = 0; // x-range: 120-935 p.y = 0; // y-range: 152-880 p.z = 0; // assuming a press and not noise if p.z >= 40. getPoint(&p); p.z=abs(p.z); //Debounce Code switch(pushState){ case NOPUSH: if(p.z >= 40){ pushState = MAYBEPUSH; } else pushState = NOPUSH; break; case MAYBEPUSH: if(p.z >= 40){ pushState = PUSHED; x = (p.x-120)*2/5; y = (p.y-152)/3; if ( isStart(x, y) ) { start=true; } else if (playing) { if (!playerSet) { selectedPlayer = playerSelection(x,y); playerSet = true; playerChanged=true; } if (sendButtonPushed(x,y) && playerSet==true){ send = true; } else if ( clearButtonPushed(x,y) ) { clear = true; } else if ( resetButtonPushed(x,y) ) { reset = true; } int scoreChange = scoreButtons(x,y); if (scoreChange != 0) { if ( (score + scoreChange) < -999 ) { score = -999; } else if ( (score + scoreChange) > 999 ) { score = 999; } else { score += scoreChange; } updateScore = true; } //else {updateScore = false; } } } else pushState = NOPUSH; break; case PUSHED: if(p.z >= 40){ pushState = PUSHED; } else pushState = MAYBENOPUSH; break; case MAYBENOPUSH: if(p.z >= 40){ pushState = PUSHED; } else { pushState = NOPUSH; send = false; clear = false; updateScore = false; } break; default: pushState = NOPUSH; break; }//end case } // END WHILE(1) PT_END(pt); } // thread /* * Main method */ void main(void) { SYSTEMConfigPerformance(PBCLK); ANSELA = 0; ANSELB = 0; CM1CON = 0; CM2CON = 0; // === config threads ========== PT_setup(); // init the threads // PT_INIT(&pt_input); // PT_INIT(&pt_read); // PT_INIT(&pt_clear); PT_INIT(&pt_screen); PT_INIT(&pt_touch); // init the display tft_init_hw(); tft_begin(); tft_fillScreen(ILI9341_BLACK); //240x320 vertical display tft_setRotation(3); // Use tft_setRotation(1) for 320x240 // draw a send button tft_fillRoundRect(250, 10, 60, 40, 10, ILI9341_YELLOW); tft_setCursor(255, 20); tft_setTextColor(ILI9341_BLACK); tft_setTextSize(2); tft_writeString("Send"); // draw a clear button tft_fillRoundRect(250, 190, 62, 40, 10, ILI9341_YELLOW); tft_setCursor(252, 200); tft_setTextColor(ILI9341_BLACK); tft_setTextSize(2); tft_writeString("Clear"); // draw a reset button tft_fillRoundRect(10, 190, 62, 40, 10, ILI9341_YELLOW); tft_setCursor(12, 200); tft_setTextColor(ILI9341_BLACK); tft_setTextSize(2); tft_writeString("Reset"); // draw Scoring settings // hundreds place tft_fillTriangle( 50, 80, 110, 80, 80, 50, ILI9341_GREEN); tft_fillTriangle( 50, 160, 110, 160, 80, 190, ILI9341_RED); // tens place tft_fillTriangle( 120, 80, 180, 80, 150, 50, ILI9341_GREEN); tft_fillTriangle( 120, 160, 180, 160, 150, 190, ILI9341_RED); // ones place tft_fillTriangle( 190, 80, 250, 80, 220, 50, ILI9341_GREEN); tft_fillTriangle( 190, 160, 250, 160, 220, 190, ILI9341_RED); // draw player selection buttons tft_fillCircle(25, 25, 15, ILI9341_ORANGE); tft_setCursor(18, 15); tft_setTextColor(ILI9341_WHITE); tft_setTextSize(3); tft_writeString("1"); tft_fillCircle(75, 25, 15, ILI9341_RED); tft_setCursor(68, 15); tft_setTextColor(ILI9341_WHITE); tft_setTextSize(3); tft_writeString("2"); //disable JTAG mJTAGPortEnable(0); TRISACLR = 1; configureADC(); // UARTSetFifoMode(UART2, UART_INTERRUPT_ON_RX_NOT_EMPTY); // enable IC interrupt INTEnableSystemMultiVectoredInt(); mPORTBSetPinsDigitalOut(BIT_15); // UART Directive printf("Enter Commands Below:\n"); //reset BLE chip mPORTBSetBits(BIT_15); delay(2500); mPORTBClearBits(BIT_15); delay(2500); // set up BLE chip biscuit_central_init(); delay(5000); printf("\nplayer1"); biscuit_central_connect(player1_address); // delay(50000); // biscuit_central_disconnect(PLAYER1); delay(40000); printf("\nplayer2"); biscuit_central_connect(player2_address); // delay(50000); // biscuit_central_disconnect(PLAYER2); // delay(40000); printf("\nplayer3"); // biscuit_central_connect(player3_address); // delay(50000); // biscuit_central_disconnect(PLAYER3); delay(40000); biscuit_central_enable_notification(PLAYER1); delay(2500); biscuit_central_enable_notification(PLAYER2); delay(2500); // biscuit_central_enable_notification(PLAYER3); // delay(2500); // display start button tft_fillRoundRect(120, 100, 80, 40, 10, ILI9341_GREENYELLOW); tft_setCursor(128, 112); tft_setTextColor(ILI9341_DARKGREEN); tft_setTextSize(2); tft_writeString("START!"); // round-robin scheduler for threads while (1){ PT_SCHEDULE(protothread_touch(&pt_touch)); PT_SCHEDULE(protothread_screen(&pt_screen)); // PT_SCHEDULE(protothread_read(&pt_read)); // PT_SCHEDULE(protothread_clear(&pt_clear)); } }