xref: /btstack/example/sco_demo_util.c (revision 435e3c4e0d833cf29306bcbe25c84a0f767a8539)
1 /*
2  * Copyright (C) 2016 BlueKitchen GmbH
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holders nor the names of
14  *    contributors may be used to endorse or promote products derived
15  *    from this software without specific prior written permission.
16  * 4. Any redistribution, use, or modification is done solely for
17  *    personal benefit and not for any commercial purpose or for
18  *    monetary gain.
19  *
20  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * Please inquire about commercial licensing options at
34  * [email protected]
35  *
36  */
37 
38 /*
39  * sco_demo_util.c - send/receive test data via SCO, used by hfp_*_demo and hsp_*_demo
40  */
41 
42 #include "sco_demo_util.h"
43 #include <stdio.h>
44 
45 // configure test mode
46 #define SCO_DEMO_MODE_SINE		0
47 #define SCO_DEMO_MODE_ASCII		1
48 #define SCO_DEMO_MODE_COUNTER	2
49 
50 // SCO demo configuration
51 #define SCO_DEMO_MODE SCO_DEMO_MODE_SINE
52 #define SCO_REPORT_PERIOD 100
53 
54 // portaudio config
55 #define NUM_CHANNELS 1
56 #define SAMPLE_RATE 8000
57 #define FRAMES_PER_BUFFER 24
58 #define PA_SAMPLE_TYPE paInt8
59 
60 #if defined(HAVE_PORTAUDIO) && (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE)
61 #define USE_PORTAUDIO
62 #endif
63 
64 
65 #ifdef USE_PORTAUDIO
66 #include <portaudio.h>
67 // portaudio globals
68 static  PaStream * stream;
69 #endif
70 
71 #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
72 // input signal: pre-computed sine wave, 160 Hz
73 static const uint8_t sine[] = {
74       0,  15,  31,  46,  61,  74,  86,  97, 107, 114,
75     120, 124, 126, 126, 124, 120, 114, 107,  97,  86,
76      74,  61,  46,  31,  15,   0, 241, 225, 210, 195,
77     182, 170, 159, 149, 142, 136, 132, 130, 130, 132,
78     136, 142, 149, 159, 170, 182, 195, 210, 225, 241,
79 };
80 #endif
81 
82 static int phase;
83 
84 void sco_demo_init(void){
85 
86 	// status
87 #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
88 #ifdef HAVE_PORTAUDIO
89 	printf("SCO Demo: Sending sine wave, audio output via portaudio.\n");
90 #else
91 	printf("SCO Demo: Sending sine wave, hexdump received data.\n");
92 #endif
93 #endif
94 #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
95 	printf("SCO Demo: Sending ASCII blocks, print received data.\n");
96 #endif
97 #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
98 	printf("SCO Demo: Sending counter value, hexdump received data.\n");
99 #endif
100 
101 #ifdef USE_PORTAUDIO
102     int err;
103     PaStreamParameters outputParameters;
104 
105     /* -- initialize PortAudio -- */
106     err = Pa_Initialize();
107     if( err != paNoError ) return;
108     /* -- setup input and output -- */
109     outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
110     outputParameters.channelCount = NUM_CHANNELS;
111     outputParameters.sampleFormat = PA_SAMPLE_TYPE;
112     outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;
113     outputParameters.hostApiSpecificStreamInfo = NULL;
114     /* -- setup stream -- */
115     err = Pa_OpenStream(
116            &stream,
117            NULL, // &inputParameters,
118            &outputParameters,
119            SAMPLE_RATE,
120            FRAMES_PER_BUFFER,
121            paClipOff, /* we won't output out of range samples so don't bother clipping them */
122            NULL, 	  /* no callback, use blocking API */
123            NULL ); 	  /* no callback, so no callback userData */
124     if( err != paNoError ) return;
125     /* -- start stream -- */
126     err = Pa_StartStream( stream );
127     if( err != paNoError ) return;
128 #endif
129 
130 #if SCO_DEMO_MODE != SCO_DEMO_MODE_SINE
131     hci_set_sco_voice_setting(0x03);    // linear, unsigned, 8-bit, transparent
132 #endif
133 
134 #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
135     phase = 'a';
136 #endif
137 }
138 
139 
140 void sco_demo_send(hci_con_handle_t sco_handle){
141 
142     if (!sco_handle) return;
143 
144     const int sco_packet_length = 24 + 3; // hci_get_sco_packet_length();
145     const int sco_payload_length = sco_packet_length - 3;
146 
147     hci_reserve_packet_buffer();
148     uint8_t * sco_packet = hci_get_outgoing_packet_buffer();
149     // set handle + flags
150     little_endian_store_16(sco_packet, 0, sco_handle);
151     // set len
152     sco_packet[2] = sco_payload_length;
153     const int frames_per_packet = sco_payload_length;    // for 8-bit data. for 16-bit data it's /2
154 
155 #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
156     int i;
157     for (i=0;i<frames_per_packet;i++){
158         sco_packet[3+i] = sine[phase];
159         phase++;
160         if (phase >= sizeof(sine)) phase = 0;
161     }
162 #else
163 #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
164     memset(&sco_packet[3], phase++, frames_per_packet);
165     if (phase > 'z') phase = 'a';
166 #else
167     for (i=0;i<frames_per_packet;i++){
168         sco_packet[3+i] = phase++;
169     }
170 #endif
171 #endif
172     hci_send_sco_packet_buffer(sco_packet_length);
173 
174     // request another send event
175     hci_request_sco_can_send_now_event();
176 
177     static int count = 0;
178     count++;
179     if ((count % SCO_REPORT_PERIOD) == 0) printf("SCO: sent %u\n", count);
180 }
181 
182 /**
183  * @brief Process received data
184  */
185 void sco_demo_receive(uint8_t * packet, uint16_t size){
186 
187 	if (packet[1] & 0xf0){
188 	    printf("SCO CRC Error: %x - data: ", packet[1] >> 4);
189 	    printf_hexdump(&packet[3], size-3);
190 	    return;
191 	}
192 
193 #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
194 #ifdef USE_PORTAUDIO
195     uint32_t start = btstack_run_loop_get_time_ms();
196     Pa_WriteStream( stream, &packet[3], size -3);
197     uint32_t end   = btstack_run_loop_get_time_ms();
198     if (end - start > 5){
199         printf("Portaudio: write stream took %u ms\n", end - start);
200     }
201 #else
202     printf_hexdump(&packet[3], size-3);
203 #endif
204 #else
205     printf("data: ");
206 #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
207     int i;
208     for (i=3;i<size;i++){
209         printf("%c", packet[i]);
210     }
211     printf("\n");
212 #endif
213     printf_hexdump(&packet[3], size-3);
214 #endif
215 
216     static int count = 0;
217     count++;
218     if ((count % SCO_REPORT_PERIOD) == 0) printf("SCO: received %u\n", count);
219 }
220