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