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