gb-dtmf.c (15108B)
1/* ---------------------------------------- */ 2/* GB-DTMF Ver1.0 */ 3/* by */ 4/* Osamu Ohashi */ 5/* ---------------------------------------- */ 6 7#include <gb/gb.h> 8#include <stdint.h> 9#include <stdio.h> 10#include <string.h> 11 12/* BG data */ 13#include "frm_lcd.c" /* Back ground pattern */ 14#include "brk_btn.c" /* button image when broken */ 15#include "prs_btn.c" /* button image when pressed */ 16 17#include "dtmf_lcd.c" /* LCD characters */ 18 19/* Sprite data */ 20#include "key_num.c" /* Sprite pattern for each key pad */ 21#include "cursor.c" /* cursor pattern */ 22 23/* 24 usage of BG data 25 file name number of BG type of matrix aount 26 ------------------------------------------------- 27 frame_lcd.c 9 8 x 8 9 28 break_btn.c 9 8 x 8 9 29 press_btn.c 9 8 x 8 9 30 dtmf_lcd.c 25 8 x 16 50 31 ------------------------------------------------ 32 total 77 33 34 35 usage of OBJ data 36 file name number of obj type of matrix amount 37 -------------------------------------------------- 38 key_num.c 23 8 x 8 23 39 cursor.c 2 16 x 16 8 40 -------------------------------------------------- 41 total 31 42*/ 43 44 45/* display */ 46#define TITLE " GB-DTMF BY 05AMU " 47 48#define OFFSET 27U 49#define KEY_STEP 24U /* Key matrix size as 24 x 24 */ 50#define START_CURSOR_X 24U /* CURSOR position */ 51#define START_CURSOR_Y 72U 52 53#define LCD_X 1U /* start position of X */ 54#define LCD_Y 2U /* start position of Y */ 55#define LCD_WIDTH 18U /* Horizontal size of LCD */ 56#define LCD_HIGHT 2U /* Vertical Size of LCD */ 57 58 59#define ON 1 60#define OFF 0 61 62/* DTMF */ 63#define DTMF_ON 100UL /* Tone on time */ 64#define DTMF_OFF 100UL /* Tone off time */ 65 66#define MAX_DTMF 30 /* Maximum length of DTMF strings */ 67 68/* 69 Frequency setting 70*/ 71/* 72 We have to calculate the frequency as following formula 73 74 DTMF has two set frequency, we have to decide Row & Column 75 with each digit('0','1','2'...) 76*/ 77 78#define C1 0x94U /* 1209Hz, 1213Hz */ 79#define C2 0x9EU /* 1336Hz, 1337Hz */ 80#define C3 0xA7U /* 1477Hz, 1472Hz */ 81#define C4 0xB0U /* 1633Hz, 1638Hz */ 82 83#define R1 0x44U /* 697Hz, 697Hz */ 84#define R2 0x56U /* 770Hz, 770Hz */ 85#define R3 0x66U /* 852Hz, 851Hz */ 86#define R4 0x75U /* 941Hz, 942Hz */ 87 88const unsigned char row[4] = {R1,R2,R3,R4}; /* DTMF frequency strage of Row */ 89const unsigned char col[4] = {C1,C2,C3,C4}; /* DTMF frequency strage of Col */ 90 91/* It is possible to set up initial screen by each BG data. */ 92const unsigned char dtmf_tile[] = { 93 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 94 95 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 96 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 97 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 98 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 99 100 4, 9,10,11, 9,10,11, 9,10,11, 9,10,11, 4, 9,10,11, 9,10,11, 101 4,12,13,14,12,13,14,12,13,14,12,13,14, 4,12,13,14,12,13,14, 102 4,15,16,17,15,16,17,15,16,17,15,16,17, 4,15,16,17,15,16,17, 103 104 4, 9,10,11, 9,10,11, 9,10,11, 9,10,11, 4, 9,10,11, 9,10,11, 105 4,12,13,14,12,13,14,12,13,14,12,13,14, 4,12,13,14,12,13,14, 106 4,15,16,17,15,16,17,15,16,17,15,16,17, 4,15,16,17,15,16,17, 107 108 4, 9,10,11, 9,10,11, 9,10,11, 9,10,11, 4, 9,10,11, 9,10,11, 109 4,12,13,14,12,13,14,12,13,14,12,13,14, 4,12,13,14,12,13,14, 110 4,15,16,17,15,16,17,15,16,17,15,16,17, 4,15,16,17,15,16,17, 111 112 4, 9,10,11, 9,10,11, 9,10,11, 9,10,11, 4, 9,10,10,10,10,11, 113 4,12,13,14,12,13,14,12,13,14,12,13,14, 4,12,13,13,13,13,14, 114 4,15,16,17,15,16,17,15,16,17,15,16,17, 4,15,16,16,16,16,17, 115 116 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 117}; 118 119/* 120 Button image 121 Normal buttons are created by 3tiles x 3tiles(24pixels x 24pixels) 122 Dialing button is created by 6tiles x 3tiles(48pixels x 24pixels) 123*/ 124const unsigned char break_tile[] = { 125 9,10,11, 126 12,13,14, 127 15,16,17 128}; 129 130const unsigned char dialing_break[] = { 131 9,10,10,10,10,11, 132 12,13,13,13,13,14, 133 15,16,16,16,16,17 134}; 135 136const unsigned char press_tile[] = { 137 18,19,20, 138 21,22,23, 139 24,25,26 140}; 141 142 143const unsigned char dialing_press[] = { 144 18,19,19,19,19,20, 145 21,22,22,22,22,23, 146 24,25,25,25,25,26 147}; 148 149/* 150 LCD image at initial & AC 151*/ 152const unsigned char init_disp[] = { 153 59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59, 154 60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60 155}; 156 157const char pad[4][6] = { /* DTMF Pad assign */ 158 {'1','2','3','A','%','P'}, 159 {'4','5','6','B','-','F'}, 160 {'7','8','9','C',',','?'}, 161 {'*','0','#','D','s','s'} 162}; 163 164unsigned char disp_tile[MAX_DTMF * 2]; 165 166/* 167 Initialize for sound registers 168 ch1, ch2 are used for this routine. 169*/ 170void init_dial() 171{ 172 173 NR52_REG = 0x83U; 174 NR51_REG = 0x00U; 175 NR50_REG = 0x77U; 176 177 NR24_REG = 0x87U; 178 NR22_REG = 0xffU; 179 NR21_REG = 0xbfU; 180 181 NR14_REG = 0x87U; 182 NR12_REG = 0xffU; 183 NR11_REG = 0xbfU; 184 NR10_REG = 0x04U; 185} 186 187/* sound engine for DTMF */ 188void dialtone(uint16_t dtmf_on, uint16_t dtmf_off, char str[20]) 189{ 190 uint8_t i = 0; 191 192 while(str[i]){ 193 switch(str[i]){ 194 case '1': 195 NR13_REG = R1; 196 NR23_REG = C1; 197 break; 198 case '2': 199 NR13_REG = R1; 200 NR23_REG = C2; 201 break; 202 case '3': 203 NR13_REG = R1; 204 NR23_REG = C3; 205 break; 206 case 'A': 207 case 'a': 208 NR13_REG = R1; 209 NR23_REG = C4; 210 break; 211 case '4': 212 NR13_REG = R2; 213 NR23_REG = C1; 214 break; 215 case '5': 216 NR13_REG = R2; 217 NR23_REG = C2; 218 break; 219 case '6': 220 NR13_REG = R2; 221 NR23_REG = C3; 222 break; 223 case 'B': 224 case 'b': 225 NR13_REG = R2; 226 NR23_REG = C4; 227 break; 228 case '7': 229 NR13_REG = R3; 230 NR23_REG = C1; 231 break; 232 case '8': 233 NR13_REG = R3; 234 NR23_REG = C2; 235 break; 236 case '9': 237 NR13_REG = R3; 238 NR23_REG = C3; 239 break; 240 case 'C': 241 case 'c': 242 NR13_REG = R3; 243 NR23_REG = C4; 244 break; 245 case '*': 246 NR13_REG = R4; 247 NR23_REG = C1; 248 break; 249 case '0': 250 NR13_REG = R4; 251 NR23_REG = C2; 252 break; 253 case '#': 254 NR13_REG = R4; 255 NR23_REG = C3; 256 break; 257 case 'D': 258 case 'd': 259 NR13_REG = R4; 260 NR23_REG = C4; 261 break; 262 case ',': 263 delay(dtmf_on); /* keep on */ 264 delay(dtmf_off); /* keep off */ 265 266 default: 267 NR51_REG = 0x00U; /* sound off */ 268 goto skip; 269 270 } 271 NR24_REG = 0x87U; /* ch2 tips */ 272 NR51_REG = 0x33U; /* sound on */ 273 delay(dtmf_on); /* keep on */ 274 275 NR51_REG = 0x00U; /* sound off */ 276 delay(dtmf_off); /* keep off */ 277 278 skip: 279 i++; 280 } 281} 282 283 284/* Display looks like 7-SEGMENT LED */ 285void disp_lcd(uint8_t len, char str[MAX_DTMF]) 286{ 287 uint8_t i,j; 288 289 j = len; 290 291 i=0; 292 while(str[i]){ 293 if(str[i] >= '0'||'9' <= str[i]){ 294 disp_tile[i] = OFFSET + (str[i] - '0') * 2; 295 disp_tile[i+j] = OFFSET + (str[i] - '0') * 2 + 1; 296 } 297 switch(str[i]){ 298 case 'A': 299 disp_tile[i] = OFFSET + 10 * 2; 300 disp_tile[i+j] = OFFSET + 10 * 2 + 1; 301 break; 302 case 'B': 303 disp_tile[i] = OFFSET + 11 * 2; 304 disp_tile[i+j] = OFFSET + 11 * 2 + 1; 305 break; 306 case 'C': 307 disp_tile[i] = OFFSET + 12 * 2; 308 disp_tile[i+j] = OFFSET + 12 * 2 + 1; 309 break; 310 case 'D': 311 disp_tile[i] = OFFSET + 13 * 2; 312 disp_tile[i+j] = OFFSET + 13 * 2 + 1; 313 break; 314 case '#': 315 disp_tile[i] = OFFSET + 14 * 2; 316 disp_tile[i+j] = OFFSET + 14 * 2 + 1; 317 break; 318 case '*': 319 disp_tile[i] = OFFSET + 15 * 2; 320 disp_tile[i+j] = OFFSET + 15 * 2 + 1; 321 break; 322 case ' ': 323 disp_tile[i] = OFFSET + 16 * 2; 324 disp_tile[i+j] = OFFSET + 16 * 2 + 1; 325 break; 326 case 'Y': 327 disp_tile[i] = OFFSET + 17 * 2; 328 disp_tile[i+j] = OFFSET + 17 * 2 + 1; 329 break; 330 case 'M': 331 disp_tile[i] = OFFSET + 18 * 2; 332 disp_tile[i+j] = OFFSET + 18 * 2 + 1; 333 break; 334 case 'U': 335 disp_tile[i] = OFFSET + 19 * 2; 336 disp_tile[i+j] = OFFSET + 19 * 2 + 1; 337 break; 338 case 'G': 339 disp_tile[i] = OFFSET + 20 * 2; 340 disp_tile[i+j] = OFFSET + 20 * 2 + 1; 341 break; 342 case '-': 343 disp_tile[i] = OFFSET + 21 * 2; 344 disp_tile[i+j] = OFFSET + 21 * 2 + 1; 345 break; 346 case 'T': 347 disp_tile[i] = OFFSET + 22 * 2; 348 disp_tile[i+j] = OFFSET + 22 * 2 + 1; 349 break; 350 case ',': 351 disp_tile[i] = OFFSET + 23 * 2; 352 disp_tile[i+j] = OFFSET + 23 * 2 + 1; 353 break; 354 case 'F': 355 disp_tile[i] = OFFSET + 24 * 2; 356 disp_tile[i+j] = OFFSET + 24 * 2 + 1; 357 break; 358 case 'S': 359 disp_tile[i] = OFFSET + ('5' - '0') * 2; 360 disp_tile[i+j] = OFFSET + ('5' - '0') * 2 + 1; 361 break; 362 } 363 i++; 364 } 365} 366 367/* clear display */ 368void clr_disp() 369{ 370 set_bkg_data(OFFSET, 50, dtmf_lcd); 371 set_bkg_tiles(LCD_X, LCD_Y, LCD_WIDTH, LCD_HIGHT, init_disp); 372} 373 374/* 375 CAUTION: Don't display the NULL code 376*/ 377void disp(const char *str) 378{ 379 uint8_t no, left_pos; 380 uint8_t i, start_ch, end_ch; 381 char work[MAX_DTMF]; 382 383 clr_disp(); 384 385 no = 0; 386 while(str[no]){ 387 no++; 388 } 389 390 if(no >= LCD_WIDTH){ 391 start_ch = no - LCD_WIDTH; 392 end_ch = LCD_WIDTH; 393 } 394 else{ 395 start_ch = 0; 396 end_ch = no; 397 } 398 for(i = 0;i < end_ch;i++){ 399 work[i] = str[i+start_ch]; 400 } 401 work[end_ch] = 0x00; 402 403 disp_lcd(end_ch, work); 404 405 left_pos = 19 - end_ch; 406 set_bkg_tiles(left_pos, 2, end_ch, LCD_HIGHT, disp_tile); 407} 408 409void press_button(uint8_t x, uint8_t y) 410{ 411 if(x <= 3 && y <= 3){ 412 set_bkg_tiles(x * 3 + 1, y * 3 + 5, 3, 3, press_tile); 413 } 414 if((x == 4 || x == 5) && (y <= 2)){ 415 set_bkg_tiles(x * 3 + 2, y * 3 + 5, 3, 3, press_tile); 416 } 417 if((x == 4 || x == 5) && (y == 3)){ 418 set_bkg_tiles(14, 14, 6, 3, dialing_press); 419 } 420} 421 422void break_button(uint8_t x, uint8_t y) 423{ 424 if(x <= 3 && y <= 3){ 425 set_bkg_tiles(x * 3 + 1, y * 3 + 5, 3, 3, break_tile); 426 } 427 if((x == 4 || x == 5) && (y <= 2)){ 428 set_bkg_tiles(x * 3 + 2, y * 3 + 5, 3, 3, break_tile); 429 } 430 if((x == 4 || x == 5) && (y == 3)){ 431 set_bkg_tiles(14, 14, 6, 3, dialing_break); 432 } 433} 434 435 436void init_key() 437{ 438 uint8_t key_x, key_y, i; 439 440 /* To make numeric KeyPad */ 441 set_sprite_data(0, 24, key_num); 442 443 /* key pad 1 - 3 */ 444 key_y = KEY_STEP + 40; 445 for(i = 1;i <= 3;i++){ 446 key_x = i * KEY_STEP; 447 set_sprite_tile(i, i); 448 move_sprite(i, key_x, key_y); 449 } 450 451 /* key pad 4 - 6 */ 452 key_y = KEY_STEP * 2 + 40; 453 for(i = 4;i <= 6;i++){ 454 key_x = (i - 3) * KEY_STEP; 455 set_sprite_tile(i, i); 456 move_sprite(i, key_x, key_y); 457 } 458 459 /* key pad 7 - 9 */ 460 key_y = KEY_STEP * 3 + 40; 461 for(i = 7;i <= 9;i++){ 462 key_x = (i - 6) * KEY_STEP; 463 set_sprite_tile(i, i); 464 move_sprite(i, key_x, key_y); 465 } 466 467 /* key pad 'A' - 'D' */ 468 key_x = KEY_STEP * 4; 469 for(i = 0;i <= 3;i++){ 470 key_y = (i+1) * KEY_STEP + 40; 471 set_sprite_tile(i+10, i+10); 472 move_sprite(i+10, key_x, key_y); 473 } 474 475 /* key pad '*', '0', '#' */ 476 set_sprite_tile(15, 15); 477 move_sprite(15, KEY_STEP * 1, KEY_STEP * 4 + 40U); 478 set_sprite_tile(0, 0); 479 move_sprite(0, KEY_STEP * 2, KEY_STEP * 4 + 40U); 480 set_sprite_tile(14, 14); 481 move_sprite(14, KEY_STEP * 3, KEY_STEP * 4 + 40U); 482 483 /* func left */ 484 key_x = KEY_STEP * 5 + 8U; 485 for(i = 0;i <= 2;i++){ 486 key_y = (i+1) * KEY_STEP + 40; 487 set_sprite_tile(i+16, i+16); 488 move_sprite(i+16, key_x, key_y); 489 } 490 491 /* func right */ 492 key_x = KEY_STEP * 6 + 8U; 493 for(i = 0;i <= 2;i++){ 494 key_y = (i+1) * KEY_STEP + 40; 495 set_sprite_tile(i+19, i+19); 496 move_sprite(i+19, key_x, key_y); 497 } 498 499 /* dialing button */ 500 key_x = KEY_STEP * 5 + 20U; 501 key_y = KEY_STEP * 4 + 40U; 502 set_sprite_tile(22, 22); 503 move_sprite(22, key_x, key_y); 504} 505 506void init_background() 507{ 508 /* Initialize the background */ 509 set_bkg_data( 0, 9, frame_lcd); 510 set_bkg_data( 9, 9, break_btn); 511 set_bkg_data(18, 9, press_btn); 512 513 set_bkg_tiles(0, 0, 20, 18, dtmf_tile); 514} 515 516void init_cursor() 517{ 518 uint8_t i; 519 520 /* Setup the cursor data*/ 521 set_sprite_data(23, 8, cursor_data); 522 523 for(i = 23;i <= 30;i++){ 524 set_sprite_tile(i, i); 525 } 526} 527 528void move_cursor(uint8_t x, uint8_t y) 529{ 530 move_sprite(23, x, y); 531 move_sprite(24, x, y+8); 532 move_sprite(25, x+8, y); 533 move_sprite(26, x+8, y+8); 534} 535 536void main() 537{ 538 uint8_t key1, key2, i, j, pos_x, pos_y, ch_pos; 539 uint8_t non_flick = OFF; 540 uint16_t on_time, off_time; 541 542 char str[MAX_DTMF]; 543 char str_ms[10]; 544 545 /* PENDING: sdcc is broken and needs this to be initalised. */ 546 key2 = 0; 547 548 /* default dialling time setting */ 549 on_time = DTMF_ON; 550 off_time = DTMF_OFF; 551 552 disable_interrupts(); 553 554 SPRITES_8x8; /* sprites are 8x8 */ 555 556 init_dial(); 557 558 init_background(); 559 560 init_key(); 561 562 init_cursor(); 563 564 disp(TITLE); 565 566 SHOW_BKG; 567 SHOW_SPRITES; 568 DISPLAY_ON; 569 570 enable_interrupts(); 571 572 i = j = 0; 573 574 ch_pos = 0; 575 576 while(1) { 577 wait_vbl_done(); 578 key1 = joypad(); 579 580 if(key1 != key2){ 581 pos_x = i * KEY_STEP + START_CURSOR_X; 582 pos_y = j * KEY_STEP + START_CURSOR_Y; 583 move_cursor(pos_x, pos_y); 584 } 585 586 if(key2 & J_A){ 587 if(key1 & J_A){ 588 /* value set for each sound reg only numeric key pad*/ 589 if(i <= 3 && j <= 3){ 590 /* frequncy register set up for DTMF */ 591 NR13_REG = row[i]; 592 NR23_REG = col[j]; 593 NR24_REG = 0x87U; 594 595 /* sound output on */ 596 NR51_REG = 0x33U; 597 } 598 599 /* '?' button */ 600 /* appear the title during press A button */ 601 if(i == 5 && j == 0 && !non_flick){ 602 disp(TITLE); 603 non_flick = ON; 604 } 605 606 /* incremental button */ 607 /* decremental button */ 608 /* appear the delay during press A button */ 609 if(i == 5 && (j == 1 || j == 2) && !non_flick){ 610 sprintf(str_ms, "%u MS", on_time); 611 disp(str_ms); 612 non_flick = ON; 613 } 614 } 615 else{ 616 /* sound output off */ 617 NR51_REG = 0x00U; 618 619 break_button(i, j); 620 621 /* '?' button */ 622 /* incremental button */ 623 /* decremental button */ 624 /* return to normal display at release the A button */ 625 if(i == 5 && (j == 0 || j == 1 || j == 2)){ 626 non_flick = OFF; 627 if(ch_pos == 0) 628 clr_disp(); 629 else 630 disp(str); 631 } 632 } 633 } 634 else{ 635 if(key1 & J_A){ 636 /* button display handle */ 637 press_button(i, j); 638 639 /* numeric key pad handling */ 640 if(i <= 3 && j <= 3){ 641 /* string length check */ 642 if(ch_pos < MAX_DTMF-1){ 643 str[ch_pos] = pad[j][i]; 644 ch_pos++; 645 str[ch_pos] = 0x00; 646 disp(str); 647 } 648 } 649 650 /* ',' button */ 651 if(i == 4 && j == 2){ 652 /* string length check */ 653 if(ch_pos < MAX_DTMF-1){ 654 str[ch_pos] = pad[j][i]; 655 ch_pos++; 656 str[ch_pos] = 0x00; 657 disp(str); 658 } 659 } 660 661 /* all clear button */ 662 if(i == 4 && j == 0){ 663 ch_pos = 0x00; 664 strcpy(str,""); 665 clr_disp(); 666 } 667 668 /* delete button */ 669 if(i == 4 && j == 1){ 670 if(ch_pos > 0){ 671 ch_pos--; 672 str[ch_pos] = 0x00; 673 if(ch_pos == 0) 674 clr_disp(); 675 else 676 disp(str); 677 } 678 } 679 680 /* incremental button */ 681 if(i == 5 && j == 1){ 682 if(on_time >= DTMF_ON / 2){ 683 on_time = on_time - 10; 684 off_time = off_time - 10; 685 } 686 } 687 688 /* decremental button */ 689 if(i == 5 && j == 2){ 690 if(on_time <= DTMF_ON * 2){ 691 on_time = on_time + 10; 692 off_time = off_time + 10; 693 } 694 } 695 696 /* dialing button */ 697 if((i==4 || i==5) && j==3){ 698 dialtone(on_time, off_time, str); 699 } 700 } 701 } 702 if(!(key1 & J_A)){ 703 if((key1 & J_UP) && !(key2 & J_UP) && j > 0) 704 j--; 705 else if((key1 & J_DOWN) && !(key2 & J_DOWN) && j < 3) 706 j++; 707 708 if((key1 & J_LEFT) && !(key2 & J_LEFT) && i > 0) 709 i--; 710 else if((key1 & J_RIGHT) && !(key2 & J_RIGHT) && i < 5) 711 i++; 712 } 713 key2 = key1; 714 } 715}