From 8a30115398cd66e1fcb8da9a5c265b27b9540deb Mon Sep 17 00:00:00 2001 From: lwvmobile Date: Sun, 22 Jun 2025 15:16:19 -0400 Subject: [PATCH] SDRTrunk .mbe File Replay Initial Commit; #298 --- include/dsd.h | 4 + src/dsd_events.c | 3 +- src/dsd_file.c | 622 +++++++++++++++++++++++++++++++++++++++++++++-- src/dsd_main.c | 24 +- src/dsd_mbe.c | 5 + src/dsd_time.c | 17 ++ 6 files changed, 645 insertions(+), 30 deletions(-) diff --git a/include/dsd.h b/include/dsd.h index 98f3915..6323493 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -1153,6 +1153,8 @@ void PrintAMBEData (dsd_opts * opts, dsd_state * state, char *ambe_d); void PrintIMBEData (dsd_opts * opts, dsd_state * state, char *imbe_d); int readImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d); int readAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d); +void keyring(dsd_opts * opts, dsd_state * state); +void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state); void openMbeInFile (dsd_opts * opts, dsd_state * state); void closeMbeOutFile (dsd_opts * opts, dsd_state * state); void closeMbeOutFileR (dsd_opts * opts, dsd_state * state); //tdma slot 2 @@ -1412,10 +1414,12 @@ void decode_ars(dsd_opts * opts, dsd_state * state, uint8_t * input, int len); char * getTime(); char * getTimeC(); char * getTimeN(time_t t); +char * getTimeF(time_t t); char * getDate(); char * getDateH(); char * getDateS(); char * getDateN(time_t t); +char * getDateF(time_t t); //event history functions void init_event_history (Event_History_I * event_struct, uint8_t start, uint8_t stop); diff --git a/src/dsd_events.c b/src/dsd_events.c index 8714f07..f97ff1b 100644 --- a/src/dsd_events.c +++ b/src/dsd_events.c @@ -617,7 +617,8 @@ void watchdog_event_current (dsd_opts * opts, dsd_state * state, uint8_t slot) event_struct->Event_History_Items[0].source_id = source_id; event_struct->Event_History_Items[0].target_id = target_id; event_struct->Event_History_Items[0].channel = channel; //need to add this to trunking messages, if tuned from call grant - event_struct->Event_History_Items[0].event_time = time(NULL); + if (opts->playfiles == 0) //if playing back .mbe files with a time in it, don't set this + event_struct->Event_History_Items[0].event_time = time(NULL); sprintf (event_struct->Event_History_Items[0].sysid_string, "%s", sysid_string); sprintf (event_struct->Event_History_Items[0].src_str, "%s", src_str); sprintf (event_struct->Event_History_Items[0].tgt_str, "%s", tgt_str); diff --git a/src/dsd_file.c b/src/dsd_file.c index a030aca..ec34d0f 100644 --- a/src/dsd_file.c +++ b/src/dsd_file.c @@ -16,6 +16,8 @@ */ #include "dsd.h" +#include "p25p1_const.h" //for imbe fr (7200) +#include "dmr_const.h" //for ambe+2 fr void saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d) { @@ -244,9 +246,17 @@ openMbeInFile (dsd_opts * opts, dsd_state * state) opts->mbe_in_f = fopen (opts->mbe_in_file, "ro"); if (opts->mbe_in_f == NULL) - { - fprintf (stderr,"Error: could not open %s\n", opts->mbe_in_file); - } + fprintf (stderr,"Error: could not open %s\n", opts->mbe_in_file); + + //this will check the last 4 characters of the opts->mbe_in_file string + char ext[5]; memset(ext, 0, sizeof(ext)); + uint16_t str_len = strlen((const char*)opts->mbe_in_file); + uint16_t ext_ptr = str_len - 4; + strncpy (ext, opts->mbe_in_file+ext_ptr, 4); + + //debug + // fprintf (stderr, "EXT: %s;", ext); + // read cookie cookie[0] = fgetc (opts->mbe_in_f); @@ -254,26 +264,27 @@ openMbeInFile (dsd_opts * opts, dsd_state * state) cookie[2] = fgetc (opts->mbe_in_f); cookie[3] = fgetc (opts->mbe_in_f); cookie[4] = 0; + //ambe+2 if (strstr (cookie, ".amb") != NULL) - { state->mbe_file_type = 1; - } //p1 and pv else if (strstr (cookie, ".imb") != NULL) - { state->mbe_file_type = 0; - } //d-star ambe else if (strstr (cookie, ".dmb") != NULL) - { state->mbe_file_type = 2; - } + //sdrtrunk formated mbe json file + else if (strncmp (".mbe", ext, 4) == 0) + state->mbe_file_type = 3; else - { - state->mbe_file_type = -1; - fprintf (stderr,"Error - unrecognized file type\n"); - } + { + state->mbe_file_type = -1; + fprintf (stderr,"Error - unrecognized file type\n"); + + //try SDRTrunk JSON format as last resort + state->mbe_file_type = 3; + } } @@ -323,6 +334,9 @@ void openMbeOutFile (dsd_opts * opts, dsd_state * state) char * timestr; //add timestr here, so we can assign it and also free it to prevent memory leak char * datestr; + //random element of filename, so two files won't overwrite one another + uint16_t random_number = rand() & 0xFFFF; + timestr = getTime(); datestr = getDate(); @@ -350,7 +364,7 @@ void openMbeOutFile (dsd_opts * opts, dsd_state * state) state->tgcount = 0; - sprintf (opts->mbe_out_file, "%s %s S1%s", datestr, timestr, ext); + sprintf (opts->mbe_out_file, "%s_%s_%04X_S1%s", datestr, timestr, random_number, ext); sprintf (opts->mbe_out_path, "%s%s", opts->mbe_out_dir, opts->mbe_out_file); @@ -385,6 +399,9 @@ void openMbeOutFileR (dsd_opts * opts, dsd_state * state) char * timestr; //add timestr here, so we can assign it and also free it to prevent memory leak char * datestr; + //random element of filename, so two files won't overwrite one another + uint16_t random_number = rand() & 0xFFFF; + timestr = getTime(); datestr = getDate(); @@ -412,7 +429,7 @@ void openMbeOutFileR (dsd_opts * opts, dsd_state * state) state->tgcount = 0; - sprintf (opts->mbe_out_fileR, "%s %s S2%s", datestr, timestr, ext); + sprintf (opts->mbe_out_fileR, "%s_%s_%04X_S2%s", datestr, timestr, random_number, ext); sprintf (opts->mbe_out_path, "%s%s", opts->mbe_out_dir, opts->mbe_out_fileR); @@ -488,8 +505,9 @@ SNDFILE * close_and_rename_wav_file(SNDFILE * wav_file, char * wav_out_filename, { sf_close(wav_file); - char * datestr = getDate(); - char * timestr = getTime(); + time_t event_time = event_struct->Event_History_Items[0].event_time; + char * datestr = getDateF(event_time); + char * timestr = getTimeF(event_time); uint16_t random_number = rand(); uint32_t source_id = event_struct->Event_History_Items[0].source_id; @@ -849,4 +867,574 @@ uint16_t parse_raw_user_string (char * input, uint8_t * output) if (shift) output[len-1] <<= 4; return len; +} + +uint16_t ambe2_str_to_decode(dsd_opts * opts, dsd_state * state, char * ambe_str, uint8_t * ks, uint16_t ks_idx, uint8_t dmra) +{ + UNUSED(opts); + + char ambe_fr[4][24]; memset (ambe_fr, 0, sizeof(ambe_fr)); + uint8_t dibit_pair = 0; + uint8_t dibit1 = 0, dibit2 = 0; + const int *w, *x, *y, *z; + w = rW; + x = rX; + y = rY; + z = rZ; + for (size_t i = 0; i < 18; i++) + { + + char octet_char[2]; + octet_char[1] = 0; + + strncpy (octet_char, ambe_str+i, 1); + sscanf (octet_char, "%hhX", &dibit_pair); + + dibit1 = (dibit_pair >> 2) & 0x3; + dibit2 = (dibit_pair >> 0) & 0x3; + + //debug + // fprintf (stderr, "\n dibit_pair: %X = %d, %d;", dibit_pair, dibit1, dibit2); + + //load into ambe_fr + ambe_fr[*w][*x] = (1 & (dibit1 >> 1)); // bit 1 + ambe_fr[*y][*z] = (1 & (dibit1 >> 0)); // bit 0 + + w++; + x++; + y++; + z++; + + ambe_fr[*w][*x] = (1 & (dibit2 >> 1)); // bit 1 + ambe_fr[*y][*z] = (1 & (dibit2 >> 0)); // bit 0 + + w++; + x++; + y++; + z++; + + //working now! + + } + + char ambe_d[49]; memset(ambe_d, 0, sizeof(ambe_d)); + state->errs = mbe_eccAmbe3600x2450C0 (ambe_fr); + state->errs2 = state->errs; + mbe_demodulateAmbe3600x2450Data (ambe_fr); + state->errs2 += mbe_eccAmbe3600x2450Data (ambe_fr, ambe_d); + state->debug_audio_errors += state->errs2; + + //keystream application + for (uint8_t i = 0; i < 49; i++) + ambe_d[i] ^= ks[(ks_idx++)%3000]; + + //DMRA or P25 KS, skip the left over 7 bits from a byte + if (dmra == 1) + ks_idx += 7; + + mbe_processAmbe2450Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, + ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); + + PrintAMBEData (opts, state, ambe_d); + + //convert and save to .amb file if desired + if (opts->mbe_out_f != NULL) + saveAmbe2450Data (opts, state, ambe_d); + + //audio out stack + if (opts->floating_point == 0) + processAudio(opts, state); + + if (opts->wav_out_f != NULL) + writeSynthesizedVoice (opts, state); + + if (opts->audio_out == 1 && opts->floating_point == 0) + playSynthesizedVoiceMS (opts, state); + + if (opts->floating_point == 1) + { + memcpy (state->f_l, state->audio_out_temp_buf, sizeof(state->f_l)); + playSynthesizedVoiceFM (opts, state); + } + //else if not floating point audio or audio out, then purge the audio buffers before they overflow and segfault + else if (opts->audio_out == 0) + { + if (state->audio_out_idx2 >= 800000) + { + state->audio_out_float_buf_p = state->audio_out_float_buf + 100; + state->audio_out_buf_p = state->audio_out_buf + 100; + memset (state->audio_out_float_buf, 0, 100 * sizeof (float)); + memset (state->audio_out_buf, 0, 100 * sizeof (short)); + state->audio_out_idx2 = 0; + } + } + + return ks_idx; //return current ks_idx + +} + +uint16_t imbe_str_to_decode(dsd_opts * opts, dsd_state * state, char * imbe_str, uint8_t * ks, uint16_t ks_idx) +{ + UNUSED(opts); + + char imbe_fr[8][23]; memset (imbe_fr, 0, sizeof(imbe_fr)); + uint8_t dibit_pair = 0; + uint8_t dibit1 = 0, dibit2 = 0; + const int *w, *x, *y, *z; + w = iW; + x = iX; + y = iY; + z = iZ; + for (size_t i = 0; i < 36; i++) + { + + char octet_char[2]; + octet_char[1] = 0; + + strncpy (octet_char, imbe_str+i, 1); + sscanf (octet_char, "%hhX", &dibit_pair); + + dibit1 = (dibit_pair >> 2) & 0x3; + dibit2 = (dibit_pair >> 0) & 0x3; + + //debug + // fprintf (stderr, "\n dibit_pair: %X = %d, %d;", dibit_pair, dibit1, dibit2); + + //load into imbe_fr + imbe_fr[*w][*x] = (1 & (dibit1 >> 1)); // bit 1 + imbe_fr[*y][*z] = (1 & (dibit1 >> 0)); // bit 0 + + w++; + x++; + y++; + z++; + + imbe_fr[*w][*x] = (1 & (dibit2 >> 1)); // bit 1 + imbe_fr[*y][*z] = (1 & (dibit2 >> 0)); // bit 0 + + w++; + x++; + y++; + z++; + + //working now! + + } + + char imbe_d[88]; memset(imbe_d, 0, sizeof(imbe_d)); + state->errs = mbe_eccImbe7200x4400C0 (imbe_fr); + state->errs2 = state->errs; + mbe_demodulateImbe7200x4400Data (imbe_fr); + state->errs2 += mbe_eccImbe7200x4400Data (imbe_fr, imbe_d); + state->debug_audio_errors += state->errs2; + + //keystream application + for (uint8_t i = 0; i < 88; i++) + imbe_d[i] ^= ks[(ks_idx++)%3000]; + + mbe_processImbe4400Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, + imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); + + PrintIMBEData (opts, state, imbe_d); + + //convert and save to .imb file if desired + if (opts->mbe_out_f != NULL) + saveImbe4400Data (opts, state, imbe_d); + + //audio out stack + if (opts->floating_point == 0) + processAudio(opts, state); + + if (opts->wav_out_f != NULL) + writeSynthesizedVoice (opts, state); + + if (opts->audio_out == 1 && opts->floating_point == 0) + playSynthesizedVoiceMS (opts, state); + + if (opts->floating_point == 1) + { + memcpy (state->f_l, state->audio_out_temp_buf, sizeof(state->f_l)); + playSynthesizedVoiceFM (opts, state); + } + //else if not floating point audio or audio out, then purge the audio buffers before they overflow and segfault + else if (opts->audio_out == 0) + { + if (state->audio_out_idx2 >= 800000) + { + state->audio_out_float_buf_p = state->audio_out_float_buf + 100; + state->audio_out_buf_p = state->audio_out_buf + 100; + memset (state->audio_out_float_buf, 0, 100 * sizeof (float)); + memset (state->audio_out_buf, 0, 100 * sizeof (short)); + state->audio_out_idx2 = 0; + } + } + + return ks_idx; //return current ks_idx + +} + +void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state) +{ + + char * source_str = calloc(0x100000, sizeof(char)); + size_t source_size; + + int8_t protocol = -1; + uint32_t source = 0; UNUSED(source); + uint32_t target = 0; UNUSED(target); + int8_t gi = -1; UNUSED(gi); + uint8_t is_enc = 0; UNUSED(is_enc); + uint8_t is_dmra = 1; //Denny, we need an MFID in the JSON file plz + + uint8_t alg_id = 0; + uint16_t key_id = 0; + unsigned long long int iv_hex = 0; + int rc4_db = 256; + int rc4_mod = 13; + + time_t event_time = time(NULL); UNUSED(event_time); + + //for event history items + state->dmr_color_code = 0; + state->lastsrc = 0; + state->lasttg = 0; + state->gi[0] = -1; + state->synctype = -1; + state->lastsynctype = -1; + + //watchdog for event history + watchdog_event_history(opts, state, 0); + watchdog_event_current(opts, state, 0); + + uint8_t ks[3000]; memset (ks, 0, sizeof(ks)); + uint16_t ks_idx = 0; //keystream index value + + source_size = fread (source_str, 1, 0x100000, opts->mbe_in_f); + + //debug + // fprintf (stderr, " Source Size: %d.\n", source_size); + // fprintf (stderr, "\n"); + + char * str_buffer = calloc(source_size, sizeof(char)); + + str_buffer = strtok(source_str, "{ \""); //value after initial { open bracket + + //debug print current str_buffer + // fprintf (stderr, "%s", str_buffer); + + for (size_t i = 0; i < source_size; i++) + { + + //debug print current str_buffer + // fprintf (stderr, "%s", str_buffer); + + //compare and set items accordingly + if (strncmp ("protocol", str_buffer, 8) == 0) + { + str_buffer = strtok(NULL, " : \""); //next value after any : "" string + + //debug print current str_buffer + fprintf (stderr, "\n Protocol: %s", str_buffer); + + //compare protocol and set to proper codec etc + if (strncmp ("APCO25-PHASE1", str_buffer, 13) == 0) + { + //set IMBE protocol here + protocol = 1; + + //rc4 dropbyte and key len mod + rc4_db = 267; + rc4_mod = 13; + + state->synctype = 0; + state->lastsynctype = 0; + } + + if (strncmp ("APCO25-PHASE2", str_buffer, 13) == 0) + { + //set AMBE+2 protocol here + protocol = 2; + + //rc4 dropbyte and key len mod + rc4_db = 256; + rc4_mod = 13; + + state->synctype = 35; + state->lastsynctype = 35; + } + + if (strncmp ("DMR", str_buffer, 3) == 0) + { + //set AMBE+2 protocol here + protocol = 2; + + //rc4 dropbyte and key len mod + rc4_db = 256; + rc4_mod = 9; + + state->synctype = 10; + state->lastsynctype = 10; + } + + //open .imb or .amb file, if desired, but only after setting a synctype + if (state->synctype != -1) + { + //if converting to .amb or .imb, open that file format as well + if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) + openMbeOutFile (opts, state); + } + + } + + if (strncmp ("call_type", str_buffer, 9) == 0) + { + str_buffer = strtok(NULL, " : \""); //next value after any : "" string + + //set gi value based on this + if (strncmp ("GROUP", str_buffer, 5) == 0) + gi = 0; + else gi = 1; + + state->gi[0] = gi; + + //debug set value + // fprintf (stderr, " GI: %d;", gi); + + //debug print current str_buffer + fprintf (stderr, "\n Call Type: %s", str_buffer); + + } + + if (strncmp ("encrypted", str_buffer, 9) == 0) + { + str_buffer = strtok(NULL, " : \""); //next value after any : "" string + + //set enc value based on this + if (strncmp ("true", str_buffer, 4) == 0) + is_enc = 1; + else is_enc = 0; + + //reset other enc variables (filled in later on if available) + alg_id = 0; + key_id = 0; + iv_hex = 0; + + //debug set value + // fprintf (stderr, " ENC: %d;", is_enc); + + //debug print current str_buffer + fprintf (stderr, "\n Encryption: %s", str_buffer); + + } + + if (strncmp ("to", str_buffer, 2) == 0) + { + str_buffer = strtok(NULL, " : \""); //next value after any : "" string + + target = strtol (str_buffer, NULL, 10); + + state->lasttg = target; + + //debug set value + // fprintf (stderr, " Target: %d;", target); + + //debug print current str_buffer + fprintf (stderr, "\n To: %s", str_buffer); + + } + + if (strncmp ("from", str_buffer, 4) == 0) + { + str_buffer = strtok(NULL, " : \""); //next value after any : "" string + + source = strtol (str_buffer, NULL, 10); + + state->lastsrc = source; + + //debug set value + // fprintf (stderr, " Source: %d;", source); + + //debug print current str_buffer + fprintf (stderr, "\n From: %s", str_buffer); + + } + + if (strncmp ("encryption_algorithm", str_buffer, 20) == 0) + { + str_buffer = strtok(NULL, " : \""); //next value after any : "" string + + alg_id = strtol (str_buffer, NULL, 10); + + //debug set value + fprintf (stderr, "\n Alg ID: %02X;", alg_id); + + //debug print current str_buffer + // fprintf (stderr, "\n Encryption Alg: %s", str_buffer); + + } + + if (strncmp ("encryption_key_id", str_buffer, 17) == 0) + { + str_buffer = strtok(NULL, " : \""); //next value after any : "" string + + key_id = strtol (str_buffer, NULL, 10); + + //debug set value + fprintf (stderr, "\n Key ID: %04X;", key_id); + + //debug print current str_buffer + // fprintf (stderr, "\n Encryption KID: %s", str_buffer); + + } + + if (strncmp ("encryption_mi", str_buffer, 13) == 0) + { + str_buffer = strtok(NULL, " : \""); //next value after any : "" string + + uint16_t iv_len = strlen((const char*)str_buffer); + char iv_str[20]; memset(iv_str, 0, sizeof(iv_str)); + + //debug this str_buffer len + // fprintf (stderr, " IV STR LEN: %d;", iv_len); + + if (iv_len == 18) //P25 MI has an extra zero byte (two zeroes) appended to MI, remove those + iv_len = 16; + strncpy(iv_str, str_buffer, iv_len); //copy out final IV value from the MI + + iv_hex = strtoull (iv_str, NULL, 16); //Note: The 16 here is for base 16 (hex), not 16 chars + + //debug set value + fprintf (stderr, "\n IV: %016llX;", iv_hex); //not really needed if loaded into array + + //debug print current str_buffer + // fprintf (stderr, "\n Encryption MI/IV: %s", str_buffer); + + //WIP: This is the last field of enc, so we create a new keystream here, if needed + state->currentslot = 0; + state->payload_algid = alg_id; + state->payload_mi = iv_hex; + state->payload_keyid = key_id; + if (state->keyloader == 1) + keyring(opts, state); + + //TODO: Handle multi keystream creation with a new function + uint8_t ks_bytes[375]; memset(ks_bytes, 0, sizeof(ks_bytes)); + uint8_t kiv[15]; memset(kiv, 0, sizeof(kiv)); + + //Test: Setup a simple RC4 for now (working) + if ( (alg_id == 0xAA || alg_id == 0x21) && state->R != 0 ) + { + + //load key into key portion of kiv + kiv[0] = ((state->R & 0xFF00000000) >> 32); + kiv[1] = ((state->R & 0xFF000000) >> 24); + kiv[2] = ((state->R & 0xFF0000) >> 16); + kiv[3] = ((state->R & 0xFF00) >> 8); + kiv[4] = ((state->R & 0xFF) >> 0); + + //load the str_buffer into the IV portion of kiv + parse_raw_user_string(str_buffer, kiv+5); + + rc4_block_output (rc4_db, rc4_mod, 375, kiv, ks_bytes); + + unpack_byte_array_into_bit_array(ks_bytes, ks, 375); + + } //end test + + //reset ks_idx to 0 + ks_idx = 0; + + } + + if (strncmp ("hex", str_buffer, 3) == 0) + { + str_buffer = strtok(NULL, " : \""); //next value after any : "" string + + if (protocol == 1) //P25p1 IMBE + { + //debug print current str_buffer + // fprintf (stderr, "\n IMBE HEX: %s", str_buffer); + + //36 hex characters on 'hex' which is the IMBE interleaved C codewords + ks_idx = imbe_str_to_decode(opts, state, str_buffer, ks, ks_idx); + } + else if (protocol == 2) //P25p2 AMBE + { + //debug print current str_buffer + // fprintf (stderr, "\n AMBE HEX: %s", str_buffer); + + //18 hex characters on 'hex' which is the AMBE interleaved C codewords + ks_idx = ambe2_str_to_decode(opts, state, str_buffer, ks, ks_idx, is_dmra); + } + } + + if (strncmp ("time", str_buffer, 4) == 0) + { + str_buffer = strtok(NULL, " : \""); //next value after any : "" string + + char time_str[20]; memset(time_str, 0, sizeof(time_str)); + strncpy(time_str, str_buffer, 10); //full string is 13, but not copying milliseconds to match time(NULL) + + event_time = strtol (time_str, NULL, 10); + + //working now with tweak + state->event_history_s[0].Event_History_Items[0].event_time = event_time; + + //debug set value + // fprintf (stderr, " Time: %ld;", event_time); + + //what is actual time_t for time(NULL); + // fprintf (stderr, " Time(NULL): %ld;", time(NULL)); + + //convert to legible time and date format + char * timestr = getTimeN(event_time); UNUSED(timestr); + char * datestr = getDateN(event_time); UNUSED(datestr); + + //user legible time + fprintf (stderr, " Date: %s Time: %s;", datestr, timestr); + + if (timestr != NULL) + { + free (timestr); + timestr = NULL; + } + if (datestr != NULL) + { + free (datestr); + datestr = NULL; + } + + //debug print current str_buffer + // fprintf (stderr, "\n Time: %s", str_buffer); + + } + + str_buffer = strtok(NULL, " : \""); //next value after any : "" string + + if (str_buffer == NULL) + break; + + //exit loop if signal + if (exitflag == 1) + break; + } + + //free allocated memory from the source string + if (source_str != NULL) + { + free (source_str); + source_str = NULL; + } + + //watchdog for event history + watchdog_event_history(opts, state, 0); + watchdog_event_current(opts, state, 0); + + //if .imb or .amb file open, close it now + if (opts->mbe_out_f != NULL) + closeMbeOutFile (opts, state); + + //end line break + fprintf (stderr, "\n"); + } \ No newline at end of file diff --git a/src/dsd_main.c b/src/dsd_main.c index 98cc9c9..a203732 100644 --- a/src/dsd_main.c +++ b/src/dsd_main.c @@ -1412,7 +1412,7 @@ printf (" -n Audio Analog Output Gain (Default: 0 = Auto; 0-100%% )\n"); //printf (" -w Output synthesized speech to a .wav file, FDMA modes only.\n"); //disabled printf (" -6 Output raw audio .wav file (48K/1). (WARNING! Large File Sizes 1 Hour ~= 360 MB)\n"); - printf (" -7 Create/Use Custom directory for Per Call decoded .wav file saving.\n"); + // printf (" -7 Create/Use Custom directory for Per Call decoded .wav file saving.\n"); //disabled printf (" (Use ./folder for Nested Directory!)\n"); printf (" (Use /path/to/folder for hard coded directory!)\n"); printf (" (Use Before the -P option!)\n"); @@ -2223,17 +2223,17 @@ fprintf (stderr,"Writing + Appending Event History to file %s\n", opts.event_out_file); break; - case '7': //make a custom wav file directory in the current working directory -- use this before -P - strncpy(opts.wav_out_dir, optarg, 511); - opts.wav_out_dir[511] = '\0'; - if (stat(opts.wav_out_dir, &st) == -1) - { - fprintf (stderr, "%s directory does not exist\n", opts.wav_out_dir); - fprintf (stderr, "Creating directory %s to save wav files\n", opts.wav_out_dir); - mkdir(opts.wav_out_dir, 0700); - } - else fprintf (stderr,"Writing wav decoded audio files to directory %s\n", opts.wav_out_dir); - break; + // case '7': //make a custom wav file directory in the current working directory -- use this before -P + // strncpy(opts.wav_out_dir, optarg, 511); + // opts.wav_out_dir[511] = '\0'; + // if (stat(opts.wav_out_dir, &st) == -1) + // { + // fprintf (stderr, "%s directory does not exist\n", opts.wav_out_dir); + // fprintf (stderr, "Creating directory %s to save wav files\n", opts.wav_out_dir); + // mkdir(opts.wav_out_dir, 0700); + // } + // else fprintf (stderr,"Writing wav decoded audio files to directory %s\n", opts.wav_out_dir); + // break; case 'P': //Per Call Wav Files sprintf (wav_file_directory, "%s", opts.wav_out_dir); diff --git a/src/dsd_mbe.c b/src/dsd_mbe.c index ed010f2..c3e23a8 100644 --- a/src/dsd_mbe.c +++ b/src/dsd_mbe.c @@ -68,6 +68,7 @@ void playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv) int i; char imbe_d[88]; char ambe_d[49]; + srand(time(NULL)); //random seed for some file names using random numbers in file name for (i = state->optind; i < argc; i++) { @@ -100,6 +101,10 @@ void playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv) playSynthesizedVoiceFM (opts, state); } } + else if (state->mbe_file_type == 3) + { + read_sdrtrunk_json_format (opts, state); + } else if (state->mbe_file_type > 0) //ambe files { readAmbe2450Data (opts, state, ambe_d); diff --git a/src/dsd_time.c b/src/dsd_time.c index 7a16cf8..06e5df4 100644 --- a/src/dsd_time.c +++ b/src/dsd_time.c @@ -79,3 +79,20 @@ char * getDateN(time_t t) return curr; } +//get HHmmss timestamp no colon (file operations) +char * getTimeF(time_t t) +{ + char * curr = calloc(7, sizeof(char)); + struct tm * ptm = localtime(& t); + sprintf(curr,"%02d%02d%02d", ptm->tm_hour, ptm->tm_min, ptm->tm_sec); + return curr; +} + +//get YYYYMMDD without hyphen (file operations) +char * getDateF(time_t t) +{ + char * curr = calloc(25, sizeof(char)); + struct tm * ptm = localtime(& t); + sprintf(curr,"%04d%02d%02d", ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday); + return curr; +}