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