// This thread blinks a circle on the display every second as a heartbeat static PT_THREAD(protothread_blink(struct pt *pt)) { PT_BEGIN(pt); while(1) { //draw circle tft_fillCircle(xc, yc, 4, ILI9340_GREEN); //yield time 1 second PT_YIELD_TIME_msec(500); //erase circle tft_fillCircle(xc, yc, 4, ILI9340_BLACK); //yield time 1 second PT_YIELD_TIME_msec(500); } PT_END(pt); }
//method to remove a ball from the linked list and attach void deleteBall(ball *delete_this){ if(iterator->next != NULL) iterator = iterator->next; if(current_balls == 1) { initial_ball = NULL; end_ball = NULL; } //if we need to delete initial ball else if (initial_ball == delete_this){ initial_ball = delete_this -> next; initial_ball->prev = NULL; } //if we need to delete end ball else if (end_ball == delete_this){ end_ball = delete_this -> prev; end_ball->next = NULL; } //if it's a middle ball else{ (delete_this->next)->prev = delete_this->prev; (delete_this->prev)->next = delete_this->next; } tft_fillCircle(fix2int16(delete_this->xc), fix2int16(delete_this->yc), RADIUS, ILI9340_BLACK); free(delete_this); delete_this = NULL; current_balls--; }//function deleteBall
//==================== Calculate ===================== // static PT_THREAD (protothread_calculate (struct pt *pt)) { PT_BEGIN(pt); while(1) { PT_YIELD_TIME_msec(refreshRate); struct Ball *ti = head; struct Ball *tj = head; while(ti !=NULL){ //Calculates the collisions between every ball while(tj != NULL) { signed short rij_x = ti->xpos - tj->xpos; signed short rij_y = ti->ypos - tj->ypos; signed short mag_rij = pow(rij_x,2) + pow(rij_y,2); //Checks if ti and tj are not pointing to the same ball, //If they close enough for a collision and there is no collision //delay. if(ti != tj && ti->delay + tj->delay == 0 && mag_rij < 4*pow(ballradius,2)) { signed short vij_x = ti->xvel - tj->xvel; signed short vij_y = ti->yvel - tj->yvel; signed short temp = pow(2*pow(ballradius,2),2); signed short deltaVi_x = -1*(rij_x * (rij_x * vij_x+ rij_y*vij_y))/temp; signed short deltaVi_y = -1*(rij_y * (rij_x * vij_x+ rij_y*vij_y))/temp; //Updates the velocity ti->xvel = ti->xvel + deltaVi_x; ti->yvel = ti->yvel + deltaVi_y; tj->xvel = tj->xvel - deltaVi_x; tj->yvel = tj->yvel - deltaVi_y; ti->delay = delay_master; tj->delay = delay_master; collisions++; } tj = tj->b; } //"Clears" the image of the last ball tft_fillCircle(ti->xpos,ti->ypos,ballradius,ILI9340_BLACK); //Updates the new position of the ball ti->xpos = ti->xpos + ti->xvel * refreshRate/10; ti->ypos = ti->ypos + ti->yvel * refreshRate/10; //checks for wall collisions if(ti->xpos > 240 || ti->xpos < 0) ti->xvel = -1*ti->xvel; if(ti->ypos > 320 || ti->ypos < 0) ti->yvel = -1*ti->yvel; //Decrement the collide delay if(ti->delay > 0) ti->delay = ti->delay -1; ti = ti->b; tj = head; } } PT_END(pt); }
// === Animation Thread ============================================= // move a disk static PT_THREAD (protothread_anim(struct pt *pt)) { PT_BEGIN(pt); static int xc=10, yc=150, vxc=2, vyc=0; while(1) { // yield time 1 second PT_YIELD_TIME_msec(32); // erase disk tft_fillCircle(xc, yc, 4, ILI9340_BLACK); //x, y, radius, color // compute new position xc = xc + vxc; if (xc<5 || xc>235) vxc = -vxc; // draw disk tft_fillCircle(xc, yc, 4, ILI9340_GREEN); //x, y, radius, color // NEVER exit while } // END WHILE(1) PT_END(pt); } // animation thread
//======================= Refresh ========================= // static PT_THREAD (protothread_refresh(struct pt *pt)) { PT_BEGIN(pt); while(1) { PT_YIELD_TIME_msec(10); struct Ball *ti = head; while(ti != NULL){ tft_fillCircle(ti->xpos, ti->ypos, ballradius, ILI9340_WHITE); ti = ti->b; } } PT_END(pt); } // blink
// === Animation Thread ============================================= static PT_THREAD (protothread_anim_balls(struct pt *pt)) { PT_BEGIN(pt); while(1) { PT_YIELD_TIME_msec(20); iterator = initial_ball; while(iterator != NULL) { iterator2 = iterator->next; tft_fillCircle(fix2int16(iterator->xc), fix2int16(iterator->yc), RADIUS, ILI9340_BLACK); (iterator->xc) = (iterator->xc) + multfix16((iterator->vxc), drag); (iterator->yc) = (iterator->yc) + multfix16((iterator->vyc), drag); tft_fillCircle(fix2int16(iterator->xc), fix2int16(iterator->yc), RADIUS, ILI9340_WHITE); while(iterator2 != NULL) { if (balls_collide(iterator, iterator2) && (iterator->hit_counter <= 0) && (iterator2->hit_counter <= 0)) computeVelocityChange(iterator, iterator2); else if (balls_collide(iterator, iterator2)) { iterator->hit_counter = COUNTER; iterator2->hit_counter = COUNTER; } else{ iterator->hit_counter--; iterator2->hit_counter--; } iterator2 = iterator2->next; } // If the ball hits the paddle if ((myPaddle->xc+DIAMETER >= fix2int16(iterator->xc)) && (myPaddle->yc <= fix2int16(iterator->yc)) && ((myPaddle->yc+PADDLE_LEN) >= fix2int16(iterator->yc))){ iterator->vxc = -(iterator->vxc); iterator->vyc = iterator->vyc + multfix16(int2fix16(myPaddle->vyc),pdrag); //DmaChnSetTxfer(dmaChn, sine_table2, (void*)&CVRCON, sizeof(sine_table2), 1, 1); //DmaChnEnable(dmaChn); //PT_YIELD_TIME_msec(2); //DmaChnDisable(dmaChn); } // Else the ball went off the right edge else if (myPaddle->xc+DIAMETER >= fix2int16(iterator->xc)) { DmaChnSetTxfer(dmaChn, ball_scored, (void*)&CVRCON, sizeof(ball_scored), 1, 1); DmaChnEnable(dmaChn); PT_YIELD_TIME_msec(2); DmaChnDisable(dmaChn); deleteBall(iterator); score--; } // Calculate top bin else if ((iterator->xc) <= int2fix16(250+2) && iterator->xc >= int2fix16(175-2) && iterator->yc <= int2fix16(25+9)) { deleteBall(iterator); score++;} // Calculate bottom bin else if ((iterator->xc) <= int2fix16(250+2) && iterator->xc >= int2fix16(175-2) && iterator->yc >= int2fix16(233-2)) { deleteBall(iterator); score++;} // Bounce off right wall else if ((iterator->xc) >= int2fix16(315)) (iterator->vxc) = -(iterator->vxc); // Bounce off top or bottom wall else if ((iterator->yc) <= int2fix16(25) ||(iterator->yc) >= int2fix16(233)) (iterator->vyc) = -(iterator->vyc); iterator = iterator->next; } } // END WHILE(1) PT_END(pt); } // animation thread
void menu(void) { uint16_t x,y,z; while (1) { switch (selection((const char**)menu_table,10)) { case 0: #ifdef MT9D111 setRes(QVGA); setColor(RGB565); MT9D111Refresh(); editRegs(0); #else setColor(RGB565); setRes(QVGA); editRegs(); #endif break; case 1: #ifdef MT9D111 setRes(QVGA); setColor(RGB565); MT9D111Refresh(); editRegs(1); #else #ifdef ov7740 setmatrix(selection((const char**)maxtrix_table,2)); #else setmatrix(selection((const char**)maxtrix_table,3)); #endif tft_setOrientation(1); capImg(); tft_setDisplayDirect(DOWN2UP); #endif break; case 2: #ifdef ov7670 initCam(0); #else initCam(); #endif break; #ifndef MT9D111 case 3: //compare matrices tft_setOrientation(1); do { getPoint(&x,&y,&z); uint8_t a; #ifdef ov7670 for (a=0; a<3; a++) { #elif defined ov7740 for (a=0; a<2; a++) { #endif setmatrix(a); capImg(); } } while (z < 10); tft_setDisplayDirect(DOWN2UP); break; #endif case 4: setColor(RGB565); setRes(QQVGA); #ifdef MT9D111 MT9D111Refresh(); #endif do { getPoint(&x,&y,&z); tft_setOrientation(1); capImgqqvga(160); tft_setDisplayDirect(DOWN2UP); } while(z<10); setRes(QVGA); break; case 5: #ifdef ov7670 setColor(RGB565); #endif gammaEdit(); break; case 6: //File browser //start by listing files #ifdef haveSDcard browserSD(); #else tft_drawStringP(PSTR("No SD card"),16,320,3,WHITE); _delay_ms(666); #endif break; case 7: #ifdef ov7670 { uint8_t pick=selection((const char**)wb_table,7);//registers from http://thinksmallthings.wordpress.com/2012/10/25/white-balance-control-with-ov7670/ if(pick==1||pick==2) { wrReg(0x13, 0xE7); wrReg(0x6F, 0x9E|(pick&1)); } else { wrReg(0x13, 0xE5); switch(pick) { case 2: wrReg(0x01, 0x5A); wrReg(0x02, 0x5C); break; case 3: wrReg(0x01, 0x58); wrReg(0x02, 0x60); break; case 4: wrReg(0x01, 0x84); wrReg(0x02, 0x4C); break; case 5: wrReg(0x01, 0x96); wrReg(0x02, 0x40); break; } } tft_setOrientation(1); setRes(QVGA); setColor(RGB565); capImg(); tft_setDisplayDirect(DOWN2UP); } #endif break; case 8: #ifdef ov7670 wrReg(0x1e,rdReg(0x1e)&(~(1<<5))&(~(1<<4))); #endif { #ifdef MT9D111 uint8_t reso=selection((const char**)res_tab,4); #else uint8_t reso=selection((const char**)res_tab,3); #endif #ifdef MT9D111 wrReg16(0xF0,2);//page 2 wrReg16(0x0D,0); setColor(YUV422); #endif switch(reso) { case 0: #ifdef ov7670 wrReg(REG_COM7, COM7_BAYER); // BGBGBG... GRGRGR... #elif defined MT9D111 //setup jpeg MT9D111JPegCapture(); #endif break; case 1: #ifdef MT9D111 setRes(SVGA); #else setRes(QVGA); setColor(YUV422); #endif break; #ifdef MT9D111 case 2: setRes(QVGA); break; #endif default: goto theEnd; break; } #ifdef ov7670 _delay_ms(200); if(reso) wrReg(0x11,1); else wrReg(0x11,2); #endif tft_setOrientation(1); do { #ifdef MT9D111 switch(reso) { case 0: { uint32_t jpgSize=capJpeg(); serialWrB('R'); serialWrB('D'); serialWrB('Y'); uint16_t w; uint8_t h=0; serialWrB(jpgSize&255); serialWrB(jpgSize>>8); serialWrB(jpgSize>>16); serialWrB(jpgSize>>24); while(jpgSize) { if(jpgSize>=640) { for (w=0; w<320; ++w) { tft_setXY(h,w); BSend(); } ++h; jpgSize-=640; } else { for(w=0; w<jpgSize/2; ++w) { tft_setXY(h,w); BSend(); } if(jpgSize&1) { tft_setXY(h,w); uint16_t res=tft_readRegister(0x22); serialWrB(res>>8); } jpgSize=0; } } } break; case 1: capImgPC(); break; case 2: capImgPCqvga(); break; } #else if(reso) capImgPCqvga(); else capImgPC(); #endif getPoint(&x,&y,&z); } while(z<10); theEnd: tft_setDisplayDirect(DOWN2UP); } break; case 9: switch(selection((const char**)menu_tablep2,3)) { case 0: { tft_drawImage_P(exit_icon,32,32,0,0); uint16_t x1,y1; do { getPoint(&x,&y,&z); } while(z<10); if((y<=32)&&(x<=32)) break; tft_fillCircle(x,y,4,WHITE); while(1) { x1=x; y1=y; do { getPoint(&x,&y,&z); } while(z<10); tft_fillRectangle(224,320,16,36,BLACK); tft_fillCircle(x1,y1,4,BLACK); tft_fillCircle(x,y,4,WHITE); if((y<=32)&&(x<=32)) break; char temp[6]; utoa(x,temp,10); tft_drawString(temp,224,320,1,WHITE); utoa(y,temp,10); tft_drawString(temp,232,320,1,WHITE); } } break; case 1: //time lapse #ifdef MT9D111 //MT9D111Refresh(); //Since This is a time lapse we want to be in "video" mode MT9D111JPegCapture(); /*do{ _delay_ms(10); wrReg16(0xC6,(1<<15)|(1<<13)|(1<<8)|4); }while(rdReg16(0xC8)<4); waitStateMT9D111(3);*/ #endif #ifdef haveSDcard { char buf[24]; uint16_t imgc=0; tft_setOrientation(1); do { FIL Fo; #ifdef MT9D111 uint32_t jpgSize=capJpeg(); #else capImg(); #endif utoa(imgc,buf,10); #ifdef MT9D111 strcat(buf,".JPG"); #else strcat(buf,".RAW"); #endif f_open(&Fo,buf,FA_WRITE|FA_CREATE_ALWAYS); ++imgc; UINT written; uint16_t w; uint8_t h; uint16_t cpybuf[320]; #ifdef MT9D111 h=0; uint8_t * cpyptr=cpybuf; for(w=0; w<619; ++w) *cpyptr++=pgm_read_byte_near(jpegHeader+w); f_write(&Fo,cpybuf,619,&written); while(jpgSize) { if(jpgSize>=640) { for (w=0; w<320; ++w) { tft_setXY(h,w); cpybuf[w]=__builtin_bswap16(tft_readRegister(0x22));//Either bytes need to be swapped or a byte is being missed } f_write(&Fo,cpybuf,640,&written); ++h; jpgSize-=640; } else { for(w=0; w<jpgSize/2; ++w) { tft_setXY(h,w); cpybuf[w]=__builtin_bswap16(tft_readRegister(0x22)); } f_write(&Fo,cpybuf,jpgSize,&written); if(jpgSize&1) { tft_setXY(h,w); cpybuf[w]=tft_readRegister(0x22); f_write(&Fo,&cpybuf[w],1,&written); } jpgSize=0; } } cpybuf[0]=0xFFD9; f_write(&Fo,cpybuf,2,&written); #else for (h=0; h<240; ++h) { for (w=0; w<320; ++w) { tft_setXY(h,w); cpybuf[w]=tft_readRegister(0x22); } f_write(&Fo,cpybuf,640,&written); } #endif f_close(&Fo); getPoint(&x,&y,&z); } while(z<10); tft_setDisplayDirect(DOWN2UP); #ifdef MT9D111 MT9D111DoPreview(); #endif } #else tft_drawStringP(PSTR("No SD card"),16,320,3,WHITE); _delay_ms(666); #endif break; case 2: //previous page break; } break; } } }
//======================= Refresh ========================= // //Does Ball calculations and Draws the necessary elements on the screen static PT_THREAD (protothread_refresh(struct pt *pt)) { PT_BEGIN(pt); PT_YIELD_TIME_msec(100); //waits for the scoreboard to be set up while(1) { while (timeElapsed <=60) { PT_YIELD_TIME_msec(10); DmaChnDisable(dmaChn); DmaChnDisable(dmaChn2); //Generates a new ball at a given interval if(ballgen >= 10) { int troll1 = -((rand()) % 2)-1; int troll2 = ((rand()) % 6) - 3; struct Ball *temp = Ball_create(320,120,troll1,troll2,(numBalls+1)*500,0,NULL); temp->b = head; head = temp; ballgen = 0; numBalls++; } else ballgen ++; //collision calculations struct Ball *ti = head; struct Ball *tj = NULL; if(ti != NULL) tj = ti->b; while(ti !=NULL){ //Calculates the collisions between every ball while(tj != NULL) { int rij_x = ti->xpos - tj->xpos; int rij_y = ti->ypos - tj->ypos; int mag_rij = pow(rij_x,2) + pow(rij_y,2); //Checks if ti and tj are not pointing to the same ball, //If they close enough for a collision and there is no collision //delay. if( ti->delay + tj->delay == 0 && mag_rij < dist) { int vij_x = ti->xvel - tj->xvel; int vij_y = ti->yvel - tj->yvel; if (mag_rij==0) { mag_rij=dist; } int deltaVi_x = (int)((-1*(rij_x) * ((((rij_x * vij_x)+ (rij_y*vij_y)) << 7)/mag_rij)) >> 7); int deltaVi_y = (int)((-1*(rij_y) * ((((rij_x * vij_x)+ (rij_y*vij_y)) << 7)/mag_rij)) >> 7); /* tft_fillRoundRect(0,30, 320, 14, 1, ILI9340_BLACK);// x,y,w,h,radius,color tft_setCursor(0, 30); tft_setTextColor(ILI9340_WHITE); tft_setTextSize(2); sprintf(buffer,"%d:%d", (-1*(rij_x)/128 * (128*((rij_x * vij_x)+ (rij_y*vij_y))/mag_rij)), mag_rij); tft_writeString(buffer); */ //Updates the velocity ti->xvel = ti->xvel + deltaVi_x; ti->yvel = ti->yvel + deltaVi_y; tj->xvel = tj->xvel - deltaVi_x; tj->yvel = tj->yvel - deltaVi_y; ti->delay = delay_master; tj->delay = delay_master; } tj = tj->b; } //checks for wall collisions if(ti->xpos >= 320*scale || ti->xpos <= 0) ti->xvel = -1*ti->xvel; if(ti->ypos >= 240*scale || ti->ypos <= 35*scale) { ti->yvel = -1*ti->yvel; if (ti->xpos > 120*scale && ti->xpos < 200*scale) { //check for catch bin ti->delay=-1; //set to -1 to indicate +1 point } } //calculates the drag if(ti->xvel > 0) ti->xvel = ti->xvel - ti->xvel/drag; else ti->xvel = ti->xvel + ti->xvel/drag; if(ti->yvel > 0) ti->yvel = ti->yvel - ti->yvel/drag; else ti->yvel = ti->yvel - ti->yvel/drag; // Check for paddle Collisions if(abs(paddle_xpos-ti->xpos/scale) <= ballradius && ti->delay == 0) if(ti->ypos/scale > paddle_ypos - half_paddle_length && ti->ypos/scale < paddle_ypos + half_paddle_length) { ti->xvel = -1*ti->xvel; ti->yvel = ti->yvel + paddle_drag*paddle_v; ti->delay=delay_master; } //Decrement the collide delay if(ti->delay > 0) ti->delay = ti->delay -1; //iterates through the next set ti = ti->b; if(ti != NULL) tj = ti->b; //removes the last element if the limit is reached if(numBalls > maxBalls && tj->b == NULL) { tft_fillCircle(tj->xpos/scale,tj->ypos/scale,ballradius,ILI9340_BLACK); //erases from the screen ti->b = NULL; numBalls--; score++; //free(tj); } } // Calculates position of the paddle and draw //TODO: Calculate paddle position tft_drawLine(paddle_xpos,paddle_ypos - half_paddle_length, paddle_xpos, paddle_ypos + half_paddle_length, ILI9340_BLACK); paddle_v=paddle_ypos; paddle_ypos=(adc_9*240)/1023; paddle_v=paddle_ypos-paddle_v; tft_drawLine(paddle_xpos,paddle_ypos - half_paddle_length, paddle_xpos, paddle_ypos + half_paddle_length, ILI9340_WHITE); // Now it calculates the new position ti = head; tj = head; while(ti != NULL){ //"Clears" the image of the last ball tft_fillCircle(ti->xpos/scale,ti->ypos/scale,ballradius,ILI9340_BLACK); //Updates the new position of the ball ti->xpos = ti->xpos + ti->xvel; ti->ypos = ti->ypos + ti->yvel; //ensures the positions are within bounds //If the pos is less than 0 then we remove it //delay must also not be -1 (ie >=0) if(ti->xpos > paddle_xpos && ti->delay != -1) { if(ti->xpos > 320*scale) ti->xpos = 320*scale; if(ti->ypos > 240*scale) ti->ypos = 240*scale; else if(ti->ypos < 35*scale) ti->ypos = 35*scale; if(ti->delay > 0) tft_fillCircle(ti->xpos/scale, ti->ypos/scale, ballradius, ILI9340_WHITE); else tft_fillCircle(ti->xpos/scale, ti->ypos/scale, ballradius, ti->color); } else { //REMOVES THE BALL IF IT CROSSES THE BOUNDARY if (ti->delay==-1) { //check if went into catch bins score++; DmaChnEnable(dmaChn2); } else { DmaChnEnable(dmaChn); score--; } if(ti == head) head = head->b; else tj->b = ti->b; numBalls--; //free(ti); } tj = ti;//what does this do? ti = ti->b; } frames ++; } tft_fillRoundRect(0,35, 320, 205, 1, ILI9340_BLACK);// x,y,w,h,radius,color DmaChnDisable(dmaChn); DmaChnDisable(dmaChn2); DmaChnEnable(dmaChn3); while (1) { tft_setCursor(20, 120); tft_setTextColor(ILI9340_WHITE); tft_setTextSize(4); sprintf(buffer,"Game Over!"); tft_writeString(buffer); } }