From 59f8d3890e65ea5b1f5f42b2aaeed24fa68f692a Mon Sep 17 00:00:00 2001 From: Jared Szechy Date: Sun, 21 Aug 2011 03:31:35 -0400 Subject: [PATCH] version 1.3 --- CHANGELOG | 37 +++ COPYRIGHT | 14 + DSD_Author.pgp | 30 ++ Makefile | 109 ++++++++ README | 520 +++++++++++++++++++++++++++++++++++ config.h | 32 +++ configure | 3 + dmr_const.h | 64 +++++ dmr_data.c | 251 +++++++++++++++++ dmr_voice.c | 376 ++++++++++++++++++++++++++ dsd.h | 218 +++++++++++++++ dsd_audio.c | 365 +++++++++++++++++++++++++ dsd_dibit.c | 290 ++++++++++++++++++++ dsd_file.c | 331 +++++++++++++++++++++++ dsd_frame.c | 421 +++++++++++++++++++++++++++++ dsd_frame_sync.c | 691 +++++++++++++++++++++++++++++++++++++++++++++++ dsd_main.c | 635 +++++++++++++++++++++++++++++++++++++++++++ dsd_mbe.c | 122 +++++++++ dsd_serial.c | 88 ++++++ dsd_symbol.c | 180 ++++++++++++ dsd_upsample.c | 171 ++++++++++++ dstar.c | 79 ++++++ dstar_const.h | 311 +++++++++++++++++++++ nxdn96.c | 124 +++++++++ nxdn96_const.h | 62 +++++ p25_lcw.c | 162 +++++++++++ p25p1_const.h | 89 ++++++ p25p1_hdu.c | 312 +++++++++++++++++++++ p25p1_ldu1.c | 295 ++++++++++++++++++++ p25p1_ldu2.c | 352 ++++++++++++++++++++++++ p25p1_tdulc.c | 158 +++++++++++ provoice.c | 519 +++++++++++++++++++++++++++++++++++ provoice_const.h | 81 ++++++ x2tdma_const.h | 62 +++++ x2tdma_data.c | 252 +++++++++++++++++ x2tdma_voice.c | 635 +++++++++++++++++++++++++++++++++++++++++++ 36 files changed, 8441 insertions(+) create mode 100644 CHANGELOG create mode 100644 COPYRIGHT create mode 100644 DSD_Author.pgp create mode 100644 Makefile create mode 100644 README create mode 100644 config.h create mode 100644 configure create mode 100644 dmr_const.h create mode 100644 dmr_data.c create mode 100644 dmr_voice.c create mode 100644 dsd.h create mode 100644 dsd_audio.c create mode 100644 dsd_dibit.c create mode 100644 dsd_file.c create mode 100644 dsd_frame.c create mode 100644 dsd_frame_sync.c create mode 100644 dsd_main.c create mode 100644 dsd_mbe.c create mode 100644 dsd_serial.c create mode 100644 dsd_symbol.c create mode 100644 dsd_upsample.c create mode 100644 dstar.c create mode 100644 dstar_const.h create mode 100644 nxdn96.c create mode 100644 nxdn96_const.h create mode 100644 p25_lcw.c create mode 100644 p25p1_const.h create mode 100644 p25p1_hdu.c create mode 100644 p25p1_ldu1.c create mode 100644 p25p1_ldu2.c create mode 100644 p25p1_tdulc.c create mode 100644 provoice.c create mode 100644 provoice_const.h create mode 100644 x2tdma_const.h create mode 100644 x2tdma_data.c create mode 100644 x2tdma_voice.c diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..f25297d --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,37 @@ +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/COPYRIGHT b/COPYRIGHT new file mode 100644 index 0000000..d402478 --- /dev/null +++ b/COPYRIGHT @@ -0,0 +1,14 @@ +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_Author.pgp b/DSD_Author.pgp new file mode 100644 index 0000000..2303a46 --- /dev/null +++ b/DSD_Author.pgp @@ -0,0 +1,30 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.10 + +mQENBEufusYBCADN1SNkRkQzdLM02MCjen8KQmfuA38MrQIV0dZLpPJcn1+hsvZZ +KWvpUiWCNw1ClGRsJAT5cjonndi1PV7tpzQz+CyMqSP5OwR40eTJBoZhl74hdmU8 +QvcKkJ32khSsOXMo60NHk5iIMDELzOGqq57NHhbunj6NtYog2mR5+WT37JLCvF/q +dvYl2KkRwEHD76/b/O1CyheiiqNMGBb13zPN0qO/PRlENSgViLcDh9qVj4ETNNS6 +zMlP4D4pa07iED4Ua31wiXI04ReznnmvMqzQb8uFbg7d98F3bZpsbNURbmsFHMhj +c9qw65nzaMa3OHfZ3Qwl4XRlNqEzZrclIZADABEBAAG0DW1iZWxpYiBBdXRob3KJ +ATgEEwECACIFAkufusYCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEE+Y +6GPqXv4sI/4H/RsumInT5GtDdBTgxt3lERqc5GF8tI5CAQX9DUMMkKxQ306Fgb4M +ISYdepgL6BlbtSyMdKpKsDLScNA6YXER4gMU1nhhyBulqj41kAfsVbG8hiTBy5Ri +FTo36HrC//Zj1MlaTCB8Rl6B6IftAHIb1U+Gda3WnLDe+R5Pym/76TqeYx23PnJl +V+qfrkjbNyOb2bttyko2iccm9DSq/I1OF0Ufz3P60ssUwHW/b2S6WOXRxiZIq0sz +8pAweUFCxIMWo+XYlSpRtwpebfx+JoHJKdW1cSCgY9jwVsOZO1zxc8P+jr3ByiIR +ZPd0PfBt/AHuC6Hmw9nC12e49+4qsHkj50S5AQ0ES5+6xgEIALf60WjqHm552FIX +KqmG0TIrXpCsYoTWzDdO5j0Ro6fmg9U48BqDH5aS4YRvuyPE7q6DGYEnXF5EIPtU +FhUk4FMmez5eMg91UW4Qjqx8M3reoBROYocM5Nfbc9w7St8+3oRS6rUBIh/B6o4O +kEjkoW3R7O3uFpC53Oi9IVhx/joWxhi430RrUTig5CQzuPFTAHd3xJVE6Pv44nsY +/PsOhBLu2Z3kRkvjcGbsGDlAl2bDEobzQdsqXDD8gJkF5W4IeBKvRC54SE0FSm57 +G1gadhZ7vT4DWQZvYYKXR+AE7FTcopoAFHdapYokOGLHCguabyeZ5q7+s7J4nddL +p5yq8ikAEQEAAYkBHwQYAQIACQUCS5+6xgIbDAAKCRBPmOhj6l7+LPi6B/sEkDkm +Qs/aTz9HDANBAbTuDZTY4WBbkPdFos3xxC2Z/TH5m4bfHEkvNk5WD+j+vYB3exAc +uBi7ZiqibRpap4kiAiKKCRXOyvmEmrjKB5wOWbRpkdTeEdPcpsQ4dDDw1ZUKwzjN +1jI/9GOgq49nAGdlU59f3IdPut6oQNq9vrtanTq2xHVN/rOhV9GLE6gLX1YWkpIH +zYSUheGPsnv4sWRsQDTB7xmF+6RZzjmauKNwsGFscX1TenOWtUbYb9qFCwvNMOSk +51sEaD6PK6wWTXMqQlgjaoGqh1ZaePgT0QTh1W/bvOD0fL5NEToJl2h/lBSvO+ez +R9B++dt5JX9BMxAH +=puA7 +-----END PGP PUBLIC KEY BLOCK----- diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8825fde --- /dev/null +++ b/Makefile @@ -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. + +CC = gcc +CFLAGS = -O2 +INCLUDES = -I. -I/usr/local/include -I/usr/include +LIBS = -L/usr/local/lib -lm -lmbe +INSTALL=install +AR=ar +RANLIB=ranlib +DEST_BASE=/usr/local +DEST_INC=${DEST_BASE}/include +DEST_LIB=${DEST_BASE}/lib +DEST_BIN=${DEST_BASE}/bin +OBJS = dsd_main.o dsd_symbol.o dsd_dibit.o dsd_frame_sync.o dsd_file.o dsd_audio.o dsd_serial.o dsd_frame.o dsd_mbe.o dsd_upsample.o p25p1_hdu.o p25p1_ldu1.o p25p1_ldu2.o p25p1_tdulc.o p25_lcw.o x2tdma_voice.o x2tdma_data.o dstar.o nxdn96.o dmr_voice.o dmr_data.o provoice.o + +all: dsd + +build: all + +dsd_main.o: dsd_main.c dsd.h config.h + $(CC) $(CFLAGS) $(INCLUDES) -c dsd_main.c -o dsd_main.o + +dsd_symbol.o: dsd_symbol.c dsd.h config.h + $(CC) $(CFLAGS) $(INCLUDES) -c dsd_symbol.c -o dsd_symbol.o + +dsd_dibit.o: dsd_dibit.c dsd.h config.h + $(CC) $(CFLAGS) $(INCLUDES) -c dsd_dibit.c -o dsd_dibit.o + +dsd_frame_sync.o: dsd_frame_sync.c dsd.h config.h + $(CC) $(CFLAGS) $(INCLUDES) -c dsd_frame_sync.c -o dsd_frame_sync.o + +dsd_file.o: dsd_file.c dsd.h config.h + $(CC) $(CFLAGS) $(INCLUDES) -c dsd_file.c -o dsd_file.o + +dsd_audio.o: dsd_audio.c dsd.h config.h + $(CC) $(CFLAGS) $(INCLUDES) -c dsd_audio.c -o dsd_audio.o + +dsd_serial.o: dsd_serial.c dsd.h config.h + $(CC) $(CFLAGS) $(INCLUDES) -c dsd_serial.c -o dsd_serial.o + +dsd_frame.o: dsd_frame.c dsd.h config.h + $(CC) $(CFLAGS) $(INCLUDES) -c dsd_frame.c -o dsd_frame.o + +dsd_mbe.o: dsd_mbe.c dsd.h config.h + $(CC) $(CFLAGS) $(INCLUDES) -c dsd_mbe.c -o dsd_mbe.o + +dsd_upsample.o: dsd_upsample.c dsd.h config.h + $(CC) $(CFLAGS) $(INCLUDES) -c dsd_upsample.c -o dsd_upsample.o + +p25p1_hdu.o: p25p1_hdu.c dsd.h config.h + $(CC) $(CFLAGS) $(INCLUDES) -c p25p1_hdu.c -o p25p1_hdu.o + +p25p1_ldu1.o: p25p1_ldu1.c p25p1_const.h dsd.h config.h + $(CC) $(CFLAGS) $(INCLUDES) -c p25p1_ldu1.c -o p25p1_ldu1.o + +p25p1_ldu2.o: p25p1_ldu2.c p25p1_const.h dsd.h config.h + $(CC) $(CFLAGS) $(INCLUDES) -c p25p1_ldu2.c -o p25p1_ldu2.o + +p25p1_tdulc.o: p25p1_tdulc.c dsd.h config.h + $(CC) $(CFLAGS) $(INCLUDES) -c p25p1_tdulc.c -o p25p1_tdulc.o + +p25_lcw.o: p25_lcw.c dsd.h config.h + $(CC) $(CFLAGS) $(INCLUDES) -c p25_lcw.c -o p25_lcw.o + +x2tdma_voice.o: x2tdma_voice.c x2tdma_const.h dsd.h config.h + $(CC) $(CFLAGS) $(INCLUDES) -c x2tdma_voice.c -o x2tdma_voice.o + +x2tdma_data.o: x2tdma_data.c x2tdma_const.h dsd.h config.h + $(CC) $(CFLAGS) $(INCLUDES) -c x2tdma_data.c -o x2tdma_data.o + +dstar.o: dstar.c dstar_const.h dsd.h config.h + $(CC) $(CFLAGS) $(INCLUDES) -c dstar.c -o dstar.o + +nxdn96.o: nxdn96.c nxdn96_const.h dsd.h config.h + $(CC) $(CFLAGS) $(INCLUDES) -c nxdn96.c -o nxdn96.o + +dmr_voice.o: dmr_voice.c dmr_const.h dsd.h config.h + $(CC) $(CFLAGS) $(INCLUDES) -c dmr_voice.c -o dmr_voice.o + +dmr_data.o: dmr_data.c dmr_const.h dsd.h config.h + $(CC) $(CFLAGS) $(INCLUDES) -c dmr_data.c -o dmr_data.o + +provoice.o: provoice.c provoice_const.h dsd.h config.h + $(CC) $(CFLAGS) $(INCLUDES) -c provoice.c -o provoice.o + +dsd: $(OBJS) dsd.h config.h + $(CC) $(CFLAGS) $(LIBS) -o dsd $(OBJS) + +clean: + rm -f *.o + rm -f dsd + +install: dsd + $(INSTALL) dsd $(DEST_BIN) + chgrp uucp $(DEST_BIN)/dsd + chmod g+s $(DEST_BIN)/dsd diff --git a/README b/README new file mode 100644 index 0000000..9709a75 --- /dev/null +++ b/README @@ -0,0 +1,520 @@ +Digital Speech Decoder 1.3 +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. DSD 1.3 + requires mbelib 1.1 or later. + + Supported formats in version 1.3: + + 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. + + Development (no speech) support only: + + NXDN (9600) Digital radio standard used by NEXEDGE and IDAS brands. + + Development support only. DSD recognizes frames and can + extract the voice bits but speech is not yet decoded. + The issue is likely either an unusual interleave pattern + or a pseudo-random bit mask initialized by a "color code" + Note: not enabled by default, use -fn to enable. + + D-STAR Amateur radio digital voice standard + + Development support only. DSD recognized frames and can + extract the voice bits but speech is not yet decoded. + D-STAR likely uses a version of AMBE not yet supported by + mbelib. The voice bit interleave pattern also needs to be + determined. + Note: not enabled by default, use -fn to enable. + + Unsupported formats in version 1.3 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. + + NXDN (4800) This should be supportable as soon as we have .wav files + or access to a radio programmed in this format. + + Supported demodulation optimizations in version 1.3: + + 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. + Just untar and run "make" or "make install". There are some debugging/ + development options in config.h that normal users will want to leave + disabled as they can severely impact performance. + +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 input: 39% nac: 5C2 src: 0 tg: 32464 TDULC +Sync: -p25p1 mod: C4FM input: 39% nac: 5C2 src: 0 tg: 32464 TDULC +Sync: -p25p1 mod: C4FM input: 39% nac: 5C2 src: 0 tg: 32464 TDULC +Sync: -p25p1 mod: C4FM input: 39% nac: 5C2 src: 0 tg: 32464 TDULC +Sync: -p25p1 mod: C4FM input: 38% nac: 5C2 src: 0 tg: 32464 TDU +Sync: -p25p1 mod: C4FM input: 38% nac: 5C2 src: 0 tg: 32464 HDU +Sync: -p25p1 mod: C4FM input: 42% nac: 5C2 src: 0 tg: 32464 LDU1 e: +Sync: (-p25p1) mod: C4FM input: 39% nac: 5C2 src: 52610 tg: 32464 (LDU2) e: +Sync: -p25p1 mod: C4FM input: 38% nac: 5C2 src: 52610 tg: 32464 LDU1 e: +Sync: -p25p1 mod: C4FM input: 39% nac: 5C2 src: 52610 tg: 32464 LDU2 e: +Sync: -p25p1 mod: C4FM input: 39% nac: 5C2 src: 52610 tg: 32464 LDU1 e: +Sync: -p25p1 mod: C4FM input: 39% nac: 5C2 src: 52610 tg: 32464 LDU2 e: +Sync: -p25p1 mod: C4FM input: 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. + + "input" 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 input: 59% src: 17211 tg: 197 [SLOT0] slot1 VOICE e: +Sync: -X2-TDMA mod: QPSK input: 47% src: 17211 tg: 197 [SLOT0] slot1 VOICE e: +Sync: -X2-TDMA mod: QPSK input: 43% src: 17211 tg: 197 [SLOT0] slot1 VOICE e: +Sync: (-X2-TDMA) mod: QPSK input: 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 (default is /dev/audio) + -o Audio output device (default is /dev/audio) + -d Create mbe data files, use this directory + -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 + + 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* (no audio) + -fn Decode only NXDN96* (no audio) + -fp Decode only ProVoice* + -fr Decode only DMR/MOTOTRBO + -fx Decode only X2-TDMA + -ma Auto-select modulation optimizations (default) + -mc Use only C4FM modulation optimizations + -mg Use only GFSK modulation optimizations + -mq Use only QPSK modulation optimizations + -u Unvoiced speech quality (default=3) + -xx Expect non-inverted X2-TDMA signal + -xr Expect inverted DMR/MOTOTRBO signal + + + NXDN and D-STAR are not enabled by default as they are for development + testing only and have shorter frame sync patterns that are prone to + false triggering. + + 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/config.h b/config.h new file mode 100644 index 0000000..a0eccf9 --- /dev/null +++ b/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/configure b/configure new file mode 100644 index 0000000..b27b5a8 --- /dev/null +++ b/configure @@ -0,0 +1,3 @@ +#!/bin/sh + +echo "There is no configure script, just run make" diff --git a/dmr_const.h b/dmr_const.h new file mode 100644 index 0000000..22a62e3 --- /dev/null +++ b/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/dmr_data.c b/dmr_data.c new file mode 100644 index 0000000..1e809d0 --- /dev/null +++ b/dmr_data.c @@ -0,0 +1,251 @@ +/* + * 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_DATA_SYNC) == 0) + { + if (state->currentslot == 0) + { + sprintf (state->slot0light, "[slot0]"); + } + else + { + sprintf (state->slot1light, "[slot1]"); + } + } + else if (strcmp (sync, DMR_VOICE_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/dmr_voice.c b/dmr_voice.c new file mode 100644 index 0000000..329b50e --- /dev/null +++ b/dmr_voice.c @@ -0,0 +1,376 @@ +/* + * 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; + +#ifdef DMR_DUMP + int k; + char syncbits[49]; + char cachbits[25]; +#endif + + mutecurrentslot = 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_DATA_SYNC) == 0) + { + mutecurrentslot = 1; + if (state->currentslot == 0) + { + sprintf (state->slot0light, "[slot0]"); + } + else + { + sprintf (state->slot1light, "[slot1]"); + } + } + else if (strcmp (sync, DMR_VOICE_SYNC) == 0) + { + mutecurrentslot = 0; + if (state->currentslot == 0) + { + sprintf (state->slot0light, "[SLOT0]"); + } + else + { + sprintf (state->slot1light, "[SLOT1]"); + } + } + + 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_DATA_SYNC) == 0) + { + if (state->currentslot == 0) + { + sprintf (state->slot1light, " slot1 "); + } + else + { + sprintf (state->slot0light, " slot0 "); + } + } + else if (strcmp (sync, DMR_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.h b/dsd.h new file mode 100644 index 0000000..f737dc1 --- /dev/null +++ b/dsd.h @@ -0,0 +1,218 @@ +/* + * 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 +#define __USE_XOPEN +#include +#include +#include +#include +#include +#include +#include +#ifdef SOLARIS +#include +#endif +#ifdef BSD +#include +#endif +#include +#include + +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; + char audio_out_dev[1024]; + int audio_out_fd; + int split; + int playoffset; + char mbe_out_dir[1024]; + char mbe_out_file[1024]; + FILE *mbe_out_f; + float audio_gain; + int audio_out; + char wav_out_file[1024]; + FILE *wav_out_f; + 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_nxdn; + 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; +} dsd_opts; + +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 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; +} dsd_state; + +/* + * Frame sync patterns + */ +#define INV_FRAME_SYNC "333331331133111131311111" +#define FRAME_SYNC "111113113311333313133333" +#define X2TDMA_VOICE_SYNC "113131333331313331113311" +#define X2TDMA_DATA_SYNC "331313111113131113331133" +#define DSTAR_SYNC "313131313133131113313111" +#define INV_DSTAR_SYNC "131313131311313331131333" +#define INV_NXDN96_SYNC "313133113131111333" +#define NXDN96_SYNC "131311331313333111" +#define DMR_DATA_SYNC "313333111331131131331131" +#define DMR_VOICE_SYNC "131111333113313313113313" +#define INV_PROVOICE_SYNC "31313111333133133311331133113311" +#define PROVOICE_SYNC "13131333111311311133113311331133" + + +/* + * 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); +void skipDibit (dsd_opts * opts, dsd_state * state, int count); +void saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d); +void saveAmbe2250Data (dsd_opts * opts, dsd_state * state, char *ambe_d); +int readImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d); +int readAmbe2250Data (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 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 noCarrier (dsd_opts * opts, dsd_state * state); +void initOpts (dsd_opts * opts); +void initState (dsd_state * state); +void usage (); +void liveScanner (dsd_opts * opts, dsd_state * state); +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 processNXDN96 (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 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); diff --git a/dsd_audio.c b/dsd_audio.c new file mode 100644 index 0000000..0ba069b --- /dev/null +++ b/dsd_audio.c @@ -0,0 +1,365 @@ +/* + * 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 > 74) + { + state->aout_max_buf_idx = 0; + state->aout_max_buf_p = state->aout_max_buf; + } + + // lookup max history + for (i = 0; i < 75; 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; + } + + // 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) +{ + + int n; + short aout_buf[160]; + short *aout_buf_p; + + 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++; + } + + write (opts->wav_out_fd, aout_buf, 320); + fflush (opts->wav_out_f); +} + +void +playSynthesizedVoice (dsd_opts * opts, dsd_state * state) +{ + + if (state->audio_out_idx > opts->delay) + { + // output synthesized speech to sound card + 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) +{ + +#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 + +#ifdef BSD + + 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; + } + + 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 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 /dev/audio\n"); + } + + // 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 + +#ifdef BSD + 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); + } +} diff --git a/dsd_dibit.c b/dsd_dibit.c new file mode 100644 index 0000000..5ebcbd1 --- /dev/null +++ b/dsd_dibit.c @@ -0,0 +1,290 @@ +/* + * 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++; + } + + // determine dibit state + if ((state->synctype == 6) || (state->synctype == 14)) + { + 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)) + { + 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_file.c b/dsd_file.c new file mode 100644 index 0000000..9918fc7 --- /dev/null +++ b/dsd_file.c @@ -0,0 +1,331 @@ +/* + * 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 +saveAmbe2250Data (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 +readAmbe2250Data (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; + + 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; + + 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); + } + + for (i = 0; i < 17; i++) + { + tgid[i] = 0; + } + + 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); + } + 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); + system (shell); + } +} + +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"); + if (opts->wav_out_f == NULL) + { + printf ("Error - could not open wav output file %s\n", opts->wav_out_file); + return; + } + opts->wav_out_fd = fileno (opts->wav_out_f); + + fprintf (opts->wav_out_f, "RIFF"); + // total length + fputc (0, opts->wav_out_f); + fputc (0, opts->wav_out_f); + fputc (0, opts->wav_out_f); + fputc (0, 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 (176, opts->wav_out_f); + fputc (62, opts->wav_out_f); + fputc (0, opts->wav_out_f); + fputc (0, opts->wav_out_f); + + // bytes/sample + 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 (0, opts->wav_out_f); + fputc (0, opts->wav_out_f); + fputc (0, opts->wav_out_f); + fputc (127, opts->wav_out_f); + + fflush (opts->wav_out_f); +} diff --git a/dsd_frame.c b/dsd_frame.c new file mode 100644 index 0000000..3cccfee --- /dev/null +++ b/dsd_frame.c @@ -0,0 +1,421 @@ +/* + * 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 +printFrameInfo (dsd_opts * opts, dsd_state * state) +{ + + int level; + + level = (int) (((float) state->max / (float) 32768) * (float) 100); + if (opts->verbose > 0) + { + printf ("input: %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->nac = 0; + state->lastsrc = 0; + state->lasttg = 0; + if (opts->errorbars == 1) + { + if (opts->verbose > 0) + { + level = (int) (((float) state->max / (float) 32768) * (float) 100); + printf ("input: %2i%% ", level); + } + } + state->nac = 0; + if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) + { + openMbeOutFile (opts, state); + } + sprintf (state->fsubtype, " VOICE "); + processNXDN96 (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) (((float) state->max / (float) 32768) * (float) 100); + printf ("input: %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 >= 10) && (state->synctype <= 13)) + { + state->nac = 0; + state->lastsrc = 0; + state->lasttg = 0; + if (opts->errorbars == 1) + { + if (opts->verbose > 0) + { + level = (int) (((float) state->max / (float) 32768) * (float) 100); + printf ("input: %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; + state->lastsrc = 0; + state->lasttg = 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) (((float) state->max / (float) 32768) * (float) 100); + printf ("input: %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"); + } + state->cur_mp->repeat = 0; + 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"); + } + state->cur_mp->repeat = 0; + if (opts->mbe_out_dir[0] != 0) + { + closeMbeOutFile (opts, state); + } + mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced); + state->tgcount = 0; + state->lastp25type = 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"); + } + state->cur_mp->repeat = 0; + if (opts->mbe_out_dir[0] != 0) + { + closeMbeOutFile (opts, state); + } + mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced); + state->tgcount = 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"); + } + 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_frame_sync.c b/dsd_frame_sync.c new file mode 100644 index 0000000..26aa100 --- /dev/null +++ b/dsd_frame_sync.c @@ -0,0 +1,691 @@ +/* + * 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 +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 = +NXDN96 + * 9 = -NXDN96 + * 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 + */ + + 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]; + + // detect frame sync + t = 0; + synctest[24] = 0; + synctest18[18] = 0; + synctest32[32] = 0; + synctest_pos = 0; + synctest_p = synctest_buf; + 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++; + } + + //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; + } + +/* +printf("%c", dibit); +if (t == 768) +{ + printf("\n"); + t=0; +} +*/ + + + *synctest_p = dibit; + if (t >= 24) + { + 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, FRAME_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_FRAME_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_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_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_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_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) + { + 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) + { + 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_nxdn == 1) + { + strncpy (synctest18, (synctest_p - 17), 18); + if (strcmp (synctest18, NXDN96_SYNC) == 0) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + sprintf (state->ftype, " NXDN96 "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, " +NXDN96 ", synctest_pos + 1, modulation); + } + state->lastsynctype = 8; + return (8); + } + if (strcmp (synctest18, INV_NXDN96_SYNC) == 0) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + sprintf (state->ftype, " NXDN96 "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, " -NXDN96 ", synctest_pos + 1, modulation); + } + state->lastsynctype = 9; + return (9); + } + } + 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 ((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_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_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_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_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 (synctest_pos < 10200) + { + synctest_pos++; + synctest_p++; + } + else + { + // buffer reset + synctest_pos = 0; + synctest_p = synctest_buf; + noCarrier (opts, state); + } + + if (state->carrier == 1) + { + if (synctest_pos >= 1800) + { + if (opts->errorbars == 1) + { + if (opts->verbose > 1) + { + printf ("Sync: no sync\n"); + } + } + noCarrier (opts, state); + return (-1); + } + } + } + + return (-1); +} diff --git a/dsd_main.c b/dsd_main.c new file mode 100644 index 0000000..dbe1c28 --- /dev/null +++ b/dsd_main.c @@ -0,0 +1,635 @@ +/* + * 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 "nxdn96_const.h" +#include "dmr_const.h" +#include "provoice_const.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->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_nxdn = 0; + 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; +} + +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->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 (j = 0; i < 25; j++) + { + for (i = 0; j < 16; i++) + { + state->tg[i][j] = 0; + } + } + 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); +} + +void +usage () +{ + printf ("Digital Speech Decoder 1.3\n"); + 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 (" -g Audio output gain (default = 0 = auto)\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\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* (no audio)\n"); + printf (" -fn Decode only NXDN96* (no audio)\n"); + printf (" -fp Decode only ProVoice*\n"); + printf (" -fr Decode only DMR/MOTOTRBO\n"); + printf (" -fx Decode only X2-TDMA\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 (" -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) +{ + 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; + } + } +} + +int +main (int argc, char **argv) +{ + + int c; + extern char *optarg; + extern int optind, opterr, optopt; + + dsd_opts opts; + dsd_state state; + + initOpts (&opts); + initState (&state); + + while ((c = getopt (argc, argv, "hep:qstv:z:i:o:d:g:nw:B:C:R:f:m:u:x:A:S:M:r")) != -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; + } + 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': + sscanf (optarg, "%s", opts.audio_in_dev); + break; + case 'o': + sscanf (optarg, "%s", opts.audio_out_dev); + break; + case 'd': + sscanf (optarg, "%s", opts.mbe_out_dir); + 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) + { + 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': + sscanf (optarg, "%s", opts.wav_out_file); + 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': + sscanf (optarg, "%s", opts.serial_dev); + 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 = 0; + opts.frame_x2tdma = 1; + opts.frame_p25p1 = 1; + opts.frame_nxdn = 0; + 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_nxdn = 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_nxdn = 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_nxdn = 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 ("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_nxdn = 0; + opts.frame_dmr = 0; + opts.frame_provoice = 0; + printf ("Decoding only P25 Phase 1 frames.\n"); + } + else if (optarg[0] == 'n') + { + opts.frame_dstar = 0; + opts.frame_x2tdma = 0; + opts.frame_p25p1 = 0; + opts.frame_nxdn = 1; + opts.frame_dmr = 0; + opts.frame_provoice = 0; + 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_nxdn = 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; + default: + usage (); + exit (0); + } + } + + + if (opts.resume > 0) + { + openSerial (&opts, &state); + } + + if (opts.playfiles == 1) + { + opts.split = 1; + opts.playoffset = 0; + opts.delay = 0; + openAudioOutDevice (&opts, 8000); + } + else if (strcmp (opts.audio_in_dev, opts.audio_out_dev) != 0) + { + opts.split = 1; + opts.playoffset = 0; + opts.delay = 0; + openAudioOutDevice (&opts, 8000); + openAudioInDevice (&opts); + } + else + { + opts.split = 0; + opts.playoffset = 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); + } + return (0); +} diff --git a/dsd_mbe.c b/dsd_mbe.c new file mode 100644 index 0000000..67f1b34 --- /dev/null +++ b/dsd_mbe.c @@ -0,0 +1,122 @@ +/* + * 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 +playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv) +{ + + int i; + char imbe_d[88]; + char ambe_d[49]; + + for (i = state->optind; i < argc; i++) + { + sprintf (opts->mbe_in_file, 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_fd != -1) + { + writeSynthesizedVoice (opts, state); + } + + if (opts->audio_out == 1) + { + playSynthesizedVoice (opts, state); + } + } + else if (state->mbe_file_type == 1) + { + readAmbe2250Data (opts, state, ambe_d); + mbe_processAmbe2250Dataf (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_fd != -1) + { + writeSynthesizedVoice (opts, state); + } + if (opts->audio_out == 1) + { + playSynthesizedVoice (opts, state); + } + } + } + } +} + +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]; + + 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 + { + mbe_processAmbe3600x2250Framef (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) + { + saveAmbe2250Data (opts, state, ambe_d); + } + } + + if (opts->errorbars == 1) + { + printf ("%s", state->err_str); + } + + processAudio (opts, state); + if (opts->wav_out_fd != -1) + { + writeSynthesizedVoice (opts, state); + } + + if (opts->audio_out == 1) + { + playSynthesizedVoice (opts, state); + } +} diff --git a/dsd_serial.c b/dsd_serial.c new file mode 100644 index 0000000..dfd6a03 --- /dev/null +++ b/dsd_serial.c @@ -0,0 +1,88 @@ +#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; + + 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[7]; + + if (opts->serial_fd > 0) + { + sprintf (cmd, "\rKEY00\r"); + write (opts->serial_fd, cmd, 7); + cmd[0] = 2; + cmd[1] = 75; + cmd[2] = 15; + cmd[3] = 3; + cmd[4] = 93; + cmd[5] = 0; + write (opts->serial_fd, cmd, 5); + state->numtdulc = 0; + } +} diff --git a/dsd_symbol.c b/dsd_symbol.c new file mode 100644 index 0000000..45cda67 --- /dev/null +++ b/dsd_symbol.c @@ -0,0 +1,180 @@ +/* + * 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 +getSymbol (dsd_opts * opts, dsd_state * state, int have_sync) +{ + + short sample; + int i, sum, symbol, count; + + sum = 0; + count = 0; + for (i = 0; i < state->samplesPerSymbol; i++) + { + // timing control + if ((i == 0) && (have_sync == 0)) + { + 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; + } + + read (opts->audio_in_fd, &sample, 2); + 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 == 5) + { + if ((i >= 2) && (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_upsample.c b/dsd_upsample.c new file mode 100644 index 0000000..8d12aa2 --- /dev/null +++ b/dsd_upsample.c @@ -0,0 +1,171 @@ +/* + * 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, a, b, c, d; + float phasestart, phaseend, resamplestart, resampleend, phasestep, resampleamp2; + float resamplemin, resamplemax; + + if (state->audio_out_idx2 > 23) + { + outbuf1 = state->audio_out_float_buf_p; + outbuf1--; + c = *outbuf1; + outbuf1 -= 6; + b = *outbuf1; + outbuf1 -= 6; + a = *outbuf1; + d = (invalue); + resamplemin = 32767; + resamplemax = -32768; + if (a < resamplemin) + { + resamplemin = a; + } + if (a > resamplemax) + { + resamplemax = a; + } + if (b < resamplemin) + { + resamplemin = b; + } + if (b > resamplemax) + { + resamplemax = b; + } + if (c < resamplemin) + { + resamplemin = c; + } + if (c > resamplemax) + { + resamplemax = c; + } + if (d < resamplemin) + { + resamplemin = d; + } + if (d > resamplemax) + { + resamplemax = d; + } + resampleamp2 = ((float) resamplemax - (float) resamplemin) / (float) 2; +#ifdef UPSAMPLE_DEBUG + printf ("a:%f b:%f c:%f d:%f resamplemin:%f resamplemax:%f resampleamp2:%f\n", a, b, c, d, resamplemin, resamplemax, resampleamp2); +#endif + if (resampleamp2 == 0) + { + resamplestart = (float) 0; + resampleend = (float) 0; + } + else + { + resamplestart = (((float) b - (float) resamplemin) / resampleamp2) - (float) 1.0; + resampleend = (((float) c - (float) resamplemin) / resampleamp2) - (float) 1.0; + } + + if (resamplestart < -1) + { + resamplestart = (float) -1; + } + else if (resamplestart > (float) 1) + { + resamplestart = (float) 1; + } + if (resampleend < -1) + { + resampleend = (float) -1; + } + else if (resampleend > (float) 1) + { + resampleend = (float) 1; + } + + phasestart = asinf (resamplestart); + phaseend = asinf (resampleend); + phasestep = (phaseend - phasestart) / 6; +#ifdef UPSAMPLE_DEBUG + printf ("resamplestart:%f, resampleend:%f, phasestart:%f, phaseend:%f, phasestep:%f\n", resamplestart, resampleend, phasestart, phaseend, phasestep); +#endif + + // rewrite samples between b and c + outbuf1 = state->audio_out_float_buf_p; + outbuf1 -= 6; + for (i = 1; i < 6; i++) + { + *outbuf1 = (resamplemin + resampleamp2 + (resampleamp2 * sin (phasestart + (phasestep * (float) i)))); +#ifdef UPSAMPLE_DEBUG + printf ("audio_out_idx2:%i outbuf:%f\n", state->audio_out_idx2, *outbuf1); +#endif + outbuf1++; + } +#ifdef UPSAMPLE_DEBUG + printf ("(c):%f\n", *outbuf1); +#endif + // write d + outbuf1 += 6; + *outbuf1 = d; +#ifdef UPSAMPLE_DEBUG + printf ("audio_out_idx2:%i outbuf(d):%f\n", state->audio_out_idx2, *outbuf1); +#endif + outbuf1++; + + // smooth + outbuf1 -= 36; + for (j = 0; j < 12; j++) + { + for (i = 0; i < 12; i++) + { + sum = 0; + outbuf1--; + sum += *outbuf1; + outbuf1++; + sum += *outbuf1; + outbuf1++; + sum += *outbuf1; + outbuf1--; + *outbuf1 = (sum / (float) 3); + outbuf1++; + } + outbuf1 -= 11; + } + } + else + { + outbuf1 = state->audio_out_float_buf_p; + outbuf1--; + c = *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 = invalue; + } +} diff --git a/dstar.c b/dstar.c new file mode 100644 index 0000000..640a7a1 --- /dev/null +++ b/dstar.c @@ -0,0 +1,79 @@ +/* + * 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 very incomplete and does not work yet + * It is unknown if the ambe3600x2250 decoder is even compatible with D-STAR + * voice frames. If it is then the interleave pattern needs to be determined. + * GMSK modulation optimizations will also required to get a usable bit error + * rate. This was included mainly as an example of how other systmes might + * be supported. + */ + +#include "dsd.h" +#include "dstar_const.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]; + char dstar[300]; + const int *w, *x; + + if (opts->errorbars == 1) + { + printf ("e:"); + } + +#ifdef DSTAR_DUMP + printf ("\n"); +#endif + + for (j = 0; j < 210; j++) // 210 is very long but used for debugging + { + // voice frame + w = dW; + x = dX; + for (i = 0; i < 72; i++) + { + dibit = getDibit (opts, state); + dstar[i] = dibit + 48; + ambe_fr[*w][*x] = (1 & dibit); + w++; + x++; + } + dstar[i] = 32; + processMbeFrame (opts, state, NULL, ambe_fr, NULL); + + // data frame + for (i = 73; i < 97; i++) + { + dstar[i] = getDibit (opts, state) + 48; + } + dstar[i] = 0; + +#ifdef DSTAR_DUMP + printf ("%s\n", dstar); +#endif + } + if (opts->errorbars == 1) + { + printf ("\n"); + } +} diff --git a/dstar_const.h b/dstar_const.h new file mode 100644 index 0000000..35bf59e --- /dev/null +++ b/dstar_const.h @@ -0,0 +1,311 @@ +/* + * 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 + +/* + * 4x18 + */ +/* +const int dW[72] = { +0,0,1,2, +0,0,1,2, +0,0,1,2, +0,0,1,2, +0,0,1,3, +0,0,1,3, +0,1,1,3, +0,1,1,3, +0,1,1,3, +0,1,1,3, +0,1,1,3, +0,1,2,3, +0,1,2,3, +0,1,2,3, +0,1,2,3, +0,1,2,3, +0,1,2,3, +0,1,2,3 +}; + +const int dX[72] = { +23,5,10,3, +22,4,9,2, +21,3,8,1, +20,2,7,0, +19,1,6,13, +18,0,5,12, +17,22,4,11, +16,21,3,10, +15,20,2,9, +14,19,1,8, +13,18,0,7, +12,17,10,6, +11,16,9,5, +10,15,8,4, +9,14,7,3, +8,13,6,2, +7,12,5,1, +6,11,4,0 +}; +*/ + +/* + * 3x24 alt + */ +const int dW[72] = { + 1, 0, 3, + 1, 0, 3, + 1, 0, 3, + 1, 0, 3, + 1, 0, 3, + 1, 0, 3, + 1, 0, 3, + 1, 0, 3, + 1, 0, 3, + 1, 0, 3, + 1, 0, 3, + 1, 0, 3, + 1, 0, 3, + 1, 0, 2, + 1, 0, 2, + 1, 0, 2, + 1, 0, 2, + 1, 0, 2, + 1, 0, 2, + 1, 0, 2, + 1, 0, 2, + 1, 0, 2, + 1, 0, 2, + 0, 3, 2, +}; + +const int dX[72] = { + 22, 22, 12, + 21, 21, 11, + 20, 20, 10, + 19, 19, 9, + 18, 18, 8, + 17, 17, 7, + 16, 16, 6, + 15, 15, 5, + 14, 14, 4, + 13, 13, 3, + 12, 12, 2, + 11, 11, 1, + 10, 10, 0, + 9, 9, 10, + 8, 8, 9, + 7, 7, 8, + 6, 6, 7, + 5, 5, 6, + 4, 4, 5, + 3, 3, 4, + 2, 2, 3, + 1, 1, 2, + 0, 0, 1, + 23, 13, 0 +}; + +/* + * 3x24 + */ +/* +const int dW[72] = { +0,1,2, +0,1,2, +0,1,2, +0,1,2, +0,1,2, +0,1,2, +0,1,2, +0,1,2, +0,1,2, +0,1,2, +0,1,3, +0,1,3, +0,1,3, +0,1,3, +0,1,3, +0,1,3, +0,1,3, +0,1,3, +0,1,3, +0,1,3, +0,1,3, +0,1,3, +0,1,3, +0,2,3, +}; + +const int dX[72] = { +23,22,9, +22,21,8, +21,20,7, +20,19,6, +19,18,5, +18,17,4, +17,16,3, +16,15,2, +15,14,1, +14,13,0, +13,12,13, +12,11,12, +11,10,11, +10,9,10, +9,8,9, +8,7,8, +7,6,7, +6,5,6, +5,4,5, +4,3,4, +3,2,3, +2,1,2, +1,0,1, +0,10,0 +}; +*/ + + +/* + * 2x36 + */ +/* +const int dW[72] = { +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, +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 dX[72] = { +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, +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 +}; +*/ + +/* + * non-interleaved + */ +/* +const int dW[72] = { +0,0,0,0,0,0, +0,0,0,0,0,0, +0,0,0,0,0,0, +0,0,0,0,0,0, +1,1,1,1,1,1, +1,1,1,1,1,1, +1,1,1,1,1,1, +1,1,1,1,1,2, +2,2,2,2,2,2, +2,2,2,2,3,3, +3,3,3,3,3,3, +3,3,3,3,3,3 +}; + +const int dX[72] = { +23,22,21,20,19,18, +17,16,15,14,13,12, +11,10,9,8,7,6, +5,4,3,2,1,0, +22,21,20,19,18,17, +16,15,14,13,12,11, +10,9,8,7,6,5, +4,3,2,1,0,10, +9,8,7,6,5,4, +3,2,1,0,13,12, +11,10,9,8,7,6, +5,4,3,2,1,0 +}; +*/ + +#endif diff --git a/nxdn96.c b/nxdn96.c new file mode 100644 index 0000000..4072b76 --- /dev/null +++ b/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/nxdn96_const.h b/nxdn96_const.h new file mode 100644 index 0000000..8af701e --- /dev/null +++ b/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/p25_lcw.c b/p25_lcw.c new file mode 100644 index 0000000..43014c2 --- /dev/null +++ b/p25_lcw.c @@ -0,0 +1,162 @@ +#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 + if (state->tgcount < 24) + { + // update tg buffer + j = 0; + for (i = 40; i < 52; i++) + { + state->tg[state->tgcount][j] = lcinfo[i]; + j++; + } + tmpstr[12] = 48; + tmpstr[13] = 48; + tmpstr[14] = 48; + tmpstr[15] = 48; + tmpstr[16] = 0; + state->tgcount = state->tgcount + 1; + } + + // first one again for tg display + j = 0; + for (i = 40; i < 52; i++) + { + tmpstr[j] = lcinfo[i]; + j++; + } + tmpstr[12] = 48; + tmpstr[13] = 48; + tmpstr[14] = 48; + tmpstr[15] = 48; + tmpstr[16] = 0; + tmpstr[16] = 0; + talkgroup = strtol (tmpstr, NULL, 2); + state->lasttg = 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 (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/p25p1_const.h b/p25p1_const.h new file mode 100644 index 0000000..5f67dde --- /dev/null +++ b/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/p25p1_hdu.c b/p25p1_hdu.c new file mode 100644 index 0000000..699e07a --- /dev/null +++ b/p25p1_hdu.c @@ -0,0 +1,312 @@ +/* + * 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); + + 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 (opts->p25tg == 1) + { + printf ("tg: %li\n", talkgroup); + } +} diff --git a/p25p1_ldu1.c b/p25p1_ldu1.c new file mode 100644 index 0000000..6a6379a --- /dev/null +++ b/p25p1_ldu1.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" +#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++; + } + 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/p25p1_ldu2.c b/p25p1_ldu2.c new file mode 100644 index 0000000..fe6b193 --- /dev/null +++ b/p25p1_ldu2.c @@ -0,0 +1,352 @@ +/* + * 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++; + } + 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/p25p1_tdulc.c b/p25p1_tdulc.c new file mode 100644 index 0000000..77fe6c6 --- /dev/null +++ b/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/provoice.c b/provoice.c new file mode 100644 index 0000000..2c01329 --- /dev/null +++ b/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/provoice_const.h b/provoice_const.h new file mode 100644 index 0000000..ea7f9a9 --- /dev/null +++ b/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/x2tdma_const.h b/x2tdma_const.h new file mode 100644 index 0000000..23b5662 --- /dev/null +++ b/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/x2tdma_data.c b/x2tdma_data.c new file mode 100644 index 0000000..c70f3f3 --- /dev/null +++ b/x2tdma_data.c @@ -0,0 +1,252 @@ +/* + * 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_DATA_SYNC) == 0) + { + if (state->currentslot == 0) + { + sprintf (state->slot0light, "[slot0]"); + } + else + { + sprintf (state->slot1light, "[slot1]"); + } + } + else if (strcmp (sync, X2TDMA_VOICE_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/x2tdma_voice.c b/x2tdma_voice.c new file mode 100644 index 0000000..da3eeeb --- /dev/null +++ b/x2tdma_voice.c @@ -0,0 +1,635 @@ +/* + * 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; + +#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; + + 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_DATA_SYNC) == 0) + { + mutecurrentslot = 1; + if (state->currentslot == 0) + { + sprintf (state->slot0light, "[slot0]"); + } + else + { + sprintf (state->slot1light, "[slot1]"); + } + } + else if (strcmp (sync, X2TDMA_VOICE_SYNC) == 0) + { + mutecurrentslot = 0; + if (state->currentslot == 0) + { + sprintf (state->slot0light, "[SLOT0]"); + } + else + { + sprintf (state->slot1light, "[SLOT1]"); + } + } + + 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_DATA_SYNC) == 0) + { + if (state->currentslot == 0) + { + sprintf (state->slot1light, " slot1 "); + } + else + { + sprintf (state->slot0light, " slot0 "); + } + } + else if (strcmp (sync, X2TDMA_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); + } + } +}