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 43 #include <stdio.h> 44 45 #include "sco_demo_util.h" 46 #include "btstack_debug.h" 47 #include "classic/btstack_sbc.h" 48 #include "classic/btstack_cvsd_plc.h" 49 #include "classic/hfp_msbc.h" 50 #include "classic/hfp.h" 51 52 #ifdef HAVE_POSIX_FILE_IO 53 #include "wav_util.h" 54 #endif 55 56 // configure test mode 57 #define SCO_DEMO_MODE_SINE 0 58 #define SCO_DEMO_MODE_ASCII 1 59 #define SCO_DEMO_MODE_COUNTER 2 60 61 62 // SCO demo configuration 63 #define SCO_DEMO_MODE SCO_DEMO_MODE_SINE 64 #define SCO_REPORT_PERIOD 100 65 66 #ifdef HAVE_POSIX_FILE_IO 67 #define SCO_WAV_FILENAME "sco_input.wav" 68 #define SCO_MSBC_OUT_FILENAME "sco_output.msbc" 69 #define SCO_MSBC_IN_FILENAME "sco_input.mscb" 70 71 #define SCO_WAV_DURATION_IN_SECONDS 15 72 #endif 73 74 75 #if defined(HAVE_PORTAUDIO) && (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) 76 #define USE_PORTAUDIO 77 #endif 78 79 #ifdef USE_PORTAUDIO 80 #include <portaudio.h> 81 #include "btstack_ring_buffer.h" 82 83 // portaudio config 84 #define NUM_CHANNELS 1 85 86 #define CVSD_SAMPLE_RATE 8000 87 #define CVSD_FRAMES_PER_BUFFER 24 88 #define CVSD_PA_SAMPLE_TYPE paInt8 89 #define CVSD_BYTES_PER_FRAME (1*NUM_CHANNELS) 90 #define CVSD_PREBUFFER_MS 5 91 #define CVSD_PREBUFFER_BYTES (CVSD_PREBUFFER_MS * CVSD_SAMPLE_RATE/1000 * CVSD_BYTES_PER_FRAME) 92 93 #define MSBC_SAMPLE_RATE 16000 94 #define MSBC_FRAMES_PER_BUFFER 120 95 #define MSBC_PA_SAMPLE_TYPE paInt16 96 #define MSBC_BYTES_PER_FRAME (2*NUM_CHANNELS) 97 #define MSBC_PREBUFFER_MS 50 98 #define MSBC_PREBUFFER_BYTES (MSBC_PREBUFFER_MS * MSBC_SAMPLE_RATE/1000 * MSBC_BYTES_PER_FRAME) 99 100 // portaudio globals 101 static PaStream * stream; 102 static uint8_t pa_stream_started = 0; 103 104 static uint8_t ring_buffer_storage[2*MSBC_PREBUFFER_BYTES]; 105 static btstack_ring_buffer_t ring_buffer; 106 #endif 107 108 109 static int dump_data = 1; 110 static int count_sent = 0; 111 static int count_received = 0; 112 static uint8_t negotiated_codec = 0; 113 static int num_audio_frames = 0; 114 115 FILE * msbc_file_in; 116 FILE * msbc_file_out; 117 118 #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 119 120 // input signal: pre-computed sine wave, at 8000 kz 121 static const uint8_t sine_uint8[] = { 122 0, 15, 31, 46, 61, 74, 86, 97, 107, 114, 123 120, 124, 126, 126, 124, 120, 114, 107, 97, 86, 124 74, 61, 46, 31, 15, 0, 241, 225, 210, 195, 125 182, 170, 159, 149, 142, 136, 132, 130, 130, 132, 126 136, 142, 149, 159, 170, 182, 195, 210, 225, 241, 127 }; 128 129 130 // input signal: pre-computed sine wave, 160 Hz at 16000 kHz 131 static const int16_t sine_int16[] = { 132 0, 2057, 4107, 6140, 8149, 10126, 12062, 13952, 15786, 17557, 133 19260, 20886, 22431, 23886, 25247, 26509, 27666, 28714, 29648, 30466, 134 31163, 31738, 32187, 32509, 32702, 32767, 32702, 32509, 32187, 31738, 135 31163, 30466, 29648, 28714, 27666, 26509, 25247, 23886, 22431, 20886, 136 19260, 17557, 15786, 13952, 12062, 10126, 8149, 6140, 4107, 2057, 137 0, -2057, -4107, -6140, -8149, -10126, -12062, -13952, -15786, -17557, 138 -19260, -20886, -22431, -23886, -25247, -26509, -27666, -28714, -29648, -30466, 139 -31163, -31738, -32187, -32509, -32702, -32767, -32702, -32509, -32187, -31738, 140 -31163, -30466, -29648, -28714, -27666, -26509, -25247, -23886, -22431, -20886, 141 -19260, -17557, -15786, -13952, -12062, -10126, -8149, -6140, -4107, -2057, 142 }; 143 144 static int phase = 0; 145 static void sco_demo_sine_wave_int8(int num_samples, int8_t * data){ 146 int i; 147 for (i=0; i<num_samples; i++){ 148 data[i] = (int8_t)sine_uint8[phase]; 149 phase++; 150 if (phase >= sizeof(sine_uint8)) phase = 0; 151 } 152 } 153 154 static void sco_demo_sine_wave_int16(int num_samples, int16_t * data){ 155 int i; 156 for (i=0; i < num_samples; i++){ 157 data[i] = sine_int16[phase++]; 158 if (phase >= (sizeof(sine_int16) / sizeof(int16_t))){ 159 phase = 0; 160 } 161 } 162 } 163 164 static void sco_demo_fill_audio_frame(void){ 165 if (!hfp_msbc_can_encode_audio_frame_now()) return; 166 int num_samples = hfp_msbc_num_audio_samples_per_frame(); 167 int16_t sample_buffer[num_samples]; 168 sco_demo_sine_wave_int16(num_samples, sample_buffer); 169 hfp_msbc_encode_audio_frame(sample_buffer); 170 num_audio_frames++; 171 } 172 173 #ifdef SCO_WAV_FILENAME 174 static btstack_sbc_decoder_state_t decoder_state; 175 static btstack_cvsd_plc_state_t cvsd_plc_state; 176 static int num_samples_to_write; 177 178 #ifdef USE_PORTAUDIO 179 static int patestCallback( const void *inputBuffer, void *outputBuffer, 180 unsigned long framesPerBuffer, 181 const PaStreamCallbackTimeInfo* timeInfo, 182 PaStreamCallbackFlags statusFlags, 183 void *userData ) { 184 (void) timeInfo; /* Prevent unused variable warnings. */ 185 (void) statusFlags; 186 (void) inputBuffer; 187 188 uint32_t bytes_read = 0; 189 int bytes_per_buffer = framesPerBuffer; 190 if (negotiated_codec == HFP_CODEC_MSBC){ 191 bytes_per_buffer *= MSBC_BYTES_PER_FRAME; 192 } else { 193 bytes_per_buffer *= CVSD_BYTES_PER_FRAME; 194 } 195 196 if (btstack_ring_buffer_bytes_available(&ring_buffer) >= bytes_per_buffer){ 197 btstack_ring_buffer_read(&ring_buffer, outputBuffer, bytes_per_buffer, &bytes_read); 198 } else { 199 printf("NOT ENOUGH DATA!\n"); 200 memset(outputBuffer, 0, bytes_per_buffer); 201 } 202 // printf("bytes avail after read: %d\n", btstack_ring_buffer_bytes_available(&ring_buffer)); 203 return 0; 204 } 205 #endif 206 207 static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){ 208 // printf("handle_pcm_data num samples %u, sample rate %d\n", num_samples, num_channels); 209 #ifdef USE_PORTAUDIO 210 if (!pa_stream_started && btstack_ring_buffer_bytes_available(&ring_buffer) >= MSBC_PREBUFFER_BYTES){ 211 /* -- start stream -- */ 212 PaError err = Pa_StartStream(stream); 213 if (err != paNoError){ 214 printf("Error starting the stream: \"%s\"\n", Pa_GetErrorText(err)); 215 return; 216 } 217 pa_stream_started = 1; 218 } 219 btstack_ring_buffer_write(&ring_buffer, (uint8_t *)data, num_samples*num_channels*2); 220 // printf("bytes avail after write: %d\n", btstack_ring_buffer_bytes_available(&ring_buffer)); 221 #endif 222 223 if (!num_samples_to_write) return; 224 225 num_samples = btstack_min(num_samples, num_samples_to_write); 226 num_samples_to_write -= num_samples; 227 228 wav_writer_write_int16(num_samples, data); 229 230 if (num_samples_to_write == 0){ 231 sco_demo_close(); 232 } 233 } 234 235 static void sco_demo_init_mSBC(void){ 236 int sample_rate = 16000; 237 wav_writer_open(SCO_WAV_FILENAME, 1, sample_rate); 238 btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL); 239 240 num_samples_to_write = sample_rate * SCO_WAV_DURATION_IN_SECONDS; 241 242 hfp_msbc_init(); 243 sco_demo_fill_audio_frame(); 244 245 #ifdef SCO_MSBC_IN_FILENAME 246 msbc_file_in = fopen(SCO_MSBC_IN_FILENAME, "wb"); 247 printf("SCO Demo: creating mSBC in file %s, %p\n", SCO_MSBC_IN_FILENAME, msbc_file_in); 248 #endif 249 #ifdef SCO_MSBC_OUT_FILENAME 250 msbc_file_out = fopen(SCO_MSBC_OUT_FILENAME, "wb"); 251 printf("SCO Demo: creating mSBC out file %s, %p\n", SCO_MSBC_OUT_FILENAME, msbc_file_out); 252 #endif 253 254 #ifdef USE_PORTAUDIO 255 PaError err; 256 PaStreamParameters outputParameters; 257 258 /* -- initialize PortAudio -- */ 259 err = Pa_Initialize(); 260 if( err != paNoError ) return; 261 /* -- setup input and output -- */ 262 outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ 263 outputParameters.channelCount = NUM_CHANNELS; 264 outputParameters.sampleFormat = MSBC_PA_SAMPLE_TYPE; 265 outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency; 266 outputParameters.hostApiSpecificStreamInfo = NULL; 267 /* -- setup stream -- */ 268 err = Pa_OpenStream( 269 &stream, 270 NULL, // &inputParameters, 271 &outputParameters, 272 MSBC_SAMPLE_RATE, 273 MSBC_FRAMES_PER_BUFFER, 274 paClipOff, /* we won't output out of range samples so don't bother clipping them */ 275 patestCallback, /* no callback, use blocking API */ 276 NULL ); /* no callback, so no callback userData */ 277 if (err != paNoError){ 278 printf("Error initializing portaudio: \"%s\"\n", Pa_GetErrorText(err)); 279 return; 280 } 281 memset(ring_buffer_storage, 0, sizeof(ring_buffer_storage)); 282 btstack_ring_buffer_init(&ring_buffer, ring_buffer_storage, sizeof(ring_buffer_storage)); 283 pa_stream_started = 0; 284 #endif 285 } 286 287 static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){ 288 if (num_samples_to_write){ 289 if (msbc_file_in){ 290 // log incoming mSBC data for testing 291 fwrite(packet+3, size-3, 1, msbc_file_in); 292 } 293 } 294 btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3); 295 } 296 297 static void sco_demo_init_CVSD(void){ 298 int sample_rate = 8000; 299 wav_writer_open(SCO_WAV_FILENAME, 1, sample_rate); 300 btstack_cvsd_plc_init(&cvsd_plc_state); 301 num_samples_to_write = sample_rate * SCO_WAV_DURATION_IN_SECONDS; 302 303 #ifdef USE_PORTAUDIO 304 PaError err; 305 PaStreamParameters outputParameters; 306 307 /* -- initialize PortAudio -- */ 308 err = Pa_Initialize(); 309 if( err != paNoError ) return; 310 /* -- setup input and output -- */ 311 outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ 312 outputParameters.channelCount = NUM_CHANNELS; 313 outputParameters.sampleFormat = CVSD_PA_SAMPLE_TYPE; 314 outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency; 315 outputParameters.hostApiSpecificStreamInfo = NULL; 316 /* -- setup stream -- */ 317 err = Pa_OpenStream( 318 &stream, 319 NULL, // &inputParameters, 320 &outputParameters, 321 CVSD_SAMPLE_RATE, 322 CVSD_FRAMES_PER_BUFFER, 323 paClipOff, /* we won't output out of range samples so don't bother clipping them */ 324 patestCallback, /* no callback, use blocking API */ 325 NULL ); /* no callback, so no callback userData */ 326 if (err != paNoError){ 327 printf("Error initializing portaudio: \"%s\"\n", Pa_GetErrorText(err)); 328 return; 329 } 330 memset(ring_buffer_storage, 0, sizeof(ring_buffer_storage)); 331 btstack_ring_buffer_init(&ring_buffer, ring_buffer_storage, sizeof(ring_buffer_storage)); 332 pa_stream_started = 0; 333 #endif 334 } 335 336 static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){ 337 if (!num_samples_to_write) return; 338 339 const int num_samples = size - 3; 340 const int samples_to_write = btstack_min(num_samples, num_samples_to_write); 341 int8_t audio_frame_out[24]; 342 343 344 // memcpy(audio_frame_out, (int8_t*)(packet+3), 24); 345 btstack_cvsd_plc_process_data(&cvsd_plc_state, (int8_t *)(packet+3), num_samples, audio_frame_out); 346 347 wav_writer_write_int8(samples_to_write, audio_frame_out); 348 num_samples_to_write -= samples_to_write; 349 if (num_samples_to_write == 0){ 350 sco_demo_close(); 351 } 352 #ifdef USE_PORTAUDIO 353 if (!pa_stream_started && btstack_ring_buffer_bytes_available(&ring_buffer) >= CVSD_PREBUFFER_BYTES){ 354 /* -- start stream -- */ 355 PaError err = Pa_StartStream(stream); 356 if (err != paNoError){ 357 printf("Error starting the stream: \"%s\"\n", Pa_GetErrorText(err)); 358 return; 359 } 360 pa_stream_started = 1; 361 } 362 btstack_ring_buffer_write(&ring_buffer, (uint8_t *)audio_frame_out, samples_to_write); 363 #endif 364 } 365 366 #endif 367 #endif 368 369 void sco_demo_close(void){ 370 #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 371 #if defined(SCO_WAV_FILENAME) || defined(SCO_SBC_FILENAME) 372 wav_writer_close(); 373 printf("SCO demo statistics: "); 374 if (negotiated_codec == HFP_CODEC_MSBC){ 375 printf("Used mSBC with PLC, number of processed frames: \n - %d good frames, \n - %d zero frames, \n - %d bad frames.", decoder_state.good_frames_nr, decoder_state.zero_frames_nr, decoder_state.bad_frames_nr); 376 } else { 377 printf("Used CVSD with PLC, number of proccesed frames: \n - %d good frames, \n - %d bad frames.", cvsd_plc_state.good_frames_nr, cvsd_plc_state.bad_frames_nr); 378 } 379 #endif 380 #endif 381 382 #ifdef HAVE_PORTAUDIO 383 if (pa_stream_started){ 384 PaError err = Pa_StopStream(stream); 385 if (err != paNoError){ 386 printf("Error stopping the stream: \"%s\"\n", Pa_GetErrorText(err)); 387 return; 388 } 389 pa_stream_started = 0; 390 err = Pa_CloseStream(stream); 391 if (err != paNoError){ 392 printf("Error closing the stream: \"%s\"\n", Pa_GetErrorText(err)); 393 return; 394 } 395 396 err = Pa_Terminate(); 397 if (err != paNoError){ 398 printf("Error terminating portaudio: \"%s\"\n", Pa_GetErrorText(err)); 399 return; 400 } 401 } 402 #endif 403 404 #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 405 #ifdef SCO_WAV_FILENAME 406 407 #if 0 408 printf("SCO Demo: closing wav file\n"); 409 if (negotiated_codec == HFP_CODEC_MSBC){ 410 wav_writer_state_t * writer_state = &wav_writer_state; 411 if (!writer_state->wav_file) return; 412 rewind(writer_state->wav_file); 413 write_wav_header(writer_state->wav_file, writer_state->total_num_samples, btstack_sbc_decoder_num_channels(&decoder_state), btstack_sbc_decoder_sample_rate(&decoder_state),2); 414 fclose(writer_state->wav_file); 415 writer_state->wav_file = NULL; 416 } 417 #endif 418 #endif 419 #endif 420 } 421 422 void sco_demo_set_codec(uint8_t codec){ 423 if (negotiated_codec == codec) return; 424 negotiated_codec = codec; 425 #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 426 #if defined(SCO_WAV_FILENAME) || defined(SCO_SBC_FILENAME) 427 if (negotiated_codec == HFP_CODEC_MSBC){ 428 sco_demo_init_mSBC(); 429 } else { 430 sco_demo_init_CVSD(); 431 } 432 #endif 433 #endif 434 } 435 436 void sco_demo_init(void){ 437 438 // status 439 #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 440 #ifdef HAVE_PORTAUDIO 441 printf("SCO Demo: Sending sine wave, audio output via portaudio.\n"); 442 #else 443 printf("SCO Demo: Sending sine wave, hexdump received data.\n"); 444 #endif 445 #endif 446 #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 447 printf("SCO Demo: Sending ASCII blocks, print received data.\n"); 448 #endif 449 #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER 450 printf("SCO Demo: Sending counter value, hexdump received data.\n"); 451 #endif 452 453 #if SCO_DEMO_MODE != SCO_DEMO_MODE_SINE 454 hci_set_sco_voice_setting(0x03); // linear, unsigned, 8-bit, transparent 455 #endif 456 457 #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 458 phase = 'a'; 459 #endif 460 } 461 462 static void sco_report(void){ 463 printf("SCO: sent %u, received %u\n", count_sent, count_received); 464 } 465 466 void sco_demo_send(hci_con_handle_t sco_handle){ 467 468 if (!sco_handle) return; 469 470 const int sco_packet_length = 24 + 3; // hci_get_sco_packet_length(); 471 const int sco_payload_length = sco_packet_length - 3; 472 473 hci_reserve_packet_buffer(); 474 uint8_t * sco_packet = hci_get_outgoing_packet_buffer(); 475 // set handle + flags 476 little_endian_store_16(sco_packet, 0, sco_handle); 477 // set len 478 sco_packet[2] = sco_payload_length; 479 const int audio_samples_per_packet = sco_payload_length; // for 8-bit data. for 16-bit data it's /2 480 481 #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 482 if (negotiated_codec == HFP_CODEC_MSBC){ 483 484 if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){ 485 log_error("mSBC stream is empty."); 486 } 487 hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length); 488 if (msbc_file_out){ 489 // log outgoing mSBC data for testing 490 fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out); 491 } 492 493 sco_demo_fill_audio_frame(); 494 } else { 495 sco_demo_sine_wave_int8(audio_samples_per_packet, (int8_t *) (sco_packet+3)); 496 } 497 #else 498 #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 499 memset(&sco_packet[3], phase++, audio_samples_per_packet); 500 if (phase > 'z') phase = 'a'; 501 #else 502 int j; 503 for (j=0;j<audio_samples_per_packet;j++){ 504 sco_packet[3+j] = phase++; 505 } 506 #endif 507 #endif 508 509 hci_send_sco_packet_buffer(sco_packet_length); 510 511 // request another send event 512 hci_request_sco_can_send_now_event(); 513 514 count_sent++; 515 if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report(); 516 } 517 518 /** 519 * @brief Process received data 520 */ 521 void sco_demo_receive(uint8_t * packet, uint16_t size){ 522 523 dump_data = 1; 524 525 count_received++; 526 // if ((count_received % SCO_REPORT_PERIOD) == 0) sco_report(); 527 528 529 #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 530 #ifdef SCO_WAV_FILENAME 531 if (negotiated_codec == HFP_CODEC_MSBC){ 532 sco_demo_receive_mSBC(packet, size); 533 } else { 534 sco_demo_receive_CVSD(packet, size); 535 } 536 dump_data = 0; 537 #endif 538 #endif 539 540 if (packet[1] & 0x30){ 541 printf("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4); 542 log_info("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4); 543 printf_hexdump(&packet[3], size-3); 544 545 return; 546 } 547 if (dump_data){ 548 printf("data: "); 549 #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 550 int i; 551 for (i=3;i<size;i++){ 552 printf("%c", packet[i]); 553 } 554 printf("\n"); 555 dump_data = 0; 556 #else 557 printf_hexdump(&packet[3], size-3); 558 #endif 559 } 560 } 561