diff --git a/CMakeLists.txt b/CMakeLists.txt index e4798d1db..055b6eba7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,7 @@ find_package(PkgConfig) find_package(Boost) find_package(FFTW3F) +find_package(LibMbe) IF(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64|x86") SET(USE_SIMD "SSE2" CACHE STRING "Use SIMD instructions") @@ -372,6 +373,10 @@ qt5_use_modules(sdrangel Widgets Multimedia) add_subdirectory(plugins) +if(LIBMBE_FOUND) + add_subdirectory(dsd) +endif(LIBMBE_FOUND) + if(LIBUSB_FOUND AND UNIX) add_subdirectory(fcdhid) add_subdirectory(fcdlib) diff --git a/cmake/Modules/FindLibMbe.cmake b/cmake/Modules/FindLibMbe.cmake new file mode 100644 index 000000000..9e5528ab5 --- /dev/null +++ b/cmake/Modules/FindLibMbe.cmake @@ -0,0 +1,22 @@ +# Find libmbe + +FIND_PATH(LIBMBE_INCLUDE_DIR mbelib.h) + +SET(LIBMBE_NAMES ${LIBMBE_NAMES} mbe libmbe) +FIND_LIBRARY(LIBMBE_LIBRARY NAMES ${LIBMBE_NAMES} PATH) + +IF (LIBMBE_INCLUDE_DIR AND LIBMBE_LIBRARY) + SET(LIBMBE_FOUND TRUE) +ENDIF (LIBMBE_INCLUDE_DIR AND LIBMBE_LIBRARY) + +IF (LIBMBE_FOUND) + IF (NOT LibMbe_FIND_QUIETLY) + MESSAGE (STATUS "Found LibMbe: ${LIBMBE_LIBRARY}") + ENDIF (NOT LibMbe_FIND_QUIETLY) +ELSE (LIBMBE_FOUND) + IF (LibMbe_FIND_REQUIRED) + MESSAGE (FATAL_ERROR "Could not find mbe") + ENDIF (LibMbe_FIND_REQUIRED) +ENDIF (LIBMBE_FOUND) + +mark_as_advanced(LIBMBE_INCLUDE_DIR LIBMBE_LIBRARY) diff --git a/dsd/.gitmodules b/dsd/.gitmodules new file mode 100644 index 000000000..50e20f6ad --- /dev/null +++ b/dsd/.gitmodules @@ -0,0 +1,3 @@ +[submodule "samples"] + path = samples + url = https://github.com/szechyjs/dsd-samples.git diff --git a/dsd/CHANGELOG b/dsd/CHANGELOG new file mode 100644 index 000000000..67315b44b --- /dev/null +++ b/dsd/CHANGELOG @@ -0,0 +1,98 @@ +1.7.0-dev + New features: + CMake build system replaces Makefile + Use libsndfile for reading and writing audio files + Initial DSTAR voice support + +1.6.0 + New features: + Auto mutes P25 encrypted signals by default. + Raised cosine filters. + + Fixed bugs: + Changed the crazy dibit buffer which filled for ever until it + ran out of allocated memory then caused a segmentation error. The + buffer is now allowed to fill to 90% before being returned to the + initial pointer value where it over writes the old samples, it + seems to work ok and no segmentation errors now. + Input level is now calculated differently, before when it reported 50% + the soundcard would be fully overloaded. With the new method aim for 30% inlvl. + +1.4.1 + New features: + Several new sync types for existing formats now recognized: + Decodes voice from NXDN 4800 (6.25kHz) signals + Decodes voice from NXDN 9600 (12.5kHz) repeater output + Decodes voice from DMR/MotoTRBO simplex/repeater input + Decodes voice from X2-TDMA simplex/repeater input + + Fixed bugs: + renamed "input:" to "inlvl:" to reduce confusion. This value + indicates the audio input level, NOT the "decode success + rate". Voice decode errors are indicated by the errorbars "=". + +1.4 + New features: + Decodes voice from NXDN 9600 (12.5 kHz) simplex/repeater input + NXDN96 frames enabled by default + Improved resistance to NXDN96 sync false positives + + Fixed bugs: + .wav file header updated after playing .imb/.amb data files + .imb/.amb files now have correct tgid in filename + +1.3.1 New features: + Support for ProVoice EA sync + CTRL-C is now caught so .wav files can be properly closed + DSD now shows mbelib version as well as it's own version + -R resume option now triggers on any TSDU so control channels can be left + in conventional scanlists. + Auto output gain now has 0.5 second hold time for faster error burst recovery + (was 1.5 seconds) + Audio output upsampling function simplified and improved + + Fixed bugs: + DSD_Author.pgp now has correct public key (was copy of mbelib_Author key) + TGID and SRC are now cleared after TDULC or TDU. + Voice error counter is now reset in noCarrier() + TGID and SRC were not displaying for X2-TDMA frames + Fixed buffer issue in resumeScan() + Fixed error in .wav file headers preventing playback on some apps + +1.3 New features: + Decodes voice from ProVoice signals (requires -fp option) + algid and kid are now shown in hex notation + + Fixed bugs: + auto output gain now has faster rise time + MoTDMA is now correctly labeled X2-TDMA + +1.2 New features: + Decodes voice for DMR standard (including MOTOTRBO) + Full metadata (src, talkgroup, lcinfo, mfid, lcformat, mi, algid, keyid) for X2-TDMA + TDMA slot identification for X2-TDMA/DMR/MOTOTRBO + Identifies non-voice frame types for X2-TDMA/DMR/MOTOTRBO + Frame only (no voice yet) support for 9600 baud NXDN + Auto leveling audio output gain (default) and -g option for fixed gain + GFSK modulation optimizations and improved C4FM/GFSK/QPSK auto detect + + Fixed bugs: + nac was showing wrong ID + P25 metadata (lcinfo, mfid, lfcormat, mi, keyid, algid, lsd) are now + printed out in the correct bit order (MSB -> LSB), was reversed. + fixed serveral bugs in dsd_upsample.c, with improved quality + +1.1 New features: + Scanner control options to allow scan resume during certain TDULC + Improved upsampling function audio quality + Greatly improved handling of X2-TDMA frames + Much faster QPSK decision point tracking by default + + Fixed bugs: + playMbeFiles was not output to .wav file when -w was given + Now correctly detects/handles Mot and P25 talkgroup formats + PDU frames were not detected + +1.0.3 Fixed buggy C4FM/QPSK auto detection and added -A option to adjust it. + +1.0 Initial release diff --git a/dsd/CMakeLists.txt b/dsd/CMakeLists.txt new file mode 100644 index 000000000..29a3c83b8 --- /dev/null +++ b/dsd/CMakeLists.txt @@ -0,0 +1,71 @@ +project(dsd) + +set(dsd_SOURCES + dmr_data.c + dmr_voice.c + dsd_audio.c + dsd_cleanupexit.c + dsd_dibit.c +# dsd_file.c + dsd_filters.c + dsd_frame_sync.c + dsd_frame.c + dsd_livescanner.c + dsd_mbe.c + dsd_nocarrier.c + dsd_opts.c + dsd_symbol.c + dsd_upsample.c + dstar_header.c + dstar.c + nxdn_data.c + nxdn_voice.c + nxdn96.c + p25_lcw.c + p25p1_hdu.c + p25p1_ldu1.c + p25p1_ldu2.c + p25p1_tdulc.c + provoice.c + x2tdma_data.c + x2tdma_voice.c +) + +set(dsd_HEADERS + config.h + descramble.h + dmr_const.h + dsd_cleanupexit.h + dsd_livescanner.h + dsd_nocarrier.h + dsd_opts.h + dsd_state.h + dsd.h + dstar_const.h + dstar_header.h + fcs.h + nxdn_const.h + nxdn96_const.h + p25p1_const.h + p25p1_heuristics.h + provoice_const.h + x2tdma_const.h +) + +include_directories( + ${PROJECT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${LIBMBE_INCLUDE_DIR} +) + +SET(LIBS ${LIBS} ${LIBMBE_LIBRARY}) + +add_definitions(-DQT_SHARED) + +add_library(dsd SHARED + ${dsd_SOURCES} +) + +target_link_libraries(dsd ${LIBS}) + +install(TARGETS dsd DESTINATION lib) \ No newline at end of file diff --git a/dsd/COPYRIGHT b/dsd/COPYRIGHT new file mode 100644 index 000000000..1d3e29c55 --- /dev/null +++ b/dsd/COPYRIGHT @@ -0,0 +1,29 @@ +dstar_header.c/h, descramble.h, and fcs.h are under the following license: + +dstar_header.c/h and fcs.h: Copyright (C) 2010 by Kristoff Bonne, ON1ARF +descramble.h: Copyright (C) 2011 by Jonathan Naylor, G4KLX + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; version 2 of the License. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +All other code is under the following license: + +Copyright (C) 2010 DSD Author +GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/dsd/DSD_Author.pgp b/dsd/DSD_Author.pgp new file mode 100644 index 000000000..cdc0327c9 --- /dev/null +++ b/dsd/DSD_Author.pgp @@ -0,0 +1,30 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.10 + +mQENBEufuqsBCADAtWFE1qE3xqJE4xggUn6id0fVulM7y+rSH1VPxo7Ps9duc/O9 +VegEx8+N5KphDROS4RgHxMiS1O8Qy5Hpq4gEp6RvLNj3s+0DMwqRZoA0tBCkNmvF +K7sF+GncrOu/NZkDIZ8emN9NWWeWynWJvuM2H5HQA9yCq+YTFae5sgyr3APC3xh4 +OkTuVMcclGTJdVrISlNBDpo/AZLJ/nV0SgITpiZVsI4RSNiQPP1kX+2fIDEAwtxN +3HIDyegDoX36cOItsb05zHkLxoUoZnWoxMvV3rwnqXg5cr6PWfiwgqWd0avl1sg6 +abpR6MKV68OCpTkqMrDIXJJrM2sTz+ZB2bBtABEBAAG0CkRTRCBBdXRob3KJATgE +EwECACIFAkufuqsCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEPqiY10/ +HX/Q11UH/0ZutGQWLZyZD5ZqVdBeYEf6IKhKhaC2vD/+5zUJ2cIgT5xJVTPCKN7X +sygBANJc9GyPRYRvQecdcTHR5B+wUKCPeibv9iQuU3v7Uqb5edXEh2b4jOMWNvHJ +l3lqBdUefuQdbc2xXCPgn+GkyexXEBsVF3hCzWV9r4bCpY57iWUYZZT0wAbN81hz +jPKCCRmF+gZUUufxyhUGq/+eAKeUll6lgG5Ms2YKOlUMphfMav45qgWZHj1DASOV +wPsiIVUaC6+GtHTTzHYRL05ydxxduX+yyKDO1emCE4fx1n3jdwToHLRrC1ui+AJM +Q1s+bp+bGmMYaYaKc/JtNHcN8mbWyCK5AQ0ES5+6qwEIAJvPrnv2QO5Be3FRsnYL +qbA1h/Lj0SjnuimaiNOzCYFIYtusLpyWjwWUnOEXdw5FoExqUStOHJ557SDG/zFB +qy+DsNC9ncSRZ5U2tUQUtt50m2lpYvoy/sVf3oN+IsyZ5hZpiAwrxlyMC/aoGR3C +6ZlLkZ42azNCmEmoBniIxQ+XwhwkLMRsOnqLoFyXB9CcDFIXeEhZkVWZT0B5+20f +yGSBDJ6VcIAASoaIyvSwU9l/DT7D/s0J8WnZQZmRdrsZ3Ikj0Sv/4D2MJnCVJTSw +DHq5Sf7DmUq/WD0iWRLEXWmPt9w3WxP4imhtmIpICxCDoeQUTkqFpOTf29sVcpPt +838AEQEAAYkBHwQYAQIACQUCS5+6qwIbDAAKCRD6omNdPx1/0O8ECADAcPORjGFl +RnIrsgiVMp82GQ7hnZZxktU1WVVx8EsPTT1DD79nIoeKI+UcenzuOGyTX7DGcy+P +rWntUbt2ZygPTbP5Wu6zd845y9EzjxQ5q0vDF4oAefQptwqGDVeO/KBv9cZLbnih +VEjQELgC/rVB7nd5p83EL5vb8qL/Eiu65stxwZ3QOT9pp2bsAPk6LJWWnVqJroKI +Pc6KWG7n6mMJPbhFmE8Ld2lcNlSKQwLHIxDocL2GAqh5S5hJeGg2oLMFpy0g2Ron +643w0zPfpKC15TlnkJDCIgtRlHovrs42Qkypz9y3e8yOL9O0RLYIKbuKw4mNR3cT +OdeV+TjfiZ5I +=2oe6 +-----END PGP PUBLIC KEY BLOCK----- diff --git a/dsd/README.md b/dsd/README.md new file mode 100644 index 000000000..ce11a5444 --- /dev/null +++ b/dsd/README.md @@ -0,0 +1,561 @@ +# Digital Speech Decoder 1.7.0-dev +Copyright (C) 2010 DSD Author +GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + PERFORMANCE OF THIS SOFTWARE. + +DSD is able to decode several digital voice formats from discriminator +tap audio and synthesize the decoded speech. Speech +synthesis requires mbelib, which is a separate package. + + +### Supported formats + +#### P25 Phase 1 + +Widely deployed radio standard used in public safety and amateur radio. + +Support includes decoding and synthesis of speech, +display of all link control info, and the ability to save +and replay .imb data files + +#### ProVoice + +EDACS Digital voice format used by public safety and amateur radio. + +Support includes decoding and synthesis of speech and +the ability to save and replay .imb data files. + +Note: not enabled by default, use `-fp` to enable. + +#### X2-TDMA + +Two slot TDMA system currently being deployed by several +public safety organizations. Based on the DMR +standard with extensions for P25 style signaling. + +Support includes decoding and synthesis of speech, +display of all link control info, and the ability to save +and replay .amb data files + +#### DMR/MOTOTRBO + +"Digital Mobile Radio" Eurpoean two slot TDMA standard. +MOTOTRBO is a popular implementation of this standard. + +Support includes decoding and synthesis of speech and +the ability to save and replay .amb data files. + +#### NXDN + +Digital radio standard used by NEXEDGE and IDAS brands. +Supports both 9600 baud (12.5 kHz) and +4800 baud (6.25 kHz) digital voice. + +Support includes decoding and synthesis of speech and +the ability to save and replay .amb data files. + +#### D-STAR + +Amateur radio digital voice standard + +This is an earlier version of the AMBE codec than the one +used by most of the protocols. Support for this was added by +various developers. + +### Unsupported formats in version 1.6 considered for future development: + +#### P25 Phase 2 + +This is not yet a published standard. Full support is +expected once the standard is published and there are +systems operating to test against. Phase 2 will use +a vocoder supported by mbelib. + +#### OpenSKY + +It is possible that the four slot version uses a vocoder +supported by mbelib. The two slot version does not. + +### Supported demodulation optimizations in version 1.6: + +#### C4FM + +Continuous envelope 2 or 4 level FSK with relatively +sharp transitions between symbols. Used by most P25 +systems. + +Optimizations include calibrating decision points only +during sync, 4/10 sample window per symbol, and symbol +edge timing calibration. + +#### GFSK + +Continuous envelope 2 or 4 level FSK with a narrower +Gaussian/"raised cosine" filter that affects transitions +between symbols. Used by DMR/MOTOTRBO, NXDN and many +others. Noisy C4FM signals may be detected as GFSK + +but this is ok, the optimization changes will help with +noisy signals. + +Optimizations are similar to C4FM except symbol transitions +are only kept out of the middle 4 samples and only the +middle two samples are used. + +#### QPSK + +Quadrature Phase Shift Keying (and variants) used in +some P25 systems and all known X2-TDMA systems. May be +advertised under the marketing term "LSM" + +Optimizations include continuous decision point +calibration, using middle two samples, and using the +symbol midpoint "spike" for symbol timing. + +## Installation + +DSD should easily compile on any Linux or *BSD system with gcc. +There are some debugging/development options in `config.h` that +normal users will want to leave disabled as they can severely +impact performance. + +### Requirements +* cmake +* mbelib +* sndfile + +### Example building instructions on Ubuntu: + +```` +sudo apt-get update +sudo apt-get install git make cmake # Update packages +git clone # Something like: git@github.com:USERNAME/dsd.git +cd dsd # Move into source folder +mkdir build # Create build directory +cd build # Move to build directory +cmake .. # Create Makefile for current system +make # Compiles DSD +sudo make install # Installs DSD to the system +```` + +## Operation + +There are two main operating modes, "Live scanner" and "Play files" + + Usage: dsd [options] Live scanner mode + +Live Scanner mode takes 48KHz/16 bit mono audio samples from a +sound card input and decodes speech in real time. Options are provided +for controling information display and saving mbe data files. + +The synthesized speech can be output to a soundcard and/or a +.wav file. + + Usage: dsd [options] -r Read/Play saved mbe data from file(s) + + +Play files mode reads mbe data from files specified on the command +line (including wildcards) and synthesizes speech from those files. +The synthesized speech can be output to a soundcard and/or a +.wav file. The `-r` command line options is used to activate Play files +mode. + +### Display modes + +There are two main display modes in Live scanner mode. "Errorbars" +and "Datascope". + +Errorbars mode output for P25 Phase 1 looks like this: + +```` +Sync: -P25p1 mod: C4FM inlvl: 39% nac: 5C2 src: 0 tg: 32464 TDULC +Sync: -P25p1 mod: C4FM inlvl: 39% nac: 5C2 src: 0 tg: 32464 TDULC +Sync: -P25p1 mod: C4FM inlvl: 39% nac: 5C2 src: 0 tg: 32464 TDULC +Sync: -P25p1 mod: C4FM inlvl: 39% nac: 5C2 src: 0 tg: 32464 TDULC +Sync: -P25p1 mod: C4FM inlvl: 38% nac: 5C2 src: 0 tg: 32464 TDU +Sync: -P25p1 mod: C4FM inlvl: 38% nac: 5C2 src: 0 tg: 32464 HDU +Sync: -P25p1 mod: C4FM inlvl: 42% nac: 5C2 src: 0 tg: 32464 LDU1 e: +Sync: (-P25p1) mod: C4FM inlvl: 39% nac: 5C2 src: 52610 tg: 32464 (LDU2) e: +Sync: -P25p1 mod: C4FM inlvl: 38% nac: 5C2 src: 52610 tg: 32464 LDU1 e: +Sync: -P25p1 mod: C4FM inlvl: 39% nac: 5C2 src: 52610 tg: 32464 LDU2 e: +Sync: -P25p1 mod: C4FM inlvl: 39% nac: 5C2 src: 52610 tg: 32464 LDU1 e: +Sync: -P25p1 mod: C4FM inlvl: 39% nac: 5C2 src: 52610 tg: 32464 LDU2 e: +Sync: -P25p1 mod: C4FM inlvl: 39% nac: 5C2 src: 52610 tg: 32464 LDU1 e: +```` + +* "Sync" indicates the frame type detected and whether the polarity is +positive or negative. DSD automatically detects and handles either +polarity except for DMR/MOTOTRBO/X2-TDMA which unfortunatley use both +sync polarities. + +* Most combinations of transmitter, receiver and soundcard show netagive +(-) polarity for X2-TDMA signals and (+) polarity for DMR/MOTOTRBO so +those are the defaults. + + * You may need to use the `-x` option to select non-inverted polarity if + you are not getting usable X2-TDMA/MOTOTRBO/DMR speech. As they use both + normal and inverted sync it is not possible to detect polariy + automatically. + +* "mod" indicates the current demodulation optimizations. + +* "inlvl" indicates the audio input level. QPSK signals tend to appear +much "wider" than C4FM from a discriminator tap so it is important +to set your input gain using a QPSK signal if you plan to montir them. +It is not necessary nor desirable to get to 100%, in fact your sound +card may max out below 100%. It is best to use the Datascope mode for +setting input gain (see below). Typical values with good results are +40% for C4FM and 66% for QPSK. + +* "nac" is the P25 Phase 1 Network Access Code. This is a 12 bit field +in each P25 Phase 1 header. It should not be confused with the 16 +bit System ID used in non-P25 trunking control channels. + +* "src" is the radio id of the trasmitting subscriber unit. + +* "tg" is the talkgroup derived from link control information. + +* "HDU/LDU1/LDU2/TDU/TDULC" are P25 Phase 1 frame types, referred to as +frame subtype within DSD. + +* "e:" is the beginning of the errorbars display. Each "=" indicates a +detected error within the voice data. "R" and "M" indicat that a voice +frame was repeated or muted due to excessive errors. + +* Values in parentheses () indicate an assumption (soft decision) was +made based on the previous frame. + +Errorbars mode output for X2-TDMA looks like this: +```` +Sync: -X2-TDMA mod: QPSK inlvl: 59% src: 17211 tg: 197 [SLOT0] slot1 VOICE e: +Sync: -X2-TDMA mod: QPSK inlvl: 47% src: 17211 tg: 197 [SLOT0] slot1 VOICE e: +Sync: -X2-TDMA mod: QPSK inlvl: 43% src: 17211 tg: 197 [SLOT0] slot1 VOICE e: +Sync: (-X2-TDMA) mod: QPSK inlvl: 28% src: 17211 tg: 197 [SLOT0] slot1 VOICE e: +```` + +DMR/MOTOTRBO display is similar except it does not yet show source +and talkgroup information. + +As of version 1.2 DSD shows which specific TDMA slots are active (with +capital SLOT letters) and which slot is currently being monitored (with +square brackets []. Noisy/degraded signals will affect the accuracy +of this display. + +The frame subtypes (Voice/LC etc) are shown based on the DMR standard +types. + +Datascope mode output looks like this: + +```` +Demod mode: C4FM Nac: 8C3 +Frame Type: P25 Phase 1 Talkgroup: 16528 +Frame Subtype: LDU1 Source: 0 +TDMA activity: slot0 slot1 Voice errors: ++----------------------------------------------------------------+ +| # ^ !| ^ # | +| * | * | +| * | * | +| * | * * | +| * * | * * | +| * * | ** * | +| * ** | ** * | +| ** ** | ** * | +| ** ** | ** * | +| ** ** | ** * | ++----------------------------------------------------------------+ + C4FM Example +```` +```` +Demod mode: C4FM Nac: 126 +Frame Type: P25 Phase 1 Talkgroup: 25283 +Frame Subtype: LDU2 Source: 0 +TDMA activity: slot0 slot1 Voice errors: ++----------------------------------------------------------------+ +| # ^ ! ^ # | +| * | | +| * | | +| ** | | +| ** | * | +| * ** | * * | +| ** ** | * * | +| *** ** | ** * | +| *** ** | *** * | +| *** **** | **** * * | ++----------------------------------------------------------------+ + QPSK Example +```` + +At the top is various information about the signal, similar to the +information provided in Errorbars mode. The large box is similar to +a spectrum analyzer viewing the channel bandwidth. + +The horizontal axis is the input audio level, minimum on the left and +maximum on the right. The vertical axis is the number of samples +seend at each audio level. + +The "*" symbols represent the number of audio +samples that were at each level during the aggregation period. +(default = 36 symbols) The `-S` options controls the aggregation period +as well as the QPSK tracking symbol buffer, so changing that will affect +QPSK performance as well as the Datascope display. + +As you can see from the figures above, clean C4FM signals tend to have +four very sharply defined audio levels. The datascope pattern also +tends to be faily stable with minor shifts left and right as the +receiver tries to frequency track any DC offset. + +QPSK signals on the other hand tend to appear much broader (and artifact +of how they are distored by FM PLL discriminators). They also tend +to vary wildly in width and centering. This is especially true when +monitoring simulcast systems. Muliple QPSK signals interfere much more +dramatically with an FM discriminator than C4FM signals. + + For this reason it is important to isolate your receiver to one + transmitter tower, _especially_ for QPSK signals. + + The "#" symbols indicate the detected min/max values that are used + to calibrate the symbol decision points. These are indicated by + "!" for the center decision point and "^" for the mid decision points. + +### Display Options + +There are several options to control the type and quantity of +information displayed in Errorbars mode: + +```` +-e Show Frame Info and errorbars (default) +-pe Show P25 encryption sync bits +-pl Show P25 link control bits +-ps Show P25 status bits and low speed data +-pt Show P25 talkgroup info +-q Don't show Frame Info/errorbars +-s Datascope (disables other display options) +-t Show symbol timing during sync +-v Frame information Verbosity +-z Frame rate for datascope +```` + +Most of these options are self explanitory. Symbol timing is a noisy +option that allows you to view the quality of the frame sync samples +and accuracy of the symbol timing adjustments. + +Symbol Timing display looks like this: +```` +Symbol Timing: +---------- +---------- +---------- +---------- +---------- +-+++++++++ 1 ++---------- 0 +---------- +++++++++++ 0 +++++++++++ +---------- 0 +---------- +++++++++++ 0 +++++++++++ +++++++++++ +++++++++++ +---------- 0 +++++++++++ 0 +---------- 0 +++++++++++ 0 +++++++++++ +++++++++++ +++++++++++ +++++++++++ +C4FM example +```` +```` +Symbol Timing: ++--------- +---------- +---------- +---------- +-----X---- 5 +--+++O++++- 4 +---------- +----X----- 4 +++++O++--- 4 +--++O++++- 4 +----X----- 4 +---------- +++++O+++-- 4 +-+++O+++-- 4 +--++O+++-- 4 +--++O+++-- 4 +---------- +++++O++++- 4 +---------- +++++O+++-- 4 +-+++O++++- 4 +-+++O+++++ 4 +-+++O++--- 4 +--++O+++-- 4 +QPSK example +```` + +Symbol timing is only displayed for symbols during the frame sync +period. Each horizontal line represents the 10 audio samples for each +symbol. "-" indicates an audio sample below the center reference level +and "+" represents a sample above center. "X" indicates a low spike +below a reference threshold (reference minimum for C4FM and 80% +of reference minimum for QPSK). "O" represents a high spike above +the high reference threshold. The numbers to the right indicate which +sample position the targeted transition occurred (+/- for C4FM or +spike high/low for QPSK). The number of audio samples for the next +symbol are adjusted to get this value closer to the target (0 for +C4FM and 4 for QPSK). This shows how DSD maintains accurate symbol +timing. Symbol timing adjustments are only made during sync, which +is the only time reliable transitions can be observed. + +In both examples above the symbol timing was off by one sample at +the beginning of the frame sync period and was adjusted. Generally +if you see any spike values "X/O" in C4FM mode, or lots of them in +QPSK mode it indicates noise on the input signal. + +### Input/Output Options + +```` +-i Audio input device/file (default is /dev/audio) +-o Audio output device (default is /dev/audio) +-d Create mbe data files, use this directory +-r Read/Play saved mbe data from file(s) +-g Audio output gain (default = 0 = auto) +-n Do not send synthesized speech to audio output device +-w Output synthesized speech to a .wav file +```` + +The audio in device can be a sound card OR a .wav file if the file +is in the exact format 48k/16bits/mono/pcm. Audio in should be an +unfilterd discriminator tap signal. + +The audio out device should be a sound card (use the `-w` options to +output to a .wav file). + +If the audio in device is the same as the audio out device, the +synthesized speech has to be upsampled to the 48k sample rate required +for input. A fast upsample function is provided but still leaves some +artifacts. + + The best sound and minimum cpu usage is achieved with separate sound + cards for input and output + +If you specify different input/output devices DSD will use 8k as the +output sample rate and the lack of resampling results in much better +audio as well as lowe cpu consumption. + +If you are using onboard "AC97" sound device you may find that DSD uses +much more cpu than expected, in some cases more than is available. +This is because many AC97 sound devices are designed to rely on CPU +processing power instead of hardware. You may also find that 8k sample +rate output is upsampled in the driver using a very basic algorithim +resulting in severe distortion. The solution is to use a real hardware +sound device (pci card, usb device etc). + +As of version 1.2 DSD now automatically levels the output audio. This +greately improves readability and eliminates the painful effects of +noise bursts. You can specify a fixed audio output gain with the -g +option. + +### Scanner control options: +```` +-B Serial port baud rate (default=115200) +-C Serial port for scanner control (default=/dev/ttyUSB0) +-R Resume scan after TDULC frames or any PDU or TSDU +```` + +On some P25 systems Packet Data Units (PDU) are sent on the same +frequencies used for voice traffic. If done constantly this can +be a severe hinderance to scanning the system in conventional +mode. The -R option enables sending a "resume scan" command to +a scanner connected to a serial port. Use `-B` and `-C` to set the baud +rate and serial port device if necessary. + +### Decoder options +```` +-fa Auto-detect frame type (default) +-f1 Decode only P25 Phase 1 +-fd Decode only D-STAR* +-fi Decode only NXDN48* (6.25 kHz) / IDAS* +-fn Decode only NXDN96 (12.5 kHz) +-fp Decode only ProVoice* +-fr Decode only DMR/MOTOTRBO +-fx Decode only X2-TDMA +-l Disable Filters (not recommended) +-ma Auto-select modulation optimizations (default) +-mc Use only C4FM modulation optimizations +-mg Use only GFSK modulation optimizations +-mq Use only QPSK modulation optimizations +-pu Unmute Encrypted P25 +-u Unvoiced speech quality (default=3) +-xx Expect non-inverted X2-TDMA signal +-xr Expect inverted DMR/MOTOTRBO signal +```` +\* denotes frame types that cannot be auto-detected. + +ProVoice and NXDN48 not auto-detected as use different symbol +rates (9600 and 2400) than most formats (4800). + +MBE speech synthesis is broken down into two main types of sounds, +"Voiced" and "Unvoiced". Voiced speech bands are synthesized with +a single sine wave centered in the frequency band with the appropriate +phase and amplitude. + +Unvoiced speech is supposed to be generated with a noise source, 256 +point DFT a number of band filters, followed by a 256 point inverse DFT. +For computational simplicity mbelib uses a different method. For each +unvoiced speech band, a number of sine waves are generated, each with a +different random initial phase. The number of waves used per band is +controlled by the `-u` option. A setting of 4 would approximate the +performance of the 256 point DFT method as the maximum number of voice +bands is 56, and very low frequencies are not synthesized. Values less +than 3 have a noticable lack of unvoiced speech and/or artifacts. The +defualt of 3 provides good speech quality with reasonable cpu use. +Increasing the quality above the default rapidly consumes more CPU for +increasingly diminishing returns. + + +#### Advanced decoder options +```` +-A QPSK modulation auto detection threshold (default=26) +-S Symbol buffer size for QPSK decision point tracking + (default=36) +-M Min/Max buffer size for QPSK decision point tracking + (default=15) +```` + +### Encryption + +Decryption of speech is **NOT** supported, even if you lawfully posess the +encryption keys. Decryption support will not be added in the future as +the authors wish to steer as far away from the legal issues associated +with encryption as possible. + + + We realize that there are many legitemate and lawful uses of decryption + software including system/interoperability testing and lawful monitoring. + This software is distributed under a liberal BSD license so there is + nothing to stop others from supplying patches, forking this project or + incorporating it into a commercial product and adding decryption support. + + There is support for displaying the encryption sync bits transmitted in + the clear on P25 Phase 1 systems. These bits do not allow for the + decryption of signals without the secret encryption keys. The + encryption sync bits are useful for determining whether a signal is + encrypted vs merely noisy or degraded. As the encryption sync bits + typically include long strings of zeros when a transmission is not + encrypted they can also be used to visually estimate bit error rates. diff --git a/dsd/cmake/FindLibMbe.cmake b/dsd/cmake/FindLibMbe.cmake new file mode 100644 index 000000000..cfcbbdec8 --- /dev/null +++ b/dsd/cmake/FindLibMbe.cmake @@ -0,0 +1,20 @@ +# Find libmbe + +FIND_PATH(LIBMBE_INCLUDE_DIR mbelib.h) + +SET(LIBMBE_NAMES ${LIBMBE_NAMES} mbe libmbe) +FIND_LIBRARY(LIBMBE_LIBRARY NAMES ${LIBMBE_NAMES} PATH) + +IF (LIBMBE_INCLUDE_DIR AND LIBMBE_LIBRARY) + SET(LIBMBE_FOUND TRUE) +ENDIF (LIBMBE_INCLUDE_DIR AND LIBMBE_LIBRARY) + +IF (LIBMBE_FOUND) + IF (NOT LibMbe_FIND_QUIETLY) + MESSAGE (STATUS "Found LibMbe: ${LIBMBE_LIBRARY}") + ENDIF (NOT LibMbe_FIND_QUIETLY) +ELSE (LIBMBE_FOUND) + IF (LibMbe_FIND_REQUIRED) + MESSAGE (FATAL_ERROR "Could not find mbe") + ENDIF (LibMbe_FIND_REQUIRED) +ENDIF (LIBMBE_FOUND) diff --git a/dsd/cmake/FindLibSndFile.cmake b/dsd/cmake/FindLibSndFile.cmake new file mode 100644 index 000000000..32ec92583 --- /dev/null +++ b/dsd/cmake/FindLibSndFile.cmake @@ -0,0 +1,21 @@ +# Find libsndfile + +FIND_PATH(LIBSNDFILE_INCLUDE_DIR sndfile.h) + +SET(LIBSNDFILE_NAMES ${LIBSNDFILE_NAMES} sndfile libsndfile) +FIND_LIBRARY(LIBSNDFILE_LIBRARY NAMES ${LIBSNDFILE_NAMES} PATH) + +IF (LIBSNDFILE_INCLUDE_DIR AND LIBSNDFILE_LIBRARY) + SET(LIBSNDFILE_FOUND TRUE) +ENDIF (LIBSNDFILE_INCLUDE_DIR AND LIBSNDFILE_LIBRARY) + +IF (LIBSNDFILE_FOUND) + IF (NOT LibSndFile_FIND_QUIETLY) + MESSAGE (STATUS "Found LibSndFile: ${LIBSNDFILE_LIBRARY}") + ENDIF (NOT LibSndFile_FIND_QUIETLY) + add_definitions(-DUSE_LIBSNDFILE) +ELSE (LIBSNDFILE_FOUND) + IF (LibSndFile_FIND_REQUIRED) + MESSAGE (FATAL_ERROR "Could not find sndfile") + ENDIF (LibSndFile_FIND_REQUIRED) +ENDIF (LIBSNDFILE_FOUND) diff --git a/dsd/cmake/git_revision.cmake b/dsd/cmake/git_revision.cmake new file mode 100644 index 000000000..fcfbdf0c3 --- /dev/null +++ b/dsd/cmake/git_revision.cmake @@ -0,0 +1,130 @@ +# - Returns a version string from Git +# +# These functions force a re-configure on each git commit so that you can +# trust the values of the variables in your build system. +# +# get_git_head_revision( [ ...]) +# +# Returns the refspec and sha hash of the current head revision +# +# git_describe( [ ...]) +# +# Returns the results of git describe on the source tree, and adjusting +# the output so that it tests false if an error occurs. +# +# git_get_exact_tag( [ ...]) +# +# Returns the results of git describe --exact-match on the source tree, +# and adjusting the output so that it tests false if there was no exact +# matching tag. +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2010. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +if(__get_git_revision_description) + return() +endif() +set(__get_git_revision_description YES) + +# We must run the following at "include" time, not at function call time, +# to find the path to this module rather than the path to a calling list file +get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH) + +function(get_git_head_revision _refspecvar _hashvar) + set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + set(GIT_DIR "${GIT_PARENT_DIR}/.git") + while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories + set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}") + get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH) + if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT) + # We have reached the root directory, we are not in git + set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE) + set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE) + return() + endif() + set(GIT_DIR "${GIT_PARENT_DIR}/.git") + endwhile() + # check if this is a submodule + if(NOT IS_DIRECTORY ${GIT_DIR}) + file(READ ${GIT_DIR} submodule) + string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule}) + get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH) + get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE) + endif() + set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data") + if(NOT EXISTS "${GIT_DATA}") + file(MAKE_DIRECTORY "${GIT_DATA}") + endif() + + if(NOT EXISTS "${GIT_DIR}/HEAD") + return() + endif() + set(HEAD_FILE "${GIT_DATA}/HEAD") + configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY) + + configure_file("cmake/git_revision.cmake.in" + "${GIT_DATA}/grabRef.cmake" + @ONLY) + include("${GIT_DATA}/grabRef.cmake") + + set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE) + set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE) +endfunction() + +function(git_describe _var) + if(NOT GIT_FOUND) + find_package(Git QUIET) + endif() + get_git_head_revision(refspec hash) + if(NOT GIT_FOUND) + set(${_var} "GIT-NOTFOUND" PARENT_SCOPE) + return() + endif() + if(NOT hash) + set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE) + return() + endif() + + # TODO sanitize + #if((${ARGN}" MATCHES "&&") OR + # (ARGN MATCHES "||") OR + # (ARGN MATCHES "\\;")) + # message("Please report the following error to the project!") + # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}") + #endif() + + #message(STATUS "Arguments to execute_process: ${ARGN}") + + execute_process(COMMAND + "${GIT_EXECUTABLE}" + describe + ${hash} + ${ARGN} + WORKING_DIRECTORY + "${CMAKE_SOURCE_DIR}" + RESULT_VARIABLE + res + OUTPUT_VARIABLE + out + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT res EQUAL 0) + set(out "${out}-${res}-NOTFOUND") + endif() + + set(${_var} "${out}" PARENT_SCOPE) +endfunction() + +function(git_get_exact_tag _var) + git_describe(out --exact-match ${ARGN}) + set(${_var} "${out}" PARENT_SCOPE) +endfunction() diff --git a/dsd/cmake/git_revision.cmake.in b/dsd/cmake/git_revision.cmake.in new file mode 100644 index 000000000..888ce13aa --- /dev/null +++ b/dsd/cmake/git_revision.cmake.in @@ -0,0 +1,38 @@ +# +# Internal file for GetGitRevisionDescription.cmake +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2010. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +set(HEAD_HASH) + +file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024) + +string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS) +if(HEAD_CONTENTS MATCHES "ref") + # named branch + string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") + if(EXISTS "@GIT_DIR@/${HEAD_REF}") + configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) + elseif(EXISTS "@GIT_DIR@/logs/${HEAD_REF}") + configure_file("@GIT_DIR@/logs/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) + set(HEAD_HASH "${HEAD_REF}") + endif() +else() + # detached HEAD + configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY) +endif() + +if(NOT HEAD_HASH) + file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) + string(STRIP "${HEAD_HASH}" HEAD_HASH) +endif() diff --git a/dsd/cmake_uninstall.cmake.in b/dsd/cmake_uninstall.cmake.in new file mode 100644 index 000000000..4dc1b63a4 --- /dev/null +++ b/dsd/cmake_uninstall.cmake.in @@ -0,0 +1,23 @@ +if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") +endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + +file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +string(REGEX REPLACE "\n" ";" files "${files}") +cmake_policy(SET CMP0007 OLD) +list(REVERSE files) +foreach (file ${files}) + message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") + if (EXISTS "$ENV{DESTDIR}${file}") + execute_process( + COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}" + OUTPUT_VARIABLE rm_out + RESULT_VARIABLE rm_retval + ) + if(NOT ${rm_retval} EQUAL 0) + message(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") + endif (NOT ${rm_retval} EQUAL 0) + else (EXISTS "$ENV{DESTDIR}${file}") + message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") + endif (EXISTS "$ENV{DESTDIR}${file}") +endforeach(file) \ No newline at end of file diff --git a/dsd/config.h b/dsd/config.h new file mode 100644 index 000000000..a0eccf9dc --- /dev/null +++ b/dsd/config.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * System target + */ +#define BSD // bsd/linux audio interface +//#define SOLARIS // solaris audio interface, untested + +/* + * noisy debug/development options + */ +//#define X2TDMA_DUMP // cach and sync bits dump +//#define DMR_DUMP +//#define DSTAR_DUMP // dstar frame dump +//#define NXDN_DUMP +//#define UPSAMPLE_DEBUG +//#define PROVOICE_DUMP diff --git a/dsd/configure b/dsd/configure new file mode 100755 index 000000000..b27b5a82d --- /dev/null +++ b/dsd/configure @@ -0,0 +1,3 @@ +#!/bin/sh + +echo "There is no configure script, just run make" diff --git a/dsd/descramble.h b/dsd/descramble.h new file mode 100644 index 000000000..c167f7b77 --- /dev/null +++ b/dsd/descramble.h @@ -0,0 +1,293 @@ +/* descramble.h */ + +// Functions for processing the radio-header: +// descramble +// deinterleave +// FECdecoder + +// (C) 2011 Jonathan Naylor G4KLX + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +// This code was originally written by JOnathan Naylor, G4KLX, as part +// of the "pcrepeatercontroller" project +// More info: +// http://groups.yahoo.com/group/pcrepeatercontroller + + + +// Changes: +// Convert C++ to C + +// Version 20111106: initial release + + + + +#include +#include + +// function traceBack +int traceBack (int * out, int * m_pathMemory0, int * m_pathMemory1, int * m_pathMemory2, int * m_pathMemory3) { + enum FEC_STATE { S0, S1, S2, S3 } state; + int loop; + int length=0; + + state=S0; + + for (loop=329; loop >= 0; loop--, length++) { + + switch (state) { + case S0: // if state S0 + if (m_pathMemory0[loop]) { + state = S2; // lower path + } else { + state = S0; // upper path + }; // end else - if + out[loop]=0; + break; + + case S1: // if state S1 + if (m_pathMemory1[loop]) { + state = S2; // lower path + } else { + state = S0; // upper path + }; // end else - if + out[loop]=1; + break; + + case S2: // if state S2 + if (m_pathMemory2[loop]) { + state = S3; // lower path + } else { + state = S1; // upper path + }; // end else - if + out[loop]=0; + break; + + case S3: // if state S3 + if (m_pathMemory3[loop]) { + state = S3; // lower path + } else { + state = S1; // upper path + }; // end else - if + out[loop]=1; + break; + + }; // end switch + }; // end for + +return(length); +}; // end function + + + +// function viterbiDecode + +void viterbiDecode (int n, int *data, int *m_pathMemory0, int *m_pathMemory1, int *m_pathMemory2, int *m_pathMemory3, int *m_pathMetric) { + int tempMetric[4]; + int metric[8]; + int loop; + + int m1; + int m2; + + metric[0]=(data[1]^0)+(data[0]^0); + metric[1]=(data[1]^1)+(data[0]^1); + metric[2]=(data[1]^1)+(data[0]^0); + metric[3]=(data[1]^0)+(data[0]^1); + metric[4]=(data[1]^1)+(data[0]^1); + metric[5]=(data[1]^0)+(data[0]^0); + metric[6]=(data[1]^0)+(data[0]^1); + metric[7]=(data[1]^1)+(data[0]^0); + + // Pres. state = S0, Prev. state = S0 & S2 + m1=metric[0]+m_pathMetric[0]; + m2=metric[4]+m_pathMetric[2]; + if (m1= 672) { + k -= 671; + } else if (k >= 660) { + k -= 647; + }; // end elsif - if +}; // end for + +}; // end function deinterleave + + + +/// function scramble + +void scramble (int * in,int * out) { + +static const int SCRAMBLER_TABLE_BITS[] = { + 0,0,0,0,1,1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0, + 0,0,1,0,0,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0, + 1,1,0,1,0,1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0,1,0,0,0,0,1,0,1,0,1,0, + 1,1,1,1,1,0,1,0,0,1,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,0, + 0,0,0,1,1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0, + 0,1,0,0,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,1, + 1,0,1,0,1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0,1,0,0,0,0,1,0,1,0,1,0,1, + 1,1,1,1,0,1,0,0,1,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0, + 0,0,1,1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0, + 1,0,0,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,1,1, + 0,1,0,1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0,1,0,0,0,0,1,0,1,0,1,0,1,1, + 1,1,1,0,1,0,0,1,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,0, + 0,1,1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,1, + 0,0,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,1,1,0, + 1,0,1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0,1,0,0,0,0,1,0,1,0,1,0,1,1,1, + 1,1,0,1,0,0,1,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,0,0, + 1,1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0, + 0,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,1,1,0,1, + 0,1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0,1,0,0,0,0,1,0,1,0,1,0,1,1,1,1, + 1,0,1,0,0,1,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,0,0,1, + 1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0, + 1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,1,1,0,1,0, + 1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0}; + +const int SCRAMBLER_TABLE_BITS_LENGTH=720; + +int loop=0; +int m_count=0; + + +for (loop=0; loop < 660; loop++) { + out[loop] = in[loop] ^ SCRAMBLER_TABLE_BITS[m_count++]; + + if (m_count >= SCRAMBLER_TABLE_BITS_LENGTH) { + m_count = 0U; + }; // end if +}; // end for + +}; // end function scramble + + + + diff --git a/dsd/dmr_const.h b/dsd/dmr_const.h new file mode 100644 index 000000000..22a62e3ba --- /dev/null +++ b/dsd/dmr_const.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _MAIN +extern const int rW[36]; +extern const int rX[36]; +extern const int rY[36]; +extern const int rZ[36]; + +#else +/* + * DMR AMBE interleave schedule + */ +const int rW[36] = { + 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 2, + 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2 +}; + +const int rX[36] = { + 23, 10, 22, 9, 21, 8, + 20, 7, 19, 6, 18, 5, + 17, 4, 16, 3, 15, 2, + 14, 1, 13, 0, 12, 10, + 11, 9, 10, 8, 9, 7, + 8, 6, 7, 5, 6, 4 +}; + +const int rY[36] = { + 0, 2, 0, 2, 0, 2, + 0, 2, 0, 3, 0, 3, + 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 3 +}; + +const int rZ[36] = { + 5, 3, 4, 2, 3, 1, + 2, 0, 1, 13, 0, 12, + 22, 11, 21, 10, 20, 9, + 19, 8, 18, 7, 17, 6, + 16, 5, 15, 4, 14, 3, + 13, 2, 12, 1, 11, 0 +}; + +#endif diff --git a/dsd/dmr_data.c b/dsd/dmr_data.c new file mode 100644 index 000000000..ab47f10f8 --- /dev/null +++ b/dsd/dmr_data.c @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "dsd.h" + +void +processDMRdata (dsd_opts * opts, dsd_state * state) +{ + + int i, dibit; + int *dibit_p; + char sync[25]; + char syncdata[25]; + char cachdata[13]; + char cc[5]; + char bursttype[5]; + +#ifdef DMR_DUMP + int k; + char syncbits[49]; + char cachbits[25]; +#endif + + cc[4] = 0; + bursttype[4] = 0; + + dibit_p = state->dibit_buf_p - 90; + + // CACH + for (i = 0; i < 12; i++) + { + dibit = *dibit_p; + dibit_p++; + if (opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + cachdata[i] = dibit; + if (i == 2) + { + state->currentslot = (1 & (dibit >> 1)); // bit 1 + if (state->currentslot == 0) + { + state->slot0light[0] = '['; + state->slot0light[6] = ']'; + state->slot1light[0] = ' '; + state->slot1light[6] = ' '; + } + else + { + state->slot1light[0] = '['; + state->slot1light[6] = ']'; + state->slot0light[0] = ' '; + state->slot0light[6] = ' '; + } + } + } + cachdata[12] = 0; + +#ifdef DMR_DUMP + k = 0; + for (i = 0; i < 12; i++) + { + dibit = cachdata[i]; + cachbits[k] = (1 & (dibit >> 1)) + 48; // bit 1 + k++; + cachbits[k] = (1 & dibit) + 48; // bit 0 + k++; + } + cachbits[24] = 0; + printf ("%s ", cachbits); +#endif + + // current slot + dibit_p += 49; + + // slot type + dibit = *dibit_p; + dibit_p++; + if (opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + cc[0] = (1 & (dibit >> 1)) + 48; // bit 1 + cc[1] = (1 & dibit) + 48; // bit 0 + + dibit = *dibit_p; + dibit_p++; + if (opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + cc[2] = (1 & (dibit >> 1)) + 48; // bit 1 + cc[3] = (1 & dibit) + 48; // bit 0 + + dibit = *dibit_p; + dibit_p++; + if (opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + bursttype[0] = (1 & (dibit >> 1)) + 48; // bit 1 + bursttype[1] = (1 & dibit) + 48; // bit 0 + + dibit = *dibit_p; + dibit_p++; + if (opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + bursttype[2] = (1 & (dibit >> 1)) + 48; // bit 1 + bursttype[3] = (1 & dibit) + 48; // bit 0 + + // parity bit + dibit_p++; + + if (strcmp (bursttype, "0000") == 0) + { + sprintf (state->fsubtype, " PI Header "); + } + else if (strcmp (bursttype, "0001") == 0) + { + sprintf (state->fsubtype, " VOICE Header "); + } + else if (strcmp (bursttype, "0010") == 0) + { + sprintf (state->fsubtype, " TLC "); + } + else if (strcmp (bursttype, "0011") == 0) + { + sprintf (state->fsubtype, " CSBK "); + } + else if (strcmp (bursttype, "0100") == 0) + { + sprintf (state->fsubtype, " MBC Header "); + } + else if (strcmp (bursttype, "0101") == 0) + { + sprintf (state->fsubtype, " MBC "); + } + else if (strcmp (bursttype, "0110") == 0) + { + sprintf (state->fsubtype, " DATA Header "); + } + else if (strcmp (bursttype, "0111") == 0) + { + sprintf (state->fsubtype, " RATE 1/2 DATA"); + } + else if (strcmp (bursttype, "1000") == 0) + { + sprintf (state->fsubtype, " RATE 3/4 DATA"); + } + else if (strcmp (bursttype, "1001") == 0) + { + sprintf (state->fsubtype, " Slot idle "); + } + else if (strcmp (bursttype, "1010") == 0) + { + sprintf (state->fsubtype, " Rate 1 DATA "); + } + else + { + sprintf (state->fsubtype, " "); + } + + // signaling data or sync + for (i = 0; i < 24; i++) + { + dibit = *dibit_p; + dibit_p++; + if (opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + syncdata[i] = dibit; + sync[i] = (dibit | 1) + 48; + } + sync[24] = 0; + syncdata[24] = 0; + +#ifdef DMR_DUMP + k = 0; + for (i = 0; i < 24; i++) + { + dibit = syncdata[i]; + syncbits[k] = (1 & (dibit >> 1)) + 48; // bit 1 + k++; + syncbits[k] = (1 & dibit) + 48; // bit 0 + k++; + } + syncbits[48] = 0; + printf ("%s ", syncbits); +#endif + + if ((strcmp (sync, DMR_BS_DATA_SYNC) == 0) || (strcmp (sync, DMR_MS_DATA_SYNC) == 0)) + { + if (state->currentslot == 0) + { + sprintf (state->slot0light, "[slot0]"); + } + else + { + sprintf (state->slot1light, "[slot1]"); + } + } + + if (opts->errorbars == 1) + { + printf ("%s %s ", state->slot0light, state->slot1light); + } + + // current slot second half, cach, next slot 1st half + skipDibit (opts, state, 120); + + if (opts->errorbars == 1) + { + if (strcmp (state->fsubtype, " ") == 0) + { + printf (" Unknown burst type: %s\n", bursttype); + } + else + { + printf ("%s\n", state->fsubtype); + } + } +} diff --git a/dsd/dmr_voice.c b/dsd/dmr_voice.c new file mode 100644 index 000000000..b567e22e3 --- /dev/null +++ b/dsd/dmr_voice.c @@ -0,0 +1,382 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "dsd.h" +#include "dmr_const.h" + +void +processDMRvoice (dsd_opts * opts, dsd_state * state) +{ + // extracts AMBE frames from DMR frame + int i, j, dibit; + int *dibit_p; + char ambe_fr[4][24]; + char ambe_fr2[4][24]; + char ambe_fr3[4][24]; + const int *w, *x, *y, *z; + char sync[25]; + char syncdata[25]; + char cachdata[13]; + int mutecurrentslot; + int msMode; + +#ifdef DMR_DUMP + int k; + char syncbits[49]; + char cachbits[25]; +#endif + + mutecurrentslot = 0; + msMode = 0; + + dibit_p = state->dibit_buf_p - 144; + for (j = 0; j < 6; j++) + { + // 2nd half of previous slot + for (i = 0; i < 54; i++) + { + if (j > 0) + { + dibit = getDibit (opts, state); + } + else + { + dibit = *dibit_p; + dibit_p++; + if (opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + } + } + + // CACH + for (i = 0; i < 12; i++) + { + if (j > 0) + { + dibit = getDibit (opts, state); + } + else + { + dibit = *dibit_p; + dibit_p++; + if (opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + } + cachdata[i] = dibit; + if (i == 2) + { + state->currentslot = (1 & (dibit >> 1)); // bit 1 + if (state->currentslot == 0) + { + state->slot0light[0] = '['; + state->slot0light[6] = ']'; + state->slot1light[0] = ' '; + state->slot1light[6] = ' '; + } + else + { + state->slot1light[0] = '['; + state->slot1light[6] = ']'; + state->slot0light[0] = ' '; + state->slot0light[6] = ' '; + } + } + } + cachdata[12] = 0; + + +#ifdef DMR_DUMP + k = 0; + for (i = 0; i < 12; i++) + { + dibit = cachdata[i]; + cachbits[k] = (1 & (dibit >> 1)) + 48; // bit 1 + k++; + cachbits[k] = (1 & dibit) + 48; // bit 0 + k++; + } + cachbits[24] = 0; + printf ("%s ", cachbits); +#endif + + // current slot frame 1 + w = rW; + x = rX; + y = rY; + z = rZ; + for (i = 0; i < 36; i++) + { + if (j > 0) + { + dibit = getDibit (opts, state); + } + else + { + dibit = *dibit_p; + dibit_p++; + if (opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + } + ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1 + ambe_fr[*y][*z] = (1 & dibit); // bit 0 + w++; + x++; + y++; + z++; + } + + // current slot frame 2 first half + w = rW; + x = rX; + y = rY; + z = rZ; + for (i = 0; i < 18; i++) + { + if (j > 0) + { + dibit = getDibit (opts, state); + } + else + { + dibit = *dibit_p; + dibit_p++; + if (opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + } + ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1 + ambe_fr2[*y][*z] = (1 & dibit); // bit 0 + w++; + x++; + y++; + z++; + } + + // signaling data or sync + for (i = 0; i < 24; i++) + { + if (j > 0) + { + dibit = getDibit (opts, state); + } + else + { + dibit = *dibit_p; + dibit_p++; + if (opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + } + syncdata[i] = dibit; + sync[i] = (dibit | 1) + 48; + } + sync[24] = 0; + syncdata[24] = 0; + + if ((strcmp (sync, DMR_BS_DATA_SYNC) == 0) || (strcmp (sync, DMR_MS_DATA_SYNC) == 0)) + { + mutecurrentslot = 1; + if (state->currentslot == 0) + { + sprintf (state->slot0light, "[slot0]"); + } + else + { + sprintf (state->slot1light, "[slot1]"); + } + } + else if ((strcmp (sync, DMR_BS_VOICE_SYNC) == 0) || (strcmp (sync, DMR_MS_VOICE_SYNC) == 0)) + { + mutecurrentslot = 0; + if (state->currentslot == 0) + { + sprintf (state->slot0light, "[SLOT0]"); + } + else + { + sprintf (state->slot1light, "[SLOT1]"); + } + } + if ((strcmp (sync, DMR_MS_VOICE_SYNC) == 0) || (strcmp (sync, DMR_MS_DATA_SYNC) == 0)) + { + msMode = 1; + } + + if ((j == 0) && (opts->errorbars == 1)) + { + printf ("%s %s VOICE e:", state->slot0light, state->slot1light); + } + +#ifdef DMR_DUMP + k = 0; + for (i = 0; i < 24; i++) + { + dibit = syncdata[i]; + syncbits[k] = (1 & (dibit >> 1)) + 48; // bit 1 + k++; + syncbits[k] = (1 & dibit) + 48; // bit 0 + k++; + } + syncbits[48] = 0; + printf ("%s ", syncbits); +#endif + + // current slot frame 2 second half + for (i = 0; i < 18; i++) + { + dibit = getDibit (opts, state); + ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1 + ambe_fr2[*y][*z] = (1 & dibit); // bit 0 + w++; + x++; + y++; + z++; + } + + if (mutecurrentslot == 0) + { + if (state->firstframe == 1) + { // we don't know if anything received before the first sync after no carrier is valid + state->firstframe = 0; + } + else + { + processMbeFrame (opts, state, NULL, ambe_fr, NULL); + processMbeFrame (opts, state, NULL, ambe_fr2, NULL); + } + } + + // current slot frame 3 + w = rW; + x = rX; + y = rY; + z = rZ; + for (i = 0; i < 36; i++) + { + dibit = getDibit (opts, state); + ambe_fr3[*w][*x] = (1 & (dibit >> 1)); // bit 1 + ambe_fr3[*y][*z] = (1 & dibit); // bit 0 + w++; + x++; + y++; + z++; + } + if (mutecurrentslot == 0) + { + processMbeFrame (opts, state, NULL, ambe_fr3, NULL); + } + + // CACH + for (i = 0; i < 12; i++) + { + dibit = getDibit (opts, state); + cachdata[i] = dibit; + } + cachdata[12] = 0; + +#ifdef DMR_DUMP + k = 0; + for (i = 0; i < 12; i++) + { + dibit = cachdata[i]; + cachbits[k] = (1 & (dibit >> 1)) + 48; // bit 1 + k++; + cachbits[k] = (1 & dibit) + 48; // bit 0 + k++; + } + cachbits[24] = 0; + printf ("%s ", cachbits); +#endif + + + // next slot + skipDibit (opts, state, 54); + + // signaling data or sync + for (i = 0; i < 24; i++) + { + dibit = getDibit (opts, state); + syncdata[i] = dibit; + sync[i] = (dibit | 1) + 48; + } + sync[24] = 0; + syncdata[24] = 0; + + if ((strcmp (sync, DMR_BS_DATA_SYNC) == 0) || (msMode == 1)) + { + if (state->currentslot == 0) + { + sprintf (state->slot1light, " slot1 "); + } + else + { + sprintf (state->slot0light, " slot0 "); + } + } + else if (strcmp (sync, DMR_BS_VOICE_SYNC) == 0) + { + if (state->currentslot == 0) + { + sprintf (state->slot1light, " SLOT1 "); + } + else + { + sprintf (state->slot0light, " SLOT0 "); + } + } + +#ifdef DMR_DUMP + k = 0; + for (i = 0; i < 24; i++) + { + dibit = syncdata[i]; + syncbits[k] = (1 & (dibit >> 1)) + 48; // bit 1 + k++; + syncbits[k] = (1 & dibit) + 48; // bit 0 + k++; + } + syncbits[48] = 0; + printf ("%s ", syncbits); +#endif + + if (j == 5) + { + // 2nd half next slot + skipDibit (opts, state, 54); + + // CACH + skipDibit (opts, state, 12); + + // first half current slot + skipDibit (opts, state, 54); + } + } + + if (opts->errorbars == 1) + { + printf ("\n"); + } + +} diff --git a/dsd/dsd.h b/dsd/dsd.h new file mode 100644 index 000000000..87c493013 --- /dev/null +++ b/dsd/dsd.h @@ -0,0 +1,159 @@ +#ifndef DSD_H +#define DSD_H +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "config.h" +#include +#include +#include +#include +#define __USE_XOPEN +#include +#include +#include +#include +#include +#include +#include +#ifdef SOLARIS +#include +#endif +#if defined(BSD) && !defined(__APPLE__) +#include +#endif +#include +#include +#include + +#include "p25p1_heuristics.h" + + +#define SAMPLE_RATE_IN 48000 +#define SAMPLE_RATE_OUT 8000 + +#ifdef USE_PORTAUDIO +#include "portaudio.h" +#define PA_FRAMES_PER_BUFFER 64 +//Buffer needs to be large enough to prevent input buffer overruns while DSD is doing other struff (like outputting voice) +//else you get skipped samples which result in incomplete/erronous decodes and a mountain of error messages. +#define PA_LATENCY_IN 0.500 +//Buffer needs to be large enough to prevent output buffer underruns while DSD is doing other stuff (like decoding input) +//else you get choppy audio and in 'extreme' cases errors. +//Buffer also needs to be as small as possible so we don't have a lot of audio delay. +#define PA_LATENCY_OUT 0.100 +#endif + +/* + * global variables + */ +int exitflag; + +#include "dsd_opts.h" +#include "dsd_state.h" +#include "dsd_livescanner.h" + +/* + * Frame sync patterns + */ +#define INV_P25P1_SYNC "333331331133111131311111" +#define P25P1_SYNC "111113113311333313133333" + +#define X2TDMA_BS_VOICE_SYNC "113131333331313331113311" +#define X2TDMA_BS_DATA_SYNC "331313111113131113331133" +#define X2TDMA_MS_DATA_SYNC "313113333111111133333313" +#define X2TDMA_MS_VOICE_SYNC "131331111333333311111131" + +#define DSTAR_HD "131313131333133113131111" +#define INV_DSTAR_HD "313131313111311331313333" +#define DSTAR_SYNC "313131313133131113313111" +#define INV_DSTAR_SYNC "131313131311313331131333" + +#define NXDN_MS_DATA_SYNC "313133113131111333" +#define INV_NXDN_MS_DATA_SYNC "131311331313333111" +#define NXDN_MS_VOICE_SYNC "313133113131113133" +#define INV_NXDN_MS_VOICE_SYNC "131311331313331311" +#define INV_NXDN_BS_DATA_SYNC "131311331313333131" +#define NXDN_BS_DATA_SYNC "313133113131111313" +#define INV_NXDN_BS_VOICE_SYNC "131311331313331331" +#define NXDN_BS_VOICE_SYNC "313133113131113113" + +#define DMR_BS_DATA_SYNC "313333111331131131331131" +#define DMR_BS_VOICE_SYNC "131111333113313313113313" +#define DMR_MS_DATA_SYNC "311131133313133331131113" +#define DMR_MS_VOICE_SYNC "133313311131311113313331" + +#define INV_PROVOICE_SYNC "31313111333133133311331133113311" +#define PROVOICE_SYNC "13131333111311311133113311331133" +#define INV_PROVOICE_EA_SYNC "13313133113113333311313133133311" +#define PROVOICE_EA_SYNC "31131311331331111133131311311133" + +/* + * function prototypes + */ +void processDMRdata (dsd_opts * opts, dsd_state * state); +void processDMRvoice (dsd_opts * opts, dsd_state * state); +void processAudio (dsd_opts * opts, dsd_state * state); +void writeSynthesizedVoice (dsd_opts * opts, dsd_state * state); +void playSynthesizedVoice (dsd_opts * opts, dsd_state * state); +void openAudioOutDevice (dsd_opts * opts, int speed); +void openAudioInDevice (dsd_opts * opts); + +int getDibit (dsd_opts * opts, dsd_state * state); +int get_dibit_and_analog_signal (dsd_opts * opts, dsd_state * state, int * out_analog_signal); + +void skipDibit (dsd_opts * opts, dsd_state * state, int count); +void saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d); +void saveAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d); +int readImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d); +int readAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d); +void openMbeInFile (dsd_opts * opts, dsd_state * state); +void closeMbeOutFile (dsd_opts * opts, dsd_state * state); +void openMbeOutFile (dsd_opts * opts, dsd_state * state); +void openWavOutFile (dsd_opts * opts, dsd_state * state); +void closeWavOutFile (dsd_opts * opts, dsd_state * state); +void printFrameInfo (dsd_opts * opts, dsd_state * state); +void processFrame (dsd_opts * opts, dsd_state * state); +void printFrameSync (dsd_opts * opts, dsd_state * state, char *frametype, int offset, char *modulation); +int getFrameSync (dsd_opts * opts, dsd_state * state); +int comp (const void *a, const void *b); +void usage (); +void sigfun (int sig); +int main (int argc, char **argv); +void playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv); +void processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char ambe_fr[4][24], char imbe7100_fr[7][24]); +void openSerial (dsd_opts * opts, dsd_state * state); +void resumeScan (dsd_opts * opts, dsd_state * state); +int getSymbol (dsd_opts * opts, dsd_state * state, int have_sync); +void upsample (dsd_state * state, float invalue); +void processDSTAR (dsd_opts * opts, dsd_state * state); +void processNXDNVoice (dsd_opts * opts, dsd_state * state); +void processNXDNData (dsd_opts * opts, dsd_state * state); +void processP25lcw (dsd_opts * opts, dsd_state * state, char *lcformat, char *mfid, char *lcinfo); +void processHDU (dsd_opts * opts, dsd_state * state); +void processLDU1 (dsd_opts * opts, dsd_state * state); +void processLDU2 (dsd_opts * opts, dsd_state * state); +void processTDU (dsd_opts * opts, dsd_state * state); +void processTDULC (dsd_opts * opts, dsd_state * state); +void processProVoice (dsd_opts * opts, dsd_state * state); +void processX2TDMAdata (dsd_opts * opts, dsd_state * state); +void processX2TDMAvoice (dsd_opts * opts, dsd_state * state); +void processDSTAR_HD (dsd_opts * opts, dsd_state * state); +short dmr_filter(short sample); +short nxdn_filter(short sample); + +#endif // DSD_H diff --git a/dsd/dsd_audio.c b/dsd/dsd_audio.c new file mode 100644 index 000000000..60fca90c5 --- /dev/null +++ b/dsd/dsd_audio.c @@ -0,0 +1,440 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "dsd.h" + +void +processAudio (dsd_opts * opts, dsd_state * state) +{ + + int i, n; + float aout_abs, max, gainfactor, gaindelta, maxbuf; + + if (opts->audio_gain == (float) 0) + { + // detect max level + max = 0; + state->audio_out_temp_buf_p = state->audio_out_temp_buf; + for (n = 0; n < 160; n++) + { + aout_abs = fabsf (*state->audio_out_temp_buf_p); + if (aout_abs > max) + { + max = aout_abs; + } + state->audio_out_temp_buf_p++; + } + *state->aout_max_buf_p = max; + state->aout_max_buf_p++; + state->aout_max_buf_idx++; + if (state->aout_max_buf_idx > 24) + { + state->aout_max_buf_idx = 0; + state->aout_max_buf_p = state->aout_max_buf; + } + + // lookup max history + for (i = 0; i < 25; i++) + { + maxbuf = state->aout_max_buf[i]; + if (maxbuf > max) + { + max = maxbuf; + } + } + + // determine optimal gain level + if (max > (float) 0) + { + gainfactor = ((float) 30000 / max); + } + else + { + gainfactor = (float) 50; + } + if (gainfactor < state->aout_gain) + { + state->aout_gain = gainfactor; + gaindelta = (float) 0; + } + else + { + if (gainfactor > (float) 50) + { + gainfactor = (float) 50; + } + gaindelta = gainfactor - state->aout_gain; + if (gaindelta > ((float) 0.05 * state->aout_gain)) + { + gaindelta = ((float) 0.05 * state->aout_gain); + } + } + gaindelta /= (float) 160; + } + else + { + gaindelta = (float) 0; + } + + if(opts->audio_gain >= 0){ + // adjust output gain + state->audio_out_temp_buf_p = state->audio_out_temp_buf; + for (n = 0; n < 160; n++) + { + *state->audio_out_temp_buf_p = (state->aout_gain + ((float) n * gaindelta)) * (*state->audio_out_temp_buf_p); + state->audio_out_temp_buf_p++; + } + state->aout_gain += ((float) 160 * gaindelta); + } + + // copy audio datat to output buffer and upsample if necessary + state->audio_out_temp_buf_p = state->audio_out_temp_buf; + if (opts->split == 0) + { + for (n = 0; n < 160; n++) + { + upsample (state, *state->audio_out_temp_buf_p); + state->audio_out_temp_buf_p++; + state->audio_out_float_buf_p += 6; + state->audio_out_idx += 6; + state->audio_out_idx2 += 6; + } + state->audio_out_float_buf_p -= (960 + opts->playoffset); + // copy to output (short) buffer + for (n = 0; n < 960; n++) + { + if (*state->audio_out_float_buf_p > (float) 32760) + { + *state->audio_out_float_buf_p = (float) 32760; + } + else if (*state->audio_out_float_buf_p < (float) -32760) + { + *state->audio_out_float_buf_p = (float) -32760; + } + *state->audio_out_buf_p = (short) *state->audio_out_float_buf_p; + state->audio_out_buf_p++; + state->audio_out_float_buf_p++; + } + state->audio_out_float_buf_p += opts->playoffset; + } + else + { + for (n = 0; n < 160; n++) + { + if (*state->audio_out_temp_buf_p > (float) 32760) + { + *state->audio_out_temp_buf_p = (float) 32760; + } + else if (*state->audio_out_temp_buf_p < (float) -32760) + { + *state->audio_out_temp_buf_p = (float) -32760; + } + *state->audio_out_buf_p = (short) *state->audio_out_temp_buf_p; + state->audio_out_buf_p++; + state->audio_out_temp_buf_p++; + state->audio_out_idx++; + state->audio_out_idx2++; + } + } +} + +void +writeSynthesizedVoice (dsd_opts * opts, dsd_state * state) +{ +#ifdef USE_LIBSNDFILE + int n; + short aout_buf[160]; + short *aout_buf_p; + +// for(n=0; n<160; n++) +// printf("%d ", ((short*)(state->audio_out_temp_buf))[n]); +// printf("\n"); + + aout_buf_p = aout_buf; + state->audio_out_temp_buf_p = state->audio_out_temp_buf; + + for (n = 0; n < 160; n++) + { + if (*state->audio_out_temp_buf_p > (float) 32767) + { + *state->audio_out_temp_buf_p = (float) 32767; + } + else if (*state->audio_out_temp_buf_p < (float) -32768) + { + *state->audio_out_temp_buf_p = (float) -32768; + } + *aout_buf_p = (short) *state->audio_out_temp_buf_p; + aout_buf_p++; + state->audio_out_temp_buf_p++; + } + + sf_write_short(opts->wav_out_f, aout_buf, 160); + /* + + int n; + short aout_buf[160]; + short *aout_buf_p; + ssize_t result; + + aout_buf_p = aout_buf; + state->audio_out_temp_buf_p = state->audio_out_temp_buf; + for (n = 0; n < 160; n++) + { + if (*state->audio_out_temp_buf_p > (float) 32760) + { + *state->audio_out_temp_buf_p = (float) 32760; + } + else if (*state->audio_out_temp_buf_p < (float) -32760) + { + *state->audio_out_temp_buf_p = (float) -32760; + } + *aout_buf_p = (short) *state->audio_out_temp_buf_p; + aout_buf_p++; + state->audio_out_temp_buf_p++; + } + + result = write (opts->wav_out_fd, aout_buf, 320); + fflush (opts->wav_out_f); + state->wav_out_bytes += 320; + */ +#endif +} + +void +playSynthesizedVoice (dsd_opts * opts, dsd_state * state) +{ + + ssize_t result; + + if (state->audio_out_idx > opts->delay) + { + // output synthesized speech to sound card + if (opts->audio_out_fd == -1) + { + memcpy(state->output_buffer + state->output_offset, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2)); + state->output_offset += state->audio_out_idx; + } + else + { + result = write (opts->audio_out_fd, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2)); + } + state->audio_out_idx = 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; + } +} + +void +openAudioOutDevice (dsd_opts * opts, int speed) +{ + // get info of device/file + struct stat stat_buf; + if(stat(opts->audio_out_dev, &stat_buf) != 0) { + printf("Error, couldn't open %s\n", opts->audio_out_dev); + exit(1); + } + + if( !(S_ISCHR(stat_buf.st_mode) || S_ISBLK(stat_buf.st_mode))) { // this is not a device + printf("Error, %s is not a device. use -w filename for wav output.\n", opts->audio_out_dev); + exit(1); + } +#ifdef SOLARIS + sample_info_t aset, aget; + + opts->audio_out_fd = open (opts->audio_out_dev, O_WRONLY); + if (opts->audio_out_fd == -1) + { + printf ("Error, couldn't open %s\n", opts->audio_out_dev); + exit (1); + } + + // get current + ioctl (opts->audio_out_fd, AUDIO_GETINFO, &aset); + + aset.record.sample_rate = speed; + aset.play.sample_rate = speed; + aset.record.channels = 1; + aset.play.channels = 1; + aset.record.precision = 16; + aset.play.precision = 16; + aset.record.encoding = AUDIO_ENCODING_LINEAR; + aset.play.encoding = AUDIO_ENCODING_LINEAR; + + if (ioctl (opts->audio_out_fd, AUDIO_SETINFO, &aset) == -1) + { + printf ("Error setting sample device parameters\n"); + exit (1); + } +#endif + +#if defined(BSD) && !defined(__APPLE__) && defined(USE_LIBSNDFILE) + + int fmt; + + opts->audio_out_fd = open (opts->audio_out_dev, O_WRONLY); + if (opts->audio_out_fd == -1) + { + printf ("Error, couldn't open %s\n", opts->audio_out_dev); + opts->audio_out = 0; + exit(1); + } + + fmt = 0; + if (ioctl (opts->audio_out_fd, SNDCTL_DSP_RESET) < 0) + { + printf ("ioctl reset error \n"); + } + fmt = speed; + if (ioctl (opts->audio_out_fd, SNDCTL_DSP_SPEED, &fmt) < 0) + { + printf ("ioctl speed error \n"); + } + fmt = 0; + if (ioctl (opts->audio_out_fd, SNDCTL_DSP_STEREO, &fmt) < 0) + { + printf ("ioctl stereo error \n"); + } + fmt = AFMT_S16_LE; + if (ioctl (opts->audio_out_fd, SNDCTL_DSP_SETFMT, &fmt) < 0) + { + printf ("ioctl setfmt error \n"); + } + +#endif + printf ("Audio Out Device: %s\n", opts->audio_out_dev); +} + +void +openAudioInDevice (dsd_opts * opts) +{ +#ifdef USE_LIBSNDFILE + // get info of device/file + struct stat stat_buf; + if (stat(opts->audio_in_dev, &stat_buf) != 0) { + printf("Error, couldn't open %s\n", opts->audio_in_dev); + exit(1); + } + if(S_ISREG(stat_buf.st_mode)) { // is this a regular file? then process with libsndfile. + opts->audio_in_type = 1; + opts->audio_in_file_info = calloc(1, sizeof(SF_INFO)); + opts->audio_in_file_info->channels = 1; + opts->audio_in_file = sf_open(opts->audio_in_dev, SFM_READ, opts->audio_in_file_info); + if(opts->audio_in_file == NULL) { + printf ("Error, couldn't open file %s\n", opts->audio_in_dev); + exit(1); + } + } + else { // this is a device, use old handling + opts->audio_in_type = 0; +#ifdef SOLARIS + sample_info_t aset, aget; + int rgain; + + rgain = 64; + + if (opts->split == 1) + { + opts->audio_in_fd = open (opts->audio_in_dev, O_RDONLY); + } + else + { + opts->audio_in_fd = open (opts->audio_in_dev, O_RDWR); + } + if (opts->audio_in_fd == -1) + { + printf ("Error, couldn't open %s\n", opts->audio_in_dev); + exit(1); + } + + // get current + ioctl (opts->audio_in_fd, AUDIO_GETINFO, &aset); + + aset.record.sample_rate = 48000; + aset.play.sample_rate = 48000; + aset.record.channels = 1; + aset.play.channels = 1; + aset.record.precision = 16; + aset.play.precision = 16; + aset.record.encoding = AUDIO_ENCODING_LINEAR; + aset.play.encoding = AUDIO_ENCODING_LINEAR; + aset.record.port = AUDIO_LINE_IN; + aset.record.gain = rgain; + + if (ioctl (opts->audio_in_fd, AUDIO_SETINFO, &aset) == -1) + { + printf ("Error setting sample device parameters\n"); + exit (1); + } +#endif + +#if defined(BSD) && !defined(__APPLE__) + int fmt; + + if (opts->split == 1) + { + opts->audio_in_fd = open (opts->audio_in_dev, O_RDONLY); + } + else + { + opts->audio_in_fd = open (opts->audio_in_dev, O_RDWR); + } + + if (opts->audio_in_fd == -1) + { + printf ("Error, couldn't open %s\n", opts->audio_in_dev); + opts->audio_out = 0; + } + + fmt = 0; + if (ioctl (opts->audio_in_fd, SNDCTL_DSP_RESET) < 0) + { + printf ("ioctl reset error \n"); + } + fmt = 48000; + if (ioctl (opts->audio_in_fd, SNDCTL_DSP_SPEED, &fmt) < 0) + { + printf ("ioctl speed error \n"); + } + fmt = 0; + if (ioctl (opts->audio_in_fd, SNDCTL_DSP_STEREO, &fmt) < 0) + { + printf ("ioctl stereo error \n"); + } + fmt = AFMT_S16_LE; + if (ioctl (opts->audio_in_fd, SNDCTL_DSP_SETFMT, &fmt) < 0) + { + printf ("ioctl setfmt error \n"); + } +#endif + } + if (opts->split == 1) + { + printf ("Audio In Device: %s\n", opts->audio_in_dev); + } + else + { + printf ("Audio In/Out Device: %s\n", opts->audio_in_dev); + } +#endif +} diff --git a/dsd/dsd_cleanupexit.c b/dsd/dsd_cleanupexit.c new file mode 100644 index 000000000..4388946ec --- /dev/null +++ b/dsd/dsd_cleanupexit.c @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "dsd_cleanupexit.h" +#include "dsd_nocarrier.h" +#include "dsd.h" + +void +cleanupAndExit (dsd_opts * opts, dsd_state * state) +{ + noCarrier (opts, state); +#ifdef USE_LIBSNDFILE + if (opts->wav_out_f != NULL) + { + closeWavOutFile (opts, state); + } +#endif + printf ("Exiting.\n"); + exit (0); +} + + diff --git a/dsd/dsd_cleanupexit.h b/dsd/dsd_cleanupexit.h new file mode 100644 index 000000000..4a05e8472 --- /dev/null +++ b/dsd/dsd_cleanupexit.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef INCLUDE_DSD_CLEANUPEXIT_H_ +#define INCLUDE_DSD_CLEANUPEXIT_H_ + +#include "dsd_opts.h" +#include "dsd_state.h" + +void cleanupAndExit(dsd_opts * opts, dsd_state * state); + +#endif /* INCLUDE_DSD_CLEANUPEXIT_H_ */ diff --git a/dsd/dsd_dibit.c b/dsd/dsd_dibit.c new file mode 100644 index 000000000..3d05e4ee9 --- /dev/null +++ b/dsd/dsd_dibit.c @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "dsd.h" + +int +getDibit (dsd_opts * opts, dsd_state * state) +{ + // returns one dibit value + int i, j, o, symbol; + int sbuf2[128]; + int spectrum[64]; + char modulation[8]; + int lmin, lmax, lsum; + + state->numflips = 0; + + symbol = getSymbol (opts, state, 1); + state->sbuf[state->sidx] = symbol; + + for (i = 0; i < opts->ssize; i++) + { + sbuf2[i] = state->sbuf[i]; + } + + qsort (sbuf2, opts->ssize, sizeof (int), comp); + // continuous update of min/max in rf_mod=1 (QPSK) mode + // in c4fm min/max must only be updated during sync + if (state->rf_mod == 1) + { + lmin = (sbuf2[0] + sbuf2[1]) / 2; + lmax = (sbuf2[(opts->ssize - 1)] + sbuf2[(opts->ssize - 2)]) / 2; + state->minbuf[state->midx] = lmin; + state->maxbuf[state->midx] = lmax; + if (state->midx == (opts->msize - 1)) + { + state->midx = 0; + } + else + { + state->midx++; + } + lsum = 0; + for (i = 0; i < opts->msize; i++) + { + lsum += state->minbuf[i]; + } + state->min = lsum / opts->msize; + lsum = 0; + for (i = 0; i < opts->msize; i++) + { + lsum += state->maxbuf[i]; + } + state->max = lsum / opts->msize; + state->center = ((state->max) + (state->min)) / 2; + state->umid = (((state->max) - state->center) * 5 / 8) + state->center; + state->lmid = (((state->min) - state->center) * 5 / 8) + state->center; + state->maxref = ((state->max) * 0.80); + state->minref = ((state->min) * 0.80); + } + else + { + state->maxref = state->max; + state->minref = state->min; + } + + if (state->sidx == (opts->ssize - 1)) + { + + state->sidx = 0; + + if (opts->datascope == 1) + { + if (state->rf_mod == 0) + { + sprintf (modulation, "C4FM"); + } + else if (state->rf_mod == 1) + { + sprintf (modulation, "QPSK"); + } + else if (state->rf_mod == 2) + { + sprintf (modulation, "GFSK"); + } + + for (i = 0; i < 64; i++) + { + spectrum[i] = 0; + } + for (i = 0; i < opts->ssize; i++) + { + o = (sbuf2[i] + 32768) / 1024; + spectrum[o]++; + } + if (state->symbolcnt > (4800 / opts->scoperate)) + { + state->symbolcnt = 0; + printf ("\n"); + printf ("Demod mode: %s Nac: %4X\n", modulation, state->nac); + printf ("Frame Type: %s Talkgroup: %7i\n", state->ftype, state->lasttg); + printf ("Frame Subtype: %s Source: %12i\n", state->fsubtype, state->lastsrc); + printf ("TDMA activity: %s %s Voice errors: %s\n", state->slot0light, state->slot1light, state->err_str); + printf ("+----------------------------------------------------------------+\n"); + for (i = 0; i < 10; i++) + { + printf ("|"); + for (j = 0; j < 64; j++) + { + if (i == 0) + { + if ((j == ((state->min) + 32768) / 1024) || (j == ((state->max) + 32768) / 1024)) + { + printf ("#"); + } + else if ((j == ((state->lmid) + 32768) / 1024) || (j == ((state->umid) + 32768) / 1024)) + { + printf ("^"); + } + else if (j == (state->center + 32768) / 1024) + { + printf ("!"); + } + else + { + if (j == 32) + { + printf ("|"); + } + else + { + printf (" "); + } + } + } + else + { + if (spectrum[j] > 9 - i) + { + printf ("*"); + } + else + { + if (j == 32) + { + printf ("|"); + } + else + { + printf (" "); + } + } + } + } + printf ("|\n"); + } + printf ("+----------------------------------------------------------------+\n"); + } + } + } + else + { + state->sidx++; + } + + if (state->dibit_buf_p > state->dibit_buf + 900000) + { + state->dibit_buf_p = state->dibit_buf + 200; + } + + // determine dibit state + if ((state->synctype == 6) || (state->synctype == 14)|| (state->synctype == 18)) + { + if (symbol > state->center) + { + *state->dibit_buf_p = 1; + state->dibit_buf_p++; + return (0); + } + else + { + *state->dibit_buf_p = 3; + state->dibit_buf_p++; + return (1); + } + } + else if ((state->synctype == 7) || (state->synctype == 15)|| (state->synctype == 19)) + { + if (symbol > state->center) + { + *state->dibit_buf_p = 1; + state->dibit_buf_p++; + return (1); + } + else + { + *state->dibit_buf_p = 3; + state->dibit_buf_p++; + return (0); + } + } + else if ((state->synctype == 1) || (state->synctype == 3) || (state->synctype == 5) || (state->synctype == 9) || (state->synctype == 11) || (state->synctype == 13)) + { + if (symbol > state->center) + { + if (symbol > state->umid) + { + *state->dibit_buf_p = 1; // store non-inverted values in dibit_buf + state->dibit_buf_p++; + return (3); + } + else + { + *state->dibit_buf_p = 0; + state->dibit_buf_p++; + return (2); + } + } + else + { + if (symbol < state->lmid) + { + *state->dibit_buf_p = 3; + state->dibit_buf_p++; + return (1); + } + else + { + *state->dibit_buf_p = 2; + state->dibit_buf_p++; + return (0); + } + } + } + else + { + if (symbol > state->center) + { + if (symbol > state->umid) + { + *state->dibit_buf_p = 1; + state->dibit_buf_p++; + return (1); + } + else + { + *state->dibit_buf_p = 0; + state->dibit_buf_p++; + return (0); + } + } + else + { + if (symbol < state->lmid) + { + *state->dibit_buf_p = 3; + state->dibit_buf_p++; + return (3); + } + else + { + *state->dibit_buf_p = 2; + state->dibit_buf_p++; + return (2); + } + } + } +} + +void +skipDibit (dsd_opts * opts, dsd_state * state, int count) +{ + + short sample; + int i; + + for (i = 0; i < (count); i++) + { + sample = getDibit (opts, state); + } +} diff --git a/dsd/dsd_file.c b/dsd/dsd_file.c new file mode 100644 index 000000000..25fcbc90c --- /dev/null +++ b/dsd/dsd_file.c @@ -0,0 +1,362 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "dsd.h" + +void +saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d) +{ + int i, j, k; + unsigned char b; + unsigned char err; + + err = (unsigned char) state->errs2; + fputc (err, opts->mbe_out_f); + + k = 0; + for (i = 0; i < 11; i++) + { + b = 0; + for (j = 0; j < 8; j++) + { + b = b << 1; + b = b + imbe_d[k]; + k++; + } + fputc (b, opts->mbe_out_f); + } + fflush (opts->mbe_out_f); +} + +void +saveAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d) +{ + int i, j, k; + unsigned char b; + unsigned char err; + + err = (unsigned char) state->errs2; + fputc (err, opts->mbe_out_f); + + k = 0; + for (i = 0; i < 6; i++) + { + b = 0; + for (j = 0; j < 8; j++) + { + b = b << 1; + b = b + ambe_d[k]; + k++; + } + fputc (b, opts->mbe_out_f); + } + b = ambe_d[48]; + fputc (b, opts->mbe_out_f); + fflush (opts->mbe_out_f); +} + +int +readImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d) +{ + + int i, j, k; + unsigned char b; + + state->errs2 = fgetc (opts->mbe_in_f); + state->errs = state->errs2; + + k = 0; + for (i = 0; i < 11; i++) + { + b = fgetc (opts->mbe_in_f); + if (feof (opts->mbe_in_f)) + { + return (1); + } + for (j = 0; j < 8; j++) + { + imbe_d[k] = (b & 128) >> 7; + b = b << 1; + b = b & 255; + k++; + } + } + return (0); +} + +int +readAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d) +{ + + int i, j, k; + unsigned char b; + + state->errs2 = fgetc (opts->mbe_in_f); + state->errs = state->errs2; + + k = 0; + for (i = 0; i < 6; i++) + { + b = fgetc (opts->mbe_in_f); + if (feof (opts->mbe_in_f)) + { + return (1); + } + for (j = 0; j < 8; j++) + { + ambe_d[k] = (b & 128) >> 7; + b = b << 1; + b = b & 255; + k++; + } + } + b = fgetc (opts->mbe_in_f); + ambe_d[48] = (b & 1); + + return (0); +} + +void +openMbeInFile (dsd_opts * opts, dsd_state * state) +{ + + char cookie[5]; + + opts->mbe_in_f = fopen (opts->mbe_in_file, "ro"); + if (opts->mbe_in_f == NULL) + { + printf ("Error: could not open %s\n", opts->mbe_in_file); + } + + // read cookie + cookie[0] = fgetc (opts->mbe_in_f); + cookie[1] = fgetc (opts->mbe_in_f); + cookie[2] = fgetc (opts->mbe_in_f); + cookie[3] = fgetc (opts->mbe_in_f); + cookie[4] = 0; + if (strstr (cookie, ".amb") != NULL) + { + state->mbe_file_type = 1; + } + else if (strstr (cookie, ".imb") != NULL) + { + state->mbe_file_type = 0; + } + else + { + state->mbe_file_type = -1; + printf ("Error - unrecognized file type\n"); + } + +} + +void +closeMbeOutFile (dsd_opts * opts, dsd_state * state) +{ + + char shell[255], newfilename[64], ext[5], datestr[32]; + char tgid[17]; + int sum, i, j; + int talkgroup; + struct tm timep; + int result; + + if (opts->mbe_out_f != NULL) + { + if ((state->synctype == 0) || (state->synctype == 1) || (state->synctype == 14) || (state->synctype == 15)) + { + sprintf (ext, ".imb"); + strptime (opts->mbe_out_file, "%s.imb", &timep); + } + else + { + sprintf (ext, ".amb"); + strptime (opts->mbe_out_file, "%s.amb", &timep); + } + + if (state->tgcount > 0) + { + for (i = 0; i < 16; i++) + { + sum = 0; + for (j = 0; j < state->tgcount; j++) + { + sum = sum + state->tg[j][i] - 48; + } + tgid[i] = (char) (((float) sum / (float) state->tgcount) + 48.5); + } + tgid[16] = 0; + talkgroup = (int) strtol (tgid, NULL, 2); + } + else + { + talkgroup = 0; + } + + fflush (opts->mbe_out_f); + fclose (opts->mbe_out_f); + opts->mbe_out_f = NULL; + strftime (datestr, 31, "%Y-%m-%d-%H%M%S", &timep); + sprintf (newfilename, "nac%X-%s-tg%i%s", state->nac, datestr, talkgroup, ext); + sprintf (shell, "mv %s %s", opts->mbe_out_file, newfilename); + result = system (shell); + + state->tgcount = 0; + for (i = 0; i < 25; i++) + { + for (j = 0; j < 16; j++) + { + state->tg[i][j] = 48; + } + } + } +} + +void +openMbeOutFile (dsd_opts * opts, dsd_state * state) +{ + + struct timeval tv; + int i, j; + char ext[5]; + + if ((state->synctype == 0) || (state->synctype == 1) || (state->synctype == 14) || (state->synctype == 15)) + { + sprintf (ext, ".imb"); + } + else + { + sprintf (ext, ".amb"); + } + + // reset talkgroup id buffer + for (i = 0; i < 12; i++) + { + for (j = 0; j < 25; j++) + { + state->tg[j][i] = 0; + } + } + + state->tgcount = 0; + + gettimeofday (&tv, NULL); + sprintf (opts->mbe_out_file, "%i%s", (int) tv.tv_sec, ext); + opts->mbe_out_f = fopen (opts->mbe_out_file, "w"); + if (opts->mbe_out_f == NULL) + { + printf ("Error, couldn't open %s\n", opts->mbe_out_file); + } + + // write magic + fprintf (opts->mbe_out_f, "%s", ext); + + fflush (opts->mbe_out_f); +} + +void +openWavOutFile (dsd_opts * opts, dsd_state * state) +{ + + // opts->wav_out_f = fopen (opts->wav_out_file, "w"); + + SF_INFO info; + info.samplerate = 8000; + info.channels = 1; + info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE; + opts->wav_out_f = sf_open (opts->wav_out_file, SFM_WRITE, &info); + + if (opts->wav_out_f == NULL) + { + printf ("Error - could not open wav output file %s\n", opts->wav_out_file); + return; + } + +// state->wav_out_bytes = 0; + +} + +void +closeWavOutFile (dsd_opts * opts, dsd_state * state) +{ + sf_close(opts->wav_out_f); + +/* + int length; + + if (opts->wav_out_f != NULL) + { + rewind (opts->wav_out_f); + length = state->wav_out_bytes; + + fprintf (opts->wav_out_f, "RIFF"); + // total length + fputc (((36 + length) & 0xff), opts->≈≈); + fputc ((((36 + length) >> 8) & 0xff), opts->wav_out_f); + fputc ((((36 + length) >> 16) & 0xff), opts->wav_out_f); + fputc ((((36 + length) >> 24) & 0xff), opts->wav_out_f); + + fprintf (opts->wav_out_f, "WAVE"); + fprintf (opts->wav_out_f, "fmt "); + + // length of format chunk + fputc (16, opts->wav_out_f); + fputc (0, opts->wav_out_f); + fputc (0, opts->wav_out_f); + fputc (0, opts->wav_out_f); + + // always 0x1 + fputc (1, opts->wav_out_f); + fputc (0, opts->wav_out_f); + + // channels + fputc (1, opts->wav_out_f); + fputc (0, opts->wav_out_f); + + // sample rate + fputc (64, opts->wav_out_f); + fputc (31, opts->wav_out_f); + fputc (0, opts->wav_out_f); + fputc (0, opts->wav_out_f); + + // bytes per second + fputc (128, opts->wav_out_f); + fputc (62, opts->wav_out_f); + fputc (0, opts->wav_out_f); + fputc (0, opts->wav_out_f); + + // block align + fputc (2, opts->wav_out_f); + fputc (0, opts->wav_out_f); + + // bits/sample + fputc (16, opts->wav_out_f); + fputc (0, opts->wav_out_f); + + // data chunk header + fprintf (opts->wav_out_f, "data"); + + // length of data + fputc ((length & 0xff), opts->wav_out_f); + fputc (((length >> 8) & 0xff), opts->wav_out_f); + fputc (((length >> 16) & 0xff), opts->wav_out_f); + fputc (((length >> 24) & 0xff), opts->wav_out_f); + + fflush (opts->wav_out_f); + } + */ +} diff --git a/dsd/dsd_filters.c b/dsd/dsd_filters.c new file mode 100644 index 000000000..aff98dd46 --- /dev/null +++ b/dsd/dsd_filters.c @@ -0,0 +1,116 @@ +// DMR filter +#define NZEROS 60 +float ngain = 7.423339364f; +static float xv[NZEROS+1]; +float xcoeffs[] = +{ -0.0083649323f, -0.0265444850f, -0.0428141462f, -0.0537571943f, +-0.0564141052f, -0.0489161045f, -0.0310068662f, -0.0043393881f, ++0.0275375106f, +0.0595423283f, +0.0857543325f, +0.1003565948f, ++0.0986944931f, +0.0782804830f, +0.0395670487f, -0.0136691535f, +-0.0744390415f, -0.1331834575f, -0.1788967208f, -0.2005995448f, +-0.1889627181f, -0.1378439993f, -0.0454976231f, +0.0847488694f, ++0.2444859269f, +0.4209222342f, +0.5982295474f, +0.7593684540f, ++0.8881539892f, +0.9712773915f, +0.9999999166f, +0.9712773915f, ++0.8881539892f, +0.7593684540f, +0.5982295474f, +0.4209222342f, ++0.2444859269f, +0.0847488694f, -0.0454976231f, -0.1378439993f, +-0.1889627181f, -0.2005995448f, -0.1788967208f, -0.1331834575f, +-0.0744390415f, -0.0136691535f, +0.0395670487f, +0.0782804830f, ++0.0986944931f, +0.1003565948f, +0.0857543325f, +0.0595423283f, ++0.0275375106f, -0.0043393881f, -0.0310068662f, -0.0489161045f, +-0.0564141052f, -0.0537571943f, -0.0428141462f, -0.0265444850f, +-0.0083649323f, +}; + +// NXDN filter +#define NXZEROS 134 +float nxgain = 15.95930463f; + +static float nxv[NXZEROS+1]; + +float nxcoeffs[] = +{ +0.031462429f, +0.031747267f, +0.030401148f, +0.027362877f, ++0.022653298f, +0.016379869f, +0.008737200f, +0.000003302f, +-0.009468531f, -0.019262057f, -0.028914291f, -0.037935027f, +-0.045828927f, -0.052119261f, -0.056372283f, -0.058221106f, +-0.057387924f, -0.053703443f, -0.047122444f, -0.037734535f, +-0.025769308f, -0.011595336f, +0.004287292f, +0.021260954f, ++0.038610717f, +0.055550276f, +0.071252765f, +0.084885375f, ++0.095646450f, +0.102803611f, +0.105731303f, +0.103946126f, ++0.097138329f, +0.085197939f, +0.068234131f, +0.046586711f, ++0.020828821f, -0.008239664f, -0.039608255f, -0.072081234f, +-0.104311776f, -0.134843790f, -0.162160200f, -0.184736015f, +-0.201094346f, -0.209863285f, -0.209831516f, -0.200000470f, +-0.179630919f, -0.148282051f, -0.105841323f, -0.052543664f, ++0.011020985f, +0.083912428f, +0.164857408f, +0.252278939f, ++0.344336996f, +0.438979335f, +0.534000832f, +0.627109358f, ++0.715995947f, +0.798406824f, +0.872214756f, +0.935487176f, ++0.986548646f, +1.024035395f, +1.046939951f, +1.054644241f, ++1.046939951f, +1.024035395f, +0.986548646f, +0.935487176f, ++0.872214756f, +0.798406824f, +0.715995947f, +0.627109358f, ++0.534000832f, +0.438979335f, +0.344336996f, +0.252278939f, ++0.164857408f, +0.083912428f, +0.011020985f, -0.052543664f, +-0.105841323f, -0.148282051f, -0.179630919f, -0.200000470f, +-0.209831516f, -0.209863285f, -0.201094346f, -0.184736015f, +-0.162160200f, -0.134843790f, -0.104311776f, -0.072081234f, +-0.039608255f, -0.008239664f, +0.020828821f, +0.046586711f, ++0.068234131f, +0.085197939f, +0.097138329f, +0.103946126f, ++0.105731303f, +0.102803611f, +0.095646450f, +0.084885375f, ++0.071252765f, +0.055550276f, +0.038610717f, +0.021260954f, ++0.004287292f, -0.011595336f, -0.025769308f, -0.037734535f, +-0.047122444f, -0.053703443f, -0.057387924f, -0.058221106f, +-0.056372283f, -0.052119261f, -0.045828927f, -0.037935027f, +-0.028914291f, -0.019262057f, -0.009468531f, +0.000003302f, ++0.008737200f, +0.016379869f, +0.022653298f, +0.027362877f, ++0.030401148f, +0.031747267f, +0.031462429f, +}; + +short dsd_input_filter(short sample, int mode); + +short +dmr_filter(short sample) +{ + return dsd_input_filter(sample, 1); +} + +short +nxdn_filter(short sample) +{ + return dsd_input_filter(sample, 2); +} + + +short +dsd_input_filter(short sample, int mode) +{ + float sum; int i; + float gain; + int zeros; + float *v, *coeffs; + switch(mode) { + case 1: + gain = ngain; + v = xv; + coeffs = xcoeffs; + zeros = NZEROS; + break; + case 2: + gain = nxgain; + v = nxv; + coeffs = nxcoeffs; + zeros = NXZEROS; + break; + default: + return sample; + } + + for (i = 0; i < zeros; i++) + v[i] = v[i+1]; + + v[zeros] = sample; // unfiltered sample in + sum = 0.0f; + + for (i = 0; i <= zeros; i++) + sum += (coeffs[i] * v[i]); + + return sum / ngain; // filtered sample out +} \ No newline at end of file diff --git a/dsd/dsd_frame.c b/dsd/dsd_frame.c new file mode 100644 index 000000000..8a7aef1c4 --- /dev/null +++ b/dsd/dsd_frame.c @@ -0,0 +1,474 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "dsd.h" +#if !defined(NULL) +#define NULL 0 +#endif + +void +printFrameInfo (dsd_opts * opts, dsd_state * state) +{ + + int level; + + level = (int) state->max / 164; + if (opts->verbose > 0) + { + printf ("inlvl: %2i%% ", level); + } + if (state->nac != 0) + { + printf ("nac: %4X ", state->nac); + } + + if (opts->verbose > 1) + { + printf ("src: %8i ", state->lastsrc); + } + printf ("tg: %5i ", state->lasttg); +} + +void +processFrame (dsd_opts * opts, dsd_state * state) +{ + + int i, j, dibit; + char duid[3]; + char nac[13]; + int level; + + duid[2] = 0; + j = 0; + + if (state->rf_mod == 1) + { + state->maxref = (state->max * 0.80); + state->minref = (state->min * 0.80); + } + else + { + state->maxref = state->max; + state->minref = state->min; + } + + if ((state->synctype == 8) || (state->synctype == 9)) + { + state->rf_mod = 2; + state->nac = 0; + state->lastsrc = 0; + state->lasttg = 0; + if (opts->errorbars == 1) + { + if (opts->verbose > 0) + { + level = (int) state->max / 164; + printf ("inlvl: %2i%% ", level); + } + } + state->nac = 0; + if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) + { + openMbeOutFile (opts, state); + } + sprintf (state->fsubtype, " VOICE "); + processNXDNVoice (opts, state); + return; + } + else if ((state->synctype == 16) || (state->synctype == 17)) + { + state->rf_mod = 2; + state->nac = 0; + state->lastsrc = 0; + state->lasttg = 0; + if (opts->errorbars == 1) + { + if (opts->verbose > 0) + { + level = (int) state->max / 164; + printf ("inlvl: %2i%% ", level); + } + } + state->nac = 0; + if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) + { + openMbeOutFile (opts, state); + } + sprintf (state->fsubtype, " DATA "); + processNXDNData (opts, state); + return; + } + else if ((state->synctype == 6) || (state->synctype == 7)) + { + state->nac = 0; + state->lastsrc = 0; + state->lasttg = 0; + if (opts->errorbars == 1) + { + if (opts->verbose > 0) + { + level = (int) state->max / 164; + printf ("inlvl: %2i%% ", level); + } + } + state->nac = 0; + if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) + { + openMbeOutFile (opts, state); + } + sprintf (state->fsubtype, " VOICE "); + processDSTAR (opts, state); + return; + } + else if ((state->synctype == 18) || (state->synctype == 19)) + { + state->nac = 0; + state->lastsrc = 0; + state->lasttg = 0; + if (opts->errorbars == 1) + { + if (opts->verbose > 0) + { + level = (int) state->max / 164; + printf ("inlvl: %2i%% ", level); + } + } + state->nac = 0; + if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) + { + openMbeOutFile (opts, state); + } + sprintf (state->fsubtype, " DATA "); + processDSTAR_HD (opts, state); + return; + } + + else if ((state->synctype >= 10) && (state->synctype <= 13)) + { + state->nac = 0; + state->lastsrc = 0; + state->lasttg = 0; + if (opts->errorbars == 1) + { + if (opts->verbose > 0) + { + level = (int) state->max / 164; + printf ("inlvl: %2i%% ", level); + } + } + if ((state->synctype == 11) || (state->synctype == 12)) + { + if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) + { + openMbeOutFile (opts, state); + } + sprintf (state->fsubtype, " VOICE "); + processDMRvoice (opts, state); + } + else + { + closeMbeOutFile (opts, state); + state->err_str[0] = 0; + processDMRdata (opts, state); + } + return; + } + else if ((state->synctype >= 2) && (state->synctype <= 5)) + { + state->nac = 0; + if (opts->errorbars == 1) + { + printFrameInfo (opts, state); + } + if ((state->synctype == 3) || (state->synctype == 4)) + { + if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) + { + openMbeOutFile (opts, state); + } + sprintf (state->fsubtype, " VOICE "); + processX2TDMAvoice (opts, state); + } + else + { + closeMbeOutFile (opts, state); + state->err_str[0] = 0; + processX2TDMAdata (opts, state); + } + return; + } + else if ((state->synctype == 14) || (state->synctype == 15)) + { + state->nac = 0; + state->lastsrc = 0; + state->lasttg = 0; + if (opts->errorbars == 1) + { + if (opts->verbose > 0) + { + level = (int) state->max / 164; + printf ("inlvl: %2i%% ", level); + } + } + if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) + { + openMbeOutFile (opts, state); + } + sprintf (state->fsubtype, " VOICE "); + processProVoice (opts, state); + return; + } + else + { + j = 0; + for (i = 0; i < 6; i++) + { + dibit = getDibit (opts, state); + nac[j] = (1 & (dibit >> 1)) + 48; // bit 1 + j++; + nac[j] = (1 & dibit) + 48; // bit 0 + j++; + } + nac[12] = 0; + state->nac = strtol (nac, NULL, 2); + + for (i = 0; i < 2; i++) + { + duid[i] = getDibit (opts, state) + 48; + } + } + + if (strcmp (duid, "00") == 0) + { + if (opts->errorbars == 1) + { + printFrameInfo (opts, state); + printf (" HDU\n"); + } + if (opts->mbe_out_dir[0] != 0) + { + closeMbeOutFile (opts, state); + openMbeOutFile (opts, state); + } + mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced); + state->lastp25type = 2; + sprintf (state->fsubtype, " HDU "); + processHDU (opts, state); + } + else if (strcmp (duid, "11") == 0) + { + if (opts->errorbars == 1) + { + printFrameInfo (opts, state); + printf (" LDU1 "); + } + if (opts->mbe_out_dir[0] != 0) + { + if (opts->mbe_out_f == NULL) + { + openMbeOutFile (opts, state); + } + } + state->lastp25type = 1; + sprintf (state->fsubtype, " LDU1 "); + state->numtdulc = 0; + processLDU1 (opts, state); + } + else if (strcmp (duid, "22") == 0) + { + if (state->lastp25type != 1) + { + if (opts->errorbars == 1) + { + printFrameInfo (opts, state); + printf (" Ignoring LDU2 not preceeded by LDU1\n"); + } + state->lastp25type = 0; + sprintf (state->fsubtype, " "); + } + else + { + if (opts->errorbars == 1) + { + printFrameInfo (opts, state); + printf (" LDU2 "); + } + if (opts->mbe_out_dir[0] != 0) + { + if (opts->mbe_out_f == NULL) + { + openMbeOutFile (opts, state); + } + } + state->lastp25type = 2; + sprintf (state->fsubtype, " LDU2 "); + state->numtdulc = 0; + processLDU2 (opts, state); + } + } + else if (strcmp (duid, "33") == 0) + { + if (opts->errorbars == 1) + { + printFrameInfo (opts, state); + printf (" TDULC\n"); + } + if (opts->mbe_out_dir[0] != 0) + { + closeMbeOutFile (opts, state); + } + mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced); + state->lasttg = 0; + state->lastsrc = 0; + state->lastp25type = 0; + state->err_str[0] = 0; + sprintf (state->fsubtype, " TDULC "); + state->numtdulc++; + if ((opts->resume > 0) && (state->numtdulc > opts->resume)) + { + resumeScan (opts, state); + } + processTDULC (opts, state); + state->err_str[0] = 0; + } + else if (strcmp (duid, "03") == 0) + { + if (opts->errorbars == 1) + { + printFrameInfo (opts, state); + printf (" TDU\n"); + } + if (opts->mbe_out_dir[0] != 0) + { + closeMbeOutFile (opts, state); + } + mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced); + state->lasttg = 0; + state->lastsrc = 0; + state->lastp25type = 0; + state->err_str[0] = 0; + sprintf (state->fsubtype, " TDU "); + skipDibit (opts, state, 40); + } + else if (strcmp (duid, "13") == 0) + { + if (opts->errorbars == 1) + { + printFrameInfo (opts, state); + printf (" TSDU\n"); + } + if (opts->resume > 0) + { + resumeScan (opts, state); + } + state->lasttg = 0; + state->lastsrc = 0; + state->lastp25type = 3; + sprintf (state->fsubtype, " TSDU "); + skipDibit (opts, state, 328); + } + else if (strcmp (duid, "30") == 0) + { + if (opts->errorbars == 1) + { + printFrameInfo (opts, state); + printf (" PDU\n"); + } + if (opts->resume > 0) + { + resumeScan (opts, state); + } + if (opts->mbe_out_dir[0] != 0) + { + if (opts->mbe_out_f == NULL) + { + openMbeOutFile (opts, state); + } + } + state->lastp25type = 4; + sprintf (state->fsubtype, " PDU "); + } + // try to guess based on previous frame if unknown type + else if (state->lastp25type == 1) + { + if (opts->errorbars == 1) + { + printFrameInfo (opts, state); + printf ("(LDU2) "); + } + if (opts->mbe_out_dir[0] != 0) + { + if (opts->mbe_out_f == NULL) + { + openMbeOutFile (opts, state); + } + } + state->lastp25type = 0; + sprintf (state->fsubtype, "(LDU2) "); + state->numtdulc = 0; + processLDU2 (opts, state); + } + else if (state->lastp25type == 2) + { + if (opts->errorbars == 1) + { + printFrameInfo (opts, state); + printf ("(LDU1) "); + } + if (opts->mbe_out_dir[0] != 0) + { + if (opts->mbe_out_f == NULL) + { + openMbeOutFile (opts, state); + } + } + state->lastp25type = 0; + sprintf (state->fsubtype, "(LDU1) "); + state->numtdulc = 0; + processLDU1 (opts, state); + } + else if (state->lastp25type == 3) + { + if (opts->errorbars == 1) + { + printFrameInfo (opts, state); + printf (" (TSDU)\n"); + } + state->lastp25type = 0; + sprintf (state->fsubtype, "(TSDU) "); + skipDibit (opts, state, 328); + } + else if (state->lastp25type == 4) + { + if (opts->errorbars == 1) + { + printFrameInfo (opts, state); + printf (" (PDU)\n"); + } + state->lastp25type = 0; + } + else + { + state->lastp25type = 0; + sprintf (state->fsubtype, " "); + if (opts->errorbars == 1) + { + printFrameInfo (opts, state); + printf (" duid:%s *Unknown DUID*\n", duid); + } + } +} diff --git a/dsd/dsd_frame_sync.c b/dsd/dsd_frame_sync.c new file mode 100644 index 000000000..bd6286322 --- /dev/null +++ b/dsd/dsd_frame_sync.c @@ -0,0 +1,830 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "dsd.h" +#include "dsd_cleanupexit.h" +#include "dsd_nocarrier.h" + +void +printFrameSync (dsd_opts * opts, dsd_state * state, char *frametype, int offset, char *modulation) +{ + + if (opts->verbose > 0) + { + printf ("Sync: %s ", frametype); + } + if (opts->verbose > 2) + { + printf ("o: %4i ", offset); + } + if (opts->verbose > 1) + { + printf ("mod: %s ", modulation); + } + if (opts->verbose > 2) + { + printf ("g: %f ", state->aout_gain); + } +} + +int +getFrameSync (dsd_opts * opts, dsd_state * state) +{ + /* detects frame sync and returns frame type + * 0 = +P25p1 + * 1 = -P25p1 + * 2 = +X2-TDMA (non inverted signal data frame) + * 3 = +X2-TDMA (inverted signal voice frame) + * 4 = -X2-TDMA (non inverted signal voice frame) + * 5 = -X2-TDMA (inverted signal data frame) + * 6 = +D-STAR + * 7 = -D-STAR + * 8 = +NXDN (non inverted voice frame) + * 9 = -NXDN (inverted voice frame) + * 10 = +DMR (non inverted singlan data frame) + * 11 = -DMR (inverted signal voice frame) + * 12 = +DMR (non inverted signal voice frame) + * 13 = -DMR (inverted signal data frame) + * 14 = +ProVoice + * 15 = -ProVoice + * 16 = +NXDN (non inverted data frame) + * 17 = -NXDN (inverted data frame) + * 18 = +D-STAR_HD + * 19 = -D-STAR_HD + */ + + int i, j, t, o, dibit, sync, symbol, synctest_pos, lastt; + char synctest[25]; + char synctest18[19]; + char synctest32[33]; + char modulation[8]; + char *synctest_p; + char synctest_buf[10240]; + int lmin, lmax, lidx; + int lbuf[24], lbuf2[24]; + int lsum; + char spectrum[64]; + + for (i = 18; i < 24; i++) + { + lbuf[i] = 0; + lbuf2[i] = 0; + } + + // detect frame sync + t = 0; + synctest[24] = 0; + synctest18[18] = 0; + synctest32[32] = 0; + synctest_pos = 0; + synctest_p = synctest_buf + 10; + sync = 0; + lmin = 0; + lmax = 0; + lidx = 0; + lastt = 0; + state->numflips = 0; + if ((opts->symboltiming == 1) && (state->carrier == 1)) + { + printf ("\nSymbol Timing:\n"); + } + while (sync == 0) + { + t++; + symbol = getSymbol (opts, state, 0); + lbuf[lidx] = symbol; + state->sbuf[state->sidx] = symbol; + if (lidx == 23) + { + lidx = 0; + } + else + { + lidx++; + } + if (state->sidx == (opts->ssize - 1)) + { + state->sidx = 0; + } + else + { + state->sidx++; + } + + if (lastt == 23) + { + lastt = 0; + if (state->numflips > opts->mod_threshold) + { + if (opts->mod_qpsk == 1) + { + state->rf_mod = 1; + } + } + else if (state->numflips > 18) + { + if (opts->mod_gfsk == 1) + { + state->rf_mod = 2; + } + } + else + { + if (opts->mod_c4fm == 1) + { + state->rf_mod = 0; + } + } + state->numflips = 0; + } + else + { + lastt++; + } + + if (state->dibit_buf_p > state->dibit_buf + 900000) + { + state->dibit_buf_p = state->dibit_buf + 200; + } + + //determine dibit state + if (symbol > 0) + { + *state->dibit_buf_p = 1; + state->dibit_buf_p++; + dibit = 49; + } + else + { + *state->dibit_buf_p = 3; + state->dibit_buf_p++; + dibit = 51; + } + + *synctest_p = dibit; + if (t >= 18) + { + for (i = 0; i < 24; i++) + { + lbuf2[i] = lbuf[i]; + } + qsort (lbuf2, 24, sizeof (int), comp); + lmin = (lbuf2[2] + lbuf2[3] + lbuf2[4]) / 3; + lmax = (lbuf2[21] + lbuf2[20] + lbuf2[19]) / 3; + + if (state->rf_mod == 1) + { + state->minbuf[state->midx] = lmin; + state->maxbuf[state->midx] = lmax; + if (state->midx == (opts->msize - 1)) + { + state->midx = 0; + } + else + { + state->midx++; + } + lsum = 0; + for (i = 0; i < opts->msize; i++) + { + lsum += state->minbuf[i]; + } + state->min = lsum / opts->msize; + lsum = 0; + for (i = 0; i < opts->msize; i++) + { + lsum += state->maxbuf[i]; + } + state->max = lsum / opts->msize; + state->center = ((state->max) + (state->min)) / 2; + state->maxref = ((state->max) * 0.80); + state->minref = ((state->min) * 0.80); + } + else + { + state->maxref = state->max; + state->minref = state->min; + } + + if (state->rf_mod == 0) + { + sprintf (modulation, "C4FM"); + } + else if (state->rf_mod == 1) + { + sprintf (modulation, "QPSK"); + } + else if (state->rf_mod == 2) + { + sprintf (modulation, "GFSK"); + } + + if (opts->datascope == 1) + { + if (lidx == 0) + { + for (i = 0; i < 64; i++) + { + spectrum[i] = 0; + } + for (i = 0; i < 24; i++) + { + o = (lbuf2[i] + 32768) / 1024; + spectrum[o]++; + } + if (state->symbolcnt > (4800 / opts->scoperate)) + { + state->symbolcnt = 0; + printf ("\n"); + printf ("Demod mode: %s Nac: %4X\n", modulation, state->nac); + printf ("Frame Type: %s Talkgroup: %7i\n", state->ftype, state->lasttg); + printf ("Frame Subtype: %s Source: %12i\n", state->fsubtype, state->lastsrc); + printf ("TDMA activity: %s %s Voice errors: %s\n", state->slot0light, state->slot1light, state->err_str); + printf ("+----------------------------------------------------------------+\n"); + for (i = 0; i < 10; i++) + { + printf ("|"); + for (j = 0; j < 64; j++) + { + if (i == 0) + { + if ((j == ((state->min) + 32768) / 1024) || (j == ((state->max) + 32768) / 1024)) + { + printf ("#"); + } + else if (j == (state->center + 32768) / 1024) + { + printf ("!"); + } + else + { + if (j == 32) + { + printf ("|"); + } + else + { + printf (" "); + } + } + } + else + { + if (spectrum[j] > 9 - i) + { + printf ("*"); + } + else + { + if (j == 32) + { + printf ("|"); + } + else + { + printf (" "); + } + } + } + } + printf ("|\n"); + } + printf ("+----------------------------------------------------------------+\n"); + } + } + } + + strncpy (synctest, (synctest_p - 23), 24); + if (opts->frame_p25p1 == 1) + { + if (strcmp (synctest, P25P1_SYNC) == 0) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + sprintf (state->ftype, " P25 Phase 1 "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, " +P25p1 ", synctest_pos + 1, modulation); + } + state->lastsynctype = 0; + return (0); + } + if (strcmp (synctest, INV_P25P1_SYNC) == 0) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + sprintf (state->ftype, " P25 Phase 1 "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, " -P25p1 ", synctest_pos + 1, modulation); + } + state->lastsynctype = 1; + return (1); + } + } + if (opts->frame_x2tdma == 1) + { + if ((strcmp (synctest, X2TDMA_BS_DATA_SYNC) == 0) || (strcmp (synctest, X2TDMA_MS_DATA_SYNC) == 0)) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + (lmax)) / 2; + state->min = ((state->min) + (lmin)) / 2; + if (opts->inverted_x2tdma == 0) + { + // data frame + sprintf (state->ftype, " X2-TDMA "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, " +X2-TDMA ", synctest_pos + 1, modulation); + } + state->lastsynctype = 2; + return (2); + } + else + { + // inverted voice frame + sprintf (state->ftype, " X2-TDMA "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, " -X2-TDMA ", synctest_pos + 1, modulation); + } + if (state->lastsynctype != 3) + { + state->firstframe = 1; + } + state->lastsynctype = 3; + return (3); + } + } + if ((strcmp (synctest, X2TDMA_BS_VOICE_SYNC) == 0) || (strcmp (synctest, X2TDMA_MS_VOICE_SYNC) == 0)) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + if (opts->inverted_x2tdma == 0) + { + // voice frame + sprintf (state->ftype, " X2-TDMA "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, " +X2-TDMA ", synctest_pos + 1, modulation); + } + if (state->lastsynctype != 4) + { + state->firstframe = 1; + } + state->lastsynctype = 4; + return (4); + } + else + { + // inverted data frame + sprintf (state->ftype, " X2-TDMA "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, " -X2-TDMA ", synctest_pos + 1, modulation); + } + state->lastsynctype = 5; + return (5); + } + } + } + if (opts->frame_dmr == 1) + { + if ((strcmp (synctest, DMR_MS_DATA_SYNC) == 0) || (strcmp (synctest, DMR_BS_DATA_SYNC) == 0)) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + (lmax)) / 2; + state->min = ((state->min) + (lmin)) / 2; + if (opts->inverted_dmr == 0) + { + // data frame + sprintf (state->ftype, " DMR "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, " +DMR ", synctest_pos + 1, modulation); + } + state->lastsynctype = 10; + return (10); + } + else + { + // inverted voice frame + sprintf (state->ftype, " DMR "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, " -DMR ", synctest_pos + 1, modulation); + } + if (state->lastsynctype != 11) + { + state->firstframe = 1; + } + state->lastsynctype = 11; + return (11); + } + } + if ((strcmp (synctest, DMR_MS_VOICE_SYNC) == 0) || (strcmp (synctest, DMR_BS_VOICE_SYNC) == 0)) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + if (opts->inverted_dmr == 0) + { + // voice frame + sprintf (state->ftype, " DMR "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, " +DMR ", synctest_pos + 1, modulation); + } + if (state->lastsynctype != 12) + { + state->firstframe = 1; + } + state->lastsynctype = 12; + return (12); + } + else + { + // inverted data frame + sprintf (state->ftype, " DMR "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, " -DMR ", synctest_pos + 1, modulation); + } + state->lastsynctype = 13; + return (13); + } + } + } + if (opts->frame_provoice == 1) + { + strncpy (synctest32, (synctest_p - 31), 32); + if ((strcmp (synctest32, PROVOICE_SYNC) == 0) || (strcmp (synctest32, PROVOICE_EA_SYNC) == 0)) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + sprintf (state->ftype, " ProVoice "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, " -ProVoice ", synctest_pos + 1, modulation); + } + state->lastsynctype = 14; + return (14); + } + else if ((strcmp (synctest32, INV_PROVOICE_SYNC) == 0) || (strcmp (synctest32, INV_PROVOICE_EA_SYNC) == 0)) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + sprintf (state->ftype, " ProVoice "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, " -ProVoice ", synctest_pos + 1, modulation); + } + state->lastsynctype = 15; + return (15); + } + + } + if ((opts->frame_nxdn96 == 1) || (opts->frame_nxdn48 == 1)) + { + strncpy (synctest18, (synctest_p - 17), 18); + if ((strcmp (synctest18, NXDN_BS_VOICE_SYNC) == 0) || (strcmp (synctest18, NXDN_MS_VOICE_SYNC) == 0)) + { + if ((state->lastsynctype == 8) || (state->lastsynctype == 16)) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + if (state->samplesPerSymbol == 20) + { + sprintf (state->ftype, " NXDN48 "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, " +NXDN48 ", synctest_pos + 1, modulation); + } + } + else + { + sprintf (state->ftype, " NXDN96 "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, " +NXDN96 ", synctest_pos + 1, modulation); + } + } + state->lastsynctype = 8; + return (8); + } + else + { + state->lastsynctype = 8; + } + } + else if ((strcmp (synctest18, INV_NXDN_BS_VOICE_SYNC) == 0) || (strcmp (synctest18, INV_NXDN_MS_VOICE_SYNC) == 0)) + { + if ((state->lastsynctype == 9) || (state->lastsynctype == 17)) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + if (state->samplesPerSymbol == 20) + { + sprintf (state->ftype, " NXDN48 "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, " -NXDN48 ", synctest_pos + 1, modulation); + } + } + else + { + sprintf (state->ftype, " NXDN96 "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, " -NXDN96 ", synctest_pos + 1, modulation); + } + } + state->lastsynctype = 9; + return (9); + } + else + { + state->lastsynctype = 9; + } + } + else if ((strcmp (synctest18, NXDN_BS_DATA_SYNC) == 0) || (strcmp (synctest18, NXDN_MS_DATA_SYNC) == 0)) + { + if ((state->lastsynctype == 8) || (state->lastsynctype == 16)) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + if (state->samplesPerSymbol == 20) + { + sprintf (state->ftype, " NXDN48 "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, " +NXDN48 ", synctest_pos + 1, modulation); + } + } + else + { + sprintf (state->ftype, " NXDN96 "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, " +NXDN96 ", synctest_pos + 1, modulation); + } + } + state->lastsynctype = 16; + return (16); + } + else + { + state->lastsynctype = 16; + } + } + else if ((strcmp (synctest18, INV_NXDN_BS_DATA_SYNC) == 0) || (strcmp (synctest18, INV_NXDN_MS_DATA_SYNC) == 0)) + { + if ((state->lastsynctype == 9) || (state->lastsynctype == 17)) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + sprintf (state->ftype, " NXDN "); + if (state->samplesPerSymbol == 20) + { + sprintf (state->ftype, " NXDN48 "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, " -NXDN48 ", synctest_pos + 1, modulation); + } + } + else + { + sprintf (state->ftype, " NXDN96 "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, " -NXDN96 ", synctest_pos + 1, modulation); + } + } + state->lastsynctype = 17; + return (17); + } + else + { + state->lastsynctype = 17; + } + } + } + if (opts->frame_dstar == 1) + { + if (strcmp (synctest, DSTAR_SYNC) == 0) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + sprintf (state->ftype, " D-STAR "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, " +D-STAR ", synctest_pos + 1, modulation); + } + state->lastsynctype = 6; + return (6); + } + if (strcmp (synctest, INV_DSTAR_SYNC) == 0) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + sprintf (state->ftype, " D-STAR "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, " -D-STAR ", synctest_pos + 1, modulation); + } + state->lastsynctype = 7; + return (7); + } + if (strcmp (synctest, DSTAR_HD) == 0) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + sprintf (state->ftype, " D-STAR_HD "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, " +D-STAR_HD ", synctest_pos + 1, modulation); + } + state->lastsynctype = 18; + return (18); + } + if (strcmp (synctest, INV_DSTAR_HD) == 0) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + sprintf (state->ftype, " D-STAR_HD "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, " -D-STAR_HD ", synctest_pos + 1, modulation); + } + state->lastsynctype = 19; + return (19); + } + + } + + if ((t == 24) && (state->lastsynctype != -1)) + { + if ((state->lastsynctype == 0) && ((state->lastp25type == 1) || (state->lastp25type == 2))) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + (lmax)) / 2; + state->min = ((state->min) + (lmin)) / 2; + sprintf (state->ftype, "(P25 Phase 1)"); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, "(+P25p1) ", synctest_pos + 1, modulation); + } + state->lastsynctype = -1; + return (0); + } + else if ((state->lastsynctype == 1) && ((state->lastp25type == 1) || (state->lastp25type == 2))) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + sprintf (state->ftype, "(P25 Phase 1)"); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, "(-P25p1) ", synctest_pos + 1, modulation); + } + state->lastsynctype = -1; + return (1); + } + else if ((state->lastsynctype == 3) && ((strcmp (synctest, X2TDMA_BS_VOICE_SYNC) != 0) || (strcmp (synctest, X2TDMA_MS_VOICE_SYNC) != 0))) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + sprintf (state->ftype, "(X2-TDMA) "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, "(-X2-TDMA) ", synctest_pos + 1, modulation); + } + state->lastsynctype = -1; + return (3); + } + else if ((state->lastsynctype == 4) && ((strcmp (synctest, X2TDMA_BS_DATA_SYNC) != 0) || (strcmp (synctest, X2TDMA_MS_DATA_SYNC) != 0))) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + sprintf (state->ftype, "(X2-TDMA) "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, "(+X2-TDMA) ", synctest_pos + 1, modulation); + } + state->lastsynctype = -1; + return (4); + } + else if ((state->lastsynctype == 11) && ((strcmp (synctest, DMR_BS_VOICE_SYNC) != 0) || (strcmp (synctest, DMR_MS_VOICE_SYNC) != 0))) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + sprintf (state->ftype, "(DMR) "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, "(-DMR) ", synctest_pos + 1, modulation); + } + state->lastsynctype = -1; + return (11); + } + else if ((state->lastsynctype == 12) && ((strcmp (synctest, DMR_BS_DATA_SYNC) != 0) || (strcmp (synctest, DMR_MS_DATA_SYNC) != 0))) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + sprintf (state->ftype, "(DMR) "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, "(+DMR) ", synctest_pos + 1, modulation); + } + state->lastsynctype = -1; + return (12); + } + } + } + + if (exitflag == 1) + { + cleanupAndExit (opts, state); + } + + if (synctest_pos < 10200) + { + synctest_pos++; + synctest_p++; + } + else + { + // buffer reset + synctest_pos = 0; + synctest_p = synctest_buf; + noCarrier (opts, state); + } + + if (state->lastsynctype != 1) + { + if (synctest_pos >= 1800) + { + if ((opts->errorbars == 1) && (opts->verbose > 1) && (state->carrier == 1)) + { + printf ("Sync: no sync\n"); + } + noCarrier (opts, state); + return (-1); + } + } + } + + return (-1); +} diff --git a/dsd/dsd_livescanner.c b/dsd/dsd_livescanner.c new file mode 100644 index 000000000..869c036ae --- /dev/null +++ b/dsd/dsd_livescanner.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "dsd.h" +#include "dsd_nocarrier.h" + +void liveScanner(dsd_opts * opts, dsd_state * state) +{ +#ifdef USE_PORTAUDIO + if(opts->audio_in_type == 2) + { + PaError err = Pa_StartStream( opts->audio_in_pa_stream ); + if( err != paNoError ) + { + fprintf( stderr, "An error occured while starting the portaudio input stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return; + } + } +#endif + while (1) + { + noCarrier(opts, state); + state->synctype = getFrameSync(opts, state); + // recalibrate center/umid/lmid + state->center = ((state->max) + (state->min)) / 2; + state->umid = (((state->max) - state->center) * 5 / 8) + state->center; + state->lmid = (((state->min) - state->center) * 5 / 8) + state->center; + while (state->synctype != -1) + { + processFrame(opts, state); + +#ifdef TRACE_DSD + state->debug_prefix = 'S'; +#endif + + state->synctype = getFrameSync(opts, state); + +#ifdef TRACE_DSD + state->debug_prefix = '\0'; +#endif + + // recalibrate center/umid/lmid + state->center = ((state->max) + (state->min)) / 2; + state->umid = (((state->max) - state->center) * 5 / 8) + + state->center; + state->lmid = (((state->min) - state->center) * 5 / 8) + + state->center; + } + } +} + + + + diff --git a/dsd/dsd_livescanner.h b/dsd/dsd_livescanner.h new file mode 100644 index 000000000..36ba09cda --- /dev/null +++ b/dsd/dsd_livescanner.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef INCLUDE_DSD_LIVESCANNER_H_ +#define INCLUDE_DSD_LIVESCANNER_H_ + +#include "dsd_opts.h" +#include "dsd_state.h" + +void liveScanner (dsd_opts * opts, dsd_state * state); + +#endif /* INCLUDE_DSD_LIVESCANNER_H_ */ diff --git a/dsd/dsd_main.c b/dsd/dsd_main.c new file mode 100644 index 000000000..7740bf017 --- /dev/null +++ b/dsd/dsd_main.c @@ -0,0 +1,737 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#define _MAIN + +#include "dsd.h" +#include "p25p1_const.h" +#include "x2tdma_const.h" +#include "dstar_const.h" +#include "nxdn_const.h" +#include "dmr_const.h" +#include "provoice_const.h" +#include "git_ver.h" + +int +comp (const void *a, const void *b) +{ + if (*((const int *) a) == *((const int *) b)) + return 0; + else if (*((const int *) a) < *((const int *) b)) + return -1; + else + return 1; +} + +void +noCarrier (dsd_opts * opts, dsd_state * state) +{ + state->dibit_buf_p = state->dibit_buf + 200; + memset (state->dibit_buf, 0, sizeof (int) * 200); + if (opts->mbe_out_f != NULL) + { + closeMbeOutFile (opts, state); + } + state->jitter = -1; + state->lastsynctype = -1; + state->carrier = 0; + state->max = 15000; + state->min = -15000; + state->center = 0; + state->err_str[0] = 0; + sprintf (state->fsubtype, " "); + sprintf (state->ftype, " "); + state->errs = 0; + state->errs2 = 0; + state->lasttg = 0; + state->lastsrc = 0; + state->lastp25type = 0; + state->repeat = 0; + state->nac = 0; + state->numtdulc = 0; + sprintf (state->slot0light, " slot0 "); + sprintf (state->slot1light, " slot1 "); + state->firstframe = 0; + if (opts->audio_gain == (float) 0) + { + state->aout_gain = 25; + } + memset (state->aout_max_buf, 0, sizeof (float) * 200); + state->aout_max_buf_p = state->aout_max_buf; + state->aout_max_buf_idx = 0; + sprintf (state->algid, "________"); + sprintf (state->keyid, "________________"); + mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced); +} + +void +initOpts (dsd_opts * opts) +{ + + opts->onesymbol = 10; + opts->mbe_in_file[0] = 0; + opts->mbe_in_f = NULL; + opts->errorbars = 1; + opts->datascope = 0; + opts->symboltiming = 0; + opts->verbose = 2; + opts->p25enc = 0; + opts->p25lc = 0; + opts->p25status = 0; + opts->p25tg = 0; + opts->scoperate = 15; + sprintf (opts->audio_in_dev, "/dev/audio"); + opts->audio_in_fd = -1; + sprintf (opts->audio_out_dev, "/dev/audio"); + opts->audio_out_fd = -1; + opts->split = 0; + opts->playoffset = 0; + opts->mbe_out_dir[0] = 0; + opts->mbe_out_file[0] = 0; + opts->mbe_out_f = NULL; + opts->audio_gain = 0; + opts->audio_out = 1; + opts->wav_out_file[0] = 0; + opts->wav_out_f = NULL; + //opts->wav_out_fd = -1; + opts->serial_baud = 115200; + sprintf (opts->serial_dev, "/dev/ttyUSB0"); + opts->resume = 0; + opts->frame_dstar = 0; + opts->frame_x2tdma = 1; + opts->frame_p25p1 = 1; + opts->frame_nxdn48 = 0; + opts->frame_nxdn96 = 1; + opts->frame_dmr = 1; + opts->frame_provoice = 0; + opts->mod_c4fm = 1; + opts->mod_qpsk = 1; + opts->mod_gfsk = 1; + opts->uvquality = 3; + opts->inverted_x2tdma = 1; // most transmitter + scanner + sound card combinations show inverted signals for this + opts->inverted_dmr = 0; // most transmitter + scanner + sound card combinations show non-inverted signals for this + opts->mod_threshold = 26; + opts->ssize = 36; + opts->msize = 15; + opts->playfiles = 0; + opts->delay = 0; + opts->use_cosine_filter = 1; + opts->unmute_encrypted_p25 = 0; +} + +void +initState (dsd_state * state) +{ + + int i, j; + + state->dibit_buf = malloc (sizeof (int) * 1000000); + state->dibit_buf_p = state->dibit_buf + 200; + memset (state->dibit_buf, 0, sizeof (int) * 200); + state->repeat = 0; + state->audio_out_buf = malloc (sizeof (short) * 1000000); + memset (state->audio_out_buf, 0, 100 * sizeof (short)); + state->audio_out_buf_p = state->audio_out_buf + 100; + state->audio_out_float_buf = malloc (sizeof (float) * 1000000); + memset (state->audio_out_float_buf, 0, 100 * sizeof (float)); + state->audio_out_float_buf_p = state->audio_out_float_buf + 100; + state->audio_out_idx = 0; + state->audio_out_idx2 = 0; + state->audio_out_temp_buf_p = state->audio_out_temp_buf; + //state->wav_out_bytes = 0; + state->center = 0; + state->jitter = -1; + state->synctype = -1; + state->min = -15000; + state->max = 15000; + state->lmid = 0; + state->umid = 0; + state->minref = -12000; + state->maxref = 12000; + state->lastsample = 0; + for (i = 0; i < 128; i++) + { + state->sbuf[i] = 0; + } + state->sidx = 0; + for (i = 0; i < 1024; i++) + { + state->maxbuf[i] = 15000; + } + for (i = 0; i < 1024; i++) + { + state->minbuf[i] = -15000; + } + state->midx = 0; + state->err_str[0] = 0; + sprintf (state->fsubtype, " "); + sprintf (state->ftype, " "); + state->symbolcnt = 0; + state->rf_mod = 0; + state->numflips = 0; + state->lastsynctype = -1; + state->lastp25type = 0; + state->offset = 0; + state->carrier = 0; + for (i = 0; i < 25; i++) + { + for (j = 0; j < 16; j++) + { + state->tg[i][j] = 48; + } + } + state->tgcount = 0; + state->lasttg = 0; + state->lastsrc = 0; + state->nac = 0; + state->errs = 0; + state->errs2 = 0; + state->mbe_file_type = -1; + state->optind = 0; + state->numtdulc = 0; + state->firstframe = 0; + sprintf (state->slot0light, " slot0 "); + sprintf (state->slot1light, " slot1 "); + state->aout_gain = 25; + memset (state->aout_max_buf, 0, sizeof (float) * 200); + state->aout_max_buf_p = state->aout_max_buf; + state->aout_max_buf_idx = 0; + state->samplesPerSymbol = 10; + state->symbolCenter = 4; + sprintf (state->algid, "________"); + sprintf (state->keyid, "________________"); + state->currentslot = 0; + state->cur_mp = malloc (sizeof (mbe_parms)); + state->prev_mp = malloc (sizeof (mbe_parms)); + state->prev_mp_enhanced = malloc (sizeof (mbe_parms)); + mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced); + state->p25kid = 0; +} + +void +usage () +{ + printf ("\n"); + printf ("Usage:\n"); + printf (" dsd [options] Live scanner mode\n"); + printf (" dsd [options] -r Read/Play saved mbe data from file(s)\n"); + printf (" dsd -h Show help\n"); + printf ("\n"); + printf ("Display Options:\n"); + printf (" -e Show Frame Info and errorbars (default)\n"); + printf (" -pe Show P25 encryption sync bits\n"); + printf (" -pl Show P25 link control bits\n"); + printf (" -ps Show P25 status bits and low speed data\n"); + printf (" -pt Show P25 talkgroup info\n"); + printf (" -q Don't show Frame Info/errorbars\n"); + printf (" -s Datascope (disables other display options)\n"); + printf (" -t Show symbol timing during sync\n"); + printf (" -v Frame information Verbosity\n"); + printf (" -z Frame rate for datascope\n"); + printf ("\n"); + printf ("Input/Output options:\n"); + printf (" -i Audio input device (default is /dev/audio)\n"); + printf (" -o Audio output device (default is /dev/audio)\n"); + printf (" -d Create mbe data files, use this directory\n"); + printf (" -r Read/Play saved mbe data from file(s)\n"); + printf (" -g Audio output gain (default = 0 = auto, disable = -1)\n"); + printf (" -n Do not send synthesized speech to audio output device\n"); + printf (" -w Output synthesized speech to a .wav file\n"); + printf ("\n"); + printf ("Scanner control options:\n"); + printf (" -B Serial port baud rate (default=115200)\n"); + printf (" -C Serial port for scanner control (default=/dev/ttyUSB0)\n"); + printf (" -R Resume scan after TDULC frames or any PDU or TSDU\n"); + printf ("\n"); + printf ("Decoder options:\n"); + printf (" -fa Auto-detect frame type (default)\n"); + printf (" -f1 Decode only P25 Phase 1\n"); + printf (" -fd Decode only D-STAR\n"); + printf (" -fi Decode only NXDN48* (6.25 kHz) / IDAS*\n"); + printf (" -fn Decode only NXDN96 (12.5 kHz)\n"); + printf (" -fp Decode only ProVoice*\n"); + printf (" -fr Decode only DMR/MOTOTRBO\n"); + printf (" -fx Decode only X2-TDMA\n"); + printf (" -l Disable DMR/MOTOTRBO and NXDN input filtering\n"); + printf (" -ma Auto-select modulation optimizations (default)\n"); + printf (" -mc Use only C4FM modulation optimizations\n"); + printf (" -mg Use only GFSK modulation optimizations\n"); + printf (" -mq Use only QPSK modulation optimizations\n"); + printf (" -pu Unmute Encrypted P25\n"); + printf (" -u Unvoiced speech quality (default=3)\n"); + printf (" -xx Expect non-inverted X2-TDMA signal\n"); + printf (" -xr Expect inverted DMR/MOTOTRBO signal\n"); + printf ("\n"); + printf (" * denotes frame types that cannot be auto-detected.\n"); + printf ("\n"); + printf ("Advanced decoder options:\n"); + printf (" -A QPSK modulation auto detection threshold (default=26)\n"); + printf (" -S Symbol buffer size for QPSK decision point tracking\n"); + printf (" (default=36)\n"); + printf (" -M Min/Max buffer size for QPSK decision point tracking\n"); + printf (" (default=15)\n"); + exit (0); +} + +void +liveScanner (dsd_opts * opts, dsd_state * state) +{ + if (opts->audio_in_fd == -1) + { + if (pthread_mutex_lock(&state->input_mutex)) + { + printf("liveScanner -> Unable to lock mutex\n"); + } + } + while (1) + { + noCarrier (opts, state); + state->synctype = getFrameSync (opts, state); + // recalibrate center/umid/lmid + state->center = ((state->max) + (state->min)) / 2; + state->umid = (((state->max) - state->center) * 5 / 8) + state->center; + state->lmid = (((state->min) - state->center) * 5 / 8) + state->center; + while (state->synctype != -1) + { + processFrame (opts, state); + state->synctype = getFrameSync (opts, state); + // recalibrate center/umid/lmid + state->center = ((state->max) + (state->min)) / 2; + state->umid = (((state->max) - state->center) * 5 / 8) + state->center; + state->lmid = (((state->min) - state->center) * 5 / 8) + state->center; + } + } +} + +void +cleanupAndExit (dsd_opts * opts, dsd_state * state) +{ + noCarrier (opts, state); + if (opts->wav_out_f != NULL) + { + closeWavOutFile (opts, state); + } + printf ("Exiting.\n"); + exit (0); +} + +void +sigfun (int sig) +{ + exitflag = 1; + signal (SIGINT, SIG_DFL); +} + +int +main (int argc, char **argv) +{ + + int c; + extern char *optarg; + extern int optind, opterr, optopt; + dsd_opts opts; + dsd_state state; + char versionstr[25]; + mbe_printVersion (versionstr); + + printf ("Digital Speech Decoder 1.7.0-dev (build:%s)\n", GIT_TAG); + printf ("mbelib version %s\n", versionstr); + + initOpts (&opts); + initState (&state); + + exitflag = 0; + signal (SIGINT, sigfun); + + while ((c = getopt (argc, argv, "hep:qstv:z:i:o:d:g:nw:B:C:R:f:m:u:x:A:S:M:rl")) != -1) + { + opterr = 0; + switch (c) + { + case 'h': + usage (); + exit (0); + case 'e': + opts.errorbars = 1; + opts.datascope = 0; + break; + case 'p': + if (optarg[0] == 'e') + { + opts.p25enc = 1; + } + else if (optarg[0] == 'l') + { + opts.p25lc = 1; + } + else if (optarg[0] == 's') + { + opts.p25status = 1; + } + else if (optarg[0] == 't') + { + opts.p25tg = 1; + } + else if (optarg[0] == 'u') + { + opts.unmute_encrypted_p25 = 1; + } + break; + case 'q': + opts.errorbars = 0; + opts.verbose = 0; + break; + case 's': + opts.errorbars = 0; + opts.p25enc = 0; + opts.p25lc = 0; + opts.p25status = 0; + opts.p25tg = 0; + opts.datascope = 1; + opts.symboltiming = 0; + break; + case 't': + opts.symboltiming = 1; + opts.errorbars = 1; + opts.datascope = 0; + break; + case 'v': + sscanf (optarg, "%d", &opts.verbose); + break; + case 'z': + sscanf (optarg, "%d", &opts.scoperate); + opts.errorbars = 0; + opts.p25enc = 0; + opts.p25lc = 0; + opts.p25status = 0; + opts.p25tg = 0; + opts.datascope = 1; + opts.symboltiming = 0; + printf ("Setting datascope frame rate to %i frame per second.\n", opts.scoperate); + break; + case 'i': + strncpy(opts.audio_in_dev, optarg, 1023); + opts.audio_in_dev[1023] = '\0'; + break; + case 'o': + strncpy(opts.audio_out_dev, optarg, 1023); + opts.audio_out_dev[1023] = '\0'; + break; + case 'd': + strncpy(opts.mbe_out_dir, optarg, 1023); + opts.mbe_out_dir[1023] = '\0'; + printf ("Writing mbe data files to directory %s\n", opts.mbe_out_dir); + break; + case 'g': + sscanf (optarg, "%f", &opts.audio_gain); + if (opts.audio_gain < (float) 0 ) + { + printf ("Disabling audio out gain setting\n"); + } + else if (opts.audio_gain == (float) 0) + { + opts.audio_gain = (float) 0; + printf ("Enabling audio out auto-gain\n"); + } + else + { + printf ("Setting audio out gain to %f\n", opts.audio_gain); + state.aout_gain = opts.audio_gain; + } + break; + case 'n': + opts.audio_out = 0; + printf ("Disabling audio output to soundcard.\n"); + break; + case 'w': + strncpy(opts.wav_out_file, optarg, 1023); + opts.wav_out_file[1023] = '\0'; + printf ("Writing audio to file %s\n", opts.wav_out_file); + openWavOutFile (&opts, &state); + break; + case 'B': + sscanf (optarg, "%d", &opts.serial_baud); + break; + case 'C': + strncpy(opts.serial_dev, optarg, 1023); + opts.serial_dev[1023] = '\0'; + break; + case 'R': + sscanf (optarg, "%d", &opts.resume); + printf ("Enabling scan resume after %i TDULC frames\n", opts.resume); + break; + case 'f': + if (optarg[0] == 'a') + { + opts.frame_dstar = 1; + opts.frame_x2tdma = 1; + opts.frame_p25p1 = 1; + opts.frame_nxdn48 = 0; + opts.frame_nxdn96 = 1; + opts.frame_dmr = 1; + opts.frame_provoice = 0; + } + else if (optarg[0] == 'd') + { + opts.frame_dstar = 1; + opts.frame_x2tdma = 0; + opts.frame_p25p1 = 0; + opts.frame_nxdn48 = 0; + opts.frame_nxdn96 = 0; + opts.frame_dmr = 0; + opts.frame_provoice = 0; + printf ("Decoding only D-STAR frames.\n"); + } + else if (optarg[0] == 'x') + { + opts.frame_dstar = 0; + opts.frame_x2tdma = 1; + opts.frame_p25p1 = 0; + opts.frame_nxdn48 = 0; + opts.frame_nxdn96 = 0; + opts.frame_dmr = 0; + opts.frame_provoice = 0; + printf ("Decoding only X2-TDMA frames.\n"); + } + else if (optarg[0] == 'p') + { + opts.frame_dstar = 0; + opts.frame_x2tdma = 0; + opts.frame_p25p1 = 0; + opts.frame_nxdn48 = 0; + opts.frame_nxdn96 = 0; + opts.frame_dmr = 0; + opts.frame_provoice = 1; + state.samplesPerSymbol = 5; + state.symbolCenter = 2; + opts.mod_c4fm = 0; + opts.mod_qpsk = 0; + opts.mod_gfsk = 1; + state.rf_mod = 2; + printf ("Setting symbol rate to 9600 / second\n"); + printf ("Enabling only GFSK modulation optimizations.\n"); + printf ("Decoding only ProVoice frames.\n"); + } + else if (optarg[0] == '1') + { + opts.frame_dstar = 0; + opts.frame_x2tdma = 0; + opts.frame_p25p1 = 1; + opts.frame_nxdn48 = 0; + opts.frame_nxdn96 = 0; + opts.frame_dmr = 0; + opts.frame_provoice = 0; + printf ("Decoding only P25 Phase 1 frames.\n"); + } + else if (optarg[0] == 'i') + { + opts.frame_dstar = 0; + opts.frame_x2tdma = 0; + opts.frame_p25p1 = 0; + opts.frame_nxdn48 = 1; + opts.frame_nxdn96 = 0; + opts.frame_dmr = 0; + opts.frame_provoice = 0; + state.samplesPerSymbol = 20; + state.symbolCenter = 10; + opts.mod_c4fm = 0; + opts.mod_qpsk = 0; + opts.mod_gfsk = 1; + state.rf_mod = 2; + printf ("Setting symbol rate to 2400 / second\n"); + printf ("Enabling only GFSK modulation optimizations.\n"); + printf ("Decoding only NXDN 4800 baud frames.\n"); + } + else if (optarg[0] == 'n') + { + opts.frame_dstar = 0; + opts.frame_x2tdma = 0; + opts.frame_p25p1 = 0; + opts.frame_nxdn48 = 0; + opts.frame_nxdn96 = 1; + opts.frame_dmr = 0; + opts.frame_provoice = 0; + opts.mod_c4fm = 0; + opts.mod_qpsk = 0; + opts.mod_gfsk = 1; + state.rf_mod = 2; + printf ("Enabling only GFSK modulation optimizations.\n"); + printf ("Decoding only NXDN 9600 baud frames.\n"); + } + else if (optarg[0] == 'r') + { + opts.frame_dstar = 0; + opts.frame_x2tdma = 0; + opts.frame_p25p1 = 0; + opts.frame_nxdn48 = 0; + opts.frame_nxdn96 = 0; + opts.frame_dmr = 1; + opts.frame_provoice = 0; + printf ("Decoding only DMR/MOTOTRBO frames.\n"); + } + break; + case 'm': + if (optarg[0] == 'a') + { + opts.mod_c4fm = 1; + opts.mod_qpsk = 1; + opts.mod_gfsk = 1; + state.rf_mod = 0; + } + else if (optarg[0] == 'c') + { + opts.mod_c4fm = 1; + opts.mod_qpsk = 0; + opts.mod_gfsk = 0; + state.rf_mod = 0; + printf ("Enabling only C4FM modulation optimizations.\n"); + } + else if (optarg[0] == 'g') + { + opts.mod_c4fm = 0; + opts.mod_qpsk = 0; + opts.mod_gfsk = 1; + state.rf_mod = 2; + printf ("Enabling only GFSK modulation optimizations.\n"); + } + else if (optarg[0] == 'q') + { + opts.mod_c4fm = 0; + opts.mod_qpsk = 1; + opts.mod_gfsk = 0; + state.rf_mod = 1; + printf ("Enabling only QPSK modulation optimizations.\n"); + } + break; + case 'u': + sscanf (optarg, "%i", &opts.uvquality); + if (opts.uvquality < 1) + { + opts.uvquality = 1; + } + else if (opts.uvquality > 64) + { + opts.uvquality = 64; + } + printf ("Setting unvoice speech quality to %i waves per band.\n", opts.uvquality); + break; + case 'x': + if (optarg[0] == 'x') + { + opts.inverted_x2tdma = 0; + printf ("Expecting non-inverted X2-TDMA signals.\n"); + } + else if (optarg[0] == 'r') + { + opts.inverted_dmr = 1; + printf ("Expecting inverted DMR/MOTOTRBO signals.\n"); + } + break; + case 'A': + sscanf (optarg, "%i", &opts.mod_threshold); + printf ("Setting C4FM/QPSK auto detection threshold to %i\n", opts.mod_threshold); + break; + case 'S': + sscanf (optarg, "%i", &opts.ssize); + if (opts.ssize > 128) + { + opts.ssize = 128; + } + else if (opts.ssize < 1) + { + opts.ssize = 1; + } + printf ("Setting QPSK symbol buffer to %i\n", opts.ssize); + break; + case 'M': + sscanf (optarg, "%i", &opts.msize); + if (opts.msize > 1024) + { + opts.msize = 1024; + } + else if (opts.msize < 1) + { + opts.msize = 1; + } + printf ("Setting QPSK Min/Max buffer to %i\n", opts.msize); + break; + case 'r': + opts.playfiles = 1; + opts.errorbars = 0; + opts.datascope = 0; + state.optind = optind; + break; + case 'l': + opts.use_cosine_filter = 0; + break; + default: + usage (); + exit (0); + } + } + + + if (opts.resume > 0) + { + openSerial (&opts, &state); + } + + if (opts.playfiles == 1) + { + opts.split = 1; + opts.playoffset = 0; + opts.delay = 0; + if(strlen(opts.wav_out_file) > 0) { + openWavOutFile (&opts, &state); + } + else { + openAudioOutDevice (&opts, 8000); + } + } + else if (strcmp (opts.audio_in_dev, opts.audio_out_dev) != 0) + { + opts.split = 1; + opts.playoffset = 0; + opts.delay = 0; + if(strlen(opts.wav_out_file) > 0) { + openWavOutFile (&opts, &state); + } + else { + openAudioOutDevice (&opts, 8000); + } + openAudioInDevice (&opts); + } + else + { + opts.split = 0; + opts.playoffset = 25; // 38 + opts.delay = 0; + openAudioInDevice (&opts); + opts.audio_out_fd = opts.audio_in_fd; + } + + if (opts.playfiles == 1) + { + playMbeFiles (&opts, &state, argc, argv); + } + else + { + liveScanner (&opts, &state); + } + cleanupAndExit (&opts, &state); + return (0); +} diff --git a/dsd/dsd_mbe.c b/dsd/dsd_mbe.c new file mode 100644 index 000000000..cda58d1bd --- /dev/null +++ b/dsd/dsd_mbe.c @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "dsd.h" +#include "dsd_cleanupexit.h" + +void +playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv) +{ +#ifdef USE_LIBSNDFILE + int i; + char imbe_d[88]; + char ambe_d[49]; + + for (i = state->optind; i < argc; i++) + { + sprintf (opts->mbe_in_file, "%s", argv[i]); + openMbeInFile (opts, state); + mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced); + printf ("playing %s\n", opts->mbe_in_file); + while (feof (opts->mbe_in_f) == 0) + { + if (state->mbe_file_type == 0) + { + readImbe4400Data (opts, state, imbe_d); + 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); + processAudio (opts, state); + if (opts->wav_out_f != NULL) + { + writeSynthesizedVoice (opts, state); + } + + if (opts->audio_out != 1) + { + playSynthesizedVoice (opts, state); + } + } + else if (state->mbe_file_type == 1) + { + readAmbe2450Data (opts, state, ambe_d); + 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); + processAudio (opts, state); + if (opts->wav_out_f != NULL) + { + writeSynthesizedVoice (opts, state); + } + if (opts->audio_out == 1) + { + playSynthesizedVoice (opts, state); + } + } + if (exitflag == 1) + { + cleanupAndExit (opts, state); + } + } + } +#endif +} + +void +processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char ambe_fr[4][24], char imbe7100_fr[7][24]) +{ + + int i; + char imbe_d[88]; + char ambe_d[49]; +#ifdef AMBE_PACKET_OUT + char ambe_d_str[50]; +#endif + + for (i = 0; i < 88; i++) + { + imbe_d[i] = 0; + } + + if ((state->synctype == 0) || (state->synctype == 1)) + { + mbe_processImbe7200x4400Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, imbe_fr, imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); + if (opts->mbe_out_f != NULL) + { + saveImbe4400Data (opts, state, imbe_d); + } + } + else if ((state->synctype == 14) || (state->synctype == 15)) + { + mbe_processImbe7100x4400Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, imbe7100_fr, imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); + if (opts->mbe_out_f != NULL) + { + saveImbe4400Data (opts, state, imbe_d); + } + } + else if ((state->synctype == 6) || (state->synctype == 7)) + { + mbe_processAmbe3600x2400Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, ambe_fr, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); + if (opts->mbe_out_f != NULL) + { + saveAmbe2450Data (opts, state, ambe_d); + } + } + else + { + mbe_processAmbe3600x2450Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, ambe_fr, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); +#ifdef AMBE_PACKET_OUT + for(i=0; i<49; i++) { + ambe_d_str[i] = ambe_d[i] + '0'; + } + ambe_d_str[49] = '\0'; + // print binary string + fprintf(stderr, "\n?\t?\t%s\t", ambe_d_str); + // print error data + fprintf(stderr, "E1: %d; E2: %d; S: %s", state->errs, state->errs2, state->err_str); +#endif + if (opts->mbe_out_f != NULL) + { + saveAmbe2450Data (opts, state, ambe_d); + } + } + + if (opts->errorbars == 1) + { + printf ("%s", state->err_str); + } + + processAudio (opts, state); +#ifdef USE_LIBSNDFILE + if (opts->wav_out_f != NULL) + { + writeSynthesizedVoice (opts, state); + } +#endif + + if (opts->audio_out == 1) + { + playSynthesizedVoice (opts, state); + } +} diff --git a/dsd/dsd_nocarrier.c b/dsd/dsd_nocarrier.c new file mode 100644 index 000000000..ab13cd3b3 --- /dev/null +++ b/dsd/dsd_nocarrier.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "dsd_nocarrier.h" +#include "dsd.h" + +void noCarrier(dsd_opts * opts, dsd_state * state) +{ + state->dibit_buf_p = state->dibit_buf + 200; + memset(state->dibit_buf, 0, sizeof(int) * 200); + if (opts->mbe_out_f != NULL) + { + closeMbeOutFile(opts, state); + } + state->jitter = -1; + state->lastsynctype = -1; + state->carrier = 0; + state->max = 15000; + state->min = -15000; + state->center = 0; + state->err_str[0] = 0; + sprintf(state->fsubtype, " "); + sprintf(state->ftype, " "); + state->errs = 0; + state->errs2 = 0; + state->lasttg = 0; + state->lastsrc = 0; + state->lastp25type = 0; + state->repeat = 0; + state->nac = 0; + state->numtdulc = 0; + sprintf(state->slot0light, " slot0 "); + sprintf(state->slot1light, " slot1 "); + state->firstframe = 0; + if (opts->audio_gain == (float) 0) + { + state->aout_gain = 25; + } + memset(state->aout_max_buf, 0, sizeof(float) * 200); + state->aout_max_buf_p = state->aout_max_buf; + state->aout_max_buf_idx = 0; + sprintf(state->algid, "________"); + sprintf(state->keyid, "________________"); + mbe_initMbeParms(state->cur_mp, state->prev_mp, state->prev_mp_enhanced); +} diff --git a/dsd/dsd_nocarrier.h b/dsd/dsd_nocarrier.h new file mode 100644 index 000000000..92d2275a4 --- /dev/null +++ b/dsd/dsd_nocarrier.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef INCLUDE_DSD_NOCARRIER_H_ +#define INCLUDE_DSD_NOCARRIER_H_ + +#include "dsd_opts.h" +#include "dsd_state.h" + +void noCarrier(dsd_opts * opts, dsd_state * state); + +#endif /* INCLUDE_DSD_NOCARRIER_H_ */ diff --git a/dsd/dsd_opts.c b/dsd/dsd_opts.c new file mode 100644 index 000000000..5cecf3926 --- /dev/null +++ b/dsd/dsd_opts.c @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "dsd_opts.h" + +void initOpts(dsd_opts * opts) +{ + opts->onesymbol = 10; + opts->mbe_in_file[0] = 0; + opts->mbe_in_f = NULL; + opts->errorbars = 1; + opts->datascope = 0; + opts->symboltiming = 0; + opts->verbose = 2; + opts->p25enc = 0; + opts->p25lc = 0; + opts->p25status = 0; + opts->p25tg = 0; + opts->scoperate = 15; + sprintf(opts->audio_in_dev, "/dev/audio"); + opts->audio_in_fd = -1; // with audio_out_type = 0 and this fd = -1 it will use the bufferized (in-memory) version +#ifdef USE_PORTAUDIO + opts->audio_in_pa_stream = NULL; +#endif + sprintf(opts->audio_out_dev, "/dev/audio"); + opts->audio_out_fd = -1; // with audio_out_type = 0 and this fd = -1 it will use the bufferized (in-memory)version +#ifdef USE_PORTAUDIO + opts->audio_out_pa_stream = NULL; +#endif + opts->split = 0; + opts->upsample = 0; + opts->playoffset = 0; + opts->mbe_out_dir[0] = 0; + opts->mbe_out_file[0] = 0; + opts->mbe_out_path[0] = 0; + opts->mbe_out_f = NULL; + opts->audio_gain = 0; + opts->audio_out = 1; + opts->wav_out_file[0] = 0; +#ifdef USE_LIBSNDFILE + opts->wav_out_f = NULL; +#endif + //opts->wav_out_fd = -1; + opts->serial_baud = 115200; + sprintf(opts->serial_dev, "/dev/ttyUSB0"); + opts->resume = 0; + opts->frame_dstar = 0; + opts->frame_x2tdma = 1; + opts->frame_p25p1 = 1; + opts->frame_nxdn48 = 0; + opts->frame_nxdn96 = 1; + opts->frame_dmr = 1; + opts->frame_provoice = 0; + opts->mod_c4fm = 1; + opts->mod_qpsk = 1; + opts->mod_gfsk = 1; + opts->uvquality = 3; + opts->inverted_x2tdma = 1; // most transmitter + scanner + sound card combinations show inverted signals for this + opts->inverted_dmr = 0; // most transmitter + scanner + sound card combinations show non-inverted signals for this + opts->mod_threshold = 26; + opts->ssize = 36; + opts->msize = 15; + opts->playfiles = 0; + opts->delay = 0; + opts->use_cosine_filter = 1; + opts->unmute_encrypted_p25 = 0; +} + diff --git a/dsd/dsd_opts.h b/dsd/dsd_opts.h new file mode 100644 index 000000000..cc2051470 --- /dev/null +++ b/dsd/dsd_opts.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef INCLUDE_DSD_OPTS_H_ +#define INCLUDE_DSD_OPTS_H_ + +#include "config.h" +#include +#ifdef USE_LIBSNDFILE +#include +#endif +// Portaudio is not needed for bufferized (in-memory) operations +#ifdef USE_PORTAUDIO +#include "portaudio.h" +#endif + +typedef struct +{ + int onesymbol; + char mbe_in_file[1024]; + FILE *mbe_in_f; + int errorbars; + int datascope; + int symboltiming; + int verbose; + int p25enc; + int p25lc; + int p25status; + int p25tg; + int scoperate; + char audio_in_dev[1024]; + int audio_in_fd; +#ifdef USE_LIBSNDFILE + SNDFILE *audio_in_file; + SF_INFO *audio_in_file_info; +#endif +#ifdef USE_PORTAUDIO + PaStream* audio_in_pa_stream; +#endif + int audio_in_type; // 0 for device, 1 for file, 2 for portaudio + char audio_out_dev[1024]; + int audio_out_fd; +#ifdef USE_LIBSNDFILE + SNDFILE *audio_out_file; + SF_INFO *audio_out_file_info; +#endif +#ifdef USE_PORTAUDIO + PaStream* audio_out_pa_stream; +#endif + int audio_out_type; // 0 for device, 1 for file, 2 for portaudio + int split; + int upsample; //!< Force audio output upsampling to 48kHz + int playoffset; + char mbe_out_dir[1024]; + char mbe_out_file[1024]; + char mbe_out_path[1024]; + FILE *mbe_out_f; + float audio_gain; + int audio_out; + char wav_out_file[1024]; +#ifdef USE_LIBSNDFILE + SNDFILE *wav_out_f; +#endif + //int wav_out_fd; + int serial_baud; + char serial_dev[1024]; + int serial_fd; + int resume; + int frame_dstar; + int frame_x2tdma; + int frame_p25p1; + int frame_nxdn48; + int frame_nxdn96; + int frame_dmr; + int frame_provoice; + int mod_c4fm; + int mod_qpsk; + int mod_gfsk; + int uvquality; + int inverted_x2tdma; + int inverted_dmr; + int mod_threshold; + int ssize; + int msize; + int playfiles; + int delay; + int use_cosine_filter; + int unmute_encrypted_p25; +} dsd_opts; + +void initOpts (dsd_opts * opts); + +#endif /* INCLUDE_DSD_OPTS_H_ */ diff --git a/dsd/dsd_serial.c b/dsd/dsd_serial.c new file mode 100644 index 000000000..cc6a10047 --- /dev/null +++ b/dsd/dsd_serial.c @@ -0,0 +1,90 @@ +#include +#include "dsd.h" + +void +openSerial (dsd_opts * opts, dsd_state * state) +{ + + struct termios tty; + speed_t baud; + + printf ("Opening serial port %s and setting baud to %i\n", opts->serial_dev, opts->serial_baud); + opts->serial_fd = open (opts->serial_dev, O_WRONLY); + if (opts->serial_fd == -1) + { + printf ("Error, couldn't open %s\n", opts->serial_dev); + exit (1); + } + + tty.c_cflag = 0; + + baud = B115200; + switch (opts->serial_baud) + { + case 1200: + baud = B1200; + case 2400: + baud = B2400; + case 4800: + baud = B4800; + case 9600: + baud = B9600; + break; + case 19200: + baud = B19200; + break; + case 38400: + baud = B38400; + break; + case 57600: + baud = B57600; + break; + case 115200: + baud = B115200; + break; + case 230400: + baud = B230400; + break; + } + if (opts->serial_baud > 0) + { + cfsetospeed (&tty, baud); + cfsetispeed (&tty, baud); + } + + tty.c_cflag |= (tty.c_cflag & ~CSIZE) | CS8; + tty.c_iflag = IGNBRK; + tty.c_lflag = 0; + tty.c_oflag = 0; + tty.c_cflag &= ~CRTSCTS; + tty.c_iflag &= ~(IXON | IXOFF | IXANY); + tty.c_cflag &= ~(PARENB | PARODD); + tty.c_cflag &= ~CSTOPB; + tty.c_cc[VMIN] = 1; + tty.c_cc[VTIME] = 5; + + tcsetattr (opts->serial_fd, TCSANOW, &tty); + +} + +void +resumeScan (dsd_opts * opts, dsd_state * state) +{ + + char cmd[16]; + ssize_t result; + + if (opts->serial_fd > 0) + { + sprintf (cmd, "\rKEY00\r"); + result = write (opts->serial_fd, cmd, 7); + cmd[0] = 2; + cmd[1] = 75; + cmd[2] = 15; + cmd[3] = 3; + cmd[4] = 93; + cmd[5] = 0; + result = write (opts->serial_fd, cmd, 5); + state->numtdulc = 0; + } +} diff --git a/dsd/dsd_state.c b/dsd/dsd_state.c new file mode 100644 index 000000000..961798d44 --- /dev/null +++ b/dsd/dsd_state.c @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include "dsd_state.h" + +void initState(dsd_state * state) +{ + int i, j; + + state->dibit_buf = malloc(sizeof(int) * 1000000); + state->dibit_buf_p = state->dibit_buf + 200; + memset(state->dibit_buf, 0, sizeof(int) * 200); + state->repeat = 0; + state->audio_out_buf = malloc(sizeof(short) * 1000000); + memset(state->audio_out_buf, 0, 100 * sizeof(short)); + state->audio_out_buf_p = state->audio_out_buf + 100; + state->audio_out_float_buf = malloc(sizeof(float) * 1000000); + memset(state->audio_out_float_buf, 0, 100 * sizeof(float)); + state->audio_out_float_buf_p = state->audio_out_float_buf + 100; + state->audio_out_idx = 0; + state->audio_out_idx2 = 0; + state->audio_out_temp_buf_p = state->audio_out_temp_buf; + //state->wav_out_bytes = 0; + state->center = 0; + state->jitter = -1; + state->synctype = -1; + state->min = -15000; + state->max = 15000; + state->lmid = 0; + state->umid = 0; + state->minref = -12000; + state->maxref = 12000; + state->lastsample = 0; + for (i = 0; i < 128; i++) + { + state->sbuf[i] = 0; + } + state->sidx = 0; + for (i = 0; i < 1024; i++) + { + state->maxbuf[i] = 15000; + } + for (i = 0; i < 1024; i++) + { + state->minbuf[i] = -15000; + } + state->midx = 0; + state->err_str[0] = 0; + sprintf(state->fsubtype, " "); + sprintf(state->ftype, " "); + state->symbolcnt = 0; + state->rf_mod = 0; + state->numflips = 0; + state->lastsynctype = -1; + state->lastp25type = 0; + state->offset = 0; + state->carrier = 0; + for (i = 0; i < 25; i++) + { + for (j = 0; j < 16; j++) + { + state->tg[i][j] = 48; + } + } + state->tgcount = 0; + state->lasttg = 0; + state->lastsrc = 0; + state->nac = 0; + state->errs = 0; + state->errs2 = 0; + state->mbe_file_type = -1; + state->optind = 0; + state->numtdulc = 0; + state->firstframe = 0; + sprintf(state->slot0light, " slot0 "); + sprintf(state->slot1light, " slot1 "); + state->aout_gain = 25; + memset(state->aout_max_buf, 0, sizeof(float) * 200); + state->aout_max_buf_p = state->aout_max_buf; + state->aout_max_buf_idx = 0; + state->samplesPerSymbol = 10; + state->symbolCenter = 4; + sprintf(state->algid, "________"); + sprintf(state->keyid, "________________"); + state->currentslot = 0; + state->cur_mp = malloc(sizeof(mbe_parms)); + state->prev_mp = malloc(sizeof(mbe_parms)); + state->prev_mp_enhanced = malloc(sizeof(mbe_parms)); + mbe_initMbeParms(state->cur_mp, state->prev_mp, state->prev_mp_enhanced); + state->p25kid = 0; + + state->debug_audio_errors = 0; + state->debug_header_errors = 0; + state->debug_header_critical_errors = 0; + +#ifdef TRACE_DSD + state->debug_sample_index = 0; + state->debug_label_file = NULL; + state->debug_label_dibit_file = NULL; + state->debug_label_imbe_file = NULL; +#endif + + initialize_p25_heuristics(&state->p25_heuristics); +} + diff --git a/dsd/dsd_state.h b/dsd/dsd_state.h new file mode 100644 index 000000000..bde2f27f8 --- /dev/null +++ b/dsd/dsd_state.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef INCLUDE_DSD_STATE_H_ +#define INCLUDE_DSD_STATE_H_ + +#include +#include +#include "p25p1_heuristics.h" + +typedef struct +{ + int *dibit_buf; + int *dibit_buf_p; + int repeat; + short *audio_out_buf; + short *audio_out_buf_p; + float *audio_out_float_buf; + float *audio_out_float_buf_p; + float audio_out_temp_buf[160]; + float *audio_out_temp_buf_p; + int audio_out_idx; + int audio_out_idx2; + //int wav_out_bytes; + int center; + int jitter; + int synctype; + int min; + int max; + int lmid; + int umid; + int minref; + int maxref; + int lastsample; + int sbuf[128]; + int sidx; + int maxbuf[1024]; + int minbuf[1024]; + int midx; + char err_str[64]; + char fsubtype[16]; + char ftype[16]; + int symbolcnt; + int rf_mod; + int numflips; + int lastsynctype; + int lastp25type; + int offset; + int carrier; + char tg[25][16]; + int tgcount; + int lasttg; + int lastsrc; + int nac; + int errs; + int errs2; + int mbe_file_type; + int optind; + int numtdulc; + int firstframe; + char slot0light[8]; + char slot1light[8]; + float aout_gain; + float aout_max_buf[200]; + float *aout_max_buf_p; + int aout_max_buf_idx; + int samplesPerSymbol; + int symbolCenter; + char algid[9]; + char keyid[17]; + int currentslot; + mbe_parms *cur_mp; + mbe_parms *prev_mp; + mbe_parms *prev_mp_enhanced; + int p25kid; + + pthread_mutex_t input_mutex; + pthread_cond_t input_ready; + const float *input_samples; + int input_length; + int input_offset; + + pthread_mutex_t output_mutex; + pthread_cond_t output_ready; + short *output_buffer; + int output_offset; + float *output_samples; + int output_num_samples; + int output_length; + int output_finished; +} dsd_state; + +void initState (dsd_state * state); + +#endif /* INCLUDE_DSD_STATE_H_ */ diff --git a/dsd/dsd_symbol.c b/dsd/dsd_symbol.c new file mode 100644 index 000000000..2baf63b9d --- /dev/null +++ b/dsd/dsd_symbol.c @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "dsd.h" +#include "dsd_cleanupexit.h" + +int +getSymbol (dsd_opts * opts, dsd_state * state, int have_sync) +{ + + short sample; + int i, sum, symbol, count; + ssize_t result; + + sum = 0; + count = 0; + for (i = 0; i < state->samplesPerSymbol; i++) + { + // timing control + if ((i == 0) && (have_sync == 0)) + { + if (state->samplesPerSymbol == 20) + { + if ((state->jitter >= 7) && (state->jitter <= 10)) + { + i--; + } + else if ((state->jitter >= 11) && (state->jitter <= 14)) + { + i++; + } + } + else if (state->rf_mod == 1) + { + if ((state->jitter >= 0) && (state->jitter < state->symbolCenter)) + { + i++; // fall back + } + else if ((state->jitter > state->symbolCenter) && (state->jitter < 10)) + { + i--; // catch up + } + } + else if (state->rf_mod == 2) + { + if ((state->jitter >= state->symbolCenter - 1) && (state->jitter <= state->symbolCenter)) + { + i--; + } + else if ((state->jitter >= state->symbolCenter + 1) && (state->jitter <= state->symbolCenter + 2)) + { + i++; + } + } + else if (state->rf_mod == 0) + { + if ((state->jitter > 0) && (state->jitter <= state->symbolCenter)) + { + i--; // catch up + } + else if ((state->jitter > state->symbolCenter) && (state->jitter < state->samplesPerSymbol)) + { + i++; // fall back + } + } + state->jitter = -1; + } + if(opts->audio_in_type == 0) { + if (opts->audio_in_fd == -1) + { + while (state->input_length == 0) + { + // If the buffer is empty, wait for more samples to arrive. + if (pthread_cond_wait(&state->input_ready, &state->input_mutex)) + { + printf("getSymbol -> Error waiting for condition\n"); + } + } + // Get the next sample from the buffer, converting from float to short. + sample = (short) (state->input_samples[state->input_offset++] * 32768); + if (state->input_offset == state->input_length) + { + int i; + + // We've reached the end of the buffer. Wait for more next time. + state->input_length = 0; + + if (pthread_mutex_lock(&state->output_mutex)) + { + printf("Unable to lock mutex\n"); + } + + state->output_num_samples = state->output_offset; + if (state->output_num_samples > state->output_length) { + state->output_num_samples = state->output_length; + } + for (i = 0; i < state->output_length - state->output_num_samples; i++) + { + state->output_samples[i] = 0; + } + for (; i < state->output_length; i++) + { + state->output_samples[i] = state->output_buffer[i - (state->output_length - state->output_num_samples)] / 32768.0; + } + state->output_offset -= state->output_num_samples; + for (i = 0; i < state->output_offset; i++) + { + state->output_buffer[i] = state->output_buffer[i + state->output_num_samples]; + } + state->output_finished = 1; + + // Wake up general_work + if (pthread_cond_signal(&state->output_ready)) + { + printf("Unable to signal\n"); + } + + if (pthread_mutex_unlock(&state->output_mutex)) + { + printf("Unable to unlock mutex\n"); + } + } + } + else + { + result = read (opts->audio_in_fd, &sample, 2); + } + + } +#ifdef USE_LIBSNDFILE + else { + result = sf_read_short(opts->audio_in_file, &sample, 1); + if(result == 0) { + cleanupAndExit (opts, state); + } + } +#endif + // printf("res: %zd\n, offset: %lld", result, sf_seek(opts->audio_in_file, 0, SEEK_CUR)); + if (opts->use_cosine_filter) + { + if (state->lastsynctype >= 10 && state->lastsynctype <= 13) + sample = dmr_filter(sample); + else if (state->lastsynctype == 8 || state->lastsynctype == 9 || + state->lastsynctype == 16 || state->lastsynctype == 17) + sample = nxdn_filter(sample); + } + + if ((sample > state->max) && (have_sync == 1) && (state->rf_mod == 0)) + { + sample = state->max; + } + else if ((sample < state->min) && (have_sync == 1) && (state->rf_mod == 0)) + { + sample = state->min; + } + + if (sample > state->center) + { + if (state->lastsample < state->center) + { + state->numflips += 1; + } + if (sample > (state->maxref * 1.25)) + { + if (state->lastsample < (state->maxref * 1.25)) + { + state->numflips += 1; + } + if ((state->jitter < 0) && (state->rf_mod == 1)) + { // first spike out of place + state->jitter = i; + } + if ((opts->symboltiming == 1) && (have_sync == 0) && (state->lastsynctype != -1)) + { + printf ("O"); + } + } + else + { + if ((opts->symboltiming == 1) && (have_sync == 0) && (state->lastsynctype != -1)) + { + printf ("+"); + } + if ((state->jitter < 0) && (state->lastsample < state->center) && (state->rf_mod != 1)) + { // first transition edge + state->jitter = i; + } + } + } + else + { // sample < 0 + if (state->lastsample > state->center) + { + state->numflips += 1; + } + if (sample < (state->minref * 1.25)) + { + if (state->lastsample > (state->minref * 1.25)) + { + state->numflips += 1; + } + if ((state->jitter < 0) && (state->rf_mod == 1)) + { // first spike out of place + state->jitter = i; + } + if ((opts->symboltiming == 1) && (have_sync == 0) && (state->lastsynctype != -1)) + { + printf ("X"); + } + } + else + { + if ((opts->symboltiming == 1) && (have_sync == 0) && (state->lastsynctype != -1)) + { + printf ("-"); + } + if ((state->jitter < 0) && (state->lastsample > state->center) && (state->rf_mod != 1)) + { // first transition edge + state->jitter = i; + } + } + } + if (state->samplesPerSymbol == 20) + { + if ((i >= 9) && (i <= 11)) + { + sum += sample; + count++; + } + } + if (state->samplesPerSymbol == 5) + { + if (i == 2) + { + sum += sample; + count++; + } + } + else + { + if (((i >= state->symbolCenter - 1) && (i <= state->symbolCenter + 2) && (state->rf_mod == 0)) || (((i == state->symbolCenter) || (i == state->symbolCenter + 1)) && (state->rf_mod != 0))) + { + sum += sample; + count++; + } + } + state->lastsample = sample; + } + symbol = (sum / count); + + if ((opts->symboltiming == 1) && (have_sync == 0) && (state->lastsynctype != -1)) + { + if (state->jitter >= 0) + { + printf (" %i\n", state->jitter); + } + else + { + printf ("\n"); + } + } + + state->symbolcnt++; + return (symbol); +} diff --git a/dsd/dsd_upsample.c b/dsd/dsd_upsample.c new file mode 100644 index 000000000..3bbc584df --- /dev/null +++ b/dsd/dsd_upsample.c @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "dsd.h" + +void +upsample (dsd_state * state, float invalue) +{ + + int i, j, sum; + float *outbuf1, c, d; + + outbuf1 = state->audio_out_float_buf_p; + outbuf1--; + c = *outbuf1; + d = invalue; + // basic triangle interpolation + outbuf1++; + *outbuf1 = ((invalue * (float) 0.166) + (c * (float) 0.834)); + outbuf1++; + *outbuf1 = ((invalue * (float) 0.332) + (c * (float) 0.668)); + outbuf1++; + *outbuf1 = ((invalue * (float) 0.5) + (c * (float) 0.5)); + outbuf1++; + *outbuf1 = ((invalue * (float) 0.668) + (c * (float) 0.332)); + outbuf1++; + *outbuf1 = ((invalue * (float) 0.834) + (c * (float) 0.166)); + outbuf1++; + *outbuf1 = d; + outbuf1++; + + if (state->audio_out_idx2 > 24) + { + // smoothing + outbuf1 -= 16; + for (j = 0; j < 4; j++) + { + for (i = 0; i < 6; i++) + { + sum = 0; + outbuf1 -= 2; + sum += *outbuf1; + outbuf1 += 2; + sum += *outbuf1; + outbuf1 += 2; + sum += *outbuf1; + outbuf1 -= 2; + *outbuf1 = (sum / (float) 3); + outbuf1++; + } + outbuf1 -= 8; + } + } +} diff --git a/dsd/dstar.c b/dsd/dstar.c new file mode 100644 index 000000000..358baa1b2 --- /dev/null +++ b/dsd/dstar.c @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Note: D-STAR support is fairly complete at this point. + * The ambe3600x2450 decoder is similar butnot compatible with D-STAR voice frames. + * The dstar interleave pattern is different as well. + * GMSK modulation optimizations will also required to get a usable bit error + */ + +#include "dsd.h" +#include "dstar_const.h" +#include "dstar_header.h" + + +void processDSTAR(dsd_opts * opts, dsd_state * state) { + // extracts AMBE frames from D-STAR voice frame + int i, j, dibit; + char ambe_fr[4][24]; + unsigned char data[9]; + unsigned int bits[4]; + int framecount; + int sync_missed = 0; + unsigned char slowdata[4]; + unsigned int bitbuffer = 0; + const int *w, *x; + + if (opts->errorbars == 1) { + printf("e:"); + } + +#ifdef DSTAR_DUMP + printf ("\n"); +#endif + + if (state->synctype == 18) { + framecount = 0; + state->synctype = 6; + } else if (state->synctype == 19) { + framecount = 0; + state->synctype = 7; + } else { + framecount = 1; //just saw a sync frame; there should be 20 not 21 till the next + } + + while (sync_missed < 3) { + + memset(ambe_fr, 0, 96); + // voice frame + w = dW; + x = dX; + + for (i = 0; i < 72; i++) { + + dibit = getDibit(opts, state); + + bitbuffer <<= 1; + if (dibit == 1) { + bitbuffer |= 0x01; + } + if ((bitbuffer & 0x00FFFFFF) == 0x00AAB468) { + // we're slipping bits + printf("sync in voice after i=%d, restarting\n", i); + //ugh just start over + i = 0; + w = dW; + x = dX; + framecount = 1; + continue; + } + + ambe_fr[*w][*x] = (1 & dibit); + w++; + x++; + } + + + processMbeFrame(opts, state, NULL, ambe_fr, NULL); + + // data frame - 24 bits + for (i = 73; i < 97; i++) { + dibit = getDibit(opts, state); + bitbuffer <<= 1; + if (dibit == 1) { + bitbuffer |= 0x01; + } + if ((bitbuffer & 0x00FFFFFF) == 0x00AAB468) { + // looking if we're slipping bits + if (i != 96) { + printf("sync after i=%d\n", i); + i = 96; + } + } + } + + slowdata[0] = (bitbuffer >> 16) & 0x000000FF; + slowdata[1] = (bitbuffer >> 8) & 0x000000FF; + slowdata[2] = (bitbuffer) & 0x000000FF; + slowdata[3] = 0; + + if ((bitbuffer & 0x00FFFFFF) == 0x00AAB468) { + //We got sync! + //printf("Sync on framecount = %d\n", framecount); + sync_missed = 0; + } else if ((bitbuffer & 0x00FFFFFF) == 0xAAAAAA) { + //End of transmission + printf("End of transmission\n"); + goto end; + } else if (framecount % 21 == 0) { + printf("Missed sync on framecount = %d, value = %x/%x/%x\n", + framecount, slowdata[0], slowdata[1], slowdata[2]); + sync_missed++; + } else if (framecount != 0 && (bitbuffer & 0x00FFFFFF) != 0x000000) { + slowdata[0] ^= 0x70; + slowdata[1] ^= 0x4f; + slowdata[2] ^= 0x93; + //printf("unscrambled- %s",slowdata); + + } else if (framecount == 0) { + //printf("never scrambled-%s\n",slowdata); + } + + framecount++; + } + + end: if (opts->errorbars == 1) { + printf("\n"); + } +} + +void processDSTAR_HD(dsd_opts * opts, dsd_state * state) { + + int i, j; + int radioheaderbuffer[660]; + + for (j = 0; j < 660; j++) { + radioheaderbuffer[j] = getDibit(opts, state); + } + + // Note: These routines contain GPLed code. Remove if you object to that. + // Due to this, they are in a separate source file. + dstar_header_decode(radioheaderbuffer); + + //We officially have sync now, so just pass on to the above routine: + + processDSTAR(opts, state); + +} + diff --git a/dsd/dstar_const.h b/dsd/dstar_const.h new file mode 100644 index 000000000..23df45918 --- /dev/null +++ b/dsd/dstar_const.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * dstar interleave experiments + */ + +#ifndef _MAIN + +extern const int dW[72]; +extern const int dX[72]; + +#else +const int dW[72] = { + + // 0-11 + 0, 0, + 3, 2, + 1, 1, + 0, 0, + 1, 1, + 0, 0, + + // 12-23 + 3, 2, + 1, 1, + 3, 2, + 1, 1, + 0, 0, + 3, 2, + + // 24-35 + 0, 0, + 3, 2, + 1, 1, + 0, 0, + 1, 1, + 0, 0, + + // 36-47 + 3, 2, + 1, 1, + 3, 2, + 1, 1, + 0, 0, + 3, 2, + + // 48-59 + 0, 0, + 3, 2, + 1, 1, + 0, 0, + 1, 1, + 0, 0, + + // 60-71 + 3, 2, + 1, 1, + 3, 3, + 2, 1, + 0, 0, + 3, 3, +}; +const int dX[72] = { + + // 0-11 + 10, 22, + 11, 9, + 10, 22, + 11, 23, + 8, 20, + 9, 21, + + // 12-23 + 10, 8, + 9, 21, + 8, 6, + 7, 19, + 8, 20, + 9, 7, + + // 24-35 + 6, 18, + 7, 5, + 6, 18, + 7, 19, + 4, 16, + 5, 17, + + // 36-47 + 6, 4, + 5, 17, + 4, 2, + 3, 15, + 4, 16, + 5, 3, + + // 48-59 + 2, 14, + 3, 1, + 2, 14, + 3, 15, + 0, 12, + 1, 13, + + // 60-71 + 2, 0, + 1, 13, + 0, 12, + 10, 11, + 0, 12, + 1, 13, +}; + +#endif diff --git a/dsd/dstar_header.c b/dsd/dstar_header.c new file mode 100644 index 000000000..9314b9ee3 --- /dev/null +++ b/dsd/dstar_header.c @@ -0,0 +1,76 @@ +/* + * + * This code is taken largely from on1arf's GMSK code. Original copyright below: + * + * +* Copyright (C) 2011 by Kristoff Bonne, ON1ARF +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; version 2 of the License. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. + * + */ + +#include "fcs.h" +#include "descramble.h" +#include "dstar_header.h" + +void dstar_header_decode(int radioheaderbuffer[660]) { + int radioheaderbuffer2[660]; + unsigned char radioheader[41]; + int octetcount, bitcount, loop; + unsigned char bit2octet[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; + unsigned int FCSinheader; + unsigned int FCScalculated; + int len; + + scramble(radioheaderbuffer, radioheaderbuffer2); + deinterleave(radioheaderbuffer2, radioheaderbuffer); + len = FECdecoder(radioheaderbuffer, radioheaderbuffer2); + memset(radioheader, 0, 41); + // note we receive 330 bits, but we only use 328 of them (41 octets) + // bits 329 and 330 are unused + octetcount = 0; + bitcount = 0; + for (loop = 0; loop < 328; loop++) { + if (radioheaderbuffer2[loop]) { + radioheader[octetcount] |= bit2octet[bitcount]; + }; + bitcount++; + // increase octetcounter and reset bitcounter every 8 bits + if (bitcount >= 8) { + octetcount++; + bitcount = 0; + } + } + // print header + printf("\nDSTAR HEADER: "); + //printf("FLAG1: %02X - FLAG2: %02X - FLAG3: %02X\n", radioheader[0], + // radioheader[1], radioheader[2]); + printf("RPT 2: %c%c%c%c%c%c%c%c ", radioheader[3], radioheader[4], + radioheader[5], radioheader[6], radioheader[7], radioheader[8], + radioheader[9], radioheader[10]); + printf("RPT 1: %c%c%c%c%c%c%c%c ", radioheader[11], radioheader[12], + radioheader[13], radioheader[14], radioheader[15], radioheader[16], + radioheader[17], radioheader[18]); + printf("YOUR: %c%c%c%c%c%c%c%c ", radioheader[19], radioheader[20], + radioheader[21], radioheader[22], radioheader[23], radioheader[24], + radioheader[25], radioheader[26]); + printf("MY: %c%c%c%c%c%c%c%c/%c%c%c%c\n", radioheader[27], + radioheader[28], radioheader[29], radioheader[30], radioheader[31], + radioheader[32], radioheader[33], radioheader[34], radioheader[35], + radioheader[36], radioheader[37], radioheader[38]); + //FCSinheader = ((radioheader[39] << 8) | radioheader[40]) & 0xFFFF; + //FCScalculated = calc_fcs((unsigned char*) radioheader, 39); + //printf("Check sum = %04X ", FCSinheader); + //if (FCSinheader == FCScalculated) { + // printf("(OK)\n"); + //} else { + // printf("(NOT OK- Calculated FCS = %04X)\n", FCScalculated); + //}; // end else - if +} diff --git a/dsd/dstar_header.h b/dsd/dstar_header.h new file mode 100644 index 000000000..9723fbfaa --- /dev/null +++ b/dsd/dstar_header.h @@ -0,0 +1,6 @@ +/* This is the header file for dstar_header.c, which is under the GPL. */ + +#ifndef _DSTAR_HEADER_H +#define _DSTAR_HEADER_H +void dstar_header_decode(int radioheaderbuffer[660]); +#endif /* _DSTAR_HEADER_H */ \ No newline at end of file diff --git a/dsd/fcs.h b/dsd/fcs.h new file mode 100644 index 000000000..314ebac52 --- /dev/null +++ b/dsd/fcs.h @@ -0,0 +1,91 @@ +/* fcs.h */ + +// Viterbi decoder using Traceback method. + +// Original Source was written by Sho Tamaoki and Tom Wada +// See http://www.lsi.ie.u-ryukyu.ac.jp/~sho/midterm/ +// Modified by Satoshi Yasuda 7m3tjz/ad6gz +// Modified by Jonathan Nayor, G4KLX (C) 2009 + +// Converted from C++ to C by Kristoff Bonne, ON1ARF + +/* + * Copyright (C) 2010 by Kristoff Bonne, ON1ARF + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +static const unsigned short ccittTab[] = { + 0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf, + 0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7, + 0x1081,0x0108,0x3393,0x221a,0x56a5,0x472c,0x75b7,0x643e, + 0x9cc9,0x8d40,0xbfdb,0xae52,0xdaed,0xcb64,0xf9ff,0xe876, + 0x2102,0x308b,0x0210,0x1399,0x6726,0x76af,0x4434,0x55bd, + 0xad4a,0xbcc3,0x8e58,0x9fd1,0xeb6e,0xfae7,0xc87c,0xd9f5, + 0x3183,0x200a,0x1291,0x0318,0x77a7,0x662e,0x54b5,0x453c, + 0xbdcb,0xac42,0x9ed9,0x8f50,0xfbef,0xea66,0xd8fd,0xc974, + 0x4204,0x538d,0x6116,0x709f,0x0420,0x15a9,0x2732,0x36bb, + 0xce4c,0xdfc5,0xed5e,0xfcd7,0x8868,0x99e1,0xab7a,0xbaf3, + 0x5285,0x430c,0x7197,0x601e,0x14a1,0x0528,0x37b3,0x263a, + 0xdecd,0xcf44,0xfddf,0xec56,0x98e9,0x8960,0xbbfb,0xaa72, + 0x6306,0x728f,0x4014,0x519d,0x2522,0x34ab,0x0630,0x17b9, + 0xef4e,0xfec7,0xcc5c,0xddd5,0xa96a,0xb8e3,0x8a78,0x9bf1, + 0x7387,0x620e,0x5095,0x411c,0x35a3,0x242a,0x16b1,0x0738, + 0xffcf,0xee46,0xdcdd,0xcd54,0xb9eb,0xa862,0x9af9,0x8b70, + 0x8408,0x9581,0xa71a,0xb693,0xc22c,0xd3a5,0xe13e,0xf0b7, + 0x0840,0x19c9,0x2b52,0x3adb,0x4e64,0x5fed,0x6d76,0x7cff, + 0x9489,0x8500,0xb79b,0xa612,0xd2ad,0xc324,0xf1bf,0xe036, + 0x18c1,0x0948,0x3bd3,0x2a5a,0x5ee5,0x4f6c,0x7df7,0x6c7e, + 0xa50a,0xb483,0x8618,0x9791,0xe32e,0xf2a7,0xc03c,0xd1b5, + 0x2942,0x38cb,0x0a50,0x1bd9,0x6f66,0x7eef,0x4c74,0x5dfd, + 0xb58b,0xa402,0x9699,0x8710,0xf3af,0xe226,0xd0bd,0xc134, + 0x39c3,0x284a,0x1ad1,0x0b58,0x7fe7,0x6e6e,0x5cf5,0x4d7c, + 0xc60c,0xd785,0xe51e,0xf497,0x8028,0x91a1,0xa33a,0xb2b3, + 0x4a44,0x5bcd,0x6956,0x78df,0x0c60,0x1de9,0x2f72,0x3efb, + 0xd68d,0xc704,0xf59f,0xe416,0x90a9,0x8120,0xb3bb,0xa232, + 0x5ac5,0x4b4c,0x79d7,0x685e,0x1ce1,0x0d68,0x3ff3,0x2e7a, + 0xe70e,0xf687,0xc41c,0xd595,0xa12a,0xb0a3,0x8238,0x93b1, + 0x6b46,0x7acf,0x4854,0x59dd,0x2d62,0x3ceb,0x0e70,0x1ff9, + 0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330, + 0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78}; + + +uint16_t calc_fcs (unsigned char * dvstartframe, int size) { +// this function calculated the CRC-values of a DSTAR digital +// voice frame. It calculates this value on octets 0 up to 38 of the D-STAR +// radio header (fields flag1, flag2, flag3, destination, departure, companion, +// own1 and own2) +uint16_t m_crc; + +m_crc=0xFFFF; + +int loop; +unsigned short tmp; + + +for (loop=0; loop < size; loop++) { + tmp = (m_crc & 0x00ff) ^ dvstartframe[loop]; + + m_crc = (m_crc >> 8) ^ ccittTab[tmp]; + +}; // end for + +// calculate and save crc-value in fields 54 and 55 of dvframe +m_crc = ~m_crc; + +tmp = m_crc; +m_crc = (m_crc << 8) | (tmp >> 8 & 0xFF); + + +// done +return(m_crc); +}; // end function diff --git a/dsd/git_ver.c.in b/dsd/git_ver.c.in new file mode 100644 index 000000000..36e042b95 --- /dev/null +++ b/dsd/git_ver.c.in @@ -0,0 +1,2 @@ +#define _GIT_TAG "@GIT_TAG@" +const char GIT_TAG[] = _GIT_TAG; diff --git a/dsd/git_ver.h b/dsd/git_ver.h new file mode 100644 index 000000000..be9b35520 --- /dev/null +++ b/dsd/git_ver.h @@ -0,0 +1 @@ +extern const char GIT_TAG[]; diff --git a/dsd/nxdn96.c b/dsd/nxdn96.c new file mode 100644 index 000000000..4072b7674 --- /dev/null +++ b/dsd/nxdn96.c @@ -0,0 +1,124 @@ +#include "dsd.h" +#include "nxdn96_const.h" + +void +processNXDN96 (dsd_opts * opts, dsd_state * state) +{ + int i, j, k, dibit; + + char ambe_fr[4][24]; + const int *w, *x, *y, *z; + + if (opts->errorbars == 1) + { + printf ("VOICE e:"); + } + +#ifdef NXDN_DUMP + printf ("\n"); +#endif + + for (k = 0; k < 4; k++) + { + for (i = 0; i < 222; i++) + { + dibit = getDibit (opts, state); +#ifdef NXDN_DUMP + printf ("%c", dibit + 48); +#endif + } +#ifdef NXDN_DUMP + printf (" "); +#endif + + if (k < 3) + { + for (j = 0; j < 4; j++) + { + w = nW; + x = nX; + y = nY; + z = nZ; + for (i = 0; i < 36; i++) + { + dibit = getDibit (opts, state); +#ifdef NXDN_DUMP + printf ("%c", dibit + 48); +#endif + ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1 + ambe_fr[*y][*z] = (1 & dibit); // bit 0 + w++; + x++; + y++; + z++; + } + processMbeFrame (opts, state, NULL, ambe_fr, NULL); +#ifdef NXDN_DUMP + printf (" "); +#endif + } + } + else + { + for (j = 0; j < 3; j++) // we skip the last voice frame until frame sync can work with < 24 symbols + { + w = nW; + x = nX; + y = nY; + z = nZ; + for (i = 0; i < 36; i++) + { + dibit = getDibit (opts, state); +#ifdef NXDN_DUMP + printf ("%c", dibit + 48); +#endif + ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1 + ambe_fr[*y][*z] = (1 & dibit); // bit 0 + w++; + x++; + y++; + z++; + } + processMbeFrame (opts, state, NULL, ambe_fr, NULL); +#ifdef NXDN_DUMP + printf (" "); +#endif + } + } + + if (k < 3) + { + for (i = 0; i < 18; i++) + { + dibit = getDibit (opts, state); +#ifdef NXDN_DUMP + printf ("%c", dibit + 48); +#endif + } +#ifdef NXDN_DUMP + printf (" "); +#endif + + } + else + { + for (i = 0; i < 30; i++) + { + dibit = getDibit (opts, state); +#ifdef NXDN_DUMP + printf ("%c", dibit + 48); +#endif + } + } + } + +#ifdef NXDN_DUMP + printf ("\n"); +#endif + + if (opts->errorbars == 1) + { + printf ("\n"); + } + +} diff --git a/dsd/nxdn96_const.h b/dsd/nxdn96_const.h new file mode 100644 index 000000000..8af701ee5 --- /dev/null +++ b/dsd/nxdn96_const.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * NXDN AMBE interleave schedule + */ + +#ifndef _MAIN +extern const int nW[36]; +extern const int nX[36]; +extern const int nY[36]; +extern const int nZ[36]; + +#else + +const int nW[36] = { 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 2, + 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2 +}; + +const int nX[36] = { 23, 10, 22, 9, 21, 8, + 20, 7, 19, 6, 18, 5, + 17, 4, 16, 3, 15, 2, + 14, 1, 13, 0, 12, 10, + 11, 9, 10, 8, 9, 7, + 8, 6, 7, 5, 6, 4 +}; + +const int nY[36] = { 0, 2, 0, 2, 0, 2, + 0, 2, 0, 3, 0, 3, + 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 3 +}; + +const int nZ[36] = { 5, 3, 4, 2, 3, 1, + 2, 0, 1, 13, 0, 12, + 22, 11, 21, 10, 20, 9, + 19, 8, 18, 7, 17, 6, + 16, 5, 15, 4, 14, 3, + 13, 2, 12, 1, 11, 0 +}; + +#endif diff --git a/dsd/nxdn_const.h b/dsd/nxdn_const.h new file mode 100644 index 000000000..a447faa13 --- /dev/null +++ b/dsd/nxdn_const.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _MAIN +extern const int nW[36]; +extern const int nX[36]; +extern const int nY[36]; +extern const int nZ[36]; +extern const char nxdnpr[145]; + +#else +/* + * pseudorandom bit sequence + */ +const char nxdnpr[145] = { 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1 }; + +/* + * NXDN AMBE interleave schedule + */ +const int nW[36] = { 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 2, + 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2 +}; + +const int nX[36] = { 23, 10, 22, 9, 21, 8, + 20, 7, 19, 6, 18, 5, + 17, 4, 16, 3, 15, 2, + 14, 1, 13, 0, 12, 10, + 11, 9, 10, 8, 9, 7, + 8, 6, 7, 5, 6, 4 +}; + +const int nY[36] = { 0, 2, 0, 2, 0, 2, + 0, 2, 0, 3, 0, 3, + 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 3 +}; + +const int nZ[36] = { 5, 3, 4, 2, 3, 1, + 2, 0, 1, 13, 0, 12, + 22, 11, 21, 10, 20, 9, + 19, 8, 18, 7, 17, 6, + 16, 5, 15, 4, 14, 3, + 13, 2, 12, 1, 11, 0 +}; + +#endif diff --git a/dsd/nxdn_data.c b/dsd/nxdn_data.c new file mode 100644 index 000000000..403fe7abf --- /dev/null +++ b/dsd/nxdn_data.c @@ -0,0 +1,36 @@ +#include "dsd.h" + +void +processNXDNData (dsd_opts * opts, dsd_state * state) +{ + int i, dibit; + + if (opts->errorbars == 1) + { + printf ("DATA "); + } + + for (i = 0; i < 30; i++) + { + dibit = getDibit (opts, state); +#ifdef NXDN_DUMP + printf ("%c", dibit + 48); +#endif + } +#ifdef NXDN_DUMP + printf (" "); +#endif + + for (i = 0; i < 144; i++) + { + dibit = getDibit (opts, state); +#ifdef NXDN_DUMP + printf ("%c", dibit + 48); +#endif + } + + if (opts->errorbars == 1) + { + printf ("\n"); + } +} diff --git a/dsd/nxdn_voice.c b/dsd/nxdn_voice.c new file mode 100644 index 000000000..2f001fc94 --- /dev/null +++ b/dsd/nxdn_voice.c @@ -0,0 +1,59 @@ +#include "dsd.h" +#include "nxdn_const.h" + +void +processNXDNVoice (dsd_opts * opts, dsd_state * state) +{ + int i, j, dibit; + char ambe_fr[4][24]; + const int *w, *x, *y, *z; + const char *pr; + + if (opts->errorbars == 1) + { + printf ("VOICE e:"); + } + + for (i = 0; i < 30; i++) + { + dibit = getDibit (opts, state); +#ifdef NXDN_DUMP + printf ("%c", dibit + 48); +#endif + } +#ifdef NXDN_DUMP + printf (" "); +#endif + + pr = nxdnpr; + for (j = 0; j < 4; j++) + { + w = nW; + x = nX; + y = nY; + z = nZ; + for (i = 0; i < 36; i++) + { + dibit = getDibit (opts, state); +#ifdef NXDN_DUMP + printf ("%c", dibit + 48); +#endif + ambe_fr[*w][*x] = *pr ^ (1 & (dibit >> 1)); // bit 1 + pr++; + ambe_fr[*y][*z] = (1 & dibit); // bit 0 + w++; + x++; + y++; + z++; + } + processMbeFrame (opts, state, NULL, ambe_fr, NULL); +#ifdef NXDN_DUMP + printf (" "); +#endif + } + + if (opts->errorbars == 1) + { + printf ("\n"); + } +} diff --git a/dsd/p25_lcw.c b/dsd/p25_lcw.c new file mode 100644 index 000000000..392d11eb9 --- /dev/null +++ b/dsd/p25_lcw.c @@ -0,0 +1,160 @@ +#include "dsd.h" + +void +processP25lcw (dsd_opts * opts, dsd_state * state, char *lcformat, char *mfid, char *lcinfo) +{ + + char tgid[17], tmpstr[255]; + long talkgroup, source; + int i, j; + + tgid[16] = 0; + + if (opts->p25lc == 1) + { + printf ("lcformat: %s mfid: %s lcinfo: %s ", lcformat, mfid, lcinfo); + if (opts->p25tg == 0) + { + printf ("\n"); + } + } + + if (strcmp (lcformat, "00000100") == 0) + { + + // first tg is the active channel + j = 0; + for (i = 40; i < 52; i++) + { + if (state->tgcount < 24) + { + state->tg[state->tgcount][j] = lcinfo[i]; + } + tmpstr[j] = lcinfo[i]; + j++; + } + tmpstr[12] = 48; + tmpstr[13] = 48; + tmpstr[14] = 48; + tmpstr[15] = 48; + tmpstr[16] = 0; + talkgroup = strtol (tmpstr, NULL, 2); + state->lasttg = talkgroup; + if (state->tgcount < 24) + { + state->tgcount = state->tgcount + 1; + } + if (opts->p25tg == 1) + { + printf ("tg: %li ", talkgroup); + } + + if (opts->p25tg == 1) + { + printf ("tg: %li ", talkgroup); + + // the remaining 3 appear to be other active tg's on the system + j = 0; + for (i = 28; i < 40; i++) + { + tmpstr[j] = lcinfo[i]; + j++; + } + tmpstr[12] = 48; + tmpstr[13] = 48; + tmpstr[14] = 48; + tmpstr[15] = 48; + tmpstr[16] = 0; + talkgroup = strtol (tmpstr, NULL, 2); + printf ("%li ", talkgroup); + j = 0; + for (i = 16; i < 28; i++) + { + tmpstr[j] = lcinfo[i]; + j++; + } + tmpstr[12] = 48; + tmpstr[13] = 48; + tmpstr[14] = 48; + tmpstr[15] = 48; + tmpstr[16] = 0; + talkgroup = strtol (tmpstr, NULL, 2); + printf ("%li ", talkgroup); + j = 0; + for (i = 4; i < 16; i++) + { + tmpstr[j] = lcinfo[i]; + j++; + } + tmpstr[12] = 48; + tmpstr[13] = 48; + tmpstr[14] = 48; + tmpstr[15] = 48; + tmpstr[16] = 0; + talkgroup = strtol (tmpstr, NULL, 2); + printf ("%li\n", talkgroup); + } + } + + else if (strcmp (lcformat, "00000000") == 0) + { + j = 0; + if (strcmp (mfid, "10010000") == 0) + { + for (i = 20; i < 32; i++) + { + if (state->tgcount < 24) + { + state->tg[state->tgcount][j] = lcinfo[i]; + } + tmpstr[j] = lcinfo[i]; + j++; + } + tmpstr[12] = 48; + tmpstr[13] = 48; + tmpstr[14] = 48; + tmpstr[15] = 48; + } + else + { + for (i = 16; i < 32; i++) + { + if (state->tgcount < 24) + { + state->tg[state->tgcount][j] = lcinfo[i]; + } + tmpstr[j] = lcinfo[i]; + j++; + } + } + tmpstr[16] = 0; + talkgroup = strtol (tmpstr, NULL, 2); + state->lasttg = talkgroup; + if (state->tgcount < 24) + { + state->tgcount = state->tgcount + 1; + } + if (opts->p25tg == 1) + { + printf ("tg: %li ", talkgroup); + } + + j = 0; + for (i = 32; i < 56; i++) + { + tmpstr[j] = lcinfo[i]; + j++; + } + tmpstr[24] = 0; + source = strtol (tmpstr, NULL, 2); + state->lastsrc = source; + if (opts->p25tg == 1) + { + printf ("src: %li emr: %c\n", source, lcinfo[0]); + } + } + else if ((opts->p25tg == 1) && (opts->p25lc == 1)) + { + printf ("\n"); + } +} diff --git a/dsd/p25p1_const.h b/dsd/p25p1_const.h new file mode 100644 index 000000000..5f67dde0d --- /dev/null +++ b/dsd/p25p1_const.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _MAIN + +extern const int iW[72]; +extern const int iX[72]; +extern const int iY[72]; +extern const int iZ[72]; + +#else +/* + * P25 Phase1 IMBE interleave schedule + */ + +const int iW[72] = { + 0, 2, 4, 1, 3, 5, + 0, 2, 4, 1, 3, 6, + 0, 2, 4, 1, 3, 6, + 0, 2, 4, 1, 3, 6, + 0, 2, 4, 1, 3, 6, + 0, 2, 4, 1, 3, 6, + 0, 2, 5, 1, 3, 6, + 0, 2, 5, 1, 3, 6, + 0, 2, 5, 1, 3, 7, + 0, 2, 5, 1, 3, 7, + 0, 2, 5, 1, 4, 7, + 0, 3, 5, 2, 4, 7 +}; + +const int iX[72] = { + 22, 20, 10, 20, 18, 0, + 20, 18, 8, 18, 16, 13, + 18, 16, 6, 16, 14, 11, + 16, 14, 4, 14, 12, 9, + 14, 12, 2, 12, 10, 7, + 12, 10, 0, 10, 8, 5, + 10, 8, 13, 8, 6, 3, + 8, 6, 11, 6, 4, 1, + 6, 4, 9, 4, 2, 6, + 4, 2, 7, 2, 0, 4, + 2, 0, 5, 0, 13, 2, + 0, 21, 3, 21, 11, 0 +}; + +const int iY[72] = { + 1, 3, 5, 0, 2, 4, + 1, 3, 6, 0, 2, 4, + 1, 3, 6, 0, 2, 4, + 1, 3, 6, 0, 2, 4, + 1, 3, 6, 0, 2, 4, + 1, 3, 6, 0, 2, 5, + 1, 3, 6, 0, 2, 5, + 1, 3, 6, 0, 2, 5, + 1, 3, 6, 0, 2, 5, + 1, 3, 7, 0, 2, 5, + 1, 4, 7, 0, 3, 5, + 2, 4, 7, 1, 3, 5 +}; + +const int iZ[72] = { + 21, 19, 1, 21, 19, 9, + 19, 17, 14, 19, 17, 7, + 17, 15, 12, 17, 15, 5, + 15, 13, 10, 15, 13, 3, + 13, 11, 8, 13, 11, 1, + 11, 9, 6, 11, 9, 14, + 9, 7, 4, 9, 7, 12, + 7, 5, 2, 7, 5, 10, + 5, 3, 0, 5, 3, 8, + 3, 1, 5, 3, 1, 6, + 1, 14, 3, 1, 22, 4, + 22, 12, 1, 22, 20, 2 +}; +#endif diff --git a/dsd/p25p1_hdu.c b/dsd/p25p1_hdu.c new file mode 100644 index 000000000..2f0f3f9dc --- /dev/null +++ b/dsd/p25p1_hdu.c @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "dsd.h" + +void +processHDU (dsd_opts * opts, dsd_state * state) +{ + + char mi[73], mfid[9], algid[9], kid[17], tgid[17], tmpstr[255]; + int dibit, count, i, j; + long talkgroup; + int algidhex, kidhex; + + mi[72] = 0; + mfid[8] = 0; + algid[8] = 0; + kid[16] = 0; + tgid[16] = 0; + + skipDibit (opts, state, 25); + count = 57; + + dibit = getDibit (opts, state); + mi[0] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[1] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[2] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[3] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[4] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[5] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 6); + + dibit = getDibit (opts, state); + mi[6] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[7] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[8] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[9] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[10] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[11] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 7); + + dibit = getDibit (opts, state); + mi[12] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[13] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[14] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[15] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[16] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[17] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 6); + + dibit = getDibit (opts, state); + mi[18] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[19] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[20] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[21] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[22] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[23] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 6); + + dibit = getDibit (opts, state); + mi[24] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[25] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[26] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[27] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[28] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[29] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 6); + + dibit = getDibit (opts, state); + mi[30] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[31] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[32] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[33] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[34] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[35] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 7); + + dibit = getDibit (opts, state); + mi[36] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[37] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[38] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[39] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[40] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[41] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 6); + + dibit = getDibit (opts, state); + mi[42] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[43] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[44] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[45] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[46] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[47] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 6); + + dibit = getDibit (opts, state); + mi[48] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[49] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[50] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[51] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[52] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[53] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 6); + + dibit = getDibit (opts, state); + mi[54] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[55] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[56] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[57] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[58] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[59] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 7); + + dibit = getDibit (opts, state); + mi[60] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[61] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[62] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[63] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[64] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[65] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 6); + + dibit = getDibit (opts, state); + mi[66] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[67] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[68] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[69] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[70] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[71] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 6); + + dibit = getDibit (opts, state); + mfid[0] = (1 & (dibit >> 1)) + 48; // bit 1 + mfid[1] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mfid[2] = (1 & (dibit >> 1)) + 48; // bit 1 + mfid[3] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mfid[4] = (1 & (dibit >> 1)) + 48; // bit 1 + mfid[5] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 6); + + dibit = getDibit (opts, state); + mfid[6] = (1 & (dibit >> 1)) + 48; // bit 1 + mfid[7] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + algid[0] = (1 & (dibit >> 1)) + 48; // bit 1 + algid[1] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 1); + dibit = getDibit (opts, state); + algid[2] = (1 & (dibit >> 1)) + 48; // bit 1 + algid[3] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 6); + + dibit = getDibit (opts, state); + algid[4] = (1 & (dibit >> 1)) + 48; // bit 1 + algid[5] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + algid[6] = (1 & (dibit >> 1)) + 48; // bit 1 + algid[7] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + kid[0] = (1 & (dibit >> 1)) + 48; // bit 1 + kid[1] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 6); + + dibit = getDibit (opts, state); + kid[2] = (1 & (dibit >> 1)) + 48; // bit 1 + kid[3] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + kid[4] = (1 & (dibit >> 1)) + 48; // bit 1 + kid[5] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + kid[6] = (1 & (dibit >> 1)) + 48; // bit 1 + kid[7] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 6); + + dibit = getDibit (opts, state); + kid[8] = (1 & (dibit >> 1)) + 48; // bit 1 + kid[9] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + kid[10] = (1 & (dibit >> 1)) + 48; // bit 1 + kid[11] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + kid[12] = (1 & (dibit >> 1)) + 48; // bit 1 + kid[13] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 6); + + dibit = getDibit (opts, state); + kid[14] = (1 & (dibit >> 1)) + 48; // bit 1 + kid[15] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 1); + dibit = getDibit (opts, state); + tgid[0] = (1 & (dibit >> 1)) + 48; // bit 1 + tgid[1] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + tgid[2] = (1 & (dibit >> 1)) + 48; // bit 1 + tgid[3] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 6); + + dibit = getDibit (opts, state); + tgid[4] = (1 & (dibit >> 1)) + 48; // bit 1 + tgid[5] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + tgid[6] = (1 & (dibit >> 1)) + 48; // bit 1 + tgid[7] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + tgid[8] = (1 & (dibit >> 1)) + 48; // bit 1 + tgid[9] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 6); + + dibit = getDibit (opts, state); + tgid[10] = (1 & (dibit >> 1)) + 48; // bit 1 + tgid[11] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + tgid[12] = (1 & (dibit >> 1)) + 48; // bit 1 + tgid[13] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + tgid[14] = (1 & (dibit >> 1)) + 48; // bit 1 + tgid[15] = (1 & dibit) + 48; // bit 0 + + skipDibit (opts, state, 160); + + state->p25kid = strtol(kid, NULL, 2); + + if (opts->p25enc == 1) + { + algidhex = strtol (algid, NULL, 2); + kidhex = strtol (kid, NULL, 2); + printf ("mi: %s algid: $%x kid: $%x\n", mi, algidhex, kidhex); + } + if (opts->p25lc == 1) + { + printf ("mfid: %s tgid: %s ", mfid, tgid); + if (opts->p25tg == 0) + { + printf ("\n"); + } + } + + j = 0; + if (strcmp (mfid, "10010000") == 0) + { + for (i = 4; i < 16; i++) + { + if (state->tgcount < 24) + { + state->tg[state->tgcount][j] = tgid[i]; + } + tmpstr[j] = tgid[i]; + j++; + } + tmpstr[12] = 48; + tmpstr[13] = 48; + tmpstr[14] = 48; + tmpstr[15] = 48; + } + else + { + for (i = 0; i < 16; i++) + { + if (state->tgcount < 24) + { + state->tg[state->tgcount][j] = tgid[i]; + } + tmpstr[j] = tgid[i]; + j++; + } + } + tmpstr[16] = 0; + talkgroup = strtol (tmpstr, NULL, 2); + state->lasttg = talkgroup; + if (state->tgcount < 24) + { + state->tgcount = state->tgcount + 1; + } + if (opts->p25tg == 1) + { + printf ("tg: %li\n", talkgroup); + } +} diff --git a/dsd/p25p1_heuristics.h b/dsd/p25p1_heuristics.h new file mode 100644 index 000000000..a4245962a --- /dev/null +++ b/dsd/p25p1_heuristics.h @@ -0,0 +1,91 @@ + +#ifndef P25P1_HEURISTICS_H_030dd3530b7546abbb56f8dd1e66a2f6 +#define P25P1_HEURISTICS_H_030dd3530b7546abbb56f8dd1e66a2f6 + +#define HEURISTICS_SIZE 200 +typedef struct +{ + int values[HEURISTICS_SIZE]; + float means[HEURISTICS_SIZE]; + int index; + int count; + float sum; + float var_sum; +} SymbolHeuristics; + +typedef struct +{ + unsigned int bit_count; + unsigned int bit_error_count; + SymbolHeuristics symbols[4][4]; +} P25Heuristics; + +typedef struct +{ + int value; + int dibit; + int corrected_dibit; + int sequence_broken; +} AnalogSignal; + +#ifdef __cplusplus +extern "C"{ +#endif + +/** + * Initializes the heuristics state. + * \param heuristics The P25Heuristics structure to initialize. + */ +void initialize_p25_heuristics(P25Heuristics* heuristics); + +/** + * Important method that estimates the most likely symbol for a given analog signal value and previous dibit. + * This is called by the digitizer. + * \param rf_mod Indicates the modulation used. The previous dibit is only used on C4FM. + * \param heuristics Pointer to the P25Heuristics module with all the needed state information. + * \param previous_dibit The previous dibit. + * \param analog_value The signal's analog value we want to interpret as a dibit. + * \param dibit Address were to store the estimated dibit. + * \return A boolean set to true if we are able to estimate a dibit. The reason why we might not be able + * to estimate it is because we don't have enough information to model the Gaussians (not enough data + * has been passed to contribute_to_heuristics). + */ +int estimate_symbol(int rf_mod, P25Heuristics* heuristics, int previous_dibit, int analog_value, int* dibit); + +/** + * Log some useful information on the heuristics state. + */ +void debug_print_heuristics(P25Heuristics* heuristics); + +/** + * This method contributes valuable information from dibits whose value we are confident is correct. We take + * the dibits and corresponding analog signal values to model the Gaussians for each dibit (and previous + * dibit if enabled). + * \param rf_mod Indicates the modulation used. The previous dibit is only used on C4FM. + * \param heuristics Pointer to the P25Heuristics module with all the needed state information. + * \param analog_signal_array Sequence of AnalogSignal which contain the cleared dibits and analog values. + * \param count number of cleared dibits passed (= number of elements to use from analog_signal_array). + */ +void contribute_to_heuristics(int rf_mod, P25Heuristics* heuristics, AnalogSignal* analog_signal_array, int count); + +/** + * Updates the estimate for the BER (bit error rate). Mind this is method is not called for every single + * bit in the data stream but only for those bits over which we have an estimate of its error rate, + * specifically the bits that are protected by Reed-Solomon codes. + * \param heuristics The heuristics state. + * \param bits The number of bits we have read. + * \param errors The number of errors we estimate in those bits. + */ +void update_error_stats(P25Heuristics* heuristics, int bits, int errors); + +/** + * Returns the estimate for the BER (bit error rate). + * \return The estimated BER. This is just the percentage of errors over the processed bits. + */ +float get_P25_BER_estimate(P25Heuristics* heuristics); + +#ifdef __cplusplus +} +#endif + +#endif // P25P1_HEURISTICS_H_030dd3530b7546abbb56f8dd1e66a2f6 diff --git a/dsd/p25p1_ldu1.c b/dsd/p25p1_ldu1.c new file mode 100644 index 000000000..fd6abe859 --- /dev/null +++ b/dsd/p25p1_ldu1.c @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "dsd.h" +#include "p25p1_const.h" + +void +processLDU1 (dsd_opts * opts, dsd_state * state) +{ + // extracts IMBE frames rom LDU frame + int i, j, k, dibit, stats, count, scount; + char imbe_fr[8][23]; + char lcformat[9], mfid[9], lcinfo[57], lsd1[9], lsd2[9], status[25]; + const int *w, *x, *y, *z; + + lcformat[8] = 0; + mfid[8] = 0; + lcinfo[56] = 0; + lsd1[8] = 0; + lsd2[8] = 0; + status[24] = 0; + + skipDibit (opts, state, 3); + status[0] = getDibit (opts, state) + 48; + skipDibit (opts, state, 21); + count = 57; + scount = 1; + + if (opts->errorbars == 1) + { + printf ("e:"); + } + + // separate imbe frames and deinterleave + stats = 21; // we skip the status dibits that occur every 36 symbols + // the first IMBE frame starts 14 symbols before next status + // so we start counter at 22 + for (i = 0; i < 9; i++) + { // 9 IMBE frames per LDU + w = iW; + x = iX; + y = iY; + z = iZ; + for (j = 0; j < 72; j++) + { + if (stats == 35) + { + status[scount] = getDibit (opts, state) + 48; + scount++; + stats = 1; + count++; + } + else + { + stats++; + } + dibit = getDibit (opts, state); + count++; + imbe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1 + imbe_fr[*y][*z] = (1 & dibit); // bit 0 + w++; + x++; + y++; + z++; + } + if (state->p25kid == 0 || opts->unmute_encrypted_p25 == 1) + { + processMbeFrame (opts, state, imbe_fr, NULL, NULL); + } + + // skip over non imbe data sometimes between frames + if ((i < 4) || (i == 8)) + { + k = 0; + } + else if (i == 7) + { + //k=16; + k = 0; + } + else + { + k = 20; + } + for (j = 0; j < k; j++) + { + if (stats == 35) + { + status[scount] = getDibit (opts, state) + 48; + scount++; + count++; + stats = 1; + } + else + { + stats++; + } + skipDibit (opts, state, 1); + count++; + } + + if (i == 1) + { + dibit = getDibit (opts, state); + lcformat[0] = (1 & (dibit >> 1)) + 48; // bit 1 + lcformat[1] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcformat[2] = (1 & (dibit >> 1)) + 48; // bit 1 + lcformat[3] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcformat[4] = (1 & (dibit >> 1)) + 48; // bit 1 + lcformat[5] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 2); + dibit = getDibit (opts, state); + lcformat[6] = (1 & (dibit >> 1)) + 48; // bit 1 + lcformat[7] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mfid[0] = (1 & (dibit >> 1)) + 48; // bit 1 + mfid[1] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mfid[2] = (1 & (dibit >> 1)) + 48; // bit 1 + mfid[3] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 2); + status[scount] = getDibit (opts, state) + 48; + scount++; + dibit = getDibit (opts, state); + mfid[4] = (1 & (dibit >> 1)) + 48; // bit 1 + mfid[5] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mfid[6] = (1 & (dibit >> 1)) + 48; // bit 1 + mfid[7] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[0] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[1] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 2); + dibit = getDibit (opts, state); + lcinfo[2] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[3] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[4] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[5] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[6] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[7] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 2); + stats = 10; + } + else if (i == 2) + { + dibit = getDibit (opts, state); + lcinfo[8] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[9] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[10] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[11] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[12] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[13] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 2); + dibit = getDibit (opts, state); + lcinfo[14] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[15] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[16] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[17] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[18] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[19] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 2); + dibit = getDibit (opts, state); + lcinfo[20] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[21] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[22] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[23] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[24] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[25] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 2); + dibit = getDibit (opts, state); + lcinfo[26] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[27] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[28] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[29] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[30] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[31] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 2); + stats = 32; + } + else if (i == 3) + { + dibit = getDibit (opts, state); + lcinfo[32] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[33] = (1 & dibit) + 48; // bit 0 + status[scount] = getDibit (opts, state) + 48; + scount++; + dibit = getDibit (opts, state); + lcinfo[34] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[35] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[36] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[37] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 2); + dibit = getDibit (opts, state); + lcinfo[38] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[39] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[40] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[41] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[42] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[43] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 2); + dibit = getDibit (opts, state); + lcinfo[44] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[45] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[46] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[47] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[48] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[49] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 2); + dibit = getDibit (opts, state); + lcinfo[50] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[51] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[52] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[53] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[54] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[55] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 2); + stats = 19; + } + else if (i == 7) + { + dibit = getDibit (opts, state); + lsd1[0] = (1 & (dibit >> 1)) + 48; // bit 1 + lsd1[1] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lsd1[2] = (1 & (dibit >> 1)) + 48; // bit 1 + lsd1[3] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lsd1[4] = (1 & (dibit >> 1)) + 48; // bit 1 + lsd1[5] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lsd1[6] = (1 & (dibit >> 1)) + 48; // bit 1 + lsd1[7] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 4); + dibit = getDibit (opts, state); + lsd2[0] = (1 & (dibit >> 1)) + 48; // bit 1 + lsd2[1] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lsd2[2] = (1 & (dibit >> 1)) + 48; // bit 1 + lsd2[3] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lsd2[4] = (1 & (dibit >> 1)) + 48; // bit 1 + lsd2[5] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lsd2[6] = (1 & (dibit >> 1)) + 48; // bit 1 + lsd2[7] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 4); + stats = 33; + } + } + // trailing status symbol + status[scount] = getDibit (opts, state) + 48; + scount++; + + if (opts->errorbars == 1) + { + printf ("\n"); + } + + if (opts->p25status == 1) + { + printf ("status: %s lsd1: %s lsd2: %s\n", status, lsd1, lsd2); + } + + processP25lcw (opts, state, lcformat, mfid, lcinfo); +} diff --git a/dsd/p25p1_ldu2.c b/dsd/p25p1_ldu2.c new file mode 100644 index 000000000..a0f8fbb3e --- /dev/null +++ b/dsd/p25p1_ldu2.c @@ -0,0 +1,355 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "dsd.h" +#include "p25p1_const.h" + +void +processLDU2 (dsd_opts * opts, dsd_state * state) +{ + // extracts IMBE frames rom LDU frame + int i, j, k, dibit, stats, count, scount; + char imbe_fr[8][23]; + char mi[73], algid[9], kid[17], lsd3[9], lsd4[9], status[25]; + const int *w, *x, *y, *z; + int algidhex, kidhex; + + status[24] = 0; + mi[72] = 0; + algid[8] = 0; + kid[16] = 0; + lsd3[8] = 0; + lsd4[8] = 0; + + skipDibit (opts, state, 3); + status[0] = getDibit (opts, state) + 48; + skipDibit (opts, state, 21); + scount = 1; + + count = 57; + + if (opts->errorbars == 1) + { + printf ("e:"); + } + + // separate imbe frames and deinterleave + stats = 21; + // we skip the status dibits that occur every 36 symbols + // the first IMBE frame starts 14 symbols before next status + // so we start counter at 22 + for (i = 0; i < 9; i++) + { // 9 IMBE frames per LDU + w = iW; + x = iX; + y = iY; + z = iZ; + for (j = 0; j < 72; j++) + { + if (stats == 35) + { + status[scount] = getDibit (opts, state) + 48; + scount++; + stats = 1; + count++; + } + else + { + stats++; + } + dibit = getDibit (opts, state); + count++; + imbe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1 + imbe_fr[*y][*z] = (1 & dibit); // bit 0 + w++; + x++; + y++; + z++; + } + if (state->p25kid == 0 || opts->unmute_encrypted_p25 == 1) + { + processMbeFrame (opts, state, imbe_fr, NULL, NULL); + } + + // skip over non imbe data sometimes between frames + if ((i < 5) || (i == 8)) + { + k = 0; + } + else if (i == 7) + { + //k=16; + k = 0; + } + else + { + k = 20; + } + + for (j = 0; j < k; j++) + { + if (stats == 35) + { + status[scount] = getDibit (opts, state) + 48; + scount++; + count++; + stats = 1; + } + else + { + stats++; + } + skipDibit (opts, state, 1); + count++; + } + + if (i == 1) + { + dibit = getDibit (opts, state); + mi[0] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[1] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[2] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[3] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[4] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[5] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 2); + dibit = getDibit (opts, state); + mi[6] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[7] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[8] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[9] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[10] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[11] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 2); + status[scount] = getDibit (opts, state) + 48; + scount++; + dibit = getDibit (opts, state); + mi[12] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[13] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[14] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[15] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[16] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[17] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 2); + dibit = getDibit (opts, state); + mi[18] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[19] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[20] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[21] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[22] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[23] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 2); + stats = 10; + } + else if (i == 2) + { + dibit = getDibit (opts, state); + mi[24] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[25] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[26] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[27] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[28] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[29] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 2); + dibit = getDibit (opts, state); + mi[30] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[31] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[32] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[33] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[34] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[35] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 2); + dibit = getDibit (opts, state); + mi[36] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[37] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[38] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[39] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[40] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[41] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 2); + dibit = getDibit (opts, state); + mi[42] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[43] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[44] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[45] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[46] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[47] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 2); + stats = 32; + } + else if (i == 3) + { + dibit = getDibit (opts, state); + mi[48] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[49] = (1 & dibit) + 48; // bit 0 + status[scount] = getDibit (opts, state) + 48; + scount++; + dibit = getDibit (opts, state); + mi[50] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[51] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[52] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[53] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 2); + dibit = getDibit (opts, state); + mi[54] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[55] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[56] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[57] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[58] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[59] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 2); + dibit = getDibit (opts, state); + mi[60] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[61] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[62] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[63] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[64] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[65] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 2); + dibit = getDibit (opts, state); + mi[66] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[67] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[68] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[69] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mi[70] = (1 & (dibit >> 1)) + 48; // bit 1 + mi[71] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 2); + stats = 19; + } + else if (i == 4) + { + dibit = getDibit (opts, state); + algid[0] = (1 & (dibit >> 1)) + 48; // bit 1 + algid[1] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + algid[2] = (1 & (dibit >> 1)) + 48; // bit 1 + algid[3] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + algid[4] = (1 & (dibit >> 1)) + 48; // bit 1 + algid[5] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 2); + dibit = getDibit (opts, state); + algid[6] = (1 & (dibit >> 1)) + 48; // bit 1 + algid[7] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + kid[0] = (1 & (dibit >> 1)) + 48; // bit 1 + kid[1] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + kid[2] = (1 & (dibit >> 1)) + 48; // bit 1 + kid[3] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 2); + dibit = getDibit (opts, state); + kid[4] = (1 & (dibit >> 1)) + 48; // bit 1 + kid[5] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + kid[6] = (1 & (dibit >> 1)) + 48; // bit 1 + kid[7] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + kid[8] = (1 & (dibit >> 1)) + 48; // bit 1 + kid[9] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 1); + status[scount] = getDibit (opts, state) + 48; + scount++; + skipDibit (opts, state, 1); + dibit = getDibit (opts, state); + kid[10] = (1 & (dibit >> 1)) + 48; // bit 1 + kid[11] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + kid[12] = (1 & (dibit >> 1)) + 48; // bit 1 + kid[13] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + kid[14] = (1 & (dibit >> 1)) + 48; // bit 1 + kid[15] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 2); + stats = 6; + } + else if (i == 7) + { + dibit = getDibit (opts, state); + lsd3[0] = (1 & (dibit >> 1)) + 48; // bit 1 + lsd3[1] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lsd3[2] = (1 & (dibit >> 1)) + 48; // bit 1 + lsd3[3] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lsd3[4] = (1 & (dibit >> 1)) + 48; // bit 1 + lsd3[5] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lsd3[6] = (1 & (dibit >> 1)) + 48; // bit 1 + lsd3[7] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 4); + dibit = getDibit (opts, state); + lsd4[0] = (1 & (dibit >> 1)) + 48; // bit 1 + lsd4[1] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lsd4[2] = (1 & (dibit >> 1)) + 48; // bit 1 + lsd4[3] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lsd4[4] = (1 & (dibit >> 1)) + 48; // bit 1 + lsd4[5] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lsd4[6] = (1 & (dibit >> 1)) + 48; // bit 1 + lsd4[7] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 4); + stats = 33; + } + + } + + //trailing status symbol + status[scount] = getDibit (opts, state) + 48; + scount++; + + if (opts->errorbars == 1) + { + printf ("\n"); + } + + if (opts->p25status == 1) + { + printf ("status: %s lsd3: %s lsd4: %s\n", status, lsd3, lsd4); + } + if (opts->p25enc == 1) + { + algidhex = strtol (algid, NULL, 2); + kidhex = strtol (kid, NULL, 2); + printf ("mi: %s algid: $%x kid: $%x\n", mi, algidhex, kidhex); + } +} diff --git a/dsd/p25p1_tdulc.c b/dsd/p25p1_tdulc.c new file mode 100644 index 000000000..77fe6c6c9 --- /dev/null +++ b/dsd/p25p1_tdulc.c @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "dsd.h" + +void +processTDULC (dsd_opts * opts, dsd_state * state) +{ + + char lcinfo[57], lcformat[9], mfid[9]; + int dibit, count; + + lcformat[8] = 0; + mfid[8] = 0; + lcinfo[56] = 0; + + skipDibit (opts, state, 25); + count = 57; + + dibit = getDibit (opts, state); + lcformat[0] = (1 & (dibit >> 1)) + 48; // bit 1 + lcformat[1] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcformat[2] = (1 & (dibit >> 1)) + 48; // bit 1 + lcformat[3] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcformat[4] = (1 & (dibit >> 1)) + 48; // bit 1 + lcformat[5] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcformat[6] = (1 & (dibit >> 1)) + 48; // bit 1 + lcformat[7] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mfid[0] = (1 & (dibit >> 1)) + 48; // bit 1 + mfid[1] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mfid[2] = (1 & (dibit >> 1)) + 48; // bit 1 + mfid[3] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 6); + + dibit = getDibit (opts, state); + mfid[4] = (1 & (dibit >> 1)) + 48; // bit 1 + mfid[5] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + mfid[6] = (1 & (dibit >> 1)) + 48; // bit 1 + mfid[7] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 1); + dibit = getDibit (opts, state); + lcinfo[0] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[1] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[2] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[3] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[4] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[5] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[6] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[7] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 6); + + dibit = getDibit (opts, state); + lcinfo[8] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[9] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[10] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[11] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[12] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[13] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[14] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[15] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[16] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[17] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[18] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[19] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 6); + + dibit = getDibit (opts, state); + lcinfo[20] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[21] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[22] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[23] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[24] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[25] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[26] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[27] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[28] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[29] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[30] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[31] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 6); + + dibit = getDibit (opts, state); + lcinfo[32] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[33] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 1); + dibit = getDibit (opts, state); + lcinfo[34] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[35] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[36] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[37] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[38] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[39] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[40] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[41] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[42] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[43] = (1 & dibit) + 48; // bit 0 + skipDibit (opts, state, 6); + + dibit = getDibit (opts, state); + lcinfo[44] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[45] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[46] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[47] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[48] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[49] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[50] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[51] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[52] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[53] = (1 & dibit) + 48; // bit 0 + dibit = getDibit (opts, state); + lcinfo[54] = (1 & (dibit >> 1)) + 48; // bit 1 + lcinfo[55] = (1 & dibit) + 48; // bit 0 + + skipDibit (opts, state, 91); + + processP25lcw (opts, state, lcformat, mfid, lcinfo); +} diff --git a/dsd/provoice.c b/dsd/provoice.c new file mode 100644 index 000000000..2c01329ff --- /dev/null +++ b/dsd/provoice.c @@ -0,0 +1,519 @@ +#include "dsd.h" +#include "provoice_const.h" + +void +processProVoice (dsd_opts * opts, dsd_state * state) +{ + int i, j, dibit; + + char imbe7100_fr1[7][24]; + char imbe7100_fr2[7][24]; + const int *w, *x; + + if (opts->errorbars == 1) + { + printf ("VOICE e:"); + } + + for (i = 0; i < 64; i++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + } +#ifdef PROVOICE_DUMP + printf (" "); +#endif + + // lid + for (i = 0; i < 16; i++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + } +#ifdef PROVOICE_DUMP + printf (" "); +#endif + + for (i = 0; i < 64; i++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + } +#ifdef PROVOICE_DUMP + printf (" "); +#endif + + // imbe frames 1,2 first half + w = pW; + x = pX; + + for (i = 0; i < 11; i++) + { + for (j = 0; j < 6; j++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + imbe7100_fr1[*w][*x] = dibit; + w++; + x++; + } +#ifdef PROVOICE_DUMP + printf ("_"); +#endif + w -= 6; + x -= 6; + for (j = 0; j < 6; j++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + imbe7100_fr2[*w][*x] = dibit; + w++; + x++; + } +#ifdef PROVOICE_DUMP + printf ("_"); +#endif + } + + for (j = 0; j < 6; j++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + imbe7100_fr1[*w][*x] = dibit; + w++; + x++; + } +#ifdef PROVOICE_DUMP + printf ("_"); +#endif + w -= 6; + x -= 6; + for (j = 0; j < 4; j++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + imbe7100_fr2[*w][*x] = dibit; + w++; + x++; + } +#ifdef PROVOICE_DUMP + printf (" "); +#endif + + // spacer bits + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); + printf (" "); +#endif + + // imbe frames 1,2 second half + + for (j = 0; j < 2; j++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + imbe7100_fr2[*w][*x] = dibit; + w++; + x++; + } +#ifdef PROVOICE_DUMP + printf ("_"); +#endif + + for (i = 0; i < 3; i++) + { + for (j = 0; j < 6; j++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + imbe7100_fr1[*w][*x] = dibit; + w++; + x++; + } +#ifdef PROVOICE_DUMP + printf ("_"); +#endif + w -= 6; + x -= 6; + for (j = 0; j < 6; j++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + imbe7100_fr2[*w][*x] = dibit; + w++; + x++; + } +#ifdef PROVOICE_DUMP + printf ("_"); +#endif + } + + for (j = 0; j < 5; j++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + imbe7100_fr1[*w][*x] = dibit; + w++; + x++; + } +#ifdef PROVOICE_DUMP + printf ("_"); +#endif + w -= 5; + x -= 5; + for (j = 0; j < 5; j++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + imbe7100_fr2[*w][*x] = dibit; + w++; + x++; + } +#ifdef PROVOICE_DUMP + printf ("_"); +#endif + + for (i = 0; i < 7; i++) + { + for (j = 0; j < 6; j++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + imbe7100_fr1[*w][*x] = dibit; + w++; + x++; + } +#ifdef PROVOICE_DUMP + printf ("_"); +#endif + w -= 6; + x -= 6; + for (j = 0; j < 6; j++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + imbe7100_fr2[*w][*x] = dibit; + w++; + x++; + } +#ifdef PROVOICE_DUMP + printf ("_"); +#endif + } + + for (j = 0; j < 5; j++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + imbe7100_fr1[*w][*x] = dibit; + w++; + x++; + } +#ifdef PROVOICE_DUMP + printf ("_"); +#endif + w -= 5; + x -= 5; + for (j = 0; j < 5; j++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + imbe7100_fr2[*w][*x] = dibit; + w++; + x++; + } +#ifdef PROVOICE_DUMP + printf (" "); +#endif + + processMbeFrame (opts, state, NULL, NULL, imbe7100_fr1); + processMbeFrame (opts, state, NULL, NULL, imbe7100_fr2); + + // spacer bits + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); + printf (" "); +#endif + + for (i = 0; i < 16; i++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + } +#ifdef PROVOICE_DUMP + printf (" "); +#endif + + // imbe frames 3,4 first half + w = pW; + x = pX; + for (i = 0; i < 11; i++) + { + for (j = 0; j < 6; j++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + imbe7100_fr1[*w][*x] = dibit; + w++; + x++; + } +#ifdef PROVOICE_DUMP + printf ("_"); +#endif + w -= 6; + x -= 6; + for (j = 0; j < 6; j++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + imbe7100_fr2[*w][*x] = dibit; + w++; + x++; + } +#ifdef PROVOICE_DUMP + printf ("_"); +#endif + } + for (j = 0; j < 6; j++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + imbe7100_fr1[*w][*x] = dibit; + w++; + x++; + } +#ifdef PROVOICE_DUMP + printf ("_"); +#endif + w -= 6; + x -= 6; + for (j = 0; j < 4; j++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + imbe7100_fr2[*w][*x] = dibit; + w++; + x++; + } +#ifdef PROVOICE_DUMP + printf (" "); +#endif + + // spacer bits + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); + printf ("_"); +#endif + + // imbe frames 3,4 second half + for (j = 0; j < 2; j++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + imbe7100_fr2[*w][*x] = dibit; + w++; + x++; + } +#ifdef PROVOICE_DUMP + printf ("_"); +#endif + for (i = 0; i < 3; i++) + { + for (j = 0; j < 6; j++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + imbe7100_fr1[*w][*x] = dibit; + w++; + x++; + } +#ifdef PROVOICE_DUMP + printf ("_"); +#endif + w -= 6; + x -= 6; + for (j = 0; j < 6; j++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + imbe7100_fr2[*w][*x] = dibit; + w++; + x++; + } +#ifdef PROVOICE_DUMP + printf ("_"); +#endif + } + + for (j = 0; j < 5; j++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + imbe7100_fr1[*w][*x] = dibit; + w++; + x++; + } +#ifdef PROVOICE_DUMP + printf ("_"); +#endif + w -= 5; + x -= 5; + for (j = 0; j < 5; j++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + imbe7100_fr2[*w][*x] = dibit; + w++; + x++; + } +#ifdef PROVOICE_DUMP + printf (" "); +#endif + + for (i = 0; i < 7; i++) + { + for (j = 0; j < 6; j++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + imbe7100_fr1[*w][*x] = dibit; + w++; + x++; + } +#ifdef PROVOICE_DUMP + printf ("_"); +#endif + w -= 6; + x -= 6; + for (j = 0; j < 6; j++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + imbe7100_fr2[*w][*x] = dibit; + w++; + x++; + } +#ifdef PROVOICE_DUMP + printf ("_"); +#endif + } + + for (j = 0; j < 5; j++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + imbe7100_fr1[*w][*x] = dibit; + w++; + x++; + } +#ifdef PROVOICE_DUMP + printf ("_"); +#endif + w -= 5; + x -= 5; + for (j = 0; j < 5; j++) + { + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + imbe7100_fr2[*w][*x] = dibit; + w++; + x++; + } +#ifdef PROVOICE_DUMP + printf (" "); +#endif + + processMbeFrame (opts, state, NULL, NULL, imbe7100_fr1); + processMbeFrame (opts, state, NULL, NULL, imbe7100_fr2); + + // spacer bits + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); +#endif + dibit = getDibit (opts, state); +#ifdef PROVOICE_DUMP + printf ("%i", dibit); + printf (" "); +#endif + + if (opts->errorbars == 1) + { + printf ("\n"); + } +} diff --git a/dsd/provoice_const.h b/dsd/provoice_const.h new file mode 100644 index 000000000..ea7f9a9d4 --- /dev/null +++ b/dsd/provoice_const.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _MAIN + +extern const int pW[142]; +extern const int pX[142]; + +#else +/* + * ProVoice IMBE interleave schedule + */ + +const int pW[142] = { + 0, 1, 2, 3, 4, 6, + 0, 1, 2, 3, 4, 6, + 0, 1, 2, 3, 4, 6, + 0, 1, 2, 3, 5, 6, + 0, 1, 2, 3, 5, 6, + 0, 1, 2, 3, 5, 6, + 0, 1, 3, 4, 5, 6, + 1, 2, 3, 4, 5, 6, + 0, 1, 2, 3, 4, 6, + 0, 1, 2, 3, 4, 6, + 0, 1, 2, 3, 4, 6, + 0, 1, 2, 3, 5, 6, + 0, 1, 2, 3, 5, 6, + 0, 1, 2, 3, 5, 6, + 1, 2, 3, 4, 5, 6, + 1, 2, 3, 4, 5, + 0, 1, 2, 3, 4, 6, + 0, 1, 2, 3, 4, 6, + 0, 1, 2, 3, 5, 6, + 0, 1, 2, 3, 5, 6, + 0, 1, 2, 3, 5, 6, + 0, 1, 2, 4, 5, 6, + 1, 2, 3, 4, 5, 6, + 1, 2, 3, 4, 6 +}; + +const int pX[142] = { + 18, 18, 17, 16, 7, 21, + 15, 15, 14, 13, 4, 18, + 12, 12, 11, 10, 1, 15, + 9, 9, 8, 7, 13, 12, + 6, 6, 5, 4, 10, 9, + 3, 3, 2, 1, 7, 6, + 0, 0, 22, 13, 4, 3, + 21, 20, 19, 10, 1, 0, + 17, 17, 16, 15, 6, 20, + 14, 14, 13, 12, 3, 17, + 11, 11, 10, 9, 0, 14, + 8, 8, 7, 6, 12, 11, + 5, 5, 4, 3, 9, 8, + 2, 2, 1, 0, 6, 5, + 23, 22, 21, 12, 3, 2, + 20, 19, 18, 9, 0, + 16, 16, 15, 14, 5, 19, + 13, 13, 12, 11, 2, 16, + 10, 10, 9, 8, 14, 13, + 7, 7, 6, 5, 11, 10, + 4, 4, 3, 2, 8, 7, + 1, 1, 0, 14, 5, 4, + 22, 21, 20, 11, 2, 1, + 19, 18, 17, 8, 22 +}; +#endif diff --git a/dsd/x2tdma_const.h b/dsd/x2tdma_const.h new file mode 100644 index 000000000..23b5662d1 --- /dev/null +++ b/dsd/x2tdma_const.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * X2TDMA AMBE interleave schedule + */ + +#ifndef _MAIN +extern const int aW[36]; +extern const int aX[36]; +extern const int aY[36]; +extern const int aZ[36]; + +#else + +const int aW[36] = { 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 2, + 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2 +}; + +const int aX[36] = { 23, 10, 22, 9, 21, 8, + 20, 7, 19, 6, 18, 5, + 17, 4, 16, 3, 15, 2, + 14, 1, 13, 0, 12, 10, + 11, 9, 10, 8, 9, 7, + 8, 6, 7, 5, 6, 4 +}; + +const int aY[36] = { 0, 2, 0, 2, 0, 2, + 0, 2, 0, 3, 0, 3, + 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 3 +}; + +const int aZ[36] = { 5, 3, 4, 2, 3, 1, + 2, 0, 1, 13, 0, 12, + 22, 11, 21, 10, 20, 9, + 19, 8, 18, 7, 17, 6, + 16, 5, 15, 4, 14, 3, + 13, 2, 12, 1, 11, 0 +}; + +#endif diff --git a/dsd/x2tdma_data.c b/dsd/x2tdma_data.c new file mode 100644 index 000000000..3829270f8 --- /dev/null +++ b/dsd/x2tdma_data.c @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "dsd.h" + +void +processX2TDMAdata (dsd_opts * opts, dsd_state * state) +{ + + int i, dibit; + int *dibit_p; + char sync[25]; + char syncdata[25]; + char cachdata[13]; + char cc[4]; + int aiei; + char bursttype[5]; + +#ifdef X2TDMA_DUMP + int k; + char syncbits[49]; + char cachbits[25]; +#endif + + cc[3] = 0; + bursttype[4] = 0; + + dibit_p = state->dibit_buf_p - 90; + + // CACH + for (i = 0; i < 12; i++) + { + dibit = *dibit_p; + dibit_p++; + if (opts->inverted_x2tdma == 1) + { + dibit = (dibit ^ 2); + } + cachdata[i] = dibit; + if (i == 2) + { + state->currentslot = (1 & (dibit >> 1)); // bit 1 + if (state->currentslot == 0) + { + state->slot0light[0] = '['; + state->slot0light[6] = ']'; + state->slot1light[0] = ' '; + state->slot1light[6] = ' '; + } + else + { + state->slot1light[0] = '['; + state->slot1light[6] = ']'; + state->slot0light[0] = ' '; + state->slot0light[6] = ' '; + } + } + } + cachdata[12] = 0; + +#ifdef X2TDMA_DUMP + k = 0; + for (i = 0; i < 12; i++) + { + dibit = cachdata[i]; + cachbits[k] = (1 & (dibit >> 1)) + 48; // bit 1 + k++; + cachbits[k] = (1 & dibit) + 48; // bit 0 + k++; + } + cachbits[24] = 0; + printf ("%s ", cachbits); +#endif + + // current slot + dibit_p += 49; + + // slot type + dibit = *dibit_p; + dibit_p++; + if (opts->inverted_x2tdma == 1) + { + dibit = (dibit ^ 2); + } + cc[0] = (1 & (dibit >> 1)) + 48; // bit 1 + cc[1] = (1 & dibit) + 48; // bit 0 + + dibit = *dibit_p; + dibit_p++; + if (opts->inverted_x2tdma == 1) + { + dibit = (dibit ^ 2); + } + cc[2] = (1 & (dibit >> 1)) + 48; // bit 1 + aiei = (1 & dibit); // bit 0 + + dibit = *dibit_p; + dibit_p++; + if (opts->inverted_x2tdma == 1) + { + dibit = (dibit ^ 2); + } + bursttype[0] = (1 & (dibit >> 1)) + 48; // bit 1 + bursttype[1] = (1 & dibit) + 48; // bit 0 + + dibit = *dibit_p; + dibit_p++; + if (opts->inverted_x2tdma == 1) + { + dibit = (dibit ^ 2); + } + bursttype[2] = (1 & (dibit >> 1)) + 48; // bit 1 + bursttype[3] = (1 & dibit) + 48; // bit 0 + + // parity bit + dibit_p++; + + if (strcmp (bursttype, "0000") == 0) + { + sprintf (state->fsubtype, " PI Header "); + } + else if (strcmp (bursttype, "0001") == 0) + { + sprintf (state->fsubtype, " VOICE Header "); + } + else if (strcmp (bursttype, "0010") == 0) + { + sprintf (state->fsubtype, " TLC "); + } + else if (strcmp (bursttype, "0011") == 0) + { + sprintf (state->fsubtype, " CSBK "); + } + else if (strcmp (bursttype, "0100") == 0) + { + sprintf (state->fsubtype, " MBC Header "); + } + else if (strcmp (bursttype, "0101") == 0) + { + sprintf (state->fsubtype, " MBC "); + } + else if (strcmp (bursttype, "0110") == 0) + { + sprintf (state->fsubtype, " DATA Header "); + } + else if (strcmp (bursttype, "0111") == 0) + { + sprintf (state->fsubtype, " RATE 1/2 DATA"); + } + else if (strcmp (bursttype, "1000") == 0) + { + sprintf (state->fsubtype, " RATE 3/4 DATA"); + } + else if (strcmp (bursttype, "1001") == 0) + { + sprintf (state->fsubtype, " Slot idle "); + } + else if (strcmp (bursttype, "1010") == 0) + { + sprintf (state->fsubtype, " Rate 1 DATA "); + } + else + { + sprintf (state->fsubtype, " "); + } + + // signaling data or sync + for (i = 0; i < 24; i++) + { + dibit = *dibit_p; + dibit_p++; + if (opts->inverted_x2tdma == 1) + { + dibit = (dibit ^ 2); + } + syncdata[i] = dibit; + sync[i] = (dibit | 1) + 48; + } + sync[24] = 0; + syncdata[24] = 0; + +#ifdef X2TDMA_DUMP + k = 0; + for (i = 0; i < 24; i++) + { + dibit = syncdata[i]; + syncbits[k] = (1 & (dibit >> 1)) + 48; // bit 1 + k++; + syncbits[k] = (1 & dibit) + 48; // bit 0 + k++; + } + syncbits[48] = 0; + printf ("%s ", syncbits); +#endif + + if ((strcmp (sync, X2TDMA_BS_DATA_SYNC) == 0) || (strcmp (sync, X2TDMA_BS_DATA_SYNC) == 0)) + { + if (state->currentslot == 0) + { + sprintf (state->slot0light, "[slot0]"); + } + else + { + sprintf (state->slot1light, "[slot1]"); + } + } + + if (opts->errorbars == 1) + { + printf ("%s %s ", state->slot0light, state->slot1light); + } + + // current slot second half, cach, next slot 1st half + skipDibit (opts, state, 120); + + if (opts->errorbars == 1) + { + if (strcmp (state->fsubtype, " ") == 0) + { + printf (" Unknown burst type: %s\n", bursttype); + } + else + { + printf ("%s\n", state->fsubtype); + } + } +} diff --git a/dsd/x2tdma_voice.c b/dsd/x2tdma_voice.c new file mode 100644 index 000000000..4fd6d212f --- /dev/null +++ b/dsd/x2tdma_voice.c @@ -0,0 +1,642 @@ +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "dsd.h" +#include "x2tdma_const.h" + +void +processX2TDMAvoice (dsd_opts * opts, dsd_state * state) +{ + // extracts AMBE frames from X2TDMA frame + int i, j, dibit; + int *dibit_p; + char ambe_fr[4][24]; + char ambe_fr2[4][24]; + char ambe_fr3[4][24]; + const int *w, *x, *y, *z; + char sync[25]; + char syncdata[25]; + char lcformat[9], mfid[9], lcinfo[57]; + char cachdata[13]; + char parity; + int eeei, aiei; + char mi[73]; + int burstd; + int mutecurrentslot; + int algidhex, kidhex; + int msMode; + +#ifdef X2TDMA_DUMP + int k; + char cachbits[25]; + char syncbits[49]; +#endif + + lcformat[8] = 0; + mfid[8] = 0; + lcinfo[56] = 0; + sprintf (mi, "________________________________________________________________________"); + eeei = 0; + aiei = 0; + burstd = 0; + mutecurrentslot = 0; + msMode = 0; + + dibit_p = state->dibit_buf_p - 144; + for (j = 0; j < 6; j++) + { + // 2nd half of previous slot + for (i = 0; i < 54; i++) + { + if (j > 0) + { + dibit = getDibit (opts, state); + } + else + { + dibit = *dibit_p; + dibit_p++; + if (opts->inverted_x2tdma == 1) + { + dibit = (dibit ^ 2); + } + } + } + + // CACH + for (i = 0; i < 12; i++) + { + if (j > 0) + { + dibit = getDibit (opts, state); + } + else + { + dibit = *dibit_p; + dibit_p++; + if (opts->inverted_x2tdma == 1) + { + dibit = (dibit ^ 2); + } + } + cachdata[i] = dibit; + if (i == 2) + { + state->currentslot = (1 & (dibit >> 1)); // bit 1 + if (state->currentslot == 0) + { + state->slot0light[0] = '['; + state->slot0light[6] = ']'; + state->slot1light[0] = ' '; + state->slot1light[6] = ' '; + } + else + { + state->slot1light[0] = '['; + state->slot1light[6] = ']'; + state->slot0light[0] = ' '; + state->slot0light[6] = ' '; + } + } + } + cachdata[12] = 0; + + +#ifdef X2TDMA_DUMP + k = 0; + for (i = 0; i < 12; i++) + { + dibit = cachdata[i]; + cachbits[k] = (1 & (dibit >> 1)) + 48; // bit 1 + k++; + cachbits[k] = (1 & dibit) + 48; // bit 0 + k++; + } + cachbits[24] = 0; + printf ("%s ", cachbits); +#endif + + // current slot frame 1 + w = aW; + x = aX; + y = aY; + z = aZ; + for (i = 0; i < 36; i++) + { + if (j > 0) + { + dibit = getDibit (opts, state); + } + else + { + dibit = *dibit_p; + dibit_p++; + if (opts->inverted_x2tdma == 1) + { + dibit = (dibit ^ 2); + } + } + ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1 + ambe_fr[*y][*z] = (1 & dibit); // bit 0 + w++; + x++; + y++; + z++; + } + + // current slot frame 2 first half + w = aW; + x = aX; + y = aY; + z = aZ; + for (i = 0; i < 18; i++) + { + if (j > 0) + { + dibit = getDibit (opts, state); + } + else + { + dibit = *dibit_p; + dibit_p++; + if (opts->inverted_x2tdma == 1) + { + dibit = (dibit ^ 2); + } + } + ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1 + ambe_fr2[*y][*z] = (1 & dibit); // bit 0 + w++; + x++; + y++; + z++; + } + + // signaling data or sync + for (i = 0; i < 24; i++) + { + if (j > 0) + { + dibit = getDibit (opts, state); + } + else + { + dibit = *dibit_p; + dibit_p++; + if (opts->inverted_x2tdma == 1) + { + dibit = (dibit ^ 2); + } + } + syncdata[i] = dibit; + sync[i] = (dibit | 1) + 48; + } + sync[24] = 0; + syncdata[24] = 0; + + if ((strcmp (sync, X2TDMA_BS_DATA_SYNC) == 0) || (strcmp (sync, X2TDMA_MS_DATA_SYNC) == 0)) + { + mutecurrentslot = 1; + if (state->currentslot == 0) + { + sprintf (state->slot0light, "[slot0]"); + } + else + { + sprintf (state->slot1light, "[slot1]"); + } + } + else if ((strcmp (sync, X2TDMA_BS_VOICE_SYNC) == 0) || (strcmp (sync, X2TDMA_MS_VOICE_SYNC) == 0)) + { + mutecurrentslot = 0; + if (state->currentslot == 0) + { + sprintf (state->slot0light, "[SLOT0]"); + } + else + { + sprintf (state->slot1light, "[SLOT1]"); + } + } + + if ((strcmp (sync, X2TDMA_MS_VOICE_SYNC) == 0) || (strcmp (sync, X2TDMA_MS_DATA_SYNC) == 0)) + { + msMode = 1; + } + + if ((j == 0) && (opts->errorbars == 1)) + { + printf ("%s %s VOICE e:", state->slot0light, state->slot1light); + } + +#ifdef X2TDMA_DUMP + k = 0; + for (i = 0; i < 24; i++) + { + dibit = syncdata[i]; + syncbits[k] = (1 & (dibit >> 1)) + 48; // bit 1 + k++; + syncbits[k] = (1 & dibit) + 48; // bit 0 + k++; + } + syncbits[48] = 0; + printf ("%s ", syncbits); +#endif + + if (j == 1) + { + eeei = (1 & syncdata[1]); // bit 0 + aiei = (1 & (syncdata[2] >> 1)); // bit 1 + + if ((eeei == 0) && (aiei == 0)) + { + lcformat[0] = (1 & (syncdata[4] >> 1)) + 48; // bit 1 + mfid[3] = (1 & syncdata[4]) + 48; // bit 0 + lcinfo[6] = (1 & (syncdata[5] >> 1)) + 48; // bit 1 + lcinfo[16] = (1 & syncdata[5]) + 48; // bit 0 + lcinfo[26] = (1 & (syncdata[6] >> 1)) + 48; // bit 1 + lcinfo[36] = (1 & syncdata[6]) + 48; // bit 0 + lcinfo[46] = (1 & (syncdata[7] >> 1)) + 48; // bit 1 + parity = (1 & syncdata[7]) + 48; // bit 0 + lcformat[1] = (1 & (syncdata[8] >> 1)) + 48; // bit 1 + mfid[4] = (1 & syncdata[8]) + 48; // bit 0 + lcinfo[7] = (1 & (syncdata[9] >> 1)) + 48; // bit 1 + lcinfo[17] = (1 & syncdata[9]) + 48; // bit 0 + lcinfo[27] = (1 & (syncdata[10] >> 1)) + 48; // bit 1 + lcinfo[37] = (1 & syncdata[10]) + 48; // bit 0 + lcinfo[47] = (1 & (syncdata[11] >> 1)) + 48; // bit 1 + parity = (1 & syncdata[11]) + 48; // bit 0 + lcformat[2] = (1 & (syncdata[12] >> 1)) + 48; // bit 1 + mfid[5] = (1 & syncdata[12]) + 48; // bit 0 + lcinfo[8] = (1 & (syncdata[13] >> 1)) + 48; // bit 1 + lcinfo[18] = (1 & syncdata[13]) + 48; // bit 0 + lcinfo[28] = (1 & (syncdata[14] >> 1)) + 48; // bit 1 + lcinfo[38] = (1 & syncdata[14]) + 48; // bit 0 + lcinfo[48] = (1 & (syncdata[15] >> 1)) + 48; // bit 1 + parity = (1 & syncdata[15]) + 48; // bit 0 + lcformat[3] = (1 & (syncdata[16] >> 1)) + 48; // bit 1 + mfid[6] = (1 & syncdata[16]) + 48; // bit 0 + lcinfo[9] = (1 & (syncdata[17] >> 1)) + 48; // bit 1 + lcinfo[19] = (1 & syncdata[17]) + 48; // bit 0 + lcinfo[29] = (1 & (syncdata[18] >> 1)) + 48; // bit 1 + lcinfo[39] = (1 & syncdata[18]) + 48; // bit 0 + lcinfo[49] = (1 & (syncdata[19] >> 1)) + 48; // bit 1 + parity = (1 & syncdata[19]) + 48; // bit 0 + } + else + { + mi[0] = (1 & (syncdata[4] >> 1)) + 48; // bit 1 + mi[11] = (1 & syncdata[4]) + 48; // bit 0 + mi[22] = (1 & (syncdata[5] >> 1)) + 48; // bit 1 + mi[32] = (1 & syncdata[5]) + 48; // bit 0 + mi[42] = (1 & (syncdata[6] >> 1)) + 48; // bit 1 + mi[52] = (1 & syncdata[6]) + 48; // bit 0 + mi[62] = (1 & (syncdata[7] >> 1)) + 48; // bit 1 + parity = (1 & syncdata[7]) + 48; // bit 0 + mi[1] = (1 & (syncdata[8] >> 1)) + 48; // bit 1 + mi[12] = (1 & syncdata[8]) + 48; // bit 0 + mi[23] = (1 & (syncdata[9] >> 1)) + 48; // bit 1 + mi[33] = (1 & syncdata[9]) + 48; // bit 0 + mi[43] = (1 & (syncdata[10] >> 1)) + 48; // bit 1 + mi[53] = (1 & syncdata[10]) + 48; // bit 0 + mi[63] = (1 & (syncdata[11] >> 1)) + 48; // bit 1 + parity = (1 & syncdata[11]) + 48; // bit 0 + mi[2] = (1 & (syncdata[12] >> 1)) + 48; // bit 1 + mi[13] = (1 & syncdata[12]) + 48; // bit 0 + mi[24] = (1 & (syncdata[13] >> 1)) + 48; // bit 1 + mi[34] = (1 & syncdata[13]) + 48; // bit 0 + mi[44] = (1 & (syncdata[14] >> 1)) + 48; // bit 1 + mi[54] = (1 & syncdata[14]) + 48; // bit 0 + mi[64] = (1 & (syncdata[15] >> 1)) + 48; // bit 1 + parity = (1 & syncdata[15]) + 48; // bit 0 + mi[3] = (1 & (syncdata[16] >> 1)) + 48; // bit 1 + mi[14] = (1 & syncdata[16]) + 48; // bit 0 + mi[25] = (1 & (syncdata[17] >> 1)) + 48; // bit 1 + mi[35] = (1 & syncdata[17]) + 48; // bit 0 + mi[45] = (1 & (syncdata[18] >> 1)) + 48; // bit 1 + mi[55] = (1 & syncdata[18]) + 48; // bit 0 + mi[65] = (1 & (syncdata[19] >> 1)) + 48; // bit 1 + parity = (1 & syncdata[19]) + 48; // bit 0 + } + } + else if (j == 2) + { + if ((eeei == 0) && (aiei == 0)) + { + lcformat[4] = (1 & (syncdata[4] >> 1)) + 48; // bit 1 + mfid[7] = (1 & syncdata[4]) + 48; // bit 0 + lcinfo[10] = (1 & (syncdata[5] >> 1)) + 48; // bit 1 + lcinfo[20] = (1 & syncdata[5]) + 48; // bit 0 + lcinfo[30] = (1 & (syncdata[6] >> 1)) + 48; // bit 1 + lcinfo[40] = (1 & syncdata[6]) + 48; // bit 0 + lcinfo[50] = (1 & (syncdata[7] >> 1)) + 48; // bit 1 + parity = (1 & syncdata[7]) + 48; // bit 0 + lcformat[5] = (1 & (syncdata[8] >> 1)) + 48; // bit 1 + lcinfo[0] = (1 & syncdata[8]) + 48; // bit 0 + lcinfo[11] = (1 & (syncdata[9] >> 1)) + 48; // bit 1 + lcinfo[21] = (1 & syncdata[9]) + 48; // bit 0 + lcinfo[31] = (1 & (syncdata[10] >> 1)) + 48; // bit 1 + lcinfo[41] = (1 & syncdata[10]) + 48; // bit 0 + lcinfo[51] = (1 & (syncdata[11] >> 1)) + 48; // bit 1 + parity = (1 & syncdata[11]) + 48; // bit 0 + lcformat[6] = (1 & (syncdata[12] >> 1)) + 48; // bit 1 + lcinfo[1] = (1 & syncdata[12]) + 48; // bit 0 + lcinfo[12] = (1 & (syncdata[13] >> 1)) + 48; // bit 1 + lcinfo[22] = (1 & syncdata[13]) + 48; // bit 0 + lcinfo[32] = (1 & (syncdata[14] >> 1)) + 48; // bit 1 + lcinfo[42] = (1 & syncdata[14]) + 48; // bit 0 + lcinfo[52] = (1 & (syncdata[15] >> 1)) + 48; // bit 1 + parity = (1 & syncdata[15]) + 48; // bit 0 + lcformat[7] = (1 & (syncdata[16] >> 1)) + 48; // bit 1 + lcinfo[2] = (1 & syncdata[16]) + 48; // bit 0 + lcinfo[13] = (1 & (syncdata[17] >> 1)) + 48; // bit 1 + lcinfo[23] = (1 & syncdata[17]) + 48; // bit 0 + lcinfo[33] = (1 & (syncdata[18] >> 1)) + 48; // bit 1 + lcinfo[43] = (1 & syncdata[18]) + 48; // bit 0 + lcinfo[53] = (1 & (syncdata[19] >> 1)) + 48; // bit 1 + parity = (1 & syncdata[19]) + 48; // bit 0 + } + else + { + mi[4] = (1 & (syncdata[4] >> 1)) + 48; // bit 1 + mi[15] = (1 & syncdata[4]) + 48; // bit 0 + mi[26] = (1 & (syncdata[5] >> 1)) + 48; // bit 1 + mi[36] = (1 & syncdata[5]) + 48; // bit 0 + mi[46] = (1 & (syncdata[6] >> 1)) + 48; // bit 1 + mi[56] = (1 & syncdata[6]) + 48; // bit 0 + mi[66] = (1 & (syncdata[7] >> 1)) + 48; // bit 1 + parity = (1 & syncdata[7]) + 48; // bit 0 + mi[5] = (1 & (syncdata[8] >> 1)) + 48; // bit 1 + mi[16] = (1 & syncdata[8]) + 48; // bit 0 + mi[27] = (1 & (syncdata[9] >> 1)) + 48; // bit 1 + mi[37] = (1 & syncdata[9]) + 48; // bit 0 + mi[47] = (1 & (syncdata[10] >> 1)) + 48; // bit 1 + mi[57] = (1 & syncdata[10]) + 48; // bit 0 + mi[67] = (1 & (syncdata[11] >> 1)) + 48; // bit 1 + parity = (1 & syncdata[11]) + 48; // bit 0 + mi[6] = (1 & (syncdata[12] >> 1)) + 48; // bit 1 + mi[17] = (1 & syncdata[12]) + 48; // bit 0 + mi[28] = (1 & (syncdata[13] >> 1)) + 48; // bit 1 + mi[38] = (1 & syncdata[13]) + 48; // bit 0 + mi[48] = (1 & (syncdata[14] >> 1)) + 48; // bit 1 + mi[58] = (1 & syncdata[14]) + 48; // bit 0 + mi[68] = (1 & (syncdata[15] >> 1)) + 48; // bit 1 + parity = (1 & syncdata[15]) + 48; // bit 0 + mi[7] = (1 & (syncdata[16] >> 1)) + 48; // bit 1 + mi[18] = (1 & syncdata[16]) + 48; // bit 0 + mi[29] = (1 & (syncdata[17] >> 1)) + 48; // bit 1 + mi[39] = (1 & syncdata[17]) + 48; // bit 0 + mi[49] = (1 & (syncdata[18] >> 1)) + 48; // bit 1 + mi[59] = (1 & syncdata[18]) + 48; // bit 0 + mi[69] = (1 & (syncdata[19] >> 1)) + 48; // bit 1 + parity = (1 & syncdata[19]) + 48; // bit 0 + } + } + else if (j == 3) + { + burstd = (1 & syncdata[1]); // bit 0 + + state->algid[0] = (1 & (syncdata[4] >> 1)) + 48; // bit 1 + state->algid[1] = (1 & syncdata[4]) + 48; // bit 0 + state->algid[2] = (1 & (syncdata[5] >> 1)) + 48; // bit 1 + state->algid[3] = (1 & syncdata[5]) + 48; // bit 0 + if (burstd == 0) + { + state->algid[4] = (1 & (syncdata[8] >> 1)) + 48; // bit 1 + state->algid[5] = (1 & syncdata[8]) + 48; // bit 0 + state->algid[6] = (1 & (syncdata[9] >> 1)) + 48; // bit 1 + state->algid[7] = (1 & syncdata[9]) + 48; // bit 0 + + state->keyid[0] = (1 & (syncdata[10] >> 1)) + 48; // bit 1 + state->keyid[1] = (1 & syncdata[10]) + 48; // bit 0 + state->keyid[2] = (1 & (syncdata[11] >> 1)) + 48; // bit 1 + state->keyid[3] = (1 & syncdata[11]) + 48; // bit 0 + state->keyid[4] = (1 & (syncdata[12] >> 1)) + 48; // bit 1 + state->keyid[5] = (1 & syncdata[12]) + 48; // bit 0 + state->keyid[6] = (1 & (syncdata[13] >> 1)) + 48; // bit 1 + state->keyid[7] = (1 & syncdata[13]) + 48; // bit 0 + state->keyid[8] = (1 & (syncdata[14] >> 1)) + 48; // bit 1 + state->keyid[9] = (1 & syncdata[14]) + 48; // bit 0 + state->keyid[10] = (1 & (syncdata[15] >> 1)) + 48; // bit 1 + state->keyid[11] = (1 & syncdata[15]) + 48; // bit 0 + state->keyid[12] = (1 & (syncdata[16] >> 1)) + 48; // bit 1 + state->keyid[13] = (1 & syncdata[16]) + 48; // bit 0 + state->keyid[14] = (1 & (syncdata[17] >> 1)) + 48; // bit 1 + state->keyid[15] = (1 & syncdata[17]) + 48; // bit 0 + } + else + { + sprintf (state->algid, "________"); + sprintf (state->keyid, "________________"); + } + } + else if (j == 4) + { + if ((eeei == 0) && (aiei == 0)) + { + mfid[0] = (1 & (syncdata[4] >> 1)) + 48; // bit 1 + lcinfo[3] = (1 & syncdata[4]) + 48; // bit 0 + lcinfo[14] = (1 & (syncdata[5] >> 1)) + 48; // bit 1 + lcinfo[24] = (1 & syncdata[5]) + 48; // bit 0 + lcinfo[34] = (1 & (syncdata[6] >> 1)) + 48; // bit 1 + lcinfo[44] = (1 & syncdata[6]) + 48; // bit 0 + lcinfo[54] = (1 & (syncdata[7] >> 1)) + 48; // bit 1 + parity = (1 & syncdata[7]) + 48; // bit 0 + mfid[1] = (1 & (syncdata[8] >> 1)) + 48; // bit 1 + lcinfo[4] = (1 & syncdata[8]) + 48; // bit 0 + lcinfo[15] = (1 & (syncdata[9] >> 1)) + 48; // bit 1 + lcinfo[25] = (1 & syncdata[9]) + 48; // bit 0 + lcinfo[35] = (1 & (syncdata[10] >> 1)) + 48; // bit 1 + lcinfo[45] = (1 & syncdata[10]) + 48; // bit 0 + lcinfo[55] = (1 & (syncdata[11] >> 1)) + 48; // bit 1 + parity = (1 & syncdata[11]) + 48; // bit 0 + mfid[2] = (1 & (syncdata[12] >> 1)) + 48; // bit 1 + lcinfo[5] = (1 & syncdata[12]) + 48; // bit 0 + } + else + { + mi[8] = (1 & (syncdata[4] >> 1)) + 48; // bit 1 + mi[19] = (1 & syncdata[4]) + 48; // bit 0 + mi[30] = (1 & (syncdata[5] >> 1)) + 48; // bit 1 + mi[40] = (1 & syncdata[5]) + 48; // bit 0 + mi[50] = (1 & (syncdata[6] >> 1)) + 48; // bit 1 + mi[60] = (1 & syncdata[6]) + 48; // bit 0 + mi[70] = (1 & (syncdata[7] >> 1)) + 48; // bit 1 + parity = (1 & syncdata[7]) + 48; // bit 0 + mi[9] = (1 & (syncdata[8] >> 1)) + 48; // bit 1 + mi[20] = (1 & syncdata[8]) + 48; // bit 0 + mi[31] = (1 & (syncdata[9] >> 1)) + 48; // bit 1 + mi[41] = (1 & syncdata[9]) + 48; // bit 0 + mi[51] = (1 & (syncdata[10] >> 1)) + 48; // bit 1 + mi[61] = (1 & syncdata[10]) + 48; // bit 0 + mi[71] = (1 & (syncdata[11] >> 1)) + 48; // bit 1 + parity = (1 & syncdata[11]) + 48; // bit 0 + mi[10] = (1 & (syncdata[12] >> 1)) + 48; // bit 1 + mi[21] = (1 & syncdata[12]) + 48; // bit 0 + } + } + + // current slot frame 2 second half + for (i = 0; i < 18; i++) + { + dibit = getDibit (opts, state); + ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1 + ambe_fr2[*y][*z] = (1 & dibit); // bit 0 + w++; + x++; + y++; + z++; + } + + if (mutecurrentslot == 0) + { + if (state->firstframe == 1) + { // we don't know if anything received before the first sync after no carrier is valid + state->firstframe = 0; + } + else + { + processMbeFrame (opts, state, NULL, ambe_fr, NULL); + processMbeFrame (opts, state, NULL, ambe_fr2, NULL); + } + } + + // current slot frame 3 + w = aW; + x = aX; + y = aY; + z = aZ; + for (i = 0; i < 36; i++) + { + dibit = getDibit (opts, state); + ambe_fr3[*w][*x] = (1 & (dibit >> 1)); // bit 1 + ambe_fr3[*y][*z] = (1 & dibit); // bit 0 + w++; + x++; + y++; + z++; + } + if (mutecurrentslot == 0) + { + processMbeFrame (opts, state, NULL, ambe_fr3, NULL); + } + + // CACH + for (i = 0; i < 12; i++) + { + dibit = getDibit (opts, state); + cachdata[i] = dibit; + } + cachdata[12] = 0; + +#ifdef X2TDMA_DUMP + k = 0; + for (i = 0; i < 12; i++) + { + dibit = cachdata[i]; + cachbits[k] = (1 & (dibit >> 1)) + 48; // bit 1 + k++; + cachbits[k] = (1 & dibit) + 48; // bit 0 + k++; + } + cachbits[24] = 0; + printf ("%s ", cachbits); +#endif + + + // next slot + skipDibit (opts, state, 54); + + // signaling data or sync + for (i = 0; i < 24; i++) + { + dibit = getDibit (opts, state); + syncdata[i] = dibit; + sync[i] = (dibit | 1) + 48; + } + sync[24] = 0; + syncdata[24] = 0; + + if ((strcmp (sync, X2TDMA_BS_DATA_SYNC) == 0) || (msMode == 1)) + { + if (state->currentslot == 0) + { + sprintf (state->slot1light, " slot1 "); + } + else + { + sprintf (state->slot0light, " slot0 "); + } + } + else if (strcmp (sync, X2TDMA_BS_VOICE_SYNC) == 0) + { + if (state->currentslot == 0) + { + sprintf (state->slot1light, " SLOT1 "); + } + else + { + sprintf (state->slot0light, " SLOT0 "); + } + } + +#ifdef X2TDMA_DUMP + k = 0; + for (i = 0; i < 24; i++) + { + dibit = syncdata[i]; + syncbits[k] = (1 & (dibit >> 1)) + 48; // bit 1 + k++; + syncbits[k] = (1 & dibit) + 48; // bit 0 + k++; + } + syncbits[48] = 0; + printf ("%s ", syncbits); +#endif + + if (j == 5) + { + // 2nd half next slot + skipDibit (opts, state, 54); + + // CACH + skipDibit (opts, state, 12); + + // first half current slot + skipDibit (opts, state, 54); + } + } + + if (opts->errorbars == 1) + { + printf ("\n"); + } + + if (mutecurrentslot == 0) + { + if ((eeei == 0) && (aiei == 0)) + { + processP25lcw (opts, state, lcformat, mfid, lcinfo); + } + if (opts->p25enc == 1) + { + algidhex = strtol (state->algid, NULL, 2); + kidhex = strtol (state->keyid, NULL, 2); + printf ("mi: %s algid: $%x kid: $%x\n", mi, algidhex, kidhex); + } + } +}