Better sound. Buzzing tone was caused by signed/unsigned mixture.
[firmerware] / src / function / develtest / echo.c
1 /* echo.c -- Sound I/O test program
2  *
3  * This file is part of 0cpm Firmerware.
4  *
5  * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
6  *
7  * 0cpm Firmerware is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation, version 3.
10  *
11  * 0cpm Firmerware is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20
21 /* This program will retrieve sound from the codec (sound chip), hold it for a bit,
22  * and send it back out.  When the phone is on-hook, sound communicates over the
23  * speakerphone function (if present).  When the phone is off-hook, sound
24  * communicates over the handset.
25  *
26  * From: Rick van Rein <rick@openfortress.nl>
27  */
28
29
30 #include <stdlib.h>
31 #include <stdint.h>
32 #include <stdarg.h>
33 #include <stdbool.h>
34
35 //TODO// test inclusion of bottom definitions
36 #define BOTTOM
37 #include <config.h>
38
39 #include <0cpm/kbd.h>
40 #include <0cpm/app.h>
41 #include <0cpm/cons.h>
42 #include <0cpm/show.h>
43 #include <0cpm/snd.h>
44 #include <0cpm/led.h>
45
46
47 volatile uint16_t tobeplayed   = 0;
48 volatile uint16_t toberecorded = 0;
49
50
51 timing_t top_timer_expiration (timing_t timeout) {
52         /* Keep the linker happy */ ;
53         return timeout;
54 }
55
56 void top_hook_update (bool offhook) {
57         if (offhook) {
58                 bottom_soundchannel_device (PHONE_CHANNEL_TELEPHONY, PHONE_SOUNDDEV_HANDSET);
59         } else {
60                 bottom_soundchannel_device (PHONE_CHANNEL_TELEPHONY, PHONE_SOUNDDEV_SPEAKER);
61         }
62 }
63
64 void top_network_online (void) {
65         /* Keep the linker happy */ ;
66 }
67
68 void top_network_offline (void) {
69         /* Keep the linker happy */ ;
70 }
71
72 void top_network_can_send (void) {
73         /* Keep the linker happy */ ;
74 }
75
76 void top_network_can_recv (void) {
77         /* Keep the linker happy */ ;
78 }
79
80 void top_button_press (buttonclass_t bcl, buttoncode_t cde) {
81         if (bcl != BUTCLS_FIXED_FUNCTION) {
82                 return;
83         }
84         switch (cde) {
85 #ifdef HAVE_BUTTON_UP
86         case HAVE_BUTTON_UP:
87                 bottom_soundchannel_setvolume (PHONE_CHANNEL_TELEPHONY,
88                         bottom_soundchannel_getvolume (PHONE_CHANNEL_TELEPHONY) + 1);
89                 break;
90 #endif
91 #ifdef HAVE_BUTTON_DOWN
92         case HAVE_BUTTON_DOWN:
93                 bottom_soundchannel_setvolume (PHONE_CHANNEL_TELEPHONY,
94                         bottom_soundchannel_getvolume (PHONE_CHANNEL_TELEPHONY) - 1);
95                 break;
96 #endif
97         default:
98                 break;
99         }
100 }
101
102 void top_button_release (void) {
103         /* Keep the linker happy */
104 }
105
106 uint16_t plyirqs = 0;
107 void top_can_play (uint16_t samples) {
108         tobeplayed = samples;
109         plyirqs++;
110 }
111
112 uint16_t recirqs = 0;
113 void top_can_record (uint16_t samples) {
114         toberecorded = samples;
115         recirqs++;
116 }
117
118
119 // #define top_main_sine_1khz  top_main
120 #define top_main_delay_1sec top_main
121
122
123 #ifdef CONFIG_FUNCTION_NETCONSOLE
124 uint8_t netinput [1000];
125 uint16_t netinputlen;
126 void nethandler_llconly (uint8_t *pkt, uint16_t pktlen);
127 #endif
128
129
130 /******** TOP_MAIN FOR A 1 KHZ SINE WAVE OUTPUT ********/
131
132 uint8_t sinewaveL8 [8] = {
133         0x00, 0x5a, 0x7f, 0x5a, 0x00, 0xa5, 0x80, 0xa5
134 };
135
136 uint16_t sinewaveL16 [8] = {
137         // 0x0000, 0x5a82, 0x7fff, 0x5a82, 0x0000, 0xa57e, 0x8001, 0xa57e
138         // 0x0000 + 32768, 0x5a82 + 32768, 0x7fff + 32768, 0x5a82 + 32768, 0x0000 + 32768, 0xa57e - 32768, 0x8001 - 32768, 0xa57e - 32768
139         0x0000, 0x2d41, 0x3fff, 0x2d41, 0x0000, 0xdabf, 0xc000, 0xdabf
140         // 0x0000, 0x002d, 0x0040, 0x002d, 0x0000, 0xffda, 0xffc0, 0xffda
141         // 4096+0x0000, 4096+0x05a8, 4096+0x07ff, 4096+0x05a8, 4096+0x0000, 4096+0xfa57, 4096+0xf801, 4096+0xfa57
142 };
143
144 void top_main_sine_1khz (void) {
145         uint16_t oldirqs = 0;
146 extern volatile uint16_t available_play;
147 extern volatile uint16_t available_record;
148 uint8_t l16ctr = 1;
149         top_hook_update (bottom_phone_is_offhook ());
150         bottom_critical_region_end ();
151         bottom_codec_play_samplerate (0, 8000);
152         bottom_codec_record_samplerate (0, 8000); // Both MUST be called for now
153         bottom_soundchannel_setvolume (PHONE_CHANNEL_TELEPHONY, 127);
154         bottom_show_fixed_msg (APP_LEVEL_ZERO, FIXMSG_RINGING); // TODO: Not really necessary
155         bottom_printf ("Playing 1 kHz tone to speaker or handset\n");
156         tobeplayed = 64;
157         while (true) {
158                 uint16_t newplayed = tobeplayed;
159                 uint16_t oldplayed = newplayed;
160                 if (oldirqs != plyirqs) {
161                         bottom_printf ("New playing IRQs detected; available_play=%d, available_record=%d\n", (intptr_t) available_play, (intptr_t) available_record);
162                         oldirqs = plyirqs;
163                 }
164 #if 0
165 if (SPCR2_1 & REGVAL_SPCR2_XRDY) { DXR1_1 = sinewaveL16 [l16ctr++]; if (l16ctr == 8) { l16ctr = 0; } }
166 { uint16_t _ = DRR1_1; }
167 #else
168                 while (newplayed >= 8) {
169                         bottom_codec_play (0, CODEC_L8, sinewaveL8, 8, 8);
170                         newplayed -= 8;
171                 }
172 #endif
173 #if 1
174                 if (oldplayed != newplayed) {
175                         bottom_printf ("available_play := %d\n", (intptr_t) available_play);
176                         // bottom_printf ("Playbuffer reduced from %d to %d\n", (intptr_t) oldplayed, (intptr_t) newplayed);
177                 }
178 #endif
179
180 #ifdef CONFIG_FUNCTION_NETCONSOLE
181                 // { uint32_t ctr = 10000; while (ctr--) ; }
182                 trysend ();
183                 // { uint32_t ctr = 10000; while (ctr--) ; }
184 bottom_led_set (LED_IDX_BACKLIGHT, 1);
185                 netinputlen = sizeof (netinput);
186                 if (bottom_network_recv (netinput, &netinputlen)) {
187                         nethandler_llconly (netinput, netinputlen);
188 bottom_led_set (LED_IDX_BACKLIGHT, 0);
189                         { uint32_t ctr = 10000; while (ctr--) ; }
190                 }
191 bottom_led_set (LED_IDX_BACKLIGHT, 0);
192                 trysend ();
193 #endif
194
195 #if defined NEED_KBD_SCANNER_BETWEEN_KEYS || defined NEED_KBD_SCANNER_DURING_KEYPRESS
196                 bottom_keyboard_scan ();
197 #endif
198
199 #if defined NEED_HOOK_SCANNER_WHEN_ONHOOK || defined NEED_HOOK_SCANNER_WHEN_OFFHOOK
200                 bottom_hook_scan ();
201 #endif
202
203         }
204 }
205
206
207 /******** TOP_MAIN FOR AN ECHO WITH 1 SECOND DELAY ********/
208
209 uint16_t playpos = 0;
210 uint16_t recpos = 0;
211 uint16_t sampled = 0;
212
213 #define abs(x) (((x)>0)?(x):(-(x)))
214
215 /* 1 second at 8000 samples per second, plus 25% extra */
216 uint8_t samples [10000];
217
218 void top_main_delay_1sec (void) {
219         uint16_t prevsampled = 0;
220         uint16_t prevrecirqs = 0;
221         uint16_t prevplyirqs = 0;
222 uint16_t oldspcr1 = 0xffff;
223 uint16_t loop = 0;
224         bottom_critical_region_end ();
225         top_hook_update (bottom_phone_is_offhook ());
226         bottom_codec_play_samplerate (PHONE_CHANNEL_TELEPHONY, 8000);
227         bottom_codec_record_samplerate (PHONE_CHANNEL_TELEPHONY, 8000);
228         bottom_soundchannel_setvolume (PHONE_CHANNEL_TELEPHONY, 127);
229         bottom_show_fixed_msg (APP_LEVEL_ZERO, FIXMSG_READY);
230         bottom_printf ("Running the development function \"echo\" (Test sound)\n");
231         while (true) {
232 #if 0
233                 if (recirqs != prevrecirqs) {
234                         bottom_printf ("Record IRQs #%d, ", (intptr_t) recirqs);
235                         bottom_printf ("available %d\n", (intptr_t) toberecorded);
236                         prevrecirqs = recirqs;
237                 }
238                 if (plyirqs != prevplyirqs) {
239                         bottom_printf ("Playbk IRQs #%d, ", (intptr_t) plyirqs);
240                         bottom_printf ("available %d\n", (intptr_t) tobeplayed);
241                         prevplyirqs = plyirqs;
242                 }
243 #endif
244 { uint16_t xor = oldspcr1 ^ SPCR1_1; if (xor) { oldspcr1 ^= xor; bottom_printf ("SPCR1_1 := 0x%04x\n", (intptr_t) oldspcr1); } }
245                 if (sampled != prevsampled) {
246                         bottom_printf ("Buffered %d samples\n", (intptr_t) sampled);
247                         prevsampled = sampled;
248                 }
249                 if (toberecorded > 0) {
250                         int16_t rec = toberecorded;
251 bottom_led_set (LED_IDX_HANDSET, 1);
252                         if (sampled + rec > 10000) {
253                                 rec = 10000 - sampled;
254                         }
255                         if (recpos + rec > 10000) {
256                                 rec = 10000 - recpos;
257                         }
258                         if (rec > 0) {
259                                 // bottom_printf ("Recording %d at %d extends buffer from %d to %d\n", (intptr_t) rec, (intptr_t) recpos, (intptr_t) sampled, (intptr_t) (rec+sampled));
260                                 // bottom_printf ("Recording %d at %d\n", (intptr_t) rec, (intptr_t) recpos);
261                                 // Codec implies that #samples and #bytes are the same
262                                 rec -= abs (bottom_codec_record (0, CODEC_L8, samples + recpos, rec, rec));
263                                 bottom_printf ("Got 0x%02x, 0x%02x, 0x%02x, ...\n", (intptr_t) samples [recpos], (intptr_t) samples [recpos+1], (intptr_t) samples [recpos+2]);
264                                 sampled += rec;
265                                 recpos += rec;
266                                 if (recpos >= 10000) {
267                                         recpos -= 10000;
268                                 }
269                                 bottom_critical_region_begin ();
270                                 //TODO:SPYING-ON-NEXT-LINE// toberecorded -= rec;
271                                 { extern volatile uint16_t available_record; toberecorded = available_record; }
272                                 bottom_critical_region_end ();
273                         }
274 bottom_led_set (LED_IDX_SPEAKERPHONE, 0);
275                 }
276                 if (sampled > 8000) {
277                         uint16_t ply = sampled - 8000;
278 bottom_led_set (LED_IDX_SPEAKERPHONE, 1);
279                         if (playpos + ply > 10000) {
280                                 ply = 10000 - playpos;
281                         }
282                         if (ply > 0) {
283                                 // bottom_printf ("Playback of %d samples at %d reduces buffer from %d to %d\n", (intptr_t) ply, (intptr_t) playpos, (intptr_t) sampled, (intptr_t) (sampled - ply));
284                                 // bottom_printf ("Playback of %d samples at %d\n", (intptr_t) ply, (intptr_t) playpos);
285                                 ply -= abs (bottom_codec_play (0, CODEC_L8, samples + playpos, ply, ply));
286                                 sampled -= ply;
287                                 playpos += ply;
288                                 if (playpos >= 10000) {
289                                         playpos -= 10000;
290                                 }
291 bottom_led_set (LED_IDX_HANDSET, 0);
292                         }
293                 }
294
295 #ifdef CONFIG_FUNCTION_NETCONSOLE
296                 // { uint32_t ctr = 10000; while (ctr--) ; }
297                 trysend ();
298                 // { uint32_t ctr = 10000; while (ctr--) ; }
299 bottom_led_set (LED_IDX_BACKLIGHT, 1);
300                 netinputlen = sizeof (netinput);
301                 if (bottom_network_recv (netinput, &netinputlen)) {
302                         nethandler_llconly (netinput, netinputlen);
303 bottom_led_set (LED_IDX_BACKLIGHT, 0);
304                         { uint32_t ctr = 10000; while (ctr--) ; }
305                 }
306 bottom_led_set (LED_IDX_BACKLIGHT, 0);
307                 trysend ();
308 #endif
309
310 #if defined NEED_KBD_SCANNER_BETWEEN_KEYS || defined NEED_KBD_SCANNER_DURING_KEYPRESS
311                 bottom_keyboard_scan ();
312 #endif
313
314 #if defined NEED_HOOK_SCANNER_WHEN_ONHOOK || defined NEED_HOOK_SCANNER_WHEN_OFFHOOK
315                 bottom_hook_scan ();
316 #endif
317         }
318 }
319