1 /* echo.c -- Sound I/O test program
3 * This file is part of 0cpm Firmerware.
5 * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
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.
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.
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/>.
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.
26 * From: Rick van Rein <rick@openfortress.nl>
35 //TODO// test inclusion of bottom definitions
41 #include <0cpm/cons.h>
42 #include <0cpm/show.h>
47 volatile uint16_t tobeplayed = 0;
48 volatile uint16_t toberecorded = 0;
51 timing_t top_timer_expiration (timing_t timeout) {
52 /* Keep the linker happy */ ;
56 void top_hook_update (bool offhook) {
58 bottom_soundchannel_device (PHONE_CHANNEL_TELEPHONY, PHONE_SOUNDDEV_HANDSET);
60 bottom_soundchannel_device (PHONE_CHANNEL_TELEPHONY, PHONE_SOUNDDEV_SPEAKER);
64 void top_network_online (void) {
65 /* Keep the linker happy */ ;
68 void top_network_offline (void) {
69 /* Keep the linker happy */ ;
72 void top_network_can_send (void) {
73 /* Keep the linker happy */ ;
76 void top_network_can_recv (void) {
77 /* Keep the linker happy */ ;
80 void top_button_press (buttonclass_t bcl, buttoncode_t cde) {
81 if (bcl != BUTCLS_FIXED_FUNCTION) {
87 bottom_soundchannel_setvolume (PHONE_CHANNEL_TELEPHONY,
88 bottom_soundchannel_getvolume (PHONE_CHANNEL_TELEPHONY) + 1);
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);
102 void top_button_release (void) {
103 /* Keep the linker happy */
106 uint16_t plyirqs = 0;
107 void top_can_play (uint16_t samples) {
108 tobeplayed = samples;
112 uint16_t recirqs = 0;
113 void top_can_record (uint16_t samples) {
114 toberecorded = samples;
119 // #define top_main_sine_1khz top_main
120 #define top_main_delay_1sec top_main
123 #ifdef CONFIG_FUNCTION_NETCONSOLE
124 uint8_t netinput [1000];
125 uint16_t netinputlen;
126 void nethandler_llconly (uint8_t *pkt, uint16_t pktlen);
130 /******** TOP_MAIN FOR A 1 KHZ SINE WAVE OUTPUT ********/
132 uint8_t sinewaveL8 [8] = {
133 0x00, 0x5a, 0x7f, 0x5a, 0x00, 0xa5, 0x80, 0xa5
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
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;
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");
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);
165 if (SPCR2_1 & REGVAL_SPCR2_XRDY) { DXR1_1 = sinewaveL16 [l16ctr++]; if (l16ctr == 8) { l16ctr = 0; } }
166 { uint16_t _ = DRR1_1; }
168 while (newplayed >= 8) {
169 bottom_codec_play (0, CODEC_L8, sinewaveL8, 8, 8);
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);
180 #ifdef CONFIG_FUNCTION_NETCONSOLE
181 // { uint32_t ctr = 10000; while (ctr--) ; }
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--) ; }
191 bottom_led_set (LED_IDX_BACKLIGHT, 0);
195 #if defined NEED_KBD_SCANNER_BETWEEN_KEYS || defined NEED_KBD_SCANNER_DURING_KEYPRESS
196 bottom_keyboard_scan ();
199 #if defined NEED_HOOK_SCANNER_WHEN_ONHOOK || defined NEED_HOOK_SCANNER_WHEN_OFFHOOK
207 /******** TOP_MAIN FOR AN ECHO WITH 1 SECOND DELAY ********/
209 uint16_t playpos = 0;
211 uint16_t sampled = 0;
213 #define abs(x) (((x)>0)?(x):(-(x)))
215 /* 1 second at 8000 samples per second, plus 25% extra */
216 uint8_t samples [10000];
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;
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");
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;
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;
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;
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;
255 if (recpos + rec > 10000) {
256 rec = 10000 - recpos;
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]);
266 if (recpos >= 10000) {
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 ();
274 bottom_led_set (LED_IDX_SPEAKERPHONE, 0);
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;
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));
288 if (playpos >= 10000) {
291 bottom_led_set (LED_IDX_HANDSET, 0);
295 #ifdef CONFIG_FUNCTION_NETCONSOLE
296 // { uint32_t ctr = 10000; while (ctr--) ; }
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--) ; }
306 bottom_led_set (LED_IDX_BACKLIGHT, 0);
310 #if defined NEED_KBD_SCANNER_BETWEEN_KEYS || defined NEED_KBD_SCANNER_DURING_KEYPRESS
311 bottom_keyboard_scan ();
314 #if defined NEED_HOOK_SCANNER_WHEN_ONHOOK || defined NEED_HOOK_SCANNER_WHEN_OFFHOOK