gbdk-2020 | GameBoy Development Kit |
| download: https://git.y1.nz/archives/gbdk.tar.gz | |
| README | Files | Log | Refs | LICENSE |
gbdk-lib/examples/gb/gb-dtmf/gb-dtmf.c
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
88 const unsigned char row[4] = {R1,R2,R3,R4}; /* DTMF frequency strage of Row */
89 const 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. */
92 const 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 */
124 const unsigned char break_tile[] = {
125 9,10,11,
126 12,13,14,
127 15,16,17
128 };
129
130 const 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
136 const unsigned char press_tile[] = {
137 18,19,20,
138 21,22,23,
139 24,25,26
140 };
141
142
143 const 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 */
152 const 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
157 const 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
164 unsigned char disp_tile[MAX_DTMF * 2];
165
166 /*
167 Initialize for sound registers
168 ch1, ch2 are used for this routine.
169 */
170 void init_dial(void)
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 */
188 void 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 */
285 void 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 */
368 void clr_disp(void)
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 */
377 void 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
409 void 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
422 void 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
436 void init_key(void)
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
506 void init_background(void)
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
516 void init_cursor(void)
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
528 void 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
536 void main(void)
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 vsync();
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 }
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.