1746e2845b4bad25aa9f61e7a089e8402c076e96
[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_delay_1sec top_main
120 // #define top_main_sine_1khz  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 sinewave [8] = {
133         0x00, 0x5a, 0x7f, 0x5a, 0x00, 0xa5, 0x80, 0xa5
134 };
135
136 void top_main_sine_1khz (void) {
137         uint16_t oldirqs = 0;
138 extern volatile uint16_t available_play;
139         top_hook_update (bottom_phone_is_offhook ());
140         bottom_codec_play_samplerate (0, 8000);
141         bottom_codec_record_samplerate (0, 8000); // Both MUST be called for now
142         bottom_soundchannel_setvolume (PHONE_CHANNEL_TELEPHONY, 127);
143         bottom_show_fixed_msg (APP_LEVEL_ZERO, FIXMSG_RINGING); // TODO: Not really necessary
144         bottom_printf ("Playing 1 kHz tone to speaker or handset\n");
145         tobeplayed = 64;
146         while (true) {
147                 uint16_t newplayed = tobeplayed;
148                 uint16_t oldplayed = newplayed;
149                 if (oldirqs != plyirqs) {
150                         bottom_printf ("New playing IRQs detected\n");
151                         oldirqs = plyirqs;
152                 }
153                 while (newplayed >= 8) {
154                         bottom_codec_play (0, CODEC_L8, sinewave, 8, 8);
155                         newplayed -= 8;
156                         bottom_critical_region_end ();
157                 }
158 #if 0
159                 if (oldplayed != newplayed) {
160                         bottom_printf ("available_play := %d\n", (intptr_t) available_play);
161                         bottom_printf ("Playbuffer reduced from %d to %d\n", (intptr_t) oldplayed, (intptr_t) newplayed);
162                 }
163 #endif
164
165 #ifdef CONFIG_FUNCTION_NETCONSOLE
166                 trysend ();
167 bottom_led_set (LED_IDX_BACKLIGHT, 1);
168                 netinputlen = sizeof (netinput);
169                 if (bottom_network_recv (netinput, &netinputlen)) {
170                         nethandler_llconly (netinput, netinputlen);
171                         { uint32_t ctr = 10000; while (ctr--) ; }
172 bottom_led_set (LED_IDX_BACKLIGHT, 0);
173                 }
174                 trysend ();
175 #endif
176
177 #if defined NEED_KBD_SCANNER_BETWEEN_KEYS || defined NEED_KBD_SCANNER_DURING_KEYPRESS
178                 bottom_keyboard_scan ();
179 #endif
180
181 #if defined NEED_HOOK_SCANNER_WHEN_ONHOOK || defined NEED_HOOK_SCANNER_WHEN_OFFHOOK
182                 bottom_hook_scan ();
183 #endif
184
185         }
186 }
187
188
189 /******** TOP_MAIN FOR AN ECHO WITH 1 SECOND DELAY ********/
190
191 uint16_t playpos = 0;
192 uint16_t recpos = 0;
193 uint16_t sampled = 0;
194
195 #define abs(x) (((x)>0)?(x):(-(x)))
196
197 /* 1 second at 8000 samples per second, plus 25% extra */
198 uint8_t samples [10000];
199
200 void top_main_delay_1sec (void) {
201         uint16_t prevsampled = 0;
202         uint16_t prevrecirqs = 0;
203         uint16_t prevplyirqs = 0;
204 uint16_t oldspcr1 = 0xffff;
205 uint16_t loop = 0;
206         bottom_critical_region_end ();
207         top_hook_update (bottom_phone_is_offhook ());
208         bottom_codec_play_samplerate (PHONE_CHANNEL_TELEPHONY, 8000);
209         bottom_codec_record_samplerate (PHONE_CHANNEL_TELEPHONY, 8000);
210         bottom_soundchannel_setvolume (PHONE_CHANNEL_TELEPHONY, 127);
211         bottom_show_fixed_msg (APP_LEVEL_ZERO, FIXMSG_READY); // TODO: Not really necessary
212         bottom_printf ("Running the development function \"echo\" (Test sound)\n");
213         while (true) {
214 #if 0
215 if (loop++ == 0) {
216 uint8_t reg, subreg;
217 uint8_t chan = PHONE_CHANNEL_TELEPHONY;
218 for (reg = 1; reg <= 6; reg++) {
219 uint8_t val0, val1, val2, val3;
220 for (subreg = 0; subreg <=3 ; subreg++) {
221 val0 = tlv320aic2x_getreg (chan, reg);
222 val1 = tlv320aic2x_getreg (chan, reg);
223 val2 = tlv320aic2x_getreg (chan, reg);
224 val3 = tlv320aic2x_getreg (chan, reg);
225 }
226 bottom_printf ("TLV_%d = %02x, %02x, %02x, %02x\n", (intptr_t) reg, (intptr_t) val0, (intptr_t) val1, (intptr_t) val2, (intptr_t) val3);
227 }
228 }
229 #endif
230 #if 0
231                 if (recirqs != prevrecirqs) {
232                         bottom_printf ("Record IRQs #%d, ", (intptr_t) recirqs);
233                         bottom_printf ("available %d\n", (intptr_t) toberecorded);
234                         prevrecirqs = recirqs;
235                 }
236                 if (plyirqs != prevplyirqs) {
237                         bottom_printf ("Playbk IRQs #%d, ", (intptr_t) plyirqs);
238                         bottom_printf ("available %d\n", (intptr_t) tobeplayed);
239                         prevplyirqs = plyirqs;
240                 }
241 #endif
242 {uint16_t xor = oldspcr1 ^ SPCR1_1; if (xor) { oldspcr1 ^= xor; bottom_printf ("SPCR1_1 := 0x%04x\n", oldspcr1); } }
243                 if (sampled != prevsampled) {
244                         bottom_printf ("Buffered %d samples\n", (intptr_t) sampled);
245                         prevsampled = sampled;
246                 }
247                 if (toberecorded > 0) {
248                         int16_t rec = toberecorded;
249 bottom_led_set (LED_IDX_HANDSET, 1);
250                         if (sampled + rec > 10000) {
251                                 rec = 10000 - sampled;
252                         }
253                         if (recpos + rec > 10000) {
254                                 rec = 10000 - recpos;
255                         }
256                         if (rec > 0) {
257                                 bottom_printf ("Recording %d extends buffer from %d to %d\n", (intptr_t) rec, (intptr_t) sampled, (intptr_t) (rec+sampled));
258                                 // Codec implies that #samples and #bytes are the same
259                                 rec -= abs (bottom_codec_record (0, CODEC_G711A, samples + recpos, rec, rec));
260                                 sampled += rec;
261                                 recpos += rec;
262                                 if (recpos >= 10000) {
263                                         recpos = 0;
264                                 }
265                                 bottom_critical_region_begin ();
266                                 //TODO:SPYING-ON-NEXT-LINE// toberecorded -= rec;
267                                 { extern uint16_t available_record; toberecorded = available_record; }
268                                 bottom_critical_region_end ();
269                         }
270 bottom_led_set (LED_IDX_SPEAKERPHONE, 0);
271                 }
272                 if (sampled > 8000) {
273                         uint16_t ply = sampled - 8000;
274 bottom_led_set (LED_IDX_SPEAKERPHONE, 1);
275                         if (playpos + ply > 10000) {
276                                 ply = 10000 - playpos;
277                         }
278                         if (ply > 0) {
279                                 bottom_printf ("Playback of %d samples reduces buffer from %d to %d\n", (intptr_t) ply, (intptr_t) sampled, (intptr_t) (sampled - ply));
280                                 ply -= abs (bottom_codec_play (0, CODEC_G711A, samples + playpos, ply, ply));
281                                 sampled -= ply;
282                                 playpos += ply;
283                                 if (playpos >= 10000) {
284                                         playpos = 0;
285                                 }
286 bottom_led_set (LED_IDX_HANDSET, 0);
287                         }
288                 }
289 #ifdef CONFIG_FUNCTION_NETCONSOLE
290                 // { uint32_t ctr = 10000; while (ctr--) ; }
291                 trysend ();
292                 // { uint32_t ctr = 10000; while (ctr--) ; }
293 bottom_led_set (LED_IDX_BACKLIGHT, 1);
294                 netinputlen = sizeof (netinput);
295                 if (bottom_network_recv (netinput, &netinputlen)) {
296                         nethandler_llconly (netinput, netinputlen);
297                         { uint32_t ctr = 10000; while (ctr--) ; }
298 bottom_led_set (LED_IDX_BACKLIGHT, 0);
299                 }
300                 trysend ();
301 #endif
302 #if defined NEED_KBD_SCANNER_BETWEEN_KEYS || defined NEED_KBD_SCANNER_DURING_KEYPRESS
303                 bottom_keyboard_scan ();
304 #endif
305 #if defined NEED_HOOK_SCANNER_WHEN_ONHOOK || defined NEED_HOOK_SCANNER_WHEN_OFFHOOK
306                 bottom_hook_scan ();
307 #endif
308         }
309 }
310