Compare commits

...

121 Commits

Author SHA1 Message Date
Andreas Eversberg 49925d4b95 anetz: Show prefixes and channels with --geo list 2024-04-15 23:12:31 +02:00
Andreas Eversberg f96994e0e7 SIM: Display SIM version in programming mode on memory location 06
Untested!
2024-04-13 23:04:33 +02:00
Andreas Eversberg 9b4095d894 Rename definititions that uses the exact word "DEBUG"
"DEBUG" may be defined, but we don't want to compile eurosignal and
fuenf-tone-ruf with debug code.
2024-04-12 16:57:09 +02:00
Andreas Eversberg b642f82390 pocsag: Add option to change text message padding character 2024-04-10 21:30:35 +02:00
Andreas Eversberg f294261285 Fix filter of demodulator of received radio signal
The filter was way too low. (only half of the total bandwidth)
The missing (filtered) high frequency component caused noisy signal.
Let's see how this fix changes the quality of received FM sound.
2024-04-10 20:44:47 +02:00
Andreas Eversberg e1a7791561 Fix playing anouncements and tones with libmobile
This is a fixup of the new audio processing. Without this patch you will
hear only noisy tones.
2024-04-05 22:24:12 +02:00
Andreas Eversberg 6e2fd793ac Increase compiler warnings and fix them 2024-04-05 21:51:41 +02:00
Andreas Eversberg 470fc49341 C-Netz SIM: Fix entering card numbers with leading zeroes
Numbers for the SIM card can be entered with zeroes in the front. This
will not change numbers to octal. The Bosch OF 7 phone will not accept
numbers in the phone book with less than 4 digits, so it is essential to
allow entering numbers with zeroes in front.

Also state that in the documents.
2024-04-05 21:47:57 +02:00
Andreas Eversberg 17123595ec libserial: Allow 'mark' and 'space' parity setting 2024-04-05 10:39:42 +02:00
Andreas Eversberg a2ea0339e5 pocsag: Allow dialing function digit A..D (numeric, tone 1, tone 2, alpha) 2024-04-01 21:52:36 +02:00
Andreas Eversberg b8b250bd0a Fix command to list channel on various networks 2024-03-30 23:36:03 +01:00
Andreas Eversberg ba02b27a74 jollycom: Minor fix in command line help 2024-03-30 23:28:21 +01:00
Andreas Eversberg b51c9f26d1 Fixes in C-Netz "magnetic" card comments. 2024-03-30 23:28:20 +01:00
Andreas Eversberg d3a5d5c3c6 Improve image of IMTS 2024-03-30 23:28:17 +01:00
Andreas Eversberg b5579d1f16 IMTS dialer: Calculate the parity from all pulses, not just from pulses of one digit 2024-03-30 23:28:16 +01:00
Andreas Eversberg b613123291 Open sound device for capture or playback only, if full duplex is not required 2024-03-30 23:28:13 +01:00
Andreas Eversberg ce58b765f5 A different recording device may be specified for sound card access 2024-03-30 23:28:10 +01:00
Andreas Eversberg fabc849642 datenklo: Disable the display on exit 2024-03-30 23:28:07 +01:00
Andreas Eversberg a20637825a Audio rework, new jitter buffer
Jitter buffer is now based on packets, not on samples. The frames are
dejittered in received form. After reading from jitter buffer, they are
decoded in correct order. If a frame is missing, it is concealed by
repeating audio.
2024-03-30 23:28:05 +01:00
Andreas Eversberg e7efcee289 Fix buffer overflow when displaying measurements 2024-03-25 13:00:08 +01:00
Andreas Eversberg bc3967ccb6 Docs: Minor fix 2024-03-25 13:00:07 +01:00
Andreas Eversberg d30d662307 Avoid large buffer on stack, to prevent stack overflows
This affectes:
 * demodulation in libfsk
 * audio processing in libmobile
2024-03-25 13:00:06 +01:00
Andreas Eversberg a8becfeec5 IMTS/MTS: Add/fixed/improved channel numbers 2024-03-25 13:00:00 +01:00
Andreas Eversberg 05cc5e75c8 36c3 Mate Bottle Simulator
Note: This is a fun-application. Don't take it seriously!

Dial Eventphone extension 6283 (MATE) and feed audio from this
simulator into the phone.
2024-03-25 12:59:55 +01:00
Andreas Eversberg fd3fcddc07 FuVst: Add security code and card reader type to database 2024-02-18 16:23:31 +01:00
Andreas Eversberg 2dcf10b1b1 Add metering information from osmo-cc to B-Netz and C-Netz
Untested!
2024-02-18 16:23:31 +01:00
Andreas Eversberg da9b0a0f8d Add help about settings at location area overheade message 2024-02-18 16:23:30 +01:00
Andreas Eversberg 60c3e094ff Add "--no-config" option, to ignore existing default config file 2024-02-18 16:23:30 +01:00
Andreas Eversberg c844fcc1f6 If a mobile inscribes, show station ID on the console
If the console's station ID is not set, it will be automatically set
when a call is made from the mobile phone or when it performs
inscription to the network. (Only works for cellular networks with
inscription support.)
2024-02-18 16:23:30 +01:00
Andreas Eversberg 7e5663a709 Jollycom: Fix initial voice sample resampling 2024-02-18 16:23:30 +01:00
Andreas Eversberg 26c348411c Datenklo: Timers may only be scheduled or deleted in the main thread
Set flags to schedule timers in main thread.
Timers are: vtimer (datenklo.c), tx/rx timers (am791x.c)
2024-02-18 16:23:30 +01:00
Andreas Eversberg 3c2b5286c5 Disable rtprio by default and abort, if given prio is not allowed 2024-02-18 16:23:30 +01:00
Andreas Eversberg 3158c48365 Move from local to external osmo* libraries
src/libdebug -> libosmocore
src/libselect -> libosmocore
src/libtimer -> libosmocore
src/libosmocc -> libosmo-cc
src/libg711 -> libosmo-cc
2024-02-18 16:23:29 +01:00
Andreas Eversberg 6cd2c3e323 C-Netz-SIM: Store Jolly's phone number to phonebook entry 02
Also set version number to 3.
2024-01-04 17:58:30 +01:00
Andreas Eversberg 31d5667516 Fix usage of strncat 2024-01-04 17:58:05 +01:00
Andreas Eversberg 454086f04c Zeitansage: Remove useless FUSE library flags from Makefile.am 2023-12-13 23:58:49 +01:00
Andreas Eversberg d8950408cc G711: Fix bitorder of u-law codec
Tested with Grandstream
2023-11-27 17:17:52 +01:00
Andreas Eversberg d1b8ed8250 Add option to disable L16 codec (linear 16 bit PCM)
Yate uses wrong byte order, so the codec fails. Disable it if you have
problems with Yate or other defective peers.
2023-11-15 20:37:40 +01:00
Andreas Eversberg a9573aa5cb libosmocc: Support for telephone-events 2023-11-12 17:41:43 +01:00
Andreas Eversberg 865f280bb1 libosmocc: Flag codec as not accepted instead of removing it
This is required if multiple SDP responses are returned. We don't want
to remove a codec with with the first SDP response, which might get
accepted by the second SDP response. Instead we flag the codec as
negotiated or not negotiated.

When early media is received, different codecs may be accepted as when
we receive the actual answer.
2023-11-12 17:36:05 +01:00
Andreas Eversberg 39266802ef 5-tones: Minor fixes in command line help 2023-11-12 17:22:17 +01:00
Harald Welte 4fcea2c07d docs/install.html: git:// is long deprecated, use https:// instead 2023-11-07 17:26:02 +01:00
Vasyl Samoilov 2636b36c22 [NMT] fix UA UMC country code 2023-10-08 19:04:08 +03:00
Andreas Eversberg f4eba26d27 Golay: Add voice message support
A voice message can be sent with a wave file. Pagers that support voice
messages will listen to the wave file on the radio channel.

Use the following command to send a voice message:

	$ echo "1709829,v,<wave file>" > /tmp/golay_msg_send
2023-10-08 12:14:46 +02:00
Andreas Eversberg a949470ec3 AMPS: Add ESN manufacturer names
The ESN list "FCC Public Notice CL-97-70" is found at:
https://web.archive.org/web/19990223224835/http://www.fcc.gov/wtb/cellular/mnfrlst.html

When showing the ESN in logging, the manufacturer name is shown, if
found in the list.

Thanx to shadowcaster3, point to that list.
2023-09-10 21:54:50 +02:00
Andreas Eversberg 43dfab23e0 C-Netz-SIM: Store version number in phone book entry 01 as default. 2023-09-10 21:36:39 +02:00
Andreas Eversberg 4252ca1f82 C-Netz-SIM: Added delay before answering to messages
This delay is required, so that the card reader has enough time to
release the I/O line. The AEG OLYMPIA now works.
2023-08-27 20:28:43 +02:00
Andreas Eversberg abe449bd0e C-Netz: Added new service codes for AEG phone 2023-08-27 20:27:34 +02:00
Andreas Eversberg 38b9a4ac58 C-Netz: Updated sim card layout to support memory card emulation.
A jumper must be switched in order to emulate the reset input.

Also added new service codes to the silk mask.
2023-08-27 20:25:35 +02:00
Andreas Eversberg d09e9c95fd C-Netz: Make memory card emulation work with AEG OLYMPIA phone
Now it is ok to have the first clock pulse after reset. The software
does not care. At least there must be a clock after rising the reset.
2023-08-27 11:52:53 +02:00
Andreas Eversberg 20b5132ef7 Fix notch filter and add a test for it 2023-06-10 11:33:58 +02:00
Andreas Eversberg 963be6e2c5 Osmo-CC: Add R1 interface type 2023-06-10 11:33:14 +02:00
Andreas Eversberg 4c54be0f4d Add R1 debugging class 2023-06-10 11:32:48 +02:00
Andreas Eversberg 0e132f6167 Fix minor compiler warning in sdr.c 2023-05-25 21:56:48 +02:00
Andreas Eversberg 5816f8e7c0 libosmo-cc: Allow remote port change with RTP
In case of port translation, the different remote RTP port is adopted
for further transfer.

This happens, if remote peer uses NAT that changes source port also.
2023-03-26 17:06:37 +02:00
Andreas Eversberg 5c20a3e8b7 libosmo-cc: Fix critical bug in RTCP handling
Upon an RTCP read event, read from RTCP socket and not from RTP socket.
2023-03-26 12:03:53 +02:00
Andreas Eversberg 28a297f97d Generate compador table only once when the application starts 2023-03-18 19:49:56 +01:00
Andreas Eversberg bdecacc99e Changed logging of libosmocc to osmocom style 2023-01-22 18:28:34 +01:00
Andreas Eversberg 746c1fb4ff Add libph_socket (not used by any app now) 2023-01-21 15:15:57 +01:00
Andreas Eversberg 9f662d309f Add libselect to use select instead of polling all file descriptors 2023-01-21 15:15:52 +01:00
Andreas Eversberg ffaed13648 Make libdebug osmocore complatible in some places 2023-01-21 15:15:42 +01:00
Andreas Eversberg f4abbaf027 Make libtimer to be osmo_* compatible in some places 2023-01-21 15:15:39 +01:00
Andreas Eversberg 3bc3e67abb libosmo-cc: Fixed NULL-pointer bug 2022-12-16 12:43:20 +01:00
Andreas Eversberg fd3b4dae50 FSK modulator improvements
1. Phase is now changed proportional to the time of the bit change, if
   it happens somewhere between samples. The amount of phase change per
   bit is now the same for all bits, no matter how many samples
   currently lay inside this bit.

2. IIR filter is removed, because it causes distortions. A cosine shape
   is now used to transit between phase change of F0 to F1 and vice
   versa. This limits the spectrum. This filter is optional.
2022-12-16 12:43:19 +01:00
Andreas Eversberg 7609e98b8f Resampling filter can now be turned off
Only linear filtering remains when off.
2022-12-16 12:43:16 +01:00
Andreas Eversberg 3d18361d2e Removed obsolete hexdump function from DTMF decoder 2022-12-16 12:43:14 +01:00
Andreas Eversberg 5acdb94f10 Fixed a bug on datenklo's ioctrls 2022-12-16 12:43:11 +01:00
Andreas Eversberg aadfd50a0f Osmo-CC: Change UPDATE to MODIFY message
Naming it UPDATE was not a good idea.

Now this is renamed to MODIFY message, related to MNCC (GSM). It is used
to change media coding during a call. It allows new codec negotiation
using SDP protocol and/or changing RTP peer. Also useful for SIP.
2022-12-16 12:43:09 +01:00
Andreas Eversberg 2110a0f111 osmo-cc: Add private pointer to codecs 2022-11-24 21:16:43 +01:00
Andreas Eversberg 791a1d79a9 osmo-cc: Set session to NULL, if no codec matches
Applications will crash, due to use-after-free bug, if this is not done.
2022-11-24 21:15:47 +01:00
Andreas Eversberg 616a5e2820 DCF77: Add weather info decoding and coding 2022-11-24 21:08:02 +01:00
Andreas Eversberg 5ae64a2712 AMPS: Fix compilation 2022-11-07 18:18:04 +01:00
Andreas Eversberg 508197e9a8 TACS: Corrected TACS power levels in help description 2022-11-07 18:18:00 +01:00
Andreas Eversberg 1eed20420e AMPS: Fixed caller ID transmission 2022-10-30 17:23:25 +01:00
Andreas Eversberg a3835b001d AMPS: Minor fixes at DTX handling 2022-10-30 17:23:24 +01:00
Andreas Eversberg 8e67c3fda0 Golay/GSC paging support 2022-10-30 09:28:34 +01:00
Andreas Eversberg ed0f8694f7 dejitter: Added timeout for interpolation 2022-10-30 09:24:35 +01:00
Andreas Eversberg 825f395e09 Move AMPS/TACS/JTACS into one source directory 2022-10-23 16:56:46 +02:00
Andreas Eversberg 376cef4fa5 Osmo-CC: Add marker bit support 2022-10-23 16:56:40 +02:00
Andreas Eversberg 5684c0a7de Osmo-CC: Add UPDATE messages 2022-10-23 16:56:37 +02:00
Andreas Eversberg b60c844b4f DTMF: Now allows to give duration and pause for digit
Also the dtmf encoder will return less samples, if the digit(+pause)
ends, so that the caller call set the next digit to play seamlessly.

A reset function allows to clear the decoder states, to prevent glitches
when re-attaching to an interrupted stream.
2022-10-23 16:56:36 +02:00
Andreas Eversberg a756ba8fd9 libsample: Add another function for converting between int16_t and sample_t
Now we have speech level and 1mW (0 dBm) conversion functions
2022-10-23 16:56:32 +02:00
Andreas Eversberg 486d6b3780 JTACS (Japanese Total Access Communication System) works now
Tested with MT209 phone.
2022-10-23 16:56:30 +02:00
Andreas Eversberg 2b7efedc48 Refactoring jitter buffer
Features are:
 * Packet based buffer
 * Random in, first out
 * Adaptive delay compensation (voice)
 * Fixed delay (data, optionally MODEM/FAX)
 * Interpolation of missing frames
 * Any sample size
2022-10-23 16:56:27 +02:00
Andreas Eversberg 4fc92eba45 Improved libsamplerate to allow size calculations 2022-09-17 20:50:14 +02:00
Andreas Eversberg 1d77952717 Zeitansage: Removed glitches of some sounds 2022-09-17 20:47:28 +02:00
Andreas Eversberg a7a1ac7c5e TV: Add individual test image for selected color of color bar 2022-09-17 20:47:25 +02:00
Andreas Eversberg 26213d667a Fixed README 2022-09-15 07:23:37 +02:00
Andreas Eversberg b3e00b5085 POCSAG: Minor fixes. 2022-09-15 07:23:37 +02:00
Andreas Eversberg 4e669ecf79 AMPS: Caller ID Support
Support for sending caller ID for newer phones.
Currently does not work with older phones, they will abort.
2022-09-10 21:19:18 +02:00
Andreas Eversberg 1a0813069f NMT: Minor changes 2022-07-31 20:15:22 +02:00
Andreas Eversberg f906fcc708 Improved documents and layout for SIM and magnetic cards 2022-07-23 08:26:57 +02:00
Andreas Eversberg 89e3b89758 C-Netz: Improved RX speech quality and decoder debugging 2022-07-23 08:26:53 +02:00
Andreas Eversberg 059d4f25b1 FuVst: Removed unused scrambler dependency 2022-07-23 08:26:49 +02:00
Andreas Eversberg 8fd8205a6e C-Netz: Changed voice diversion back to 2.4 KHz
Most phones use this deviation. C5 does not for some unknown reason.
2022-07-23 08:26:48 +02:00
Andreas Eversberg b94443e57a Osmo-CC: Minor 'cause conversion' fix 2022-07-23 08:26:45 +02:00
Andreas Eversberg a34ffda422 Osmo-CC: Fixed routing in screen tables 2022-07-23 08:26:44 +02:00
Andreas Eversberg 5335795759 JTACS: Fixed channel allocation, but have no hardware to verify 2022-07-23 08:26:42 +02:00
Andreas Eversberg c6149ed3b4 NMT: Fixes to 'additional info' and added clock (time) support
- untested -
2022-07-23 08:26:30 +02:00
Andreas Eversberg f901eedd8e Osmo-CC: Fixed simple routing using screen option 2022-06-25 14:27:21 +02:00
Andreas Eversberg 5335a77e48 Osmo-CC: Option to remove remote peer, if given by application 2022-06-25 14:26:24 +02:00
Andreas Eversberg 334ead6908 Osmo-CC: Option to override interface name given by application 2022-06-25 14:23:16 +02:00
Andreas Eversberg c3f29a3302 Osmo-CC: Minor compiler warning fix 2022-06-25 14:22:04 +02:00
Andreas Eversberg f4aa9b79bb Osmo-CC: Minor compiler warning fixes 2022-06-19 06:51:49 +02:00
Andreas Eversberg 641ba0881f R2000: Show debugging for IDLE frames
Suppress repeated IDLE frame
2022-06-19 06:51:48 +02:00
Andreas Eversberg 181617aa81 NMT: Show debugging for IDLE frames
Suppress repeated IDLE frame
2022-06-19 06:51:45 +02:00
Andreas Eversberg 6f84314b93 AMPS: Show debugging for filler/system frames
Show them only once when FOCC is enabled.
2022-06-19 06:51:43 +02:00
Andreas Eversberg 253dfcc8bb C-Netz: Fix station list and selection 2022-06-19 06:51:40 +02:00
Andreas Eversberg 7cd3f85294 C-Netz: Show debugging for IDLE (LR and LMR) frames
Suppress repeated IDLE frame
2022-06-19 06:51:38 +02:00
Andreas Eversberg ec286f3d94 C-Netz: Add options to change 'Meldeaufruf' timer and counter. 2022-06-19 06:51:35 +02:00
Andreas Eversberg cb9c85adb5 C-Netz: Add capability of special tunnel base station (bahn-bs)
Totally useless, if you don't have a train phone - don't you?
2022-06-19 06:51:33 +02:00
Andreas Eversberg 26f4b3f711 C-Netz: Cleanup OgK slot allocation and polarity detection
Now you can select between 1 and 8 slots per frame.
2022-06-19 06:51:30 +02:00
Andreas Eversberg 4930da8e0c C-Netz: Add capability of non-standard OgK channel(s) 2022-06-19 06:51:28 +02:00
Andreas Eversberg 4758f16324 Implementation of DCF77 transmitter and receiver 2022-06-18 21:26:02 +02:00
Andreas Eversberg 8c382431b5 sdr: RF level is only provided when requested and available 2022-06-18 21:25:59 +02:00
Andreas Eversberg 1708d24d73 Alsa will indivate RF level with 0 dB 2022-06-18 21:25:58 +02:00
Andreas Eversberg df2b017472 debug: Show debug category together with debug level 2022-06-18 21:25:57 +02:00
Andreas Eversberg 98ed54124a Fixed glitch in sound buffer space calculation
Sometimes the sound buffer (ALSA) returns a few more samples than we
sent to it. In this case we return 0, which means that no data has
to be sent.
2022-06-10 20:22:10 +02:00
Andreas Eversberg ba4c095d09 Added UK0 and PH socket to libdebug 2022-05-29 17:07:28 +02:00
Andreas Eversberg fd81881922 ALSA: Add environment variable to delay input
This helps to avoid corrupted date in rx buffer.

Sorry: No more info, because I really don't know why this happens.
2022-05-29 17:06:23 +02:00
Andreas Eversberg e453c10169 Work on docs 2022-05-29 17:06:21 +02:00
336 changed files with 156729 additions and 138560 deletions

12
.gitignore vendored
View File

@ -19,8 +19,8 @@ compile
.deps
.libs
.dirstamp
src/liblogging/liblogging.a
src/liboptions/liboptions.a
src/libdebug/libdebug.a
src/libmobile/libmobile.a
src/libdisplay/libdisplay.a
src/libimage/libimage.a
@ -31,7 +31,6 @@ src/libjitter/libjitter.a
src/libsquelch/libsquelch.a
src/libhagelbarger/libhagelbarger.a
src/libdtmf/libdtmf.a
src/libtimer/libtimer.a
src/libsamplerate/libsamplerate.a
src/libscrambler/libscrambler.a
src/libemphasis/libemphasis.a
@ -48,8 +47,6 @@ src/libclipper/libclipper.a
src/libserial/libserial.a
src/libv27/libv27.a
src/libmtp/libmtp.a
src/libosmocc/libosmocc.a
src/libg711/libg711.a
src/libaaimage/libaaimage.a
src/anetz/libgermanton.a
src/anetz/anetz
@ -62,8 +59,8 @@ src/nmt/nmt
src/amps/libusatone.a
src/amps/libamps.a
src/amps/amps
src/tacs/tacs
src/jtacs/jtacs
src/amps/tacs
src/amps/jtacs
src/r2000/radiocom2000
src/imts/imts
src/imts/imts-dialer
@ -71,6 +68,7 @@ src/mpt1327/mpt1327
src/jolly/jollycom
src/eurosignal/eurosignal
src/pocsag/pocsag
src/golay/golay
src/fuenf/5-ton-folge
src/tv/osmotv
src/radio/osmoradio
@ -80,6 +78,8 @@ src/sim/cnetz_sim
src/magnetic/cnetz_magnetic
src/fuvst/fuvst
src/fuvst/fuvst_sniffer
src/dcf77/dcf77
src/mate/matesimulator
extra/cnetz_memory_card_generator
src/test/test_filter
src/test/test_sendevolumenregler

32
INSTALL
View File

@ -1,24 +1,30 @@
You need to have the following packages install:
* libosmocore, core libraries for various osmocom related projects
* libosmo-cc, call control interface library, to interconnect applications
* automake, gcc for compilation
* libasound2 for sound card support, which is what you need!
* libsoapysdr or libuhd (developer) to support SDR
* -> SoapySDR modules to support your SDR hardware
* libimagamagick version >= 7 (developer) optionally for TV image display
Install libosmocore:
See: https://osmocom.org/projects/libosmocore/wiki/Libosmocore
Generate "configure":
$ autoreconf -if
Run "configure":
$ ./configure
Build and install:
Install libosmo-cc:
$ git clone https://gitea.osmocom.org/osmocom/libosmo-cc.git
$ cd libosmocore/
$ autoreconf -i
$./configure
$ make
$ make install
s udo make install
$ sudo ldconfig -i
$ cd ..
Install osmocom-analog:
$ autoreconf -i
$ ./configure
$ make
$ sudo make install

14
README
View File

@ -24,11 +24,13 @@ Additionally the following communication services are implemented:
* TV Transmitter with test Images
* Radio transmitter / receiver
* Analog Modem Emulation (AM7911)
* Analog Modem Emulation 'Datenklo' (AM7911)
* German classic 'Zeitansage' (talking clock)
* POCSAG transmitter / receiver
* 5-Ton-Folge + Sirenensteuerung
* Golay/GSC transmitter / receiver
* DCF77 time signal transmitter and receiver with weather info
* C-Netz SIM emulator
* C-Netz magnetic card emulator
USE AT YOUR OWN RISK!
@ -67,10 +69,10 @@ providing memory cards to be programmed for older C-Netz phone.
Dieter Spaar providing TACS recordings to verify and debug TACS support.
Hans Wigger providing Radiocom 2000 recordings, to reverse-enigeer the standard,
which seems not to exist anymore...
Hans Wigger providing Radiocom 2000 recordings, to reverse-enigineer the
standard, which seems not to exist anymore...
Peter, Peter and Friedhelm and Stephan for providing documentation and hardware
Peter, Peter, Friedhelm and Stephan for providing documentation and hardware
for C-Netz Base Station and other C-Netz documents.
Carsten Wollesen for donating MPT1327 radios and programming tools.

View File

@ -1,7 +1,5 @@
dnl Process this file with autoconf to produce a configure script
AC_INIT([abcnetz],
m4_esyscmd([./git-version-gen .tarball-version]),
[jolly@eversberg.eu])
AC_INIT([abcnetz],[m4_esyscmd(./git-version-gen .tarball-version)],[jolly@eversberg.eu])
AM_INIT_AUTOMAKE([dist-bzip2])
@ -17,9 +15,6 @@ AC_PROG_CXX
AC_PROG_INSTALL
AC_PROG_RANLIB
dnl checks for header files
AC_HEADER_STDC
dnl Checks for typedefs, structures and compiler characteristics
AC_CANONICAL_HOST
@ -27,6 +22,9 @@ AC_CANONICAL_HOST
AC_CHECK_LIB([m], [main], [], [echo "Failed to find lib!" ; exit -1])
AC_CHECK_LIB([pthread], [main], [], [echo "Failed to find lib!" ; exit -1])
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.6.0)
PKG_CHECK_MODULES(LIBOSMOCC, libosmocc >= 2.0.0)
with_sdr=no
soapy_0_8_0_or_higher=
AC_ARG_WITH([alsa], [AS_HELP_STRING([--with-alsa], [compile with Alsa driver @<:@default=check@:>@]) ], [], [with_alsa="check"])
@ -60,9 +58,8 @@ AS_IF([test "x$with_alsa" != "xyes" -a "x$with_sdr" != "xyes"],[AC_MSG_NOTICE( W
SOAPY_CFLAGS="$soapy_0_8_0_or_higher"
AC_OUTPUT(
AC_CONFIG_FILES([src/liblogging/Makefile
src/liboptions/Makefile
src/libdebug/Makefile
src/libmobile/Makefile
src/libdisplay/Makefile
src/libimage/Makefile
@ -73,7 +70,6 @@ AC_OUTPUT(
src/libsquelch/Makefile
src/libhagelbarger/Makefile
src/libdtmf/Makefile
src/libtimer/Makefile
src/libsamplerate/Makefile
src/libscrambler/Makefile
src/libemphasis/Makefile
@ -90,22 +86,19 @@ AC_OUTPUT(
src/libserial/Makefile
src/libv27/Makefile
src/libmtp/Makefile
src/libosmocc/Makefile
src/libg711/Makefile
src/libaaimage/Makefile
src/anetz/Makefile
src/bnetz/Makefile
src/cnetz/Makefile
src/nmt/Makefile
src/amps/Makefile
src/tacs/Makefile
src/jtacs/Makefile
src/r2000/Makefile
src/imts/Makefile
src/mpt1327/Makefile
src/jolly/Makefile
src/eurosignal/Makefile
src/pocsag/Makefile
src/golay/Makefile
src/fuenf/Makefile
src/tv/Makefile
src/radio/Makefile
@ -114,9 +107,12 @@ AC_OUTPUT(
src/sim/Makefile
src/magnetic/Makefile
src/fuvst/Makefile
src/dcf77/Makefile
src/mate/Makefile
src/test/Makefile
src/Makefile
extra/Makefile
Makefile)
Makefile])
AC_OUTPUT

View File

@ -54,7 +54,7 @@ A caller must not know the location of the phone anymore to reach the right base
<li>Channel spacing: 10 KHz and optionally 12.5 KHz
<li>Voice modulation: FM
<li>Signaling modulation: carrier FSK
<li>Frequency deviation: 2.5 KHz (FSK); 4 KHz (Voice)
<li>Frequency deviation: 2.5 KHz (FSK); 2.4 or 4 KHz (Voice)
<li>Mobile station transmit power: 50 mW up to 15 Watts
<li>Base station transmit power: 25 Watts
<li>Features: Speech Compandor, Audio scrambling

View File

@ -129,8 +129,10 @@ Additional features:
<li><a href="magnetic.html">C-Netz Magnetic Card</a></li>
<li>Zeitansage (German talking clock)</li>
<li>C-Netz FuVSt (MSC to control a real base station)</li>
<li>POCSAG</li>
<li>POCSAG (paging system)</li>
<li>Golay / GSC (paging system)</li>
<li>5-Ton-Ruf (firefighter's pagers and siren control)</li>
<li>DCF77 The German longwave time signal transmitter/receiver</li>
</ul>
</td></tr></table></center>

View File

@ -66,7 +66,7 @@ Create a virtual machine with the following settings:
<ul>
<li>Create a virtual machine with Ubuntu (64-bit)
<li>Choose memory size of at least 2 GB
<li>Create a virtual hard drive with at least 10 GB
<li>Create a virtual hard drive with 25 GB
<li>Emulate sound with output and input
<li>Select USB 3.0 (xHCI) Controller
</ul>
@ -162,6 +162,18 @@ Installing osmocom-analog
</p>
<p>
You need two libraries, the first is "libosmocore". It is included with Ubuntu/Debian:
</p>
<pre>
# sudo apt install libosmocore-dev
</pre>
<p>
The next library is "libosmo-cc". It is not included with Ubuntu/Debian, so you need to install it from GIT.
Use GIT to clone latest source repository. First you need to install GIT.
</p>
@ -173,31 +185,83 @@ Use GIT to clone latest source repository. First you need to install GIT.
</pre>
<p>
Then you can clone osmocom-analog from <a href="git://git.osmocom.org/osmocom-analog">git://git.osmocom.org/osmocom-analog</a> in your home directory.
Then you can clone libosmo-cc from <a href="https://gitea.osmocom.org/cc/libosmo-cc">https://gitea.osmocom.org/cc/libosmo-cc</a> in your home directory.
</p>
<pre>
# cd ~
# git clone git://git.osmocom.org/osmocom-analog
Cloning into 'osmocom-analog'...
# git clone https://gitea.osmocom.org/cc/libosmo-cc
Cloning into 'libosmo-cc'...
...
</pre>
<p>
Before you can compile, you need to install <b>"autoconf"</b>, <b>"gcc"</b> and <b>"make"</b>.
Before you can compile, you need to install <b>"autoconf"</b>, <b>"gcc"</b> and <b>"make"</b>, and <b>"libtool"</b>.
</p>
<pre>
# sudo apt install autoconf
# sudo apt install gcc
# sudo apt install make
# sudo apt install autoconf gcc make libtool
</pre>
<p>
Change to the repository directory and run <b>"autoreconf -if"</b> once. This is only needed the first time compiling. It will generate the configure script.
</p>
<pre>
# cd libosmo-cc
# autoreconf -if
...
#
</pre>
<p>
Run configure script. It will generate the make files depending on your supported libraries.
</p>
<pre>
# ./configure
</pre>
<p>
Run <b>"make"</b> and <b>"make install"</b> to build and install osmocom-analog. Don't forget to run <b>"ldconfig"</b>, so you library database does know it.
</p>
<pre>
# make clean # always do this after you pulled from GIT server
# make
...
# sudo make install
...
# sudo ldconfig
# cd ..
</pre>
<p>
Use GIT to clone latest source repository. First you need to install GIT.
</p>
<p>
Then you can clone osmocom-analog from <a href="https://gitea.osmocom.org/cellular-infrastructure/osmocom-analog">https://gitea.osmocom.org/cellular-infrastructure/osmocom-analog</a> in your home directory.
</p>
<pre>
# cd ~
# git clone https://gitea.osmocom.org/cellular-infrastructure/osmocom-analog
Cloning into 'osmocom-analog'...
...
</pre>
<p>
@ -242,6 +306,10 @@ configure: Compiling with FUSE
</pre>
<p style="background-color: yellow;">
If you get something like "sytax error near unexpected token `ALSA,`", check, if pkg-config is installed. If you just installed it, run "autoreconf -if" again and then "./configure".
</p>
<p>
Run <b>"make"</b> and <b>"make install"</b> to build and install osmocom-analog.
</p>
@ -253,6 +321,7 @@ Run <b>"make"</b> and <b>"make install"</b> to build and install osmocom-analog.
...
# sudo make install
...
# cd ..
</pre>

BIN
docs/mag5.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

View File

@ -158,6 +158,12 @@ Be sure to print it without scaling!
<center><img src="mag1.jpg"/></center>
<p>
Also there is a KiCad version with the coil on PCB and space for battery holder:
</p>
<center><img src="mag5.jpg"/></center>
<p>
Leave the fuses of the ATTINY85 as it is shipped by default.
The fuses are set to use the internal 8 MHz clock with scaling to 1 MHz.
@ -283,6 +289,8 @@ The Security code must be a 16 bit unsigned integer, entered in decimal notation
BSA 44 Service Cards
</p>
<center><img src="mag3.jpg"/></center>
<p>
When inserting (simulating) a service card, a BSA44 phone will show "Wartungskarte" on its LC display.
Turn off the phone and then turn it on again, but leave card inserted and power connected.

View File

@ -293,7 +293,7 @@ Build Your Own SIM Card
You find the PCB drawings inside the "layout" directory of the git repository.
Be sure to print it without scaling!
Check if the printed size matches an ISO card.
Also there is the source files for the 'Eagle' layout program, if you like to change it.
Also there are the source files for the 'Eagle' and 'KiCad' layout programs.
</p>
<p>
@ -427,10 +427,12 @@ Turn on the phone and you will be asked for a PIN.
Enter the PIN 9991 to alter the first subscriber data.
Enter the PIN 9992 .. 9998 to alter second to eighth subscriber data.
The subscriber data is shown in the telephone directory and can be altered by changing the numbers in that directory.
Also the SIM software version is shown on entry 06 of the telephone directory, but it cannot be changed.
The Bosch OF 7 does not like to store numbers less than 3 digits. Put zeroes in front, if you want to store a value less than 1000.
</p>
<p>
The default subscriber data and where to change them in the telephone directory:
The default subscriber data and SIM version and where to change them in the telephone directory:
<br><br>
<table class="sim">
<tr><th>Entry</th><th>Name</th><th>Number</th></tr>
@ -439,9 +441,12 @@ The default subscriber data and where to change them in the telephone directory:
<tr><td>03</td><td>Kartenkennung</td><td>3</td></tr>
<tr><td>04</td><td>Sonderheitsschl.</td><td>0</td></tr>
<tr><td>05</td><td>Wartungsschl.</td><td>65535</td></tr>
<tr><td>06</td><td>SIM software version</td><td>xxx **</td></tr>
</table>
<br>
(*) When PIN 9991 was entered.
<br>
(**) This value represents the software version and cannot be changed.
</p>
@ -463,6 +468,8 @@ To program one of the following service cards, change the subscriber data to the
<tr><td>Philips Miniporty<br><a href="monitorkarte.pdf">extended cell monitor</a></td><td>-</td><td>-</td><td>-</td><td>900</td><td>2729</td></tr>
<tr><td>Philips Porty<br>service mode</td><td>0</td><td>0</td><td>0</td><td>2304</td><td>-</td></tr>
<tr><td>Philips Porty<br>cell monitor</td><td>-</td><td>-</td><td>-</td><td>898</td><td>-</td></tr>
<tr><td>AEG Telecar C<br>service mode</td><td>-</td><td>-</td><td>-</td><td>144 or 911</td><td>-</td></tr>
<tr><td>AEG Telecar C<br>cell monitor</td><td>-</td><td>-</td><td>-</td><td>899</td><td>-</td></tr>
</table>
</p>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 KiB

After

Width:  |  Height:  |  Size: 180 KiB

View File

@ -15,7 +15,7 @@ To get a list of all options, run the base station software (E.g bnetz) with no
</p>
<p class="toppic">
Sound interface
Sound interface using ALSA
</p>
<p>
@ -64,6 +64,69 @@ If you prefer card 2, device 0, add '-a hw:2,0' or '--audio-device hw:2,0' to th
</pre>
<p class="toppic">
Prevent Puleaudio from occupying a sound adapter
</p>
<p>
In some cases, pulseaudio occupies the sound interface, so that it cannot be used via ALSA API.
"Device or resource busy" will be reported by the application.
One way would be to stop pulseaudio daemon, if there is only a single audio device available.
If an extra sound device, like an USB stick shall be used, we can just block it for pulseaudio, using udev rule.
</p>
<p>
First, we need to check the device ID using lsusb (USB) or lspci (PCI):
</p>
<pre>
# lsusb
...
Bus 001 Device 030: ID 0bda:4937 Realtek Semiconductor Corp. Realtek Audio USB
...
</pre>
<p>
In this case there is an USB stick with vendor ID "0bda" and device ID "4937".
If nano is our favorite editor, we add a new udev rule (sudo or be root):
</p>
<pre>
# nano /etc/udev/rules.d/89-pulseaudio-ignore_0bda_4937.rules
</pre>
<p>
Choose any index (like 89), but be sure that it must be lower than any other pulseaudio rule, if there is any at all. Add some name that explains exactly what device is blocked, but feel free to user any other name.
</p>
<p>
Add this line to block the device shown above, but use the right IDs:
</p>
<pre>
ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="4937", ENV{PULSE_IGNORE}="1"
</pre>
<p>
When using PCI, you need to reboot.
When using USB, unplug it and then load the new rules before replugging it:
</p>
<pre>
udevadm control --reload-rules
</pre>
<p>
To verify that the rule works, check if the device is available using "pavucontrol".
Do that before and after, to see the effect.
</p>
<p class="toppic">
Basic level adjustment
</p>

View File

@ -7,6 +7,7 @@ cnetz_memory_card_generator_SOURCES = \
main.c
cnetz_memory_card_generator_LDADD = \
$(COMMON_LA) \
$(top_builddir)/src/libdebug/libdebug.a \
$(top_builddir)/src/liboptions/liboptions.a
$(top_builddir)/src/liboptions/liboptions.a \
$(top_builddir)/src/liblogging/liblogging.a \
$(LIBOSMOCORE_LIBS)

View File

@ -22,7 +22,7 @@
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <../src/libdebug/debug.h>
#include <../src/liblogging/logging.h>
#include <../src/liboptions/options.h>
int num_kanal = 1;
@ -196,7 +196,8 @@ int main(int argc, char *argv[])
int argi;
int i;
debuglevel = DEBUG_INFO;
loglevel = LOGL_INFO;
logging_init();
add_options();
@ -255,3 +256,5 @@ inval_sub:
return 0;
}
void osmo_cc_set_log_cat(void) {}

View File

@ -17,11 +17,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* NOTE: Reset must be an input pin, not the reset of the controller.
* The clock pulse must be detected during reset.
*/
#if defined(__AVR_ATtiny85__)
#define RST_PIN 2
#define CLK_PIN 3
#define DATA_PIN 4
#error UNTESTED!
#else
#define CLK_PIN 5
#define RST_PIN 6
@ -29,15 +31,14 @@
#endif
uint8_t card_data[] = {
/* Example: Service card for AEG OLYMPIA. */
0xff, 0xf7, 0x5c, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4b, 0x90,
0x5f, 0x25, 0x07, 0x0c, 0x00, 0x00, 0xfe, 0xfd,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x47, 0x38,
0x78, 0x28, 0x07, 0x8c, 0xc7, 0x03, 0xfe, 0xfd,
0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
};
volatile uint8_t *rst_in, *clk_in, *data_in, *data_out, *data_mode;
@ -70,6 +71,8 @@ void setup()
data_out = portOutputRegister(port);
data_in = portInputRegister(port);
*data_mode |= data_bit; /* output */
/* wait for reset */
while (!(*rst_in & rst_bit));
}
uint8_t byte_count;
@ -78,22 +81,14 @@ uint8_t bit_count;
void loop()
{
reset:
/* initial reset state */
byte_count = 0;
bit_count = 0;
/* wait for reset pulse */
while (!(*rst_in & rst_bit));
/* now we have reset, so we wait for clock pulse */
while (!(*clk_in & clk_bit)) {
/* if we lost reset, go to start */
if (!(*rst_in & rst_bit))
goto reset;
}
while ((*clk_in & clk_bit)) {
/* if we lost reset, go to start */
if (!(*rst_in & rst_bit))
goto reset;
}
*data_out |= data_bit; /* high */
/* now we have reset, so we wait for the first clock pulse */
while (!(*clk_in & clk_bit));
while ((*clk_in & clk_bit));
/* wait for reset to become low, if not already before first clock pulse (AEG phone) */
while ((*rst_in & rst_bit));
next_bit:

View File

@ -0,0 +1,87 @@
(module LOGO (layer F.Cu)
(at 0 0)
(fp_text reference "G***" (at 0 0) (layer F.SilkS) hide
(effects (font (thickness 0.3)))
)
(fp_text value "LOGO" (at 0.75 0) (layer F.SilkS) hide
(effects (font (thickness 0.3)))
)
(fp_poly (pts (xy 3.066152 -6.121191) (xy 3.428893 -6.120766) (xy 3.752319 -6.119859) (xy 4.038875 -6.118399) (xy 4.291009 -6.116313) (xy 4.511168 -6.113530) (xy 4.701799 -6.109980) (xy 4.865348 -6.105590)
(xy 5.004263 -6.100290) (xy 5.120991 -6.094008) (xy 5.217978 -6.086672) (xy 5.297671 -6.078211) (xy 5.362518 -6.068554) (xy 5.414965 -6.057629) (xy 5.457458 -6.045365) (xy 5.492446 -6.031691)
(xy 5.522375 -6.016535) (xy 5.549692 -5.999825) (xy 5.576844 -5.981491) (xy 5.606277 -5.961461) (xy 5.621560 -5.951464) (xy 5.802237 -5.806446) (xy 5.943182 -5.626144) (xy 6.008480 -5.504621)
(xy 6.081889 -5.348111) (xy 6.081889 5.065889) (xy 6.008480 5.222399) (xy 5.886481 5.426964) (xy 5.729099 5.591065) (xy 5.622219 5.668819) (xy 5.590776 5.689726) (xy 5.562762 5.708887)
(xy 5.535715 5.726375) (xy 5.507170 5.742266) (xy 5.474661 5.756634) (xy 5.435724 5.769553) (xy 5.387896 5.781099) (xy 5.328710 5.791346) (xy 5.255703 5.800368) (xy 5.166409 5.808240)
(xy 5.058365 5.815037) (xy 4.929106 5.820832) (xy 4.776167 5.825702) (xy 4.597084 5.829720) (xy 4.389392 5.832960) (xy 4.150626 5.835498) (xy 3.878322 5.837408) (xy 3.570016 5.838765)
(xy 3.223242 5.839643) (xy 2.835536 5.840116) (xy 2.404434 5.840260) (xy 1.927471 5.840149) (xy 1.402182 5.839857) (xy 0.826103 5.839459) (xy 0.196769 5.839030) (xy 0.001126 5.838908)
(xy -0.535567 5.838462) (xy -1.058045 5.837786) (xy -1.563427 5.836894) (xy -2.048833 5.835799) (xy -2.511382 5.834517) (xy -2.948193 5.833062) (xy -3.356385 5.831447) (xy -3.733077 5.829687)
(xy -4.075389 5.827796) (xy -4.380439 5.825788) (xy -4.645347 5.823678) (xy -4.867232 5.821480) (xy -5.043214 5.819207) (xy -5.170410 5.816875) (xy -5.245941 5.814497) (xy -5.266077 5.812913)
(xy -5.491258 5.740750) (xy -5.690423 5.620986) (xy -5.856268 5.458485) (xy -5.911083 5.383451) (xy -5.933608 5.350592) (xy -5.954232 5.321477) (xy -5.973038 5.293611) (xy -5.990111 5.264501)
(xy -6.005534 5.231654) (xy -6.019391 5.192575) (xy -6.031764 5.144771) (xy -6.042737 5.085749) (xy -6.052394 5.013016) (xy -6.060819 4.924076) (xy -6.068093 4.816438) (xy -6.074302 4.687607)
(xy -6.079529 4.535089) (xy -6.083857 4.356392) (xy -6.087369 4.149022) (xy -6.090149 3.910484) (xy -6.092281 3.638287) (xy -6.093847 3.329935) (xy -6.094932 2.982935) (xy -6.095619 2.594794)
(xy -6.095991 2.163018) (xy -6.096131 1.685114) (xy -6.096124 1.158588) (xy -6.096053 0.580947) (xy -6.096001 -0.050304) (xy -6.096000 -0.141111) (xy -6.096043 -0.779900) (xy -6.096116 -1.364739)
(xy -6.096137 -1.898120) (xy -6.096052 -2.256360) (xy -5.814193 -2.256360) (xy -5.814125 -1.757197) (xy -5.813966 -1.208271) (xy -5.813819 -0.607124) (xy -5.813777 -0.141111) (xy -5.813854 0.499116)
(xy -5.814015 1.085355) (xy -5.814159 1.620064) (xy -5.814184 2.105699) (xy -5.813989 2.544718) (xy -5.813470 2.939576) (xy -5.812526 3.292731) (xy -5.811055 3.606639) (xy -5.808956 3.883758)
(xy -5.806125 4.126544) (xy -5.802462 4.337453) (xy -5.797865 4.518944) (xy -5.792230 4.673472) (xy -5.785457 4.803495) (xy -5.777444 4.911469) (xy -5.768088 4.999850) (xy -5.757287 5.071097)
(xy -5.744940 5.127665) (xy -5.730944 5.172012) (xy -5.715199 5.206594) (xy -5.697600 5.233868) (xy -5.678048 5.256290) (xy -5.656439 5.276319) (xy -5.632672 5.296410) (xy -5.606645 5.319020)
(xy -5.586384 5.338304) (xy -5.561771 5.364561) (xy -5.541081 5.388626) (xy -5.521883 5.410597) (xy -5.501747 5.430569) (xy -5.478242 5.448637) (xy -5.448937 5.464897) (xy -5.411403 5.479446)
(xy -5.363209 5.492377) (xy -5.301924 5.503789) (xy -5.225118 5.513775) (xy -5.130361 5.522432) (xy -5.015222 5.529855) (xy -4.877271 5.536141) (xy -4.714078 5.541384) (xy -4.523212 5.545681)
(xy -4.302242 5.549127) (xy -4.048739 5.551819) (xy -3.760271 5.553851) (xy -3.434409 5.555319) (xy -3.068722 5.556320) (xy -2.660779 5.556948) (xy -2.208151 5.557300) (xy -1.708406 5.557471)
(xy -1.159115 5.557557) (xy -0.557847 5.557654) (xy -0.012178 5.557812) (xy 0.631245 5.558012) (xy 1.220601 5.558088) (xy 1.758268 5.558023) (xy 2.246624 5.557799) (xy 2.688045 5.557398)
(xy 3.084909 5.556803) (xy 3.439595 5.555995) (xy 3.754479 5.554958) (xy 4.031940 5.553673) (xy 4.274354 5.552123) (xy 4.484100 5.550290) (xy 4.663554 5.548156) (xy 4.815095 5.545704)
(xy 4.941100 5.542915) (xy 5.043947 5.539772) (xy 5.126012 5.536258) (xy 5.189674 5.532355) (xy 5.237311 5.528044) (xy 5.271300 5.523308) (xy 5.293600 5.518255) (xy 5.468036 5.437528)
(xy 5.619157 5.309399) (xy 5.722084 5.169645) (xy 5.799667 5.037667) (xy 5.799667 -5.319888) (xy 5.722084 -5.451866) (xy 5.654063 -5.548879) (xy 5.572372 -5.640625) (xy 5.538639 -5.671399)
(xy 5.514868 -5.692021) (xy 5.493943 -5.710917) (xy 5.473421 -5.728161) (xy 5.450859 -5.743829) (xy 5.423815 -5.757996) (xy 5.389844 -5.770737) (xy 5.346504 -5.782127) (xy 5.291352 -5.792243)
(xy 5.221946 -5.801158) (xy 5.135842 -5.808948) (xy 5.030596 -5.815689) (xy 4.903768 -5.821456) (xy 4.752912 -5.826324) (xy 4.575587 -5.830368) (xy 4.369349 -5.833663) (xy 4.131755 -5.836285)
(xy 3.860363 -5.838309) (xy 3.552729 -5.839811) (xy 3.206411 -5.840864) (xy 2.818965 -5.841546) (xy 2.387948 -5.841930) (xy 1.910918 -5.842093) (xy 1.385432 -5.842109) (xy 0.809046 -5.842054)
(xy 0.179318 -5.842003) (xy 0.000000 -5.842000) (xy -0.647201 -5.842068) (xy -1.240388 -5.842208) (xy -1.781990 -5.842324) (xy -2.274439 -5.842319) (xy -2.720163 -5.842096) (xy -3.121593 -5.841560)
(xy -3.481159 -5.840613) (xy -3.801291 -5.839160) (xy -4.084419 -5.837103) (xy -4.332972 -5.834346) (xy -4.549381 -5.830793) (xy -4.736077 -5.826347) (xy -4.895488 -5.820912) (xy -5.030045 -5.814390)
(xy -5.142178 -5.806687) (xy -5.234316 -5.797705) (xy -5.308891 -5.787347) (xy -5.368331 -5.775518) (xy -5.415068 -5.762121) (xy -5.451530 -5.747058) (xy -5.480148 -5.730235) (xy -5.503352 -5.711554)
(xy -5.523572 -5.690918) (xy -5.543238 -5.668232) (xy -5.564779 -5.643398) (xy -5.586748 -5.620162) (xy -5.614426 -5.594245) (xy -5.639774 -5.572614) (xy -5.662894 -5.552810) (xy -5.683888 -5.532378)
(xy -5.702857 -5.508859) (xy -5.719902 -5.479799) (xy -5.735127 -5.442739) (xy -5.748633 -5.395223) (xy -5.760521 -5.334795) (xy -5.770893 -5.258997) (xy -5.779852 -5.165373) (xy -5.787498 -5.051467)
(xy -5.793934 -4.914820) (xy -5.799262 -4.752978) (xy -5.803583 -4.563482) (xy -5.806999 -4.343877) (xy -5.809612 -4.091705) (xy -5.811524 -3.804509) (xy -5.812836 -3.479834) (xy -5.813650 -3.115222)
(xy -5.814069 -2.708216) (xy -5.814193 -2.256360) (xy -6.096052 -2.256360) (xy -6.096021 -2.382538) (xy -6.095685 -2.820485) (xy -6.095047 -3.214456) (xy -6.094021 -3.566944) (xy -6.092526 -3.880442)
(xy -6.090477 -4.157444) (xy -6.087792 -4.400443) (xy -6.084386 -4.611933) (xy -6.080176 -4.794408) (xy -6.075080 -4.950361) (xy -6.069013 -5.082285) (xy -6.061892 -5.192675) (xy -6.053634 -5.284023)
(xy -6.044156 -5.358823) (xy -6.033373 -5.419569) (xy -6.021202 -5.468754) (xy -6.007561 -5.508872) (xy -5.992366 -5.542416) (xy -5.975533 -5.571880) (xy -5.956978 -5.599757) (xy -5.936619 -5.628541)
(xy -5.914372 -5.660725) (xy -5.911207 -5.665485) (xy -5.776472 -5.825354) (xy -5.604536 -5.962390) (xy -5.418666 -6.059831) (xy -5.400964 -6.065986) (xy -5.378659 -6.071628) (xy -5.349305 -6.076783)
(xy -5.310456 -6.081478) (xy -5.259665 -6.085739) (xy -5.194485 -6.089592) (xy -5.112469 -6.093065) (xy -5.011172 -6.096183) (xy -4.888146 -6.098973) (xy -4.740946 -6.101462) (xy -4.567124 -6.103675)
(xy -4.364234 -6.105640) (xy -4.129829 -6.107382) (xy -3.861462 -6.108929) (xy -3.556688 -6.110306) (xy -3.213060 -6.111541) (xy -2.828131 -6.112659) (xy -2.399454 -6.113686) (xy -1.924583 -6.114651)
(xy -1.401071 -6.115578) (xy -0.826472 -6.116494) (xy -0.198339 -6.117426) (xy -0.072960 -6.117607) (xy 0.577063 -6.118577) (xy 1.173088 -6.119493) (xy 1.717563 -6.120284) (xy 2.212933 -6.120878)
(xy 2.661648 -6.121204) (xy 3.066152 -6.121191) )(layer F.SilkS) (width 0.010000)
)
(fp_poly (pts (xy 0.388056 -5.224861) (xy 0.926284 -5.151909) (xy 1.442169 -5.030009) (xy 1.931989 -4.860185) (xy 2.269161 -4.707442) (xy 2.385467 -4.646290) (xy 2.515386 -4.573424) (xy 2.649910 -4.494458)
(xy 2.780026 -4.415003) (xy 2.896725 -4.340672) (xy 2.990997 -4.277077) (xy 3.053830 -4.229830) (xy 3.076223 -4.204760) (xy 3.054679 -4.181883) (xy 2.996572 -4.134523) (xy 2.911693 -4.070406)
(xy 2.843389 -4.020972) (xy 2.588378 -3.819391) (xy 2.327603 -3.576761) (xy 2.072524 -3.305783) (xy 1.834598 -3.019161) (xy 1.625286 -2.729598) (xy 1.505020 -2.537285) (xy 1.380316 -2.322904)
(xy 1.142496 -2.442260) (xy 0.832858 -2.574342) (xy 0.519563 -2.658740) (xy 0.184960 -2.699984) (xy 0.127000 -2.702934) (xy -0.253898 -2.695011) (xy -0.612890 -2.637152) (xy -0.957530 -2.527568)
(xy -1.290385 -2.367282) (xy -1.454436 -2.258755) (xy -1.632699 -2.113583) (xy -1.812300 -1.944640) (xy -1.980365 -1.764801) (xy -2.124018 -1.586940) (xy -2.226171 -1.431496) (xy -2.390141 -1.085856)
(xy -2.501199 -0.729720) (xy -2.559954 -0.368118) (xy -2.567011 -0.006082) (xy -2.522977 0.351358) (xy -2.428460 0.699171) (xy -2.284065 1.032326) (xy -2.090401 1.345792) (xy -1.857529 1.624740)
(xy -1.581126 1.879192) (xy -1.286102 2.083481) (xy -0.963395 2.243070) (xy -0.657253 2.348609) (xy -0.558411 2.374336) (xy -0.462583 2.392205) (xy -0.355847 2.403564) (xy -0.224279 2.409764)
(xy -0.053956 2.412154) (xy 0.000000 2.412321) (xy 0.240604 2.407938) (xy 0.442234 2.391658) (xy 0.621727 2.360022) (xy 0.795921 2.309569) (xy 0.981650 2.236841) (xy 1.089842 2.188395)
(xy 1.296608 2.092863) (xy 1.385999 2.252932) (xy 1.674923 2.720001) (xy 1.994558 3.141962) (xy 2.343638 3.517301) (xy 2.702425 3.830121) (xy 2.796896 3.907276) (xy 2.869966 3.973160)
(xy 2.913014 4.019593) (xy 2.920358 4.036818) (xy 2.890949 4.061096) (xy 2.824331 4.106288) (xy 2.731997 4.164778) (xy 2.673266 4.200547) (xy 2.185366 4.462492) (xy 1.685599 4.669552)
(xy 1.174901 4.821510) (xy 0.654210 4.918150) (xy 0.124462 4.959255) (xy -0.413406 4.944609) (xy -0.507003 4.936422) (xy -1.021420 4.859022) (xy -1.521966 4.728701) (xy -2.004900 4.548065)
(xy -2.466482 4.319721) (xy -2.902970 4.046276) (xy -3.310625 3.730336) (xy -3.685705 3.374508) (xy -4.024470 2.981398) (xy -4.323179 2.553614) (xy -4.573789 2.102556) (xy -4.783501 1.612640)
(xy -4.939426 1.111284) (xy -5.042121 0.602317) (xy -5.092138 0.089570) (xy -5.090033 -0.423127) (xy -5.036358 -0.931945) (xy -4.931668 -1.433053) (xy -4.776518 -1.922622) (xy -4.571461 -2.396821)
(xy -4.317052 -2.851821) (xy -4.013845 -3.283791) (xy -3.749271 -3.596340) (xy -3.382862 -3.955827) (xy -2.981063 -4.275414) (xy -2.549031 -4.553070) (xy -2.091924 -4.786766) (xy -1.614902 -4.974470)
(xy -1.123122 -5.114152) (xy -0.621743 -5.203781) (xy -0.115923 -5.241328) (xy 0.388056 -5.224861) )(layer F.SilkS) (width 0.010000)
)
(fp_poly (pts (xy 3.871625 -3.467031) (xy 3.936780 -3.388271) (xy 4.011992 -3.292079) (xy 4.090056 -3.188391) (xy 4.163767 -3.087143) (xy 4.225919 -2.998272) (xy 4.269307 -2.931714) (xy 4.286725 -2.897407)
(xy 4.286321 -2.895141) (xy 4.256882 -2.877822) (xy 4.194588 -2.844925) (xy 4.158744 -2.826659) (xy 3.950167 -2.701112) (xy 3.732023 -2.533119) (xy 3.515113 -2.332872) (xy 3.310237 -2.110568)
(xy 3.128198 -1.876398) (xy 3.084732 -1.813015) (xy 2.876739 -1.451909) (xy 2.720513 -1.075306) (xy 2.615119 -0.687924) (xy 2.559623 -0.294477) (xy 2.553090 0.100317) (xy 2.594586 0.491743)
(xy 2.683176 0.875084) (xy 2.817926 1.245625) (xy 2.997901 1.598649) (xy 3.222167 1.929440) (xy 3.489789 2.233281) (xy 3.799833 2.505457) (xy 3.963878 2.623760) (xy 4.057511 2.688520)
(xy 4.130173 2.741777) (xy 4.171370 2.775690) (xy 4.176889 2.782893) (xy 4.159358 2.818264) (xy 4.112213 2.884836) (xy 4.043629 2.972966) (xy 3.961777 3.073010) (xy 3.874832 3.175325)
(xy 3.790967 3.270269) (xy 3.718356 3.348198) (xy 3.665171 3.399470) (xy 3.641219 3.414889) (xy 3.607900 3.400100) (xy 3.542981 3.361487) (xy 3.467445 3.312042) (xy 3.101674 3.029765)
(xy 2.770771 2.705500) (xy 2.477816 2.343901) (xy 2.225892 1.949622) (xy 2.018078 1.527317) (xy 1.857455 1.081641) (xy 1.773671 0.753207) (xy 1.740101 0.543137) (xy 1.718323 0.295285)
(xy 1.708507 0.027101) (xy 1.710821 -0.243961) (xy 1.725435 -0.500449) (xy 1.752517 -0.724913) (xy 1.758994 -0.762000) (xy 1.856772 -1.162283) (xy 1.999581 -1.564167) (xy 2.180636 -1.952063)
(xy 2.393154 -2.310382) (xy 2.496438 -2.456741) (xy 2.663059 -2.660010) (xy 2.863628 -2.872909) (xy 3.082493 -3.080547) (xy 3.304004 -3.268031) (xy 3.501693 -3.413279) (xy 3.765487 -3.589728)
(xy 3.871625 -3.467031) )(layer F.SilkS) (width 0.010000)
)
(fp_poly (pts (xy 4.708743 -2.093743) (xy 4.715703 -2.086271) (xy 4.732652 -2.047799) (xy 4.761169 -1.970683) (xy 4.797375 -1.866741) (xy 4.837394 -1.747787) (xy 4.877349 -1.625636) (xy 4.913364 -1.512106)
(xy 4.941562 -1.419010) (xy 4.958066 -1.358165) (xy 4.960324 -1.340693) (xy 4.934857 -1.323406) (xy 4.877100 -1.284341) (xy 4.826000 -1.249815) (xy 4.607190 -1.069768) (xy 4.431450 -0.857898)
(xy 4.300458 -0.620760) (xy 4.215893 -0.364908) (xy 4.179433 -0.096895) (xy 4.192756 0.176724) (xy 4.257542 0.449397) (xy 4.340061 0.647631) (xy 4.405102 0.752448) (xy 4.500803 0.875917)
(xy 4.613103 1.002252) (xy 4.727941 1.115669) (xy 4.831254 1.200380) (xy 4.834353 1.202538) (xy 4.913261 1.257086) (xy 4.810446 1.552466) (xy 4.751037 1.717503) (xy 4.699070 1.850800)
(xy 4.657218 1.946047) (xy 4.628156 1.996937) (xy 4.619134 2.003778) (xy 4.593095 1.989948) (xy 4.533783 1.954143) (xy 4.473461 1.916380) (xy 4.335424 1.815149) (xy 4.183457 1.681269)
(xy 4.033324 1.530091) (xy 3.900793 1.376964) (xy 3.848574 1.307997) (xy 3.668412 1.009181) (xy 3.537673 0.689345) (xy 3.456452 0.354911) (xy 3.424846 0.012297) (xy 3.442951 -0.332076)
(xy 3.510863 -0.671788) (xy 3.628678 -1.000421) (xy 3.796493 -1.311553) (xy 3.809056 -1.330900) (xy 3.897570 -1.452007) (xy 4.004725 -1.577172) (xy 4.123758 -1.700762) (xy 4.247908 -1.817143)
(xy 4.370412 -1.920682) (xy 4.484510 -2.005745) (xy 4.583439 -2.066698) (xy 4.660437 -2.097909) (xy 4.708743 -2.093743) )(layer F.SilkS) (width 0.010000)
)
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,75 @@
{
"board": {
"active_layer": 0,
"active_layer_preset": "All Layers",
"auto_track_width": false,
"hidden_nets": [],
"high_contrast_mode": 0,
"net_color_mode": 1,
"opacity": {
"pads": 1.0,
"tracks": 1.0,
"vias": 1.0,
"zones": 0.6
},
"ratsnest_display_mode": 0,
"selection_filter": {
"dimensions": true,
"footprints": true,
"graphics": true,
"keepouts": true,
"lockedItems": true,
"otherItems": true,
"pads": true,
"text": true,
"tracks": true,
"vias": true,
"zones": true
},
"visible_items": [
0,
1,
2,
3,
4,
5,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
32,
33,
34,
35,
36
],
"visible_layers": "fffffff_ffffffff",
"zone_display_mode": 0
},
"meta": {
"filename": "magnetkarte.kicad_prl",
"version": 3
},
"project": {
"files": []
}
}

View File

@ -0,0 +1,440 @@
{
"board": {
"design_settings": {
"defaults": {
"board_outline_line_width": 0.049999999999999996,
"copper_line_width": 0.19999999999999998,
"copper_text_italic": false,
"copper_text_size_h": 1.5,
"copper_text_size_v": 1.5,
"copper_text_thickness": 0.3,
"copper_text_upright": true,
"courtyard_line_width": 0.049999999999999996,
"dimension_precision": 4,
"dimension_units": 3,
"dimensions": {
"arrow_length": 1270000,
"extension_offset": 500000,
"keep_text_aligned": true,
"suppress_zeroes": false,
"text_position": 0,
"units_format": 1
},
"fab_line_width": 0.09999999999999999,
"fab_text_italic": false,
"fab_text_size_h": 1.0,
"fab_text_size_v": 1.0,
"fab_text_thickness": 0.15,
"fab_text_upright": false,
"other_line_width": 0.15,
"other_text_italic": false,
"other_text_size_h": 1.0,
"other_text_size_v": 1.0,
"other_text_thickness": 0.15,
"other_text_upright": true,
"pads": {
"drill": 0.762,
"height": 1.524,
"width": 1.524
},
"silk_line_width": 0.12,
"silk_text_italic": false,
"silk_text_size_h": 1.0,
"silk_text_size_v": 1.0,
"silk_text_thickness": 0.15,
"silk_text_upright": true,
"zones": {
"45_degree_only": false,
"min_clearance": 0.508
}
},
"diff_pair_dimensions": [
{
"gap": 0.0,
"via_gap": 0.0,
"width": 0.0
}
],
"drc_exclusions": [],
"meta": {
"version": 2
},
"rule_severities": {
"annular_width": "error",
"clearance": "error",
"copper_edge_clearance": "error",
"courtyards_overlap": "error",
"diff_pair_gap_out_of_range": "error",
"diff_pair_uncoupled_length_too_long": "error",
"drill_out_of_range": "error",
"duplicate_footprints": "warning",
"extra_footprint": "warning",
"footprint_type_mismatch": "error",
"hole_clearance": "error",
"hole_near_hole": "error",
"invalid_outline": "error",
"item_on_disabled_layer": "error",
"items_not_allowed": "error",
"length_out_of_range": "error",
"malformed_courtyard": "error",
"microvia_drill_out_of_range": "error",
"missing_courtyard": "ignore",
"missing_footprint": "warning",
"net_conflict": "warning",
"npth_inside_courtyard": "ignore",
"padstack": "error",
"pth_inside_courtyard": "ignore",
"shorting_items": "error",
"silk_over_copper": "warning",
"silk_overlap": "warning",
"skew_out_of_range": "error",
"through_hole_pad_without_hole": "error",
"too_many_vias": "error",
"track_dangling": "warning",
"track_width": "error",
"tracks_crossing": "error",
"unconnected_items": "error",
"unresolved_variable": "error",
"via_dangling": "warning",
"zone_has_empty_net": "error",
"zones_intersect": "error"
},
"rule_severitieslegacy_courtyards_overlap": true,
"rule_severitieslegacy_no_courtyard_defined": false,
"rules": {
"allow_blind_buried_vias": false,
"allow_microvias": false,
"max_error": 0.005,
"min_clearance": 0.0,
"min_copper_edge_clearance": 0.01,
"min_hole_clearance": 0.25,
"min_hole_to_hole": 0.25,
"min_microvia_diameter": 0.19999999999999998,
"min_microvia_drill": 0.09999999999999999,
"min_silk_clearance": 0.0,
"min_through_hole_diameter": 0.3,
"min_track_width": 0.19999999999999998,
"min_via_annular_width": 0.049999999999999996,
"min_via_diameter": 0.39999999999999997,
"solder_mask_clearance": 0.0,
"solder_mask_min_width": 0.0,
"solder_paste_clearance": 0.0,
"solder_paste_margin_ratio": -0.0,
"use_height_for_length_calcs": true
},
"track_widths": [
0.0,
0.25,
0.4,
0.6
],
"via_dimensions": [
{
"diameter": 0.0,
"drill": 0.0
}
],
"zones_allow_external_fillets": false,
"zones_use_no_outline": true
},
"layer_presets": []
},
"boards": [],
"cvpcb": {
"equivalence_files": []
},
"erc": {
"erc_exclusions": [],
"meta": {
"version": 0
},
"pin_map": [
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
1,
0,
1,
2
],
[
0,
1,
0,
0,
0,
0,
1,
1,
2,
1,
1,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
2
],
[
1,
1,
1,
1,
1,
0,
1,
1,
1,
1,
1,
2
],
[
0,
0,
0,
1,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
1,
2,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
0,
2,
1,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2
]
],
"rule_severities": {
"bus_definition_conflict": "error",
"bus_entry_needed": "error",
"bus_label_syntax": "error",
"bus_to_bus_conflict": "error",
"bus_to_net_conflict": "error",
"different_unit_footprint": "error",
"different_unit_net": "error",
"duplicate_reference": "error",
"duplicate_sheet_names": "error",
"extra_units": "error",
"global_label_dangling": "warning",
"hier_label_mismatch": "error",
"label_dangling": "error",
"lib_symbol_issues": "warning",
"multiple_net_names": "warning",
"net_not_bus_member": "warning",
"no_connect_connected": "warning",
"no_connect_dangling": "warning",
"pin_not_connected": "error",
"pin_not_driven": "error",
"pin_to_pin": "warning",
"power_pin_not_driven": "error",
"similar_labels": "warning",
"unannotated": "error",
"unit_value_mismatch": "error",
"unresolved_variable": "error",
"wire_dangling": "error"
}
},
"libraries": {
"pinned_footprint_libs": [],
"pinned_symbol_libs": []
},
"meta": {
"filename": "magnetkarte.kicad_pro",
"version": 1
},
"net_settings": {
"classes": [
{
"bus_width": 12.0,
"clearance": 0.2,
"diff_pair_gap": 0.25,
"diff_pair_via_gap": 0.25,
"diff_pair_width": 0.2,
"line_style": 0,
"microvia_diameter": 0.3,
"microvia_drill": 0.1,
"name": "Default",
"pcb_color": "rgba(0, 0, 0, 0.000)",
"schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 0.25,
"via_diameter": 0.8,
"via_drill": 0.4,
"wire_width": 6.0
}
],
"meta": {
"version": 2
},
"net_colors": null
},
"pcbnew": {
"last_paths": {
"gencad": "",
"idf": "",
"netlist": "",
"specctra_dsn": "",
"step": "",
"vrml": ""
},
"page_layout_descr_file": ""
},
"schematic": {
"annotate_start_num": 0,
"drawing": {
"default_line_thickness": 6.0,
"default_text_size": 50.0,
"field_names": [],
"intersheets_ref_own_page": false,
"intersheets_ref_prefix": "",
"intersheets_ref_short": false,
"intersheets_ref_show": false,
"intersheets_ref_suffix": "",
"junction_size_choice": 3,
"label_size_ratio": 0.25,
"pin_symbol_size": 0.0,
"text_offset_ratio": 0.08
},
"legacy_lib_dir": "",
"legacy_lib_list": [],
"meta": {
"version": 1
},
"net_format_name": "Pcbnew",
"ngspice": {
"fix_include_paths": true,
"fix_passive_vals": false,
"meta": {
"version": 0
},
"model_mode": 0,
"workbook_filename": ""
},
"page_layout_descr_file": "",
"plot_directory": "",
"spice_adjust_passive_values": false,
"spice_external_command": "spice \"%I\"",
"subpart_first_id": 65,
"subpart_id_separator": 0
},
"sheets": [
[
"b78e3980-fa91-4747-8504-806b364bf4af",
""
]
],
"text_variables": {}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,75 @@
{
"board": {
"active_layer": 0,
"active_layer_preset": "All Layers",
"auto_track_width": false,
"hidden_nets": [],
"high_contrast_mode": 0,
"net_color_mode": 1,
"opacity": {
"pads": 1.0,
"tracks": 1.0,
"vias": 1.0,
"zones": 0.6
},
"ratsnest_display_mode": 0,
"selection_filter": {
"dimensions": true,
"footprints": true,
"graphics": true,
"keepouts": true,
"lockedItems": true,
"otherItems": true,
"pads": true,
"text": true,
"tracks": true,
"vias": true,
"zones": true
},
"visible_items": [
0,
1,
2,
3,
4,
5,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
32,
33,
34,
35,
36
],
"visible_layers": "fffffff_ffffffff",
"zone_display_mode": 0
},
"meta": {
"filename": "simkarte.kicad_prl",
"version": 3
},
"project": {
"files": []
}
}

View File

@ -0,0 +1,436 @@
{
"board": {
"design_settings": {
"defaults": {
"board_outline_line_width": 0.049999999999999996,
"copper_line_width": 0.19999999999999998,
"copper_text_italic": false,
"copper_text_size_h": 1.5,
"copper_text_size_v": 1.5,
"copper_text_thickness": 0.3,
"copper_text_upright": false,
"courtyard_line_width": 0.049999999999999996,
"dimension_precision": 4,
"dimension_units": 3,
"dimensions": {
"arrow_length": 1270000,
"extension_offset": 500000,
"keep_text_aligned": true,
"suppress_zeroes": false,
"text_position": 0,
"units_format": 1
},
"fab_line_width": 0.09999999999999999,
"fab_text_italic": false,
"fab_text_size_h": 1.0,
"fab_text_size_v": 1.0,
"fab_text_thickness": 0.15,
"fab_text_upright": false,
"other_line_width": 0.09999999999999999,
"other_text_italic": false,
"other_text_size_h": 1.0,
"other_text_size_v": 1.0,
"other_text_thickness": 0.15,
"other_text_upright": false,
"pads": {
"drill": 0.762,
"height": 1.524,
"width": 1.524
},
"silk_line_width": 0.12,
"silk_text_italic": false,
"silk_text_size_h": 1.0,
"silk_text_size_v": 1.0,
"silk_text_thickness": 0.15,
"silk_text_upright": false,
"zones": {
"45_degree_only": false,
"min_clearance": 0.508
}
},
"diff_pair_dimensions": [
{
"gap": 0.0,
"via_gap": 0.0,
"width": 0.0
}
],
"drc_exclusions": [],
"meta": {
"filename": "board_design_settings.json",
"version": 2
},
"rule_severities": {
"annular_width": "error",
"clearance": "error",
"copper_edge_clearance": "error",
"courtyards_overlap": "error",
"diff_pair_gap_out_of_range": "error",
"diff_pair_uncoupled_length_too_long": "error",
"drill_out_of_range": "error",
"duplicate_footprints": "warning",
"extra_footprint": "warning",
"footprint_type_mismatch": "error",
"hole_clearance": "error",
"hole_near_hole": "error",
"invalid_outline": "error",
"item_on_disabled_layer": "error",
"items_not_allowed": "error",
"length_out_of_range": "error",
"malformed_courtyard": "error",
"microvia_drill_out_of_range": "error",
"missing_courtyard": "ignore",
"missing_footprint": "warning",
"net_conflict": "warning",
"npth_inside_courtyard": "ignore",
"padstack": "error",
"pth_inside_courtyard": "ignore",
"shorting_items": "error",
"silk_over_copper": "warning",
"silk_overlap": "warning",
"skew_out_of_range": "error",
"through_hole_pad_without_hole": "error",
"too_many_vias": "error",
"track_dangling": "warning",
"track_width": "error",
"tracks_crossing": "error",
"unconnected_items": "error",
"unresolved_variable": "error",
"via_dangling": "warning",
"zone_has_empty_net": "error",
"zones_intersect": "error"
},
"rule_severitieslegacy_courtyards_overlap": true,
"rule_severitieslegacy_no_courtyard_defined": false,
"rules": {
"allow_blind_buried_vias": false,
"allow_microvias": false,
"max_error": 0.005,
"min_clearance": 0.0,
"min_copper_edge_clearance": 0.024999999999999998,
"min_hole_clearance": 0.25,
"min_hole_to_hole": 0.25,
"min_microvia_diameter": 0.19999999999999998,
"min_microvia_drill": 0.09999999999999999,
"min_silk_clearance": 0.0,
"min_through_hole_diameter": 0.3,
"min_track_width": 0.19999999999999998,
"min_via_annular_width": 0.049999999999999996,
"min_via_diameter": 0.39999999999999997,
"use_height_for_length_calcs": true
},
"track_widths": [
0.0,
0.25,
0.4
],
"via_dimensions": [
{
"diameter": 0.0,
"drill": 0.0
}
],
"zones_allow_external_fillets": false,
"zones_use_no_outline": true
},
"layer_presets": []
},
"boards": [],
"cvpcb": {
"equivalence_files": []
},
"erc": {
"erc_exclusions": [],
"meta": {
"version": 0
},
"pin_map": [
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
1,
0,
1,
2
],
[
0,
1,
0,
0,
0,
0,
1,
1,
2,
1,
1,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
2
],
[
1,
1,
1,
1,
1,
0,
1,
1,
1,
1,
1,
2
],
[
0,
0,
0,
1,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
1,
2,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
0,
2,
1,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2
]
],
"rule_severities": {
"bus_definition_conflict": "error",
"bus_entry_needed": "error",
"bus_label_syntax": "error",
"bus_to_bus_conflict": "error",
"bus_to_net_conflict": "error",
"different_unit_footprint": "error",
"different_unit_net": "error",
"duplicate_reference": "error",
"duplicate_sheet_names": "error",
"extra_units": "error",
"global_label_dangling": "warning",
"hier_label_mismatch": "error",
"label_dangling": "error",
"lib_symbol_issues": "warning",
"multiple_net_names": "warning",
"net_not_bus_member": "warning",
"no_connect_connected": "warning",
"no_connect_dangling": "warning",
"pin_not_connected": "error",
"pin_not_driven": "error",
"pin_to_pin": "warning",
"power_pin_not_driven": "error",
"similar_labels": "warning",
"unannotated": "error",
"unit_value_mismatch": "error",
"unresolved_variable": "error",
"wire_dangling": "error"
}
},
"libraries": {
"pinned_footprint_libs": [],
"pinned_symbol_libs": []
},
"meta": {
"filename": "simkarte.kicad_pro",
"version": 1
},
"net_settings": {
"classes": [
{
"bus_width": 12.0,
"clearance": 0.2,
"diff_pair_gap": 0.25,
"diff_pair_via_gap": 0.25,
"diff_pair_width": 0.2,
"line_style": 0,
"microvia_diameter": 0.3,
"microvia_drill": 0.1,
"name": "Default",
"pcb_color": "rgba(0, 0, 0, 0.000)",
"schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 0.25,
"via_diameter": 0.8,
"via_drill": 0.4,
"wire_width": 6.0
}
],
"meta": {
"version": 2
},
"net_colors": null
},
"pcbnew": {
"last_paths": {
"gencad": "",
"idf": "",
"netlist": "",
"specctra_dsn": "",
"step": "",
"vrml": ""
},
"page_layout_descr_file": ""
},
"schematic": {
"annotate_start_num": 0,
"drawing": {
"default_line_thickness": 6.0,
"default_text_size": 50.0,
"field_names": [],
"intersheets_ref_own_page": false,
"intersheets_ref_prefix": "",
"intersheets_ref_short": false,
"intersheets_ref_show": false,
"intersheets_ref_suffix": "",
"junction_size_choice": 3,
"label_size_ratio": 0.25,
"pin_symbol_size": 0.0,
"text_offset_ratio": 0.08
},
"legacy_lib_dir": "",
"legacy_lib_list": [],
"meta": {
"version": 1
},
"net_format_name": "Pcbnew",
"ngspice": {
"fix_include_paths": true,
"fix_passive_vals": false,
"meta": {
"version": 0
},
"model_mode": 0,
"workbook_filename": ""
},
"page_layout_descr_file": "",
"plot_directory": "",
"spice_adjust_passive_values": false,
"spice_external_command": "spice \"%I\"",
"subpart_first_id": 65,
"subpart_id_separator": 0
},
"sheets": [
[
"d4e970ed-dbe6-470b-b0b4-94ae90c6a705",
""
]
],
"text_variables": {}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,52 @@
(module SIM-Pads (layer F.Cu) (tedit 62963936)
(fp_text reference REF** (at 0 0.5) (layer F.SilkS) hide
(effects (font (size 1 1) (thickness 0.15)))
)
(fp_text value SIM-Pads (at 0 -0.5) (layer F.Fab)
(effects (font (size 1 1) (thickness 0.15)))
)
(fp_line (start 85.6 3) (end 85.6 50.98) (layer B.SilkS) (width 0.12))
(fp_line (start 82.6 53.98) (end 3 53.98) (layer B.SilkS) (width 0.12))
(fp_line (start 3 0) (end 82.55 0) (layer B.SilkS) (width 0.12))
(fp_line (start 0 50.98) (end 0 3) (layer B.SilkS) (width 0.12))
(fp_line (start 30.957107 29.187107) (end 28.957107 31.187107) (layer B.SilkS) (width 0.12))
(fp_line (start 3 0) (end 82.55 0) (layer F.SilkS) (width 0.12))
(fp_line (start 85.6 3) (end 85.6 50.98) (layer F.SilkS) (width 0.12))
(fp_line (start 82.6 53.98) (end 3 53.98) (layer F.SilkS) (width 0.12))
(fp_line (start 0 50.98) (end 0 3) (layer F.SilkS) (width 0.12))
(fp_line (start 30.957107 29.187107) (end 28.957107 31.187107) (layer F.SilkS) (width 0.12))
(fp_line (start 31.25 28.48) (end 31.25 17.48) (layer F.SilkS) (width 0.12))
(fp_line (start 7.25 16.48) (end 30.25 16.48) (layer F.SilkS) (width 0.12))
(fp_line (start 6.25 30.48) (end 6.25 17.48) (layer F.SilkS) (width 0.12))
(fp_line (start 7.25 31.48) (end 28.25 31.48) (layer F.SilkS) (width 0.12))
(fp_line (start 7.25 16.48) (end 30.25 16.48) (layer B.SilkS) (width 0.12))
(fp_line (start 6.25 30.48) (end 6.25 17.48) (layer B.SilkS) (width 0.12))
(fp_line (start 7.25 31.48) (end 28.25 31.48) (layer B.SilkS) (width 0.12))
(fp_line (start 31.25 28.48) (end 31.25 17.48) (layer B.SilkS) (width 0.12))
(fp_arc (start 82.6 3) (end 82.6 0) (angle 90) (layer B.SilkS) (width 0.12))
(fp_arc (start 82.6 50.98) (end 85.6 50.98) (angle 90) (layer B.SilkS) (width 0.12))
(fp_arc (start 3 50.98) (end 3 53.98) (angle 90) (layer B.SilkS) (width 0.12))
(fp_arc (start 28.25 30.48) (end 28.25 31.48) (angle -45) (layer B.SilkS) (width 0.12))
(fp_arc (start 30.25 28.48) (end 31.25 28.48) (angle 45) (layer B.SilkS) (width 0.12))
(fp_arc (start 30.25 17.48) (end 30.25 16.48) (angle 90) (layer B.SilkS) (width 0.12))
(fp_arc (start 3 3) (end 0 3) (angle 90) (layer B.SilkS) (width 0.12))
(fp_arc (start 28.25 30.48) (end 28.25 31.48) (angle -45) (layer F.SilkS) (width 0.12))
(fp_arc (start 30.25 28.48) (end 31.25 28.48) (angle 45) (layer F.SilkS) (width 0.12))
(fp_arc (start 30.25 17.48) (end 30.25 16.48) (angle 90) (layer F.SilkS) (width 0.12))
(fp_arc (start 7.25 30.48) (end 7.25 31.48) (angle 90) (layer F.SilkS) (width 0.12))
(fp_arc (start 7.25 17.48) (end 6.25 17.48) (angle 90) (layer F.SilkS) (width 0.12))
(fp_arc (start 82.6 50.98) (end 85.6 50.98) (angle 90) (layer F.SilkS) (width 0.12))
(fp_arc (start 82.6 3) (end 82.6 0) (angle 90) (layer F.SilkS) (width 0.12))
(fp_arc (start 3 50.98) (end 3 53.98) (angle 90) (layer F.SilkS) (width 0.12))
(fp_arc (start 3 3) (end 0 3) (angle 90) (layer F.SilkS) (width 0.12))
(fp_arc (start 7.25 17.48) (end 6.25 17.48) (angle 90) (layer B.SilkS) (width 0.12))
(fp_arc (start 7.25 30.48) (end 7.25 31.48) (angle 90) (layer B.SilkS) (width 0.12))
(pad 8 smd rect (at 18.87 27.7) (size 2 1.7) (layers F.Cu F.Paste F.Mask))
(pad 7 smd rect (at 18.87 25.16) (size 2 1.7) (layers F.Cu F.Paste F.Mask))
(pad 6 smd rect (at 18.87 22.62) (size 2 1.7) (layers F.Cu F.Paste F.Mask))
(pad 5 smd rect (at 18.87 20.08) (size 2 1.7) (layers F.Cu F.Paste F.Mask))
(pad 4 smd rect (at 11.25 27.7) (size 2 1.7) (layers F.Cu F.Paste F.Mask))
(pad 3 smd rect (at 11.25 25.16) (size 2 1.7) (layers F.Cu F.Paste F.Mask))
(pad 2 smd rect (at 11.25 22.62) (size 2 1.7) (layers F.Cu F.Paste F.Mask))
(pad 1 smd rect (at 11.25 20.08) (size 2 1.7) (layers F.Cu F.Paste F.Mask))
)

View File

@ -0,0 +1,50 @@
(footprint "SO-8_falschrum" (version 20211014) (generator pcbnew)
(layer "F.Cu")
(tedit 5EA5315B)
(descr "SO, 8 Pin (https://www.ti.com/lit/ml/msop001a/msop001a.pdf), generated with kicad-footprint-generator ipc_gullwing_generator.py")
(tags "SO SO")
(attr smd)
(fp_text reference "REF**" (at 0 -4.05) (layer "F.SilkS")
(effects (font (size 1 1) (thickness 0.15)))
(tstamp e6d2e267-164d-4afc-8b48-cd1aff90b7d4)
)
(fp_text value "SO-8_falschrum" (at 0 4.05) (layer "F.Fab")
(effects (font (size 1 1) (thickness 0.15)))
(tstamp c06efada-401e-4dfe-b3d2-3a3e07849a0a)
)
(fp_text user "${REFERENCE}" (at 0 0) (layer "F.Fab")
(effects (font (size 1 1) (thickness 0.15)))
(tstamp f6b8865c-5ba6-45e6-a65d-a1b68be210e7)
)
(fp_line (start -2.76 -2.465) (end -4.45 -2.465) (layer "F.SilkS") (width 0.12) (tstamp 74239588-025d-4278-bb20-8aaa7c3084df))
(fp_line (start 2.76 3.21) (end 2.76 2.465) (layer "F.SilkS") (width 0.12) (tstamp 782bb1cd-d060-47ff-abe3-37addae7ab1b))
(fp_line (start 0 -3.21) (end -2.76 -3.21) (layer "F.SilkS") (width 0.12) (tstamp a37ee151-4fcc-4d66-943d-e5b1c2e17868))
(fp_line (start -2.76 3.21) (end -2.76 2.465) (layer "F.SilkS") (width 0.12) (tstamp af41f2a4-51e3-4dbb-b929-81c444ac7fff))
(fp_line (start 0 3.21) (end 2.76 3.21) (layer "F.SilkS") (width 0.12) (tstamp c79336f7-374b-471c-a2b2-c23ba36a59b5))
(fp_line (start 0 -3.21) (end 2.76 -3.21) (layer "F.SilkS") (width 0.12) (tstamp cf87a8a5-e65f-4d3a-8572-2d19d388ce69))
(fp_line (start 0 3.21) (end -2.76 3.21) (layer "F.SilkS") (width 0.12) (tstamp d48ee01a-e5c2-4b22-aaa6-a1cb107fbac3))
(fp_line (start -2.76 -3.21) (end -2.76 -2.465) (layer "F.SilkS") (width 0.12) (tstamp d861ecda-fd97-4619-9c2d-6c4f7c60cca0))
(fp_line (start 2.76 -3.21) (end 2.76 -2.465) (layer "F.SilkS") (width 0.12) (tstamp dc7ef0e4-bd3f-4bae-b16a-6091a2fbe1a5))
(fp_line (start 4.7 -3.35) (end -4.7 -3.35) (layer "F.CrtYd") (width 0.05) (tstamp 5f316919-0561-48cc-af6d-627207b632ec))
(fp_line (start -4.7 3.35) (end 4.7 3.35) (layer "F.CrtYd") (width 0.05) (tstamp 6020986c-655c-453e-a057-f214cc9d30ae))
(fp_line (start -4.7 -3.35) (end -4.7 3.35) (layer "F.CrtYd") (width 0.05) (tstamp 6794d844-873d-41de-8a23-157904a72b2b))
(fp_line (start 4.7 3.35) (end 4.7 -3.35) (layer "F.CrtYd") (width 0.05) (tstamp d7967734-f1e1-4546-a5ab-b7258f5f3f2a))
(fp_line (start -2.65 -2.1) (end -1.65 -3.1) (layer "F.Fab") (width 0.1) (tstamp 48790e43-f2fc-44b0-8322-5388cb8e0681))
(fp_line (start 2.65 3.1) (end -2.65 3.1) (layer "F.Fab") (width 0.1) (tstamp 7c60e013-b5db-4162-a3bc-3c3e55a92637))
(fp_line (start -1.65 -3.1) (end 2.65 -3.1) (layer "F.Fab") (width 0.1) (tstamp 89f17c59-8ae8-458d-9e98-a1d8017d430e))
(fp_line (start 2.65 -3.1) (end 2.65 3.1) (layer "F.Fab") (width 0.1) (tstamp d0cb6892-437f-41c0-a652-f027fe7a96eb))
(fp_line (start -2.65 3.1) (end -2.65 -2.1) (layer "F.Fab") (width 0.1) (tstamp ea99ab82-687a-410b-9f25-f99eecf53974))
(pad "1" smd roundrect (at 3.5 -1.905) (size 1.9 0.6) (layers "F.Cu" "F.Paste" "F.Mask") (roundrect_rratio 0.25) (tstamp 3ef16b5b-8b97-445d-864d-105eb1aa6c46))
(pad "2" smd roundrect (at 3.5 -0.635) (size 1.9 0.6) (layers "F.Cu" "F.Paste" "F.Mask") (roundrect_rratio 0.25) (tstamp e4871953-02b6-4389-a5ea-7cc4f8748acd))
(pad "3" smd roundrect (at 3.5 0.635) (size 1.9 0.6) (layers "F.Cu" "F.Paste" "F.Mask") (roundrect_rratio 0.25) (tstamp 9a059f78-4982-44b4-9c5e-072b9705c642))
(pad "4" smd roundrect (at 3.5 1.905) (size 1.9 0.6) (layers "F.Cu" "F.Paste" "F.Mask") (roundrect_rratio 0.25) (tstamp c02f2849-6a0e-4f4d-bf38-717a4b6fd135))
(pad "5" smd roundrect (at -3.5 1.905) (size 1.9 0.6) (layers "F.Cu" "F.Paste" "F.Mask") (roundrect_rratio 0.25) (tstamp b4cd1ee4-67da-4549-8e85-46e00c6d8f0b))
(pad "6" smd roundrect (at -3.5 0.635) (size 1.9 0.6) (layers "F.Cu" "F.Paste" "F.Mask") (roundrect_rratio 0.25) (tstamp 5515138e-0099-4ddf-8a64-f565476c169d))
(pad "7" smd roundrect (at -3.5 -0.635) (size 1.9 0.6) (layers "F.Cu" "F.Paste" "F.Mask") (roundrect_rratio 0.25) (tstamp 697f93e2-a0be-4cf3-b7ec-1bdeabd8a6ad))
(pad "8" smd roundrect (at -3.5 -1.905) (size 1.9 0.6) (layers "F.Cu" "F.Paste" "F.Mask") (roundrect_rratio 0.25) (tstamp 8018f35d-7a92-4135-8a83-0670bf6a5459))
(model "${KICAD6_3DMODEL_DIR}/Package_SO.3dshapes/SO-8_5.3x6.2mm_P1.27mm.wrl"
(offset (xyz 0 0 0))
(scale (xyz 1 1 1))
(rotate (xyz 0 0 0))
)
)

View File

@ -0,0 +1,87 @@
(module LOGO (layer F.Cu)
(at 0 0)
(fp_text reference "G***" (at 0 0) (layer F.SilkS) hide
(effects (font (thickness 0.3)))
)
(fp_text value "LOGO" (at 0.75 0) (layer F.SilkS) hide
(effects (font (thickness 0.3)))
)
(fp_poly (pts (xy 3.066152 -6.121191) (xy 3.428893 -6.120766) (xy 3.752319 -6.119859) (xy 4.038875 -6.118399) (xy 4.291009 -6.116313) (xy 4.511168 -6.113530) (xy 4.701799 -6.109980) (xy 4.865348 -6.105590)
(xy 5.004263 -6.100290) (xy 5.120991 -6.094008) (xy 5.217978 -6.086672) (xy 5.297671 -6.078211) (xy 5.362518 -6.068554) (xy 5.414965 -6.057629) (xy 5.457458 -6.045365) (xy 5.492446 -6.031691)
(xy 5.522375 -6.016535) (xy 5.549692 -5.999825) (xy 5.576844 -5.981491) (xy 5.606277 -5.961461) (xy 5.621560 -5.951464) (xy 5.802237 -5.806446) (xy 5.943182 -5.626144) (xy 6.008480 -5.504621)
(xy 6.081889 -5.348111) (xy 6.081889 5.065889) (xy 6.008480 5.222399) (xy 5.886481 5.426964) (xy 5.729099 5.591065) (xy 5.622219 5.668819) (xy 5.590776 5.689726) (xy 5.562762 5.708887)
(xy 5.535715 5.726375) (xy 5.507170 5.742266) (xy 5.474661 5.756634) (xy 5.435724 5.769553) (xy 5.387896 5.781099) (xy 5.328710 5.791346) (xy 5.255703 5.800368) (xy 5.166409 5.808240)
(xy 5.058365 5.815037) (xy 4.929106 5.820832) (xy 4.776167 5.825702) (xy 4.597084 5.829720) (xy 4.389392 5.832960) (xy 4.150626 5.835498) (xy 3.878322 5.837408) (xy 3.570016 5.838765)
(xy 3.223242 5.839643) (xy 2.835536 5.840116) (xy 2.404434 5.840260) (xy 1.927471 5.840149) (xy 1.402182 5.839857) (xy 0.826103 5.839459) (xy 0.196769 5.839030) (xy 0.001126 5.838908)
(xy -0.535567 5.838462) (xy -1.058045 5.837786) (xy -1.563427 5.836894) (xy -2.048833 5.835799) (xy -2.511382 5.834517) (xy -2.948193 5.833062) (xy -3.356385 5.831447) (xy -3.733077 5.829687)
(xy -4.075389 5.827796) (xy -4.380439 5.825788) (xy -4.645347 5.823678) (xy -4.867232 5.821480) (xy -5.043214 5.819207) (xy -5.170410 5.816875) (xy -5.245941 5.814497) (xy -5.266077 5.812913)
(xy -5.491258 5.740750) (xy -5.690423 5.620986) (xy -5.856268 5.458485) (xy -5.911083 5.383451) (xy -5.933608 5.350592) (xy -5.954232 5.321477) (xy -5.973038 5.293611) (xy -5.990111 5.264501)
(xy -6.005534 5.231654) (xy -6.019391 5.192575) (xy -6.031764 5.144771) (xy -6.042737 5.085749) (xy -6.052394 5.013016) (xy -6.060819 4.924076) (xy -6.068093 4.816438) (xy -6.074302 4.687607)
(xy -6.079529 4.535089) (xy -6.083857 4.356392) (xy -6.087369 4.149022) (xy -6.090149 3.910484) (xy -6.092281 3.638287) (xy -6.093847 3.329935) (xy -6.094932 2.982935) (xy -6.095619 2.594794)
(xy -6.095991 2.163018) (xy -6.096131 1.685114) (xy -6.096124 1.158588) (xy -6.096053 0.580947) (xy -6.096001 -0.050304) (xy -6.096000 -0.141111) (xy -6.096043 -0.779900) (xy -6.096116 -1.364739)
(xy -6.096137 -1.898120) (xy -6.096052 -2.256360) (xy -5.814193 -2.256360) (xy -5.814125 -1.757197) (xy -5.813966 -1.208271) (xy -5.813819 -0.607124) (xy -5.813777 -0.141111) (xy -5.813854 0.499116)
(xy -5.814015 1.085355) (xy -5.814159 1.620064) (xy -5.814184 2.105699) (xy -5.813989 2.544718) (xy -5.813470 2.939576) (xy -5.812526 3.292731) (xy -5.811055 3.606639) (xy -5.808956 3.883758)
(xy -5.806125 4.126544) (xy -5.802462 4.337453) (xy -5.797865 4.518944) (xy -5.792230 4.673472) (xy -5.785457 4.803495) (xy -5.777444 4.911469) (xy -5.768088 4.999850) (xy -5.757287 5.071097)
(xy -5.744940 5.127665) (xy -5.730944 5.172012) (xy -5.715199 5.206594) (xy -5.697600 5.233868) (xy -5.678048 5.256290) (xy -5.656439 5.276319) (xy -5.632672 5.296410) (xy -5.606645 5.319020)
(xy -5.586384 5.338304) (xy -5.561771 5.364561) (xy -5.541081 5.388626) (xy -5.521883 5.410597) (xy -5.501747 5.430569) (xy -5.478242 5.448637) (xy -5.448937 5.464897) (xy -5.411403 5.479446)
(xy -5.363209 5.492377) (xy -5.301924 5.503789) (xy -5.225118 5.513775) (xy -5.130361 5.522432) (xy -5.015222 5.529855) (xy -4.877271 5.536141) (xy -4.714078 5.541384) (xy -4.523212 5.545681)
(xy -4.302242 5.549127) (xy -4.048739 5.551819) (xy -3.760271 5.553851) (xy -3.434409 5.555319) (xy -3.068722 5.556320) (xy -2.660779 5.556948) (xy -2.208151 5.557300) (xy -1.708406 5.557471)
(xy -1.159115 5.557557) (xy -0.557847 5.557654) (xy -0.012178 5.557812) (xy 0.631245 5.558012) (xy 1.220601 5.558088) (xy 1.758268 5.558023) (xy 2.246624 5.557799) (xy 2.688045 5.557398)
(xy 3.084909 5.556803) (xy 3.439595 5.555995) (xy 3.754479 5.554958) (xy 4.031940 5.553673) (xy 4.274354 5.552123) (xy 4.484100 5.550290) (xy 4.663554 5.548156) (xy 4.815095 5.545704)
(xy 4.941100 5.542915) (xy 5.043947 5.539772) (xy 5.126012 5.536258) (xy 5.189674 5.532355) (xy 5.237311 5.528044) (xy 5.271300 5.523308) (xy 5.293600 5.518255) (xy 5.468036 5.437528)
(xy 5.619157 5.309399) (xy 5.722084 5.169645) (xy 5.799667 5.037667) (xy 5.799667 -5.319888) (xy 5.722084 -5.451866) (xy 5.654063 -5.548879) (xy 5.572372 -5.640625) (xy 5.538639 -5.671399)
(xy 5.514868 -5.692021) (xy 5.493943 -5.710917) (xy 5.473421 -5.728161) (xy 5.450859 -5.743829) (xy 5.423815 -5.757996) (xy 5.389844 -5.770737) (xy 5.346504 -5.782127) (xy 5.291352 -5.792243)
(xy 5.221946 -5.801158) (xy 5.135842 -5.808948) (xy 5.030596 -5.815689) (xy 4.903768 -5.821456) (xy 4.752912 -5.826324) (xy 4.575587 -5.830368) (xy 4.369349 -5.833663) (xy 4.131755 -5.836285)
(xy 3.860363 -5.838309) (xy 3.552729 -5.839811) (xy 3.206411 -5.840864) (xy 2.818965 -5.841546) (xy 2.387948 -5.841930) (xy 1.910918 -5.842093) (xy 1.385432 -5.842109) (xy 0.809046 -5.842054)
(xy 0.179318 -5.842003) (xy 0.000000 -5.842000) (xy -0.647201 -5.842068) (xy -1.240388 -5.842208) (xy -1.781990 -5.842324) (xy -2.274439 -5.842319) (xy -2.720163 -5.842096) (xy -3.121593 -5.841560)
(xy -3.481159 -5.840613) (xy -3.801291 -5.839160) (xy -4.084419 -5.837103) (xy -4.332972 -5.834346) (xy -4.549381 -5.830793) (xy -4.736077 -5.826347) (xy -4.895488 -5.820912) (xy -5.030045 -5.814390)
(xy -5.142178 -5.806687) (xy -5.234316 -5.797705) (xy -5.308891 -5.787347) (xy -5.368331 -5.775518) (xy -5.415068 -5.762121) (xy -5.451530 -5.747058) (xy -5.480148 -5.730235) (xy -5.503352 -5.711554)
(xy -5.523572 -5.690918) (xy -5.543238 -5.668232) (xy -5.564779 -5.643398) (xy -5.586748 -5.620162) (xy -5.614426 -5.594245) (xy -5.639774 -5.572614) (xy -5.662894 -5.552810) (xy -5.683888 -5.532378)
(xy -5.702857 -5.508859) (xy -5.719902 -5.479799) (xy -5.735127 -5.442739) (xy -5.748633 -5.395223) (xy -5.760521 -5.334795) (xy -5.770893 -5.258997) (xy -5.779852 -5.165373) (xy -5.787498 -5.051467)
(xy -5.793934 -4.914820) (xy -5.799262 -4.752978) (xy -5.803583 -4.563482) (xy -5.806999 -4.343877) (xy -5.809612 -4.091705) (xy -5.811524 -3.804509) (xy -5.812836 -3.479834) (xy -5.813650 -3.115222)
(xy -5.814069 -2.708216) (xy -5.814193 -2.256360) (xy -6.096052 -2.256360) (xy -6.096021 -2.382538) (xy -6.095685 -2.820485) (xy -6.095047 -3.214456) (xy -6.094021 -3.566944) (xy -6.092526 -3.880442)
(xy -6.090477 -4.157444) (xy -6.087792 -4.400443) (xy -6.084386 -4.611933) (xy -6.080176 -4.794408) (xy -6.075080 -4.950361) (xy -6.069013 -5.082285) (xy -6.061892 -5.192675) (xy -6.053634 -5.284023)
(xy -6.044156 -5.358823) (xy -6.033373 -5.419569) (xy -6.021202 -5.468754) (xy -6.007561 -5.508872) (xy -5.992366 -5.542416) (xy -5.975533 -5.571880) (xy -5.956978 -5.599757) (xy -5.936619 -5.628541)
(xy -5.914372 -5.660725) (xy -5.911207 -5.665485) (xy -5.776472 -5.825354) (xy -5.604536 -5.962390) (xy -5.418666 -6.059831) (xy -5.400964 -6.065986) (xy -5.378659 -6.071628) (xy -5.349305 -6.076783)
(xy -5.310456 -6.081478) (xy -5.259665 -6.085739) (xy -5.194485 -6.089592) (xy -5.112469 -6.093065) (xy -5.011172 -6.096183) (xy -4.888146 -6.098973) (xy -4.740946 -6.101462) (xy -4.567124 -6.103675)
(xy -4.364234 -6.105640) (xy -4.129829 -6.107382) (xy -3.861462 -6.108929) (xy -3.556688 -6.110306) (xy -3.213060 -6.111541) (xy -2.828131 -6.112659) (xy -2.399454 -6.113686) (xy -1.924583 -6.114651)
(xy -1.401071 -6.115578) (xy -0.826472 -6.116494) (xy -0.198339 -6.117426) (xy -0.072960 -6.117607) (xy 0.577063 -6.118577) (xy 1.173088 -6.119493) (xy 1.717563 -6.120284) (xy 2.212933 -6.120878)
(xy 2.661648 -6.121204) (xy 3.066152 -6.121191) )(layer F.SilkS) (width 0.010000)
)
(fp_poly (pts (xy 0.388056 -5.224861) (xy 0.926284 -5.151909) (xy 1.442169 -5.030009) (xy 1.931989 -4.860185) (xy 2.269161 -4.707442) (xy 2.385467 -4.646290) (xy 2.515386 -4.573424) (xy 2.649910 -4.494458)
(xy 2.780026 -4.415003) (xy 2.896725 -4.340672) (xy 2.990997 -4.277077) (xy 3.053830 -4.229830) (xy 3.076223 -4.204760) (xy 3.054679 -4.181883) (xy 2.996572 -4.134523) (xy 2.911693 -4.070406)
(xy 2.843389 -4.020972) (xy 2.588378 -3.819391) (xy 2.327603 -3.576761) (xy 2.072524 -3.305783) (xy 1.834598 -3.019161) (xy 1.625286 -2.729598) (xy 1.505020 -2.537285) (xy 1.380316 -2.322904)
(xy 1.142496 -2.442260) (xy 0.832858 -2.574342) (xy 0.519563 -2.658740) (xy 0.184960 -2.699984) (xy 0.127000 -2.702934) (xy -0.253898 -2.695011) (xy -0.612890 -2.637152) (xy -0.957530 -2.527568)
(xy -1.290385 -2.367282) (xy -1.454436 -2.258755) (xy -1.632699 -2.113583) (xy -1.812300 -1.944640) (xy -1.980365 -1.764801) (xy -2.124018 -1.586940) (xy -2.226171 -1.431496) (xy -2.390141 -1.085856)
(xy -2.501199 -0.729720) (xy -2.559954 -0.368118) (xy -2.567011 -0.006082) (xy -2.522977 0.351358) (xy -2.428460 0.699171) (xy -2.284065 1.032326) (xy -2.090401 1.345792) (xy -1.857529 1.624740)
(xy -1.581126 1.879192) (xy -1.286102 2.083481) (xy -0.963395 2.243070) (xy -0.657253 2.348609) (xy -0.558411 2.374336) (xy -0.462583 2.392205) (xy -0.355847 2.403564) (xy -0.224279 2.409764)
(xy -0.053956 2.412154) (xy 0.000000 2.412321) (xy 0.240604 2.407938) (xy 0.442234 2.391658) (xy 0.621727 2.360022) (xy 0.795921 2.309569) (xy 0.981650 2.236841) (xy 1.089842 2.188395)
(xy 1.296608 2.092863) (xy 1.385999 2.252932) (xy 1.674923 2.720001) (xy 1.994558 3.141962) (xy 2.343638 3.517301) (xy 2.702425 3.830121) (xy 2.796896 3.907276) (xy 2.869966 3.973160)
(xy 2.913014 4.019593) (xy 2.920358 4.036818) (xy 2.890949 4.061096) (xy 2.824331 4.106288) (xy 2.731997 4.164778) (xy 2.673266 4.200547) (xy 2.185366 4.462492) (xy 1.685599 4.669552)
(xy 1.174901 4.821510) (xy 0.654210 4.918150) (xy 0.124462 4.959255) (xy -0.413406 4.944609) (xy -0.507003 4.936422) (xy -1.021420 4.859022) (xy -1.521966 4.728701) (xy -2.004900 4.548065)
(xy -2.466482 4.319721) (xy -2.902970 4.046276) (xy -3.310625 3.730336) (xy -3.685705 3.374508) (xy -4.024470 2.981398) (xy -4.323179 2.553614) (xy -4.573789 2.102556) (xy -4.783501 1.612640)
(xy -4.939426 1.111284) (xy -5.042121 0.602317) (xy -5.092138 0.089570) (xy -5.090033 -0.423127) (xy -5.036358 -0.931945) (xy -4.931668 -1.433053) (xy -4.776518 -1.922622) (xy -4.571461 -2.396821)
(xy -4.317052 -2.851821) (xy -4.013845 -3.283791) (xy -3.749271 -3.596340) (xy -3.382862 -3.955827) (xy -2.981063 -4.275414) (xy -2.549031 -4.553070) (xy -2.091924 -4.786766) (xy -1.614902 -4.974470)
(xy -1.123122 -5.114152) (xy -0.621743 -5.203781) (xy -0.115923 -5.241328) (xy 0.388056 -5.224861) )(layer F.SilkS) (width 0.010000)
)
(fp_poly (pts (xy 3.871625 -3.467031) (xy 3.936780 -3.388271) (xy 4.011992 -3.292079) (xy 4.090056 -3.188391) (xy 4.163767 -3.087143) (xy 4.225919 -2.998272) (xy 4.269307 -2.931714) (xy 4.286725 -2.897407)
(xy 4.286321 -2.895141) (xy 4.256882 -2.877822) (xy 4.194588 -2.844925) (xy 4.158744 -2.826659) (xy 3.950167 -2.701112) (xy 3.732023 -2.533119) (xy 3.515113 -2.332872) (xy 3.310237 -2.110568)
(xy 3.128198 -1.876398) (xy 3.084732 -1.813015) (xy 2.876739 -1.451909) (xy 2.720513 -1.075306) (xy 2.615119 -0.687924) (xy 2.559623 -0.294477) (xy 2.553090 0.100317) (xy 2.594586 0.491743)
(xy 2.683176 0.875084) (xy 2.817926 1.245625) (xy 2.997901 1.598649) (xy 3.222167 1.929440) (xy 3.489789 2.233281) (xy 3.799833 2.505457) (xy 3.963878 2.623760) (xy 4.057511 2.688520)
(xy 4.130173 2.741777) (xy 4.171370 2.775690) (xy 4.176889 2.782893) (xy 4.159358 2.818264) (xy 4.112213 2.884836) (xy 4.043629 2.972966) (xy 3.961777 3.073010) (xy 3.874832 3.175325)
(xy 3.790967 3.270269) (xy 3.718356 3.348198) (xy 3.665171 3.399470) (xy 3.641219 3.414889) (xy 3.607900 3.400100) (xy 3.542981 3.361487) (xy 3.467445 3.312042) (xy 3.101674 3.029765)
(xy 2.770771 2.705500) (xy 2.477816 2.343901) (xy 2.225892 1.949622) (xy 2.018078 1.527317) (xy 1.857455 1.081641) (xy 1.773671 0.753207) (xy 1.740101 0.543137) (xy 1.718323 0.295285)
(xy 1.708507 0.027101) (xy 1.710821 -0.243961) (xy 1.725435 -0.500449) (xy 1.752517 -0.724913) (xy 1.758994 -0.762000) (xy 1.856772 -1.162283) (xy 1.999581 -1.564167) (xy 2.180636 -1.952063)
(xy 2.393154 -2.310382) (xy 2.496438 -2.456741) (xy 2.663059 -2.660010) (xy 2.863628 -2.872909) (xy 3.082493 -3.080547) (xy 3.304004 -3.268031) (xy 3.501693 -3.413279) (xy 3.765487 -3.589728)
(xy 3.871625 -3.467031) )(layer F.SilkS) (width 0.010000)
)
(fp_poly (pts (xy 4.708743 -2.093743) (xy 4.715703 -2.086271) (xy 4.732652 -2.047799) (xy 4.761169 -1.970683) (xy 4.797375 -1.866741) (xy 4.837394 -1.747787) (xy 4.877349 -1.625636) (xy 4.913364 -1.512106)
(xy 4.941562 -1.419010) (xy 4.958066 -1.358165) (xy 4.960324 -1.340693) (xy 4.934857 -1.323406) (xy 4.877100 -1.284341) (xy 4.826000 -1.249815) (xy 4.607190 -1.069768) (xy 4.431450 -0.857898)
(xy 4.300458 -0.620760) (xy 4.215893 -0.364908) (xy 4.179433 -0.096895) (xy 4.192756 0.176724) (xy 4.257542 0.449397) (xy 4.340061 0.647631) (xy 4.405102 0.752448) (xy 4.500803 0.875917)
(xy 4.613103 1.002252) (xy 4.727941 1.115669) (xy 4.831254 1.200380) (xy 4.834353 1.202538) (xy 4.913261 1.257086) (xy 4.810446 1.552466) (xy 4.751037 1.717503) (xy 4.699070 1.850800)
(xy 4.657218 1.946047) (xy 4.628156 1.996937) (xy 4.619134 2.003778) (xy 4.593095 1.989948) (xy 4.533783 1.954143) (xy 4.473461 1.916380) (xy 4.335424 1.815149) (xy 4.183457 1.681269)
(xy 4.033324 1.530091) (xy 3.900793 1.376964) (xy 3.848574 1.307997) (xy 3.668412 1.009181) (xy 3.537673 0.689345) (xy 3.456452 0.354911) (xy 3.424846 0.012297) (xy 3.442951 -0.332076)
(xy 3.510863 -0.671788) (xy 3.628678 -1.000421) (xy 3.796493 -1.311553) (xy 3.809056 -1.330900) (xy 3.897570 -1.452007) (xy 4.004725 -1.577172) (xy 4.123758 -1.700762) (xy 4.247908 -1.817143)
(xy 4.370412 -1.920682) (xy 4.484510 -2.005745) (xy 4.583439 -2.066698) (xy 4.660437 -2.097909) (xy 4.708743 -2.093743) )(layer F.SilkS) (width 0.010000)
)
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,9 @@
(module tp_for_sim (layer F.Cu) (tedit 62960959)
(fp_text reference REF** (at 0 0.5) (layer F.SilkS)
(effects (font (size 1 1) (thickness 0.15)))
)
(fp_text value tp_for_sim (at 0 -0.5) (layer F.Fab)
(effects (font (size 1 1) (thickness 0.15)))
)
(pad 1 smd roundrect (at 0 0) (size 1 1) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25))
)

View File

@ -1,8 +1,8 @@
AUTOMAKE_OPTIONS = foreign
SUBDIRS = \
liblogging \
liboptions \
libdebug \
libmobile \
libdisplay \
libsample \
@ -14,7 +14,6 @@ SUBDIRS = \
libsquelch \
libhagelbarger \
libdtmf \
libtimer \
libsamplerate \
libscrambler \
libemphasis \
@ -28,8 +27,6 @@ SUBDIRS = \
libserial \
libv27 \
libmtp \
libosmocc \
libg711 \
libaaimage
if HAVE_ALSA
@ -48,21 +45,22 @@ SUBDIRS += \
cnetz \
nmt \
amps \
tacs \
jtacs \
r2000 \
imts \
mpt1327 \
jolly \
eurosignal \
pocsag \
golay \
fuenf \
tv \
radio \
zeitansage \
sim \
magnetic \
fuvst
fuvst \
dcf77 \
mate
if HAVE_ALSA
if HAVE_FUSE

View File

@ -1,51 +1,51 @@
AM_CPPFLAGS = -Wall -Wextra -g $(all_includes)
AM_CPPFLAGS = -Wall -Wextra -Wmissing-prototypes -g $(all_includes)
bin_PROGRAMS = \
amps
amps tacs jtacs
noinst_LIBRARIES = libamps.a libusatone.a
libamps_a_SOURCES = \
amps_tacs_main.c \
main_common.c \
amps.c \
transaction.c \
frame.c \
dsp.c \
sysinfo.c
sysinfo.c \
esn.c
libusatone_a_SOURCES = \
tones.c \
noanswer.c \
outoforder.c \
invalidnumber.c \
congestion.c
usa_tones.c \
usa_noanswer.c \
usa_outoforder.c \
usa_invalidnumber.c \
usa_congestion.c
amps_SOURCES = \
stations.c \
image.c \
main.c
amps_stations.c \
amps_image.c \
amps_main.c
amps_LDADD = \
$(COMMON_LA) \
libamps.a \
libusatone.a \
$(top_builddir)/src/liboptions/liboptions.a \
$(top_builddir)/src/libdebug/libdebug.a \
$(top_builddir)/src/libmobile/libmobile.a \
$(top_builddir)/src/libosmocc/libosmocc.a \
$(top_builddir)/src/libdisplay/libdisplay.a \
$(top_builddir)/src/libcompandor/libcompandor.a \
$(top_builddir)/src/libgoertzel/libgoertzel.a \
$(top_builddir)/src/libjitter/libjitter.a \
$(top_builddir)/src/libtimer/libtimer.a \
$(top_builddir)/src/libsamplerate/libsamplerate.a \
$(top_builddir)/src/libemphasis/libemphasis.a \
$(top_builddir)/src/libfm/libfm.a \
$(top_builddir)/src/libfilter/libfilter.a \
$(top_builddir)/src/libwave/libwave.a \
$(top_builddir)/src/libsample/libsample.a \
$(top_builddir)/src/libg711/libg711.a \
$(top_builddir)/src/libaaimage/libaaimage.a \
$(top_builddir)/src/liblogging/liblogging.a \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOCC_LIBS) \
-lm
if HAVE_ALSA
@ -63,3 +63,88 @@ amps_LDADD += \
$(SOAPY_LIBS)
endif
tacs_SOURCES = \
tacs_tones.c \
tacs_outoforder.c \
tacs_stations.c \
tacs_image.c \
tacs_main.c
tacs_LDADD = \
$(COMMON_LA) \
libamps.a \
$(top_builddir)/src/liboptions/liboptions.a \
$(top_builddir)/src/libmobile/libmobile.a \
$(top_builddir)/src/libdisplay/libdisplay.a \
$(top_builddir)/src/libcompandor/libcompandor.a \
$(top_builddir)/src/libgoertzel/libgoertzel.a \
$(top_builddir)/src/libjitter/libjitter.a \
$(top_builddir)/src/libsamplerate/libsamplerate.a \
$(top_builddir)/src/libemphasis/libemphasis.a \
$(top_builddir)/src/libfm/libfm.a \
$(top_builddir)/src/libfilter/libfilter.a \
$(top_builddir)/src/libwave/libwave.a \
$(top_builddir)/src/libsample/libsample.a \
$(top_builddir)/src/libaaimage/libaaimage.a \
$(top_builddir)/src/liblogging/liblogging.a \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOCC_LIBS) \
-lm
if HAVE_ALSA
tacs_LDADD += \
$(top_builddir)/src/libsound/libsound.a \
$(ALSA_LIBS)
endif
if HAVE_SDR
tacs_LDADD += \
$(top_builddir)/src/libsdr/libsdr.a \
$(top_builddir)/src/libam/libam.a \
$(top_builddir)/src/libfft/libfft.a \
$(UHD_LIBS) \
$(SOAPY_LIBS)
endif
jtacs_SOURCES = \
jtacs_tones.c \
jtacs_stations.c \
jtacs_image.c \
jtacs_main.c
jtacs_LDADD = \
$(COMMON_LA) \
libamps.a \
$(top_builddir)/src/liboptions/liboptions.a \
$(top_builddir)/src/libmobile/libmobile.a \
$(top_builddir)/src/libdisplay/libdisplay.a \
$(top_builddir)/src/libcompandor/libcompandor.a \
$(top_builddir)/src/libgoertzel/libgoertzel.a \
$(top_builddir)/src/libjitter/libjitter.a \
$(top_builddir)/src/libsamplerate/libsamplerate.a \
$(top_builddir)/src/libemphasis/libemphasis.a \
$(top_builddir)/src/libfm/libfm.a \
$(top_builddir)/src/libfilter/libfilter.a \
$(top_builddir)/src/libwave/libwave.a \
$(top_builddir)/src/libsample/libsample.a \
$(top_builddir)/src/libaaimage/libaaimage.a \
$(top_builddir)/src/liblogging/liblogging.a \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOCC_LIBS) \
-lm
if HAVE_ALSA
jtacs_LDADD += \
$(top_builddir)/src/libsound/libsound.a \
$(ALSA_LIBS)
endif
if HAVE_SDR
jtacs_LDADD += \
$(top_builddir)/src/libsdr/libsdr.a \
$(top_builddir)/src/libam/libam.a \
$(top_builddir)/src/libfft/libfft.a \
$(UHD_LIBS) \
$(SOAPY_LIBS)
endif

View File

@ -43,26 +43,30 @@
#include <string.h>
#include <errno.h>
#include "../libsample/sample.h"
#include "../libdebug/debug.h"
#include "../liblogging/logging.h"
#include "../libmobile/call.h"
#include "../libmobile/cause.h"
#include "../libosmocc/message.h"
#include "../libmobile/console.h"
#include <osmocom/cc/message.h>
#include "amps.h"
#include "dsp.h"
#include "frame.h"
#include "stations.h"
#include "esn.h"
#include "main.h"
/* Uncomment this to test SAT via loopback */
//#define DEBUG_VC
#define SAT_TO1 5.0 /* 5 sec to detect after setup */
#define SAT_TO2 5.0 /* 5 sec lost until abort (specs say 5) */
#define PAGE_TRIES 2 /* how many times to page the phone */
#define PAGE_TO1 8.0 /* max time to wait for paging reply */
#define PAGE_TO2 4.0 /* max time to wait for last paging reply */
#define ALERT_TO 60.0 /* max time to wait for answer */
#define RELEASE_TIMER 5.0 /* max time to send release messages */
#define SAT_TO1 5,0 /* 5 sec to detect after setup */
#define SAT_TO2 5,0 /* 5 sec lost until abort (specs say 5) */
#define PAGE_TRIES 2 /* how many times to page the phone */
#define PAGE_TO1 8,0 /* max time to wait for paging reply */
#define PAGE_TO2 4,0 /* max time to wait for last paging reply */
#define ALERT_TRIES 3 /* how many times to alert the phone */
#define ALERT_TO 0,600000 /* max time to wait for alert confirm */
#define ANSWER_TO 60,0 /* max time to wait for answer */
#define RELEASE_TIMER 5,0 /* max time to send release messages */
/* Convert channel number to frequency number of base station.
Set 'uplink' to 1 to get frequency of mobile station. */
@ -71,6 +75,7 @@ double amps_channel2freq(int channel, int uplink)
double freq;
if (!tacs) {
/* AMPS */
if (uplink == 2)
return -45.000 * 1e6;
@ -86,6 +91,7 @@ double amps_channel2freq(int channel, int uplink)
if (uplink)
freq -= 45.000;
} else if (!jtacs) {
/* TACS */
if (uplink == 2)
return -45.000 * 1e6;
@ -98,14 +104,23 @@ double amps_channel2freq(int channel, int uplink)
if (uplink)
freq -= 45.000;
} else {
/* JTACS */
/* see "ARIB_STD-T64-C.S0057-0v1.0.pdf" */
if (uplink == 2)
return -55.000 * 1e6;
return 55.000 * 1e6;
/* 799 channels */
if (channel < 1 || channel > 799)
if (channel >= 1 && channel <= 799)
freq = 860.0125 + (channel - 1) * 0.0125;
else if (channel >= 801 && channel <= 1039)
freq = 843.0125 + (channel - 801) * 0.0125;
else if (channel >= 1041 && channel <= 1199)
freq = 832.0125 + (channel - 1041) * 0.0125;
else if (channel >= 1201 && channel <= 1600)
freq = 838.0125 + (channel - 1201) * 0.0125;
else
return 0;
freq = 860.0125 + (channel - 1) * 0.025;
if (uplink)
freq += 55.000;
@ -117,13 +132,19 @@ double amps_channel2freq(int channel, int uplink)
enum amps_chan_type amps_channel2type(int channel)
{
if (!tacs) {
/* AMPS */
if (channel >= 313 && channel <= 354)
return CHAN_TYPE_CC;
} else {
} else if (!jtacs) {
/* TACS */
if (channel >= 23 && channel <= 43)
return CHAN_TYPE_CC;
if (channel >= 323 && channel <= 343)
return CHAN_TYPE_CC;
} else {
/* JTACS */
if (channel >= 418 && channel <= 456)
return CHAN_TYPE_CC;
}
return CHAN_TYPE_VC;
@ -132,6 +153,7 @@ enum amps_chan_type amps_channel2type(int channel)
const char *amps_channel2band(int channel)
{
if (!tacs) {
/* AMPS */
if (channel >= 991 && channel <= 1023)
return "A''";
if (channel >= 1 && channel <= 333)
@ -142,11 +164,15 @@ const char *amps_channel2band(int channel)
return "A'";
if (channel >= 717 && channel <= 799)
return "B'";
} else {
} else if (!jtacs) {
/* TACS */
if (channel >= 1 && channel <= 300)
return "A";
if (channel >= 301 && channel <= 600)
return "B";
} else {
/* JTACS */
return "A";
}
return "<invalid>";
@ -200,12 +226,12 @@ void amps_number2min(const char *number, uint32_t *min1, uint16_t *min2)
}
if (!tacs) {
/* MIN1 */
/* MIN1 (amps) */
*min1 = ((uint32_t)(digit2binary(number[0]) * 100 + digit2binary(number[1]) * 10 + digit2binary(number[2]) - 111)) << 14;
*min1 |= digit2binary(number[3]) << 10;
*min1 |= digit2binary(number[4]) * 100 + digit2binary(number[5]) * 10 + digit2binary(number[6]) - 111;
} else {
/* MIN1 */
/* MIN1 (tacs/jtacs) */
*min1 = digit2binary(number[0]) << 20;
*min1 |= (digit2binary(number[1]) * 100 + digit2binary(number[2]) * 10 + digit2binary(number[3]) - 111) << 10;
*min1 |= digit2binary(number[4]) * 100 + digit2binary(number[5]) * 10 + digit2binary(number[6]) - 111;
@ -216,6 +242,8 @@ void amps_number2min(const char *number, uint32_t *min1, uint16_t *min2)
*/
/* TACS: convert MIN1 and MIN2 to AREA-XXXXXXX
*/
/* JTACS: convert MIN1 and MIN2 to NET-XXXXXXX (NET = mobile network code, always 440)
*/
const char *amps_min22number(uint16_t min2)
{
static char number[4];
@ -238,7 +266,7 @@ const char *amps_min12number(uint32_t min1)
static char number[8];
if (!tacs) {
/* MIN1 */
/* MIN1 (amps) */
if ((min1 >> 14) > 999)
strcpy(number, "???");
else {
@ -258,7 +286,7 @@ const char *amps_min12number(uint32_t min1)
number[6] = binary2digit(((min1 & 0x3ff) % 10) + 1);
}
} else {
/* MIN1 */
/* MIN1 (tacs/jtacs) */
if ((min1 >> 20) < 1 || (min1 >> 20) > 10)
number[0] = '?';
else
@ -314,7 +342,7 @@ const char *amps_scm(uint8_t scm)
return text;
}
const char *amps_mpci(uint8_t mpci)
static const char *amps_mpci(uint8_t mpci)
{
switch (mpci) {
case 0:
@ -331,7 +359,7 @@ const char *amps_mpci(uint8_t mpci)
}
const char *amps_state_name(enum amps_state state)
static const char *amps_state_name(enum amps_state state)
{
static char invalid[16];
@ -368,7 +396,7 @@ static void amps_new_state(amps_t *amps, enum amps_state new_state)
{
if (amps->state == new_state)
return;
PDEBUG_CHAN(DAMPS, DEBUG_DEBUG, "State change: %s -> %s\n", amps_state_name(amps->state), amps_state_name(new_state));
LOGP_CHAN(DAMPS, LOGL_DEBUG, "State change: %s -> %s\n", amps_state_name(amps->state), amps_state_name(new_state));
amps->state = new_state;
amps_display_status();
}
@ -402,7 +430,7 @@ int amps_channel_by_short_name(const char *short_name)
for (i = 0; amps_channels[i].short_name; i++) {
if (!strcasecmp(amps_channels[i].short_name, short_name)) {
PDEBUG(DAMPS, DEBUG_INFO, "Selecting channel '%s' = %s\n", amps_channels[i].short_name, amps_channels[i].long_name);
LOGP(DAMPS, LOGL_INFO, "Selecting channel '%s' = %s\n", amps_channels[i].short_name, amps_channels[i].long_name);
return amps_channels[i].chan_type;
}
}
@ -491,7 +519,7 @@ static amps_t *search_pc(void)
}
/* Create transceiver instance and link to a list. */
int amps_create(const char *kanal, enum amps_chan_type chan_type, const char *device, int use_sdr, int samplerate, double rx_gain, double tx_gain, int pre_emphasis, int de_emphasis, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, const char *read_tx_wave, amps_si *si, uint16_t sid, uint8_t sat, int polarity, int tolerant, int loopback)
int amps_create(const char *kanal, enum amps_chan_type chan_type, const char *device, int use_sdr, int samplerate, double rx_gain, double tx_gain, int pre_emphasis, int de_emphasis, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, const char *read_tx_wave, amps_si *si, uint16_t sid, uint8_t sat, int polarity, int send_callerid, int tolerant, int loopback)
{
sender_t *sender;
amps_t *amps;
@ -501,13 +529,15 @@ int amps_create(const char *kanal, enum amps_chan_type chan_type, const char *de
/* check for channel number */
if (amps_channel2freq(atoi(kanal), 0) == 0) {
PDEBUG(DAMPS, DEBUG_ERROR, "Channel number %s invalid.\n", kanal);
LOGP(DAMPS, LOGL_ERROR, "Channel number %s invalid.\n", kanal);
if (jtacs)
LOGP(DAMPS, LOGL_ERROR, "Try an even channel number, like 440.\n");
return -EINVAL;
}
/* no paging channel (without control channel) support */
if (chan_type == CHAN_TYPE_PC) {
PDEBUG(DAMPS, DEBUG_ERROR, "Dedicated paging channel currently not supported. Please select CC/PC or CC/PC/VC instead.\n");
LOGP(DAMPS, LOGL_ERROR, "Dedicated paging channel currently not supported. Please select CC/PC or CC/PC/VC instead.\n");
return -EINVAL;
}
@ -516,7 +546,7 @@ int amps_create(const char *kanal, enum amps_chan_type chan_type, const char *de
for (sender = sender_head; sender; sender = sender->next) {
amps = (amps_t *)sender;
if (amps->chan_type == CHAN_TYPE_PC || amps->chan_type == CHAN_TYPE_CC_PC || amps->chan_type == CHAN_TYPE_CC_PC_VC) {
PDEBUG(DAMPS, DEBUG_ERROR, "Only one paging channel is currently supported. Please check your channel types.\n");
LOGP(DAMPS, LOGL_ERROR, "Only one paging channel is currently supported. Please check your channel types.\n");
return -EINVAL;
}
}
@ -525,58 +555,63 @@ int amps_create(const char *kanal, enum amps_chan_type chan_type, const char *de
/* check if channel type matches channel number */
ct = amps_channel2type(atoi(kanal));
if (ct == CHAN_TYPE_CC && chan_type != CHAN_TYPE_PC && chan_type != CHAN_TYPE_CC_PC && chan_type != CHAN_TYPE_CC_PC_VC) {
PDEBUG(DAMPS, DEBUG_NOTICE, "Channel number %s belongs to a control channel, but your channel type '%s' requires to be on a voice channel number. Some phone may reject this, but all my phones don't.\n", kanal, chan_type_long_name(chan_type));
LOGP(DAMPS, LOGL_NOTICE, "Channel number %s belongs to a control channel, but your channel type '%s' requires to be on a voice channel number. Some phone may reject this, but all my phones don't.\n", kanal, chan_type_long_name(chan_type));
}
if (ct == CHAN_TYPE_VC && chan_type != CHAN_TYPE_VC) {
PDEBUG(DAMPS, DEBUG_ERROR, "Channel number %s belongs to a voice channel, but your channel type '%s' requires to be on a control channel number. Please use correct channel.\n", kanal, chan_type_long_name(chan_type));
LOGP(DAMPS, LOGL_ERROR, "Channel number %s belongs to a voice channel, but your channel type '%s' requires to be on a control channel number. Please use correct channel.\n", kanal, chan_type_long_name(chan_type));
return -EINVAL;
}
/* only even channels */
if (jtacs && chan_type != CHAN_TYPE_VC && (atoi(kanal) & 1)) {
LOGP(DAMPS, LOGL_ERROR, "Control channel on JTACS system seem not to work with odd channel numbers. Please use even channel number.\n");
return -EINVAL;
}
/* check if sid machtes channel band */
band = amps_channel2band(atoi(kanal));
if (band[0] == 'A' && (sid & 1) == 0 && chan_type != CHAN_TYPE_VC) {
PDEBUG(DAMPS, DEBUG_ERROR, "Channel number %s belongs to system A, but your %s %d is even and belongs to system B. Please give odd %s.\n", kanal, (!tacs) ? "SID" : "AID", sid, (!tacs) ? "SID" : "AID");
LOGP(DAMPS, LOGL_ERROR, "Channel number %s belongs to system A, but your %s %d is even and belongs to system B. Please give odd %s.\n", kanal, (!tacs) ? "SID" : "AID", sid, (!tacs) ? "SID" : "AID");
return -EINVAL;
}
if (band[0] == 'B' && (sid & 1) == 1 && chan_type != CHAN_TYPE_VC) {
PDEBUG(DAMPS, DEBUG_ERROR, "Channel number %s belongs to system B, but your %s %d is odd and belongs to system A. Please give even %s.\n", kanal, (!tacs) ? "SID" : "AID", sid, (!tacs) ? "SID" : "AID");
LOGP(DAMPS, LOGL_ERROR, "Channel number %s belongs to system B, but your %s %d is odd and belongs to system A. Please give even %s.\n", kanal, (!tacs) ? "SID" : "AID", sid, (!tacs) ? "SID" : "AID");
return -EINVAL;
}
/* check if we use combined voice channel hack */
if (chan_type == CHAN_TYPE_CC_PC_VC) {
PDEBUG(DAMPS, DEBUG_NOTICE, "You selected '%s'. This is a hack, but the only way to use control channel and voice channel on one transceiver. Some phones may reject this, but all my phones don't.\n", chan_type_long_name(chan_type));
LOGP(DAMPS, LOGL_NOTICE, "You selected '%s'. This is a hack, but the only way to use control channel and voice channel on one transceiver. Some phones may reject this, but all my phones don't.\n", chan_type_long_name(chan_type));
}
/* check if we selected a voice channel that i outside 20 MHz band */
if (chan_type == CHAN_TYPE_VC && atoi(kanal) > 666) {
PDEBUG(DAMPS, DEBUG_NOTICE, "You selected '%s' on channel #%s. Older phones do not support channels above #666.\n", chan_type_long_name(chan_type), kanal);
LOGP(DAMPS, LOGL_NOTICE, "You selected '%s' on channel #%s. Older phones do not support channels above #666.\n", chan_type_long_name(chan_type), kanal);
}
amps = calloc(1, sizeof(amps_t));
if (!amps) {
PDEBUG(DAMPS, DEBUG_ERROR, "No memory!\n");
LOGP(DAMPS, LOGL_ERROR, "No memory!\n");
return -ENOMEM;
}
PDEBUG(DAMPS, DEBUG_DEBUG, "Creating 'AMPS' instance for channel = %s of band %s (sample rate %d).\n", kanal, band, samplerate);
LOGP(DAMPS, LOGL_DEBUG, "Creating 'AMPS' instance for channel = %s of band %s (sample rate %d).\n", kanal, band, samplerate);
/* init general part of transceiver */
rc = sender_create(&amps->sender, kanal, amps_channel2freq(atoi(kanal), 0), amps_channel2freq(atoi(kanal), 1), device, use_sdr, samplerate, rx_gain, tx_gain, 0, 0, write_rx_wave, write_tx_wave, read_rx_wave, read_tx_wave, loopback, PAGING_SIGNAL_NONE);
if (rc < 0) {
PDEBUG(DAMPS, DEBUG_ERROR, "Failed to init transceiver process!\n");
LOGP(DAMPS, LOGL_ERROR, "Failed to init transceiver process!\n");
goto error;
}
amps->chan_type = chan_type;
memcpy(&amps->si, si, sizeof(amps->si));
amps->sat = sat;
amps->send_callerid = send_callerid;
if (polarity < 0)
amps->flip_polarity = 1;
amps->pre_emphasis = pre_emphasis;
amps->de_emphasis = de_emphasis;
/* the AMPS uses a frequency rage of 300..3000 Hz, but we still use the default low pass filter, which is not too far above */
rc = init_emphasis(&amps->estate, samplerate, CUT_OFF_EMPHASIS_DEFAULT, CUT_OFF_HIGHPASS_DEFAULT, CUT_OFF_LOWPASS_DEFAULT);
if (rc < 0)
@ -585,7 +620,7 @@ int amps_create(const char *kanal, enum amps_chan_type chan_type, const char *de
/* init audio processing */
rc = dsp_init_sender(amps, tolerant);
if (rc < 0) {
PDEBUG(DAMPS, DEBUG_ERROR, "Failed to init audio processing!\n");
LOGP(DAMPS, LOGL_ERROR, "Failed to init audio processing!\n");
goto error;
}
@ -600,7 +635,7 @@ int amps_create(const char *kanal, enum amps_chan_type chan_type, const char *de
// amps_new_state(amps, STATE_BUSY);
#endif
PDEBUG(DAMPS, DEBUG_NOTICE, "Created channel #%s (System %s) of type '%s' = %s\n", kanal, band, chan_type_short_name(chan_type), chan_type_long_name(chan_type));
LOGP(DAMPS, LOGL_NOTICE, "Created channel #%s (System %s) of type '%s' = %s\n", kanal, band, chan_type_short_name(chan_type), chan_type_long_name(chan_type));
return 0;
@ -616,11 +651,11 @@ void amps_destroy(sender_t *sender)
amps_t *amps = (amps_t *) sender;
transaction_t *trans;
PDEBUG(DAMPS, DEBUG_DEBUG, "Destroying 'AMPS' instance for channel = %s.\n", sender->kanal);
LOGP(DAMPS, LOGL_DEBUG, "Destroying 'AMPS' instance for channel = %s.\n", sender->kanal);
while ((trans = amps->trans_list)) {
const char *number = amps_min2number(trans->min1, trans->min2);
PDEBUG(DAMPS, DEBUG_NOTICE, "Removing pending transaction for subscriber '%s'\n", number);
LOGP(DAMPS, LOGL_NOTICE, "Removing pending transaction for subscriber '%s'\n", number);
destroy_transaction(trans);
}
@ -638,7 +673,7 @@ void amps_go_idle(amps_t *amps)
return;
if (amps->trans_list) {
PDEBUG(DAMPS, DEBUG_ERROR, "Releasing but still having transaction, please fix!\n");
LOGP(DAMPS, LOGL_ERROR, "Releasing but still having transaction, please fix!\n");
if (amps->trans_list->callref)
call_up_release(amps->trans_list->callref, CAUSE_NORMAL);
destroy_transaction(amps->trans_list);
@ -647,14 +682,14 @@ void amps_go_idle(amps_t *amps)
amps_new_state(amps, STATE_IDLE);
if (amps->chan_type != CHAN_TYPE_VC) {
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Entering IDLE state, sending Overhead/Filler frames on %s.\n", chan_type_long_name(amps->chan_type));
LOGP_CHAN(DAMPS, LOGL_INFO, "Entering IDLE state, sending Overhead/Filler frames on %s.\n", chan_type_long_name(amps->chan_type));
if (amps->sender.loopback)
frame_length = 441; /* bits after sync (FOCC) */
else
frame_length = 247; /* bits after sync (RECC) */
amps_set_dsp_mode(amps, DSP_MODE_FRAME_RX_FRAME_TX, frame_length);
} else {
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Entering IDLE state (sending silence / no RF) on %s.\n", chan_type_long_name(amps->chan_type));
LOGP_CHAN(DAMPS, LOGL_INFO, "Entering IDLE state (sending silence / no RF) on %s.\n", chan_type_long_name(amps->chan_type));
amps_set_dsp_mode(amps, DSP_MODE_OFF, 0);
}
}
@ -664,8 +699,8 @@ static void amps_release(transaction_t *trans, uint8_t cause)
{
amps_t *amps = trans->amps;
timer_stop(&trans->timer);
timer_start(&trans->timer, RELEASE_TIMER);
osmo_timer_del(&trans->timer);
osmo_timer_schedule(&trans->timer, RELEASE_TIMER);
trans_new_state(trans, TRANS_CALL_RELEASE);
trans->chan = 0;
trans->msg_type = 0;
@ -677,28 +712,28 @@ static void amps_release(transaction_t *trans, uint8_t cause)
trans->callref = 0;
}
/* change DSP mode to transmit release */
if (amps->dsp_mode == DSP_MODE_AUDIO_RX_AUDIO_TX || amps->dsp_mode == DSP_MODE_OFF)
if (amps->dsp_mode == DSP_MODE_AUDIO_RX_AUDIO_TX || amps->dsp_mode == DSP_MODE_AUDIO_RX_SILENCE_TX || amps->dsp_mode == DSP_MODE_OFF)
amps_set_dsp_mode(amps, DSP_MODE_AUDIO_RX_FRAME_TX, 0);
}
/*
* receive signaling
*/
void amps_rx_signaling_tone(amps_t *amps, int tone, double quality)
{
transaction_t *trans = amps->trans_list;
if (trans == NULL) {
PDEBUG_CHAN(DAMPS, DEBUG_ERROR, "Signaling Tone without transaction, please fix!\n");
LOGP_CHAN(DAMPS, LOGL_ERROR, "Signaling Tone without transaction, please fix!\n");
return;
}
if (tone)
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Detected Signaling Tone with quality=%.0f.\n", quality * 100.0);
LOGP_CHAN(DAMPS, LOGL_INFO, "Detected Signaling Tone with quality=%.0f.\n", quality * 100.0);
else
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Lost Signaling Tone signal\n");
LOGP_CHAN(DAMPS, LOGL_INFO, "Lost Signaling Tone signal\n");
switch (trans->state) {
case TRANS_CALL_MO_ASSIGN_CONFIRM: // should not happen
case TRANS_CALL:
if (!tone)
break;
@ -706,32 +741,35 @@ void amps_rx_signaling_tone(amps_t *amps, int tone, double quality)
case TRANS_CALL_RELEASE:
case TRANS_CALL_RELEASE_SEND:
/* also loosing singaling tone indicates release confirm (after alerting) */
timer_stop(&trans->timer);
osmo_timer_del(&trans->timer);
if (trans->callref)
call_up_release(trans->callref, CAUSE_NORMAL);
destroy_transaction(trans);
amps_go_idle(amps);
break;
case TRANS_CALL_MT_ALERT:
case TRANS_CALL_MT_ASSIGN_CONFIRM: // should not happen
case TRANS_CALL_MT_ALERT: // should not happen
case TRANS_CALL_MT_ALERT_SEND: // should not happen
case TRANS_CALL_MT_ALERT_CONFIRM:
if (tone) {
timer_stop(&trans->timer);
osmo_timer_del(&trans->timer);
call_up_alerting(trans->callref);
amps_set_dsp_mode(amps, DSP_MODE_AUDIO_RX_AUDIO_TX, 0);
trans_new_state(trans, TRANS_CALL_MT_ALERT_SEND);
timer_start(&trans->timer, ALERT_TO);
trans_new_state(trans, TRANS_CALL_MT_ANSWER_WAIT);
osmo_timer_schedule(&trans->timer, ANSWER_TO);
}
break;
case TRANS_CALL_MT_ALERT_SEND:
case TRANS_CALL_MT_ANSWER_WAIT:
if (!tone) {
timer_stop(&trans->timer);
osmo_timer_del(&trans->timer);
if (!trans->sat_detected)
timer_start(&trans->timer, SAT_TO1);
osmo_timer_schedule(&trans->timer, SAT_TO1);
call_up_answer(trans->callref, amps_min2number(trans->min1, trans->min2));
trans_new_state(trans, TRANS_CALL);
}
break;
default:
PDEBUG_CHAN(DAMPS, DEBUG_ERROR, "Signaling Tone without active call, please fix!\n");
LOGP_CHAN(DAMPS, LOGL_ERROR, "Signaling Tone without active call, please fix!\n");
}
}
@ -739,60 +777,63 @@ void amps_rx_sat(amps_t *amps, int tone, double quality)
{
transaction_t *trans = amps->trans_list;
if (trans == NULL) {
PDEBUG_CHAN(DAMPS, DEBUG_ERROR, "SAT signal without transaction, please fix!\n");
LOGP_CHAN(DAMPS, LOGL_ERROR, "SAT signal without transaction, please fix!\n");
return;
}
/* irgnoring SAT loss on release */
if (trans->state == TRANS_CALL_RELEASE
|| trans->state == TRANS_CALL_RELEASE_SEND)
return;
if (trans->state != TRANS_CALL
/* only SAT with these states */
if (trans->state != TRANS_CALL_MO_ASSIGN_CONFIRM
&& trans->state != TRANS_CALL_MT_ASSIGN_CONFIRM
&& trans->state != TRANS_CALL_MT_ALERT
&& trans->state != TRANS_CALL_MT_ALERT_SEND) {
PDEBUG_CHAN(DAMPS, DEBUG_ERROR, "SAT signal without active call, please fix!\n");
&& trans->state != TRANS_CALL_MT_ALERT_SEND
&& trans->state != TRANS_CALL_MT_ALERT_CONFIRM
&& trans->state != TRANS_CALL_MT_ANSWER_WAIT
&& trans->state != TRANS_CALL) {
LOGP_CHAN(DAMPS, LOGL_ERROR, "SAT signal without active call, please fix!\n");
return;
}
if (tone) {
PDEBUG(DAMPS, DEBUG_INFO, "Detected SAT signal with quality=%.0f.\n", quality * 100.0);
LOGP(DAMPS, LOGL_INFO, "Detected SAT signal with quality=%.0f.\n", quality * 100.0);
trans->sat_detected = 1;
} else {
PDEBUG(DAMPS, DEBUG_INFO, "Lost SAT signal\n");
LOGP(DAMPS, LOGL_INFO, "Lost SAT signal\n");
trans->sat_detected = 0;
}
/* no SAT during alerting */
if (trans->state == TRANS_CALL_MT_ALERT
|| trans->state == TRANS_CALL_MT_ALERT_SEND)
return;
/* initial SAT received */
if (tone && trans->state == TRANS_CALL_MO_ASSIGN_CONFIRM) {
LOGP_CHAN(DAMPS, LOGL_INFO, "Confirm from mobile (SAT) received\n");
osmo_timer_del(&trans->timer);
trans_new_state(trans, TRANS_CALL);
amps_set_dsp_mode(amps, DSP_MODE_AUDIO_RX_AUDIO_TX, 0);
}
if (tone && trans->state == TRANS_CALL_MT_ASSIGN_CONFIRM) {
LOGP_CHAN(DAMPS, LOGL_INFO, "Confirm from mobile (SAT) received\n");
osmo_timer_del(&trans->timer);
trans->alert_retry = 1;
trans_new_state(trans, TRANS_CALL_MT_ALERT);
amps_set_dsp_mode(amps, DSP_MODE_AUDIO_RX_FRAME_TX, 0);
}
if (tone) {
timer_stop(&trans->timer);
osmo_timer_del(&trans->timer);
} else {
if (!trans->dtx)
timer_start(&trans->timer, SAT_TO2);
osmo_timer_schedule(&trans->timer, SAT_TO2);
else
timer_stop(&trans->timer);
osmo_timer_del(&trans->timer);
}
if (amps->sender.loopback)
return;
}
static void timeout_sat(amps_t *amps, double duration)
{
if (!amps->trans_list) {
PDEBUG_CHAN(DAMPS, DEBUG_ERROR, "SAT timeout, but no transaction, please fix!\n");
return;
}
if (duration == SAT_TO1)
PDEBUG_CHAN(DAMPS, DEBUG_NOTICE, "Timeout after %.0f seconds not receiving SAT signal.\n", duration);
else
PDEBUG_CHAN(DAMPS, DEBUG_NOTICE, "Timeout after %.0f seconds loosing SAT signal.\n", duration);
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Release call towards network.\n");
amps_release(amps->trans_list, CAUSE_TEMPFAIL);
}
/* receive message from phone on RECC */
void amps_rx_recc(amps_t *amps, uint8_t scm, uint8_t mpci, uint32_t esn, uint32_t min1, uint16_t min2, uint8_t msg_type, uint8_t ordq, uint8_t order, const char *dialing)
{
@ -803,50 +844,51 @@ void amps_rx_recc(amps_t *amps, uint8_t scm, uint8_t mpci, uint32_t esn, uint32_
/* check if we are busy, so we ignore all signaling */
if (amps->state == STATE_BUSY) {
PDEBUG_CHAN(DAMPS, DEBUG_NOTICE, "Ignoring RECC messages from phone while using this channel for voice.\n");
LOGP_CHAN(DAMPS, LOGL_NOTICE, "Ignoring RECC messages from phone while using this channel for voice.\n");
return;
}
if (order == 13 && (ordq == 0 || ordq == 1 || ordq == 2 || ordq == 3) && msg_type == 0) {
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Registration %s (ESN = %08x, %s, %s)\n", callerid, esn, amps_scm(scm), amps_mpci(mpci));
LOGP_CHAN(DAMPS, LOGL_INFO, "Registration %s (ESN = %s, %s, %s)\n", callerid, esn_to_string(esn), amps_scm(scm), amps_mpci(mpci));
_register:
numbering(callerid, &carrier, &country, &national_number);
if (carrier)
PDEBUG_CHAN(DAMPS, DEBUG_INFO, " -> Home carrier: %s\n", carrier);
LOGP_CHAN(DAMPS, LOGL_INFO, " -> Home carrier: %s\n", carrier);
if (country)
PDEBUG_CHAN(DAMPS, DEBUG_INFO, " -> Home country: %s\n", country);
LOGP_CHAN(DAMPS, LOGL_INFO, " -> Home country: %s\n", country);
if (national_number)
PDEBUG_CHAN(DAMPS, DEBUG_INFO, " -> Home number: %s\n", national_number);
LOGP_CHAN(DAMPS, LOGL_INFO, " -> Home number: %s\n", national_number);
trans = create_transaction(amps, TRANS_REGISTER_ACK, min1, min2, esn, msg_type, ordq, order, 0);
if (!trans) {
PDEBUG(DAMPS, DEBUG_ERROR, "Failed to create transaction\n");
LOGP(DAMPS, LOGL_ERROR, "Failed to create transaction\n");
return;
}
console_inscription(callerid);
} else
if (order == 13 && ordq == 3 && msg_type == 1) {
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Registration - Power Down %s (ESN = %08x, %s, %s)\n", callerid, esn, amps_scm(scm), amps_mpci(mpci));
LOGP_CHAN(DAMPS, LOGL_INFO, "Registration - Power Down %s (ESN = %s, %s, %s)\n", callerid, esn_to_string(esn), amps_scm(scm), amps_mpci(mpci));
goto _register;
} else
if (order == 0 && ordq == 0 && msg_type == 0) {
if (!dialing)
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Paging reply %s (ESN = %08x, %s, %s)\n", callerid, esn, amps_scm(scm), amps_mpci(mpci));
LOGP_CHAN(DAMPS, LOGL_INFO, "Paging reply %s (ESN = %s, %s, %s)\n", callerid, esn_to_string(esn), amps_scm(scm), amps_mpci(mpci));
else
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Call %s -> %s (ESN = %08x, %s, %s)\n", callerid, dialing, esn, amps_scm(scm), amps_mpci(mpci));
LOGP_CHAN(DAMPS, LOGL_INFO, "Call %s -> %s (ESN = %s, %s, %s)\n", callerid, dialing, esn_to_string(esn), amps_scm(scm), amps_mpci(mpci));
trans = search_transaction_number(amps, min1, min2);
if (!trans && !dialing) {
PDEBUG(DAMPS, DEBUG_NOTICE, "Paging reply, but call is already gone, rejecting call\n");
LOGP(DAMPS, LOGL_NOTICE, "Paging reply, but call is already gone, rejecting call\n");
goto reject;
}
if (trans && dialing)
PDEBUG(DAMPS, DEBUG_NOTICE, "There is already a transaction for this phone. Cloning?\n");
LOGP(DAMPS, LOGL_NOTICE, "There is already a transaction for this phone. Cloning?\n");
vc = search_free_vc();
if (!vc) {
PDEBUG(DAMPS, DEBUG_NOTICE, "No free channel, rejecting call\n");
LOGP(DAMPS, LOGL_NOTICE, "No free channel, rejecting call\n");
reject:
if (!trans) {
trans = create_transaction(amps, TRANS_CALL_REJECT, min1, min2, esn, 0, 0, 3, 0);
if (!trans) {
PDEBUG(DAMPS, DEBUG_ERROR, "Failed to create transaction\n");
LOGP(DAMPS, LOGL_ERROR, "Failed to create transaction\n");
return;
}
} else {
@ -862,7 +904,7 @@ reject:
trans = create_transaction(amps, TRANS_CALL_MO_ASSIGN, min1, min2, esn, 0, 0, 0, atoi(vc->sender.kanal));
strncpy(trans->dialing, dialing, sizeof(trans->dialing) - 1);
if (!trans) {
PDEBUG(DAMPS, DEBUG_ERROR, "Failed to create transaction\n");
LOGP(DAMPS, LOGL_ERROR, "Failed to create transaction\n");
return;
}
} else {
@ -872,13 +914,13 @@ reject:
/* if we support DTX and also the phone does, we set DTX state of transaction */
if (amps->si.word2.dtx) {
if ((scm & 4)) {
PDEBUG(DAMPS, DEBUG_INFO, " -> Use DTX for this call\n");
LOGP(DAMPS, LOGL_INFO, " -> Use DTX for this call\n");
trans->dtx = 1;
} else
PDEBUG(DAMPS, DEBUG_INFO, " -> Requested DTX, but not supported by phone\n");
LOGP(DAMPS, LOGL_INFO, " -> Requested DTX, but not supported by phone\n");
}
} else
PDEBUG_CHAN(DAMPS, DEBUG_NOTICE, "Unsupported RECC messages: ORDER: %d ORDQ: %d MSG TYPE: %d (See Table 4 of specs.)\n", order, ordq, msg_type);
LOGP_CHAN(DAMPS, LOGL_NOTICE, "Unsupported RECC messages: ORDER: %d ORDQ: %d MSG TYPE: %d (See Table 4 of specs.)\n", order, ordq, msg_type);
}
/*
@ -899,7 +941,7 @@ int call_down_setup(int callref, const char __attribute__((unused)) *caller_id,
/* 2. check if the subscriber is attached */
// if (!find_db(min1, min2)) {
// PDEBUG(DAMPS, DEBUG_NOTICE, "Outgoing call to not attached subscriber, rejecting!\n");
// LOGP(DAMPS, LOGL_NOTICE, "Outgoing call to not attached subscriber, rejecting!\n");
// return -CAUSE_OUTOFORDER;
// }
@ -912,38 +954,43 @@ int call_down_setup(int callref, const char __attribute__((unused)) *caller_id,
break;
}
if (sender) {
PDEBUG(DAMPS, DEBUG_NOTICE, "Outgoing call to busy number, rejecting!\n");
LOGP(DAMPS, LOGL_NOTICE, "Outgoing call to busy number, rejecting!\n");
return -CAUSE_BUSY;
}
/* 4. check if all senders are busy, return NOCHANNEL */
if (!search_free_vc()) {
PDEBUG(DAMPS, DEBUG_NOTICE, "Outgoing call, but no free channel, rejecting!\n");
LOGP(DAMPS, LOGL_NOTICE, "Outgoing call, but no free channel, rejecting!\n");
return -CAUSE_NOCHANNEL;
}
/* 5. check if we have (currently) no paging channel, return NOCHANNEL */
amps = search_pc();
if (!amps) {
PDEBUG(DAMPS, DEBUG_NOTICE, "Outgoing call, but paging channel (control channel) is currently busy, rejecting!\n");
LOGP(DAMPS, LOGL_NOTICE, "Outgoing call, but paging channel (control channel) is currently busy, rejecting!\n");
return -CAUSE_NOCHANNEL;
}
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Call to mobile station, paging station id '%s'\n", dialing);
LOGP_CHAN(DAMPS, LOGL_INFO, "Call to mobile station, paging station id '%s'\n", dialing);
/* 6. trying to page mobile station */
trans = create_transaction(amps, TRANS_PAGE, min1, min2, 0, 0, 0, 0, 0);
if (!trans) {
PDEBUG(DAMPS, DEBUG_ERROR, "Failed to create transaction\n");
LOGP(DAMPS, LOGL_ERROR, "Failed to create transaction\n");
return -CAUSE_TEMPFAIL;
}
trans->callref = callref;
trans->page_retry = 1;
if (caller_type == TYPE_INTERNATIONAL) {
trans->caller_id[0] = '+';
strncpy(trans->caller_id + 1, caller_id, sizeof(trans->caller_id) - 2);
} else
strncpy(trans->caller_id, caller_id, sizeof(trans->caller_id) - 1);
return 0;
}
void call_down_answer(int __attribute__((unused)) callref)
void call_down_answer(int __attribute__((unused)) callref, struct timeval __attribute__((unused)) *tv_meter)
{
}
@ -957,7 +1004,7 @@ void call_down_disconnect(int callref, int cause)
amps_t *amps;
transaction_t *trans;
PDEBUG(DAMPS, DEBUG_INFO, "Call has been disconnected by network.\n");
LOGP(DAMPS, LOGL_INFO, "Call has been disconnected by network.\n");
for (sender = sender_head; sender; sender = sender->next) {
amps = (amps_t *) sender;
@ -967,7 +1014,7 @@ void call_down_disconnect(int callref, int cause)
break;
}
if (!sender) {
PDEBUG(DAMPS, DEBUG_NOTICE, "Outgoing disconnect, but no callref!\n");
LOGP(DAMPS, LOGL_NOTICE, "Outgoing disconnect, but no callref!\n");
call_up_release(callref, CAUSE_INVALCALLREF);
return;
}
@ -977,14 +1024,17 @@ void call_down_disconnect(int callref, int cause)
switch (amps->dsp_mode) {
case DSP_MODE_AUDIO_RX_AUDIO_TX:
case DSP_MODE_AUDIO_RX_FRAME_TX:
if (trans->state == TRANS_CALL_MT_ALERT
|| trans->state == TRANS_CALL_MT_ALERT_SEND) {
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Call control disconnect on voice channel while alerting, releasing towards mobile station.\n");
if (trans->state == TRANS_CALL_MT_ASSIGN_CONFIRM
|| trans->state == TRANS_CALL_MT_ALERT
|| trans->state == TRANS_CALL_MT_ALERT_SEND
|| trans->state == TRANS_CALL_MT_ALERT_CONFIRM
|| trans->state == TRANS_CALL_MT_ANSWER_WAIT) {
LOGP_CHAN(DAMPS, LOGL_INFO, "Call control disconnect on voice channel while alerting, releasing towards mobile station.\n");
amps_release(trans, cause);
}
return;
default:
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Call control disconnects on control channel, removing transaction.\n");
LOGP_CHAN(DAMPS, LOGL_INFO, "Call control disconnects on control channel, removing transaction.\n");
call_up_release(callref, cause);
trans->callref = 0;
destroy_transaction(trans);
@ -999,7 +1049,7 @@ void call_down_release(int callref, int cause)
amps_t *amps;
transaction_t *trans;
PDEBUG(DAMPS, DEBUG_INFO, "Call has been released by network, releasing call.\n");
LOGP(DAMPS, LOGL_INFO, "Call has been released by network, releasing call.\n");
for (sender = sender_head; sender; sender = sender->next) {
amps = (amps_t *) sender;
@ -1009,7 +1059,7 @@ void call_down_release(int callref, int cause)
break;
}
if (!sender) {
PDEBUG(DAMPS, DEBUG_NOTICE, "Outgoing release, but no callref!\n");
LOGP(DAMPS, LOGL_NOTICE, "Outgoing release, but no callref!\n");
/* don't send release, because caller already released */
return;
}
@ -1017,76 +1067,69 @@ void call_down_release(int callref, int cause)
trans->callref = 0;
switch (amps->dsp_mode) {
case DSP_MODE_AUDIO_RX_SILENCE_TX:
case DSP_MODE_AUDIO_RX_AUDIO_TX:
case DSP_MODE_AUDIO_RX_FRAME_TX:
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Call control releases on voice channel, releasing towards mobile station.\n");
LOGP_CHAN(DAMPS, LOGL_INFO, "Call control releases on voice channel, releasing towards mobile station.\n");
amps_release(trans, cause);
break;
default:
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Call control releases on control channel, removing transaction.\n");
LOGP_CHAN(DAMPS, LOGL_INFO, "Call control releases on control channel, removing transaction.\n");
destroy_transaction(trans);
amps_go_idle(amps);
}
}
/* Receive audio from call instance. */
void call_down_audio(int callref, sample_t *samples, int count)
{
sender_t *sender;
amps_t *amps;
for (sender = sender_head; sender; sender = sender->next) {
amps = (amps_t *) sender;
if (amps->trans_list && amps->trans_list->callref == callref)
break;
}
if (!sender)
return;
if (amps->dsp_mode == DSP_MODE_AUDIO_RX_AUDIO_TX) {
sample_t up[(int)((double)count * amps->sender.srstate.factor + 0.5) + 10];
compress_audio(&amps->cstate, samples, count);
count = samplerate_upsample(&amps->sender.srstate, samples, count, up);
jitter_save(&amps->sender.dejitter, up, count);
}
}
void call_down_clock(void) {}
/* Timeout handling */
void transaction_timeout(struct timer *timer)
void transaction_timeout(void *data)
{
transaction_t *trans = (transaction_t *)timer->priv;
transaction_t *trans = data;
amps_t *amps = trans->amps;
switch (trans->state) {
case TRANS_CALL_MO_ASSIGN_CONFIRM:
case TRANS_CALL_MT_ASSIGN_CONFIRM:
LOGP_CHAN(DAMPS, LOGL_NOTICE, "Timeout after %ld seconds not receiving initial SAT signal.\n", trans->timer.timeout.tv_sec);
LOGP_CHAN(DAMPS, LOGL_INFO, "Release call towards network.\n");
amps_release(amps->trans_list, CAUSE_TEMPFAIL);
break;
case TRANS_CALL:
timeout_sat(amps, timer->duration);
LOGP_CHAN(DAMPS, LOGL_NOTICE, "Timeout after %ld seconds loosing SAT signal.\n", trans->timer.timeout.tv_sec);
LOGP_CHAN(DAMPS, LOGL_INFO, "Release call towards network.\n");
amps_release(amps->trans_list, CAUSE_TEMPFAIL);
break;
case TRANS_CALL_RELEASE:
case TRANS_CALL_RELEASE_SEND:
PDEBUG_CHAN(DAMPS, DEBUG_NOTICE, "Release timeout, destroying transaction\n");
LOGP_CHAN(DAMPS, LOGL_NOTICE, "Release timeout, destroying transaction\n");
destroy_transaction(trans);
amps_go_idle(amps);
break;
case TRANS_CALL_MT_ALERT:
amps_release(trans, CAUSE_TEMPFAIL);
break;
case TRANS_CALL_MT_ALERT_SEND:
PDEBUG_CHAN(DAMPS, DEBUG_NOTICE, "Alerting timeout, destroying transaction\n");
case TRANS_CALL_MT_ALERT_CONFIRM:
if (trans->alert_retry++ == ALERT_TRIES) {
LOGP_CHAN(DAMPS, LOGL_NOTICE, "Phone does not respond to alert order, destroying transaction\n");
amps_release(trans, CAUSE_TEMPFAIL);
} else {
LOGP_CHAN(DAMPS, LOGL_NOTICE, "Phone does not respond to alert order, retrying\n");
trans_new_state(trans, TRANS_CALL_MT_ALERT);
amps_set_dsp_mode(amps, DSP_MODE_AUDIO_RX_FRAME_TX, 0);
}
break;
case TRANS_CALL_MT_ANSWER_WAIT:
LOGP_CHAN(DAMPS, LOGL_NOTICE, "Alerting timeout, destroying transaction\n");
amps_release(trans, CAUSE_NOANSWER);
break;
case TRANS_PAGE_REPLY:
if (trans->page_retry++ == PAGE_TRIES) {
PDEBUG_CHAN(DAMPS, DEBUG_NOTICE, "Paging timeout, destroying transaction\n");
LOGP_CHAN(DAMPS, LOGL_NOTICE, "Paging timeout, destroying transaction\n");
amps_release(trans, CAUSE_OUTOFORDER);
} else {
PDEBUG_CHAN(DAMPS, DEBUG_NOTICE, "Paging timeout, retrying\n");
LOGP_CHAN(DAMPS, LOGL_NOTICE, "Paging timeout, retrying\n");
trans_new_state(trans, TRANS_PAGE);
}
break;
default:
PDEBUG_CHAN(DAMPS, DEBUG_ERROR, "Timeout unhandled in state %d\n", trans->state);
LOGP_CHAN(DAMPS, LOGL_ERROR, "Timeout unhandled in state %d\n", trans->state);
}
}
@ -1098,18 +1141,18 @@ static amps_t *assign_voice_channel(transaction_t *trans)
vc = search_channel(trans->chan);
if (!vc) {
PDEBUG(DAMPS, DEBUG_NOTICE, "Channel %d is not free anymore, rejecting call\n", trans->chan);
LOGP(DAMPS, LOGL_NOTICE, "Channel %d is not free anymore, rejecting call\n", trans->chan);
amps_release(trans, CAUSE_NOCHANNEL);
return NULL;
}
if (vc == amps)
PDEBUG(DAMPS, DEBUG_INFO, "Staying on combined control + voice channel %s\n", vc->sender.kanal);
LOGP(DAMPS, LOGL_INFO, "Staying on combined control + voice channel %s\n", vc->sender.kanal);
else
PDEBUG(DAMPS, DEBUG_INFO, "Moving to voice channel %s\n", vc->sender.kanal);
LOGP(DAMPS, LOGL_INFO, "Moving to voice channel %s\n", vc->sender.kanal);
/* switch channel... */
timer_start(&trans->timer, SAT_TO1);
osmo_timer_schedule(&trans->timer, SAT_TO1);
/* make channel busy */
amps_new_state(vc, STATE_BUSY);
/* relink */
@ -1122,7 +1165,7 @@ static amps_t *assign_voice_channel(transaction_t *trans)
char esn_text[16];
sprintf(esn_text, "%u", trans->esn);
/* setup call */
PDEBUG(DAMPS, DEBUG_INFO, "Setup call to network.\n");
LOGP(DAMPS, LOGL_INFO, "Setup call to network.\n");
trans->callref = call_up_setup(callerid, trans->dialing, OSMO_CC_NETWORK_AMPS_ESN, esn_text);
}
@ -1141,54 +1184,55 @@ again:
switch (trans->state) {
case TRANS_REGISTER_ACK:
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Sending Register acknowledge\n");
LOGP_CHAN(DAMPS, LOGL_INFO, "Sending Register acknowledge\n");
trans_new_state(trans, TRANS_REGISTER_ACK_SEND);
return trans;
case TRANS_REGISTER_ACK_SEND:
destroy_transaction(trans);
goto again;
case TRANS_CALL_REJECT:
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Rejecting call from mobile station\n");
LOGP_CHAN(DAMPS, LOGL_INFO, "Rejecting call from mobile station\n");
trans_new_state(trans, TRANS_CALL_REJECT_SEND);
return trans;
case TRANS_CALL_REJECT_SEND:
destroy_transaction(trans);
goto again;
case TRANS_CALL_MO_ASSIGN:
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Assigning channel to call from mobile station\n");
LOGP_CHAN(DAMPS, LOGL_INFO, "Assigning channel to call from mobile station\n");
trans_new_state(trans, TRANS_CALL_MO_ASSIGN_SEND);
return trans;
case TRANS_CALL_MO_ASSIGN_SEND:
vc = assign_voice_channel(trans);
if (vc) {
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Assignment complete, voice connected\n");
trans_new_state(trans, TRANS_CALL);
amps_set_dsp_mode(vc, DSP_MODE_AUDIO_RX_AUDIO_TX, 0);
LOGP_CHAN(DAMPS, LOGL_INFO, "Assignment complete, voice connected\n");
/* timer and other things are processed at assign_voice_channel() */
trans_new_state(trans, TRANS_CALL_MO_ASSIGN_CONFIRM);
amps_set_dsp_mode(vc, DSP_MODE_AUDIO_RX_SILENCE_TX, 0);
}
return NULL;
case TRANS_CALL_MT_ASSIGN:
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Assigning channel to call to mobile station\n");
LOGP_CHAN(DAMPS, LOGL_INFO, "Assigning channel to call to mobile station\n");
trans_new_state(trans, TRANS_CALL_MT_ASSIGN_SEND);
return trans;
case TRANS_CALL_MT_ASSIGN_SEND:
vc = assign_voice_channel(trans);
if (vc) {
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Assignment complete, next: sending alerting on VC\n");
trans->chan = 0;
trans->msg_type = 0;
trans->ordq = 0;
trans->order = 1;
trans_new_state(trans, TRANS_CALL_MT_ALERT);
amps_set_dsp_mode(vc, DSP_MODE_AUDIO_RX_FRAME_TX, 0);
LOGP_CHAN(DAMPS, LOGL_INFO, "Assignment complete, waiting for SAT on VC\n");
/* timer and other things are processed at assign_voice_channel() */
trans_new_state(trans, TRANS_CALL_MT_ASSIGN_CONFIRM);
amps_set_dsp_mode(vc, DSP_MODE_AUDIO_RX_SILENCE_TX, 0);
}
return NULL;
case TRANS_PAGE:
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Paging the phone\n");
LOGP_CHAN(DAMPS, LOGL_INFO, "Paging the phone\n");
trans_new_state(trans, TRANS_PAGE_SEND);
return trans;
case TRANS_PAGE_SEND:
trans_new_state(trans, TRANS_PAGE_REPLY);
timer_start(&trans->timer, (trans->page_retry == PAGE_TRIES) ? PAGE_TO2 : PAGE_TO1);
if (trans->page_retry == PAGE_TRIES)
osmo_timer_schedule(&trans->timer, PAGE_TO2);
else
osmo_timer_schedule(&trans->timer, PAGE_TO1);
return NULL;
default:
return NULL;
@ -1205,15 +1249,32 @@ transaction_t *amps_tx_frame_fvc(amps_t *amps)
switch (trans->state) {
case TRANS_CALL_RELEASE:
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Releasing call towards mobile station\n");
LOGP_CHAN(DAMPS, LOGL_INFO, "Releasing call towards mobile station\n");
trans_new_state(trans, TRANS_CALL_RELEASE_SEND);
return trans;
case TRANS_CALL_RELEASE_SEND:
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Release call was sent, continue sending release\n");
LOGP_CHAN(DAMPS, LOGL_INFO, "Release call was sent, continue sending release\n");
return trans;
case TRANS_CALL_MT_ALERT:
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Sending alerting\n");
trans->chan = 0;
trans->msg_type = 0;
trans->ordq = 0;
// "Alert with caller ID" causes older phones to interrupt the connection for some reason, therefore we don't use order 17 when no caller ID is set
if (amps->send_callerid && trans->alert_retry == 1 && trans->caller_id[0]) {
LOGP_CHAN(DAMPS, LOGL_INFO, "Sending alerting with caller ID\n");
trans->order = 17;
} else {
LOGP_CHAN(DAMPS, LOGL_INFO, "Sending alerting\n");
trans->order = 1;
}
trans_new_state(trans, TRANS_CALL_MT_ALERT_SEND);
return trans;
case TRANS_CALL_MT_ALERT_SEND:
LOGP_CHAN(DAMPS, LOGL_INFO, "Alerting was sent, continue waiting for ST or timeout\n");
osmo_timer_schedule(&trans->timer, ALERT_TO);
amps_set_dsp_mode(amps, DSP_MODE_AUDIO_RX_SILENCE_TX, 0);
trans_new_state(trans, TRANS_CALL_MT_ALERT_CONFIRM);
return NULL;
default:
return NULL;
}

View File

@ -1,6 +1,6 @@
#include "../libgoertzel/goertzel.h"
#include "../libmobile/sender.h"
#include "../libtimer/timer.h"
#include <osmocom/core/timer.h>
#include "../libcompandor/compandor.h"
typedef struct amps amps_t;
#include "sysinfo.h"
@ -10,6 +10,7 @@ enum dsp_mode {
DSP_MODE_OFF, /* channel not active (VC) */
DSP_MODE_AUDIO_RX_AUDIO_TX, /* stream audio */
DSP_MODE_AUDIO_RX_FRAME_TX, /* stream audio, send frames */
DSP_MODE_AUDIO_RX_SILENCE_TX, /* stream audio, send silence */
DSP_MODE_FRAME_RX_FRAME_TX, /* send and decode frames */
};
@ -56,6 +57,7 @@ struct amps {
/* system info */
amps_si si;
int send_callerid; /* if set, caller ID is transmitted */
/* cell nr selection */
int cell_auto; /* if set, cell_nr is selected automatically */
@ -133,12 +135,19 @@ struct amps {
uint8_t tx_focc_order;
int tx_focc_word_count; /* counts transmitted words in a multi word message */
int tx_focc_word_repeat; /* counts repeats of multi word message */
int tx_focc_debugged; /* indicator to prevent debugging all SI/filler frames */
/* FVC frame states */
int tx_fvc_send; /* if set, send message words */
int tx_fvc_chan; /* channel to assign for voice call */
uint8_t tx_fvc_msg_type; /* message (3 values) */
uint8_t tx_fvc_ordq;
uint8_t tx_fvc_order;
char tx_fvc_callerid[34]; /* caller ID */
int tx_fvc_callerid_present;/* presentation of caller ID */
int tx_fvc_callerid_screen; /* screening of caller ID */
int tx_fvc_callerid_signal; /* signal to send in conjunction with caller ID */
int tx_fvc_word_count; /* counts transmitted words in a muli word message */
int tx_fvc_word_repeat; /* counts repeats of mulit word message */
/* SAT tone */
int sat; /* use SAT tone 0..2 */
int sat_samples; /* number of samples in buffer for supervisory detection */
@ -162,6 +171,7 @@ struct amps {
int when_count; /* counter of the filler frame */
};
void amps_display_status(void);
void amps_channel_list(void);
int amps_channel_by_short_name(const char *short_name);
const char *chan_type_short_name(enum amps_chan_type chan_type);
@ -173,8 +183,10 @@ const char *amps_min22number(uint16_t min2);
const char *amps_min12number(uint32_t min1);
void amps_number2min(const char *number, uint32_t *min1, uint16_t *min2);
const char *amps_min2number(uint32_t min1, uint16_t min2);
void amps_encode_esn(uint32_t *esn, uint8_t mfr, uint32_t serial);
void amps_decode_esn(uint32_t esn, uint8_t *mfr, uint32_t *serial);
const char *amps_scm(uint8_t scm);
int amps_create(const char *kanal, enum amps_chan_type chan_type, const char *device, int use_sdr, int samplerate, double rx_gain, double tx_gain, int pre_emphasis, int de_emphasis, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, const char *read_tx_wave, amps_si *si, uint16_t sid, uint8_t sat, int polarity, int tolerant, int loopback);
int amps_create(const char *kanal, enum amps_chan_type chan_type, const char *device, int use_sdr, int samplerate, double rx_gain, double tx_gain, int pre_emphasis, int de_emphasis, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, const char *read_tx_wave, amps_si *si, uint16_t sid, uint8_t sat, int polarity, int send_callerid, int tolerant, int loopback);
void amps_destroy(sender_t *sender);
void amps_go_idle(amps_t *amps);
void amps_rx_signaling_tone(amps_t *amps, int tone, double quality);

View File

@ -5,10 +5,16 @@
#include "outoforder.h"
#include "invalidnumber.h"
#include "congestion.h"
#include "../libmobile/main_mobile.h"
const int tacs = 0;
const int jtacs = 0;
const struct number_lengths number_lengths[] = {
{ 10, "AMPS number (NPA-XXX-XXXX)" },
{ 0, NULL }
};
const char *number_prefixes[] = {
"1xxxxxxxxxx",
"+1xxxxxxxxxx",

View File

@ -82,8 +82,9 @@
#include <errno.h>
#include <math.h>
#include "../libsample/sample.h"
#include "../libdebug/debug.h"
#include "../liblogging/logging.h"
#include "../libmobile/call.h"
#include "../libmobile/get_time.h"
#include "amps.h"
#include "frame.h"
#include "dsp.h"
@ -125,7 +126,7 @@
#define SIG_LOST_COUNT 4 /* number of measures to loose Signaling Tone */
#define CUT_OFF_HIGHPASS 300.0 /* cut off frequency for high pass filter to remove dc level from sound card / sample */
#define BEST_QUALITY 0.68 /* Best possible RX quality */
#define COMFORT_NOISE 0.02 /* audio level of comfort noise (relative to ISDN level) */
#define COMFORT_NOISE 0.02 /* audio level of comfort noise (relative to speech level) */
static sample_t ramp_up[256], ramp_down[256];
@ -146,7 +147,7 @@ void dsp_init(void)
int i;
double s;
PDEBUG(DDSP, DEBUG_DEBUG, "Generating sine table for SAT signal.\n");
LOGP(DDSP, LOGL_DEBUG, "Generating sine table for SAT signal.\n");
for (i = 0; i < 65536; i++) {
s = sin((double)i / 65536.0 * 2.0 * PI);
dsp_sine_sat[i] = s * ((!tacs) ? AMPS_SAT_DEVIATION : TACS_SAT_DEVIATION);
@ -162,6 +163,8 @@ void dsp_init(void)
}
dsp_sync_check[0x712] = 0x00; /* no bit error */
dsp_sync_check[0x0ed] = 0x80; /* no bit error */
compandor_init();
}
static void dsp_init_ramp(amps_t *amps)
@ -169,7 +172,7 @@ static void dsp_init_ramp(amps_t *amps)
double c;
int i;
PDEBUG(DDSP, DEBUG_DEBUG, "Generating smooth ramp table.\n");
LOGP(DDSP, LOGL_DEBUG, "Generating smooth ramp table.\n");
for (i = 0; i < 256; i++) {
c = cos((double)i / 256.0 * PI);
#if 0
@ -194,9 +197,9 @@ int dsp_init_sender(amps_t *amps, int tolerant)
int half;
/* attack (3ms) and recovery time (13.5ms) according to amps specs */
init_compandor(&amps->cstate, 8000, 3.0, 13.5);
setup_compandor(&amps->cstate, 8000, 3.0, 13.5);
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Init DSP for transceiver.\n");
LOGP_CHAN(DDSP, LOGL_DEBUG, "Init DSP for transceiver.\n");
/* set modulation parameters */
sender_set_fm(&amps->sender,
@ -206,18 +209,18 @@ int dsp_init_sender(amps_t *amps, int tolerant)
(!tacs) ? AMPS_MAX_DISPLAY : TACS_MAX_DISPLAY);
if (amps->sender.samplerate < 96000) {
PDEBUG(DDSP, DEBUG_ERROR, "Sample rate must be at least 96000 Hz to process FSK and SAT signals.\n");
LOGP(DDSP, LOGL_ERROR, "Sample rate must be at least 96000 Hz to process FSK and SAT signals.\n");
return -EINVAL;
}
amps->fsk_bitduration = (double)amps->sender.samplerate / (double)((!tacs) ? AMPS_BITRATE : TACS_BITRATE);
amps->fsk_bitstep = 1.0 / amps->fsk_bitduration;
PDEBUG(DDSP, DEBUG_DEBUG, "Use %.4f samples for full bit duration @ %d.\n", amps->fsk_bitduration, amps->sender.samplerate);
LOGP(DDSP, LOGL_DEBUG, "Use %.4f samples for full bit duration @ %d.\n", amps->fsk_bitduration, amps->sender.samplerate);
amps->fsk_tx_buffer_size = amps->fsk_bitduration + 10; /* 10 extra to avoid overflow due to rounding */
spl = calloc(sizeof(*spl), amps->fsk_tx_buffer_size);
if (!spl) {
PDEBUG(DDSP, DEBUG_ERROR, "No memory!\n");
LOGP(DDSP, LOGL_ERROR, "No memory!\n");
rc = -ENOMEM;
goto error;
}
@ -228,12 +231,12 @@ int dsp_init_sender(amps_t *amps, int tolerant)
amps->fsk_rx_window_begin = half >> 1;
amps->fsk_rx_window_half = half;
amps->fsk_rx_window_end = amps->fsk_rx_window_length - (half >> 1);
PDEBUG(DDSP, DEBUG_DEBUG, "Bit window length: %d\n", amps->fsk_rx_window_length);
PDEBUG(DDSP, DEBUG_DEBUG, " -> Samples in window to analyse level left of edge: %d..%d\n", amps->fsk_rx_window_begin, amps->fsk_rx_window_half - 1);
PDEBUG(DDSP, DEBUG_DEBUG, " -> Samples in window to analyse level right of edge: %d..%d\n", amps->fsk_rx_window_half, amps->fsk_rx_window_end - 1);
LOGP(DDSP, LOGL_DEBUG, "Bit window length: %d\n", amps->fsk_rx_window_length);
LOGP(DDSP, LOGL_DEBUG, " -> Samples in window to analyse level left of edge: %d..%d\n", amps->fsk_rx_window_begin, amps->fsk_rx_window_half - 1);
LOGP(DDSP, LOGL_DEBUG, " -> Samples in window to analyse level right of edge: %d..%d\n", amps->fsk_rx_window_half, amps->fsk_rx_window_end - 1);
spl = calloc(sizeof(*amps->fsk_rx_window), amps->fsk_rx_window_length);
if (!spl) {
PDEBUG(DDSP, DEBUG_ERROR, "No memory!\n");
LOGP(DDSP, LOGL_ERROR, "No memory!\n");
rc = -ENOMEM;
goto error;
}
@ -250,9 +253,10 @@ int dsp_init_sender(amps_t *amps, int tolerant)
amps->sat_samples = (int)((double)amps->sender.samplerate * (1.0 / (SAT_BANDWIDTH / 2.0)) + 0.5);
spl = calloc(sizeof(*spl), amps->sat_samples);
if (!spl) {
PDEBUG(DDSP, DEBUG_ERROR, "No memory!\n");
LOGP(DDSP, LOGL_ERROR, "No memory!\n");
return -ENOMEM;
}
LOGP(DDSP, LOGL_DEBUG, "Sat detection interval is %d ms.\n", amps->sat_samples * 1000 / amps->sender.samplerate);
amps->sat_filter_spl = spl;
/* count SAT tones */
@ -286,7 +290,7 @@ error:
/* Cleanup transceiver instance. */
void dsp_cleanup_sender(amps_t *amps)
{
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Cleanup DSP for treansceiver.\n");
LOGP_CHAN(DDSP, LOGL_DEBUG, "Cleanup DSP for treansceiver.\n");
if (amps->fsk_tx_buffer)
free(amps->fsk_tx_buffer);
@ -399,8 +403,8 @@ again:
rc = amps_encode_frame_fvc(amps, amps->fsk_tx_frame);
else
rc = amps_encode_frame_focc(amps, amps->fsk_tx_frame);
/* check if we have not bit string (change to tx audio)
* we may not store fsk_tx_buffer_pos, because is was reset on a mode achange */
/* check if we have no bit string (change to tx audio / silence)
* we may not store fsk_tx_buffer_pos, because is was reset on a mode change */
if (rc)
return count;
amps->fsk_tx_frame_pos = 0;
@ -473,7 +477,7 @@ static void sat_encode(amps_t *amps, sample_t *samples, int length)
void sender_send(sender_t *sender, sample_t *samples, uint8_t *power, int length)
{
amps_t *amps = (amps_t *) sender;
int count;
int count, input_num;
again:
switch (amps->dsp_mode) {
@ -483,11 +487,24 @@ again:
break;
case DSP_MODE_AUDIO_RX_AUDIO_TX:
memset(power, 1, length);
jitter_load(&amps->sender.dejitter, samples, length);
input_num = samplerate_upsample_input_num(&sender->srstate, length);
{
int16_t spl[input_num];
jitter_load_samples(&sender->dejitter, (uint8_t *)spl, input_num, sizeof(*spl), jitter_conceal_s16, NULL);
int16_to_samples_speech(samples, spl, input_num);
}
compress_audio(&amps->cstate, samples, input_num);
samplerate_upsample(&sender->srstate, samples, input_num, samples, length);
/* pre-emphasis */
if (amps->pre_emphasis)
pre_emphasis(&amps->estate, samples, length);
/* encode sat */
/* encode SAT during call */
sat_encode(amps, samples, length);
break;
case DSP_MODE_AUDIO_RX_SILENCE_TX:
memset(power, 1, length);
memset(samples, 0, sizeof(*samples) * length);
/* encode SAT while waiting for alert response or answer */
sat_encode(amps, samples, length);
break;
case DSP_MODE_AUDIO_RX_FRAME_TX:
@ -496,6 +513,7 @@ again:
* stopped, process again for rest of stream. */
count = fsk_frame(amps, samples, length);
memset(power, 1, count);
// no SAT during frame transmission, according to specs
samples += count;
power += count;
length -= count;
@ -758,7 +776,7 @@ static void sat_decode(amps_t *amps, sample_t *samples, int length)
/* debug SAT */
if (++amps->sat_print == SAT_PRINT) {
PDEBUG_CHAN(DDSP, DEBUG_NOTICE, "SAT level %.2f%% quality %.0f%%\n", sat_level * 100.0, sat_quality * 100.0);
LOGP_CHAN(DDSP, LOGL_NOTICE, "SAT level %.2f%% quality %.0f%%\n", sat_level * 100.0, sat_quality * 100.0);
amps->sat_print = 0;
}
@ -767,8 +785,8 @@ static void sat_decode(amps_t *amps, sample_t *samples, int length)
display_measurements_update(amps->dmp_sat_quality, sat_quality * 100.0, 0.0);
/* debug signaling tone */
if (amps->sender.loopback || debuglevel == DEBUG_DEBUG) {
PDEBUG_CHAN(DDSP, debuglevel, "Signaling Tone level %.2f%% quality %.0f%%\n", sig_level * 100.0, sig_quality * 100.0);
if (amps->sender.loopback || loglevel == LOGL_DEBUG) {
LOGP_CHAN(DDSP, loglevel, "Signaling Tone level %.2f%% quality %.0f%%\n", sig_level * 100.0, sig_quality * 100.0);
}
/* mute if SAT quality or level is below threshold */
@ -784,7 +802,7 @@ static void sat_decode(amps_t *amps, sample_t *samples, int length)
if (amps->sat_detect_count == SAT_DETECT_COUNT) {
amps->sat_detected = 1;
amps->sat_detect_count = 0;
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "SAT signal detected with level=%.0f%%, quality=%.0f%%.\n", sat_level * 100.0, sat_quality * 100.0);
LOGP_CHAN(DDSP, LOGL_DEBUG, "SAT signal detected with level=%.0f%%, quality=%.0f%%.\n", sat_level * 100.0, sat_quality * 100.0);
amps_rx_sat(amps, 1, sat_quality);
}
} else
@ -795,7 +813,7 @@ static void sat_decode(amps_t *amps, sample_t *samples, int length)
if (amps->sat_detect_count == SAT_LOST_COUNT) {
amps->sat_detected = 0;
amps->sat_detect_count = 0;
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "SAT signal lost.\n");
LOGP_CHAN(DDSP, LOGL_DEBUG, "SAT signal lost.\n");
amps_rx_sat(amps, 0, 0.0);
}
} else
@ -809,7 +827,7 @@ static void sat_decode(amps_t *amps, sample_t *samples, int length)
if (amps->sig_detect_count == SIG_DETECT_COUNT) {
amps->sig_detected = 1;
amps->sig_detect_count = 0;
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Signaling Tone detected with level=%.0f%%, quality=%.0f%%.\n", sig_level * 100.0, sig_quality * 100.0);
LOGP_CHAN(DDSP, LOGL_DEBUG, "Signaling Tone detected with level=%.0f%%, quality=%.0f%%.\n", sig_level * 100.0, sig_quality * 100.0);
amps_rx_signaling_tone(amps, 1, sig_quality);
}
} else
@ -820,7 +838,7 @@ static void sat_decode(amps_t *amps, sample_t *samples, int length)
if (amps->sig_detect_count == SIG_LOST_COUNT) {
amps->sig_detected = 0;
amps->sig_detect_count = 0;
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Signaling Tone lost.\n");
LOGP_CHAN(DDSP, LOGL_DEBUG, "Signaling Tone lost.\n");
amps_rx_signaling_tone(amps, 0, 0.0);
}
} else
@ -831,7 +849,7 @@ static void sat_decode(amps_t *amps, sample_t *samples, int length)
static void sender_receive_audio(amps_t *amps, sample_t *samples, int length)
{
transaction_t *trans = amps->trans_list;
sample_t *spl;
sample_t *spl, s;
int max, pos;
int i;
@ -840,7 +858,10 @@ static void sender_receive_audio(amps_t *amps, sample_t *samples, int length)
spl = amps->sat_filter_spl;
pos = amps->sat_filter_pos;
for (i = 0; i < length; i++) {
/* unmute: use buffer, to delay audio, so we do not miss that chunk when SAT is detected */
s = spl[pos];
spl[pos++] = samples[i];
samples[i] = s;
if (pos == max) {
pos = 0;
sat_decode(amps, spl, max);
@ -894,6 +915,7 @@ void sender_receive(sender_t *sender, sample_t *samples, int length, double __at
break;
case DSP_MODE_AUDIO_RX_AUDIO_TX:
case DSP_MODE_AUDIO_RX_FRAME_TX:
case DSP_MODE_AUDIO_RX_SILENCE_TX:
sender_receive_audio(amps, samples, length);
break;
}
@ -902,7 +924,7 @@ void sender_receive(sender_t *sender, sample_t *samples, int length, double __at
/* Reset SAT detection states, so ongoing tone will be detected again. */
static void sat_reset(amps_t *amps, const char *reason)
{
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "SAT detector reset: %s.\n", reason);
LOGP_CHAN(DDSP, LOGL_DEBUG, "SAT detector reset: %s.\n", reason);
amps->sat_detected = 0;
amps->sat_detect_count = 0;
amps->sig_detected = 0;
@ -919,25 +941,30 @@ void amps_set_dsp_mode(amps_t *amps, enum dsp_mode mode, int frame_length)
if (mode == DSP_MODE_FRAME_RX_FRAME_TX) {
/* reset SAT detection */
sat_reset(amps, "Change to FOCC");
PDEBUG_CHAN(DDSP, DEBUG_INFO, "Change mode to FOCC\n");
LOGP_CHAN(DDSP, LOGL_INFO, "Change mode to FOCC\n");
amps->tx_focc_debugged = 0;
}
if (amps->dsp_mode == DSP_MODE_FRAME_RX_FRAME_TX
&& (mode == DSP_MODE_AUDIO_RX_AUDIO_TX || mode == DSP_MODE_AUDIO_RX_FRAME_TX)) {
&& (mode == DSP_MODE_AUDIO_RX_AUDIO_TX || mode == DSP_MODE_AUDIO_RX_FRAME_TX || mode == DSP_MODE_AUDIO_RX_SILENCE_TX)) {
/* reset SAT detection */
sat_reset(amps, "Change from FOCC to FVC");
PDEBUG_CHAN(DDSP, DEBUG_INFO, "Change mode from FOCC to FVC\n");
LOGP_CHAN(DDSP, LOGL_INFO, "Change mode from FOCC to FVC\n");
}
if (amps->dsp_mode == DSP_MODE_OFF
&& (mode == DSP_MODE_AUDIO_RX_AUDIO_TX || mode == DSP_MODE_AUDIO_RX_FRAME_TX)) {
&& (mode == DSP_MODE_AUDIO_RX_AUDIO_TX || mode == DSP_MODE_AUDIO_RX_FRAME_TX || mode == DSP_MODE_AUDIO_RX_SILENCE_TX)) {
/* reset SAT detection */
sat_reset(amps, "Enable FVC");
PDEBUG_CHAN(DDSP, DEBUG_INFO, "Change mode from OFF to FVC\n");
LOGP_CHAN(DDSP, LOGL_INFO, "Change mode from OFF to FVC\n");
}
if (mode == DSP_MODE_OFF) {
/* reset SAT detection */
sat_reset(amps, "Disable FVC");
PDEBUG_CHAN(DDSP, DEBUG_INFO, "Change mode from FVC to OFF\n");
LOGP_CHAN(DDSP, LOGL_INFO, "Change mode from FVC to OFF\n");
}
if (mode == DSP_MODE_AUDIO_RX_AUDIO_TX && amps->dsp_mode != mode)
jitter_reset(&amps->sender.dejitter);
LOGP_CHAN(DDSP, LOGL_DEBUG, "Reset FSK frame transmitter, due to setting dsp mode.\n");
amps->dsp_mode = mode;
if (frame_length)
@ -954,3 +981,27 @@ void amps_set_dsp_mode(amps_t *amps, enum dsp_mode mode, int frame_length)
amps->fsk_tx_frame_pos = 0;
}
/* Receive audio from call instance. */
void call_down_audio(void *decoder, void *decoder_priv, int callref, uint16_t sequence, uint8_t marker, uint32_t timestamp, uint32_t ssrc, uint8_t *payload, int payload_len)
{
sender_t *sender;
amps_t *amps;
for (sender = sender_head; sender; sender = sender->next) {
amps = (amps_t *) sender;
if (amps->trans_list && amps->trans_list->callref == callref)
break;
}
if (!sender)
return;
if (amps->dsp_mode == DSP_MODE_AUDIO_RX_AUDIO_TX) {
jitter_frame_t *jf;
jf = jitter_frame_alloc(decoder, decoder_priv, payload, payload_len, marker, sequence, timestamp, ssrc);
if (jf)
jitter_save(&amps->sender.dejitter, jf);
}
}
void call_down_clock(void) {}

153
src/amps/esn.c Normal file
View File

@ -0,0 +1,153 @@
/* AMPS ESN specification
*
* (C) 2023 by Andreas Eversberg <jolly@eversberg.eu>
* All Rights Reserved
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <pthread.h>
#include <sys/time.h>
#include "../libsample/sample.h"
#include "../liblogging/logging.h"
#include "../libmobile/call.h"
#include "../libmobile/cause.h"
#include <osmocom/cc/message.h>
#include "amps.h"
#include "esn.h"
const char *amps_manufacturer[256] = {
[129] = "Oki",
[130] = "Motorola, Inc.",
[131] = "E.F. Johnson",
[132] = "Hitachi",
[133] = "Fujitsu",
[134] = "Mitsubishi",
[135] = "NEC America, Inc.",
[136] = "Matsushita (Panasonic)",
[137] = "Harris",
[138] = "Toshiba",
[139] = "Kokusai",
[140] = "Clarion Company, Ltd.",
[141] = "GoldStar Products Co.,Ltd.",
[142] = "International Systcom (Novatel)",
[143] = "Ericsson, Inc.",
[144] = "Murata Machinery, Ltd.",
[145] = "DI-BAR Electronics, Inc.",
[146] = "Ericsson Inc. (formerly assigned to General Electric)",
[147] = "Gateway Telephone, Inc.",
[148] = "Robert Bosch Corporation (Blaupunkt)",
[149] = "Universal Cellular, Inc.",
[150] = "Alpine Electronics of America, Inc.",
[151] = "Verma Laboratories",
[152] = "Japan Radio Co.,Ltd.",
[153] = "CM Communications Incorporated",
[154] = "Sony Corporation (Japan)",
[155] = "Tama Denki Company, Ltd.",
[156] = "Mobira (Nokia-Kinex)",
[157] = "Ericsson GE Mobile Communications, Inc.",
[158] = "AT&T Technologies, Inc.",
[159] = "QUALCOMM, Incorporated",
[160] = "Hyundai",
[161] = "Satellite Technology Services, Inc.",
[162] = "Technophone Limited",
[163] = "Yupiteru Industries Company Ltd.",
[164] = "Hughes Network Systems",
[165] = "TMC Company Limited (Nokia)",
[166] = "Clarion Manufacturing Corporation of America",
[167] = "Mansoor Electronics Limited",
[168] = "Motorola International",
[169] = "Otron Corporation",
[170] = "Philips Telecom Equipment Corporation",
[171] = "Philips Circuit Assemblies",
[172] = "Uniden Corporation of America",
[173] = "Uniden Corporation - Japan",
[174] = "Shintom West Corporation of America",
[175] = "Tottori Sanyo Electric Co. Ltd.",
[176] = "Samsung Communications",
[177] = "INFA Telecom Canada, Inc.",
[178] = "Emptel Electronics Company Ltd.",
[179] = "**Unassigned**",
[180] = "ASCNet",
[181] = "Yaesu USA",
[182] = "Tecom Co. Ltd.",
[183] = "Omni Telecommunications, Inc. (formerly assigned to Valor Electronics, Inc.)",
[184] = "Royal Information Electronics Co. Ltd.",
[185] = "Tele Digital Development, Inc. (formerly assigned to Cumulus Corporation.)",
[186] = "DNC",
[187] = "**Unassigned**",
[188] = "Myday Technology, Ltd.",
[189] = "NEC America, Inc.",
[190] = "Kyocera Corporation",
[191] = "Digital Security Controls",
[192] = "CTCELL Digital, Inc.",
[193] = "Matsushita Communication Industrial Corporation of America",
[194] = "HS Electronics Corporation",
[195] = "Motorola, Inc.",
[196] = "Pacific Communication Sciences, Inc.",
[197] = "Maxon Systems, Inc., (London) Ltd.",
[198] = "Hongsheng Electronics Co., Ltd.",
[199] = "M/ACOM",
[200] = "CHANNLE LINK Incorporation",
[201] = "L.G. Information & Communications (formerly assigned to Goldstar Information & Communications, Ltd.)",
[202] = "Intel Corporation",
[203] = "Air Communications, Inc.",
[204] = "Ericsson GE Mobile Communications Inc.",
[205] = "Goldtron RF PTE Ltd.",
[206] = "Sierra Wireless Inc.",
[207] = "Mitsubishi International Corp.",
[208] = "JRC International, Inc.",
[209] = "Sapura Holdings SDN. BHD.",
[210] = "Inex Technologies, Inc.",
[211] = "Sony Electronics (U.S.A.)",
[212] = "Motorola, Inc.",
[213] = "Motorola, Inc.",
[214] = "Philips Semiconductors",
[215] = "Carillon Corp.",
[216] = "Nippondenso America, Inc.",
[217] = "International Business Machines Corporation",
[218] = "Nokia (Hong Kong)",
[219] = "Nokia (TMC Co. Ltd.)",
[220] = "TEMIC",
[221] = "Northern Telecom",
[222] = "Telrad Telecommunications Ltd.",
[223] = "Motorola, Inc.",
[224] = "Motorola, Inc.",
[225] = "Telital s.r.l.",
[226] = "Nokia (Manau, Brazil)",
[227] = "Stanilite Pacific",
[228] = "Philips Consumer Communications",
[229] = "NEC America, Inc.",
[230] = "TELLULAR Corporation",
[231] = "Ericsson Inc.",
};
const char *esn_to_string(uint32_t esn)
{
uint8_t mfr;
uint32_t serial;
static char esn_string[256];
amps_decode_esn(esn, &mfr, &serial);
if (amps_manufacturer[mfr])
snprintf(esn_string, sizeof(esn_string), "0x%08x or %d-%06d (%s)", esn, mfr, serial, amps_manufacturer[mfr]);
else
snprintf(esn_string, sizeof(esn_string), "0x%08x or %d-%06d", esn, mfr, serial);
return esn_string;
}

3
src/amps/esn.h Normal file
View File

@ -0,0 +1,3 @@
const char *esn_to_string(uint32_t esn);

View File

@ -27,7 +27,8 @@
#include <math.h>
#include <inttypes.h>
#include "../libsample/sample.h"
#include "../libdebug/debug.h"
#include "../liblogging/logging.h"
#include "../libmobile/get_time.h"
#include "amps.h"
#include "dsp.h"
#include "frame.h"
@ -2707,7 +2708,7 @@ static uint64_t amps_encode_word(frame_t *frame, struct def_word *w, int debug)
int i, t4 = 0;
#ifdef DEBUG_ALL_MESSAGES
debug=1;
debug = 1;
#endif
memset(spaces, ' ', ie_desc_max_len);
@ -2718,7 +2719,8 @@ static uint64_t amps_encode_word(frame_t *frame, struct def_word *w, int debug)
for (i = 0; w->ie[i].name; i++)
sum_bits += w->ie[i].bits;
PDEBUG(DFRAME, (debug >= 0) ? DEBUG_INFO : DEBUG_DEBUG, "Transmit: %s\n", w->name);
if (debug)
LOGP(DFRAME, LOGL_INFO, "Transmit: %s\n", w->name);
word = 0;
for (i = 0; w->ie[i].name; i++) {
bits = w->ie[i].bits;
@ -2727,26 +2729,26 @@ static uint64_t amps_encode_word(frame_t *frame, struct def_word *w, int debug)
else
value = frame->ie[w->ie[i].ie];
word = (word << bits) | (value & cut_bits[bits]);
if (debug >= 0) {
if (debug) {
if (amps_ie_desc[w->ie[i].ie].decoder)
PDEBUG(DFRAME, DEBUG_DEBUG, " %s%s: %" PRIu64 " = %s (%s)\n", spaces + strlen(w->ie[i].name), w->ie[i].name, value, amps_ie_desc[w->ie[i].ie].decoder(value), amps_ie_desc[w->ie[i].ie].desc);
LOGP(DFRAME, LOGL_DEBUG, " %s%s: %" PRIu64 " = %s (%s)\n", spaces + strlen(w->ie[i].name), w->ie[i].name, value, amps_ie_desc[w->ie[i].ie].decoder(value), amps_ie_desc[w->ie[i].ie].desc);
else
PDEBUG(DFRAME, DEBUG_DEBUG, " %s%s: %" PRIu64 " (%s)\n", spaces + strlen(w->ie[i].name), w->ie[i].name, value, amps_ie_desc[w->ie[i].ie].desc);
LOGP(DFRAME, LOGL_DEBUG, " %s%s: %" PRIu64 " (%s)\n", spaces + strlen(w->ie[i].name), w->ie[i].name, value, amps_ie_desc[w->ie[i].ie].desc);
}
/* show result for 3 IEs of table 4 */
if (w->ie[i].ie == AMPS_IE_LOCAL_MSG_TYPE || w->ie[i].ie == AMPS_IE_ORDQ || w->ie[i].ie == AMPS_IE_ORDER)
t4++;
if (t4 == 3) {
t4 = 0;
if (debug >= 0)
PDEBUG(DFRAME, DEBUG_DEBUG, " %s--> %s\n", spaces, amps_table4_name(frame->ie[AMPS_IE_LOCAL_MSG_TYPE], frame->ie[AMPS_IE_ORDQ], frame->ie[AMPS_IE_ORDER]));
if (debug)
LOGP(DFRAME, LOGL_DEBUG, " %s--> %s\n", spaces, amps_table4_name(frame->ie[AMPS_IE_LOCAL_MSG_TYPE], frame->ie[AMPS_IE_ORDQ], frame->ie[AMPS_IE_ORDER]));
}
}
return word;
}
static uint64_t amps_encode_control_filler(amps_t *amps, uint8_t dcc, uint8_t cmac, uint8_t sdcc1, uint8_t sdcc2, uint8_t wfom)
static uint64_t amps_encode_control_filler(amps_t *amps, uint8_t dcc, uint8_t cmac, uint8_t sdcc1, uint8_t sdcc2, uint8_t wfom, int debug)
{
frame_t frame;
@ -2767,10 +2769,10 @@ static uint64_t amps_encode_control_filler(amps_t *amps, uint8_t dcc, uint8_t cm
} else
frame.ie[AMPS_IE_1111] = 15;
frame.ie[AMPS_IE_OHD] = 1;
return amps_encode_word(&frame, &control_filler, -1);
return amps_encode_word(&frame, &control_filler, debug);
}
uint64_t amps_encode_word1_system(uint8_t dcc, uint16_t sid1, uint8_t ep, uint8_t auth, uint8_t pci, uint8_t nawc)
uint64_t amps_encode_word1_system(uint8_t dcc, uint16_t sid1, uint8_t ep, uint8_t auth, uint8_t pci, uint8_t nawc, int debug)
{
frame_t frame;
@ -2783,10 +2785,10 @@ uint64_t amps_encode_word1_system(uint8_t dcc, uint16_t sid1, uint8_t ep, uint8_
frame.ie[AMPS_IE_PCI] = pci;
frame.ie[AMPS_IE_NAWC] = nawc;
frame.ie[AMPS_IE_OHD] = 6;
return amps_encode_word(&frame, &amps_word1_system_parameter_overhead, -1);
return amps_encode_word(&frame, &amps_word1_system_parameter_overhead, debug);
}
uint64_t tacs_encode_word1_system(uint8_t dcc, uint16_t aid1, uint8_t ep, uint8_t auth, uint8_t pci, uint8_t nawc)
uint64_t tacs_encode_word1_system(uint8_t dcc, uint16_t aid1, uint8_t ep, uint8_t auth, uint8_t pci, uint8_t nawc, int debug)
{
frame_t frame;
@ -2799,10 +2801,10 @@ uint64_t tacs_encode_word1_system(uint8_t dcc, uint16_t aid1, uint8_t ep, uint8_
frame.ie[AMPS_IE_PCI] = pci;
frame.ie[AMPS_IE_NAWC] = nawc;
frame.ie[AMPS_IE_OHD] = 6;
return amps_encode_word(&frame, &tacs_word1_system_parameter_overhead, -1);
return amps_encode_word(&frame, &tacs_word1_system_parameter_overhead, debug);
}
uint64_t amps_encode_word2_system(uint8_t dcc, uint8_t s, uint8_t e, uint8_t regh, uint8_t regr, uint8_t dtx, uint8_t n_1, uint8_t rcf, uint8_t cpa, uint8_t cmax_1, uint8_t end)
uint64_t amps_encode_word2_system(uint8_t dcc, uint8_t s, uint8_t e, uint8_t regh, uint8_t regr, uint8_t dtx, uint8_t n_1, uint8_t rcf, uint8_t cpa, uint8_t cmax_1, uint8_t end, int debug)
{
frame_t frame;
@ -2820,10 +2822,10 @@ uint64_t amps_encode_word2_system(uint8_t dcc, uint8_t s, uint8_t e, uint8_t reg
frame.ie[AMPS_IE_CMAX_1] = cmax_1;
frame.ie[AMPS_IE_END] = end;
frame.ie[AMPS_IE_OHD] = 7;
return amps_encode_word(&frame, &word2_system_parameter_overhead, -1);
return amps_encode_word(&frame, &word2_system_parameter_overhead, debug);
}
uint64_t amps_encode_registration_id(uint8_t dcc, uint32_t regid, uint8_t end)
uint64_t amps_encode_registration_id(uint8_t dcc, uint32_t regid, uint8_t end, int debug)
{
frame_t frame;
@ -2833,10 +2835,10 @@ uint64_t amps_encode_registration_id(uint8_t dcc, uint32_t regid, uint8_t end)
frame.ie[AMPS_IE_REGID] = regid;
frame.ie[AMPS_IE_END] = end;
frame.ie[AMPS_IE_OHD] = 0;
return amps_encode_word(&frame, &registration_id, -1);
return amps_encode_word(&frame, &registration_id, debug);
}
uint64_t amps_encode_registration_increment(uint8_t dcc, uint16_t regincr, uint8_t end)
uint64_t amps_encode_registration_increment(uint8_t dcc, uint16_t regincr, uint8_t end, int debug)
{
frame_t frame;
@ -2847,10 +2849,10 @@ uint64_t amps_encode_registration_increment(uint8_t dcc, uint16_t regincr, uint8
frame.ie[AMPS_IE_REGINCR] = regincr;
frame.ie[AMPS_IE_END] = end;
frame.ie[AMPS_IE_OHD] = 4;
return amps_encode_word(&frame, &registration_increment_global_action, -1);
return amps_encode_word(&frame, &registration_increment_global_action, debug);
}
uint64_t amps_encode_location_area(uint8_t dcc, uint8_t pureg, uint8_t pdreg, uint8_t lreg, uint16_t locaid, uint8_t end)
uint64_t amps_encode_location_area(uint8_t dcc, uint8_t pureg, uint8_t pdreg, uint8_t lreg, uint16_t locaid, uint8_t end, int debug)
{
frame_t frame;
@ -2864,10 +2866,10 @@ uint64_t amps_encode_location_area(uint8_t dcc, uint8_t pureg, uint8_t pdreg, ui
frame.ie[AMPS_IE_LOCAID] = locaid;
frame.ie[AMPS_IE_END] = end;
frame.ie[AMPS_IE_OHD] = 4;
return amps_encode_word(&frame, &location_area_global_action, -1);
return amps_encode_word(&frame, &location_area_global_action, debug);
}
uint64_t amps_encode_new_access_channel_set(uint8_t dcc, uint16_t newacc, uint8_t end)
uint64_t amps_encode_new_access_channel_set(uint8_t dcc, uint16_t newacc, uint8_t end, int debug)
{
frame_t frame;
@ -2878,10 +2880,10 @@ uint64_t amps_encode_new_access_channel_set(uint8_t dcc, uint16_t newacc, uint8_
frame.ie[AMPS_IE_NEWACC] = newacc;
frame.ie[AMPS_IE_END] = end;
frame.ie[AMPS_IE_OHD] = 4;
return amps_encode_word(&frame, &new_access_channel_set_global_action, -1);
return amps_encode_word(&frame, &new_access_channel_set_global_action, debug);
}
uint64_t amps_encode_overload_control(uint8_t dcc, uint8_t *olc, uint8_t end)
uint64_t amps_encode_overload_control(uint8_t dcc, uint8_t *olc, uint8_t end, int debug)
{
frame_t frame;
@ -2907,10 +2909,10 @@ uint64_t amps_encode_overload_control(uint8_t dcc, uint8_t *olc, uint8_t end)
frame.ie[AMPS_IE_OLC_15] = olc[15];
frame.ie[AMPS_IE_END] = end;
frame.ie[AMPS_IE_OHD] = 4;
return amps_encode_word(&frame, &overload_control_global_action, -1);
return amps_encode_word(&frame, &overload_control_global_action, debug);
}
uint64_t amps_encode_access_type(uint8_t dcc, uint8_t bis, uint8_t pci_home, uint8_t pci_roam, uint8_t bspc, uint8_t bscap, uint8_t end)
uint64_t amps_encode_access_type(uint8_t dcc, uint8_t bis, uint8_t pci_home, uint8_t pci_roam, uint8_t bspc, uint8_t bscap, uint8_t end, int debug)
{
frame_t frame;
@ -2925,10 +2927,10 @@ uint64_t amps_encode_access_type(uint8_t dcc, uint8_t bis, uint8_t pci_home, uin
frame.ie[AMPS_IE_BSCAP] = bscap;
frame.ie[AMPS_IE_END] = end;
frame.ie[AMPS_IE_OHD] = 4;
return amps_encode_word(&frame, &access_type_parameters_global_action, -1);
return amps_encode_word(&frame, &access_type_parameters_global_action, debug);
}
uint64_t amps_encode_access_attempt(uint8_t dcc, uint8_t maxbusy_pgr, uint8_t maxsztr_pgr, uint8_t maxbusy_other, uint8_t maxsztr_other, uint8_t end)
uint64_t amps_encode_access_attempt(uint8_t dcc, uint8_t maxbusy_pgr, uint8_t maxsztr_pgr, uint8_t maxbusy_other, uint8_t maxsztr_other, uint8_t end, int debug)
{
frame_t frame;
@ -2942,7 +2944,7 @@ uint64_t amps_encode_access_attempt(uint8_t dcc, uint8_t maxbusy_pgr, uint8_t ma
frame.ie[AMPS_IE_MAXSZTR_OTHER] = maxsztr_other;
frame.ie[AMPS_IE_END] = end;
frame.ie[AMPS_IE_OHD] = 4;
return amps_encode_word(&frame, &access_attempt_parameters_global_action, -1);
return amps_encode_word(&frame, &access_attempt_parameters_global_action, debug);
}
static uint64_t amps_encode_word1_abbreviated_address_word(uint8_t dcc, uint32_t min1, int multiple)
@ -2956,7 +2958,7 @@ static uint64_t amps_encode_word1_abbreviated_address_word(uint8_t dcc, uint32_t
frame.ie[AMPS_IE_T1T2] = 0;
frame.ie[AMPS_IE_DCC] = dcc;
frame.ie[AMPS_IE_MIN1] = min1;
return amps_encode_word(&frame, &word1_abbreviated_address_word, DEBUG_INFO);
return amps_encode_word(&frame, &word1_abbreviated_address_word, 1);
}
static uint64_t amps_encode_word2_extended_address_word_a(uint16_t min2, uint8_t msg_type, uint8_t ordq, uint8_t order)
@ -2971,7 +2973,7 @@ static uint64_t amps_encode_word2_extended_address_word_a(uint16_t min2, uint8_t
frame.ie[AMPS_IE_LOCAL_MSG_TYPE] = msg_type;
frame.ie[AMPS_IE_ORDQ] = ordq;
frame.ie[AMPS_IE_ORDER] = order;
return amps_encode_word(&frame, &word2_extended_address_word_a, DEBUG_INFO);
return amps_encode_word(&frame, &word2_extended_address_word_a, 1);
}
static uint64_t amps_encode_word2_extended_address_word_b(uint8_t scc, uint16_t min2, uint8_t vmac, uint16_t chan)
@ -2984,7 +2986,7 @@ static uint64_t amps_encode_word2_extended_address_word_b(uint8_t scc, uint16_t
frame.ie[AMPS_IE_MIN2] = min2;
frame.ie[AMPS_IE_VMAC] = vmac;
frame.ie[AMPS_IE_CHAN] = chan;
return amps_encode_word(&frame, &word2_extended_address_word_b, DEBUG_INFO);
return amps_encode_word(&frame, &word2_extended_address_word_b, 1);
}
static uint64_t amps_encode_mobile_station_control_message_word1_a(uint8_t pscc, uint8_t msg_type, uint8_t ordq, uint8_t order)
@ -2999,7 +3001,7 @@ static uint64_t amps_encode_mobile_station_control_message_word1_a(uint8_t pscc,
frame.ie[AMPS_IE_LOCAL_MSG_TYPE] = msg_type;
frame.ie[AMPS_IE_ORDQ] = ordq;
frame.ie[AMPS_IE_ORDER] = order;
return amps_encode_word(&frame, &mobile_station_control_message_word1_a, DEBUG_INFO);
return amps_encode_word(&frame, &mobile_station_control_message_word1_a, 1);
}
static uint64_t amps_encode_mobile_station_control_message_word1_b(uint8_t scc, uint8_t pscc, uint8_t dtx, uint8_t pvi, uint8_t mem, uint8_t vmac, uint16_t chan)
@ -3016,7 +3018,38 @@ static uint64_t amps_encode_mobile_station_control_message_word1_b(uint8_t scc,
frame.ie[AMPS_IE_MEM] = mem;
frame.ie[AMPS_IE_VMAC] = vmac;
frame.ie[AMPS_IE_CHAN] = chan;
return amps_encode_word(&frame, &mobile_station_control_message_word1_b, DEBUG_INFO);
return amps_encode_word(&frame, &mobile_station_control_message_word1_b, 1);
}
static uint64_t amps_encode_word2_first_alert_with_info_word(uint8_t rl_w, uint8_t signal, uint8_t cpn_rl, uint8_t pi, uint8_t si)
{
frame_t frame;
memset(&frame, 0, sizeof(frame));
frame.ie[AMPS_IE_T1T2] = 1;
frame.ie[AMPS_IE_RL_W] = rl_w;
frame.ie[AMPS_IE_SIGNAL] = signal;
frame.ie[AMPS_IE_CPN_RL] = cpn_rl;
frame.ie[AMPS_IE_PI] = pi;
frame.ie[AMPS_IE_SI] = si;
return amps_encode_word(&frame, &word2_first_alert_with_info_word, 1);
}
static uint64_t amps_encode_wordn_n_minus_1th_alert_with_info_word(const char *character)
{
frame_t frame;
memset(&frame, 0, sizeof(frame));
frame.ie[AMPS_IE_T1T2] = 1;
if (character[0]) {
frame.ie[AMPS_IE_CHARACTER_1] = character[0];
if (character[1]) {
frame.ie[AMPS_IE_CHARACTER_2] = character[1];
if (character[2])
frame.ie[AMPS_IE_CHARACTER_3] = character[2];
}
}
return amps_encode_word(&frame, &wordn_n_minus_1th_alert_with_info_word, 1);
}
/* decoder function of a word */
@ -3038,22 +3071,22 @@ static frame_t *amps_decode_word(uint64_t word, struct def_word *w)
for (i = 0; w->ie[i].name; i++)
bits_left += w->ie[i].bits;
PDEBUG(DFRAME, DEBUG_INFO, "Received: %s\n", w->name);
LOGP(DFRAME, LOGL_INFO, "Received: %s\n", w->name);
for (i = 0; w->ie[i].name; i++) {
bits = w->ie[i].bits;
bits_left -= bits;
value = (word >> bits_left) & cut_bits[bits];
frame.ie[w->ie[i].ie] = value;
if (amps_ie_desc[w->ie[i].ie].decoder)
PDEBUG(DFRAME, DEBUG_DEBUG, " %s%s: %" PRIu64 " = %s (%s)\n", spaces + strlen(w->ie[i].name), w->ie[i].name, value, amps_ie_desc[w->ie[i].ie].decoder(value), amps_ie_desc[w->ie[i].ie].desc);
LOGP(DFRAME, LOGL_DEBUG, " %s%s: %" PRIu64 " = %s (%s)\n", spaces + strlen(w->ie[i].name), w->ie[i].name, value, amps_ie_desc[w->ie[i].ie].decoder(value), amps_ie_desc[w->ie[i].ie].desc);
else
PDEBUG(DFRAME, DEBUG_DEBUG, " %s%s: %" PRIu64 " (%s)\n", spaces + strlen(w->ie[i].name), w->ie[i].name, value, amps_ie_desc[w->ie[i].ie].desc);
LOGP(DFRAME, LOGL_DEBUG, " %s%s: %" PRIu64 " (%s)\n", spaces + strlen(w->ie[i].name), w->ie[i].name, value, amps_ie_desc[w->ie[i].ie].desc);
/* show result for 3 IEs of table 4 */
if (w->ie[i].ie == AMPS_IE_LOCAL_MSG_TYPE || w->ie[i].ie == AMPS_IE_ORDQ || w->ie[i].ie == AMPS_IE_ORDER)
t4++;
if (t4 == 3) {
t4 = 0;
PDEBUG(DFRAME, DEBUG_DEBUG, " %s--> %s\n", spaces, amps_table4_name(frame.ie[AMPS_IE_LOCAL_MSG_TYPE], frame.ie[AMPS_IE_ORDQ], frame.ie[AMPS_IE_ORDER]));
LOGP(DFRAME, LOGL_DEBUG, " %s--> %s\n", spaces, amps_table4_name(frame.ie[AMPS_IE_LOCAL_MSG_TYPE], frame.ie[AMPS_IE_ORDQ], frame.ie[AMPS_IE_ORDER]));
}
}
@ -3071,7 +3104,7 @@ static void amps_decode_word_focc(amps_t *amps, uint64_t word)
/* control message */
if (t1t2 != 3) {
PDEBUG_CHAN(DFRAME, DEBUG_INFO, "Received Mobile Station Control Message (T1T2 = %d)\n", t1t2);
LOGP_CHAN(DFRAME, LOGL_INFO, "Received Mobile Station Control Message (T1T2 = %d)\n", t1t2);
if (t1t2 == 1)
amps->rx_focc_word_count = 1;
if (t1t2 == 0 || t1t2 == 1) {
@ -3088,7 +3121,7 @@ static void amps_decode_word_focc(amps_t *amps, uint64_t word)
w = &word2_extended_address_word_b;
goto decode;
}
PDEBUG_CHAN(DFRAME, DEBUG_INFO, "Decoding of more than 2 Control messages not supported\n");
LOGP_CHAN(DFRAME, LOGL_INFO, "Decoding of more than 2 Control messages not supported\n");
}
return;
}
@ -3156,14 +3189,14 @@ static void amps_decode_word_focc(amps_t *amps, uint64_t word)
decode:
if (!w) {
PDEBUG_CHAN(DFRAME, DEBUG_INFO, "Received Illegal Overhead Message\n");
LOGP_CHAN(DFRAME, LOGL_INFO, "Received Illegal Overhead Message\n");
return;
}
frame = amps_decode_word(word, w);
/* show control filler delay */
if (amps->sender.loopback && ohd == 1)
PDEBUG_CHAN(DDSP, DEBUG_NOTICE, "Round trip delay is %.3f seconds\n", amps->when_received - amps->when_transmitted[frame->ie[AMPS_IE_1111]]);
LOGP_CHAN(DDSP, LOGL_NOTICE, "Round trip delay is %.3f seconds\n", amps->when_received - amps->when_transmitted[frame->ie[AMPS_IE_1111]]);
}
/* get word from data bits and call decoder function
@ -3182,24 +3215,24 @@ static int amps_decode_word_recc(amps_t *amps, uint64_t word, int first)
amps->rx_recc_word_count = 0;
amps->rx_recc_nawc = nawc;
if (f == 0) {
PDEBUG_CHAN(DFRAME, DEBUG_NOTICE, "Received first word, but F bit is not set.\n");
LOGP_CHAN(DFRAME, LOGL_NOTICE, "Received first word, but F bit is not set.\n");
return 0;
}
} else {
if (f == 1) {
PDEBUG_CHAN(DFRAME, DEBUG_NOTICE, "Received additional word, but F bit is set.\n");
LOGP_CHAN(DFRAME, LOGL_NOTICE, "Received additional word, but F bit is set.\n");
return 0;
}
amps->rx_recc_nawc--;
if (amps->rx_recc_nawc != nawc) {
PDEBUG_CHAN(DFRAME, DEBUG_NOTICE, "Received additional word with NAWC mismatch!\n");
LOGP_CHAN(DFRAME, LOGL_NOTICE, "Received additional word with NAWC mismatch!\n");
}
}
msg_count = amps->rx_recc_word_count;
if (msg_count == 8) {
PDEBUG_CHAN(DFRAME, DEBUG_NOTICE, "Received too many words.\n");
LOGP_CHAN(DFRAME, LOGL_NOTICE, "Received too many words.\n");
return 0;
}
@ -3236,7 +3269,7 @@ static int amps_decode_word_recc(amps_t *amps, uint64_t word, int first)
if (!w) {
PDEBUG_CHAN(DFRAME, DEBUG_INFO, "Received Illegal RECC Message\n");
LOGP_CHAN(DFRAME, LOGL_INFO, "Received Illegal RECC Message\n");
goto done;
}
@ -3301,7 +3334,7 @@ static int amps_decode_word_recc(amps_t *amps, uint64_t word, int first)
amps->rx_recc_dialing[31] = digit2number[frame->ie[AMPS_IE_DIGIT_32]];
}
PDEBUG_CHAN(DFRAME, DEBUG_INFO, "expecting %d more word(s) to come\n", amps->rx_recc_nawc);
LOGP_CHAN(DFRAME, LOGL_INFO, "expecting %d more word(s) to come\n", amps->rx_recc_nawc);
if (msg_count >= 3 && amps->rx_recc_nawc == 0) {
/* if no digit messages are present, send NULL as dial string (paging reply) */
@ -3345,7 +3378,7 @@ static void amps_encode_focc_bits(uint64_t word_a, uint64_t word_b, char *bits)
memcpy(bits + 0, dotting, 10);
bits[10] = 'i';
strcpy(bits + 11, sync_word);
memcpy(bits + 11, sync_word, 11);
bits[22] = 'i';
k = 23;
for (i = 0; i < 5; i++) {
@ -3365,22 +3398,22 @@ static void amps_encode_focc_bits(uint64_t word_a, uint64_t word_b, char *bits)
if (k != 463)
abort();
bits[463] = '\0';
bits[k] = '\0';
if (debuglevel == DEBUG_DEBUG) {
#ifdef BIT_DEBUGGING
if (loglevel == LOGL_DEBUG) {
char text[64];
strncpy(text, bits, 23);
text[23] = '\0';
#ifdef BIT_DEBUGGING
PDEBUG(DFRAME, DEBUG_INFO, "TX FOCC: %s\n", text);
LOGP(DFRAME, LOGL_INFO, "TX FOCC: %s\n", text);
for (i = 0; i < 10; i++) {
strncpy(text, bits + 23 + i * 44, 44);
text[44] = '\0';
PDEBUG(DFRAME, DEBUG_DEBUG, " word %c - %s\n", (i & 1) ? 'b' : 'a', text);
LOGP(DFRAME, LOGL_DEBUG, " word %c - %s\n", (i & 1) ? 'b' : 'a', text);
}
#endif
}
#endif
}
static void amps_encode_fvc_bits(uint64_t word_a, char *bits)
@ -3397,19 +3430,19 @@ static void amps_encode_fvc_bits(uint64_t word_a, char *bits)
memcpy(bits + k, dotting, 37);
k += 37;
}
strcpy(bits + k, sync_word);
memcpy(bits + k, sync_word, 11);
k += 11;
for (j = 39; j >= 0; j--)
bits[k++] = ((word_a >> j) & 1) + '0';
}
if (k != 1032)
abort();
bits[1032] = '\0';
bits[k] = '\0';
#ifdef BIT_DEBUGGING
if (debuglevel == DEBUG_DEBUG) {
PDEBUG(DFRAME, DEBUG_INFO, "TX FVC: %s\n", bits);
if (loglevel == LOGL_DEBUG) {
LOGP(DFRAME, LOGL_INFO, "TX FVC: %s\n", bits);
}
#endif
}
@ -3417,13 +3450,14 @@ static void amps_encode_fvc_bits(uint64_t word_a, char *bits)
int amps_encode_frame_focc(amps_t *amps, char *bits)
{
uint64_t word;
int debug = !amps->tx_focc_debugged;
/* init overhead train */
if (amps->tx_focc_frame_count == 0)
prepare_sysinfo(&amps->si);
/* send overhead train */
if (amps->si.num) {
word = get_sysinfo(&amps->si);
word = get_sysinfo(&amps->si, debug);
if (++amps->tx_focc_frame_count >= amps->si.overhead_repeat)
amps->tx_focc_frame_count = 0;
goto send;
@ -3474,9 +3508,12 @@ int amps_encode_frame_focc(amps_t *amps, char *bits)
}
/* send filler */
word = amps_encode_control_filler(amps, amps->si.dcc, amps->si.filler.cmac, amps->si.filler.sdcc1, amps->si.filler.sdcc2, amps->si.filler.wfom);
word = amps_encode_control_filler(amps, amps->si.dcc, amps->si.filler.cmac, amps->si.filler.sdcc1, amps->si.filler.sdcc2, amps->si.filler.wfom, debug);
if (++amps->tx_focc_frame_count >= amps->si.overhead_repeat)
amps->tx_focc_frame_count = 0;
if (debug)
LOGP_CHAN(DFRAME, LOGL_INFO, "Subsequent system/filler frames are not show, to prevent flooding the output.\n");
amps->tx_focc_debugged = 1;
send:
amps_encode_focc_bits(word, word, bits);
@ -3497,7 +3534,16 @@ int amps_encode_frame_fvc(amps_t *amps, char *bits)
amps->tx_fvc_ordq = trans->ordq;
amps->tx_fvc_order = trans->order;
amps->tx_fvc_chan = trans->chan;
strncpy(amps->tx_fvc_callerid, trans->caller_id, sizeof(amps->tx_fvc_callerid) - 1);
amps->tx_fvc_callerid_signal = 1;
amps->tx_fvc_callerid_screen = 3;
if (trans->caller_id[0])
amps->tx_fvc_callerid_present = 0;
else
amps->tx_fvc_callerid_signal = 1;
amps->tx_fvc_send = 1;
amps->tx_fvc_word_count = 0;
amps->tx_fvc_word_repeat = 0;
}
/* on change of dsp mode */
if (amps->dsp_mode != DSP_MODE_AUDIO_RX_FRAME_TX)
@ -3506,11 +3552,32 @@ int amps_encode_frame_fvc(amps_t *amps, char *bits)
/* send scheduled mobile control message */
if (amps->tx_fvc_send) {
amps->tx_fvc_send = 0;
if (amps->tx_fvc_chan)
word = amps_encode_mobile_station_control_message_word1_b(amps->sat, amps->sat, (amps->si.word2.dtx) ? 1 : 0, 0, 0, amps->si.vmac, amps->tx_fvc_chan);
else
word = amps_encode_mobile_station_control_message_word1_a(amps->sat, amps->tx_fvc_msg_type, amps->tx_fvc_ordq, amps->tx_fvc_order);
if (amps->tx_fvc_word_count == 0) {
if (amps->tx_fvc_chan)
word = amps_encode_mobile_station_control_message_word1_b(amps->sat, amps->sat, (amps->si.word2.dtx) ? 1 : 0, 0, 0, amps->si.vmac, amps->tx_fvc_chan);
else
word = amps_encode_mobile_station_control_message_word1_a(amps->sat, amps->tx_fvc_msg_type, amps->tx_fvc_ordq, amps->tx_fvc_order);
/* done, if we don't have ALERTING with info */
if (amps->tx_fvc_order != 17)
amps->tx_fvc_send = 0;
} else if (amps->tx_fvc_word_count == 1) {
int cpn_rl, rl_w;
/* number of characters */
cpn_rl = strlen(amps->tx_fvc_callerid);
/* number of frames that are required to hold number of characters */
rl_w = (cpn_rl + 2) / 3;
word = amps_encode_word2_first_alert_with_info_word(rl_w, amps->tx_fvc_callerid_signal, cpn_rl, amps->tx_fvc_callerid_present, amps->tx_fvc_callerid_screen);
if (cpn_rl == 0)
amps->tx_fvc_send = 0;
} else {
const char *callerid;
/* chunk of caller ID */
callerid = amps->tx_fvc_callerid + (amps->tx_fvc_word_count - 2) * 3;
word = amps_encode_wordn_n_minus_1th_alert_with_info_word(callerid);
if (strlen(callerid) <= 3)
amps->tx_fvc_send = 0;
}
amps->tx_fvc_word_count++;
} else
return 1;
@ -3560,17 +3627,17 @@ static void amps_decode_bits_focc(amps_t *amps, const char *bits)
else
idle = 0;
PDEBUG_CHAN(DFRAME, DEBUG_INFO, "RX FOCC: B/I = %s\n", (idle) ? "idle" : "busy");
if (debuglevel == DEBUG_DEBUG) {
LOGP_CHAN(DFRAME, LOGL_INFO, "RX FOCC: B/I = %s\n", (idle) ? "idle" : "busy");
if (loglevel == LOGL_DEBUG) {
char text[64];
for (i = 0; i < 10; i++) {
strncpy(text, bits + i * 44, 44);
text[44] = '\0';
if ((i & 1) == 0)
PDEBUG_CHAN(DFRAME, DEBUG_DEBUG, " word a - %s%s\n", text, (crc_a_ok[i >> 1]) ? " ok" : " BAD CRC!");
LOGP_CHAN(DFRAME, LOGL_DEBUG, " word a - %s%s\n", text, (crc_a_ok[i >> 1]) ? " ok" : " BAD CRC!");
else
PDEBUG_CHAN(DFRAME, DEBUG_DEBUG, " word b - %s%s\n", text, (crc_b_ok[i >> 1]) ? " ok" : " BAD CRC!");
LOGP_CHAN(DFRAME, LOGL_DEBUG, " word b - %s%s\n", text, (crc_b_ok[i >> 1]) ? " ok" : " BAD CRC!");
}
}
@ -3646,7 +3713,7 @@ static int amps_decode_bits_recc(amps_t *amps, const char *bits, int first)
crc_ok++;
}
if (crc_ok) {
PDEBUG_CHAN(DFRAME, DEBUG_NOTICE, "Seems we RX FOCC frame due to loopback, ignoring!\n");
LOGP_CHAN(DFRAME, LOGL_NOTICE, "Seems we RX FOCC frame due to loopback, ignoring!\n");
return 0;
}
bits_ -= 221;
@ -3658,24 +3725,24 @@ static int amps_decode_bits_recc(amps_t *amps, const char *bits, int first)
}
if (first) {
if (debuglevel == DEBUG_DEBUG || crc_ok_count > 0) {
PDEBUG_CHAN(DFRAME, DEBUG_INFO, "RX RECC: DCC=%d (%d of 5 CRCs are ok)\n", dcc, crc_ok_count);
if (loglevel == LOGL_DEBUG || crc_ok_count > 0) {
LOGP_CHAN(DFRAME, LOGL_INFO, "RX RECC: DCC=%d (%d of 5 CRCs are ok)\n", dcc, crc_ok_count);
if (dcc != amps->si.dcc) {
PDEBUG(DFRAME, DEBUG_INFO, "received DCC=%d mismatches the base station's DCC=%d\n", dcc, amps->si.dcc);
LOGP(DFRAME, LOGL_INFO, "received DCC=%d mismatches the base station's DCC=%d\n", dcc, amps->si.dcc);
return 0;
}
}
} else {
if (debuglevel == DEBUG_DEBUG || crc_ok_count > 0)
PDEBUG_CHAN(DFRAME, DEBUG_INFO, "RX RECC: (%d of 5 CRCs are ok)\n", crc_ok_count);
if (loglevel == LOGL_DEBUG || crc_ok_count > 0)
LOGP_CHAN(DFRAME, LOGL_INFO, "RX RECC: (%d of 5 CRCs are ok)\n", crc_ok_count);
}
if (debuglevel == DEBUG_DEBUG) {
if (loglevel == LOGL_DEBUG) {
char text[64];
for (i = 0; i < 5; i++) {
strncpy(text, bits + i * 48, 48);
text[48] = '\0';
PDEBUG_CHAN(DFRAME, DEBUG_DEBUG, " word - %s%s\n", text, (crc_a_ok[i]) ? " ok" : " BAD CRC!");
LOGP_CHAN(DFRAME, LOGL_DEBUG, " word - %s%s\n", text, (crc_a_ok[i]) ? " ok" : " BAD CRC!");
}
}
@ -3690,7 +3757,7 @@ int amps_decode_frame(amps_t *amps, const char *bits, int count, double level, d
/* not if additional words are received without sync */
if (count != 240) {
PDEBUG_CHAN(DDSP, DEBUG_INFO, "RX Level: %.0f%% Quality: %.0f%% Polarity: %s\n", level * 100.0, quality * 100.0, (negative) ? "NEGATIVE" : "POSITIVE");
LOGP_CHAN(DDSP, LOGL_INFO, "RX Level: %.0f%% Quality: %.0f%% Polarity: %s\n", level * 100.0, quality * 100.0, (negative) ? "NEGATIVE" : "POSITIVE");
}
if (count == 441) {
amps_decode_bits_focc(amps, bits);
@ -3699,7 +3766,7 @@ int amps_decode_frame(amps_t *amps, const char *bits, int count, double level, d
} else if (count == 240) {
more = amps_decode_bits_recc(amps, bits, 0);
} else {
PDEBUG_CHAN(DFRAME, DEBUG_ERROR, "Frame with unknown length = %d, please fix!\n", count);
LOGP_CHAN(DFRAME, LOGL_ERROR, "Frame with unknown length = %d, please fix!\n", count);
}
return more;

View File

@ -211,16 +211,16 @@ typedef struct amps_frame {
} frame_t;
void init_frame(void);
uint64_t amps_encode_word1_system(uint8_t dcc, uint16_t sid1, uint8_t ep, uint8_t auth, uint8_t pci, uint8_t nawc);
uint64_t tacs_encode_word1_system(uint8_t dcc, uint16_t aid1, uint8_t ep, uint8_t auth, uint8_t pci, uint8_t nawc);
uint64_t amps_encode_word2_system(uint8_t dcc, uint8_t s, uint8_t e, uint8_t regh, uint8_t regr, uint8_t dtx, uint8_t n_1, uint8_t rcf, uint8_t cpa, uint8_t cmax_1, uint8_t end);
uint64_t amps_encode_registration_id(uint8_t dcc, uint32_t regid, uint8_t end);
uint64_t amps_encode_registration_increment(uint8_t dcc, uint16_t regincr, uint8_t end);
uint64_t amps_encode_location_area(uint8_t dcc, uint8_t pureg, uint8_t pdreg, uint8_t lreg, uint16_t locaid, uint8_t end);
uint64_t amps_encode_new_access_channel_set(uint8_t dcc, uint16_t newacc, uint8_t end);
uint64_t amps_encode_overload_control(uint8_t dcc, uint8_t *olc, uint8_t end);
uint64_t amps_encode_access_type(uint8_t dcc, uint8_t bis, uint8_t pci_home, uint8_t pci_roam, uint8_t bspc, uint8_t bscap, uint8_t end);
uint64_t amps_encode_access_attempt(uint8_t dcc, uint8_t maxbusy_pgr, uint8_t maxsztr_pgr, uint8_t maxbusy_other, uint8_t maxsztr_other, uint8_t end);
uint64_t amps_encode_word1_system(uint8_t dcc, uint16_t sid1, uint8_t ep, uint8_t auth, uint8_t pci, uint8_t nawc, int debug);
uint64_t tacs_encode_word1_system(uint8_t dcc, uint16_t aid1, uint8_t ep, uint8_t auth, uint8_t pci, uint8_t nawc, int debug);
uint64_t amps_encode_word2_system(uint8_t dcc, uint8_t s, uint8_t e, uint8_t regh, uint8_t regr, uint8_t dtx, uint8_t n_1, uint8_t rcf, uint8_t cpa, uint8_t cmax_1, uint8_t end, int debug);
uint64_t amps_encode_registration_id(uint8_t dcc, uint32_t regid, uint8_t end, int debug);
uint64_t amps_encode_registration_increment(uint8_t dcc, uint16_t regincr, uint8_t end, int debug);
uint64_t amps_encode_location_area(uint8_t dcc, uint8_t pureg, uint8_t pdreg, uint8_t lreg, uint16_t locaid, uint8_t end, int debug);
uint64_t amps_encode_new_access_channel_set(uint8_t dcc, uint16_t newacc, uint8_t end, int debug);
uint64_t amps_encode_overload_control(uint8_t dcc, uint8_t *olc, uint8_t end, int debug);
uint64_t amps_encode_access_type(uint8_t dcc, uint8_t bis, uint8_t pci_home, uint8_t pci_roam, uint8_t bspc, uint8_t bscap, uint8_t end, int debug);
uint64_t amps_encode_access_attempt(uint8_t dcc, uint8_t maxbusy_pgr, uint8_t maxsztr_pgr, uint8_t maxbusy_other, uint8_t maxsztr_other, uint8_t end, int debug);
int amps_encode_frame_focc(amps_t *amps, char *bits);
int amps_encode_frame_fvc(amps_t *amps, char *bits);
int amps_decode_frame(amps_t *amps, const char *bits, int count, double level, double quality, int negative);

View File

@ -2,10 +2,16 @@
#include "../amps/main.h"
#include "../amps/tones.h"
#include "../amps/outoforder.h"
#include "../libmobile/main_mobile.h"
const int tacs = 1;
const int jtacs = 1;
const struct number_lengths number_lengths[] = {
{ 10, "JTACS number (440-XXXXXXX)" },
{ 0, NULL }
};
const char *number_prefixes[] = { NULL };
int main(int argc, char *argv[])

View File

@ -1,4 +1,5 @@
#include <stdint.h>
#include "tones.h"
static int16_t pattern_ringback[1000] = {
0x00e5, 0x0070, 0x001c, 0x0001, 0x001c, 0x0070, 0x00e5, 0x0168,

View File

@ -24,7 +24,7 @@
#include <errno.h>
#include "../libsample/sample.h"
#include "../libmobile/main_mobile.h"
#include "../libdebug/debug.h"
#include "../liblogging/logging.h"
#include "../libmobile/call.h"
#include "../liboptions/options.h"
#include "../libfm/fm.h"
@ -38,9 +38,19 @@
int num_chan_type = 0;
enum amps_chan_type chan_type[MAX_SENDER] = { CHAN_TYPE_CC_PC_VC };
const char *flip_polarity = "";
int ms_power = 4, dtx = 0, dcc = 0, scc = 0, sid = 0, regh = 1, regr = 1, pureg = 0, pdreg = 0, locaid = -1, regincr = 300, bis = 0;
int ms_power = 4;
int dtx = 0;
int send_callerid = 0;
int dcc = 0, scc = 0, sid = 0, regh = 1, regr = 1, pureg = 0, pdreg = 0, locaid = -1, regincr = 300, bis = 0;
int tolerant = 0;
static void print_location_area_note(void)
{
/* - - */
printf(" Warning: Older phones may not like this and show 'No Service'!\n");
printf(" Note: This feature was added 1995 to the standard, it might not work.\n");
}
void print_help(const char *arg0)
{
if (!tacs)
@ -57,12 +67,24 @@ void print_help(const char *arg0)
printf(" If the phone shows 'NoSrv', try the other way.\n");
printf(" -P --ms-power <power level>\n");
printf(" Give power level of the mobile station 0..7. (default = '%d')\n", ms_power);
printf(" 0 = %2d W; 1 = 1.6 W; 2 = 630 mW; 3 = 250 mW;\n", (tacs) ? 10 : 4);
printf(" 4 = 100 mW; 5 = 40 mW; 6 = 16 mW; 7 = 6.3 mW\n");
if (!tacs) {
printf(" 0 = 4 W; 1 = 1.6 W; 2 = 630 mW; 3 = 250 mW;\n");
printf(" 4 = 100 mW; 5 = 40 mW; 6 = 16 mW; 7 = 6.3 mW\n");
} else {
/* tacs, not jtacs: https://www.academia.edu/8265916/Total_Access_Communication_System?email_work_card=view-paper */
printf(" 0 = 2.28 W; 1 = 1.12 W; 2 = 447 mW; 3 = 178 mW;\n");
printf(" 4 = 70.8 mW; 5 = 28.2 mW; 6 = 11.2 mW; 7 = 4.5 mW\n");
}
printf(" -D --dtx <parameter>\n");
printf(" Give DTX parameter for Discontinuous Transmission. (default = '%d')\n", dtx);
printf(" 0 = disable DTX; 1 = reserved;\n");
printf(" 2 = 8 dB attenuation in low state; 3 = transmitter off\n");
printf(" -I --caller-id 1 | 0\n");
printf(" If set, the caller ID is sent while ringing the phone. (default = '%d')\n", send_callerid);
printf(" Note that this does not work as documented in the specs. If the phone\n");
printf(" does not support caller ID, it will abort connection on receiving\n");
printf(" caller ID for some unknown reason. Therefore use caller ID only with\n");
printf(" phones that support it.\n");
if (!tacs) {
printf(" -S --sysinfo sid=<System ID> | sid=list\n");
printf(" Give system ID of cell broadcast\n");
@ -82,14 +104,14 @@ void print_help(const char *arg0)
printf(" many second the phone waits before it re-registers.\n");
printf(" -S --sysinfo pureg=0 | pureg=1\n");
printf(" If 1, phone registers on every power on (default = '%d')\n", pureg);
printf(" Warning: Older phones may not like this and show 'No Service'!\n");
print_location_area_note();
printf(" -S --sysinfo pdreg=0 | pdreg=1\n");
printf(" If 1, phone de-registers on every power down (default = '%d')\n", pureg);
printf(" Warning: Older phones may not like this and show 'No Service'!\n");
print_location_area_note();
printf(" -S --sysinfo locaid=<location area ID > | locaid=-1 to disable\n");
printf(" (default = '%d')\n", locaid);
printf(" If it changes, phone re-registers.\n");
printf(" Warning: Older phones may not like this and show 'No Service'!\n");
print_location_area_note();
printf(" -S --sysinfo regh=0 | regh=1\n");
printf(" If 1, phone registers only if System ID matches (default = '%d')\n", regh);
printf(" -S --sysinfo regr=0 | regr=1\n");
@ -110,6 +132,7 @@ static void add_options(void)
option_add('F', "flip-polarity", 1);
option_add('P', "ms-power", 1);
option_add('D', "dtx", 1);
option_add('I', "caller-id", 1);
option_add('S', "sysinfo", 1);
option_add('O', "tolerant", 0);
}
@ -156,6 +179,9 @@ static int handle_options(int short_option, int argi, char **argv)
if (dtx < 0)
dtx = 0;
break;
case 'I':
send_callerid = atoi(argv[argi]);
break;
case 'S':
p = strchr(argv[argi], '=');
if (!p) {
@ -226,10 +252,7 @@ static int handle_options(int short_option, int argi, char **argv)
return 1;
}
static const struct number_lengths number_lengths[] = {
{ 10, "AMPS number" },
{ 0, NULL }
};
extern const struct number_lengths number_lengths[];
int main_amps_tacs(const char *name, int argc, char *argv[])
{
@ -238,6 +261,10 @@ int main_amps_tacs(const char *name, int argc, char *argv[])
int polarity;
int i;
/* jtacs has only system A, so there are only odd AIDs */
if (jtacs)
sid = 1;
/* override default */
dsp_samplerate = 96000;
@ -267,7 +294,7 @@ int main_amps_tacs(const char *name, int argc, char *argv[])
}
if (!num_kanal) {
printf("No channel (\"Kanal\") is specified, I suggest channel %d.\n\n", (!tacs) ? 333 : 323);
printf("No channel (\"Kanal\") is specified, I suggest channel %d.\n\n", (!tacs) ? 333 : ((!jtacs) ? 323 : 418));
print_help(argv[0]);
return 0;
}
@ -384,7 +411,7 @@ int main_amps_tacs(const char *name, int argc, char *argv[])
amps_si si;
init_sysinfo(&si, ms_power, ms_power, dtx, dcc, sid >> 1, regh, regr, pureg, pdreg, locaid, regincr, bis);
rc = amps_create(kanal[i], chan_type[i], dsp_device[i], use_sdr, dsp_samplerate, rx_gain, tx_gain, do_pre_emphasis, do_de_emphasis, write_rx_wave, write_tx_wave, read_rx_wave, read_tx_wave, &si, sid, scc, polarity, tolerant, loopback);
rc = amps_create(kanal[i], chan_type[i], dsp_device[i], use_sdr, dsp_samplerate, rx_gain, tx_gain, do_pre_emphasis, do_de_emphasis, write_rx_wave, write_tx_wave, read_rx_wave, read_tx_wave, &si, sid, scc, polarity, send_callerid, tolerant, loopback);
if (rc < 0) {
fprintf(stderr, "Failed to create \"Sender\" instance. Quitting!\n");
goto fail;
@ -403,6 +430,7 @@ fail:
amps_destroy(sender_head);
/* exits */
main_mobile_exit();
fm_exit();
options_free();

View File

@ -2,6 +2,7 @@
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>
#include "../libsample/sample.h"
#include "amps.h"
@ -150,7 +151,7 @@ void prepare_sysinfo(amps_si *si)
}
}
uint64_t get_sysinfo(amps_si *si)
uint64_t get_sysinfo(amps_si *si, int debug)
{
int count, nawc, end = 0;
time_t ti = time(NULL);
@ -166,27 +167,27 @@ uint64_t get_sysinfo(amps_si *si)
case SYSINFO_WORD1:
nawc = si->num - 1;
if (!tacs)
return amps_encode_word1_system(si->dcc, si->word1.sid1, si->word1.ep, si->word1.auth, si->word1.pci, nawc);
return amps_encode_word1_system(si->dcc, si->word1.sid1, si->word1.ep, si->word1.auth, si->word1.pci, nawc, debug);
else
return tacs_encode_word1_system(si->dcc, si->word1.sid1, si->word1.ep, si->word1.auth, si->word1.pci, nawc);
return tacs_encode_word1_system(si->dcc, si->word1.sid1, si->word1.ep, si->word1.auth, si->word1.pci, nawc, debug);
case SYSINFO_WORD2:
return amps_encode_word2_system(si->dcc, si->word2.s, si->word2.e, si->word2.regh, si->word2.regr, si->word2.dtx, si->word2.n_1, si->word2.rcf, si->word2.cpa, si->word2.cmax_1, end);
return amps_encode_word2_system(si->dcc, si->word2.s, si->word2.e, si->word2.regh, si->word2.regr, si->word2.dtx, si->word2.n_1, si->word2.rcf, si->word2.cpa, si->word2.cmax_1, end, debug);
case SYSINFO_REG_ID:
/* use time stamp to generate regid */
si->reg_id.regid = ti & 0xfffff;
return amps_encode_registration_id(si->dcc, si->reg_id.regid, end);
return amps_encode_registration_id(si->dcc, si->reg_id.regid, end, debug);
case SYSINFO_REG_INCR:
return amps_encode_registration_increment(si->dcc, si->reg_incr.regincr, end);
return amps_encode_registration_increment(si->dcc, si->reg_incr.regincr, end, debug);
case SYSINFO_LOC_AREA:
return amps_encode_location_area(si->dcc, si->loc_area.pureg, si->loc_area.pdreg, si->loc_area.lreg, si->loc_area.locaid, end);
return amps_encode_location_area(si->dcc, si->loc_area.pureg, si->loc_area.pdreg, si->loc_area.lreg, si->loc_area.locaid, end, debug);
case SYSINFO_NEW_ACC:
return amps_encode_new_access_channel_set(si->dcc, si->new_acc.newacc, end);
return amps_encode_new_access_channel_set(si->dcc, si->new_acc.newacc, end, debug);
case SYSINFO_OVERLOAD:
return amps_encode_overload_control(si->dcc, si->overload.olc, end);
return amps_encode_overload_control(si->dcc, si->overload.olc, end, debug);
case SYSINFO_ACC_TYPE:
return amps_encode_access_type(si->dcc, si->acc_type.bis, si->acc_type.pci_home, si->acc_type.pci_roam, si->acc_type.bspc, si->acc_type.bscap, end);
return amps_encode_access_type(si->dcc, si->acc_type.bis, si->acc_type.pci_home, si->acc_type.pci_roam, si->acc_type.bspc, si->acc_type.bscap, end, debug);
case SYSINFO_ACC_ATTEMPT:
return amps_encode_access_attempt(si->dcc, si->acc_attempt.maxbusy_pgr, si->acc_attempt.maxsztr_pgr, si->acc_attempt.maxbusy_other, si->acc_attempt.maxsztr_other, end);
return amps_encode_access_attempt(si->dcc, si->acc_attempt.maxbusy_pgr, si->acc_attempt.maxsztr_pgr, si->acc_attempt.maxbusy_other, si->acc_attempt.maxsztr_other, end, debug);
}
fprintf(stderr, "get_sysinfo unknown type, please fix!\n");

View File

@ -112,5 +112,5 @@ typedef struct system_information {
void init_sysinfo(amps_si *si, int cmac, int vmac, int dtx, int dcc, int sid1, int regh, int regr, int pureg, int pdreg, int locaid, int regincr, int bis);
void prepare_sysinfo(amps_si *si);
uint64_t get_sysinfo(amps_si *si);
uint64_t get_sysinfo(amps_si *si, int debug);

View File

@ -2,10 +2,16 @@
#include "../amps/main.h"
#include "../amps/tones.h"
#include "../amps/outoforder.h"
#include "../libmobile/main_mobile.h"
const int tacs = 1;
const int jtacs = 0;
const struct number_lengths number_lengths[] = {
{ 10, "TACS number (AREA-XXXXXXX)" },
{ 0, NULL }
};
const char *number_prefixes[] = {
"0xxxxxxxxxx",
"+44xxxxxxxxxx",

View File

@ -1,4 +1,5 @@
#include <stdint.h>
#include "outoforder.h"
static int16_t pattern[] = {
0x0000, 0x0000, 0xffff, 0x0002, 0xfffe, 0x0003, 0xfffd, 0x0001,

View File

@ -1,4 +1,5 @@
#include <stdint.h>
#include "tones.h"
static int16_t pattern_ringback[] = {
0x000b, 0x0008, 0x000d, 0x000e, 0x000d, 0x0012, 0x0011, 0xffcd,

View File

@ -21,7 +21,7 @@
#include <stdint.h>
#include <stdlib.h>
#include "../libsample/sample.h"
#include "../libdebug/debug.h"
#include "../liblogging/logging.h"
#include "../libmobile/call.h"
#include "../libmobile/cause.h"
#include "amps.h"
@ -37,17 +37,25 @@ static const char *trans_state_name(int state)
case TRANS_REGISTER_ACK_SEND:
return "REGISTER ACK SEND";
case TRANS_CALL_MO_ASSIGN:
return "CALL ASSIGN MOBILE ORIGINATING";
return "MO CALL ASSIGNMENT";
case TRANS_CALL_MO_ASSIGN_SEND:
return "CALL ASSIGN MOBILE ORIGINATING SEND";
return "MO CALL ASSIGNMENT SENDING";
case TRANS_CALL_MO_ASSIGN_CONFIRM:
return "MO CALL ASSIGNMENT WAIT CONFIRM";
case TRANS_CALL_MT_ASSIGN:
return "CALL ASSIGN MOBILE TERMINATING";
return "MT CALL ASSIGNMENT";
case TRANS_CALL_MT_ASSIGN_SEND:
return "CALL ASSIGN MOBILE TERMINATING SEND";
return "MT CALL ASSIGNMENT SENDING";
case TRANS_CALL_MT_ASSIGN_CONFIRM:
return "MT CALL ASSIGNMENT WAIT CONFIRM";
case TRANS_CALL_MT_ALERT:
return "CALL ALERT MOBILE TERMINATING";
return "MT CALL ALERT";
case TRANS_CALL_MT_ALERT_SEND:
return "CALL ALERT MOBILE TERMINATING SEND";
return "MT CALL ALERT SENDING";
case TRANS_CALL_MT_ALERT_CONFIRM:
return "MT CALL ALERT WAIT CONFIRM";
case TRANS_CALL_MT_ANSWER_WAIT:
return "MT CALL ANSWER WAIT";
case TRANS_CALL_REJECT:
return "CALL REJECT";
case TRANS_CALL_REJECT_SEND:
@ -79,11 +87,15 @@ const char *trans_short_state_name(int state)
return "REGISTER";
case TRANS_CALL_MO_ASSIGN:
case TRANS_CALL_MO_ASSIGN_SEND:
case TRANS_CALL_MO_ASSIGN_CONFIRM:
case TRANS_CALL_MT_ASSIGN:
case TRANS_CALL_MT_ASSIGN_SEND:
case TRANS_CALL_MT_ASSIGN_CONFIRM:
return "ASSIGN";
case TRANS_CALL_MT_ALERT:
case TRANS_CALL_MT_ALERT_SEND:
case TRANS_CALL_MT_ALERT_CONFIRM:
case TRANS_CALL_MT_ANSWER_WAIT:
return "ALERT";
case TRANS_CALL_REJECT:
case TRANS_CALL_REJECT_SEND:
@ -121,7 +133,7 @@ transaction_t *create_transaction(amps_t *amps, enum amps_trans_state state, uin
const char *number = amps_min2number(trans->min1, trans->min2);
int old_callref = trans->callref;
amps_t *old_amps = trans->amps;
PDEBUG(DTRANS, DEBUG_NOTICE, "Found already pending transaction for subscriber '%s', deleting!\n", number);
LOGP(DTRANS, LOGL_NOTICE, "Found already pending transaction for subscriber '%s', deleting!\n", number);
destroy_transaction(trans);
if (old_amps) /* should be... */
amps_go_idle(old_amps);
@ -131,11 +143,11 @@ transaction_t *create_transaction(amps_t *amps, enum amps_trans_state state, uin
trans = calloc(1, sizeof(*trans));
if (!trans) {
PDEBUG(DTRANS, DEBUG_ERROR, "No memory!\n");
LOGP(DTRANS, LOGL_ERROR, "No memory!\n");
return NULL;
}
timer_init(&trans->timer, transaction_timeout, trans);
osmo_timer_setup(&trans->timer, transaction_timeout, trans);
trans_new_state(trans, state);
trans->min1 = min1;
@ -147,7 +159,7 @@ transaction_t *create_transaction(amps_t *amps, enum amps_trans_state state, uin
trans->chan = chan;
const char *number = amps_min2number(trans->min1, trans->min2);
PDEBUG(DTRANS, DEBUG_INFO, "Created transaction for subscriber '%s'\n", number);
LOGP(DTRANS, LOGL_INFO, "Created transaction for subscriber '%s'\n", number);
link_transaction(trans, amps);
@ -160,9 +172,9 @@ void destroy_transaction(transaction_t *trans)
unlink_transaction(trans);
const char *number = amps_min2number(trans->min1, trans->min2);
PDEBUG(DTRANS, DEBUG_INFO, "Destroying transaction for subscriber '%s'\n", number);
LOGP(DTRANS, LOGL_INFO, "Destroying transaction for subscriber '%s'\n", number);
timer_exit(&trans->timer);
osmo_timer_del(&trans->timer);
trans_new_state(trans, 0);
@ -175,7 +187,7 @@ void link_transaction(transaction_t *trans, amps_t *amps)
transaction_t **transp;
/* attach to end of list, so first transaction is served first */
PDEBUG(DTRANS, DEBUG_DEBUG, "Linking transaction %p to amps %p\n", trans, amps);
LOGP(DTRANS, LOGL_DEBUG, "Linking transaction %p to amps %p\n", trans, amps);
trans->amps = amps;
trans->next = NULL;
transp = &amps->trans_list;
@ -191,12 +203,12 @@ void unlink_transaction(transaction_t *trans)
transaction_t **transp;
/* unlink */
PDEBUG(DTRANS, DEBUG_DEBUG, "Unlinking transaction %p from amps %p\n", trans, trans->amps);
LOGP(DTRANS, LOGL_DEBUG, "Unlinking transaction %p from amps %p\n", trans, trans->amps);
transp = &trans->amps->trans_list;
while (*transp && *transp != trans)
transp = &((*transp)->next);
if (!(*transp)) {
PDEBUG(DTRANS, DEBUG_ERROR, "Transaction not in list, please fix!!\n");
LOGP(DTRANS, LOGL_ERROR, "Transaction not in list, please fix!!\n");
abort();
}
*transp = trans->next;
@ -212,7 +224,7 @@ transaction_t *search_transaction_number(amps_t *amps, uint32_t min1, uint16_t m
if (trans->min1 == min1
&& trans->min2 == min2) {
const char *number = amps_min2number(trans->min1, trans->min2);
PDEBUG(DTRANS, DEBUG_DEBUG, "Found transaction for subscriber '%s'\n", number);
LOGP(DTRANS, LOGL_DEBUG, "Found transaction for subscriber '%s'\n", number);
return trans;
}
trans = trans->next;
@ -231,7 +243,7 @@ transaction_t *search_transaction_callref(amps_t *amps, int callref)
while (trans) {
if (trans->callref == callref) {
const char *number = amps_min2number(trans->min1, trans->min2);
PDEBUG(DTRANS, DEBUG_DEBUG, "Found transaction for subscriber '%s'\n", number);
LOGP(DTRANS, LOGL_DEBUG, "Found transaction for subscriber '%s'\n", number);
return trans;
}
trans = trans->next;
@ -242,7 +254,7 @@ transaction_t *search_transaction_callref(amps_t *amps, int callref)
void trans_new_state(transaction_t *trans, int state)
{
PDEBUG(DTRANS, DEBUG_INFO, "Transaction state %s -> %s\n", trans_state_name(trans->state), trans_state_name(state));
LOGP(DTRANS, LOGL_INFO, "Transaction state %s -> %s\n", trans_state_name(trans->state), trans_state_name(state));
trans->state = state;
amps_display_status();
}
@ -251,12 +263,12 @@ void amps_flush_other_transactions(amps_t *amps, transaction_t *trans)
{
/* flush after this very trans */
while (trans->next) {
PDEBUG(DTRANS, DEBUG_NOTICE, "Kicking other pending transaction\n");
LOGP(DTRANS, LOGL_NOTICE, "Kicking other pending transaction\n");
destroy_transaction(trans->next);
}
/* flush before this very trans */
while (amps->trans_list != trans) {
PDEBUG(DTRANS, DEBUG_NOTICE, "Kicking other pending transaction\n");
LOGP(DTRANS, LOGL_NOTICE, "Kicking other pending transaction\n");
destroy_transaction(amps->trans_list);
}
}

View File

@ -5,10 +5,14 @@ enum amps_trans_state {
TRANS_REGISTER_ACK_SEND, /* attach request received, sending ack */
TRANS_CALL_MO_ASSIGN, /* assigning channel, waiting to send */
TRANS_CALL_MO_ASSIGN_SEND, /* assigning channel, sending assignment */
TRANS_CALL_MO_ASSIGN_CONFIRM, /* assignment sent, waiting for confirm (SAT) */
TRANS_CALL_MT_ASSIGN, /* assigning channel, waiting to send */
TRANS_CALL_MT_ASSIGN_SEND, /* assigning channel, sending assignment */
TRANS_CALL_MT_ALERT, /* ringing the phone, sending alert order until signaling tone is received */
TRANS_CALL_MT_ALERT_SEND, /* ringing the phone, signaling tone is received */
TRANS_CALL_MT_ASSIGN_CONFIRM, /* assignment sent, waiting for confirm (SAT) */
TRANS_CALL_MT_ALERT, /* ringing the phone, waiting to send alert */
TRANS_CALL_MT_ALERT_SEND, /* ringing the phone, sending alert */
TRANS_CALL_MT_ALERT_CONFIRM, /* ringing the phone, signaling tone is received */
TRANS_CALL_MT_ANSWER_WAIT, /* ringing the phone, waiting for the phone to answer */
TRANS_CALL_REJECT, /* rejecting channel, waiting to send */
TRANS_CALL_REJECT_SEND, /* rejecting channel, sending reject */
TRANS_CALL, /* active call */
@ -31,9 +35,11 @@ typedef struct transaction {
uint8_t ordq;
uint8_t order;
uint16_t chan; /* channel to assign */
int alert_retry; /* current number of alter order (re)try */
char caller_id[33]; /* id of calling phone */
char dialing[33]; /* number dialed by the phone */
enum amps_trans_state state; /* state of transaction */
struct timer timer; /* for varous timeouts */
struct osmo_timer_list timer; /* for varous timeouts */
int sat_detected; /* state if we detected SAT */
int dtx; /* if set, DTX is used with this call */
} transaction_t;
@ -47,6 +53,6 @@ transaction_t *search_transaction_number(amps_t *amps, uint32_t min1, uint16_t m
transaction_t *search_transaction_callref(amps_t *amps, int callref);
void trans_new_state(transaction_t *trans, int state);
void amps_flush_other_transactions(amps_t *amps, transaction_t *trans);
void transaction_timeout(struct timer *timer);
void transaction_timeout(void *data);
const char *trans_short_state_name(int state);

View File

@ -1,4 +1,5 @@
#include <stdint.h>
#include "congestion.h"
static int16_t pattern[] = {
0xfffd, 0x0004, 0xfffb, 0x0004, 0xfffe, 0x0001, 0x0001, 0xfffe,

View File

@ -1,4 +1,5 @@
#include <stdint.h>
#include "invalidnumber.h"
static int16_t pattern[] = {
0xfffe, 0x0001, 0xffff, 0x0001, 0xffff, 0x0002, 0xfffe, 0x0002,

View File

@ -1,4 +1,5 @@
#include <stdint.h>
#include "noanswer.h"
static int16_t pattern[] = {
0xfe24, 0xfd20, 0xfd2c, 0xfdb5, 0xfeba, 0xfe20, 0xfd41, 0xfe32,

View File

@ -1,4 +1,5 @@
#include <stdint.h>
#include "outoforder.h"
static int16_t pattern[] = {
0xfeae, 0xfde4, 0xfe26, 0xfea7, 0xfe94, 0xfe8a, 0xfeb4, 0xfe3b,

View File

@ -1,4 +1,5 @@
#include <stdint.h>
#include "tones.h"
static int16_t pattern_ringback[] = {
0x0070, 0x00dd, 0x013b, 0x0192, 0x0191, 0x0153, 0x0099, 0xffb2,

View File

@ -1,4 +1,4 @@
AM_CPPFLAGS = -Wall -Wextra -g $(all_includes)
AM_CPPFLAGS = -Wall -Wextra -Wmissing-prototypes -g $(all_includes)
bin_PROGRAMS = \
anetz
@ -19,22 +19,21 @@ anetz_LDADD = \
$(COMMON_LA) \
libgermanton.a \
$(top_builddir)/src/liboptions/liboptions.a \
$(top_builddir)/src/libdebug/libdebug.a \
$(top_builddir)/src/libmobile/libmobile.a \
$(top_builddir)/src/libosmocc/libosmocc.a \
$(top_builddir)/src/libdisplay/libdisplay.a \
$(top_builddir)/src/libgoertzel/libgoertzel.a \
$(top_builddir)/src/libjitter/libjitter.a \
$(top_builddir)/src/libsquelch/libsquelch.a \
$(top_builddir)/src/libtimer/libtimer.a \
$(top_builddir)/src/libsamplerate/libsamplerate.a \
$(top_builddir)/src/libemphasis/libemphasis.a \
$(top_builddir)/src/libfm/libfm.a \
$(top_builddir)/src/libfilter/libfilter.a \
$(top_builddir)/src/libwave/libwave.a \
$(top_builddir)/src/libsample/libsample.a \
$(top_builddir)/src/libg711/libg711.a \
$(top_builddir)/src/libaaimage/libaaimage.a \
$(top_builddir)/src/liblogging/liblogging.a \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOCC_LIBS) \
-lm
if HAVE_ALSA

View File

@ -25,19 +25,19 @@
#include <string.h>
#include <errno.h>
#include "../libsample/sample.h"
#include "../libdebug/debug.h"
#include "../libtimer/timer.h"
#include "../liblogging/logging.h"
#include <osmocom/core/timer.h>
#include "../libmobile/call.h"
#include "../libmobile/cause.h"
#include "../libosmocc/message.h"
#include <osmocom/cc/message.h>
#include "anetz.h"
#include "dsp.h"
/* Timers */
#define PAGING_TO 30 /* Nach dieser Zeit ist der Operator genervt... */
#define RELEASE_TO 3 /* Release time, so station keeps blocked for a while */
#define PAGING_TO 30,0 /* Nach dieser Zeit ist der Operator genervt... */
#define RELEASE_TO 3,0 /* Release time, so station keeps blocked for a while */
const char *anetz_state_name(enum anetz_state state)
static const char *anetz_state_name(enum anetz_state state)
{
static char invalid[16];
@ -58,7 +58,7 @@ const char *anetz_state_name(enum anetz_state state)
return invalid;
}
void anetz_display_status(void)
static void anetz_display_status(void)
{
sender_t *sender;
anetz_t *anetz;
@ -77,7 +77,7 @@ static void anetz_new_state(anetz_t *anetz, enum anetz_state new_state)
{
if (anetz->state == new_state)
return;
PDEBUG_CHAN(DANETZ, DEBUG_DEBUG, "State change: %s -> %s\n", anetz_state_name(anetz->state), anetz_state_name(new_state));
LOGP_CHAN(DANETZ, LOGL_DEBUG, "State change: %s -> %s\n", anetz_state_name(anetz->state), anetz_state_name(new_state));
anetz->state = new_state;
anetz_display_status();
}
@ -141,7 +141,7 @@ static double *anetz_nummer2freq(const char *nummer)
/* get decade */
dekade = anetz_gruppenkennziffer[*nummer - '0'].dekade;
PDEBUG(DANETZ, DEBUG_DEBUG, "Dekaden: %d %d %d %d\n", dekade[0], dekade[1], dekade[2], dekade[3]);
LOGP(DANETZ, LOGL_DEBUG, "Dekaden: %d %d %d %d\n", dekade[0], dekade[1], dekade[2], dekade[3]);
nummer++;
/* get 4 frequencies out of decades */
@ -161,7 +161,7 @@ static double *anetz_nummer2freq(const char *nummer)
}
}
PDEBUG(DANETZ, DEBUG_DEBUG, "Frequencies: F%d=%.1f F%d=%.1f F%d=%.1f F%d=%.1f\n", f[0], freq[0], f[1], freq[1], f[2], freq[2], f[3], freq[3]);
LOGP(DANETZ, LOGL_DEBUG, "Frequencies: F%d=%.1f F%d=%.1f F%d=%.1f F%d=%.1f\n", f[0], freq[0], f[1], freq[1], f[2], freq[2], f[3], freq[3]);
return freq;
}
@ -186,7 +186,7 @@ int anetz_init(void)
return 0;
}
static void anetz_timeout(struct timer *timer);
static void anetz_timeout(void *data);
static void anetz_go_idle(anetz_t *anetz);
/* Create transceiver instance and link to a list. */
@ -196,40 +196,40 @@ int anetz_create(const char *kanal, const char *device, int use_sdr, int sampler
int rc;
if (atoi(kanal) < 30 || atoi(kanal) > 63) {
PDEBUG(DANETZ, DEBUG_ERROR, "Channel ('Kanal') number %s invalid.\n", kanal);
LOGP(DANETZ, LOGL_ERROR, "Channel ('Kanal') number %s invalid.\n", kanal);
return -EINVAL;
}
anetz = calloc(1, sizeof(anetz_t));
if (!anetz) {
PDEBUG(DANETZ, DEBUG_ERROR, "No memory!\n");
LOGP(DANETZ, LOGL_ERROR, "No memory!\n");
return -EIO;
}
anetz->operator = operator;
PDEBUG(DANETZ, DEBUG_DEBUG, "Creating 'A-Netz' instance for 'Kanal' = %s (sample rate %d).\n", kanal, samplerate);
LOGP(DANETZ, LOGL_DEBUG, "Creating 'A-Netz' instance for 'Kanal' = %s (sample rate %d).\n", kanal, samplerate);
/* init general part of transceiver */
rc = sender_create(&anetz->sender, kanal, anetz_kanal2freq(atoi(kanal), 0), anetz_kanal2freq(atoi(kanal), 1), device, use_sdr, samplerate, rx_gain, tx_gain, pre_emphasis, de_emphasis, write_rx_wave, write_tx_wave, read_rx_wave, read_tx_wave, loopback, PAGING_SIGNAL_NONE);
if (rc < 0) {
PDEBUG(DANETZ, DEBUG_ERROR, "Failed to init 'Sender' processing!\n");
LOGP(DANETZ, LOGL_ERROR, "Failed to init 'Sender' processing!\n");
goto error;
}
/* init audio processing */
rc = dsp_init_sender(anetz, page_gain, page_sequence, squelch_db);
if (rc < 0) {
PDEBUG(DANETZ, DEBUG_ERROR, "Failed to init signal processing!\n");
LOGP(DANETZ, LOGL_ERROR, "Failed to init signal processing!\n");
goto error;
}
timer_init(&anetz->timer, anetz_timeout, anetz);
osmo_timer_setup(&anetz->timer, anetz_timeout, anetz);
/* go into idle state */
anetz_go_idle(anetz);
PDEBUG(DANETZ, DEBUG_NOTICE, "Created 'Kanal' #%s\n", kanal);
LOGP(DANETZ, LOGL_NOTICE, "Created 'Kanal' #%s\n", kanal);
return 0;
@ -244,9 +244,9 @@ void anetz_destroy(sender_t *sender)
{
anetz_t *anetz = (anetz_t *) sender;
PDEBUG(DANETZ, DEBUG_DEBUG, "Destroying 'A-Netz' instance for 'Kanal' = %s.\n", sender->kanal);
LOGP(DANETZ, LOGL_DEBUG, "Destroying 'A-Netz' instance for 'Kanal' = %s.\n", sender->kanal);
timer_exit(&anetz->timer);
osmo_timer_del(&anetz->timer);
dsp_cleanup_sender(anetz);
sender_destroy(&anetz->sender);
free(sender);
@ -255,9 +255,9 @@ void anetz_destroy(sender_t *sender)
/* Abort connection towards mobile station by sending idle tone. */
static void anetz_go_idle(anetz_t *anetz)
{
timer_stop(&anetz->timer);
osmo_timer_del(&anetz->timer);
PDEBUG(DANETZ, DEBUG_INFO, "Entering IDLE state on channel %s, sending 2280 Hz tone.\n", anetz->sender.kanal);
LOGP(DANETZ, LOGL_INFO, "Entering IDLE state on channel %s, sending 2280 Hz tone.\n", anetz->sender.kanal);
anetz->station_id[0] = '\0'; /* remove station ID before state change, so status is shown correctly */
anetz_new_state(anetz, ANETZ_FREI);
/* also reset detector, so if there is a new call it is answered */
@ -267,31 +267,31 @@ static void anetz_go_idle(anetz_t *anetz)
/* Release connection towards mobile station by sending idle tone for a while. */
static void anetz_release(anetz_t *anetz)
{
timer_stop(&anetz->timer);
osmo_timer_del(&anetz->timer);
PDEBUG_CHAN(DANETZ, DEBUG_INFO, "Sending 2280 Hz release tone.\n");
LOGP_CHAN(DANETZ, LOGL_INFO, "Sending 2280 Hz release tone.\n");
anetz->station_id[0] = '\0'; /* remove station ID before state change, so status is shown correctly */
anetz_new_state(anetz, ANETZ_AUSLOESEN);
anetz_set_dsp_mode(anetz, DSP_MODE_TONE, 0);
timer_start(&anetz->timer, RELEASE_TO);
osmo_timer_schedule(&anetz->timer, RELEASE_TO);
}
/* Enter paging state and transmit 4 paging tones. */
static void anetz_page(anetz_t *anetz, const char *dial_string, double *freq)
{
PDEBUG_CHAN(DANETZ, DEBUG_INFO, "Entering paging state, sending 'Selektivruf' to '%s'.\n", dial_string);
LOGP_CHAN(DANETZ, LOGL_INFO, "Entering paging state, sending 'Selektivruf' to '%s'.\n", dial_string);
strcpy(anetz->station_id, dial_string); /* set station ID before state change, so status is shown correctly */
anetz_new_state(anetz, ANETZ_ANRUF);
anetz_set_dsp_mode(anetz, DSP_MODE_PAGING, 0);
dsp_set_paging(anetz, freq);
timer_start(&anetz->timer, PAGING_TO);
osmo_timer_schedule(&anetz->timer, PAGING_TO);
}
/* Loss of signal was detected, release active call. */
void anetz_loss_indication(anetz_t *anetz, double loss_time)
{
if (anetz->state == ANETZ_GESPRAECH) {
PDEBUG_CHAN(DANETZ, DEBUG_NOTICE, "Detected loss of signal after %.1f seconds, releasing.\n", loss_time);
LOGP_CHAN(DANETZ, LOGL_NOTICE, "Detected loss of signal after %.1f seconds, releasing.\n", loss_time);
anetz_release(anetz);
call_up_release(anetz->callref, CAUSE_TEMPFAIL);
anetz->callref = 0;
@ -302,9 +302,9 @@ void anetz_loss_indication(anetz_t *anetz, double loss_time)
void anetz_receive_tone(anetz_t *anetz, int tone)
{
if (tone >= 0)
PDEBUG_CHAN(DANETZ, DEBUG_DEBUG, "Received contiuous %d Hz tone.\n", (tone) ? 1750 : 2280);
LOGP_CHAN(DANETZ, LOGL_DEBUG, "Received contiuous %d Hz tone.\n", (tone) ? 1750 : 2280);
else
PDEBUG_CHAN(DANETZ, DEBUG_DEBUG, "Continuous tone is gone.\n");
LOGP_CHAN(DANETZ, LOGL_DEBUG, "Continuous tone is gone.\n");
/* skip any handling in loopback mode */
if (anetz->sender.loopback)
@ -318,7 +318,7 @@ void anetz_receive_tone(anetz_t *anetz, int tone)
case ANETZ_FREI:
/* initiate call on calling tone */
if (tone == 1) {
PDEBUG_CHAN(DANETZ, DEBUG_INFO, "Received 1750 Hz calling signal from mobile station, removing idle signal.\n");
LOGP_CHAN(DANETZ, LOGL_INFO, "Received 1750 Hz calling signal from mobile station, removing idle signal.\n");
strcpy(anetz->station_id, "unknown"); /* set station ID before state change, so status is shown correctly */
anetz_new_state(anetz, ANETZ_GESPRAECH);
@ -330,17 +330,17 @@ void anetz_receive_tone(anetz_t *anetz, int tone)
/* throughconnect speech when calling/answer tone is gone */
if (tone != 1) {
if (!anetz->callref) {
PDEBUG_CHAN(DANETZ, DEBUG_INFO, "1750 Hz signal from mobile station is gone, setup call.\n");
LOGP_CHAN(DANETZ, LOGL_INFO, "1750 Hz signal from mobile station is gone, setup call.\n");
anetz->callref = call_up_setup(NULL, anetz->operator, OSMO_CC_NETWORK_ANETZ_NONE, "");
} else {
PDEBUG_CHAN(DANETZ, DEBUG_INFO, "1750 Hz signal from mobile station is gone, answer call.\n");
LOGP_CHAN(DANETZ, LOGL_INFO, "1750 Hz signal from mobile station is gone, answer call.\n");
call_up_answer(anetz->callref, anetz->station_id);
}
anetz_set_dsp_mode(anetz, DSP_MODE_AUDIO, 0);
}
/* release call */
if (tone == 1) {
PDEBUG_CHAN(DANETZ, DEBUG_INFO, "Received 1750 Hz release signal from mobile station, sending release tone.\n");
LOGP_CHAN(DANETZ, LOGL_INFO, "Received 1750 Hz release signal from mobile station, sending release tone.\n");
anetz_release(anetz);
call_up_release(anetz->callref, CAUSE_NORMAL);
anetz->callref = 0;
@ -350,8 +350,8 @@ void anetz_receive_tone(anetz_t *anetz, int tone)
case ANETZ_ANRUF:
/* answer call on answer tone */
if (tone == 1) {
PDEBUG_CHAN(DANETZ, DEBUG_INFO, "Received 1750 Hz answer signal from mobile station, removing paging tones.\n");
timer_stop(&anetz->timer);
LOGP_CHAN(DANETZ, LOGL_INFO, "Received 1750 Hz answer signal from mobile station, removing paging tones.\n");
osmo_timer_del(&anetz->timer);
anetz_new_state(anetz, ANETZ_GESPRAECH);
anetz_set_dsp_mode(anetz, DSP_MODE_SILENCE, 0);
break;
@ -362,13 +362,13 @@ void anetz_receive_tone(anetz_t *anetz, int tone)
}
/* Timeout handling */
static void anetz_timeout(struct timer *timer)
static void anetz_timeout(void *data)
{
anetz_t *anetz = (anetz_t *)timer->priv;
anetz_t *anetz = data;
switch (anetz->state) {
case ANETZ_ANRUF:
PDEBUG_CHAN(DANETZ, DEBUG_NOTICE, "Timeout while waiting for answer, releasing.\n");
LOGP_CHAN(DANETZ, LOGL_NOTICE, "Timeout while waiting for answer, releasing.\n");
anetz_go_idle(anetz);
call_up_release(anetz->callref, CAUSE_NOANSWER);
anetz->callref = 0;
@ -391,8 +391,8 @@ int call_down_setup(int callref, const char __attribute__((unused)) *caller_id,
/* 1. determine paging frequencies */
freq = anetz_nummer2freq(dialing);
if (!freq) {
PDEBUG(DANETZ, DEBUG_NOTICE, "Number invalid: %s\n", anetz_nummer2freq_error);
PDEBUG(DANETZ, DEBUG_NOTICE, "Outgoing call to invalid number '%s', rejecting!\n", dialing);
LOGP(DANETZ, LOGL_NOTICE, "Number invalid: %s\n", anetz_nummer2freq_error);
LOGP(DANETZ, LOGL_NOTICE, "Outgoing call to invalid number '%s', rejecting!\n", dialing);
return -CAUSE_INVALNUMBER;
}
@ -405,7 +405,7 @@ int call_down_setup(int callref, const char __attribute__((unused)) *caller_id,
break;
}
if (sender) {
PDEBUG(DANETZ, DEBUG_NOTICE, "Outgoing call to busy number, rejecting!\n");
LOGP(DANETZ, LOGL_NOTICE, "Outgoing call to busy number, rejecting!\n");
return -CAUSE_BUSY;
}
@ -416,13 +416,13 @@ int call_down_setup(int callref, const char __attribute__((unused)) *caller_id,
break;
}
if (!sender) {
PDEBUG(DANETZ, DEBUG_NOTICE, "Outgoing call, but no free channel, rejecting!\n");
LOGP(DANETZ, LOGL_NOTICE, "Outgoing call, but no free channel, rejecting!\n");
return -CAUSE_NOCHANNEL;
}
PDEBUG_CHAN(DANETZ, DEBUG_INFO, "Call to mobile station, paging with tones: %.1f %.1f %.1f %.1f\n", freq[0], freq[1], freq[2], freq[3]);
LOGP_CHAN(DANETZ, LOGL_INFO, "Call to mobile station, paging with tones: %.1f %.1f %.1f %.1f\n", freq[0], freq[1], freq[2], freq[3]);
if (anetz->page_sequence)
PDEBUG(DANETZ, DEBUG_NOTICE, "Sending paging tones in sequence.\n");
LOGP(DANETZ, LOGL_NOTICE, "Sending paging tones in sequence.\n");
/* 4. trying to page mobile station */
anetz->callref = callref;
@ -433,7 +433,7 @@ int call_down_setup(int callref, const char __attribute__((unused)) *caller_id,
return 0;
}
void call_down_answer(int __attribute__((unused)) callref)
void call_down_answer(int __attribute__((unused)) callref, struct timeval __attribute__((unused)) *tv_meter)
{
}
@ -446,7 +446,7 @@ void call_down_disconnect(int callref, int cause)
sender_t *sender;
anetz_t *anetz;
PDEBUG(DANETZ, DEBUG_INFO, "Call has been disconnected by network.\n");
LOGP(DANETZ, LOGL_INFO, "Call has been disconnected by network.\n");
for (sender = sender_head; sender; sender = sender->next) {
anetz = (anetz_t *) sender;
@ -454,7 +454,7 @@ void call_down_disconnect(int callref, int cause)
break;
}
if (!sender) {
PDEBUG(DANETZ, DEBUG_NOTICE, "Outgoing disconnect, but no callref!\n");
LOGP(DANETZ, LOGL_NOTICE, "Outgoing disconnect, but no callref!\n");
call_up_release(callref, CAUSE_INVALCALLREF);
return;
}
@ -464,7 +464,7 @@ void call_down_disconnect(int callref, int cause)
return;
switch (anetz->state) {
case ANETZ_ANRUF:
PDEBUG_CHAN(DANETZ, DEBUG_NOTICE, "Outgoing disconnect, during alerting, going idle!\n");
LOGP_CHAN(DANETZ, LOGL_NOTICE, "Outgoing disconnect, during alerting, going idle!\n");
anetz_go_idle(anetz);
break;
default:
@ -483,7 +483,7 @@ void call_down_release(int callref, __attribute__((unused)) int cause)
sender_t *sender;
anetz_t *anetz;
PDEBUG(DANETZ, DEBUG_INFO, "Call has been released by network, releasing call.\n");
LOGP(DANETZ, LOGL_INFO, "Call has been released by network, releasing call.\n");
for (sender = sender_head; sender; sender = sender->next) {
anetz = (anetz_t *) sender;
@ -491,7 +491,7 @@ void call_down_release(int callref, __attribute__((unused)) int cause)
break;
}
if (!sender) {
PDEBUG(DANETZ, DEBUG_NOTICE, "Outgoing release, but no callref!\n");
LOGP(DANETZ, LOGL_NOTICE, "Outgoing release, but no callref!\n");
/* don't send release, because caller already released */
return;
}
@ -500,11 +500,11 @@ void call_down_release(int callref, __attribute__((unused)) int cause)
switch (anetz->state) {
case ANETZ_GESPRAECH:
PDEBUG_CHAN(DANETZ, DEBUG_NOTICE, "Outgoing release, during call, sending release tone!\n");
LOGP_CHAN(DANETZ, LOGL_NOTICE, "Outgoing release, during call, sending release tone!\n");
anetz_release(anetz);
break;
case ANETZ_ANRUF:
PDEBUG_CHAN(DANETZ, DEBUG_NOTICE, "Outgoing release, during alerting, going idle!\n");
LOGP_CHAN(DANETZ, LOGL_NOTICE, "Outgoing release, during alerting, going idle!\n");
anetz_go_idle(anetz);
break;
default:
@ -512,28 +512,5 @@ void call_down_release(int callref, __attribute__((unused)) int cause)
}
}
/* Receive audio from call instance. */
void call_down_audio(int callref, sample_t *samples, int count)
{
sender_t *sender;
anetz_t *anetz;
for (sender = sender_head; sender; sender = sender->next) {
anetz = (anetz_t *) sender;
if (anetz->callref == callref)
break;
}
if (!sender)
return;
if (anetz->dsp_mode == DSP_MODE_AUDIO) {
sample_t up[(int)((double)count * anetz->sender.srstate.factor + 0.5) + 10];
count = samplerate_upsample(&anetz->sender.srstate, samples, count, up);
jitter_save(&anetz->sender.dejitter, up, count);
}
}
void call_down_clock(void) {}
void dump_info(void) {}

View File

@ -24,7 +24,7 @@ typedef struct anetz {
enum anetz_state state; /* current sender's state */
int callref; /* call reference */
char station_id[8]; /* current station ID */
struct timer timer;
struct osmo_timer_list timer;
/* display measurements */
dispmeasparam_t *dmp_tone_level;

View File

@ -1,4 +1,5 @@
#include <stdint.h>
#include "besetztton.h"
static int16_t pattern[] = {
0x0004, 0xffe9, 0xffc9, 0xffac, 0xff92, 0xff83, 0xff75, 0xff56,

View File

@ -26,8 +26,8 @@
#include <errno.h>
#include <math.h>
#include "../libsample/sample.h"
#include "../libdebug/debug.h"
#include "../libtimer/timer.h"
#include "../liblogging/logging.h"
#include <osmocom/core/timer.h>
#include "../libmobile/call.h"
#include "anetz.h"
#include "dsp.h"
@ -68,7 +68,7 @@ void dsp_init(void)
int i;
double s;
PDEBUG(DDSP, DEBUG_DEBUG, "Generating sine tables.\n");
LOGP(DDSP, LOGL_DEBUG, "Generating sine tables.\n");
for (i = 0; i < 65536; i++) {
s = sin((double)i / 65536.0 * 2.0 * PI);
dsp_sine_tone[i] = s * TX_PEAK_TONE;
@ -83,7 +83,7 @@ int dsp_init_sender(anetz_t *anetz, double page_gain, int page_sequence, double
int i;
double tone;
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Init DSP for 'Sender'.\n");
LOGP_CHAN(DDSP, LOGL_DEBUG, "Init DSP for 'Sender'.\n");
/* init squelch */
squelch_init(&anetz->squelch, anetz->sender.kanal, squelch_db, MUTE_TIME, LOSS_TIME);
@ -95,10 +95,10 @@ int dsp_init_sender(anetz_t *anetz, double page_gain, int page_sequence, double
anetz->page_sequence = page_sequence;
anetz->samples_per_chunk = anetz->sender.samplerate * CHUNK_DURATION;
PDEBUG(DDSP, DEBUG_DEBUG, "Using %d samples per filter chunk duration.\n", anetz->samples_per_chunk);
LOGP(DDSP, LOGL_DEBUG, "Using %d samples per filter chunk duration.\n", anetz->samples_per_chunk);
spl = calloc(anetz->samples_per_chunk, sizeof(sample_t));
if (!spl) {
PDEBUG(DDSP, DEBUG_ERROR, "No memory!\n");
LOGP(DDSP, LOGL_ERROR, "No memory!\n");
return -ENOMEM;
}
anetz->fsk_filter_spl = spl;
@ -119,7 +119,7 @@ int dsp_init_sender(anetz_t *anetz, double page_gain, int page_sequence, double
/* Cleanup transceiver instance. */
void dsp_cleanup_sender(anetz_t *anetz)
{
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Cleanup DSP for 'Sender'.\n");
LOGP_CHAN(DDSP, LOGL_DEBUG, "Cleanup DSP for 'Sender'.\n");
if (anetz->fsk_filter_spl) {
free(anetz->fsk_filter_spl);
@ -133,7 +133,7 @@ static void fsk_receive_tone(anetz_t *anetz, int tone, int goodtone, double leve
/* lost tone because it is not good anymore or has changed */
if (!goodtone || tone != anetz->tone_detected) {
if (anetz->tone_count >= TONE_DETECT_TH) {
PDEBUG_CHAN(DDSP, DEBUG_INFO, "Lost %.0f Hz tone after %.0f ms.\n", fsk_tones[anetz->tone_detected], 1000.0 * CHUNK_DURATION * anetz->tone_count);
LOGP_CHAN(DDSP, LOGL_INFO, "Lost %.0f Hz tone after %.0f ms.\n", fsk_tones[anetz->tone_detected], 1000.0 * CHUNK_DURATION * anetz->tone_count);
anetz_receive_tone(anetz, -1);
}
if (goodtone)
@ -148,7 +148,7 @@ static void fsk_receive_tone(anetz_t *anetz, int tone, int goodtone, double leve
anetz->tone_count++;
if (anetz->tone_count == TONE_DETECT_TH) {
PDEBUG_CHAN(DDSP, DEBUG_INFO, "Detecting continuous %.0f Hz tone. (level = %.0f%%, quality =%.0f%%)\n", fsk_tones[anetz->tone_detected], level * 100.0, quality * 100.0);
LOGP_CHAN(DDSP, LOGL_INFO, "Detecting continuous %.0f Hz tone. (level = %.0f%%, quality =%.0f%%)\n", fsk_tones[anetz->tone_detected], level * 100.0, quality * 100.0);
anetz_receive_tone(anetz, anetz->tone_detected);
}
}
@ -171,7 +171,7 @@ static void fsk_decode_chunk(anetz_t *anetz, sample_t *spl, int max)
display_measurements_update(anetz->dmp_tone_level, level * 100.0, 0.0);
display_measurements_update(anetz->dmp_tone_quality, quality[1] * 100.0, 0.0);
if ((level > TONE_THRESHOLD && quality[1] > QUAL_THRESHOLD) || anetz->sender.loopback)
PDEBUG_CHAN(DDSP, DEBUG_INFO, "Tone %.0f: Level=%3.0f%% Quality=%3.0f%%\n", fsk_tones[1], level * 100.0, quality[1] * 100.0);
LOGP_CHAN(DDSP, LOGL_INFO, "Tone %.0f: Level=%3.0f%% Quality=%3.0f%%\n", fsk_tones[1], level * 100.0, quality[1] * 100.0);
/* adjust level, so we get peak of sine curve */
/* indicate detected tone */
@ -357,6 +357,7 @@ static void fsk_tone(anetz_t *anetz, sample_t *samples, int length)
void sender_send(sender_t *sender, sample_t *samples, uint8_t *power, int length)
{
anetz_t *anetz = (anetz_t *) sender;
int input_num;
memset(power, 1, length);
@ -365,7 +366,13 @@ void sender_send(sender_t *sender, sample_t *samples, uint8_t *power, int length
memset(samples, 0, length * sizeof(*samples));
break;
case DSP_MODE_AUDIO:
jitter_load(&anetz->sender.dejitter, samples, length);
input_num = samplerate_upsample_input_num(&sender->srstate, length);
{
int16_t spl[input_num];
jitter_load_samples(&sender->dejitter, (uint8_t *)spl, input_num, sizeof(*spl), jitter_conceal_s16, NULL);
int16_to_samples_speech(samples, spl, input_num);
}
samplerate_upsample(&sender->srstate, samples, input_num, samples, length);
break;
case DSP_MODE_TONE:
fsk_tone(anetz, samples, length);
@ -379,7 +386,7 @@ void sender_send(sender_t *sender, sample_t *samples, uint8_t *power, int length
}
}
const char *anetz_dsp_mode_name(enum dsp_mode mode)
static const char *anetz_dsp_mode_name(enum dsp_mode mode)
{
static char invalid[16];
@ -400,7 +407,10 @@ const char *anetz_dsp_mode_name(enum dsp_mode mode)
void anetz_set_dsp_mode(anetz_t *anetz, enum dsp_mode mode, int detect_reset)
{
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "DSP mode %s -> %s\n", anetz_dsp_mode_name(anetz->dsp_mode), anetz_dsp_mode_name(mode));
LOGP_CHAN(DDSP, LOGL_DEBUG, "DSP mode %s -> %s\n", anetz_dsp_mode_name(anetz->dsp_mode), anetz_dsp_mode_name(mode));
if (mode == DSP_MODE_AUDIO && anetz->dsp_mode != mode)
jitter_reset(&anetz->sender.dejitter);
anetz->dsp_mode = mode;
/* reset sequence paging */
anetz->paging_tone = 0;
@ -411,3 +421,27 @@ void anetz_set_dsp_mode(anetz_t *anetz, enum dsp_mode mode, int detect_reset)
anetz->tone_detected = -1;
}
/* Receive audio from call instance. */
void call_down_audio(void *decoder, void *decoder_priv, int callref, uint16_t sequence, uint8_t marker, uint32_t timestamp, uint32_t ssrc, uint8_t *payload, int payload_len)
{
sender_t *sender;
anetz_t *anetz;
for (sender = sender_head; sender; sender = sender->next) {
anetz = (anetz_t *) sender;
if (anetz->callref == callref)
break;
}
if (!sender)
return;
if (anetz->dsp_mode == DSP_MODE_AUDIO) {
jitter_frame_t *jf;
jf = jitter_frame_alloc(decoder, decoder_priv, payload, payload_len, marker, sequence, timestamp, ssrc);
if (jf)
jitter_save(&anetz->sender.dejitter, jf);
}
}
void call_down_clock(void) {}

View File

@ -1,4 +1,5 @@
#include <stdint.h>
#include "freiton.h"
static int16_t pattern[] = {
0x0056, 0x0068, 0x0065, 0x005d, 0x0040, 0x0031, 0x001a, 0x000d,

View File

@ -25,8 +25,8 @@
#include <math.h>
#include "../libsample/sample.h"
#include "../libmobile/main_mobile.h"
#include "../libdebug/debug.h"
#include "../libtimer/timer.h"
#include "../liblogging/logging.h"
#include <osmocom/core/timer.h>
#include "../libmobile/call.h"
#include "../liboptions/options.h"
#include "../libfm/fm.h"
@ -198,6 +198,7 @@ fail:
anetz_destroy(sender_head);
/* exits */
main_mobile_exit();
fm_exit();
options_free();

View File

@ -2,6 +2,7 @@
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "stations.h"
static struct anetz_stations {
const char *standort;
@ -147,7 +148,7 @@ static struct anetz_stations {
{ NULL, 0, 0, 0, 0, 0, NULL }
};
double lat_from_coordinates(const char *string)
static double lat_from_coordinates(const char *string)
{
if (strlen(string) != 11)
abort();
@ -168,7 +169,7 @@ double lat_from_coordinates(const char *string)
(double)(string[4] - '0') / 60.0;
}
double lon_from_coordinates(const char *string)
static double lon_from_coordinates(const char *string)
{
if (strlen(string) != 11)
abort();
@ -200,7 +201,45 @@ void station_list(void)
printf("List of all base stations:\n");
for (i = 0; anetz_stations[i].standort; i++) {
printf("%s (%.2f° N %.2f° E)\n", anetz_stations[i].standort, lat_from_coordinates(anetz_stations[i].coordinates), lon_from_coordinates(anetz_stations[i].coordinates));
printf("%s (%.2f deg N %.2f deg E)\n", anetz_stations[i].standort, lat_from_coordinates(anetz_stations[i].coordinates), lon_from_coordinates(anetz_stations[i].coordinates));
if (anetz_stations[i].kanal21) {
if (anetz_stations[i].kanal22)
printf("\tPrefix 21: Channel %d\n", anetz_stations[i].kanal21);
else if (anetz_stations[i].kanal23)
printf("\tPrefix 21-22: Channel %d\n", anetz_stations[i].kanal21);
else if (anetz_stations[i].kanal24)
printf("\tPrefix 21-23: Channel %d\n", anetz_stations[i].kanal21);
else if (anetz_stations[i].kanal25)
printf("\tPrefix 21-24: Channel %d\n", anetz_stations[i].kanal21);
else
printf("\tPrefix 21-25: Channel %d\n", anetz_stations[i].kanal21);
}
if (anetz_stations[i].kanal22) {
if (anetz_stations[i].kanal23)
printf("\tPrefix 22: Channel %d\n", anetz_stations[i].kanal22);
else if (anetz_stations[i].kanal24)
printf("\tPrefix 22-23: Channel %d\n", anetz_stations[i].kanal22);
else if (anetz_stations[i].kanal25)
printf("\tPrefix 22-24: Channel %d\n", anetz_stations[i].kanal22);
else
printf("\tPrefix 22-25: Channel %d\n", anetz_stations[i].kanal22);
}
if (anetz_stations[i].kanal23) {
if (anetz_stations[i].kanal24)
printf("\tPrefix 23: Channel %d\n", anetz_stations[i].kanal23);
else if (anetz_stations[i].kanal25)
printf("\tPrefix 23-24: Channel %d\n", anetz_stations[i].kanal23);
else
printf("\tPrefix 23-25: Channel %d\n", anetz_stations[i].kanal23);
}
if (anetz_stations[i].kanal24) {
if (anetz_stations[i].kanal25)
printf("\tPrefix 24: Channel %d\n", anetz_stations[i].kanal24);
else
printf("\tPrefix 24-25: Channel %d\n", anetz_stations[i].kanal24);
}
if (anetz_stations[i].kanal25)
printf("\tPrefix 25: Channel %d\n", anetz_stations[i].kanal25);
}
}

View File

@ -1,4 +1,4 @@
AM_CPPFLAGS = -Wall -Wextra -g $(all_includes)
AM_CPPFLAGS = -Wall -Wextra -Wmissing-prototypes -g $(all_includes)
bin_PROGRAMS = \
bnetz \
@ -16,13 +16,10 @@ bnetz_LDADD = \
$(COMMON_LA) \
../anetz/libgermanton.a \
$(top_builddir)/src/liboptions/liboptions.a \
$(top_builddir)/src/libdebug/libdebug.a \
$(top_builddir)/src/libmobile/libmobile.a \
$(top_builddir)/src/libosmocc/libosmocc.a \
$(top_builddir)/src/libdisplay/libdisplay.a \
$(top_builddir)/src/libjitter/libjitter.a \
$(top_builddir)/src/libsquelch/libsquelch.a \
$(top_builddir)/src/libtimer/libtimer.a \
$(top_builddir)/src/libsamplerate/libsamplerate.a \
$(top_builddir)/src/libemphasis/libemphasis.a \
$(top_builddir)/src/libfsk/libfsk.a \
@ -30,8 +27,10 @@ bnetz_LDADD = \
$(top_builddir)/src/libfilter/libfilter.a \
$(top_builddir)/src/libwave/libwave.a \
$(top_builddir)/src/libsample/libsample.a \
$(top_builddir)/src/libg711/libg711.a \
$(top_builddir)/src/libaaimage/libaaimage.a \
$(top_builddir)/src/liblogging/liblogging.a \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOCC_LIBS) \
-lm
bnetz_dialer_SOURCES = \
@ -40,12 +39,14 @@ bnetz_dialer_SOURCES = \
bnetz_dialer_LDADD = \
$(COMMON_LA) \
$(top_builddir)/src/liboptions/liboptions.a \
$(top_builddir)/src/libdebug/libdebug.a \
$(top_builddir)/src/libfsk/libfsk.a \
$(top_builddir)/src/libfm/libfm.a \
$(top_builddir)/src/libfilter/libfilter.a \
$(top_builddir)/src/libwave/libwave.a \
$(top_builddir)/src/libsample/libsample.a \
$(top_builddir)/src/liblogging/liblogging.a \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOCC_LIBS) \
$(ALSA_LIBS)
-lm

View File

@ -25,32 +25,33 @@
#include <string.h>
#include <errno.h>
#include "../libsample/sample.h"
#include "../libdebug/debug.h"
#include "../liblogging/logging.h"
#include "../libmobile/call.h"
#include "../libmobile/cause.h"
#include "../libosmocc/message.h"
#include "../libmobile/get_time.h"
#include <osmocom/cc/message.h>
#include "bnetz.h"
#include "telegramm.h"
#include "dsp.h"
/* mobile originating call */
#define CARRIER_TO 0.08 /* 80 ms search for carrier */
#define DIALING_TO 3.8 /* timeout after channel allocation "Kanalbelegung" (according to FTZ 1727 Pfl 32 Clause 3.2.2.2.8) */
#define DIALING_TO2 0.5 /* timeout while receiving digits */
#define CARRIER_TO 0.080000 /* 80 ms search for carrier */
#define DIALING_TO 3,800000 /* timeout after channel allocation "Kanalbelegung" (according to FTZ 1727 Pfl 32 Clause 3.2.2.2.8) */
#define DIALING_TO2 0,500000 /* timeout while receiving digits */
/* mobile terminating call */
#define ALERTING_TO 60 /* timeout after 60 seconds alerting the MS (according to FTZ 1727 Pfl 32 Clause 3.2.2.2.7) */
#define PAGING_TO 2.1 /* 700..2100 ms timeout after paging "Selektivruf" (according to FTZ 1727 Pfl 32 Clause 3.2.2.2.4.3) */
#define PAGE_TRIES 2 /* two tries (see Clause 3.2.2.2.4.3) */
#define SWITCH19_TIME 1.0 /* time to switch channel (radio should be tansmitting after that) */
#define SWITCHBACK_TIME 0.1 /* time to wait until switching back (latency of sound device shall be lower) */
#define ALERTING_TO 60,0 /* timeout after 60 seconds alerting the MS (according to FTZ 1727 Pfl 32 Clause 3.2.2.2.7) */
#define PAGING_TO 2,100000 /* 700..2100 ms timeout after paging "Selektivruf" (according to FTZ 1727 Pfl 32 Clause 3.2.2.2.4.3) */
#define PAGE_TRIES 2 /* two tries (see Clause 3.2.2.2.4.3) */
#define SWITCH19_TIME 1,0 /* time to switch channel (radio should be tansmitting after that) */
#define SWITCHBACK_TIME 0,100000 /* time to wait until switching back (latency of sound device shall be lower) */
#define TRENN_COUNT 5 /* min. 720 ms release 'Trennsignal' (according to FTZ 1727 Pfl 32 Clause 3.2.2.2.6) */
#define TRENN_COUNT 5 /* min. 720 ms release 'Trennsignal' (according to FTZ 1727 Pfl 32 Clause 3.2.2.2.6) */
#define METERING_DURATION 0.140 /* duration of metering pulse (according to FTZ 1727 Pfl 32 Clause 3.2.6.6.1) */
#define METERING_START 1.0 /* start metering 1 second after call start */
#define METERING_DURATION_US 140000 /* duration of metering pulse (according to FTZ 1727 Pfl 32 Clause 3.2.6.6.1) */
#define METERING_START 1,0 /* start metering 1 second after call start */
const char *bnetz_state_name(enum bnetz_state state)
static const char *bnetz_state_name(enum bnetz_state state)
{
static char invalid[16];
@ -79,7 +80,7 @@ const char *bnetz_state_name(enum bnetz_state state)
return invalid;
}
void bnetz_display_status(void)
static void bnetz_display_status(void)
{
sender_t *sender;
bnetz_t *bnetz;
@ -99,7 +100,7 @@ static void bnetz_new_state(bnetz_t *bnetz, enum bnetz_state new_state)
{
if (bnetz->state == new_state)
return;
PDEBUG_CHAN(DBNETZ, DEBUG_DEBUG, "State change: %s -> %s\n", bnetz_state_name(bnetz->state), bnetz_state_name(new_state));
LOGP_CHAN(DBNETZ, LOGL_DEBUG, "State change: %s -> %s\n", bnetz_state_name(bnetz->state), bnetz_state_name(new_state));
bnetz->state = new_state;
bnetz_display_status();
}
@ -133,7 +134,7 @@ static void switch_channel_19(bnetz_t *bnetz, int on)
fp = fopen(bnetz->paging_file, "w");
if (!fp) {
PDEBUG(DBNETZ, DEBUG_ERROR, "Failed to open file '%s' to switch channel 19!\n", bnetz->paging_file);
LOGP(DBNETZ, LOGL_ERROR, "Failed to open file '%s' to switch channel 19!\n", bnetz->paging_file);
return;
}
fprintf(fp, "%s\n", (on) ? bnetz->paging_on : bnetz->paging_off);
@ -150,7 +151,7 @@ int bnetz_init(void)
return 0;
}
static void bnetz_timeout(struct timer *timer);
static void bnetz_timeout(void *data);
static void bnetz_go_idle(bnetz_t *bnetz);
/* Create transceiver instance and link to a list. */
@ -162,22 +163,22 @@ int bnetz_create(const char *kanal, const char *device, int use_sdr, int sampler
int rc;
if (!(atoi(kanal) >= 1 && atoi(kanal) <= 39) && !(atoi(kanal) >= 50 && atoi(kanal) <= 86)) {
PDEBUG(DBNETZ, DEBUG_ERROR, "Channel ('Kanal') number %s invalid.\n", kanal);
LOGP(DBNETZ, LOGL_ERROR, "Channel ('Kanal') number %s invalid.\n", kanal);
return -EINVAL;
}
if (atoi(kanal) == 19) {
PDEBUG(DBNETZ, DEBUG_ERROR, "Selected calling channel ('Rufkanal') number %s can't be used as traffic channel.\n", kanal);
LOGP(DBNETZ, LOGL_ERROR, "Selected calling channel ('Rufkanal') number %s can't be used as traffic channel.\n", kanal);
return -EINVAL;
}
if (atoi(kanal) >= 38 && atoi(kanal) <= 39)
PDEBUG(DBNETZ, DEBUG_NOTICE, "Selected channel ('Kanal') number %s may not be supported by older B1-Network phones.\n", kanal);
LOGP(DBNETZ, LOGL_NOTICE, "Selected channel ('Kanal') number %s may not be supported by older B1-Network phones.\n", kanal);
if (atoi(kanal) >= 50)
PDEBUG(DBNETZ, DEBUG_NOTICE, "Selected channel ('Kanal') number %s belongs to B2-Network and is not supported by B1 phones.\n", kanal);
LOGP(DBNETZ, LOGL_NOTICE, "Selected channel ('Kanal') number %s belongs to B2-Network and is not supported by B1 phones.\n", kanal);
if ((gfs < 1 || gfs > 19)) {
PDEBUG(DBNETZ, DEBUG_ERROR, "Given 'Gruppenfreisignal' %d invalid.\n", gfs);
LOGP(DBNETZ, LOGL_ERROR, "Given 'Gruppenfreisignal' %d invalid.\n", gfs);
return -EINVAL;
}
@ -199,7 +200,7 @@ int bnetz_create(const char *kanal, const char *device, int use_sdr, int sampler
p = strchr(paging_file, '=');
if (!p) {
error_paging:
PDEBUG(DBNETZ, DEBUG_ERROR, "Given paging file (to switch to channel 19) is missing parameters. Use <file>=<on>:<off> format!\n");
LOGP(DBNETZ, LOGL_ERROR, "Given paging file (to switch to channel 19) is missing parameters. Use <file>=<on>:<off> format!\n");
return -EINVAL;
}
*p++ = '\0';
@ -213,16 +214,16 @@ error_paging:
bnetz = calloc(1, sizeof(bnetz_t));
if (!bnetz) {
PDEBUG(DBNETZ, DEBUG_ERROR, "No memory!\n");
LOGP(DBNETZ, LOGL_ERROR, "No memory!\n");
return -ENOMEM;
}
PDEBUG(DBNETZ, DEBUG_DEBUG, "Creating 'B-Netz' instance for 'Kanal' = %s 'Gruppenfreisignal' = %d (sample rate %d).\n", kanal, gfs, samplerate);
LOGP(DBNETZ, LOGL_DEBUG, "Creating 'B-Netz' instance for 'Kanal' = %s 'Gruppenfreisignal' = %d (sample rate %d).\n", kanal, gfs, samplerate);
/* init general part of transceiver */
rc = sender_create(&bnetz->sender, kanal, bnetz_kanal2freq(atoi(kanal), 0), bnetz_kanal2freq(atoi(kanal), 1), device, use_sdr, samplerate, rx_gain, tx_gain, pre_emphasis, de_emphasis, write_rx_wave, write_tx_wave, read_rx_wave, read_tx_wave, loopback, paging_signal);
if (rc < 0) {
PDEBUG(DBNETZ, DEBUG_ERROR, "Failed to init transceiver process!\n");
LOGP(DBNETZ, LOGL_ERROR, "Failed to init transceiver process!\n");
goto error;
}
bnetz->sender.ruffrequenz = bnetz_kanal2freq(19, 0);
@ -230,7 +231,7 @@ error_paging:
/* init audio processing */
rc = dsp_init_sender(bnetz, squelch_db);
if (rc < 0) {
PDEBUG(DBNETZ, DEBUG_ERROR, "Failed to init audio processing!\n");
LOGP(DBNETZ, LOGL_ERROR, "Failed to init audio processing!\n");
goto error;
}
@ -239,13 +240,13 @@ error_paging:
strncpy(bnetz->paging_file, paging_file, sizeof(bnetz->paging_file) - 1);
strncpy(bnetz->paging_on, paging_on, sizeof(bnetz->paging_on) - 1);
strncpy(bnetz->paging_off, paging_off, sizeof(bnetz->paging_off) - 1);
timer_init(&bnetz->timer, bnetz_timeout, bnetz);
osmo_timer_setup(&bnetz->timer, bnetz_timeout, bnetz);
/* go into idle state */
bnetz_go_idle(bnetz);
PDEBUG(DBNETZ, DEBUG_NOTICE, "Created 'Kanal' #%s\n", kanal);
PDEBUG(DBNETZ, DEBUG_NOTICE, " -> Using station ID (Gruppenfreisignal) %d\n", gfs);
LOGP(DBNETZ, LOGL_NOTICE, "Created 'Kanal' #%s\n", kanal);
LOGP(DBNETZ, LOGL_NOTICE, " -> Using station ID (Gruppenfreisignal) %d\n", gfs);
return 0;
@ -260,10 +261,10 @@ void bnetz_destroy(sender_t *sender)
{
bnetz_t *bnetz = (bnetz_t *) sender;
PDEBUG(DBNETZ, DEBUG_DEBUG, "Destroying 'B-Netz' instance for 'Kanal' = %s.\n", sender->kanal);
LOGP(DBNETZ, LOGL_DEBUG, "Destroying 'B-Netz' instance for 'Kanal' = %s.\n", sender->kanal);
switch_channel_19(bnetz, 0);
dsp_cleanup_sender(bnetz);
timer_exit(&bnetz->timer);
osmo_timer_del(&bnetz->timer);
sender_destroy(&bnetz->sender);
free(bnetz);
}
@ -271,9 +272,9 @@ void bnetz_destroy(sender_t *sender)
/* releaseing connection towards mobile station by sending idle digits. */
static void bnetz_go_idle(bnetz_t *bnetz)
{
timer_stop(&bnetz->timer);
osmo_timer_del(&bnetz->timer);
PDEBUG(DBNETZ, DEBUG_INFO, "Entering IDLE state on channel %s, sending 'Gruppenfreisignal' %d.\n", bnetz->sender.kanal, bnetz->gfs);
LOGP(DBNETZ, LOGL_INFO, "Entering IDLE state on channel %s, sending 'Gruppenfreisignal' %d.\n", bnetz->sender.kanal, bnetz->gfs);
bnetz->station_id[0] = '\0'; /* remove station ID before state change, so status is shown correctly */
bnetz_new_state(bnetz, BNETZ_FREI);
bnetz_set_dsp_mode(bnetz, DSP_MODE_TELEGRAMM);
@ -283,9 +284,9 @@ static void bnetz_go_idle(bnetz_t *bnetz)
/* Release connection towards mobile station by sending release digits. */
static void bnetz_release(bnetz_t *bnetz, int trenn_count)
{
timer_stop(&bnetz->timer);
osmo_timer_del(&bnetz->timer);
PDEBUG_CHAN(DBNETZ, DEBUG_INFO, "Entering release state, sending 'Trennsignal' (%d times).\n", trenn_count);
LOGP_CHAN(DBNETZ, LOGL_INFO, "Entering release state, sending 'Trennsignal' (%d times).\n", trenn_count);
bnetz->station_id[0] = '\0'; /* remove station ID before state change, so status is shown correctly */
bnetz_new_state(bnetz, BNETZ_TRENNEN);
bnetz_set_dsp_mode(bnetz, DSP_MODE_TELEGRAMM);
@ -296,14 +297,14 @@ static void bnetz_release(bnetz_t *bnetz, int trenn_count)
/* Enter paging state and transmit station ID. */
static void bnetz_page(bnetz_t *bnetz, const char *dial_string, int try)
{
PDEBUG_CHAN(DBNETZ, DEBUG_INFO, "Entering paging state (try %d), sending 'Selektivruf' to '%s'.\n", try, dial_string);
strcpy(bnetz->station_id, dial_string); /* set station ID before state change, so status is shown correctly */
LOGP_CHAN(DBNETZ, LOGL_INFO, "Entering paging state (try %d), sending 'Selektivruf' to '%s'.\n", try, dial_string);
memmove(bnetz->station_id, dial_string, strlen(dial_string) + 1); /* set station ID before state change, so status is shown correctly */
bnetz->station_id_pos = 0;
bnetz_new_state(bnetz, BNETZ_SELEKTIVRUF_EIN);
bnetz_set_dsp_mode(bnetz, DSP_MODE_0);
bnetz->page_mode = PAGE_MODE_NUMBER;
bnetz->page_try = try;
timer_start(&bnetz->timer, SWITCH19_TIME);
osmo_timer_schedule(&bnetz->timer, SWITCH19_TIME);
switch_channel_19(bnetz, 1);
}
@ -332,10 +333,10 @@ const char *bnetz_get_telegramm(bnetz_t *bnetz)
break;
case BNETZ_SELEKTIVRUF_EIN:
if (bnetz->page_mode == PAGE_MODE_KANALBEFEHL) {
PDEBUG_CHAN(DBNETZ, DEBUG_INFO, "Paging mobile station %s complete, waiting for answer.\n", bnetz->station_id);
LOGP_CHAN(DBNETZ, LOGL_INFO, "Paging mobile station %s complete, waiting for answer.\n", bnetz->station_id);
bnetz_new_state(bnetz, BNETZ_SELEKTIVRUF_AUS);
bnetz_set_dsp_mode(bnetz, DSP_MODE_SILENCE);
timer_start(&bnetz->timer, SWITCHBACK_TIME);
osmo_timer_schedule(&bnetz->timer, SWITCHBACK_TIME);
return NULL;
}
if (bnetz->station_id_pos == 5) {
@ -347,7 +348,7 @@ const char *bnetz_get_telegramm(bnetz_t *bnetz)
break;
case BNETZ_TRENNEN:
if (bnetz->trenn_count-- == 0) {
PDEBUG_CHAN(DBNETZ, DEBUG_DEBUG, "Maximum number of release digits sent, going idle.\n");
LOGP_CHAN(DBNETZ, LOGL_DEBUG, "Maximum number of release digits sent, going idle.\n");
bnetz_go_idle(bnetz);
return NULL;
}
@ -360,7 +361,7 @@ const char *bnetz_get_telegramm(bnetz_t *bnetz)
if (!it)
abort();
PDEBUG_CHAN(DBNETZ, DEBUG_DEBUG, "Sending telegramm '%s'.\n", it->description);
LOGP_CHAN(DBNETZ, LOGL_DEBUG, "Sending telegramm '%s'.\n", it->description);
return it->sequence;
}
@ -369,7 +370,7 @@ void bnetz_loss_indication(bnetz_t *bnetz, double loss_time)
{
if (bnetz->state == BNETZ_GESPRAECH
|| bnetz->state == BNETZ_RUFHALTUNG) {
PDEBUG_CHAN(DBNETZ, DEBUG_NOTICE, "Detected loss of signal after %.1f seconds, releasing.\n", loss_time);
LOGP_CHAN(DBNETZ, LOGL_NOTICE, "Detected loss of signal after %.1f seconds, releasing.\n", loss_time);
bnetz_release(bnetz, TRENN_COUNT);
call_up_release(bnetz->callref, CAUSE_TEMPFAIL);
bnetz->callref = 0;
@ -380,9 +381,9 @@ void bnetz_loss_indication(bnetz_t *bnetz, double loss_time)
void bnetz_receive_tone(bnetz_t *bnetz, int bit)
{
if (bit >= 0)
PDEBUG_CHAN(DBNETZ, DEBUG_DEBUG, "Received continuous %d Hz tone.\n", (bit)?1950:2070);
LOGP_CHAN(DBNETZ, LOGL_DEBUG, "Received continuous %d Hz tone.\n", (bit)?1950:2070);
else
PDEBUG_CHAN(DBNETZ, DEBUG_DEBUG, "Continuous tone is gone.\n");
LOGP_CHAN(DBNETZ, LOGL_DEBUG, "Continuous tone is gone.\n");
if (bnetz->sender.loopback) {
return;
@ -391,11 +392,11 @@ void bnetz_receive_tone(bnetz_t *bnetz, int bit)
switch (bnetz->state) {
case BNETZ_FREI:
if (bit == 0) {
PDEBUG_CHAN(DBNETZ, DEBUG_INFO, "Received signal 'Kanalbelegung' from mobile station, sending signal 'Wahlabruf'.\n");
LOGP_CHAN(DBNETZ, LOGL_INFO, "Received signal 'Kanalbelegung' from mobile station, sending signal 'Wahlabruf'.\n");
bnetz_new_state(bnetz, BNETZ_WAHLABRUF);
bnetz->dial_mode = DIAL_MODE_START;
bnetz_set_dsp_mode(bnetz, DSP_MODE_1);
timer_start(&bnetz->timer, DIALING_TO);
osmo_timer_schedule(&bnetz->timer, DIALING_TO);
/* must reset, so we will not get corrupt first digit */
bnetz->rx_telegramm = bnetz->tone_detected * 0xffff;
break;
@ -403,24 +404,27 @@ void bnetz_receive_tone(bnetz_t *bnetz, int bit)
break;
case BNETZ_RUFBESTAETIGUNG:
if (bit == 1) {
PDEBUG_CHAN(DBNETZ, DEBUG_INFO, "Received signal 'Rufbestaetigung' from mobile station, sending signal 'Rufhaltung'. (call is ringing)\n");
timer_stop(&bnetz->timer);
LOGP_CHAN(DBNETZ, LOGL_INFO, "Received signal 'Rufbestaetigung' from mobile station, sending signal 'Rufhaltung'. (call is ringing)\n");
osmo_timer_del(&bnetz->timer);
bnetz_new_state(bnetz, BNETZ_RUFHALTUNG);
bnetz_set_dsp_mode(bnetz, DSP_MODE_1);
call_up_alerting(bnetz->callref);
timer_start(&bnetz->timer, ALERTING_TO);
osmo_timer_schedule(&bnetz->timer, ALERTING_TO);
break;
}
break;
case BNETZ_RUFHALTUNG:
if (bit == 0) {
PDEBUG_CHAN(DBNETZ, DEBUG_INFO, "Received signal 'Beginnsignal' from mobile station, call establised.\n");
timer_stop(&bnetz->timer);
LOGP_CHAN(DBNETZ, LOGL_INFO, "Received signal 'Beginnsignal' from mobile station, call establised.\n");
osmo_timer_del(&bnetz->timer);
bnetz_new_state(bnetz, BNETZ_GESPRAECH);
bnetz_set_dsp_mode(bnetz, DSP_MODE_AUDIO);
/* start metering pulses if forced */
if (bnetz->metering < 0)
timer_start(&bnetz->timer, METERING_START);
/* start metering pulses, if forced (mobile terminating call) */
if (bnetz->metering < 0) {
bnetz->metering_tv.tv_sec = abs(bnetz->metering);
bnetz->metering_tv.tv_usec = 0;
osmo_timer_schedule(&bnetz->timer, METERING_START);
}
call_up_answer(bnetz->callref, bnetz->station_id);
break;
}
@ -438,22 +442,22 @@ void bnetz_receive_telegramm(bnetz_t *bnetz, uint16_t telegramm)
it = bnetz_telegramm2digit(telegramm);
if (it) {
digit = it->digit;
PDEBUG(DBNETZ, (bnetz->sender.loopback) ? DEBUG_NOTICE : DEBUG_INFO, "Received telegramm '%s'\n", it->description);
LOGP(DBNETZ, (bnetz->sender.loopback) ? LOGL_NOTICE : LOGL_INFO, "Received telegramm '%s'\n", it->description);
} else {
PDEBUG(DBNETZ, DEBUG_DEBUG, "Received unknown telegramm digit '0x%04x' (might be radio noise)\n", telegramm);
LOGP(DBNETZ, LOGL_DEBUG, "Received unknown telegramm digit '0x%04x' (might be radio noise)\n", telegramm);
return;
}
if (bnetz->sender.loopback) {
if (digit >= '0' && digit <= '9') {
PDEBUG(DBNETZ, DEBUG_NOTICE, "Round trip delay is %.3f seconds\n", get_time() - bnetz->loopback_time[digit - '0'] - 0.160);
LOGP(DBNETZ, LOGL_NOTICE, "Round trip delay is %.3f seconds\n", get_time() - bnetz->loopback_time[digit - '0'] - 0.160);
}
return;
}
switch (bnetz->state) {
case BNETZ_WAHLABRUF:
timer_start(&bnetz->timer, DIALING_TO2);
osmo_timer_schedule(&bnetz->timer, DIALING_TO2);
switch (bnetz->dial_mode) {
case DIAL_MODE_START:
switch (digit) {
@ -467,7 +471,7 @@ void bnetz_receive_telegramm(bnetz_t *bnetz, uint16_t telegramm)
bnetz->dial_type = DIAL_TYPE_METER_MUENZ;
break;
default:
PDEBUG(DBNETZ, DEBUG_NOTICE, "Received digit that is not a start digit ('Funkwahl'), releaseing.\n");
LOGP(DBNETZ, LOGL_NOTICE, "Received digit that is not a start digit ('Funkwahl'), releaseing.\n");
bnetz_release(bnetz, TRENN_COUNT);
return;
}
@ -477,7 +481,7 @@ void bnetz_receive_telegramm(bnetz_t *bnetz, uint16_t telegramm)
break;
case DIAL_MODE_STATIONID:
if (digit < '0' || digit > '9') {
PDEBUG(DBNETZ, DEBUG_NOTICE, "Received message that is not a valid station id digit, releaseing.\n");
LOGP(DBNETZ, LOGL_NOTICE, "Received message that is not a valid station id digit, releaseing.\n");
bnetz_release(bnetz, TRENN_COUNT);
return;
}
@ -485,29 +489,29 @@ void bnetz_receive_telegramm(bnetz_t *bnetz, uint16_t telegramm)
/* update status while receiving station ID */
bnetz_display_status();
if (bnetz->dial_pos == 5) {
PDEBUG(DBNETZ, DEBUG_INFO, "Received station id from mobile phone: %s\n", bnetz->station_id);
LOGP(DBNETZ, LOGL_INFO, "Received station id from mobile phone: %s\n", bnetz->station_id);
bnetz->dial_mode = DIAL_MODE_NUMBER;
memset(bnetz->dial_number, 0, sizeof(bnetz->dial_number));
bnetz->dial_pos = 0;
/* reply station ID */
PDEBUG(DBNETZ, DEBUG_INFO, "Sending station id back to phone: %s.\n", bnetz->station_id);
LOGP(DBNETZ, LOGL_INFO, "Sending station id back to phone: %s.\n", bnetz->station_id);
bnetz_set_dsp_mode(bnetz, DSP_MODE_TELEGRAMM);
bnetz->station_id_pos = 0;
}
break;
case DIAL_MODE_NUMBER:
if (digit == 'e') {
PDEBUG(DBNETZ, DEBUG_INFO, "Received number from mobile phone: %s\n", bnetz->dial_number);
LOGP(DBNETZ, LOGL_INFO, "Received number from mobile phone: %s\n", bnetz->dial_number);
bnetz->dial_mode = DIAL_MODE_START2;
break;
}
if (digit < '0' || digit > '9') {
PDEBUG(DBNETZ, DEBUG_NOTICE, "Received message that is not a valid number digit, releaseing.\n");
LOGP(DBNETZ, LOGL_NOTICE, "Received message that is not a valid number digit, releaseing.\n");
bnetz_release(bnetz, TRENN_COUNT);
return;
}
if (bnetz->dial_pos == sizeof(bnetz->dial_number) - 1) {
PDEBUG(DBNETZ, DEBUG_NOTICE, "Received too many number digits, releaseing.\n");
LOGP(DBNETZ, LOGL_NOTICE, "Received too many number digits, releaseing.\n");
bnetz_release(bnetz, TRENN_COUNT);
return;
}
@ -517,27 +521,27 @@ void bnetz_receive_telegramm(bnetz_t *bnetz, uint16_t telegramm)
switch (digit) {
case 's':
if (bnetz->dial_type != DIAL_TYPE_NOMETER) {
PDEBUG(DBNETZ, DEBUG_NOTICE, "Repeated start message ('Funkwahl') does not match first one (no metering support), releaseing.\n");
LOGP(DBNETZ, LOGL_NOTICE, "Repeated start message ('Funkwahl') does not match first one (no metering support), releaseing.\n");
bnetz_release(bnetz, TRENN_COUNT);
return;
}
break;
case 'S':
if (bnetz->dial_type != DIAL_TYPE_METER) {
PDEBUG(DBNETZ, DEBUG_NOTICE, "Repeated start message ('Funkwahl') does not match first one (metering support), releaseing.\n");
LOGP(DBNETZ, LOGL_NOTICE, "Repeated start message ('Funkwahl') does not match first one (metering support), releaseing.\n");
bnetz_release(bnetz, TRENN_COUNT);
return;
}
break;
case 'M':
if (bnetz->dial_type != DIAL_TYPE_METER_MUENZ) {
PDEBUG(DBNETZ, DEBUG_NOTICE, "Repeated start message ('Funkwahl') does not match first one (metering support, payphone), releaseing.\n");
LOGP(DBNETZ, LOGL_NOTICE, "Repeated start message ('Funkwahl') does not match first one (metering support, payphone), releaseing.\n");
bnetz_release(bnetz, TRENN_COUNT);
return;
}
break;
default:
PDEBUG(DBNETZ, DEBUG_NOTICE, "Repeated digit is not a start digit ('Funkwahl'), releaseing.\n");
LOGP(DBNETZ, LOGL_NOTICE, "Repeated digit is not a start digit ('Funkwahl'), releaseing.\n");
bnetz_release(bnetz, TRENN_COUNT);
return;
}
@ -546,12 +550,12 @@ void bnetz_receive_telegramm(bnetz_t *bnetz, uint16_t telegramm)
break;
case DIAL_MODE_STATIONID2:
if (digit < '0' || digit > '9') {
PDEBUG(DBNETZ, DEBUG_NOTICE, "Received message that is not a valid station id digit, releaseing.\n");
LOGP(DBNETZ, LOGL_NOTICE, "Received message that is not a valid station id digit, releaseing.\n");
bnetz_release(bnetz, TRENN_COUNT);
return;
}
if (bnetz->station_id[bnetz->dial_pos++] != digit) {
PDEBUG(DBNETZ, DEBUG_NOTICE, "Repeated station id does not match the first one, releaseing.\n");
LOGP(DBNETZ, LOGL_NOTICE, "Repeated station id does not match the first one, releaseing.\n");
bnetz_release(bnetz, TRENN_COUNT);
return;
}
@ -567,43 +571,40 @@ void bnetz_receive_telegramm(bnetz_t *bnetz, uint16_t telegramm)
strcpy(dialing + 1, bnetz->dial_number);
if (bnetz->dial_pos != (int)strlen(bnetz->dial_number)) {
PDEBUG(DBNETZ, DEBUG_NOTICE, "Received too few repeated number digits, releaseing.\n");
LOGP(DBNETZ, LOGL_NOTICE, "Received too few repeated number digits, releaseing.\n");
bnetz_release(bnetz, TRENN_COUNT);
return;
}
if (!strncmp(dialing, "0110", 4)) {
PDEBUG(DBNETZ, DEBUG_INFO, "Translating emergency number to '110'.\n");
LOGP(DBNETZ, LOGL_INFO, "Translating emergency number to '110'.\n");
strcpy(dialing, "110");
}
if (!strncmp(dialing, "0112", 4)) {
PDEBUG(DBNETZ, DEBUG_INFO, "Translating emergency number to '112'.\n");
LOGP(DBNETZ, LOGL_INFO, "Translating emergency number to '112'.\n");
strcpy(dialing, "112");
}
PDEBUG(DBNETZ, DEBUG_INFO, "Dialing complete %s->%s, call established.\n", bnetz->station_id, dialing);
timer_stop(&bnetz->timer);
LOGP(DBNETZ, LOGL_INFO, "Dialing complete %s->%s, call established.\n", bnetz->station_id, dialing);
osmo_timer_del(&bnetz->timer);
bnetz_set_dsp_mode(bnetz, DSP_MODE_AUDIO);
bnetz_new_state(bnetz, BNETZ_GESPRAECH);
/* start metering pulses if enabled and supported by phone or if forced */
if (bnetz->metering < 0 || (bnetz->metering > 0 && (bnetz->dial_type == DIAL_TYPE_METER || bnetz->dial_type == DIAL_TYPE_METER_MUENZ)))
timer_start(&bnetz->timer, METERING_START);
/* setup call */
PDEBUG(DBNETZ, DEBUG_INFO, "Setup call to network.\n");
LOGP(DBNETZ, LOGL_INFO, "Setup call to network.\n");
bnetz->callref = call_up_setup(bnetz->station_id, dialing, OSMO_CC_NETWORK_BNETZ_MUENZ, (bnetz->dial_type == DIAL_TYPE_METER_MUENZ) ? "MUENZ" : "");
break;
}
if (digit < '0' || digit > '9') {
PDEBUG(DBNETZ, DEBUG_NOTICE, "Received message that is not a valid number digit, releaseing.\n");
LOGP(DBNETZ, LOGL_NOTICE, "Received message that is not a valid number digit, releaseing.\n");
bnetz_release(bnetz, TRENN_COUNT);
return;
}
if (bnetz->dial_pos == (int)strlen(bnetz->dial_number)) {
PDEBUG(DBNETZ, DEBUG_NOTICE, "Received too many number digits, releaseing.\n");
LOGP(DBNETZ, LOGL_NOTICE, "Received too many number digits, releaseing.\n");
bnetz_release(bnetz, TRENN_COUNT);
return;
}
if (bnetz->dial_number[bnetz->dial_pos++] != digit) {
PDEBUG(DBNETZ, DEBUG_NOTICE, "Repeated number does not match the first one, releaseing.\n");
LOGP(DBNETZ, LOGL_NOTICE, "Repeated number does not match the first one, releaseing.\n");
bnetz_release(bnetz, TRENN_COUNT);
return;
}
@ -618,7 +619,7 @@ lets see, if noise will not generate a release signal....
return;
#endif
if (digit == 't') {
PDEBUG(DBNETZ, DEBUG_NOTICE, "Received 'Schlusssignal' from mobile station\n");
LOGP(DBNETZ, LOGL_NOTICE, "Received 'Schlusssignal' from mobile station\n");
bnetz_release(bnetz, TRENN_COUNT);
call_up_release(bnetz->callref, CAUSE_NORMAL);
bnetz->callref = 0;
@ -631,38 +632,39 @@ lets see, if noise will not generate a release signal....
}
/* Timeout handling */
static void bnetz_timeout(struct timer *timer)
static void bnetz_timeout(void *data)
{
bnetz_t *bnetz = (bnetz_t *)timer->priv;
bnetz_t *bnetz = data;
int to_sec, to_usec;
switch (bnetz->state) {
case BNETZ_WAHLABRUF:
PDEBUG_CHAN(DBNETZ, DEBUG_NOTICE, "Timeout while receiving call setup from mobile station, releasing.\n");
LOGP_CHAN(DBNETZ, LOGL_NOTICE, "Timeout while receiving call setup from mobile station, releasing.\n");
bnetz_release(bnetz, TRENN_COUNT);
break;
case BNETZ_SELEKTIVRUF_EIN:
PDEBUG_CHAN(DBNETZ, DEBUG_DEBUG, "Transmitter switched to channel 19, starting paging telegramms.\n");
LOGP_CHAN(DBNETZ, LOGL_DEBUG, "Transmitter switched to channel 19, starting paging telegramms.\n");
bnetz_set_dsp_mode(bnetz, DSP_MODE_TELEGRAMM);
break;
case BNETZ_SELEKTIVRUF_AUS:
PDEBUG_CHAN(DBNETZ, DEBUG_DEBUG, "Transmitter switched back to channel %s, waiting for paging response.\n", bnetz->sender.kanal);
LOGP_CHAN(DBNETZ, LOGL_DEBUG, "Transmitter switched back to channel %s, waiting for paging response.\n", bnetz->sender.kanal);
bnetz_new_state(bnetz, BNETZ_RUFBESTAETIGUNG);
switch_channel_19(bnetz, 0);
timer_start(&bnetz->timer, PAGING_TO);
osmo_timer_schedule(&bnetz->timer, PAGING_TO);
break;
case BNETZ_RUFBESTAETIGUNG:
if (bnetz->page_try == PAGE_TRIES) {
PDEBUG_CHAN(DBNETZ, DEBUG_NOTICE, "Timeout while waiting for call acknowledge from mobile station, releasing.\n");
LOGP_CHAN(DBNETZ, LOGL_NOTICE, "Timeout while waiting for call acknowledge from mobile station, releasing.\n");
bnetz_release(bnetz, TRENN_COUNT);
call_up_release(bnetz->callref, CAUSE_OUTOFORDER);
bnetz->callref = 0;
break;
}
PDEBUG_CHAN(DBNETZ, DEBUG_NOTICE, "Timeout while waiting for call acknowledge from mobile station, trying again.\n");
LOGP_CHAN(DBNETZ, LOGL_NOTICE, "Timeout while waiting for call acknowledge from mobile station, trying again.\n");
bnetz_page(bnetz, bnetz->station_id, bnetz->page_try + 1);
break;
case BNETZ_RUFHALTUNG:
PDEBUG_CHAN(DBNETZ, DEBUG_NOTICE, "Timeout while waiting for answer of mobile station, releasing.\n");
LOGP_CHAN(DBNETZ, LOGL_NOTICE, "Timeout while waiting for answer of mobile station, releasing.\n");
bnetz_release(bnetz, TRENN_COUNT);
call_up_release(bnetz->callref, CAUSE_NOANSWER);
bnetz->callref = 0;
@ -672,12 +674,21 @@ static void bnetz_timeout(struct timer *timer)
case DSP_MODE_AUDIO:
/* turn on merting pulse */
bnetz_set_dsp_mode(bnetz, DSP_MODE_AUDIO_METER);
timer_start(&bnetz->timer, METERING_DURATION);
osmo_timer_schedule(&bnetz->timer, 0, METERING_DURATION_US);
break;
case DSP_MODE_AUDIO_METER:
/* turn off and wait given seconds for next metering cycle */
bnetz_set_dsp_mode(bnetz, DSP_MODE_AUDIO);
timer_start(&bnetz->timer, (double)abs(bnetz->metering) - METERING_DURATION);
/* if metering has been disabled due to disconnect (must be at least 1s) */
if (!bnetz->metering_tv.tv_sec)
break;
to_sec = bnetz->metering_tv.tv_sec;
to_usec = bnetz->metering_tv.tv_usec - METERING_DURATION_US;
if (to_usec < 0) {
to_usec += 1000000;
to_sec--;
}
osmo_timer_schedule(&bnetz->timer, to_sec, to_usec);
break;
default:
break;
@ -701,7 +712,7 @@ int call_down_setup(int callref, const char __attribute__((unused)) *caller_id,
break;
}
if (sender) {
PDEBUG(DBNETZ, DEBUG_NOTICE, "Outgoing call to busy number, rejecting!\n");
LOGP(DBNETZ, LOGL_NOTICE, "Outgoing call to busy number, rejecting!\n");
return -CAUSE_BUSY;
}
@ -712,11 +723,11 @@ int call_down_setup(int callref, const char __attribute__((unused)) *caller_id,
break;
}
if (!sender) {
PDEBUG(DBNETZ, DEBUG_NOTICE, "Outgoing call, but no free channel, rejecting!\n");
LOGP(DBNETZ, LOGL_NOTICE, "Outgoing call, but no free channel, rejecting!\n");
return -CAUSE_NOCHANNEL;
}
PDEBUG_CHAN(DBNETZ, DEBUG_INFO, "Call to mobile station, paging station id '%s'\n", dialing);
LOGP_CHAN(DBNETZ, LOGL_INFO, "Call to mobile station, paging station id '%s'\n", dialing);
/* 3. trying to page mobile station */
bnetz->callref = callref;
@ -725,8 +736,35 @@ int call_down_setup(int callref, const char __attribute__((unused)) *caller_id,
return 0;
}
void call_down_answer(int __attribute__((unused)) callref)
void call_down_answer(int callref, struct timeval *tv_meter)
{
sender_t *sender;
bnetz_t *bnetz;
LOGP(DBNETZ, LOGL_INFO, "Call has been answered by network.\n");
for (sender = sender_head; sender; sender = sender->next) {
bnetz = (bnetz_t *) sender;
if (bnetz->callref == callref)
break;
}
if (!sender) {
LOGP(DBNETZ, LOGL_NOTICE, "Incoming answer, but no callref!\n");
return;
}
/* At least tone second! */
if (tv_meter->tv_sec) {
LOGP(DBNETZ, LOGL_INFO, "Network starts metering pulses every %lu.%03lu seconds.\n", tv_meter->tv_sec, tv_meter->tv_usec / 1000);
memcpy(&bnetz->metering_tv, tv_meter, sizeof(bnetz->metering_tv));
osmo_timer_schedule(&bnetz->timer, METERING_START);
} else if (bnetz->metering < 0 || (bnetz->metering > 0 && (bnetz->dial_type == DIAL_TYPE_METER || bnetz->dial_type == DIAL_TYPE_METER_MUENZ))) {
/* start metering pulses if enabled and supported by phone or if forced (mobile origninating call) */
LOGP(DBNETZ, LOGL_INFO, "Command line options starts metering pulses every %d seconds.\n", abs(bnetz->metering));
bnetz->metering_tv.tv_sec = abs(bnetz->metering);
bnetz->metering_tv.tv_usec = 0;
osmo_timer_schedule(&bnetz->timer, METERING_START);
}
}
/* Call control sends disconnect (with tones).
@ -738,7 +776,7 @@ void call_down_disconnect(int callref, int cause)
sender_t *sender;
bnetz_t *bnetz;
PDEBUG(DBNETZ, DEBUG_INFO, "Call has been disconnected by network.\n");
LOGP(DBNETZ, LOGL_INFO, "Call has been disconnected by network.\n");
for (sender = sender_head; sender; sender = sender->next) {
bnetz = (bnetz_t *) sender;
@ -746,23 +784,27 @@ void call_down_disconnect(int callref, int cause)
break;
}
if (!sender) {
PDEBUG(DBNETZ, DEBUG_NOTICE, "Outgoing disconnect, but no callref!\n");
LOGP(DBNETZ, LOGL_NOTICE, "Outgoing disconnect, but no callref!\n");
call_up_release(callref, CAUSE_INVALCALLREF);
return;
}
/* Release when not active */
if (bnetz->state == BNETZ_GESPRAECH)
if (bnetz->state == BNETZ_GESPRAECH) {
/* stop metering */
bnetz->metering_tv.tv_sec = 0;
bnetz->metering_tv.tv_usec = 0;
return;
}
switch (bnetz->state) {
case BNETZ_SELEKTIVRUF_EIN:
case BNETZ_SELEKTIVRUF_AUS:
case BNETZ_RUFBESTAETIGUNG:
PDEBUG_CHAN(DBNETZ, DEBUG_NOTICE, "Outgoing disconnect, during paging, releasing!\n");
LOGP_CHAN(DBNETZ, LOGL_NOTICE, "Outgoing disconnect, during paging, releasing!\n");
bnetz_release(bnetz, TRENN_COUNT);
break;
case BNETZ_RUFHALTUNG:
PDEBUG_CHAN(DBNETZ, DEBUG_NOTICE, "Outgoing disconnect, during alerting, releasing!\n");
LOGP_CHAN(DBNETZ, LOGL_NOTICE, "Outgoing disconnect, during alerting, releasing!\n");
bnetz_release(bnetz, TRENN_COUNT);
break;
default:
@ -780,7 +822,7 @@ void call_down_release(int callref, int __attribute__((unused)) cause)
sender_t *sender;
bnetz_t *bnetz;
PDEBUG(DBNETZ, DEBUG_INFO, "Call has been released by network, releasing call.\n");
LOGP(DBNETZ, LOGL_INFO, "Call has been released by network, releasing call.\n");
for (sender = sender_head; sender; sender = sender->next) {
bnetz = (bnetz_t *) sender;
@ -788,7 +830,7 @@ void call_down_release(int callref, int __attribute__((unused)) cause)
break;
}
if (!sender) {
PDEBUG(DBNETZ, DEBUG_NOTICE, "Outgoing release, but no callref!\n");
LOGP(DBNETZ, LOGL_NOTICE, "Outgoing release, but no callref!\n");
/* don't send release, because caller already released */
return;
}
@ -797,17 +839,17 @@ void call_down_release(int callref, int __attribute__((unused)) cause)
switch (bnetz->state) {
case BNETZ_GESPRAECH:
PDEBUG_CHAN(DBNETZ, DEBUG_NOTICE, "Outgoing release, during call, releasing!\n");
LOGP_CHAN(DBNETZ, LOGL_NOTICE, "Outgoing release, during call, releasing!\n");
bnetz_release(bnetz, TRENN_COUNT);
break;
case BNETZ_SELEKTIVRUF_EIN:
case BNETZ_SELEKTIVRUF_AUS:
case BNETZ_RUFBESTAETIGUNG:
PDEBUG_CHAN(DBNETZ, DEBUG_NOTICE, "Outgoing release, during paging, releasing!\n");
LOGP_CHAN(DBNETZ, LOGL_NOTICE, "Outgoing release, during paging, releasing!\n");
bnetz_release(bnetz, TRENN_COUNT);
break;
case BNETZ_RUFHALTUNG:
PDEBUG_CHAN(DBNETZ, DEBUG_NOTICE, "Outgoing release, during alerting, releasing!\n");
LOGP_CHAN(DBNETZ, LOGL_NOTICE, "Outgoing release, during alerting, releasing!\n");
bnetz_release(bnetz, TRENN_COUNT);
break;
default:
@ -815,29 +857,5 @@ void call_down_release(int callref, int __attribute__((unused)) cause)
}
}
/* Receive audio from call instance. */
void call_down_audio(int callref, sample_t *samples, int count)
{
sender_t *sender;
bnetz_t *bnetz;
for (sender = sender_head; sender; sender = sender->next) {
bnetz = (bnetz_t *) sender;
if (bnetz->callref == callref)
break;
}
if (!sender)
return;
if (bnetz->dsp_mode == DSP_MODE_AUDIO
|| bnetz->dsp_mode == DSP_MODE_AUDIO_METER) {
sample_t up[(int)((double)count * bnetz->sender.srstate.factor + 0.5) + 10];
count = samplerate_upsample(&bnetz->sender.srstate, samples, count, up);
jitter_save(&bnetz->sender.dejitter, up, count);
}
}
void call_down_clock(void) {}
void dump_info(void) {}

View File

@ -1,7 +1,7 @@
#include "../libsquelch/squelch.h"
#include "../libfsk/fsk.h"
#include "../libmobile/sender.h"
#include "../libtimer/timer.h"
#include <osmocom/core/timer.h>
/* fsk modes of transmission */
enum dsp_mode {
@ -56,6 +56,7 @@ typedef struct bnetz {
/* system info */
int gfs; /* 'Gruppenfreisignal' */
int metering; /* use metering pulses in seconds 0 = off, < 0 = force */
struct timeval metering_tv; /* time to repeat metering pulse (current call) */
/* switch sender to channel 19 */
char paging_file[256]; /* if set, write to given file to switch to channel 19 or back */
@ -74,7 +75,7 @@ typedef struct bnetz {
int station_id_pos; /* position while transmitting */
enum page_mode page_mode; /* sub state while paging */
int page_try; /* try number (1 or 2) */
struct timer timer;
struct osmo_timer_list timer;
int trenn_count; /* count number of release messages */
/* display measurements */

View File

@ -26,7 +26,7 @@
#include "../libsample/sample.h"
#include "../libfsk/fsk.h"
#include "../libwave/wave.h"
#include "../libdebug/debug.h"
#include "../liblogging/logging.h"
#ifdef HAVE_ALSA
#include "../libsound/sound.h"
#endif
@ -68,8 +68,11 @@ wave_rec_t wave_tx_rec;
/* dummy functions */
int num_kanal = 1; /* only one channel used for debugging */
void *get_sender_by_empfangsfrequenz(void);
void *get_sender_by_empfangsfrequenz() { return NULL; }
void display_measurements_add(void);
void display_measurements_add() {}
void display_measurements_update(void);
void display_measurements_update() {}
#define OPT_METERING 1000
@ -161,13 +164,13 @@ static int fsk_send_bit(void __attribute__((unused)) *inst)
if (!tx_telegramm || tx_telegramm_pos == 16) {
switch (funkwahl[digit_pos]) {
case '\0':
PDEBUG(DBNETZ, DEBUG_INFO, "Done sending dialing sequence\n");
LOGP(DBNETZ, LOGL_INFO, "Done sending dialing sequence\n");
tx_mode = TX_MODE_SILENCE;
tx_silence_count = 0;
return -1;
case 'w':
if (!tx_telegramm)
PDEBUG(DBNETZ, DEBUG_INFO, "Sending channel allocation tone ('Kanalbelegung')\n");
LOGP(DBNETZ, LOGL_INFO, "Sending channel allocation tone ('Kanalbelegung')\n");
tx_telegramm = "0000000000000000";
tx_telegramm_pos = 0;
digit_pos++;
@ -175,23 +178,23 @@ static int fsk_send_bit(void __attribute__((unused)) *inst)
default:
switch (funkwahl[digit_pos]) {
case 's':
PDEBUG(DBNETZ, DEBUG_INFO, "Sending start digit (no charging meater on board)\n");
LOGP(DBNETZ, LOGL_INFO, "Sending start digit (no charging meater on board)\n");
break;
case 'S':
PDEBUG(DBNETZ, DEBUG_INFO, "Sending start digit (with charging meater on board)\n");
LOGP(DBNETZ, LOGL_INFO, "Sending start digit (with charging meater on board)\n");
break;
case 'M':
PDEBUG(DBNETZ, DEBUG_INFO, "Sending start digit (Phone is a coin box.)\n");
LOGP(DBNETZ, LOGL_INFO, "Sending start digit (Phone is a coin box.)\n");
break;
case 'e':
PDEBUG(DBNETZ, DEBUG_INFO, "Sending stop digit\n");
LOGP(DBNETZ, LOGL_INFO, "Sending stop digit\n");
break;
default:
PDEBUG(DBNETZ, DEBUG_INFO, "Sending digit '%c'\n", funkwahl[digit_pos]);
LOGP(DBNETZ, LOGL_INFO, "Sending digit '%c'\n", funkwahl[digit_pos]);
}
impulstelegramm = bnetz_digit2telegramm(funkwahl[digit_pos]);
if (!impulstelegramm) {
PDEBUG(DBNETZ, DEBUG_ERROR, "Illegal digit '%c', please fix!\n", funkwahl[digit_pos]);
LOGP(DBNETZ, LOGL_ERROR, "Illegal digit '%c', please fix!\n", funkwahl[digit_pos]);
abort();
}
tx_telegramm = impulstelegramm->sequence;
@ -252,7 +255,7 @@ static void process_signal(int buffer_size)
count = dsp_samplerate / 1000;
#endif
if (count < 0) {
PDEBUG(DDSP, DEBUG_ERROR, "Failed to get number of samples in buffer (rc = %d)!\n", count);
LOGP(DDSP, LOGL_ERROR, "Failed to get number of samples in buffer (rc = %d)!\n", count);
break;
}
@ -267,7 +270,7 @@ static void process_signal(int buffer_size)
/* write audio */
rc = sound_write(audio, samples, power, count, NULL, NULL, 1);
if (rc < 0) {
PDEBUG(DDSP, DEBUG_ERROR, "Failed to write TX data to audio device (rc = %d)\n", rc);
LOGP(DDSP, LOGL_ERROR, "Failed to write TX data to audio device (rc = %d)\n", rc);
break;
}
#endif
@ -340,15 +343,15 @@ int main(int argc, char *argv[])
/* init fsk */
if (fsk_mod_init(&fsk_mod, NULL, fsk_send_bit, dsp_samplerate, BIT_RATE, F0, F1, 1.0, 0, 0) < 0) {
PDEBUG(DDSP, DEBUG_ERROR, "FSK init failed!\n");
LOGP(DDSP, LOGL_ERROR, "FSK init failed!\n");
goto exit;
}
#ifdef HAVE_ALSA
/* init sound */
audio = sound_open(dsp_audiodev, NULL, NULL, NULL, 1, 0.0, dsp_samplerate, buffer_size, 1.0, 1.0, 4000.0, 2.0);
audio = sound_open(SOUND_DIR_PLAY, dsp_audiodev, NULL, NULL, NULL, 1, 0.0, dsp_samplerate, buffer_size, 1.0, 1.0, 4000.0, 2.0);
if (!audio) {
PDEBUG(DBNETZ, DEBUG_ERROR, "No sound device!\n");
LOGP(DBNETZ, LOGL_ERROR, "No sound device!\n");
goto exit;
}
#endif
@ -357,13 +360,13 @@ int main(int argc, char *argv[])
if (write_tx_wave) {
rc = wave_create_record(&wave_tx_rec, write_tx_wave, dsp_samplerate, 1, 1.0);
if (rc < 0) {
PDEBUG(DBNETZ, DEBUG_ERROR, "Failed to create WAVE recoding instance!\n");
LOGP(DBNETZ, LOGL_ERROR, "Failed to create WAVE recoding instance!\n");
goto exit;
}
}
#ifndef HAVE_ALSA
else {
PDEBUG(DBNETZ, DEBUG_ERROR, "No sound support compiled in, so you need to write to a wave file. See help!\n");
LOGP(DBNETZ, LOGL_ERROR, "No sound support compiled in, so you need to write to a wave file. See help!\n");
goto exit;
}
#endif
@ -373,7 +376,7 @@ int main(int argc, char *argv[])
sound_start(audio);
#endif
PDEBUG(DBNETZ, DEBUG_ERROR, "Start audio after pause...\n");
LOGP(DBNETZ, LOGL_ERROR, "Start audio after pause...\n");
process_signal(buffer_size);

View File

@ -26,7 +26,7 @@
#include <errno.h>
#include <math.h>
#include "../libsample/sample.h"
#include "../libdebug/debug.h"
#include "../liblogging/logging.h"
#include "../libmobile/call.h"
#include "bnetz.h"
#include "dsp.h"
@ -70,7 +70,7 @@ void dsp_init(void)
{
int i;
PDEBUG(DDSP, DEBUG_DEBUG, "Generating sine table for metering tone.\n");
LOGP(DDSP, LOGL_DEBUG, "Generating sine table for metering tone.\n");
for (i = 0; i < 65536; i++)
dsp_metering[i] = sin((double)i / 65536.0 * 2.0 * PI) * TX_PEAK_METER;
}
@ -81,10 +81,10 @@ static void fsk_receive_bit(void *inst, int bit, double quality, double level);
/* Init transceiver instance. */
int dsp_init_sender(bnetz_t *bnetz, double squelch_db)
{
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Init DSP for 'Sender'.\n");
LOGP_CHAN(DDSP, LOGL_DEBUG, "Init DSP for 'Sender'.\n");
if (TONE_DETECT_CNT > sizeof(bnetz->rx_tone_quality) / sizeof(bnetz->rx_tone_quality[0])) {
PDEBUG_CHAN(DDSP, DEBUG_ERROR, "buffer for tone quality is too small, please fix!\n");
LOGP_CHAN(DDSP, LOGL_ERROR, "buffer for tone quality is too small, please fix!\n");
return -EINVAL;
}
@ -94,15 +94,15 @@ int dsp_init_sender(bnetz_t *bnetz, double squelch_db)
/* set modulation parameters */
sender_set_fm(&bnetz->sender, MAX_DEVIATION, MAX_MODULATION, SPEECH_DEVIATION, MAX_DISPLAY);
PDEBUG(DDSP, DEBUG_DEBUG, "Using FSK level of %.3f (%.3f KHz deviation @ 2000 Hz)\n", TX_PEAK_FSK, 4.0);
LOGP(DDSP, LOGL_DEBUG, "Using FSK level of %.3f (%.3f KHz deviation @ 2000 Hz)\n", TX_PEAK_FSK, 4.0);
/* init fsk */
if (fsk_mod_init(&bnetz->fsk_mod, bnetz, fsk_send_bit, bnetz->sender.samplerate, BIT_RATE, F0, F1, TX_PEAK_FSK, 0, 0) < 0) {
PDEBUG_CHAN(DDSP, DEBUG_ERROR, "FSK init failed!\n");
LOGP_CHAN(DDSP, LOGL_ERROR, "FSK init failed!\n");
return -EINVAL;
}
if (fsk_demod_init(&bnetz->fsk_demod, bnetz, fsk_receive_bit, bnetz->sender.samplerate, BIT_RATE, F0, F1, BIT_ADJUST) < 0) {
PDEBUG_CHAN(DDSP, DEBUG_ERROR, "FSK init failed!\n");
LOGP_CHAN(DDSP, LOGL_ERROR, "FSK init failed!\n");
return -EINVAL;
}
@ -124,7 +124,7 @@ int dsp_init_sender(bnetz_t *bnetz, double squelch_db)
/* Cleanup transceiver instance. */
void dsp_cleanup_sender(bnetz_t *bnetz)
{
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Cleanup DSP for 'Sender'.\n");
LOGP_CHAN(DDSP, LOGL_DEBUG, "Cleanup DSP for 'Sender'.\n");
fsk_mod_cleanup(&bnetz->fsk_mod);
fsk_demod_cleanup(&bnetz->fsk_demod);
@ -148,7 +148,7 @@ static void fsk_receive_tone(bnetz_t *bnetz, int tone, int goodtone, double leve
/* set duration to TONE_DETECT_CNT, because it took that long to detect the tone */
bnetz->tone_duration = TONE_DETECT_CNT;
bnetz->tone_detected = tone;
PDEBUG_CHAN(DDSP, DEBUG_INFO, "Detecting continuous tone: F%d Level=%3.0f%% (threshold %3.0f%%) standard deviation=%.0f%% (threshold=%.0f%%) Quality=%3.0f%%\n", bnetz->tone_detected, level_avg * 100.0, TONE_LEVEL_TH * 100.0, level_stddev / level_avg * 100.0, TONE_STDDEV_TH * 100.0, quality_avg * 100.0);
LOGP_CHAN(DDSP, LOGL_INFO, "Detecting continuous tone: F%d Level=%3.0f%% (threshold %3.0f%%) standard deviation=%.0f%% (threshold=%.0f%%) Quality=%3.0f%%\n", bnetz->tone_detected, level_avg * 100.0, TONE_LEVEL_TH * 100.0, level_stddev / level_avg * 100.0, TONE_STDDEV_TH * 100.0, quality_avg * 100.0);
bnetz_receive_tone(bnetz, bnetz->tone_detected);
}
}
@ -158,7 +158,7 @@ static void fsk_receive_tone(bnetz_t *bnetz, int tone, int goodtone, double leve
bnetz->tone_count++;
if (bnetz->tone_count == TONE_LOST_CNT) {
/* subtract TONE_LOST_CNT from duration, because it took that long to detect loss of tone */
PDEBUG_CHAN(DDSP, DEBUG_INFO, "Lost F%d tone after %.2f seconds.\n", bnetz->tone_detected, (double)(bnetz->tone_duration - TONE_LOST_CNT) / 100.0);
LOGP_CHAN(DDSP, LOGL_INFO, "Lost F%d tone after %.2f seconds.\n", bnetz->tone_detected, (double)(bnetz->tone_duration - TONE_LOST_CNT) / 100.0);
bnetz->tone_detected = -1;
bnetz_receive_tone(bnetz, -1);
}
@ -250,7 +250,7 @@ static void fsk_receive_bit(void *inst, int bit, double quality, double level)
j++;
}
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "FSK Valid bits: %d/%d Level: %.0f%% (threshold %.0f%%) Stddev: %.0f%% (threshold %.0f%%)\n", j, 16, level_avg * 100.0, TONE_LEVEL_TH * 100.0, level_stddev / level_avg * 100.0, TONE_STDDEV_TH * 100.0);
LOGP_CHAN(DDSP, LOGL_DEBUG, "FSK Valid bits: %d/%d Level: %.0f%% (threshold %.0f%%) Stddev: %.0f%% (threshold %.0f%%)\n", j, 16, level_avg * 100.0, TONE_LEVEL_TH * 100.0, level_stddev / level_avg * 100.0, TONE_STDDEV_TH * 100.0);
/* drop any telegramm that is too bad */
if (level_stddev / level_avg > TONE_STDDEV_TH || j < 16)
@ -261,7 +261,7 @@ static void fsk_receive_bit(void *inst, int bit, double quality, double level)
display_measurements_update(bnetz->dmp_frame_stddev, level_stddev / level_avg * 100.0, 0.0);
display_measurements_update(bnetz->dmp_frame_quality, quality_avg * 100.0, 0.0);
PDEBUG_CHAN(DDSP, DEBUG_INFO, "Telegramm RX Level: average=%.0f%% (threshold %.0f%%) standard deviation=%.0f%% (threshold %.0f%%) Quality: %.0f%%\n", level_avg * 100.0, TONE_LEVEL_TH * 100.0, level_stddev / level_avg * 100.0, TONE_STDDEV_TH * 100.0, quality_avg * 100.0);
LOGP_CHAN(DDSP, LOGL_INFO, "Telegramm RX Level: average=%.0f%% (threshold %.0f%%) standard deviation=%.0f%% (threshold %.0f%%) Quality: %.0f%%\n", level_avg * 100.0, TONE_LEVEL_TH * 100.0, level_stddev / level_avg * 100.0, TONE_STDDEV_TH * 100.0, quality_avg * 100.0);
/* receive telegramm */
bnetz_receive_telegramm(bnetz, bnetz->rx_telegramm);
@ -320,7 +320,7 @@ static int fsk_send_bit(void *inst)
/* request frame */
bnetz->tx_telegramm = bnetz_get_telegramm(bnetz);
if (!bnetz->tx_telegramm) {
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Stop sending 'Telegramm'.\n");
LOGP_CHAN(DDSP, LOGL_DEBUG, "Stop sending 'Telegramm'.\n");
return -1;
}
bnetz->tx_telegramm_pos = 0;
@ -361,7 +361,7 @@ static void metering_tone(bnetz_t *bnetz, sample_t *samples, int length)
void sender_send(sender_t *sender, sample_t *samples, uint8_t *power, int length)
{
bnetz_t *bnetz = (bnetz_t *) sender;
int count;
int count, input_num;
memset(power, 1, length);
@ -372,7 +372,13 @@ again:
break;
case DSP_MODE_AUDIO:
case DSP_MODE_AUDIO_METER:
jitter_load(&bnetz->sender.dejitter, samples, length);
input_num = samplerate_upsample_input_num(&sender->srstate, length);
{
int16_t spl[input_num];
jitter_load_samples(&sender->dejitter, (uint8_t *)spl, input_num, sizeof(*spl), jitter_conceal_s16, NULL);
int16_to_samples_speech(samples, spl, input_num);
}
samplerate_upsample(&sender->srstate, samples, input_num, samples, length);
if (bnetz->dsp_mode == DSP_MODE_AUDIO_METER)
metering_tone(bnetz, samples, length);
break;
@ -390,7 +396,7 @@ again:
}
}
const char *bnetz_dsp_mode_name(enum dsp_mode mode)
static const char *bnetz_dsp_mode_name(enum dsp_mode mode)
{
static char invalid[16];
@ -418,10 +424,37 @@ void bnetz_set_dsp_mode(bnetz_t *bnetz, enum dsp_mode mode)
/* reset telegramm */
if (mode == DSP_MODE_TELEGRAMM && bnetz->dsp_mode != mode) {
bnetz->tx_telegramm = 0;
fsk_mod_tx_reset(&bnetz->fsk_mod);
fsk_mod_reset(&bnetz->fsk_mod);
}
if ((mode == DSP_MODE_AUDIO || mode == DSP_MODE_AUDIO_METER) && (bnetz->dsp_mode != DSP_MODE_AUDIO && bnetz->dsp_mode != DSP_MODE_AUDIO_METER))
jitter_reset(&bnetz->sender.dejitter);
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "DSP mode %s -> %s\n", bnetz_dsp_mode_name(bnetz->dsp_mode), bnetz_dsp_mode_name(mode));
LOGP_CHAN(DDSP, LOGL_DEBUG, "DSP mode %s -> %s\n", bnetz_dsp_mode_name(bnetz->dsp_mode), bnetz_dsp_mode_name(mode));
bnetz->dsp_mode = mode;
}
/* Receive audio from call instance. */
void call_down_audio(void *decoder, void *decoder_priv, int callref, uint16_t sequence, uint8_t marker, uint32_t timestamp, uint32_t ssrc, uint8_t *payload, int payload_len)
{
sender_t *sender;
bnetz_t *bnetz;
for (sender = sender_head; sender; sender = sender->next) {
bnetz = (bnetz_t *) sender;
if (bnetz->callref == callref)
break;
}
if (!sender)
return;
if (bnetz->dsp_mode == DSP_MODE_AUDIO
|| bnetz->dsp_mode == DSP_MODE_AUDIO_METER) {
jitter_frame_t *jf;
jf = jitter_frame_alloc(decoder, decoder_priv, payload, payload_len, marker, sequence, timestamp, ssrc);
if (jf)
jitter_save(&bnetz->sender.dejitter, jf);
}
}
void call_down_clock(void) {}

View File

@ -24,7 +24,7 @@
#include <errno.h>
#include <math.h>
#include "../libsample/sample.h"
#include "../libdebug/debug.h"
#include "../liblogging/logging.h"
#include "../libmobile/call.h"
#include "../libmobile/main_mobile.h"
#include "../anetz/freiton.h"
@ -58,6 +58,8 @@ void print_help(const char *arg0)
printf(" Pulses will be sent on outgoing calls only and only if mobile station\n");
printf(" requests it. Use negative value to force metering pulses for all calls.\n");
printf(" (default = %d)\n", metering);
printf(" If metering pulses are sent via Osmo-CC interface, pulses are always\n");
printf(" sent, if mobile station requests it. This overrides this option.\n");
printf(" -P --paging tone | notone | positive | negative | <file>=<on>:<off>\n");
printf(" Send a tone, give a signal or write to a file when switching to\n");
printf(" channel 19. (paging the phone).\n");
@ -218,6 +220,7 @@ fail:
bnetz_destroy(sender_head);
/* exits */
main_mobile_exit();
fm_exit();
options_free();

View File

@ -2,6 +2,7 @@
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "stations.h"
static struct bnetz_stations {
const char *standort;
@ -221,7 +222,7 @@ static struct bnetz_stations {
{ NULL, 0, NULL }
};
double lat_from_coordinates(const char *string)
static double lat_from_coordinates(const char *string)
{
if (strlen(string) != 11)
abort();
@ -242,7 +243,7 @@ double lat_from_coordinates(const char *string)
(double)(string[4] - '0') / 60.0;
}
double lon_from_coordinates(const char *string)
static double lon_from_coordinates(const char *string)
{
if (strlen(string) != 11)
abort();

View File

@ -1,4 +1,4 @@
AM_CPPFLAGS = -Wall -Wextra -g $(all_includes)
AM_CPPFLAGS = -Wall -Wextra -Wmissing-prototypes -g $(all_includes)
bin_PROGRAMS = \
cnetz
@ -24,13 +24,10 @@ cnetz_LDADD = \
../anetz/libgermanton.a \
libcnetztones.a \
$(top_builddir)/src/liboptions/liboptions.a \
$(top_builddir)/src/libdebug/libdebug.a \
$(top_builddir)/src/libmobile/libmobile.a \
$(top_builddir)/src/libosmocc/libosmocc.a \
$(top_builddir)/src/libdisplay/libdisplay.a \
$(top_builddir)/src/libcompandor/libcompandor.a \
$(top_builddir)/src/libjitter/libjitter.a \
$(top_builddir)/src/libtimer/libtimer.a \
$(top_builddir)/src/libsamplerate/libsamplerate.a \
$(top_builddir)/src/libscrambler/libscrambler.a \
$(top_builddir)/src/libemphasis/libemphasis.a \
@ -38,8 +35,10 @@ cnetz_LDADD = \
$(top_builddir)/src/libfilter/libfilter.a \
$(top_builddir)/src/libwave/libwave.a \
$(top_builddir)/src/libsample/libsample.a \
$(top_builddir)/src/libg711/libg711.a \
$(top_builddir)/src/libaaimage/libaaimage.a \
$(top_builddir)/src/liblogging/liblogging.a \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOCC_LIBS) \
-lm
if HAVE_ALSA

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,12 @@
#include "../libcompandor/compandor.h"
#include "../libtimer/timer.h"
#include <osmocom/core/timer.h>
#include "../libmobile/sender.h"
#include "../libscrambler/scrambler.h"
typedef struct cnetz cnetz_t;
#include "fsk_demod.h"
#include "transaction.h"
#define CNETZ_OGK_KANAL 131
#define CNETZ_STD_OGK_KANAL 131
/* dsp modes of transmission */
enum dsp_mode {
@ -40,9 +40,9 @@ enum cnetz_state {
#define N_AFKT 6 /* number of release frames to send during concentrated signaling */
#define N_AFV 4 /* number of release frames to send during distributed signaling */
#define N 3 /* now many times we repeat a message on OgK */
#define T_VAG2 180 /* time on outgoing queue */
#define T_VAK 60 /* time on incoming queue */
#define T_AP 750 /* Time to wait for SIM card's authentication reply */
#define T_VAG2 180,0 /* time on outgoing queue */
#define T_VAK 60,0 /* time on incoming queue */
#define T_AP 0,750000 /* Time to wait for SIM card's authentication reply */
/* clear causes */
#define CNETZ_CAUSE_GASSENBESETZT 0 /* network congested */
@ -66,6 +66,7 @@ struct clock_speed {
/* instance of cnetz sender */
struct cnetz {
sender_t sender;
int kanal; /* channel number */
enum cnetz_chan_type chan_type; /* channel type */
scrambler_t scrambler_tx; /* mirror what we transmit to MS */
scrambler_t scrambler_rx; /* mirror what we receive from MS */
@ -81,7 +82,7 @@ struct cnetz {
int response_valid; /* expect authorizaton response */
uint64_t response; /* authorization response */
int warteschlange; /* use queue */
int metering; /* use metering pulses in seconds 0 = off */
int metering; /* send metering units in seconds 0 = off */
/* all cnetz states */
enum cnetz_state state; /* main state of sender */
@ -96,9 +97,12 @@ struct cnetz {
int sched_r_m; /* Rufblock (0) / Meldeblock (1) */
enum dsp_mode sched_dsp_mode; /* what mode shall be switched to */
int sched_dsp_mode_ts; /* time slot when to switch mode (-1 = don't switch) */
int sched_lr_debugged; /* indicator to prevent debugging all idle frames */
int sched_mlr_debugged; /* indicator to prevent debugging all idle frames */
/* dsp states */
enum dsp_mode dsp_mode; /* current mode: audio, "Telegramm", .... */
double rf_level_db; /* current RF level or nan, if not applicable */
iir_filter_t lp; /* low pass filter to eliminate noise above 5280 Hz */
fsk_fm_demod_t fsk_demod; /* demod process */
double fsk_deviation; /* deviation of FSK signal on sound card */
@ -123,8 +127,8 @@ struct cnetz {
double frame_last_phase; /* master's bit phase of last frame sync */
/* audio offset removal */
double offset_factor; /* filer alpha of high-pass filter */
double offset_y_last; /* last stored sample */
double offset_last; /* last sample value of last frame */
int offset_range; /* range of samples to ramp the offset */
/* measurements */
int measure_speed; /* measure clock speed */
@ -144,7 +148,7 @@ int cnetz_create(const char *kanal, enum cnetz_chan_type chan_type, const char *
void cnetz_destroy(sender_t *sender);
void cnetz_go_idle(cnetz_t *cnetz);
void cnetz_sync_frame(cnetz_t *cnetz, double sync, int ts);
int cnetz_meldeaufruf(uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest);
int cnetz_meldeaufruf(uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int ogk_kanal);
const struct telegramm *cnetz_transmit_telegramm_rufblock(cnetz_t *cnetz);
const struct telegramm *cnetz_transmit_telegramm_meldeblock(cnetz_t *cnetz);
void cnetz_receive_telegramm_ogk(cnetz_t *cnetz, struct telegramm *telegramm, int block);

View File

@ -22,21 +22,22 @@
#include <stdlib.h>
#include <string.h>
#include "../libsample/sample.h"
#include "../libdebug/debug.h"
#include "../liblogging/logging.h"
#include "../libmobile/get_time.h"
#include "cnetz.h"
#include "database.h"
#include "sysinfo.h"
/* the network specs say: check every 1 - 6.5 minutes for availability
* remove from database after 3 subsequent failures
* the phone will register 20 minutes after no call / no paging from network.
*/
#define MELDE_INTERVAL 120.0
#define MELDE_WIEDERHOLUNG 60.0
#define MELDE_MAXIMAL 3
#define MELDE_WIEDERHOLUNG 60.0 /* when busy */
typedef struct cnetz_database {
struct cnetz_database *next;
int ogk_kanal; /* available on which channel */
uint8_t futln_nat; /* who ... */
uint8_t futln_fuvst;
uint16_t futln_rest;
@ -45,12 +46,23 @@ typedef struct cnetz_database {
int eingebucht; /* set if still available */
double last_seen;
int busy; /* set if currently in a call */
struct timer timer; /* timer for next availability check */
struct osmo_timer_list timer; /* timer for next availability check */
int retry; /* counts number of retries */
} cnetz_db_t;
cnetz_db_t *cnetz_db_head;
static const char *print_meldeaufrufe(int versuche)
{
static char text[32];
if (versuche <= 0)
return "infinite";
sprintf(text, "%d", versuche);
return text;
}
/* destroy transaction */
static void remove_db(cnetz_db_t *db)
{
@ -61,39 +73,39 @@ static void remove_db(cnetz_db_t *db)
while (*dbp && *dbp != db)
dbp = &((*dbp)->next);
if (!(*dbp)) {
PDEBUG(DDB, DEBUG_ERROR, "Subscriber not in list, please fix!!\n");
LOGP(DDB, LOGL_ERROR, "Subscriber not in list, please fix!!\n");
abort();
}
*dbp = db->next;
PDEBUG(DDB, DEBUG_INFO, "Removing subscriber '%d,%d,%05d' from database.\n", db->futln_nat, db->futln_fuvst, db->futln_rest);
LOGP(DDB, LOGL_INFO, "Removing subscriber '%d,%d,%05d' from database.\n", db->futln_nat, db->futln_fuvst, db->futln_rest);
timer_exit(&db->timer);
osmo_timer_del(&db->timer);
free(db);
}
/* Timeout handling */
static void db_timeout(struct timer *timer)
static void db_timeout(void *data)
{
cnetz_db_t *db = (cnetz_db_t *)timer->priv;
cnetz_db_t *db = data;
int rc;
PDEBUG(DDB, DEBUG_INFO, "Check, if subscriber '%d,%d,%05d' is still available.\n", db->futln_nat, db->futln_fuvst, db->futln_rest);
LOGP(DDB, LOGL_INFO, "Check, if subscriber '%d,%d,%05d' is still available.\n", db->futln_nat, db->futln_fuvst, db->futln_rest);
rc = cnetz_meldeaufruf(db->futln_nat, db->futln_fuvst, db->futln_rest);
rc = cnetz_meldeaufruf(db->futln_nat, db->futln_fuvst, db->futln_rest, db->ogk_kanal);
if (rc < 0) {
/* OgK is used for speech, but this never happens in a real
* network. We just assume that the phone has responded and
* assume we had a response. */
PDEBUG(DDB, DEBUG_INFO, "OgK busy, so we assume a positive response.\n");
timer_start(&db->timer, MELDE_INTERVAL); /* when to check avaiability again */
LOGP(DDB, LOGL_INFO, "OgK busy, so we assume a positive response.\n");
osmo_timer_schedule(&db->timer, si.meldeinterval,0); /* when to check avaiability again */
db->retry = 0;
}
}
/* create/update db entry */
int update_db(cnetz_t __attribute__((unused)) *cnetz, uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int *futelg_bit, int *extended, int busy, int failed)
int update_db(uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int ogk_kanal, int *futelg_bit, int *extended, int busy, int failed)
{
cnetz_db_t *db, **dbp;
@ -109,10 +121,10 @@ int update_db(cnetz_t __attribute__((unused)) *cnetz, uint8_t futln_nat, uint8_t
if (!db) {
db = calloc(1, sizeof(*db));
if (!db) {
PDEBUG(DDB, DEBUG_ERROR, "No memory!\n");
LOGP(DDB, LOGL_ERROR, "No memory!\n");
return 0;
}
timer_init(&db->timer, db_timeout, db);
osmo_timer_setup(&db->timer, db_timeout, db);
db->eingebucht = 1;
db->futln_nat = futln_nat;
@ -125,9 +137,12 @@ int update_db(cnetz_t __attribute__((unused)) *cnetz, uint8_t futln_nat, uint8_t
dbp = &((*dbp)->next);
*dbp = db;
PDEBUG(DDB, DEBUG_INFO, "Adding subscriber '%d,%d,%05d' to database.\n", db->futln_nat, db->futln_fuvst, db->futln_rest);
LOGP(DDB, LOGL_INFO, "Adding subscriber '%d,%d,%05d' to database.\n", db->futln_nat, db->futln_fuvst, db->futln_rest);
}
if (ogk_kanal)
db->ogk_kanal = ogk_kanal;
if (futelg_bit && *futelg_bit >= 0)
db->futelg_bit = *futelg_bit;
@ -136,23 +151,23 @@ int update_db(cnetz_t __attribute__((unused)) *cnetz, uint8_t futln_nat, uint8_t
db->busy = busy;
if (busy) {
PDEBUG(DDB, DEBUG_INFO, "Subscriber '%d,%d,%05d' busy now.\n", db->futln_nat, db->futln_fuvst, db->futln_rest);
timer_stop(&db->timer);
LOGP(DDB, LOGL_INFO, "Subscriber '%d,%d,%05d' on OGK channel #%d is busy now.\n", db->futln_nat, db->futln_fuvst, db->futln_rest, db->ogk_kanal);
osmo_timer_del(&db->timer);
} else if (!failed) {
PDEBUG(DDB, DEBUG_INFO, "Subscriber '%d,%d,%05d' idle now.\n", db->futln_nat, db->futln_fuvst, db->futln_rest);
timer_start(&db->timer, MELDE_INTERVAL); /* when to check avaiability (again) */
LOGP(DDB, LOGL_INFO, "Subscriber '%d,%d,%05d' on OGK channel #%d is idle now.\n", db->futln_nat, db->futln_fuvst, db->futln_rest, db->ogk_kanal);
osmo_timer_schedule(&db->timer, si.meldeinterval,0); /* when to check avaiability (again) */
db->retry = 0;
db->eingebucht = 1;
db->last_seen = get_time();
} else {
db->retry++;
PDEBUG(DDB, DEBUG_NOTICE, "Paging subscriber '%d,%d,%05d' failed (try %d of %d).\n", db->futln_nat, db->futln_fuvst, db->futln_rest, db->retry, MELDE_MAXIMAL);
if (db->retry == MELDE_MAXIMAL) {
PDEBUG(DDB, DEBUG_INFO, "Marking subscriber as gone.\n");
LOGP(DDB, LOGL_NOTICE, "Paging subscriber '%d,%d,%05d' on OGK channel #%d failed (try %d of %s).\n", db->futln_nat, db->futln_fuvst, db->futln_rest, db->ogk_kanal, db->retry, print_meldeaufrufe(si.meldeaufrufe));
if (si.meldeaufrufe && db->retry == si.meldeaufrufe) {
LOGP(DDB, LOGL_INFO, "Marking subscriber as gone.\n");
db->eingebucht = 0;
return db->extended;
}
timer_start(&db->timer, MELDE_WIEDERHOLUNG); /* when to do retry */
osmo_timer_schedule(&db->timer, (si.meldeinterval < MELDE_WIEDERHOLUNG) ? si.meldeinterval : MELDE_WIEDERHOLUNG,0); /* when to do retry */
}
if (futelg_bit)
@ -162,7 +177,7 @@ int update_db(cnetz_t __attribute__((unused)) *cnetz, uint8_t futln_nat, uint8_t
return 0;
}
int find_db(uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int *futelg_bit, int *extended)
int find_db(uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int *ogk_kanal, int *futelg_bit, int *extended)
{
cnetz_db_t *db = cnetz_db_head;
@ -171,6 +186,8 @@ int find_db(uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int *fu
&& db->futln_nat == futln_nat
&& db->futln_fuvst == futln_fuvst
&& db->futln_rest == futln_rest) {
if (ogk_kanal)
*ogk_kanal = db->ogk_kanal;
if (futelg_bit)
*futelg_bit = db->futelg_bit;
if (extended)
@ -193,18 +210,20 @@ void dump_db(void)
cnetz_db_t *db = cnetz_db_head;
double now = get_time();
int last;
char attached[16];
PDEBUG(DDB, DEBUG_NOTICE, "Dump of subscriber database:\n");
LOGP(DDB, LOGL_NOTICE, "Dump of subscriber database:\n");
if (!db) {
PDEBUG(DDB, DEBUG_NOTICE, " - No subscribers attached!\n");
LOGP(DDB, LOGL_NOTICE, " - No subscribers attached!\n");
return;
}
PDEBUG(DDB, DEBUG_NOTICE, "Subscriber\tAttached\tBusy\t\tLast seen\tMeldeaufrufe\n");
PDEBUG(DDB, DEBUG_NOTICE, "-------------------------------------------------------------------------------\n");
LOGP(DDB, LOGL_NOTICE, "Subscriber\tAttached\tBusy\t\tLast seen\tMeldeaufrufe\n");
LOGP(DDB, LOGL_NOTICE, "-------------------------------------------------------------------------------\n");
while (db) {
last = (db->busy) ? 0 : (uint32_t)(now - db->last_seen);
PDEBUG(DDB, DEBUG_NOTICE, "%d,%d,%05d\t%s\t\t%s\t\t%02d:%02d:%02d \t%d/%d\n", db->futln_nat, db->futln_fuvst, db->futln_rest, (db->eingebucht) ? "YES" : "-no-", (db->busy) ? "YES" : "-no-", last / 3600, (last / 60) % 60, last % 60, db->retry, MELDE_MAXIMAL);
sprintf(attached, "YES (OGK %d)", db->ogk_kanal);
LOGP(DDB, LOGL_NOTICE, "%d,%d,%05d\t%s\t%s\t\t%02d:%02d:%02d \t%d/%s\n", db->futln_nat, db->futln_fuvst, db->futln_rest, (db->eingebucht) ? attached : "-no-\t", (db->busy) ? "YES" : "-no-", last / 3600, (last / 60) % 60, last % 60, db->retry, print_meldeaufrufe(si.meldeaufrufe));
db = db->next;
}
}

View File

@ -1,6 +1,6 @@
int update_db(cnetz_t *cnetz, uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int *futelg_bit, int *extended, int busy, int failed);
int find_db(uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int *futelg_bit, int *extended);
int update_db(uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int ogk_kanal, int *futelg_bit, int *extended, int busy, int failed);
int find_db(uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int *ogk_kanal, int *futelg_bit, int *extended);
void flush_db(void);
void dump_db(void);

View File

@ -26,8 +26,9 @@
#include <math.h>
#include <errno.h>
#include "../libsample/sample.h"
#include "../libdebug/debug.h"
#include "../liblogging/logging.h"
#include "../libmobile/call.h"
#include "../libmobile/get_time.h"
#include "cnetz.h"
#include "sysinfo.h"
#include "telegramm.h"
@ -46,15 +47,14 @@
#define MAX_DISPLAY 1.4 /* something above speech level, no emphasis */
#define BITRATE 5280.0 /* bits per second */
#define BLOCK_BITS 198 /* duration of one time slot including pause at beginning and end */
#define CUT_OFF_OFFSET 300.0 /* cut off frequency for offset filter (level correction between subsequent audio chunks) */
#ifdef TEST_SCRAMBLE
jitter_t scrambler_test_jb;
test_echo_t scrambler_test_echo = {};
scrambler_t scrambler_test_scrambler1;
scrambler_t scrambler_test_scrambler2;
#endif
const char *cnetz_dsp_mode_name(enum dsp_mode mode)
static const char *cnetz_dsp_mode_name(enum dsp_mode mode)
{
static char invalid[16];
@ -77,6 +77,7 @@ const char *cnetz_dsp_mode_name(enum dsp_mode mode)
void dsp_init(void)
{
compandor_init();
}
static void dsp_init_ramp(cnetz_t *cnetz)
@ -84,7 +85,7 @@ static void dsp_init_ramp(cnetz_t *cnetz)
double c;
int i;
PDEBUG(DDSP, DEBUG_DEBUG, "Generating smooth ramp table.\n");
LOGP(DDSP, LOGL_DEBUG, "Generating smooth ramp table.\n");
for (i = 0; i < 256; i++) {
/* use square-root of cosine ramp. tests showed that phones are more
* happy with that. (This is not correct pulse shaping!) */
@ -103,9 +104,8 @@ int dsp_init_sender(cnetz_t *cnetz, int measure_speed, double clock_speed[2], en
{
int rc = 0;
double size;
double RC, dt;
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Init FSK for 'Sender'.\n");
LOGP_CHAN(DDSP, LOGL_DEBUG, "Init FSK for 'Sender'.\n");
/* set modulation parameters */
sender_set_fm(&cnetz->sender, MAX_DEVIATION, MAX_MODULATION, speech_deviation, MAX_DISPLAY);
@ -116,20 +116,20 @@ int dsp_init_sender(cnetz_t *cnetz, int measure_speed, double clock_speed[2], en
}
if (clock_speed[0] > 1000 || clock_speed[0] < -1000 || clock_speed[1] > 1000 || clock_speed[1] < -1000) {
PDEBUG_CHAN(DDSP, DEBUG_ERROR, "Clock speed %.1f,%.1f ppm out of range! Please use range between +-1000 ppm!\n", clock_speed[0], clock_speed[1]);
LOGP_CHAN(DDSP, LOGL_ERROR, "Clock speed %.1f,%.1f ppm out of range! Please use range between +-1000 ppm!\n", clock_speed[0], clock_speed[1]);
return -EINVAL;
}
PDEBUG_CHAN(DDSP, DEBUG_INFO, "Using clock speed of %.1f ppm (RX) and %.1f ppm (TX) to correct sound card's clock.\n", clock_speed[0], clock_speed[1]);
LOGP_CHAN(DDSP, LOGL_INFO, "Using clock speed of %.1f ppm (RX) and %.1f ppm (TX) to correct sound card's clock.\n", clock_speed[0], clock_speed[1]);
cnetz->fsk_bitduration = (double)cnetz->sender.samplerate / ((double)BITRATE / (1.0 + clock_speed[1] / 1000000.0));
cnetz->fsk_tx_bitstep = 1.0 / cnetz->fsk_bitduration;
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Use %.4f samples for one bit duration @ %d.\n", cnetz->fsk_bitduration, cnetz->sender.samplerate);
LOGP_CHAN(DDSP, LOGL_DEBUG, "Use %.4f samples for one bit duration @ %d.\n", cnetz->fsk_bitduration, cnetz->sender.samplerate);
size = cnetz->fsk_bitduration * (double)BLOCK_BITS * 16.0; /* 16 blocks for distributed frames */
cnetz->fsk_tx_buffer_size = size * 1.1; /* more to compensate clock speed */
cnetz->fsk_tx_buffer = calloc(sizeof(sample_t), cnetz->fsk_tx_buffer_size);
if (!cnetz->fsk_tx_buffer) {
PDEBUG_CHAN(DDSP, DEBUG_ERROR, "No memory!\n");
LOGP_CHAN(DDSP, LOGL_ERROR, "No memory!\n");
rc = -ENOMEM;
goto error;
}
@ -144,13 +144,13 @@ int dsp_init_sender(cnetz_t *cnetz, int measure_speed, double clock_speed[2], en
/* create speech buffer */
cnetz->dsp_speech_buffer = calloc(sizeof(sample_t), (int)(cnetz->fsk_bitduration * 70.0)); /* more to compensate clock speed. we just need it to fill 62 bits (60 bits, including pause bits). */
if (!cnetz->dsp_speech_buffer) {
PDEBUG_CHAN(DDSP, DEBUG_ERROR, "No memory!\n");
LOGP_CHAN(DDSP, LOGL_ERROR, "No memory!\n");
rc = -ENOMEM;
goto error;
}
/* reinit the sample rate to shrink/expand audio */
init_samplerate(&cnetz->sender.srstate, 8000.0, (double)cnetz->sender.samplerate / 1.1, 3300.0); /* 66 <-> 60 */
init_samplerate(&cnetz->sender.srstate, 8000.0, (double)cnetz->sender.samplerate / (1.1 / (1.0 + clock_speed[0] / 1000000.0)), 3300.0); /* 66 <-> 60 */
rc = fsk_fm_init(&cnetz->fsk_demod, cnetz, cnetz->sender.samplerate, (double)BITRATE / (1.0 + clock_speed[0] / 1000000.0), demod);
if (rc < 0)
@ -160,25 +160,17 @@ int dsp_init_sender(cnetz_t *cnetz, int measure_speed, double clock_speed[2], en
scrambler_setup(&cnetz->scrambler_tx, (double)cnetz->sender.samplerate / 1.1);
scrambler_setup(&cnetz->scrambler_rx, (double)cnetz->sender.samplerate / 1.1);
/* reinit jitter buffer for 8000 kHz */
jitter_destroy(&cnetz->sender.dejitter);
rc = jitter_create(&cnetz->sender.dejitter, 8000 / 5);
if (rc < 0)
goto error;
/* init compandor, according to C-Netz specs, attack and recovery time
* shall not exceed according to ITU G.162 */
init_compandor(&cnetz->cstate, 8000, 5.0, 22.5);
setup_compandor(&cnetz->cstate, 8000, 5.0, 22.5);
/* use this filter to compensate level changes between two subsequent audio chunks */
RC = 1.0 / (CUT_OFF_OFFSET * 2.0 *3.14);
dt = 1.0 / cnetz->sender.samplerate;
cnetz->offset_factor = RC / (RC + dt);
/* use duration of one bit to ramp level of last frame to current frame */
cnetz->offset_range = ceil(cnetz->fsk_bitduration);
#ifdef TEST_SCRAMBLE
rc = jitter_create(&scrambler_test_jb, cnetz->sender.samplerate / 5);
rc = test_echo_alloc(&scrambler_test_echo, cnetz->sender.samplerate / 20);
if (rc < 0) {
PDEBUG_CHAN(DDSP, DEBUG_ERROR, "Failed to init jitter buffer for scrambler test!\n");
LOGP_CHAN(DDSP, LOGL_ERROR, "Failed to init echo buffer for scrambler test!\n");
exit(0);
}
scrambler_setup(&scrambler_test_scrambler1, cnetz->sender.samplerate);
@ -197,7 +189,7 @@ error:
void dsp_cleanup_sender(cnetz_t *cnetz)
{
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Cleanup FSK for 'Sender'.\n");
LOGP_CHAN(DDSP, LOGL_DEBUG, "Cleanup FSK for 'Sender'.\n");
if (cnetz->fsk_tx_buffer) {
free(cnetz->fsk_tx_buffer);
@ -265,7 +257,7 @@ void calc_clock_speed(cnetz_t *cnetz, double samples, int tx, int result)
speed_ppm_avg[index] += cs->speed_ppm[index][(cs->idx[index] - i - 1) & 0xff];
speed_ppm_avg[index] /= (double)cs->num[index];
}
PDEBUG_CHAN(DDSP, DEBUG_NOTICE, "Clock: RX=%.3f TX=%.3f; Signal: RX=%.3f TX=%.3f ppm\n", speed_ppm_avg[0], speed_ppm_avg[1], speed_ppm_avg[2], speed_ppm_avg[3]);
LOGP_CHAN(DDSP, LOGL_NOTICE, "Clock: RX=%.3f TX=%.3f; Signal: RX=%.3f TX=%.3f ppm\n", speed_ppm_avg[0], speed_ppm_avg[1], speed_ppm_avg[2], speed_ppm_avg[3]);
}
static int fsk_nothing_encode(cnetz_t *cnetz)
@ -568,10 +560,12 @@ static int fsk_distributed_encode(cnetz_t *cnetz, const char *bits)
/* decode samples and hut for bit changes
* use deviation to find greatest slope of the signal (bit change)
*/
void sender_receive(sender_t *sender, sample_t *samples, int length, double __attribute__((unused)) rf_level_db)
void sender_receive(sender_t *sender, sample_t *samples, int length, double rf_level_db)
{
cnetz_t *cnetz = (cnetz_t *) sender;
cnetz->rf_level_db = rf_level_db;
/* measure rx sample speed */
calc_clock_speed(cnetz, length, 0, 0);
@ -579,7 +573,7 @@ void sender_receive(sender_t *sender, sample_t *samples, int length, double __at
#ifdef TEST_UNSCRAMBLE
scrambler(&scrambler_test_scrambler1, samples, length);
#endif
jitter_save(&scrambler_test_jb, samples, length);
test_echo_store(&scrambler_test_echo, samples, length);
return;
#endif
@ -595,12 +589,15 @@ void sender_receive(sender_t *sender, sample_t *samples, int length, double __at
static int shrink_speech(cnetz_t *cnetz, sample_t *speech_buffer)
{
int speech_length;
int16_t spl[100];
jitter_load(&cnetz->sender.dejitter, speech_buffer, 100);
jitter_load_samples(&cnetz->sender.dejitter, (uint8_t *)spl, 100, sizeof(*spl), jitter_conceal_s16, NULL);
int16_to_samples_speech(speech_buffer, spl, 100);
/* 1. compress dynamics */
compress_audio(&cnetz->cstate, speech_buffer, 100);
/* 2. upsample */
speech_length = samplerate_upsample(&cnetz->sender.srstate, speech_buffer, 100, speech_buffer);
speech_length = samplerate_upsample_output_num(&cnetz->sender.srstate, 100);
samplerate_upsample(&cnetz->sender.srstate, speech_buffer, 100, speech_buffer, speech_length);
/* 3. scramble */
if (cnetz->scrambler)
scrambler(&cnetz->scrambler_tx, speech_buffer, speech_length);
@ -648,10 +645,10 @@ again:
* because one has a phase wrap before and the other after a sample.
* then we do it next super frame cycle */
if (master->frame_last_scount == cnetz->fsk_tx_scount) {
PDEBUG(DDSP, DEBUG_DEBUG, "Sync phase of slave to master: master=%.15f, slave=%.15f, diff=%.15f\n", master->frame_last_phase, cnetz->fsk_tx_phase, master->frame_last_phase - cnetz->fsk_tx_phase);
LOGP(DDSP, LOGL_DEBUG, "Sync phase of slave to master: master=%.15f, slave=%.15f, diff=%.15f\n", master->frame_last_phase, cnetz->fsk_tx_phase, master->frame_last_phase - cnetz->fsk_tx_phase);
cnetz->fsk_tx_phase = master->frame_last_phase;
} else {
PDEBUG(DDSP, DEBUG_DEBUG, "Not sync phase of slave to master: Sample counts during frame change are different, ignoring this time!\n");
LOGP(DDSP, LOGL_DEBUG, "Not sync phase of slave to master: Sample counts during frame change are different, ignoring this time!\n");
}
}
}
@ -660,7 +657,7 @@ again:
if (cnetz->sched_dsp_mode_ts >= 0 && cnetz->sched_r_m == 0) {
if (cnetz->sched_dsp_mode_ts == cnetz->sched_ts) {
/* OgK / SpK(K) / SpK(V) */
PDEBUG_CHAN(DDSP, DEBUG_INFO, "Now switching channel mode to %s at timeslot %d\n", cnetz_dsp_mode_name(cnetz->sched_dsp_mode), cnetz->sched_dsp_mode_ts);
LOGP_CHAN(DDSP, LOGL_INFO, "Now switching channel mode to %s at timeslot %d\n", cnetz_dsp_mode_name(cnetz->sched_dsp_mode), cnetz->sched_dsp_mode_ts);
cnetz->sched_dsp_mode_ts = -1;
cnetz_set_dsp_mode(cnetz, cnetz->sched_dsp_mode);
}
@ -668,31 +665,23 @@ again:
switch (cnetz->dsp_mode) {
case DSP_MODE_OGK:
/* if automatic polarity selection is used, toggle between
* two polarities (every 4 slots) until a response is received
* then continue to use the time slots of that polarity
*/
if (cnetz->auto_polarity)
cnetz->negative_polarity = (cnetz->sched_ts & 7) >> 2;
/* send on timeslots depending on the polarity:
* positive polarity: ts, ts+8, ts+16, ts+24
* negative polarity: ts+4, ts+12, ts+20, ts+28
*/
if (((cnetz->sched_ts & 7) == (si.timeslot & 7) && cnetz->negative_polarity == 0)
|| ((cnetz->sched_ts & 7) == ((si.timeslot + 4) & 7) && cnetz->negative_polarity == 1)) {
if (((si.timeslots >> cnetz->sched_ts) & 1)) {
if (cnetz->sched_r_m == 0) {
/* if automatic polarity selection is used, toggle between two polarities (every transmitted slot) until a response is received then continue to use the time slots of that polarity */
if (cnetz->auto_polarity)
cnetz->negative_polarity = (cnetz->sched_ts & 7) >> 2;
/* set last time slot, so we know to which time slot the message from mobile station belongs to */
cnetz->sched_last_ts = cnetz->sched_ts;
bits = cnetz_encode_telegramm(cnetz);
if (bits) {
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Transmitting 'Rufblock' at timeslot %d\n", cnetz->sched_ts);
LOGP_CHAN(DDSP, LOGL_DEBUG, "Transmitting 'Rufblock' at timeslot %d\n", cnetz->sched_ts);
fsk_block_encode(cnetz, bits, 1);
} else
fsk_nothing_encode(cnetz);
} else {
bits = cnetz_encode_telegramm(cnetz);
if (bits) {
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Transmitting 'Meldeblock' at timeslot %d\n", cnetz->sched_ts);
LOGP_CHAN(DDSP, LOGL_DEBUG, "Transmitting 'Meldeblock' at timeslot %d\n", cnetz->sched_ts);
fsk_block_encode(cnetz, bits, 1);
} else
fsk_nothing_encode(cnetz);
@ -704,7 +693,7 @@ again:
case DSP_MODE_SPK_K:
bits = cnetz_encode_telegramm(cnetz);
if (bits) {
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Transmitting 'Konzentrierte Signalisierung' at timeslot %d.%d\n", cnetz->sched_ts, cnetz->sched_r_m * 5);
LOGP_CHAN(DDSP, LOGL_DEBUG, "Transmitting 'Konzentrierte Signalisierung' at timeslot %d.%d\n", cnetz->sched_ts, cnetz->sched_r_m * 5);
fsk_block_encode(cnetz, bits, 0);
} else
fsk_nothing_encode(cnetz);
@ -712,7 +701,7 @@ again:
case DSP_MODE_SPK_V:
bits = cnetz_encode_telegramm(cnetz);
if (bits) {
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Transmitting 'Verteilte Signalisierung' starting at timeslot %d\n", cnetz->sched_ts);
LOGP_CHAN(DDSP, LOGL_DEBUG, "Transmitting 'Verteilte Signalisierung' starting at timeslot %d\n", cnetz->sched_ts);
fsk_distributed_encode(cnetz, bits);
} else
fsk_nothing_encode(cnetz);
@ -808,7 +797,7 @@ void sender_send(sender_t *sender, sample_t *samples, uint8_t *power, int length
calc_clock_speed(cnetz, length, 1, 0);
#ifdef TEST_SCRAMBLE
jitter_load(&scrambler_test_jb, samples, length);
test_echo_load(&scrambler_test_echo, samples, length);
scrambler(&scrambler_test_scrambler2, samples, length);
return;
#endif
@ -827,7 +816,8 @@ void unshrink_speech(cnetz_t *cnetz, sample_t *speech_buffer, int count)
{
sample_t *spl;
int pos, i;
double x, y, x_last, y_last, factor;
int range;
double offset;
/* check if we still have a transaction
* this might not be true, if we just released transaction, but still
@ -836,21 +826,13 @@ void unshrink_speech(cnetz_t *cnetz, sample_t *speech_buffer, int count)
if (!cnetz->trans_list)
return;
/* fix offset between speech blocks by using high pass filter */
/* use first sample as previous sample, so we don't have a level jump between two subsequent audio chunks */
x_last = speech_buffer[0];
y_last = cnetz->offset_y_last;
factor = cnetz->offset_factor;
for (i = 0; i < count; i++) {
/* change level */
x = speech_buffer[i];
/* high-pass to remove low level frequencies, caused by level jump between audio chunks */
y = factor * (y_last + x - x_last);
x_last = x;
y_last = y;
speech_buffer[i] = y;
/* ramp from level of last frame to level of current frame */
range = cnetz->offset_range;
offset = speech_buffer[0] - cnetz->offset_last;
for (i = 0; i < range; i++) {
speech_buffer[i] -= offset * (1.0 - (double)i / (double)range);
}
cnetz->offset_y_last = y_last;
cnetz->offset_last = speech_buffer[count - 1];
/* 4. de-emphasis is done by cnetz code, not by common code */
/* de-emphasis is only used when scrambler is off, see FTZ 171 TR 60 Clause 4 */
@ -881,9 +863,12 @@ void unshrink_speech(cnetz_t *cnetz, sample_t *speech_buffer, int count)
void cnetz_set_dsp_mode(cnetz_t *cnetz, enum dsp_mode mode)
{
if (mode != cnetz->dsp_mode) {
PDEBUG_CHAN(DDSP, DEBUG_INFO, "DSP mode %s -> %s\n", cnetz_dsp_mode_name(cnetz->dsp_mode), cnetz_dsp_mode_name(mode));
LOGP_CHAN(DDSP, LOGL_INFO, "DSP mode %s -> %s\n", cnetz_dsp_mode_name(cnetz->dsp_mode), cnetz_dsp_mode_name(mode));
cnetz->dsp_mode = mode;
}
if (mode == DSP_MODE_SPK_V && cnetz->dsp_mode != mode)
jitter_reset(&cnetz->sender.dejitter);
/* we must get rid of partly received frame */
fsk_demod_reset(&cnetz->fsk_demod);
}
@ -891,11 +876,35 @@ void cnetz_set_dsp_mode(cnetz_t *cnetz, enum dsp_mode mode)
void cnetz_set_sched_dsp_mode(cnetz_t *cnetz, enum dsp_mode mode, int timeslot)
{
if (cnetz->sched_dsp_mode_ts < 0 && mode == cnetz->dsp_mode) {
PDEBUG_CHAN(DDSP, DEBUG_INFO, "Schedule DSP mode %s not required, we are already in that mode\n", cnetz_dsp_mode_name(mode));
LOGP_CHAN(DDSP, LOGL_INFO, "Schedule DSP mode %s not required, we are already in that mode\n", cnetz_dsp_mode_name(mode));
return;
}
PDEBUG_CHAN(DDSP, DEBUG_INFO, "Schedule DSP mode %s -> %s at timeslot %d\n", cnetz_dsp_mode_name(cnetz->dsp_mode), cnetz_dsp_mode_name(mode), timeslot);
LOGP_CHAN(DDSP, LOGL_INFO, "Schedule DSP mode %s -> %s at timeslot %d\n", cnetz_dsp_mode_name(cnetz->dsp_mode), cnetz_dsp_mode_name(mode), timeslot);
cnetz->sched_dsp_mode = mode;
cnetz->sched_dsp_mode_ts = timeslot;
}
/* Receive audio from call instance. */
void call_down_audio(void *decoder, void *decoder_priv, int callref, uint16_t sequence, uint8_t marker, uint32_t timestamp, uint32_t ssrc, uint8_t *payload, int payload_len)
{
sender_t *sender;
cnetz_t *cnetz;
for (sender = sender_head; sender; sender = sender->next) {
cnetz = (cnetz_t *) sender;
if (cnetz->trans_list && cnetz->trans_list->callref == callref)
break;
}
if (!sender)
return;
if (cnetz->dsp_mode == DSP_MODE_SPK_V) {
jitter_frame_t *jf;
jf = jitter_frame_alloc(decoder, decoder_priv, payload, payload_len, marker, sequence, timestamp, ssrc);
if (jf)
jitter_save(&cnetz->sender.dejitter, jf);
}
}
void call_down_clock(void) {}

View File

@ -121,7 +121,10 @@
* if debug is set to 1, debugging will start at program start
*/
//#define DEBUG_DECODER
//static int debug = 0;
#ifdef DEBUG_DECODER
static int debug = 0;
#endif
#include <stdio.h>
#include <stdint.h>
@ -129,7 +132,7 @@
#include <string.h>
#include <math.h>
#include "../libsample/sample.h"
#include "../libdebug/debug.h"
#include "../liblogging/logging.h"
#include "cnetz.h"
#include "dsp.h"
#include "telegramm.h"
@ -140,7 +143,7 @@ int fsk_fm_init(fsk_fm_demod_t *fsk, cnetz_t *cnetz, int samplerate, double bitr
memset(fsk, 0, sizeof(*fsk));
if (samplerate < 48000) {
PDEBUG(DDSP, DEBUG_ERROR, "Sample rate must be at least 48000 Hz!\n");
LOGP(DDSP, LOGL_ERROR, "Sample rate must be at least 48000 Hz!\n");
return -1;
}
@ -149,13 +152,13 @@ int fsk_fm_init(fsk_fm_demod_t *fsk, cnetz_t *cnetz, int samplerate, double bitr
switch (demod) {
case FSK_DEMOD_SLOPE:
PDEBUG(DDSP, DEBUG_INFO, "Detecting level change by looking at slope (good for sound cards)\n");
LOGP(DDSP, LOGL_INFO, "Detecting level change by looking at slope (good for sound cards)\n");
break;
case FSK_DEMOD_LEVEL:
PDEBUG(DDSP, DEBUG_INFO, "Detecting level change by looking zero crosssing (good for SDR)\n");
LOGP(DDSP, LOGL_INFO, "Detecting level change by looking zero crosssing (good for SDR)\n");
break;
default:
PDEBUG(DDSP, DEBUG_ERROR, "Wrong demod type, please fix!\n");
LOGP(DDSP, LOGL_ERROR, "Wrong demod type, please fix!\n");
abort();
}
@ -163,7 +166,7 @@ int fsk_fm_init(fsk_fm_demod_t *fsk, cnetz_t *cnetz, int samplerate, double bitr
half = (int)((double)samplerate / bitrate / 2.0 + 0.5);
fsk->bit_buffer_spl = calloc(sizeof(fsk->bit_buffer_spl[0]), len);
if (!fsk->bit_buffer_spl) {
PDEBUG(DDSP, DEBUG_ERROR, "No mem!\n");
LOGP(DDSP, LOGL_ERROR, "No mem!\n");
goto error;
}
@ -174,7 +177,7 @@ int fsk_fm_init(fsk_fm_demod_t *fsk, cnetz_t *cnetz, int samplerate, double bitr
fsk->speech_size = samplerate * 60 / bitrate + 10; /* 60 bits duration, add 10 to be safe */
fsk->speech_buffer = calloc(sizeof(fsk->speech_buffer[0]), fsk->speech_size);
if (!fsk->speech_buffer) {
PDEBUG(DDSP, DEBUG_ERROR, "No mem!\n");
LOGP(DDSP, LOGL_ERROR, "No mem!\n");
goto error;
}
@ -182,7 +185,7 @@ int fsk_fm_init(fsk_fm_demod_t *fsk, cnetz_t *cnetz, int samplerate, double bitr
#ifdef DEBUG_DECODER
char debug_filename[256];
sprintf(debug_filename, "/tmp/debug_decoder_channel_%d.txt", cnetz->sender.kanal);
sprintf(debug_filename, "/tmp/debug_decoder_channel_%s.txt", cnetz->sender.kanal);
fsk->debug_fp = fopen(debug_filename, "w");
if (!fsk->debug_fp) {
fprintf(stderr, "Failed to open decoder debug file '%s'!\n", debug_filename);
@ -414,17 +417,6 @@ static inline void find_change_slope(fsk_fm_demod_t *fsk)
sample_t threshold;
int i;
#ifdef DEBUG_DECODER
/* show deviation of middle sample in windows (in a range of bandwidth) */
if (debug) {
fprintf(fsk->debug_fp, "%s",
debug_amplitude(
fsk->bit_buffer_spl[(fsk->bit_buffer_pos + fsk->bit_buffer_half) % fsk->bit_buffer_len]
)
);
}
#endif
/* get level range (level_min and level_max) and also
* get maximum slope (change_max) and where it was
* (change_at) and what direction it went (change_positive)
@ -492,10 +484,6 @@ static inline void find_change_slope(fsk_fm_demod_t *fsk)
}
fsk->next_bit -= fsk->bits_per_sample;
#ifdef DEBUG_DECODER
if (debug)
fprintf(fsk->debug_fp, "\n");
#endif
}
/* find bit change by looking at zero crossing */
@ -507,12 +495,6 @@ static inline void find_change_level(fsk_fm_demod_t *fsk)
/* get bit in the middle of the buffer */
s = fsk->bit_buffer_spl[(fsk->bit_buffer_pos + fsk->bit_buffer_half) % fsk->bit_buffer_len];
#ifdef DEBUG_DECODER
/* show deviation */
if (debug)
fprintf(fsk->debug_fp, "%s", debug_amplitude(s));
#endif
/* just sample first bit in distributed mode */
if (fsk->cnetz->dsp_mode == DSP_MODE_SPK_V && fsk->bit_count == 0) {
if (fmod(fsk->bit_time, BITS_PER_SPK_BLOCK) < 1.5)
@ -569,10 +551,6 @@ static inline void find_change_level(fsk_fm_demod_t *fsk)
fsk->next_bit -= fsk->bits_per_sample;
done:
#ifdef DEBUG_DECODER
if (debug)
fprintf(fsk->debug_fp, "\n");
#endif
return;
}
@ -580,7 +558,7 @@ done:
void fsk_fm_demod(fsk_fm_demod_t *fsk, sample_t *samples, int length)
{
int i;
double t;
double t = 0.0;
/* process signaling block, sample by sample */
for (i = 0; i < length; i++) {
@ -590,6 +568,14 @@ void fsk_fm_demod(fsk_fm_demod_t *fsk, sample_t *samples, int length)
if (fsk->bit_buffer_pos == fsk->bit_buffer_len)
fsk->bit_buffer_pos = 0;
#ifdef DEBUG_DECODER
/* show deviation of center sample in window */
if (debug)
fprintf(fsk->debug_fp, "%s", debug_amplitude(fsk->bit_buffer_spl[(fsk->bit_buffer_pos + fsk->bit_buffer_half) % fsk->bit_buffer_len]));
if (debug && fmod(fsk->bit_time - fsk->bits_per_sample, 1.0) > fmod(fsk->bit_time, 1.0))
fprintf(fsk->debug_fp, " -bitchange-");
#endif
/* for each sample process buffer */
if (fsk->cnetz->dsp_mode != DSP_MODE_SPK_V) {
if (fsk->demod_type == FSK_DEMOD_SLOPE)
@ -611,7 +597,7 @@ void fsk_fm_demod(fsk_fm_demod_t *fsk, sample_t *samples, int length)
fsk->next_bit = 1.0 - fsk->bits_per_sample;
#ifdef DEBUG_DECODER
if (debug && fsk->bit_count)
fprintf(fsk->debug_fp, "---- SPK(V) BLOCK START ----\n");
fprintf(fsk->debug_fp, "\n---- SPK(V) BLOCK START ----");
#endif
fsk->bit_count = 0;
} else
@ -622,13 +608,21 @@ void fsk_fm_demod(fsk_fm_demod_t *fsk, sample_t *samples, int length)
find_change_level(fsk);
} else
if (t >= 5.5 && t < 65.5) {
#ifdef DEBUG_DECODER
if (debug && !fsk->speech_count)
fprintf(fsk->debug_fp, " (start recording speech)");
#endif
/* get audio for the duration of 60 bits */
/* prevent overflow, if speech_size != 0 and SPK_V
* has been restarted. */
if (fsk->speech_count < fsk->speech_size)
fsk->speech_buffer[fsk->speech_count++] = samples[i];
fsk->speech_buffer[fsk->speech_count++] = fsk->bit_buffer_spl[(fsk->bit_buffer_pos + fsk->bit_buffer_half) % fsk->bit_buffer_len];
} else
if (t >= 65.5) {
#ifdef DEBUG_DECODER
if (debug && fsk->speech_count)
fprintf(fsk->debug_fp, " (stop recording speech)");
#endif
if (fsk->speech_count) {
unshrink_speech(fsk->cnetz, fsk->speech_buffer, fsk->speech_count);
fsk->speech_count = 0;
@ -641,6 +635,10 @@ void fsk_fm_demod(fsk_fm_demod_t *fsk, sample_t *samples, int length)
if (fsk->bit_time >= BITS_PER_SUPERFRAME) {
fsk->bit_time -= BITS_PER_SUPERFRAME;
}
#ifdef DEBUG_DECODER
if (debug && samples)
fprintf(fsk->debug_fp, "\n");
#endif
/* another clock is used to measure actual super frame time */
fsk->bit_time_uncorrected += fsk->bits_per_sample;
if (fsk->bit_time_uncorrected >= BITS_PER_SUPERFRAME) {

View File

@ -24,7 +24,7 @@
#include <errno.h>
#include "../libsample/sample.h"
#include "../libmobile/main_mobile.h"
#include "../libdebug/debug.h"
#include "../liblogging/logging.h"
#include "../libmobile/call.h"
#include "../anetz/freiton.h"
#include "../anetz/besetztton.h"
@ -44,19 +44,20 @@ enum cnetz_chan_type chan_type[MAX_SENDER] = { CHAN_TYPE_OGK_SPK };
int measure_speed = 0;
double clock_speed[2] = { 0.0, 0.0 };
int set_clock_speed = 0;
const char *flip_polarity = "auto";
const char *flip_polarity = "";
int ms_power = 6; /* 1..8 */
int warteschlange = 1;
int challenge_valid;
uint64_t challenge;
int response_valid;
uint64_t response;
uint8_t timeslot = 0;
uint32_t timeslots = 4; /* 1 up to 8 */
uint8_t fuz_nat = 1;
uint8_t fuz_fuvst = 4;
uint8_t fuz_rest = 66;
const char *fuz_name = NULL;
uint8_t kennung_fufst = 1; /* normal prio */
uint8_t bahn_bs = 0; /* normal */
uint8_t authentifikationsbit = 0;
uint8_t ws_kennung = 0; /* no queue */
uint8_t fuvst_sperren = 0; /* no blocking registration/calls */
@ -72,9 +73,11 @@ uint8_t reduzierung = 0; /* factor 4 */
uint8_t nachbar_prio = 0;
int8_t futln_sperre_start = -1; /* no blocking */
int8_t futln_sperre_end = -1; /* no range */
int meldeinterval = 120; /* when to ask the phone about beeing alive */
int meldeaufrufe = 3; /* how many times to ask phone about beeing alive */
enum demod_type demod = FSK_DEMOD_AUTO;
int metering = 20;
double speech_deviation = 4000.0; /* best results with all my equipment */
double speech_deviation = 2400.0; /* best results with older equipment (not C5) */
void print_help(const char *arg0)
{
@ -82,6 +85,10 @@ void print_help(const char *arg0)
/* - - */
printf(" -T --channel-type <channel type> | list\n");
printf(" Give channel type, use 'list' to get a list. (default = '%s')\n", chan_type_short_name(chan_type[0]));
printf(" You must define at least one OgK at channel 131. This channel may be a\n");
printf(" a combined OgK+SpK channel, but this works with older phones only.\n");
printf(" You must define additionally one or more SpK, in order to make calls.\n");
printf(" You may define alternative OgK, the phones will attach to it then.\n");
printf(" -M --measure-speed\n");
printf(" Measures clock speed. THIS IS REQUIRED! See documentation!\n");
printf(" -C --clock-speed <rx ppm>,<tx ppm>\n");
@ -95,8 +102,8 @@ void print_help(const char *arg0)
printf(" generates a negative signal rather than a positive one. If auto, the\n");
printf(" base station uses double time slots with alternating polarity.\n");
printf(" Once a mobile registers, the correct polarity is selected and used.\n");
printf(" (default = %s)\n", flip_polarity);
printf(" Note: This has no effect with SDR.\n");
printf(" (default = %s)\n", (flip_polarity[0]) ? flip_polarity : "auto");
printf(" Note: Correct polarity is selected for SDR by default.\n");
printf(" -P --ms-power <power level>\n");
printf(" Give power level of the mobile station: 1, 2, 4, 6, 8 (default = '%d')\n", ms_power);
printf(" 1 = 7.5-20 W; 2 = 4-8 W; 4 = 0.5-1 W; 6 = 50-125 mW; 8 = 2-10 mW\n");
@ -115,17 +122,18 @@ void print_help(const char *arg0)
printf(" Enable queue support. If no channel is available, calls will be kept\n");
printf(" in a queue for maximum of 60 seconds. (default = %d)\n", warteschlange);
printf(" -G --gebuehren <seconds> | 0\n");
printf(" Increment metering counter every given number of seconds.\n");
printf(" Increment metering counter every given number of seconds.\n");
printf(" To turn off, use 0. (default = %d)\n", metering);
printf(" If metering pulses are sent via Osmo-CC interface, pulses are always\n");
printf(" increment metering counter. This overrides this option.\n");
printf(" -V --voice-deviation <2400..4000 Hz>\n");
printf(" It is unclear what the actual voice deviation is. Please decrease, if\n");
printf(" mobile's microphone is too loud and speaker is too quiet.\n");
printf(" It is unclear what the actual voice deviation is. Please increase, if\n");
printf(" mobile's earpiece is too quiet and the microphone is too loud.\n");
printf(" (default = %.0f)\n", speech_deviation);
printf(" -S --sysinfo timeslot=<0..31>\n");
printf(" Set time slot of OgK broadcast. There are 32 time slots, but every 8th\n");
printf(" slot is used. This means if you select time slot 0, also slots 8, 16\n");
printf(" and 24 will be used. If you select slot 14, also slots 6, 22 and 30\n");
printf(" will be used. (default = %d)\n", timeslot);
printf(" -S --sysinfo timeslots=1|2|4|8\n");
printf(" Set number of timeslots of OgK broadcast. There are 32 time slots per\n");
printf(" frame, but only up to 8 slots can be used, because of processing\n");
printf(" delay. (default = %d)\n", timeslots);
printf(" -S --sysinfo fuz-nat=<nat>\n");
printf(" Set country ID of base station. All IDs were used inside Germany only.\n");
printf(" (default = %d)\n", fuz_nat);
@ -145,6 +153,12 @@ void print_help(const char *arg0)
printf(" 2 = Higher priority base station.\n");
printf(" 3 = Highest priority base station.\n");
printf(" Note: Priority has no effect, because there is only one base station.\n");
printf(" -S --sysinfo bahn-bs=<value>\n");
printf(" Set special tunnel base station mode for train mobile phones only.\n");
printf(" (default = %d)\n", kennung_fufst);
printf(" 0 = Disable (every phone is allowed)\n");
printf(" 1 = Enable (only train phones are allowed)\n");
printf(" Note: Enableing this will force priority to 0 (Test base station).\n");
printf(" -S --sysinfo auth=<auth>\n");
printf(" Enable authentication flag on the base station. Since we cannot\n");
printf(" authenticate, because we don't know the secret key and the algorithm,\n");
@ -217,6 +231,12 @@ void print_help(const char *arg0)
} else {
printf(" (default = %d-%d)\n", futln_sperre_start, futln_sperre_end);
}
printf(" -S --sysinfo meldeinterval=<seconds>\n");
printf(" Time to wait until pinging the phone wether it is still available.\n");
printf(" (default = %d)\n", meldeinterval);
printf(" -S --sysinfo meldeaufrufe=<count>\n");
printf(" Number of times we try to ping mobile until we assume it is gone.\n");
printf(" Use '0' for infinite tries. (default = %d)\n", meldeaufrufe);
printf(" -D --demod auto | slope | level\n");
printf(" Adjust demodulation algorithm. Use 'slope' to detect a level change\n");
printf(" by finding the highest slope of a bit transition. It is useful, if\n");
@ -346,8 +366,8 @@ static int handle_options(int short_option, int argi, char **argv)
return -EINVAL;
}
p++;
if (!strncasecmp(argv[argi], "timeslot=", p - argv[argi])) {
timeslot = atoi_limit(p, 0, 31);
if (!strncasecmp(argv[argi], "timeslots=", p - argv[argi])) {
timeslots = atoi_limit(p, 1, 8);
} else
if (!strncasecmp(argv[argi], "fuz-nat=", p - argv[argi])) {
fuz_nat = atoi_limit(p, 0, 7);
@ -380,6 +400,9 @@ error_fuz:
if (!strncasecmp(argv[argi], "kennung-fufst=", p - argv[argi])) {
kennung_fufst = atoi_limit(p, 0, 3);
} else
if (!strncasecmp(argv[argi], "bahn-bs=", p - argv[argi])) {
bahn_bs = atoi_limit(p, 0, 1);
} else
if (!strncasecmp(argv[argi], "auth=", p - argv[argi])) {
authentifikationsbit = atoi_limit(p, 0, 1);
} else
@ -433,6 +456,12 @@ error_fuz:
futln_sperre_end = atoi(q) & 0xf;
}
} else
if (!strncasecmp(argv[argi], "meldeinterval=", p - argv[argi])) {
meldeinterval = atoi_limit(p, 1, 20 * 60);
} else
if (!strncasecmp(argv[argi], "meldeaufrufe=", p - argv[argi])) {
meldeaufrufe = atoi_limit(p, 0, 1000000);
} else
{
fprintf(stderr, "Given sysinfo parameter '%s' unknown, use '-h' for help!\n", argv[argi]);
return -EINVAL;
@ -524,7 +553,7 @@ int main(int argc, char *argv[])
}
if (!num_kanal) {
printf("No channel (\"Kanal\") is specified, I suggest channel %d.\n\n", CNETZ_OGK_KANAL);
printf("No channel (\"Kanal\") is specified, I suggest channel %d.\n\n", CNETZ_STD_OGK_KANAL);
mandatory = 1;
}
if (use_sdr) {
@ -575,7 +604,13 @@ int main(int argc, char *argv[])
}
if (anzahl_gesperrter_teilnehmergruppen)
printf("Blocked subscriber with number's last 4 bits from 0x%x to 0x%x\n", teilnehmergruppensperre, (teilnehmergruppensperre + anzahl_gesperrter_teilnehmergruppen - 1) & 0xf);
init_sysinfo(timeslot, fuz_nat, fuz_fuvst, fuz_rest, kennung_fufst, authentifikationsbit, ws_kennung, fuvst_sperren, grenz_einbuchen, grenz_umschalten, grenz_ausloesen, mittel_umschalten, mittel_ausloesen, genauigkeit, bewertung, entfernung, reduzierung, nachbar_prio, teilnehmergruppensperre, anzahl_gesperrter_teilnehmergruppen);
switch(timeslots) {
case 1: timeslots=0x00000001; break;
case 2: timeslots=0x00010001; break;
case 4: timeslots=0x01010101; break;
default: timeslots=0x11111111;
}
init_sysinfo(timeslots, fuz_nat, fuz_fuvst, fuz_rest, kennung_fufst, bahn_bs, authentifikationsbit, ws_kennung, fuvst_sperren, grenz_einbuchen, grenz_umschalten, grenz_ausloesen, mittel_umschalten, mittel_ausloesen, genauigkeit, bewertung, entfernung, reduzierung, nachbar_prio, teilnehmergruppensperre, anzahl_gesperrter_teilnehmergruppen, meldeinterval, meldeaufrufe);
dsp_init();
rc = init_telegramm();
if (rc < 0) {
@ -585,7 +620,7 @@ int main(int argc, char *argv[])
init_coding();
cnetz_init();
/* check for mandatory OgK */
/* check for mandatory standard OgK */
for (i = 0; i < num_kanal; i++) {
if (chan_type[i] == CHAN_TYPE_OGK || chan_type[i] == CHAN_TYPE_OGK_SPK)
break;
@ -629,7 +664,7 @@ int main(int argc, char *argv[])
polarity = 1; /* positive */
if (!strcmp(flip_polarity, "yes"))
polarity = -1; /* negative */
if (use_sdr && polarity == 0)
if (use_sdr && !flip_polarity[0])
polarity = 1; /* SDR is always positive */
/* demodulation algorithm */
@ -667,6 +702,7 @@ fail:
cnetz_destroy(sender_head);
/* exits */
main_mobile_exit();
fm_exit();
options_free();

View File

@ -7,10 +7,10 @@
/* The list of cell towers is ripped from BSA61 phone's firmware */
static struct cnetz_stations {
char standort[32], name[8];
char long_name[32], name[8];
uint8_t nat, fuvst, rest;
} cnetz_stations[] = {
/* Standort-Name Kurzer Name, Nat FuVST Rest */
/* Langer-Name Kurzer Name, Nat FuVST Rest */
{ "Oberhausen 32", "OB32", 1, 2, 1, },
{ "Oberhausen 0 <prov.>", "OB0", 1, 2, 5, },
{ "Wuppertal 18", "WUP18", 1, 2, 6, },
@ -2143,37 +2143,37 @@ void station_list(void)
char name[33];
printf("List of all base stations:\n\n");
printf("Name Standort Nat FuVst Rest\n");
printf("Kurz Name Nat FuVst Rest\n");
printf("------------------------------------------------------------\n");
for (i = 0; cnetz_stations[i].standort[0]; i++) {
for (i = 0; cnetz_stations[i].long_name[0]; i++) {
memset(name, ' ', sizeof(name));
memcpy(name, cnetz_stations[i].name, strlen(cnetz_stations[i].name));
name[8] = '\0';
printf("%s", name);
memset(name, ' ', sizeof(name));
memcpy(name, cnetz_stations[i].standort, strlen(cnetz_stations[i].standort));
memcpy(name, cnetz_stations[i].long_name, strlen(cnetz_stations[i].long_name));
name[sizeof(name) - 1] = '\0';
printf("%s%d\t%d\t%d\n", name, cnetz_stations[i].nat, cnetz_stations[i].fuvst, cnetz_stations[i].rest);
}
}
const char *get_station_name(uint8_t nat, uint8_t fuvst, uint8_t rest, const char **standort)
const char *get_station_name(uint8_t nat, uint8_t fuvst, uint8_t rest, const char **long_name)
{
int i;
for (i = 0; cnetz_stations[i].standort[0]; i++) {
for (i = 0; cnetz_stations[i].long_name[0]; i++) {
if (cnetz_stations[i].nat == nat
&& cnetz_stations[i].fuvst == fuvst
&& cnetz_stations[i].rest == rest) {
if (standort)
*standort = cnetz_stations[i].standort;
if (long_name)
*long_name = cnetz_stations[i].long_name;
return cnetz_stations[i].name;
}
}
if (standort)
*standort = "unknown";
return *standort;
if (long_name)
*long_name = "unknown";
return *long_name;
}
const char *get_station_id(const char *name, uint8_t *nat, uint8_t *fuvst, uint8_t *rest)
@ -2182,7 +2182,8 @@ const char *get_station_id(const char *name, uint8_t *nat, uint8_t *fuvst, uint8
for (i = 0; cnetz_stations[i].name[0]; i++) {
/* check for given prefix */
if (!strncasecmp(cnetz_stations[i].name, name, strlen(name))) {
if (!strncasecmp(cnetz_stations[i].name, name, strlen(name))
|| !strncasecmp(cnetz_stations[i].long_name, name, strlen(name)) ) {
/* found twice */
if (found >= 0)
return "Given station name is ambiguous, use more letters! Use '-S fuz-name=list' to get a list of all stations.";

View File

@ -4,12 +4,12 @@
cnetz_si si;
void init_sysinfo(uint8_t timeslot, uint8_t fuz_nat, uint8_t fuz_fuvst, uint8_t fuz_rest, uint8_t kennung_fufst, uint8_t authentifikationsbit, uint8_t ws_kennung, uint8_t vermittlungstechnische_sperren, uint8_t grenz_einbuchen, uint8_t grenz_umschalten, uint8_t grenz_ausloesen, uint8_t mittel_umschalten, uint8_t mittel_ausloesen, uint8_t genauigkeit, uint8_t bewertung, uint8_t entfernung, uint8_t reduzierung, uint8_t nachbar_prio, int8_t teilnehmergruppensperre, uint8_t anzahl_gesperrter_teilnehmergruppen)
void init_sysinfo(uint32_t timeslots, uint8_t fuz_nat, uint8_t fuz_fuvst, uint8_t fuz_rest, uint8_t kennung_fufst, uint8_t bahn_bs, uint8_t authentifikationsbit, uint8_t ws_kennung, uint8_t vermittlungstechnische_sperren, uint8_t grenz_einbuchen, uint8_t grenz_umschalten, uint8_t grenz_ausloesen, uint8_t mittel_umschalten, uint8_t mittel_ausloesen, uint8_t genauigkeit, uint8_t bewertung, uint8_t entfernung, uint8_t reduzierung, uint8_t nachbar_prio, int8_t teilnehmergruppensperre, uint8_t anzahl_gesperrter_teilnehmergruppen, int meldeinterval, int meldeaufrufe)
{
memset(&si, 0, sizeof(si));
/* timeslot to use */
si.timeslot = timeslot;
si.timeslots = timeslots;
/* ID of base station */
si.fuz_nat = fuz_nat;
@ -37,7 +37,10 @@ void init_sysinfo(uint8_t timeslot, uint8_t fuz_nat, uint8_t fuz_fuvst, uint8_t
/* a low value is tollerant to bad quality */
si.grenz_einbuchen = grenz_einbuchen; /* 1..7 */
if (bahn_bs)
kennung_fufst = 0;
si.kennung_fufst = kennung_fufst;
si.bahn_bs = bahn_bs;
si.authentifikationsbit = authentifikationsbit;
@ -52,5 +55,8 @@ void init_sysinfo(uint8_t timeslot, uint8_t fuz_nat, uint8_t fuz_fuvst, uint8_t
/* deny group of subscribers. (used to balance subscribers between base stations) */
si.teilnehmergruppensperre = teilnehmergruppensperre;
si.anzahl_gesperrter_teilnehmergruppen = anzahl_gesperrter_teilnehmergruppen;
si.meldeinterval = meldeinterval;
si.meldeaufrufe = meldeaufrufe;
}

View File

@ -1,6 +1,6 @@
typedef struct system_information {
uint8_t timeslot; /* timeslot to use */
uint32_t timeslots; /* timeslot map to use */
uint8_t fuz_nat; /* national network ID */
uint8_t fuz_fuvst; /* id of switching center */
uint8_t fuz_rest; /* rest of base station id */
@ -13,6 +13,7 @@ typedef struct system_information {
uint8_t entfernung;
uint8_t grenz_einbuchen;
uint8_t kennung_fufst; /* prio of base station */
uint8_t bahn_bs; /* special train base station */
uint8_t authentifikationsbit; /* base station suppoerts authentication */
uint8_t ws_kennung; /* queue setting sof base station */
uint8_t nachbar_prio;
@ -20,9 +21,11 @@ typedef struct system_information {
uint8_t reduzierung;
int8_t teilnehmergruppensperre;
int8_t anzahl_gesperrter_teilnehmergruppen;
int meldeinterval; /* when to retry availability check */
int meldeaufrufe; /* 0 for infinite */
} cnetz_si;
extern cnetz_si si;
void init_sysinfo(uint8_t timeslot, uint8_t fuz_nat, uint8_t fuz_fuvst, uint8_t fuz_rest, uint8_t kennung_fufst, uint8_t authentifikationsbit, uint8_t ws_kennung, uint8_t vermittlungstechnische_sperren, uint8_t grenz_einbuchen, uint8_t grenz_umschalten, uint8_t grenz_ausloesen, uint8_t mittel_umschalten, uint8_t mittel_ausloesen, uint8_t genauigkeit, uint8_t bewertung, uint8_t entfernung, uint8_t reduzierung, uint8_t nachbar_prio, int8_t teilnehmergruppensperre, uint8_t anzahl_gesperrter_teilnehmergruppen);
void init_sysinfo(uint32_t timeslots, uint8_t fuz_nat, uint8_t fuz_fuvst, uint8_t fuz_rest, uint8_t kennung_fufst, uint8_t bahn_bs, uint8_t authentifikationsbit, uint8_t ws_kennung, uint8_t vermittlungstechnische_sperren, uint8_t grenz_einbuchen, uint8_t grenz_umschalten, uint8_t grenz_ausloesen, uint8_t mittel_umschalten, uint8_t mittel_ausloesen, uint8_t genauigkeit, uint8_t bewertung, uint8_t entfernung, uint8_t reduzierung, uint8_t nachbar_prio, int8_t teilnehmergruppensperre, uint8_t anzahl_gesperrter_teilnehmergruppen, int meldeinterval, int meldeaufrufe);

View File

@ -27,7 +27,7 @@
#include <errno.h>
#include <math.h>
#include "../libsample/sample.h"
#include "../libdebug/debug.h"
#include "../liblogging/logging.h"
#include "cnetz.h"
#include "dsp.h"
#include "sysinfo.h"
@ -510,13 +510,13 @@ static int encode_dialstring(uint64_t *value, const char *number)
max = strlen(number);
if (max > 16) {
PDEBUG(DFRAME, DEBUG_NOTICE, "Given number '%s' has more than 16 digits\n", number);
LOGP(DFRAME, LOGL_NOTICE, "Given number '%s' has more than 16 digits\n", number);
return -EINVAL;
}
if (max == 16) {
if (number[0] != '0') {
PDEBUG(DFRAME, DEBUG_NOTICE, "Given 16 digit number '%s' does not start with '0'\n", number);
LOGP(DFRAME, LOGL_NOTICE, "Given 16 digit number '%s' does not start with '0'\n", number);
return -EINVAL;
}
*value = 0;
@ -575,7 +575,7 @@ int match_fuz(telegramm_t *telegramm)
if (telegramm->fuz_nationalitaet != si.fuz_nat
|| telegramm->fuz_fuvst_nr != si.fuz_fuvst
|| telegramm->fuz_rest_nr != si.fuz_rest) {
PDEBUG(DFRAME, DEBUG_NOTICE, "Ignoring message from mobile phone %d,%d,%d: Cell 'Funkzelle' does not match!\n", telegramm->futln_nationalitaet, telegramm->futln_heimat_fuvst_nr, telegramm->futln_rest_nr);
LOGP(DFRAME, LOGL_NOTICE, "Ignoring message from mobile phone %d,%d,%d: Cell 'Funkzelle' does not match!\n", telegramm->futln_nationalitaet, telegramm->futln_heimat_fuvst_nr, telegramm->futln_rest_nr);
return 0;
}
@ -587,7 +587,7 @@ int match_futln(telegramm_t *telegramm, uint8_t futln_nat, uint8_t futln_fuvst,
if (telegramm->futln_nationalitaet != futln_nat
|| telegramm->futln_heimat_fuvst_nr != futln_fuvst
|| telegramm->futln_rest_nr != futln_rest) {
PDEBUG(DFRAME, DEBUG_NOTICE, "Ignoring message from mobile phone %d,%d,%d: Mobile station 'Funktelefongeraet' does not match!\n", telegramm->futln_nationalitaet, telegramm->futln_heimat_fuvst_nr, telegramm->futln_rest_nr);
LOGP(DFRAME, LOGL_NOTICE, "Ignoring message from mobile phone %d,%d,%d: Mobile station 'Funktelefongeraet' does not match!\n", telegramm->futln_nationalitaet, telegramm->futln_heimat_fuvst_nr, telegramm->futln_rest_nr);
return 0;
}
@ -600,19 +600,19 @@ static void debug_parameter(char digit, uint64_t value)
parameter = get_parameter(digit);
if (!parameter) {
PDEBUG(DFRAME, DEBUG_ERROR, "Digit '%c' not found in definition_parameter list, please fix!\n", digit);
LOGP(DFRAME, LOGL_ERROR, "Digit '%c' not found in definition_parameter list, please fix!\n", digit);
abort();
}
if (parameter->value_names)
PDEBUG(DFRAME, DEBUG_DEBUG, " (%c) %s : %s\n", digit, parameter->param_name, parameter->value_names[value]);
LOGP(DFRAME, LOGL_DEBUG, " (%c) %s : %s\n", digit, parameter->param_name, parameter->value_names[value]);
else if (parameter->bits == 64)
PDEBUG(DFRAME, DEBUG_DEBUG, " (%c) %s : 0x%016" PRIx64 "\n", digit, parameter->param_name, value);
LOGP(DFRAME, LOGL_DEBUG, " (%c) %s : 0x%016" PRIx64 "\n", digit, parameter->param_name, value);
else if (digit == 'X') {
char wahlziffern[17];
decode_dialstring(wahlziffern, value);
PDEBUG(DFRAME, DEBUG_DEBUG, " (%c) %s : '%s'\n", digit, parameter->param_name, wahlziffern);
LOGP(DFRAME, LOGL_DEBUG, " (%c) %s : '%s'\n", digit, parameter->param_name, wahlziffern);
} else
PDEBUG(DFRAME, DEBUG_DEBUG, " (%c) %s : %" PRIu64 "\n", digit, parameter->param_name, value);
LOGP(DFRAME, LOGL_DEBUG, " (%c) %s : %" PRIu64 "\n", digit, parameter->param_name, value);
}
/* encode telegram to 70 bits
@ -628,11 +628,12 @@ static char *assemble_telegramm(const telegramm_t *telegramm, int debug)
int rc;
if (telegramm->opcode >= 64) {
PDEBUG(DFRAME, DEBUG_ERROR, "Opcode '0x%x' exceeds bit range, please fix!\n", telegramm->opcode);
LOGP(DFRAME, LOGL_ERROR, "Opcode '0x%x' exceeds bit range, please fix!\n", telegramm->opcode);
abort();
}
PDEBUG(DFRAME, DEBUG_DEBUG, "Coding %s %s\n", definition_opcode[telegramm->opcode].message_name, definition_opcode[telegramm->opcode].message_text);
if (debug)
LOGP(DFRAME, LOGL_INFO, "Coding %s %s\n", definition_opcode[telegramm->opcode].message_name, definition_opcode[telegramm->opcode].message_text);
/* copy opcode */
for (i = 0; i < 6; i++)
@ -716,7 +717,7 @@ static char *assemble_telegramm(const telegramm_t *telegramm, int debug)
case 'X':
rc = encode_dialstring(&value, telegramm->wahlziffern);
if (rc < 0) {
PDEBUG(DFRAME, DEBUG_ERROR, "Illegal dial string '%s', please fix!\n", telegramm->wahlziffern);
LOGP(DFRAME, LOGL_ERROR, "Illegal dial string '%s', please fix!\n", telegramm->wahlziffern);
abort();
}
break;
@ -805,10 +806,10 @@ static char *assemble_telegramm(const telegramm_t *telegramm, int debug)
value = telegramm->illegaler_opcode;
break;
default:
PDEBUG(DFRAME, DEBUG_ERROR, "Parameter '%c' does not exist, please fix!\n", parameter);
LOGP(DFRAME, LOGL_ERROR, "Parameter '%c' does not exist, please fix!\n", parameter);
abort();
}
if (debug && debuglevel <= DEBUG_DEBUG)
if (debug && loglevel <= LOGL_DEBUG)
debug_parameter(parameter, value);
val = value;
for (j = 0; string[63 - i - j] == parameter; j++) {
@ -816,14 +817,14 @@ static char *assemble_telegramm(const telegramm_t *telegramm, int debug)
val >>= 1;
}
if (val)
PDEBUG(DFRAME, DEBUG_ERROR, "Parameter '%c' value '0x%" PRIx64 "' exceeds bit range!\n", parameter, value);
LOGP(DFRAME, LOGL_ERROR, "Parameter '%c' value '0x%" PRIx64 "' exceeds bit range!\n", parameter, value);
i += j - 1;
}
bits[70] = '\0';
if (debug) {
PDEBUG(DFRAME, DEBUG_DEBUG, "OOOOOO%s\n", string);
PDEBUG(DFRAME, DEBUG_DEBUG, "%s\n", bits);
LOGP(DFRAME, LOGL_DEBUG, "OOOOOO%s\n", string);
LOGP(DFRAME, LOGL_DEBUG, "%s\n", bits);
}
return bits;
@ -847,7 +848,7 @@ static void disassemble_telegramm(telegramm_t *telegramm, const char *bits, int
value = (value << 1) | (bits[i] == '1');
telegramm->opcode = value;
PDEBUG(DFRAME, DEBUG_DEBUG, "Decoding %s %s\n", definition_opcode[telegramm->opcode].message_name, definition_opcode[telegramm->opcode].message_text);
LOGP(DFRAME, LOGL_INFO, "Decoding %s %s\n", definition_opcode[telegramm->opcode].message_name, definition_opcode[telegramm->opcode].message_text);
/* copy parameters */
if (auth && bits[1]) /* auth flag and chip card flag */
@ -863,7 +864,7 @@ static void disassemble_telegramm(telegramm_t *telegramm, const char *bits, int
value = (value >> 1) | ((uint64_t)(bits[69 - i - j] == '1') << 63);
value >>= 64 - j;
i += j - 1;
if (debuglevel <= DEBUG_DEBUG)
if (loglevel <= LOGL_DEBUG)
debug_parameter(parameter, value);
switch (parameter) {
case 'A':
@ -1020,18 +1021,18 @@ static void disassemble_telegramm(telegramm_t *telegramm, const char *bits, int
telegramm->illegaler_opcode = value;
break;
default:
PDEBUG(DFRAME, DEBUG_ERROR, "Parameter '%c' does not exist, please fix!\n", parameter);
LOGP(DFRAME, LOGL_ERROR, "Parameter '%c' does not exist, please fix!\n", parameter);
abort();
}
}
if (debuglevel <= DEBUG_DEBUG) {
if (loglevel <= LOGL_DEBUG) {
char debug_bits[71];
memcpy(debug_bits, bits, 70);
debug_bits[70] = '\0';
PDEBUG(DFRAME, DEBUG_DEBUG, "OOOOOO%s\n", string);
PDEBUG(DFRAME, DEBUG_DEBUG, "%s\n", debug_bits);
LOGP(DFRAME, LOGL_DEBUG, "OOOOOO%s\n", string);
LOGP(DFRAME, LOGL_DEBUG, "%s\n", debug_bits);
}
}
@ -1391,11 +1392,11 @@ static const char *decode(const char *input, int *_bit_errors)
fail_str[10] = '\0';
if (failed)
PDEBUG(DFRAME, DEBUG_DEBUG, "Received Telegram with these block errors: '%s' (X = uncorrectable)\n", fail_str);
LOGP(DFRAME, LOGL_DEBUG, "Received Telegram with these block errors: '%s' (X = uncorrectable)\n", fail_str);
else if (warn)
PDEBUG(DFRAME, DEBUG_DEBUG, "Received Telegram with these block errors: '%s' (1 / 2 = correctable)\n", fail_str);
LOGP(DFRAME, LOGL_DEBUG, "Received Telegram with these block errors: '%s' (1 / 2 = correctable)\n", fail_str);
else
PDEBUG(DFRAME, DEBUG_DEBUG, "Received Telegram with no block errors.\n");
LOGP(DFRAME, LOGL_DEBUG, "Received Telegram with no block errors.\n");
if (failed)
return NULL;
@ -1495,14 +1496,13 @@ void cnetz_decode_telegramm(cnetz_t *cnetz, const char *bits, double level, doub
break;
}
if (i == 70) {
PDEBUG(DFRAME, DEBUG_INFO, "Ignoring mysterious unmodulated telegramm (noise from phone's transmitter)\n");
LOGP(DFRAME, LOGL_INFO, "Ignoring mysterious unmodulated telegramm (noise from phone's transmitter)\n");
return;
}
LOGP_CHAN(DDSP, LOGL_INFO, "RF level: %.1f dB RX Level: %.0f%% Standard deviation: %.0f%% Sync Time: %.2f (TS %.2f) %s\n", cnetz->rf_level_db, fabs(level) / cnetz->fsk_deviation * 100.0, stddev / fabs(level) * 100.0, sync_time, sync_time / 396.0, (level < 0) ? "NEGATIVE (phone's mode)" : "POSITIVE (base station's mode)");
if (bit_errors)
PDEBUG_CHAN(DDSP, DEBUG_INFO, "RX Level: %.0f%% Standard deviation: %.0f%% Sync Time: %.2f (TS %.2f) Bit errors: %d %s\n", fabs(level) / cnetz->fsk_deviation * 100.0, stddev / fabs(level) * 100.0, sync_time, sync_time / 396.0, bit_errors, (level < 0) ? "NEGATIVE (phone's mode)" : "POSITIVE (base station's mode)");
else
PDEBUG_CHAN(DDSP, DEBUG_INFO, "RX Level: %.0f%% Standard deviation: %.0f%% Sync Time: %.2f (TS %.2f) %s\n", fabs(level) / cnetz->fsk_deviation * 100.0, stddev / fabs(level) * 100.0, sync_time, sync_time / 396.0, (level < 0) ? "NEGATIVE (phone's mode)" : "POSITIVE (base station's mode)");
LOGP_CHAN(DDSP, LOGL_INFO, " -> Frame has %d bit errors.\n", bit_errors);
disassemble_telegramm(&telegramm, bits, si.authentifikationsbit);
opcode = telegramm.opcode;
@ -1510,18 +1510,18 @@ void cnetz_decode_telegramm(cnetz_t *cnetz, const char *bits, double level, doub
telegramm.sync_time = sync_time;
if (cnetz->sender.loopback) {
PDEBUG(DFRAME, DEBUG_NOTICE, "Received Telegramm in loopback test mode (opcode %d = %s)\n", opcode, definition_opcode[opcode].message_name);
LOGP(DFRAME, LOGL_NOTICE, "Received Telegramm in loopback test mode (opcode %d = %s)\n", opcode, definition_opcode[opcode].message_name);
cnetz_sync_frame(cnetz, sync_time, -1);
return;
}
if (opcode >= 32) {
PDEBUG(DFRAME, DEBUG_NOTICE, "Received Telegramm that is not used by mobile station, ignoring! (opcode %d = %s)\n", opcode, definition_opcode[opcode].message_name);
LOGP(DFRAME, LOGL_NOTICE, "Received Telegramm that is not used by mobile station, ignoring! (opcode %d = %s)\n", opcode, definition_opcode[opcode].message_name);
return;
}
if (definition_opcode[opcode].block == BLOCK_I) {
PDEBUG(DFRAME, DEBUG_NOTICE, "Received Telegramm that is an illegal opcode, ignoring! (opcode %d = %s)\n", opcode, definition_opcode[opcode].message_name);
LOGP(DFRAME, LOGL_NOTICE, "Received Telegramm that is an illegal opcode, ignoring! (opcode %d = %s)\n", opcode, definition_opcode[opcode].message_name);
return;
}
@ -1544,7 +1544,7 @@ void cnetz_decode_telegramm(cnetz_t *cnetz, const char *bits, double level, doub
switch (cnetz->dsp_mode) {
case DSP_MODE_OGK:
if (definition_opcode[opcode].block != BLOCK_R && definition_opcode[opcode].block != BLOCK_M) {
PDEBUG(DFRAME, DEBUG_NOTICE, "Received Telegramm that is not used OgK channel signaling, ignoring! (opcode %d = %s)\n", opcode, definition_opcode[opcode].message_name);
LOGP(DFRAME, LOGL_NOTICE, "Received Telegramm that is not used OgK channel signaling, ignoring! (opcode %d = %s)\n", opcode, definition_opcode[opcode].message_name);
return;
}
/* determine block by last timeslot sent and by message type
@ -1557,14 +1557,14 @@ void cnetz_decode_telegramm(cnetz_t *cnetz, const char *bits, double level, doub
break;
case DSP_MODE_SPK_K:
if (definition_opcode[opcode].block != BLOCK_K) {
PDEBUG(DFRAME, DEBUG_NOTICE, "Received Telegramm that is not used for concentrated signaling, ignoring! (opcode %d = %s)\n", opcode, definition_opcode[opcode].message_name);
LOGP(DFRAME, LOGL_NOTICE, "Received Telegramm that is not used for concentrated signaling, ignoring! (opcode %d = %s)\n", opcode, definition_opcode[opcode].message_name);
return;
}
cnetz_receive_telegramm_spk_k(cnetz, &telegramm);
break;
case DSP_MODE_SPK_V:
if (definition_opcode[opcode].block != BLOCK_V) {
PDEBUG(DFRAME, DEBUG_NOTICE, "Received Telegramm that is not used for distributed signaling, ignoring! (opcode %d = %s)\n", opcode, definition_opcode[opcode].message_name);
LOGP(DFRAME, LOGL_NOTICE, "Received Telegramm that is not used for distributed signaling, ignoring! (opcode %d = %s)\n", opcode, definition_opcode[opcode].message_name);
return;
}
cnetz_receive_telegramm_spk_v(cnetz, &telegramm);
@ -1579,6 +1579,7 @@ const char *cnetz_encode_telegramm(cnetz_t *cnetz)
const telegramm_t *telegramm = NULL;
uint8_t opcode;
char *bits;
int debug = 1;
switch (cnetz->dsp_mode) {
case DSP_MODE_OGK:
@ -1601,7 +1602,11 @@ const char *cnetz_encode_telegramm(cnetz_t *cnetz)
return NULL;
opcode = telegramm->opcode;
bits = assemble_telegramm(telegramm, (opcode != OPCODE_LR_R) && (opcode != OPCODE_MLR_M));
if (opcode == OPCODE_LR_R && cnetz->sched_lr_debugged)
debug = 0;
if (opcode == OPCODE_MLR_M && cnetz->sched_mlr_debugged)
debug = 0;
bits = assemble_telegramm(telegramm, debug);
bits = encode(bits);
bits = interleave(bits);
@ -1613,6 +1618,13 @@ const char *cnetz_encode_telegramm(cnetz_t *cnetz)
bits[i] ^= 1;
}
if (opcode == OPCODE_LR_R && !cnetz->sched_lr_debugged)
cnetz->sched_lr_debugged = 1;
if (opcode == OPCODE_MLR_M && !cnetz->sched_mlr_debugged) {
cnetz->sched_mlr_debugged = 1;
LOGP(DFRAME, LOGL_INFO, "Subsequent IDLE frames are not show, to prevent flooding the output.\n");
}
return bits;
}

View File

@ -20,14 +20,17 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <math.h>
#include "../libsample/sample.h"
#include "../libdebug/debug.h"
#include "../liblogging/logging.h"
#include "../libmobile/call.h"
#include "../libmobile/cause.h"
#include "cnetz.h"
#include "telegramm.h"
#include "database.h"
static int new_cueue_position = 0;
const char *transaction2rufnummer(transaction_t *trans)
{
static char rufnummer[32]; /* make GCC happy (overflow check) */
@ -38,25 +41,35 @@ const char *transaction2rufnummer(transaction_t *trans)
}
/* create transaction */
transaction_t *create_transaction(cnetz_t *cnetz, uint64_t state, uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int futelg_bit, int extended)
transaction_t *create_transaction(cnetz_t *cnetz, uint64_t state, uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int futelg_bit, int extended, double rf_level_db)
{
sender_t *sender;
transaction_t *trans = NULL;
cnetz_t *search_cnetz;
transaction_t *trans;
/* search transaction for this subscriber */
for (sender = sender_head; sender; sender = sender->next) {
search_cnetz = (cnetz_t *) sender;
/* search transaction for this callref */
trans = search_transaction_number(search_cnetz, futln_nat, futln_fuvst, futln_rest);
if (trans)
break;
}
trans = search_transaction_number_global(futln_nat, futln_fuvst, futln_rest);
if (trans) {
const char *rufnummer = transaction2rufnummer(trans);
int old_callref = trans->callref;
cnetz_t *old_cnetz = trans->cnetz;
PDEBUG(DTRANS, DEBUG_NOTICE, "Found already pending transaction for subscriber '%s', deleting!\n", rufnummer);
/* both states must be the same and one of the give selection */
if ((trans->state & state & (TRANS_EM | TRANS_UM | TRANS_VWG | TRANS_ATQ_IDLE))) {
if (!isnan(trans->rf_level_db) && !isnan(rf_level_db) && trans->cnetz->kanal != cnetz->kanal) {
if (rf_level_db > trans->rf_level_db) {
LOGP(DTRANS, LOGL_NOTICE, "Found already pending transaction for subscriber '%s' on channel #%d, but this message on channel #%d is stronger, so we move to that channel!\n", rufnummer, trans->cnetz->kanal, cnetz->kanal);
trans->rf_level_db = rf_level_db;
unlink_transaction(trans);
link_transaction(trans, cnetz);
update_db(trans->futln_nat, trans->futln_fuvst, trans->futln_rest, cnetz->kanal, NULL, NULL, 1, 0);
return trans;
}
if (rf_level_db < trans->rf_level_db) {
LOGP(DTRANS, LOGL_NOTICE, "Found already pending transaction for subscriber '%s' on channel #%d, but this message on channel #%d is weaker, so we ignore that channel!\n", rufnummer, trans->cnetz->kanal, cnetz->kanal);
return trans;
}
}
LOGP(DTRANS, LOGL_NOTICE, "Found already pending transaction for subscriber '%s' on channel #%d, but this message on channel #%d is also received. Try to avoid multiple OgK channels!\n", rufnummer, trans->cnetz->kanal, cnetz->kanal);
return trans;
}
LOGP(DTRANS, LOGL_NOTICE, "Found already pending transaction for subscriber '%s', deleting!\n", rufnummer);
destroy_transaction(trans);
if (old_cnetz) /* should be... */
cnetz_go_idle(old_cnetz);
@ -66,11 +79,11 @@ transaction_t *create_transaction(cnetz_t *cnetz, uint64_t state, uint8_t futln_
trans = calloc(1, sizeof(*trans));
if (!trans) {
PDEBUG(DTRANS, DEBUG_ERROR, "No memory!\n");
LOGP(DTRANS, LOGL_ERROR, "No memory!\n");
return NULL;
}
timer_init(&trans->timer, transaction_timeout, trans);
osmo_timer_setup(&trans->timer, transaction_timeout, trans);
trans_new_state(trans, state);
trans->futln_nat = futln_nat;
@ -83,15 +96,17 @@ transaction_t *create_transaction(cnetz_t *cnetz, uint64_t state, uint8_t futln_
trans->mt_call = 1;
const char *rufnummer = transaction2rufnummer(trans);
PDEBUG(DTRANS, DEBUG_INFO, "Created transaction for subscriber '%s'\n", rufnummer);
LOGP(DTRANS, LOGL_INFO, "Created transaction for subscriber '%s'\n", rufnummer);
link_transaction(trans, cnetz);
/* update database: now busy */
update_db(cnetz, futln_nat, futln_fuvst, futln_rest, &futelg_bit, &extended, 1, 0);
update_db(futln_nat, futln_fuvst, futln_rest, cnetz->kanal, &futelg_bit, &extended, 1, 0);
trans->futelg_bit = futelg_bit;
trans->extended = extended;
trans->rf_level_db = rf_level_db;
return trans;
}
@ -99,14 +114,14 @@ transaction_t *create_transaction(cnetz_t *cnetz, uint64_t state, uint8_t futln_
void destroy_transaction(transaction_t *trans)
{
/* update database: now idle */
update_db(trans->cnetz, trans->futln_nat, trans->futln_fuvst, trans->futln_rest, NULL, NULL, 0, trans->page_failed);
update_db(trans->futln_nat, trans->futln_fuvst, trans->futln_rest, 0, NULL, NULL, 0, trans->page_failed);
unlink_transaction(trans);
const char *rufnummer = transaction2rufnummer(trans);
PDEBUG(DTRANS, DEBUG_INFO, "Destroying transaction for subscriber '%s'\n", rufnummer);
LOGP(DTRANS, LOGL_INFO, "Destroying transaction for subscriber '%s'\n", rufnummer);
timer_exit(&trans->timer);
osmo_timer_del(&trans->timer);
trans_new_state(trans, 0);
@ -119,7 +134,7 @@ void link_transaction(transaction_t *trans, cnetz_t *cnetz)
transaction_t **transp;
/* attach to end of list, so first transaction is served first */
PDEBUG(DTRANS, DEBUG_DEBUG, "Linking transaction %p to cnetz %p\n", trans, cnetz);
LOGP(DTRANS, LOGL_DEBUG, "Linking transaction %p to cnetz %p\n", trans, cnetz);
trans->cnetz = cnetz;
trans->next = NULL;
transp = &cnetz->trans_list;
@ -135,12 +150,12 @@ void unlink_transaction(transaction_t *trans)
transaction_t **transp;
/* unlink */
PDEBUG(DTRANS, DEBUG_DEBUG, "Unlinking transaction %p from cnetz %p\n", trans, trans->cnetz);
LOGP(DTRANS, LOGL_DEBUG, "Unlinking transaction %p from cnetz %p\n", trans, trans->cnetz);
transp = &trans->cnetz->trans_list;
while (*transp && *transp != trans)
transp = &((*transp)->next);
if (!(*transp)) {
PDEBUG(DTRANS, DEBUG_ERROR, "Transaction not in list, please fix!!\n");
LOGP(DTRANS, LOGL_ERROR, "Transaction not in list, please fix!!\n");
abort();
}
*transp = trans->next;
@ -155,7 +170,7 @@ transaction_t *search_transaction(cnetz_t *cnetz, uint64_t state_mask)
while (trans) {
if ((trans->state & state_mask)) {
const char *rufnummer = transaction2rufnummer(trans);
PDEBUG(DTRANS, DEBUG_DEBUG, "Found transaction for subscriber '%s'\n", rufnummer);
LOGP(DTRANS, LOGL_DEBUG, "Found transaction for subscriber '%s'\n", rufnummer);
return trans;
}
trans = trans->next;
@ -173,7 +188,7 @@ transaction_t *search_transaction_number(cnetz_t *cnetz, uint8_t futln_nat, uint
&& trans->futln_fuvst == futln_fuvst
&& trans->futln_rest == futln_rest) {
const char *rufnummer = transaction2rufnummer(trans);
PDEBUG(DTRANS, DEBUG_DEBUG, "Found transaction for subscriber '%s'\n", rufnummer);
LOGP(DTRANS, LOGL_DEBUG, "Found transaction for subscriber '%s'\n", rufnummer);
return trans;
}
trans = trans->next;
@ -182,6 +197,23 @@ transaction_t *search_transaction_number(cnetz_t *cnetz, uint8_t futln_nat, uint
return NULL;
}
transaction_t *search_transaction_number_global(uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest)
{
sender_t *sender;
cnetz_t *cnetz;
transaction_t *trans = NULL;
/* search transaction for this subscriber */
for (sender = sender_head; sender; sender = sender->next) {
cnetz = (cnetz_t *) sender;
/* search transaction for this callref */
trans = search_transaction_number(cnetz, futln_nat, futln_fuvst, futln_rest);
if (trans)
break;
}
return trans;
}
transaction_t *search_transaction_callref(cnetz_t *cnetz, int callref)
{
transaction_t *trans = cnetz->trans_list;
@ -192,7 +224,7 @@ transaction_t *search_transaction_callref(cnetz_t *cnetz, int callref)
while (trans) {
if (trans->callref == callref) {
const char *rufnummer = transaction2rufnummer(trans);
PDEBUG(DTRANS, DEBUG_DEBUG, "Found transaction for subscriber '%s'\n", rufnummer);
LOGP(DTRANS, LOGL_DEBUG, "Found transaction for subscriber '%s'\n", rufnummer);
return trans;
}
trans = trans->next;
@ -201,6 +233,42 @@ transaction_t *search_transaction_callref(cnetz_t *cnetz, int callref)
return NULL;
}
/* get oldest transaction in queue:
*
* oldest means that the queue number is the smallest.
* all candidates (transactions) must be in queue state.
*/
transaction_t *search_transaction_queue(void)
{
sender_t *sender;
transaction_t *trans, *found = NULL;
cnetz_t *cnetz;
int queue_max = 0;
for (sender = sender_head; sender; sender = sender->next) {
cnetz = (cnetz_t *) sender;
trans = cnetz->trans_list;
while (trans) {
if ((trans->state & (TRANS_MO_QUEUE | TRANS_MT_QUEUE))) {
/* select if first or lower number */
if (!found || trans->queue_position < queue_max) {
queue_max = trans->queue_position;
found = trans;
}
}
trans = trans->next;
}
}
if (found) {
const char *rufnummer = transaction2rufnummer(found);
LOGP(DTRANS, LOGL_DEBUG, "Found oldest transaction in queue for subscriber '%s'\n", rufnummer);
return found;
}
return NULL;
}
static const char *trans_state_name(uint64_t state)
{
switch (state) {
@ -252,6 +320,8 @@ static const char *trans_state_name(uint64_t state)
return "AT";
case TRANS_ATQ:
return "ATQ";
case TRANS_ATQ_IDLE:
return "ATQ_IDLE";
case TRANS_MO_QUEUE:
return "MO_QUEUE";
case TRANS_MT_QUEUE:
@ -301,6 +371,7 @@ const char *trans_short_state_name(uint64_t state)
case TRANS_AF:
case TRANS_AT:
case TRANS_ATQ:
case TRANS_ATQ_IDLE:
return "RELEASE";
case TRANS_MO_QUEUE:
case TRANS_MO_DELAY:
@ -315,8 +386,11 @@ const char *trans_short_state_name(uint64_t state)
void trans_new_state(transaction_t *trans, uint64_t state)
{
PDEBUG(DTRANS, DEBUG_INFO, "Transaction (%s) state %s -> %s\n", transaction2rufnummer(trans), trans_state_name(trans->state), trans_state_name(state));
LOGP(DTRANS, LOGL_INFO, "Transaction (%s) state %s -> %s\n", transaction2rufnummer(trans), trans_state_name(trans->state), trans_state_name(state));
trans->state = state;
/* in case of a queue, set new positon */
if (!trans->queue_position && (state == TRANS_MO_QUEUE || state == TRANS_MT_QUEUE))
trans->queue_position = ++new_cueue_position;
cnetz_display_status();
}
@ -324,12 +398,12 @@ void cnetz_flush_other_transactions(cnetz_t *cnetz, transaction_t *trans)
{
/* flush after this very trans */
while (trans->next) {
PDEBUG(DTRANS, DEBUG_NOTICE, "Kicking other pending transaction\n");
LOGP(DTRANS, LOGL_NOTICE, "Kicking other pending transaction\n");
destroy_transaction(trans->next);
}
/* flush before this very trans */
while (cnetz->trans_list != trans) {
PDEBUG(DTRANS, DEBUG_NOTICE, "Kicking other pending transaction\n");
LOGP(DTRANS, LOGL_NOTICE, "Kicking other pending transaction\n");
destroy_transaction(cnetz->trans_list);
}
}

View File

@ -29,11 +29,12 @@
#define TRANS_AF (1 << 20) /* release connection by base station (SpK) */
#define TRANS_AT (1 << 21) /* release connection by mobile station */
#define TRANS_ATQ (1 << 22) /* acknowledge release of MO call in queue */
#define TRANS_ATQ_IDLE (1 << 23) /* repeat, if call has been released already (mobile sends again) */
/* queue */
#define TRANS_MO_QUEUE (1 << 23) /* MO queue */
#define TRANS_MT_QUEUE (1 << 24) /* MT queue */
#define TRANS_MO_DELAY (1 << 25) /* delay to be sure the channel is free again */
#define TRANS_MT_DELAY (1 << 26)
#define TRANS_MO_QUEUE (1 << 24) /* MO queue */
#define TRANS_MT_QUEUE (1 << 25) /* MT queue */
#define TRANS_MO_DELAY (1 << 26) /* delay to be sure the channel is free again */
#define TRANS_MT_DELAY (1 << 27)
typedef struct transaction {
struct transaction *next; /* pointer to next node in list */
@ -49,23 +50,29 @@ typedef struct transaction {
int8_t release_cause; /* reason for release, (c-netz coding) */
int try; /* counts resending messages */
int repeat; /* counts repeating messages */
struct timer timer; /* for varous timeouts */
struct osmo_timer_list timer; /* for varous timeouts */
int mo_call; /* flags a moile originating call */
int mt_call; /* flags a moile terminating call */
int page_failed; /* failed to get a response from MS */
double call_start; /* when did the call start? (used for metering) */
double metering_time; /* time between units (0.0 if no metering set) */
double meter_start; /* when did the metering start? (0.0 if not yet started) */
double meter_end; /* when did the metering end? (0.0 if not yet ended) */
int queue_position; /* to find next transaction in queue */
double rf_level_db; /* level of first contact, so we can detect correct channel at multiple receptions */
} transaction_t;
const char *transaction2rufnummer(transaction_t *trans);
transaction_t *create_transaction(cnetz_t *cnetz, uint64_t state, uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int futelg_bit, int extended);
transaction_t *create_transaction(cnetz_t *cnetz, uint64_t state, uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int futelg_bit, int extended, double rf_level_db);
void destroy_transaction(transaction_t *trans);
void link_transaction(transaction_t *trans, cnetz_t *cnetz);
void unlink_transaction(transaction_t *trans);
transaction_t *search_transaction(cnetz_t *cnetz, uint64_t state_mask);
transaction_t *search_transaction_number(cnetz_t *cnetz, uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest);
transaction_t *search_transaction_number_global(uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest);
transaction_t *search_transaction_callref(cnetz_t *cnetz, int callref);
transaction_t *search_transaction_queue(void);
void trans_new_state(transaction_t *trans, uint64_t state);
void cnetz_flush_other_transactions(cnetz_t *cnetz, transaction_t *trans);
void transaction_timeout(struct timer *timer);
void transaction_timeout(void *data);
const char *trans_short_state_name(uint64_t state);

View File

@ -1,4 +1,5 @@
AM_CPPFLAGS = -Wall -Wextra -g $(all_includes) $(FUSE_CFLAGS)
AM_CPPFLAGS = -Wall -Wextra -Wmissing-prototypes -g $(all_includes) \
$(FUSE_CFLAGS)
bin_PROGRAMS = \
datenklo
@ -12,15 +13,15 @@ datenklo_SOURCES = \
datenklo_LDADD = \
$(COMMON_LA) \
$(top_builddir)/src/liboptions/liboptions.a \
$(top_builddir)/src/libdebug/libdebug.a \
$(top_builddir)/src/libfsk/libfsk.a \
$(top_builddir)/src/libtimer/libtimer.a \
$(top_builddir)/src/libfm/libfm.a \
$(top_builddir)/src/libfilter/libfilter.a \
$(top_builddir)/src/libsound/libsound.a \
$(top_builddir)/src/libwave/libwave.a \
$(top_builddir)/src/libdisplay/libdisplay.a \
$(top_builddir)/src/libsample/libsample.a \
$(top_builddir)/src/liblogging/liblogging.a \
$(LIBOSMOCORE_LIBS) \
$(ALSA_LIBS) \
$(FUSE_LIBS) \
-lm

View File

@ -75,12 +75,14 @@
#include <string.h>
#include <errno.h>
#include <math.h>
#include "../libdebug/debug.h"
#include "../libtimer/timer.h"
#include "../liblogging/logging.h"
#include <osmocom/core/timer.h>
#include "../libsample/sample.h"
#include "../libfsk/fsk.h"
#include "am791x.h"
#define FLOAT_TO_TIMEOUT(f) floor(f), ((f) - floor(f)) * 1000000
#define db2level(db) pow(10, (double)(db) / 20.0)
#define level2db(level) (20 * log10(level))
@ -298,13 +300,13 @@ void am791x_list_mc(enum am791x_type type)
}
/* init STO signal */
void init_sto(am791x_t *am791x)
static void init_sto(am791x_t *am791x)
{
am791x->sto_phaseshift65536 = 900 / (double)am791x->samplerate * 65536.0;
}
/* transmit STO signal, use phase from FSK modulator, to avoid phase jumps */
int send_sto(am791x_t *am791x, sample_t *sample, int length)
static int send_sto(am791x_t *am791x, sample_t *sample, int length)
{
fsk_mod_t *fsk = &am791x->fsk_tx;
int count = 0;
@ -314,7 +316,7 @@ int send_sto(am791x_t *am791x, sample_t *sample, int length)
/* modulate STO */
phaseshift = am791x->sto_phaseshift65536;
while (count < length && fsk->tx_bitpos < 1.0) {
while (count < length) {
sample[count++] = fsk->sin_tab[(uint16_t)phase];
phase += phaseshift;
if (phase >= 65536.0)
@ -373,19 +375,19 @@ static int fsk_send_bit(void *inst)
/* main channel returns TD */
if (!am791x->block_td) {
#ifdef HEAVY_DEBUG
PDEBUG(DDSP, DEBUG_DEBUG, "Modulating bit '%d' for MAIN channel\n", bit);
LOGP(DDSP, LOGL_DEBUG, "Modulating bit '%d' for MAIN channel\n", bit);
#endif
return bit;
}
/* back channel returns BTD */
if (!am791x->block_btd) {
#ifdef HEAVY_DEBUG
PDEBUG(DDSP, DEBUG_DEBUG, "Modulating bit '%d' for BACK channel\n", bbit);
LOGP(DDSP, LOGL_DEBUG, "Modulating bit '%d' for BACK channel\n", bbit);
#endif
return bbit;
}
#ifdef HEAVY_DEBUG
PDEBUG(DDSP, DEBUG_DEBUG, "Modulating bit '1', because TD & BTD is ignored\n");
LOGP(DDSP, LOGL_DEBUG, "Modulating bit '1', because TD & BTD is ignored\n");
#endif
return 1;
}
@ -399,7 +401,7 @@ static void fsk_receive_bit(void *inst, int bit, double quality, double level)
int *block, *cd;
#ifdef HEAVY_DEBUG
PDEBUG(DDSP, DEBUG_DEBUG, "Demodulated bit '%d' (level = %.0f dBm, quality = %%%.0f)\n", bit, level2db(level), quality * 100.0);
LOGP(DDSP, LOGL_DEBUG, "Demodulated bit '%d' (level = %.0f dBm, quality = %%%.0f)\n", bit, level2db(level), quality * 100.0);
#endif
if (!am791x->rx_back_channel) {
@ -416,12 +418,12 @@ static void fsk_receive_bit(void *inst, int bit, double quality, double level)
handle_rx_state(am791x);
} else
if (!(*block) && !(*cd) && level > am791x->cd_on && quality >= RX_QUALITY) {
PDEBUG(DDSP, DEBUG_DEBUG, "Good quality (level = %.0f dBm, quality = %%%.0f)\n", level2db(level), quality * 100.0);
LOGP(DDSP, LOGL_DEBUG, "Good quality (level = %.0f dBm, quality = %%%.0f)\n", level2db(level), quality * 100.0);
*cd = 1;
handle_rx_state(am791x);
} else
if (*cd && (level < am791x->cd_off || quality < RX_QUALITY)) {
PDEBUG(DDSP, DEBUG_DEBUG, "Bad quality (level = %.0f dBm, quality = %%%.0f)\n", level2db(level), quality * 100.0);
LOGP(DDSP, LOGL_DEBUG, "Bad quality (level = %.0f dBm, quality = %%%.0f)\n", level2db(level), quality * 100.0);
*cd = 0;
handle_rx_state(am791x);
}
@ -437,24 +439,24 @@ static void fsk_receive_bit(void *inst, int bit, double quality, double level)
/* main channel forwards bit to RD */
if (!am791x->block_rd) {
#ifdef HEAVY_DEBUG
PDEBUG(DDSP, DEBUG_DEBUG, " -> Forwarding bit '%d' to MAIN channel\n", bit);
LOGP(DDSP, LOGL_DEBUG, " -> Forwarding bit '%d' to MAIN channel\n", bit);
#endif
am791x->rd_cb(am791x->inst, bit, quality * 100.0, level2db(level));
} else {
#ifdef HEAVY_DEBUG
PDEBUG(DDSP, DEBUG_DEBUG, " -> Forwarding bit '1' to MAIN channel, because RD is set to MARK\n");
LOGP(DDSP, LOGL_DEBUG, " -> Forwarding bit '1' to MAIN channel, because RD is set to MARK\n");
#endif
am791x->rd_cb(am791x->inst, 1, NAN, NAN);
}
/* main channel forwards bit to RD */
if (!am791x->block_brd) {
#ifdef HEAVY_DEBUG
PDEBUG(DDSP, DEBUG_DEBUG, " -> Forwarding bit '%d' to BACK channel\n", bit);
LOGP(DDSP, LOGL_DEBUG, " -> Forwarding bit '%d' to BACK channel\n", bit);
#endif
am791x->brd_cb(am791x->inst, bit, quality * 100.0, level2db(level));
} else {
#ifdef HEAVY_DEBUG
PDEBUG(DDSP, DEBUG_DEBUG, " -> Forwarding bit '1' to BACK channel, because BRD is set to MARK\n");
LOGP(DDSP, LOGL_DEBUG, " -> Forwarding bit '1' to BACK channel, because BRD is set to MARK\n");
#endif
am791x->brd_cb(am791x->inst, 1, NAN, NAN);
}
@ -529,9 +531,9 @@ static void set_filters(am791x_t *am791x)
/* transmitter used */
if (f0_tx > 0 && am791x->f0_tx == 0) {
PDEBUG(DDSP, DEBUG_DEBUG, "Setting modulator to %s channel's frequencies (F0 = %d, F1 = %d), baudrate %.0f\n", name_tx, f0_tx, f1_tx, am791x->tx_baud);
LOGP(DDSP, LOGL_DEBUG, "Setting modulator to %s channel's frequencies (F0 = %d, F1 = %d), baudrate %.0f\n", name_tx, f0_tx, f1_tx, am791x->tx_baud);
if (fsk_mod_init(&am791x->fsk_tx, am791x, fsk_send_bit, am791x->samplerate, am791x->tx_baud, (double)f0_tx, (double)f1_tx, am791x->tx_level, 0, 1) < 0)
PDEBUG(DDSP, DEBUG_ERROR, "FSK RX init failed!\n");
LOGP(DDSP, LOGL_ERROR, "FSK RX init failed!\n");
else {
am791x->f0_tx = f0_tx;
am791x->f1_tx = f1_tx;
@ -548,9 +550,9 @@ static void set_filters(am791x_t *am791x)
/* receiver used */
if (f0_rx > 0 && am791x->f0_rx == 0) {
PDEBUG(DDSP, DEBUG_DEBUG, "Setting demodulator to %s channel's frequencies (F0 = %d, F1 = %d), baudrate %.0f\n", name_rx, f0_rx, f1_rx, am791x->rx_baud);
LOGP(DDSP, LOGL_DEBUG, "Setting demodulator to %s channel's frequencies (F0 = %d, F1 = %d), baudrate %.0f\n", name_rx, f0_rx, f1_rx, am791x->rx_baud);
if (fsk_demod_init(&am791x->fsk_rx, am791x, fsk_receive_bit, am791x->samplerate, am791x->rx_baud, (double)f0_rx, (double)f1_rx, BIT_ADJUST) < 0)
PDEBUG(DDSP, DEBUG_ERROR, "FSK RX init failed!\n");
LOGP(DDSP, LOGL_ERROR, "FSK RX init failed!\n");
else {
am791x->f0_rx = f0_rx;
am791x->f1_rx = f1_rx;
@ -562,14 +564,14 @@ static void set_filters(am791x_t *am791x)
static void new_tx_state(am791x_t *am791x, enum am791x_st state)
{
if (am791x->tx_state != state)
PDEBUG(DAM791X, DEBUG_DEBUG, "Change TX state %s -> %s\n", am791x_state_names[am791x->tx_state], am791x_state_names[state]);
LOGP(DAM791X, LOGL_DEBUG, "Change TX state %s -> %s\n", am791x_state_names[am791x->tx_state], am791x_state_names[state]);
am791x->tx_state = state;
}
static void new_rx_state(am791x_t *am791x, enum am791x_st state)
{
if (am791x->rx_state != state)
PDEBUG(DAM791X, DEBUG_DEBUG, "Change RX state %s -> %s\n", am791x_state_names[am791x->rx_state], am791x_state_names[state]);
LOGP(DAM791X, LOGL_DEBUG, "Change RX state %s -> %s\n", am791x_state_names[am791x->rx_state], am791x_state_names[state]);
am791x->rx_state = state;
}
@ -577,7 +579,7 @@ static void new_rx_state(am791x_t *am791x, enum am791x_st state)
static void set_flag(int *flag_p, int value, const char *name)
{
if (*flag_p != value) {
PDEBUG(DAM791X, DEBUG_DEBUG, " -> %s\n", name);
LOGP(DAM791X, LOGL_DEBUG, " -> %s\n", name);
*flag_p = value;
}
}
@ -585,10 +587,9 @@ static void set_flag(int *flag_p, int value, const char *name)
/*
* state machine according to datasheet
*/
static void go_main_channel_tx(am791x_t *am791x)
{
PDEBUG(DAM791X, DEBUG_DEBUG, "Enable transmitter on main channel\n");
LOGP(DAM791X, LOGL_DEBUG, "Enable transmitter on main channel\n");
/* only block RD, if not full duplex and not 4-wire (loopback mode) */
if (!am791x->fullduplex && !am791x->loopback_main) {
@ -599,7 +600,8 @@ static void go_main_channel_tx(am791x_t *am791x)
/* activate TD now and set CTS timer (RCON) */
set_flag(&am791x->block_td, 0, "TD RELEASED");
set_flag(&am791x->tx_silence, 0, "RESET SILENCE");
timer_start(&am791x->tx_timer, am791x->t_rcon);
/* Flag timer, because it must be added in main thread. */
am791x->tx_timer_f = am791x->t_rcon;
new_tx_state(am791x, AM791X_STATE_RCON);
set_filters(am791x);
/* check CD to be blocked */
@ -613,7 +615,7 @@ static void go_main_channel_tx(am791x_t *am791x)
static void rcon_release_rts(am791x_t *am791x)
{
PDEBUG(DAM791X, DEBUG_DEBUG, "RTS was released\n");
LOGP(DAM791X, LOGL_DEBUG, "RTS was released\n");
set_flag(&am791x->block_td, 1, "TD IGNORED");
set_flag(&am791x->tx_silence, 1, "SET SILENCE");
@ -629,7 +631,7 @@ static void rcon_release_rts(am791x_t *am791x)
static void rcon_done(am791x_t *am791x)
{
PDEBUG(DAM791X, DEBUG_DEBUG, "Transmission started\n");
LOGP(DAM791X, LOGL_DEBUG, "Transmission started\n");
new_tx_state(am791x, AM791X_STATE_DATA);
/* CTS on */
@ -638,7 +640,7 @@ static void rcon_done(am791x_t *am791x)
static void tx_data_done(am791x_t *am791x)
{
PDEBUG(DAM791X, DEBUG_DEBUG, "RTS was released\n");
LOGP(DAM791X, LOGL_DEBUG, "RTS was released\n");
new_tx_state(am791x, AM791X_STATE_RCOFF);
set_flag(&am791x->block_td, 1, "TD IGNORED");
@ -650,12 +652,13 @@ static void tx_data_done(am791x_t *am791x)
if (!am791x->fullduplex) {
set_flag(&am791x->squelch, 1, "SET SQUELCH (ON)");
}
timer_start(&am791x->tx_timer, am791x->t_rcoff);
/* Flag timer, because it must be added in main thread. */
am791x->tx_timer_f = am791x->t_rcoff;
}
static void rcoff_done(am791x_t *am791x)
{
PDEBUG(DAM791X, DEBUG_DEBUG, "Transmission over\n");
LOGP(DAM791X, LOGL_DEBUG, "Transmission over\n");
/* CTS off */
am791x->cts_cb(am791x->inst, 0);
@ -665,17 +668,19 @@ static void rcoff_done(am791x_t *am791x)
return;
}
if (!am791x->sto) {
timer_start(&am791x->tx_timer, am791x->t_sq - am791x->t_rcoff);
/* Flag timer, because it must be added in main thread. */
am791x->tx_timer_f = am791x->t_sq - am791x->t_rcoff;
new_tx_state(am791x, AM791X_STATE_SQ_OFF);
return;
}
timer_start(&am791x->tx_timer, am791x->t_sto - am791x->t_rcoff);
/* Flag timer, because it must be added in main thread. */
am791x->tx_timer_f = am791x->t_sto - am791x->t_rcoff;
new_tx_state(am791x, AM791X_STATE_STO_OFF);
}
static void sq_done(am791x_t *am791x)
{
PDEBUG(DAM791X, DEBUG_DEBUG, "Squelch over\n");
LOGP(DAM791X, LOGL_DEBUG, "Squelch over\n");
set_flag(&am791x->block_cd, 0, "CD RELEASED");
new_tx_state(am791x, AM791X_STATE_INIT);
@ -690,16 +695,17 @@ static void sq_done(am791x_t *am791x)
static void sto_done(am791x_t *am791x)
{
PDEBUG(DAM791X, DEBUG_DEBUG, "STO over\n");
LOGP(DAM791X, LOGL_DEBUG, "STO over\n");
set_flag(&am791x->tx_sto, 0, "stop STO");
timer_start(&am791x->tx_timer, am791x->t_sq - am791x->t_sto);
/* Flag timer, because it must be added in main thread. */
am791x->tx_timer_f = am791x->t_sq - am791x->t_sto;
new_tx_state(am791x, AM791X_STATE_SQ_OFF);
}
static void go_back_channel_tx(am791x_t *am791x)
{
PDEBUG(DAM791X, DEBUG_DEBUG, "Enable transmitter on back channel\n");
LOGP(DAM791X, LOGL_DEBUG, "Enable transmitter on back channel\n");
if (!am791x->loopback_back) {
set_flag(&am791x->block_brd, 1, "BRD = MARK");
@ -709,7 +715,8 @@ static void go_back_channel_tx(am791x_t *am791x)
/* activate BTD now and set BCTS timer (BRCON) */
set_flag(&am791x->block_btd, 0, "BTD RELEASED");
set_flag(&am791x->tx_silence, 0, "RESET SILENCE");
timer_start(&am791x->tx_timer, am791x->t_brcon);
/* Flag timer, because it must be added in main thread. */
am791x->tx_timer_f = am791x->t_brcon;
new_tx_state(am791x, AM791X_STATE_BRCON);
set_filters(am791x);
/* check BCD to be blocked */
@ -723,7 +730,7 @@ static void go_back_channel_tx(am791x_t *am791x)
static void brcon_release_brts(am791x_t *am791x)
{
PDEBUG(DAM791X, DEBUG_DEBUG, "BRTS was released\n");
LOGP(DAM791X, LOGL_DEBUG, "BRTS was released\n");
set_flag(&am791x->tx_silence, 1, "SET SILENCE");
new_tx_state(am791x, AM791X_STATE_INIT);
@ -732,7 +739,7 @@ static void brcon_release_brts(am791x_t *am791x)
static void brcon_done(am791x_t *am791x)
{
PDEBUG(DAM791X, DEBUG_DEBUG, "Transmission started\n");
LOGP(DAM791X, LOGL_DEBUG, "Transmission started\n");
new_tx_state(am791x, AM791X_STATE_BDATA);
/* BCTS on */
@ -741,16 +748,17 @@ static void brcon_done(am791x_t *am791x)
static void tx_bdata_done(am791x_t *am791x)
{
PDEBUG(DAM791X, DEBUG_DEBUG, "BRTS was released\n");
LOGP(DAM791X, LOGL_DEBUG, "BRTS was released\n");
set_flag(&am791x->block_btd, 1, "BTD IGNORED");
set_flag(&am791x->tx_silence, 1, "SET SILENCE");
timer_start(&am791x->tx_timer, am791x->t_brcoff);
/* Flag timer, because it must be added in main thread. */
am791x->tx_timer_f = am791x->t_brcoff;
}
static void brcoff_done(am791x_t *am791x)
{
PDEBUG(DAM791X, DEBUG_DEBUG, "Transmission over\n");
LOGP(DAM791X, LOGL_DEBUG, "Transmission over\n");
/* BCTS off */
am791x->bcts_cb(am791x->inst, 0);
@ -791,7 +799,8 @@ static void handle_tx_state(am791x_t *am791x)
rcon_release_rts(am791x);
break;
}
if (!timer_running(&am791x->tx_timer)) {
/* If timer is about to be switched off, of if it already has been switched off. */
if (am791x->tx_timer_f < 0.0 || (!osmo_timer_pending(&am791x->tx_timer) && am791x->tx_timer_f == 0.0)) {
rcon_done(am791x);
break;
}
@ -803,19 +812,22 @@ static void handle_tx_state(am791x_t *am791x)
}
break;
case AM791X_STATE_RCOFF:
if (!timer_running(&am791x->tx_timer)) {
/* If timer is about to be switched off, of if it already has been switched off. */
if (am791x->tx_timer_f < 0.0 || (!osmo_timer_pending(&am791x->tx_timer) && am791x->tx_timer_f == 0.0)) {
rcoff_done(am791x);
break;
}
break;
case AM791X_STATE_STO_OFF:
if (!timer_running(&am791x->tx_timer)) {
/* If timer is about to be switched off, of if it already has been switched off. */
if (am791x->tx_timer_f < 0.0 || (!osmo_timer_pending(&am791x->tx_timer) && am791x->tx_timer_f == 0.0)) {
sto_done(am791x);
break;
}
break;
case AM791X_STATE_SQ_OFF:
if (!timer_running(&am791x->tx_timer)) {
/* If timer is about to be switched off, of if it already has been switched off. */
if (am791x->tx_timer_f < 0.0 || (!osmo_timer_pending(&am791x->tx_timer) && am791x->tx_timer_f == 0.0)) {
sq_done(am791x);
break;
}
@ -826,7 +838,8 @@ static void handle_tx_state(am791x_t *am791x)
brcon_release_brts(am791x);
break;
}
if (!timer_running(&am791x->tx_timer)) {
/* If timer is about to be switched off, of if it already has been switched off. */
if (am791x->tx_timer_f < 0.0 || (!osmo_timer_pending(&am791x->tx_timer) && am791x->tx_timer_f == 0.0)) {
brcon_done(am791x);
break;
}
@ -838,27 +851,29 @@ static void handle_tx_state(am791x_t *am791x)
}
break;
case AM791X_STATE_BRCOFF:
if (!timer_running(&am791x->tx_timer)) {
/* If timer is about to be switched off, of if it already has been switched off. */
if (am791x->tx_timer_f < 0.0 || (!osmo_timer_pending(&am791x->tx_timer) && am791x->tx_timer_f == 0.0)) {
brcoff_done(am791x);
break;
}
break;
default:
PDEBUG(DAM791X, DEBUG_ERROR, "State %s not handled!\n", am791x_state_names[am791x->rx_state]);
LOGP(DAM791X, LOGL_ERROR, "State %s not handled!\n", am791x_state_names[am791x->rx_state]);
}
}
static void go_main_channel_rx(am791x_t *am791x)
{
PDEBUG(DAM791X, DEBUG_DEBUG, "Enable receiver on main channel\n");
LOGP(DAM791X, LOGL_DEBUG, "Enable receiver on main channel\n");
timer_start(&am791x->rx_timer, am791x->t_cdon);
/* Flag timer, because it must be added in main thread. */
am791x->rx_timer_f = am791x->t_cdon;
new_rx_state(am791x, AM791X_STATE_CDON);
}
static void cdon_done(am791x_t *am791x)
{
PDEBUG(DAM791X, DEBUG_DEBUG, "Reception started\n");
LOGP(DAM791X, LOGL_DEBUG, "Reception started\n");
set_flag(&am791x->block_rd, 0, "RD RELEASED");
new_rx_state(am791x, AM791X_STATE_DATA);
@ -872,23 +887,25 @@ static void cdon_done(am791x_t *am791x)
static void cdon_no_cd(am791x_t *am791x)
{
PDEBUG(DAM791X, DEBUG_DEBUG, "Carrier is gone\n");
LOGP(DAM791X, LOGL_DEBUG, "Carrier is gone\n");
timer_stop(&am791x->rx_timer);
/* Flag timer, because it must be deleted in main thread. */
am791x->rx_timer_f = -1;
new_rx_state(am791x, AM791X_STATE_INIT);
}
static void rx_data_done(am791x_t *am791x)
{
PDEBUG(DAM791X, DEBUG_DEBUG, "Carrier lost\n");
LOGP(DAM791X, LOGL_DEBUG, "Carrier lost\n");
timer_start(&am791x->rx_timer, am791x->t_cdoff);
/* Flag timer, because it must be added in main thread. */
am791x->rx_timer_f = am791x->t_cdoff;
new_rx_state(am791x, AM791X_STATE_CDOFF);
}
static void cdoff_done(am791x_t *am791x)
{
PDEBUG(DAM791X, DEBUG_DEBUG, "Reception finished\n");
LOGP(DAM791X, LOGL_DEBUG, "Reception finished\n");
set_flag(&am791x->block_rd, 1, "RD = MARK");
new_rx_state(am791x, AM791X_STATE_INIT);
@ -902,23 +919,25 @@ static void cdoff_done(am791x_t *am791x)
static void cdoff_cd(am791x_t *am791x)
{
PDEBUG(DAM791X, DEBUG_DEBUG, "Carrier recovered\n");
LOGP(DAM791X, LOGL_DEBUG, "Carrier recovered\n");
timer_stop(&am791x->rx_timer);
/* Flag timer, because it must be deleted in main thread. */
am791x->rx_timer_f = -1;
new_rx_state(am791x, AM791X_STATE_DATA);
}
static void go_back_channel_rx(am791x_t *am791x)
{
PDEBUG(DAM791X, DEBUG_DEBUG, "Enable receiver on back channel\n");
LOGP(DAM791X, LOGL_DEBUG, "Enable receiver on back channel\n");
timer_start(&am791x->rx_timer, am791x->t_bcdon);
/* Flag timer, because it must be added in main thread. */
am791x->rx_timer_f = am791x->t_bcdon;
new_rx_state(am791x, AM791X_STATE_BCDON);
}
static void bcdon_done(am791x_t *am791x)
{
PDEBUG(DAM791X, DEBUG_DEBUG, "Carrier was detected\n");
LOGP(DAM791X, LOGL_DEBUG, "Carrier was detected\n");
set_flag(&am791x->block_brd, 0, "BRD RELEASED");
new_rx_state(am791x, AM791X_STATE_BDATA);
@ -932,23 +951,25 @@ static void bcdon_done(am791x_t *am791x)
static void bcdon_no_cd(am791x_t *am791x)
{
PDEBUG(DAM791X, DEBUG_DEBUG, "Carrier is gone\n");
LOGP(DAM791X, LOGL_DEBUG, "Carrier is gone\n");
timer_stop(&am791x->rx_timer);
/* Flag timer, because it must be deleted in main thread. */
am791x->rx_timer_f = -1;
new_rx_state(am791x, AM791X_STATE_INIT);
}
static void rx_bdata_done(am791x_t *am791x)
{
PDEBUG(DAM791X, DEBUG_DEBUG, "Carrier lost\n");
LOGP(DAM791X, LOGL_DEBUG, "Carrier lost\n");
timer_start(&am791x->rx_timer, am791x->t_bcdoff);
/* Flag timer, because it must be added in main thread. */
am791x->rx_timer_f = am791x->t_bcdoff;
new_rx_state(am791x, AM791X_STATE_BCDOFF);
}
static void bcdoff_done(am791x_t *am791x)
{
PDEBUG(DAM791X, DEBUG_DEBUG, "Reception finished\n");
LOGP(DAM791X, LOGL_DEBUG, "Reception finished\n");
if (!am791x->bell_202)
set_flag(&am791x->block_brd, 1, "BRD = MARK");
@ -963,9 +984,10 @@ static void bcdoff_done(am791x_t *am791x)
static void bcdoff_cd(am791x_t *am791x)
{
PDEBUG(DAM791X, DEBUG_DEBUG, "Carrier recovered\n");
LOGP(DAM791X, LOGL_DEBUG, "Carrier recovered\n");
timer_stop(&am791x->rx_timer);
/* Flag timer, because it must be deleted in main thread. */
am791x->rx_timer_f = -1;
new_rx_state(am791x, AM791X_STATE_BDATA);
}
@ -992,7 +1014,8 @@ static void handle_rx_state(am791x_t *am791x)
break;
/* all main channel states ... */
case AM791X_STATE_CDON:
if (!timer_running(&am791x->rx_timer)) {
/* If timer is about to be switched off, of if it already has been switched off. */
if (am791x->rx_timer_f < 0.0 || (!osmo_timer_pending(&am791x->rx_timer) && am791x->rx_timer_f == 0.0)) {
cdon_done(am791x);
break;
}
@ -1008,7 +1031,8 @@ static void handle_rx_state(am791x_t *am791x)
}
break;
case AM791X_STATE_CDOFF:
if (!timer_running(&am791x->rx_timer)) {
/* If timer is about to be switched off, of if it already has been switched off. */
if (am791x->rx_timer_f < 0.0 || (!osmo_timer_pending(&am791x->rx_timer) && am791x->rx_timer_f == 0.0)) {
cdoff_done(am791x);
break;
}
@ -1019,7 +1043,8 @@ static void handle_rx_state(am791x_t *am791x)
break;
/* all back channel states ... */
case AM791X_STATE_BCDON:
if (!timer_running(&am791x->rx_timer)) {
/* If timer is about to be switched off, of if it already has been switched off. */
if (am791x->rx_timer_f < 0.0 || (!osmo_timer_pending(&am791x->rx_timer) && am791x->rx_timer_f == 0.0)) {
bcdon_done(am791x);
break;
}
@ -1035,7 +1060,8 @@ static void handle_rx_state(am791x_t *am791x)
}
break;
case AM791X_STATE_BCDOFF:
if (!timer_running(&am791x->rx_timer)) {
/* If timer is about to be switched off, of if it already has been switched off. */
if (am791x->rx_timer_f < 0.0 || (!osmo_timer_pending(&am791x->rx_timer) && am791x->rx_timer_f == 0.0)) {
bcdoff_done(am791x);
break;
}
@ -1045,7 +1071,7 @@ static void handle_rx_state(am791x_t *am791x)
}
break;
default:
PDEBUG(DAM791X, DEBUG_ERROR, "State %s not handled!\n", am791x_state_names[am791x->rx_state]);
LOGP(DAM791X, LOGL_ERROR, "State %s not handled!\n", am791x_state_names[am791x->rx_state]);
}
}
@ -1066,16 +1092,16 @@ static void handle_state(am791x_t *am791x)
}
/* timeout events */
static void tx_timeout(struct timer *timer)
static void tx_timeout(void *data)
{
am791x_t *am791x = (am791x_t *)timer->priv;
am791x_t *am791x = data;
handle_tx_state(am791x);
}
static void rx_timeout(struct timer *timer)
static void rx_timeout(void *data)
{
am791x_t *am791x = (am791x_t *)timer->priv;
am791x_t *am791x = data;
handle_rx_state(am791x);
}
@ -1086,10 +1112,10 @@ int am791x_init(am791x_t *am791x, void *inst, enum am791x_type type, uint8_t mc,
memset(am791x, 0, sizeof(*am791x));
/* init timers */
timer_init(&am791x->tx_timer, tx_timeout, am791x);
timer_init(&am791x->rx_timer, rx_timeout, am791x);
osmo_timer_setup(&am791x->tx_timer, tx_timeout, am791x);
osmo_timer_setup(&am791x->rx_timer, rx_timeout, am791x);
PDEBUG(DAM791X, DEBUG_DEBUG, "Initializing instance of AM791%d:\n", type);
LOGP(DAM791X, LOGL_DEBUG, "Initializing instance of AM791%d:\n", type);
am791x->inst = inst;
am791x->type = type;
@ -1119,13 +1145,13 @@ int am791x_init(am791x_t *am791x, void *inst, enum am791x_type type, uint8_t mc,
/* exit routine, must be called when exit */
void am791x_exit(am791x_t *am791x)
{
PDEBUG(DAM791X, DEBUG_DEBUG, "Exit instance of AM791%d:\n", am791x->type);
LOGP(DAM791X, LOGL_DEBUG, "Exit instance of AM791%d:\n", am791x->type);
/* bring to reset state, be sure to clean FSK processes */
am791x_reset(am791x);
timer_exit(&am791x->tx_timer);
timer_exit(&am791x->rx_timer);
osmo_timer_del(&am791x->tx_timer);
osmo_timer_del(&am791x->rx_timer);
}
/* get some default baud rate for each mode, before IOCTL sets it (if it sets it) */
@ -1149,8 +1175,8 @@ int am791x_mc(am791x_t *am791x, uint8_t mc, int samplerate, double tx_baud, doub
if (!((am791x->type) ? am791x_modes[mc].sup_7911 : am791x_modes[mc].sup_7910))
rc = -EINVAL;
PDEBUG(DAM791X, DEBUG_INFO, "Setting mode %d: %s\n", mc, am791x_modes[mc].description);
PDEBUG(DAM791X, DEBUG_DEBUG, " -> Baud rate: %.1f/%.1f\n", rx_baud, tx_baud);
LOGP(DAM791X, LOGL_INFO, "Setting mode %d: %s\n", mc, am791x_modes[mc].description);
LOGP(DAM791X, LOGL_DEBUG, " -> Baud rate: %.1f/%.1f\n", rx_baud, tx_baud);
am791x->mc = mc;
am791x->samplerate = samplerate;
@ -1187,10 +1213,12 @@ int am791x_mc(am791x_t *am791x, uint8_t mc, int samplerate, double tx_baud, doub
/* reset at any time, may be called any time by upper layer */
void am791x_reset(am791x_t *am791x)
{
PDEBUG(DAM791X, DEBUG_INFO, "Reset!\n");
LOGP(DAM791X, LOGL_INFO, "Reset!\n");
timer_stop(&am791x->tx_timer);
timer_stop(&am791x->rx_timer);
/* Flag timer, because it must be deleted in main thread. */
am791x->tx_timer_f = -1.0;
/* Flag timer, because it must be deleted in main thread. */
am791x->rx_timer_f = -1.0;
if (am791x->f0_tx) {
fsk_mod_cleanup(&am791x->fsk_tx);
@ -1228,7 +1256,7 @@ void am791x_reset(am791x_t *am791x)
/* change input lines */
void am791x_dtr(am791x_t *am791x, int dtr)
{
PDEBUG(DAM791X, DEBUG_DEBUG, "Terminal is%s ready!\n", (dtr) ? "" : " not");
LOGP(DAM791X, LOGL_DEBUG, "Terminal is%s ready!\n", (dtr) ? "" : " not");
/* set filters, if DTR becomes on */
if (!am791x->line_dtr && dtr) {
@ -1242,7 +1270,7 @@ void am791x_dtr(am791x_t *am791x, int dtr)
void am791x_rts(am791x_t *am791x, int rts)
{
PDEBUG(DAM791X, DEBUG_DEBUG, "Terminal %s RTS.\n", (rts) ? "sets" : "clears");
LOGP(DAM791X, LOGL_DEBUG, "Terminal %s RTS.\n", (rts) ? "sets" : "clears");
am791x->line_rts = rts;
handle_state(am791x);
@ -1250,7 +1278,7 @@ void am791x_rts(am791x_t *am791x, int rts)
void am791x_brts(am791x_t *am791x, int rts)
{
PDEBUG(DAM791X, DEBUG_DEBUG, "Terminal %s BRTS.\n", (rts) ? "sets" : "clears");
LOGP(DAM791X, LOGL_DEBUG, "Terminal %s BRTS.\n", (rts) ? "sets" : "clears");
am791x->line_brts = rts;
handle_state(am791x);
@ -1258,9 +1286,25 @@ void am791x_brts(am791x_t *am791x, int rts)
void am791x_ring(am791x_t *am791x, int ring)
{
PDEBUG(DAM791X, DEBUG_DEBUG, "Terminal %s RING.\n", (ring) ? "sets" : "clears");
LOGP(DAM791X, LOGL_DEBUG, "Terminal %s RING.\n", (ring) ? "sets" : "clears");
am791x->line_ring = ring;
handle_state(am791x);
}
void am791x_add_del_timers(am791x_t *am791x)
{
/* Timers may only be processed in main thread, because libosmocore has timer lists for individual threads. */
if (am791x->tx_timer_f < 0.0)
osmo_timer_del(&am791x->tx_timer);
if (am791x->tx_timer_f > 0.0)
osmo_timer_schedule(&am791x->tx_timer, FLOAT_TO_TIMEOUT(am791x->tx_timer_f));
am791x->tx_timer_f = 0.0;
if (am791x->rx_timer_f < 0.0)
osmo_timer_del(&am791x->rx_timer);
if (am791x->rx_timer_f > 0.0)
osmo_timer_schedule(&am791x->rx_timer, FLOAT_TO_TIMEOUT(am791x->rx_timer_f));
am791x->rx_timer_f = 0.0;
}

View File

@ -67,7 +67,8 @@ typedef struct am791x {
int f0_rx, f1_rx;
/* timers */
struct timer tx_timer, rx_timer;
struct osmo_timer_list tx_timer, rx_timer;
double tx_timer_f, rx_timer_f; /* time to stat / flag to stop */
double t_rcon;
double t_rcoff;
double t_brcon;
@ -104,4 +105,5 @@ void am791x_dtr(am791x_t *am791x, int dtr);
void am791x_rts(am791x_t *am791x, int rts);
void am791x_brts(am791x_t *am791x, int brts);
void am791x_ring(am791x_t *am791x, int ring);
void am791x_add_del_timers(am791x_t *am791x);

View File

@ -32,12 +32,14 @@
#include <fcntl.h>
#include <math.h>
#include "../libsample/sample.h"
#include "../libtimer/timer.h"
#include <osmocom/core/select.h>
#include <osmocom/core/timer.h>
#include "../libfsk/fsk.h"
#include "../libsound/sound.h"
#include "../libwave/wave.h"
#include "../libdisplay/display.h"
#include "../libdebug/debug.h"
#include "../liblogging/logging.h"
#include "../libmobile/get_time.c"
#include "device.h"
#include "am791x.h"
#include "uart.h"
@ -217,7 +219,7 @@ static void cts(void *inst, int cts)
return;
if (datenklo->auto_rts) {
PDEBUG(DDATENKLO, DEBUG_INFO, "Received CTS=%d in Automatic RTS Mode.\n", cts);
LOGP(DDATENKLO, LOGL_INFO, "Received CTS=%d in Automatic RTS Mode.\n", cts);
datenklo->auto_rts_cts = cts;
return;
}
@ -226,7 +228,7 @@ static void cts(void *inst, int cts)
datenklo->lines |= TIOCM_CTS;
else
datenklo->lines &= ~TIOCM_CTS;
PDEBUG(DDATENKLO, DEBUG_INFO, "Indicating to terminal that CTS is %s\n", (cts) ? "on" : "off");
LOGP(DDATENKLO, LOGL_INFO, "Indicating to terminal that CTS is %s\n", (cts) ? "on" : "off");
}
/* modem changes CTS state (back channel) */
@ -238,7 +240,7 @@ static void bcts(void *inst, int cts)
return;
if (datenklo->auto_rts) {
PDEBUG(DDATENKLO, DEBUG_INFO, "Received BCTS=%d in Automatic RTS Mode.\n", cts);
LOGP(DDATENKLO, LOGL_INFO, "Received BCTS=%d in Automatic RTS Mode.\n", cts);
datenklo->auto_rts_cts = cts;
return;
}
@ -247,7 +249,7 @@ static void bcts(void *inst, int cts)
datenklo->lines |= TIOCM_CTS;
else
datenklo->lines &= ~TIOCM_CTS;
PDEBUG(DDATENKLO, DEBUG_INFO, "Indicating to terminal that BCTS is %s\n", (cts) ? "on" : "off");
LOGP(DDATENKLO, LOGL_INFO, "Indicating to terminal that BCTS is %s\n", (cts) ? "on" : "off");
}
/* modem changes CD state */
@ -259,7 +261,7 @@ static void cd(void *inst, int cd)
return;
if (datenklo->auto_rts) {
PDEBUG(DDATENKLO, DEBUG_INFO, "Received CD=%d in Automatic RTS Mode.\n", cd);
LOGP(DDATENKLO, LOGL_INFO, "Received CD=%d in Automatic RTS Mode.\n", cd);
datenklo->auto_rts_cd = cd;
return;
}
@ -268,7 +270,7 @@ static void cd(void *inst, int cd)
datenklo->lines |= TIOCM_CD;
else
datenklo->lines &= ~TIOCM_CD;
PDEBUG(DDATENKLO, DEBUG_INFO, "Indicating to terminal that CD is %s\n", (cd) ? "on" : "off");
LOGP(DDATENKLO, LOGL_INFO, "Indicating to terminal that CD is %s\n", (cd) ? "on" : "off");
}
/* modem changes CD state (back channel) */
@ -280,7 +282,7 @@ static void bcd(void *inst, int cd)
return;
if (datenklo->auto_rts) {
PDEBUG(DDATENKLO, DEBUG_INFO, "Received BCD=%d in Automatic RTS Mode.\n", cd);
LOGP(DDATENKLO, LOGL_INFO, "Received BCD=%d in Automatic RTS Mode.\n", cd);
datenklo->auto_rts_cd = cd;
return;
}
@ -289,7 +291,7 @@ static void bcd(void *inst, int cd)
datenklo->lines |= TIOCM_CD;
else
datenklo->lines &= ~TIOCM_CD;
PDEBUG(DDATENKLO, DEBUG_INFO, "Indicating to terminal that BCD is %s\n", (cd) ? "on" : "off");
LOGP(DDATENKLO, LOGL_INFO, "Indicating to terminal that BCD is %s\n", (cd) ? "on" : "off");
}
/* modem request bit */
@ -405,7 +407,7 @@ static int tx(void *inst)
if (datenklo->onlcr_char) {
datenklo->onlcr_char = 0;
data = '\n';
PDEBUG(DDATENKLO, DEBUG_DEBUG, "ONLCR: sending NL\n");
LOGP(DDATENKLO, LOGL_DEBUG, "ONLCR: sending NL\n");
goto out;
}
@ -414,7 +416,7 @@ again:
if (fill == (size_t)datenklo->tx_fifo_full) {
/* tell cuse to write again */
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Set POLLOUT!\n");
LOGP(DDATENKLO, LOGL_DEBUG, "Set POLLOUT!\n");
datenklo->revents |= POLLOUT;
device_set_poll_events(datenklo->device, datenklo->revents);
}
@ -424,12 +426,12 @@ again:
datenklo->auto_rts_on = 0;
if (datenklo->tcsetsw) {
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Transmission finished, applying termios now.\n");
LOGP(DDATENKLO, LOGL_DEBUG, "Transmission finished, applying termios now.\n");
memcpy(&datenklo->termios, &datenklo->tcsetsw_termios, sizeof(datenklo->termios));
if (datenklo->tcsetsw == 2) {
flush_rx(datenklo);
if ((datenklo->revents & POLLIN)) {
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Reset POLLIN (flushed)\n");
LOGP(DDATENKLO, LOGL_DEBUG, "Reset POLLIN (flushed)\n");
datenklo->revents &= ~POLLIN;
device_set_poll_events(datenklo->device, datenklo->revents);
}
@ -450,26 +452,26 @@ again:
/* process output features */
if (datenklo->opost) {
if (datenklo->olcuc) {
PDEBUG(DDATENKLO, DEBUG_DEBUG, "OLCUC: 0x%02x -> 0x%02x\n", data, toupper(data));
LOGP(DDATENKLO, LOGL_DEBUG, "OLCUC: 0x%02x -> 0x%02x\n", data, toupper(data));
data = toupper(data);
}
if (datenklo->onlret && data == '\r') {
PDEBUG(DDATENKLO, DEBUG_DEBUG, "ONLRET: ignore CR\n");
LOGP(DDATENKLO, LOGL_DEBUG, "ONLRET: ignore CR\n");
goto again;
}
if (datenklo->ocrnl && data == '\r') {
PDEBUG(DDATENKLO, DEBUG_DEBUG, "OCRNL: CR -> NL\n");
LOGP(DDATENKLO, LOGL_DEBUG, "OCRNL: CR -> NL\n");
data = '\n';
}
if (datenklo->onlcr && data == '\n') {
datenklo->onlcr_char = 1;
data = '\r';
PDEBUG(DDATENKLO, DEBUG_DEBUG, "ONLCR: sending CR\n");
LOGP(DDATENKLO, LOGL_DEBUG, "ONLCR: sending CR\n");
}
}
out:
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Transmitting byte 0x%02x to UART.\n", data);
LOGP(DDATENKLO, LOGL_DEBUG, "Transmitting byte 0x%02x to UART.\n", data);
return data;
}
@ -480,35 +482,35 @@ static void rx(void *inst, int data, uint32_t __attribute__((unused)) flags)
datenklo_t *datenklo = (datenklo_t *)inst;
size_t space;
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Received byte 0x%02x ('%c') from UART.\n", data, (data >= 32 && data <= 126) ? data : '.');
LOGP(DDATENKLO, LOGL_DEBUG, "Received byte 0x%02x ('%c') from UART.\n", data, (data >= 32 && data <= 126) ? data : '.');
/* process input features */
if (datenklo->ignbrk && (flags & UART_BREAK)) {
PDEBUG(DDATENKLO, DEBUG_DEBUG, "IGNBRK: ignore BREAK\n");
LOGP(DDATENKLO, LOGL_DEBUG, "IGNBRK: ignore BREAK\n");
return;
}
if (datenklo->istrip && (data & 0x80)) {
PDEBUG(DDATENKLO, DEBUG_DEBUG, "ISTRIP: 0x%02x -> 0x%02x\n", data, data & 0x7f);
LOGP(DDATENKLO, LOGL_DEBUG, "ISTRIP: 0x%02x -> 0x%02x\n", data, data & 0x7f);
data &= 0x7f;
}
if (datenklo->inlcr && data == '\n') {
PDEBUG(DDATENKLO, DEBUG_DEBUG, "INLCR: NL -> CR\n");
LOGP(DDATENKLO, LOGL_DEBUG, "INLCR: NL -> CR\n");
data = '\r';
}
if (datenklo->igncr && data == '\r') {
PDEBUG(DDATENKLO, DEBUG_DEBUG, "IGNCR: ignore CR\n");
LOGP(DDATENKLO, LOGL_DEBUG, "IGNCR: ignore CR\n");
return;
}
if (datenklo->icrnl && data == '\r') {
PDEBUG(DDATENKLO, DEBUG_DEBUG, "ICRNL: CR -> NL\n");
LOGP(DDATENKLO, LOGL_DEBUG, "ICRNL: CR -> NL\n");
data = '\n';
}
if (datenklo->iuclc) {
PDEBUG(DDATENKLO, DEBUG_DEBUG, "IUCLC: 0x%02x -> 0x%02x\n", data, tolower(data));
LOGP(DDATENKLO, LOGL_DEBUG, "IUCLC: 0x%02x -> 0x%02x\n", data, tolower(data));
data = tolower(data);
}
if (datenklo->echo) {
PDEBUG(DDATENKLO, DEBUG_DEBUG, "ECHO: write to output\n");
LOGP(DDATENKLO, LOGL_DEBUG, "ECHO: write to output\n");
space = (datenklo->tx_fifo_out - datenklo->tx_fifo_in - 1 + datenklo->tx_fifo_size) % datenklo->tx_fifo_size;
if (space) {
datenklo->tx_fifo[datenklo->tx_fifo_in++] = data;
@ -519,7 +521,7 @@ static void rx(void *inst, int data, uint32_t __attribute__((unused)) flags)
/* empty buffer gets data */
if (datenklo->rx_fifo_out == datenklo->rx_fifo_in) {
/* tell cuse to read again */
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Set POLLIN!\n");
LOGP(DDATENKLO, LOGL_DEBUG, "Set POLLIN!\n");
datenklo->revents |= POLLIN;
device_set_poll_events(datenklo->device, datenklo->revents);
}
@ -528,13 +530,13 @@ static void rx(void *inst, int data, uint32_t __attribute__((unused)) flags)
if (!space) {
err_overflow:
PDEBUG(DDATENKLO, DEBUG_NOTICE, "RX buffer overflow, dropping!\n");
LOGP(DDATENKLO, LOGL_NOTICE, "RX buffer overflow, dropping!\n");
return;
}
if (datenklo->parmrk) {
if ((flags & (UART_BREAK | UART_PARITY_ERROR))) {
PDEBUG(DDATENKLO, DEBUG_DEBUG, "PARMRK: 0x%02x -> 0xff,0x00,0x%02x\n", data, data);
LOGP(DDATENKLO, LOGL_DEBUG, "PARMRK: 0x%02x -> 0xff,0x00,0x%02x\n", data, data);
if (space < 3)
goto err_overflow;
datenklo->rx_fifo[datenklo->rx_fifo_in++] = 0xff;
@ -544,7 +546,7 @@ static void rx(void *inst, int data, uint32_t __attribute__((unused)) flags)
datenklo->rx_fifo_in %= datenklo->rx_fifo_size;
space--;
} else if (data == 0xff) {
PDEBUG(DDATENKLO, DEBUG_DEBUG, "PARMRK: 0xff -> 0xff,0xff\n");
LOGP(DDATENKLO, LOGL_DEBUG, "PARMRK: 0xff -> 0xff,0xff\n");
if (space < 2)
goto err_overflow;
datenklo->rx_fifo[datenklo->rx_fifo_in++] = 0xff;
@ -567,18 +569,18 @@ static void set_lines(datenklo_t *datenklo, int new)
int old = datenklo->lines;
if (!(old & TIOCM_DTR) && (new & TIOCM_DTR)) {
PDEBUG(DDATENKLO, DEBUG_INFO, "Terminal turns DTR on\n");
LOGP(DDATENKLO, LOGL_INFO, "Terminal turns DTR on\n");
flush_tx(datenklo);
flush_rx(datenklo);
am791x_dtr(&datenklo->am791x, 1);
}
if ((old & TIOCM_DTR) && !(new & TIOCM_DTR)) {
PDEBUG(DDATENKLO, DEBUG_INFO, "Terminal turns DTR off\n");
LOGP(DDATENKLO, LOGL_INFO, "Terminal turns DTR off\n");
am791x_dtr(&datenklo->am791x, 0);
}
if (!(old & TIOCM_RTS) && (new & TIOCM_RTS)) {
PDEBUG(DDATENKLO, DEBUG_INFO, "Terminal turns RTS on\n");
LOGP(DDATENKLO, LOGL_INFO, "Terminal turns RTS on\n");
if (datenklo->auto_rts)
new |= TIOCM_CTS | TIOCM_CD;
else {
@ -589,7 +591,7 @@ static void set_lines(datenklo_t *datenklo, int new)
}
}
if ((old & TIOCM_RTS) && !(new & TIOCM_RTS)) {
PDEBUG(DDATENKLO, DEBUG_INFO, "Terminal turns RTS off\n");
LOGP(DDATENKLO, LOGL_INFO, "Terminal turns RTS off\n");
if (datenklo->auto_rts)
new &= ~(TIOCM_CTS | TIOCM_CD);
else {
@ -609,7 +611,7 @@ static void process_auto_rts(datenklo_t *datenklo)
if (!datenklo->auto_rts)
return;
if (datenklo->auto_rts_on && !datenklo->auto_rts_rts && !datenklo->auto_rts_cd) {
PDEBUG(DDATENKLO, DEBUG_INFO, "Automatically raising RTS.\n");
LOGP(DDATENKLO, LOGL_INFO, "Automatically raising RTS.\n");
datenklo->auto_rts_rts = 1;
if (!datenklo->tx_back)
am791x_rts(&datenklo->am791x, 1);
@ -617,7 +619,7 @@ static void process_auto_rts(datenklo_t *datenklo)
am791x_brts(&datenklo->am791x, 1);
}
if (!datenklo->auto_rts_on && datenklo->auto_rts_rts) {
PDEBUG(DDATENKLO, DEBUG_INFO, "Automatically dropping RTS.\n");
LOGP(DDATENKLO, LOGL_INFO, "Automatically dropping RTS.\n");
datenklo->auto_rts_rts = 0;
if (!datenklo->tx_back)
am791x_rts(&datenklo->am791x, 0);
@ -634,7 +636,7 @@ static ssize_t dk_ioctl_get(void *inst, int cmd, void *buf, size_t out_bufsz)
ssize_t rc = 0;
#ifdef HEAVY_DEBUG
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Device has been read for ioctl (cmd = %d, size = %zu).\n", cmd, out_bufsz);
LOGP(DDATENKLO, LOGL_DEBUG, "Device has been read for ioctl (cmd = %d, size = %zu).\n", cmd, out_bufsz);
#endif
switch (cmd) {
@ -643,7 +645,7 @@ static ssize_t dk_ioctl_get(void *inst, int cmd, void *buf, size_t out_bufsz)
if (!out_bufsz)
break;
#ifdef HEAVY_DEBUG
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Terminal requests termios.\n");
LOGP(DDATENKLO, LOGL_DEBUG, "Terminal requests termios.\n");
#endif
memcpy(buf, &datenklo->termios, rc);
break;
@ -652,7 +654,7 @@ static ssize_t dk_ioctl_get(void *inst, int cmd, void *buf, size_t out_bufsz)
if (!out_bufsz)
break;
#ifdef HEAVY_DEBUG
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Terminal requests line states.\n");
LOGP(DDATENKLO, LOGL_DEBUG, "Terminal requests line states.\n");
#endif
status = datenklo->lines | TIOCM_LE | TIOCM_DSR;
memcpy(buf, &status, rc);
@ -662,7 +664,7 @@ static ssize_t dk_ioctl_get(void *inst, int cmd, void *buf, size_t out_bufsz)
if (!out_bufsz)
break;
#ifdef HEAVY_DEBUG
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Terminal requests window size.\n");
LOGP(DDATENKLO, LOGL_DEBUG, "Terminal requests window size.\n");
#endif
struct winsize *winsize = (struct winsize *)buf;
winsize->ws_row = 25;
@ -677,7 +679,7 @@ static ssize_t dk_ioctl_get(void *inst, int cmd, void *buf, size_t out_bufsz)
status = (datenklo->rx_fifo_in - datenklo->rx_fifo_out + datenklo->rx_fifo_size) % datenklo->rx_fifo_size;
memcpy(buf, &status, rc);
#ifdef HEAVY_DEBUG
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Terminal requests RX buffer fill states.\n");
LOGP(DDATENKLO, LOGL_DEBUG, "Terminal requests RX buffer fill states.\n");
#endif
break;
case TIOCOUTQ:
@ -685,7 +687,7 @@ static ssize_t dk_ioctl_get(void *inst, int cmd, void *buf, size_t out_bufsz)
if (!out_bufsz)
break;
#ifdef HEAVY_DEBUG
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Terminal requests TX buffer fill states.\n");
LOGP(DDATENKLO, LOGL_DEBUG, "Terminal requests TX buffer fill states.\n");
#endif
status = (datenklo->tx_fifo_in - datenklo->tx_fifo_out + datenklo->tx_fifo_size) % datenklo->tx_fifo_size;
memcpy(buf, &status, rc);
@ -786,15 +788,15 @@ static void set_termios(datenklo_t *datenklo, const void *buf)
new_echo = !!(datenklo->termios.c_lflag & ECHO);
if (old_baud != new_baud && (!datenklo->force_tx_baud || !datenklo->force_rx_baud)) {
PDEBUG(DDATENKLO, DEBUG_INFO, "Terminal changes baud rate to %.1f Baud.\n", new_baud);
LOGP(DDATENKLO, LOGL_INFO, "Terminal changes baud rate to %.1f Baud.\n", new_baud);
if ((datenklo->lines & TIOCM_DTR) && !new_baud) {
PDEBUG(DDATENKLO, DEBUG_INFO, "Baudrate is set to 0, we drop DTR\n");
LOGP(DDATENKLO, LOGL_INFO, "Baudrate is set to 0, we drop DTR\n");
am791x_dtr(&datenklo->am791x, 0);
}
datenklo->baudrate = new_baud;
am791x_mc(&datenklo->am791x, datenklo->mc, datenklo->samplerate, tx_baud_rate(datenklo), rx_baud_rate(datenklo));
if ((datenklo->lines & TIOCM_DTR) && !old_baud) {
PDEBUG(DDATENKLO, DEBUG_INFO, "Baudrate is set from 0, we raise DTR\n");
LOGP(DDATENKLO, LOGL_INFO, "Baudrate is set from 0, we raise DTR\n");
am791x_dtr(&datenklo->am791x, 1);
}
}
@ -802,10 +804,10 @@ static void set_termios(datenklo_t *datenklo, const void *buf)
if (old_databits != new_databits
|| old_parity != new_parity
|| old_stopbits != new_stopbits) {
PDEBUG(DDATENKLO, DEBUG_INFO, "Terminal changes serial mode to %d%c%d.\n", cflag2databits(datenklo->termios.c_cflag), parity2char(cflag2parity(datenklo->termios.c_cflag)), cflag2stopbits(datenklo->termios.c_cflag));
LOGP(DDATENKLO, LOGL_INFO, "Terminal changes serial mode to %d%c%d.\n", cflag2databits(datenklo->termios.c_cflag), parity2char(cflag2parity(datenklo->termios.c_cflag)), cflag2stopbits(datenklo->termios.c_cflag));
rc = uart_init(&datenklo->uart, datenklo, cflag2databits(datenklo->termios.c_cflag), cflag2parity(datenklo->termios.c_cflag), cflag2stopbits(datenklo->termios.c_cflag), tx, rx);
if (rc < 0)
PDEBUG(DDATENKLO, DEBUG_ERROR, "Failed to initialize UART.\n");
LOGP(DDATENKLO, LOGL_ERROR, "Failed to initialize UART.\n");
}
if (old_stopbits != new_stopbits
@ -835,8 +837,8 @@ static void set_termios(datenklo_t *datenklo, const void *buf)
datenklo->onlret = new_onlret;
datenklo->olcuc = new_olcuc;
datenklo->echo = new_echo;
PDEBUG(DDATENKLO, DEBUG_INFO, "Terminal sets serial flags:\n");
PDEBUG(DDATENKLO, DEBUG_INFO, "%cignbrk %cparmrk %cistrip %cinlcr %cigncr %cicrnl %ciuclc %copost %conlcr %cocrnl %conlret %colcuc %cecho\n",
LOGP(DDATENKLO, LOGL_INFO, "Terminal sets serial flags:\n");
LOGP(DDATENKLO, LOGL_INFO, "%cignbrk %cparmrk %cistrip %cinlcr %cigncr %cicrnl %ciuclc %copost %conlcr %cocrnl %conlret %colcuc %cecho\n",
(datenklo->ignbrk) ? '+' : '-',
(datenklo->parmrk) ? '+' : '-',
(datenklo->istrip) ? '+' : '-',
@ -862,7 +864,7 @@ static ssize_t dk_ioctl_set(void *inst, int cmd, const void *buf, size_t in_bufs
size_t space;
#ifdef HEAVY_DEBUG
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Device has been written for ioctl (cmd = %d, size = %zu).\n", cmd, in_bufsz);
LOGP(DDATENKLO, LOGL_DEBUG, "Device has been written for ioctl (cmd = %d, size = %zu).\n", cmd, in_bufsz);
#endif
switch (cmd) {
@ -870,7 +872,7 @@ static ssize_t dk_ioctl_set(void *inst, int cmd, const void *buf, size_t in_bufs
rc = sizeof(datenklo->termios);
if (!in_bufsz)
break;
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Terminal sets termios now.\n");
LOGP(DDATENKLO, LOGL_DEBUG, "Terminal sets termios now.\n");
set_termios(datenklo, buf);
break;
case TCSETSW:
@ -878,9 +880,9 @@ static ssize_t dk_ioctl_set(void *inst, int cmd, const void *buf, size_t in_bufs
rc = sizeof(datenklo->termios);
if (!in_bufsz)
break;
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Terminal sets termios after draining output buffer.\n");
LOGP(DDATENKLO, LOGL_DEBUG, "Terminal sets termios after draining output buffer.\n");
if (1 || datenklo->tx_fifo_out == datenklo->tx_fifo_in) {
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Output buffer empty, applying termios now.\n");
LOGP(DDATENKLO, LOGL_DEBUG, "Output buffer empty, applying termios now.\n");
set_termios(datenklo, buf);
break;
}
@ -895,12 +897,12 @@ static ssize_t dk_ioctl_set(void *inst, int cmd, const void *buf, size_t in_bufs
if (!in_bufsz)
break;
memcpy(&status, buf, rc);
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Terminal flushes buffer (status = %d).\n", status);
LOGP(DDATENKLO, LOGL_DEBUG, "Terminal flushes buffer (status = %d).\n", status);
if (status == TCIOFLUSH || status == TCOFLUSH) {
flush_tx(datenklo);
if (!(datenklo->revents & POLLOUT)) {
/* tell cuse to write again */
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Set POLLOUT (flushed)\n");
LOGP(DDATENKLO, LOGL_DEBUG, "Set POLLOUT (flushed)\n");
datenklo->revents |= POLLOUT;
device_set_poll_events(datenklo->device, datenklo->revents);
}
@ -908,7 +910,7 @@ static ssize_t dk_ioctl_set(void *inst, int cmd, const void *buf, size_t in_bufs
if (status == TCIOFLUSH || status == TCIFLUSH) {
flush_rx(datenklo);
if ((datenklo->revents & POLLIN)) {
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Reset POLLIN (flushed)\n");
LOGP(DDATENKLO, LOGL_DEBUG, "Reset POLLIN (flushed)\n");
datenklo->revents &= ~POLLIN;
device_set_poll_events(datenklo->device, datenklo->revents);
}
@ -916,7 +918,7 @@ static ssize_t dk_ioctl_set(void *inst, int cmd, const void *buf, size_t in_bufs
break;
case TCSBRK:
rc = 0;
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Terminal sends break\n");
LOGP(DDATENKLO, LOGL_DEBUG, "Terminal sends break\n");
datenklo->break_bits = tx_baud_rate(datenklo) * 3 / 10;
break;
case TCSBRKP:
@ -924,7 +926,7 @@ static ssize_t dk_ioctl_set(void *inst, int cmd, const void *buf, size_t in_bufs
if (!in_bufsz)
break;
memcpy(&status, buf, rc);
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Terminal sends break (duration = %d).\n", status);
LOGP(DDATENKLO, LOGL_DEBUG, "Terminal sends break (duration = %d).\n", status);
if (status == 0)
status = 3;
if (status > 30)
@ -933,12 +935,12 @@ static ssize_t dk_ioctl_set(void *inst, int cmd, const void *buf, size_t in_bufs
break;
case TIOCSBRK:
rc = 0;
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Terminal turns break on\n");
LOGP(DDATENKLO, LOGL_DEBUG, "Terminal turns break on\n");
datenklo->break_on = 1;
break;
case TIOCCBRK:
rc = 0;
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Terminal turns break off\n");
LOGP(DDATENKLO, LOGL_DEBUG, "Terminal turns break off\n");
datenklo->break_on = 0;
break;
case TIOCMBIS:
@ -946,7 +948,7 @@ static ssize_t dk_ioctl_set(void *inst, int cmd, const void *buf, size_t in_bufs
if (!in_bufsz)
break;
memcpy(&status, buf, rc);
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Terminal sets line status (0x%x).\n", status);
LOGP(DDATENKLO, LOGL_DEBUG, "Terminal sets line status (0x%x).\n", status);
status = datenklo->lines | status;
set_lines(datenklo, status);
break;
@ -955,7 +957,7 @@ static ssize_t dk_ioctl_set(void *inst, int cmd, const void *buf, size_t in_bufs
if (!in_bufsz)
break;
memcpy(&status, buf, rc);
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Terminal clears line status (0x%x).\n", status);
LOGP(DDATENKLO, LOGL_DEBUG, "Terminal clears line status (0x%x).\n", status);
status = datenklo->lines & ~status;
set_lines(datenklo, status);
break;
@ -964,30 +966,30 @@ static ssize_t dk_ioctl_set(void *inst, int cmd, const void *buf, size_t in_bufs
if (!in_bufsz)
break;
memcpy(&status, buf, rc);
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Terminal specifies line status (0x%x).\n", status);
LOGP(DDATENKLO, LOGL_DEBUG, "Terminal specifies line status (0x%x).\n", status);
set_lines(datenklo, status);
break;
case TIOCGSID:
PDEBUG(DDATENKLO, DEBUG_DEBUG, "TIOGSID -> ENOTTY\n");
LOGP(DDATENKLO, LOGL_DEBUG, "TIOGSID -> ENOTTY\n");
rc = -ENOTTY;
break;
case TIOCGPGRP:
PDEBUG(DDATENKLO, DEBUG_DEBUG, "TIOCGPGRP -> ENOTTY\n");
LOGP(DDATENKLO, LOGL_DEBUG, "TIOCGPGRP -> ENOTTY\n");
rc = -ENOTTY;
break;
case TIOCSCTTY:
PDEBUG(DDATENKLO, DEBUG_DEBUG, "TIOCSCTTY -> ENOTTY\n");
LOGP(DDATENKLO, LOGL_DEBUG, "TIOCSCTTY -> ENOTTY\n");
rc = -ENOTTY;
break;
case TIOCSPGRP:
PDEBUG(DDATENKLO, DEBUG_DEBUG, "TIOCSPGRP -> ENOTTY\n");
LOGP(DDATENKLO, LOGL_DEBUG, "TIOCSPGRP -> ENOTTY\n");
rc = -ENOTTY;
break;
case TIOCSWINSZ:
rc = sizeof(struct winsize);
if (!in_bufsz)
break;
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Terminal sets window size.\n");
LOGP(DDATENKLO, LOGL_DEBUG, "Terminal sets window size.\n");
break;
case TCXONC:
rc = sizeof(status);
@ -996,15 +998,15 @@ static ssize_t dk_ioctl_set(void *inst, int cmd, const void *buf, size_t in_bufs
memcpy(&status, buf, rc);
switch (status) {
case TCOOFF:
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Terminal turns off output.\n");
LOGP(DDATENKLO, LOGL_DEBUG, "Terminal turns off output.\n");
datenklo->output_off = 1;
break;
case TCOON:
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Terminal turns on output.\n");
datenklo->output_off = 1;
LOGP(DDATENKLO, LOGL_DEBUG, "Terminal turns on output.\n");
datenklo->output_off = 0;
break;
case TCIOFF:
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Terminal turns off input.\n");
LOGP(DDATENKLO, LOGL_DEBUG, "Terminal turns off input.\n");
space = (datenklo->rx_fifo_out - datenklo->rx_fifo_in - 1 + datenklo->rx_fifo_size) % datenklo->rx_fifo_size;
if (space < 1)
break;
@ -1012,7 +1014,7 @@ static ssize_t dk_ioctl_set(void *inst, int cmd, const void *buf, size_t in_bufs
datenklo->rx_fifo_in %= datenklo->rx_fifo_size;
break;
case TCION:
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Terminal turns on input.\n");
LOGP(DDATENKLO, LOGL_DEBUG, "Terminal turns on input.\n");
space = (datenklo->rx_fifo_out - datenklo->rx_fifo_in - 1 + datenklo->rx_fifo_size) % datenklo->rx_fifo_size;
if (space < 1)
break;
@ -1034,12 +1036,12 @@ static int dk_open(void *inst, int flags)
datenklo_t *datenklo = (datenklo_t *)inst;
if (datenklo->open_count) {
PDEBUG(DDATENKLO, DEBUG_NOTICE, "Device is busy.\n");
LOGP(DDATENKLO, LOGL_NOTICE, "Device is busy.\n");
return -EBUSY;
}
datenklo->open_count++;
datenklo->flags = flags;
PDEBUG(DDATENKLO, DEBUG_INFO, "Device has been opened.\n");
LOGP(DDATENKLO, LOGL_INFO, "Device has been opened.\n");
int status = datenklo->lines | TIOCM_DTR | TIOCM_RTS;
set_lines(datenklo, status);
@ -1051,7 +1053,7 @@ static void dk_close(void *inst)
{
datenklo_t *datenklo = (datenklo_t *)inst;
PDEBUG(DDATENKLO, DEBUG_INFO, "Device has been closed.\n");
LOGP(DDATENKLO, LOGL_INFO, "Device has been closed.\n");
datenklo->open_count--;
int status = datenklo->lines & ~(TIOCM_DTR | TIOCM_RTS);
set_lines(datenklo, status);
@ -1071,7 +1073,7 @@ static void debug_data(const char *buf, int count)
count--;
}
text[i] = '\0';
PDEBUG(DDATENKLO, DEBUG_DEBUG, " \"%s\"\n", text);
LOGP(DDATENKLO, LOGL_DEBUG, " \"%s\"\n", text);
}
}
@ -1091,7 +1093,7 @@ static ssize_t dk_read(void *inst, char *buf, size_t size, int flags)
if (vmin && vtime) {
/* first: start timer */
if (!datenklo->vtimeout)
timer_start(&datenklo->vtimer, (double)vtime * 0.1);
datenklo->vtimer_us = vtime * 100000; /* start timer in main loop */
/* no data: block (in blocking IO) */
if (fill == 0) {
/* special value to tell device there is no data right now, we have to block */
@ -1104,7 +1106,7 @@ static ssize_t dk_read(void *inst, char *buf, size_t size, int flags)
}
/* enough data or timeout or nonblocking IO: stop timer and return what we have */
datenklo->vtimeout = 0;
timer_stop(&datenklo->vtimer);
datenklo->vtimer_us = -1; /* stop timer in main loop */
}
/* both MIN and TIME are zero */
if (!vmin && !vtime) {
@ -1117,7 +1119,7 @@ static ssize_t dk_read(void *inst, char *buf, size_t size, int flags)
if (!vmin && vtime) {
/* first: start timer */
if (!datenklo->vtimeout)
timer_start(&datenklo->vtimer, (double)vtime * 0.1);
datenklo->vtimer_us = vtime * 100000; /* start timer in main loop */
if (fill == 0) {
/* no data and no timeout: block (in blocking IO) */
if (!datenklo->vtimeout) {
@ -1130,7 +1132,7 @@ static ssize_t dk_read(void *inst, char *buf, size_t size, int flags)
}
/* data: stop timer and return what we have */
datenklo->vtimeout = 0;
timer_stop(&datenklo->vtimer);
datenklo->vtimer_us = -1; /* stop timer in main loop */
}
/* MIN is nonzero, TIME is zero */
if (vmin && !vtime) {
@ -1142,7 +1144,7 @@ static ssize_t dk_read(void *inst, char *buf, size_t size, int flags)
/* enough data in buffer: return what we have */
}
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Device has been read from. (fill = %zu)\n", fill);
LOGP(DDATENKLO, LOGL_DEBUG, "Device has been read from. (fill = %zu)\n", fill);
/* get data from fifo */
count = 0;
@ -1160,7 +1162,7 @@ static ssize_t dk_read(void *inst, char *buf, size_t size, int flags)
if (!fill) {
/* tell cuse not to read anymore */
if ((datenklo->revents & POLLIN)) {
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Reset POLLIN (now empty)!\n");
LOGP(DDATENKLO, LOGL_DEBUG, "Reset POLLIN (now empty)!\n");
datenklo->revents &= ~POLLIN;
device_set_poll_events(datenklo->device, datenklo->revents);
}
@ -1177,17 +1179,17 @@ static ssize_t dk_write(void *inst, const char *buf, size_t size, int __attribut
size_t i;
if (!(datenklo->lines & TIOCM_DTR)) {
PDEBUG(DDATENKLO, DEBUG_INFO, "Dropping data, DTR is off!\n");
LOGP(DDATENKLO, LOGL_INFO, "Dropping data, DTR is off!\n");
return -EIO;
}
if (!(datenklo->lines & TIOCM_RTS)) {
PDEBUG(DDATENKLO, DEBUG_INFO, "Dropping data, RTS is off!\n");
LOGP(DDATENKLO, LOGL_INFO, "Dropping data, RTS is off!\n");
return -EIO;
}
if (size > (size_t)datenklo->tx_fifo_size - 1) {
PDEBUG(DDATENKLO, DEBUG_NOTICE, "Device sends us too many data. (size = %zu)\n", size);
LOGP(DDATENKLO, LOGL_NOTICE, "Device sends us too many data. (size = %zu)\n", size);
return -EIO;
}
@ -1199,7 +1201,7 @@ static ssize_t dk_write(void *inst, const char *buf, size_t size, int __attribut
return -EAGAIN;
}
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Device has been written to. (space = %zu)\n", space);
LOGP(DDATENKLO, LOGL_DEBUG, "Device has been written to. (space = %zu)\n", space);
debug_data(buf, size);
if (datenklo->auto_rts)
@ -1215,7 +1217,7 @@ static ssize_t dk_write(void *inst, const char *buf, size_t size, int __attribut
if ((datenklo->revents & POLLOUT) && fill >= (size_t)datenklo->tx_fifo_full) {
/* tell cuse not to write */
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Reset POLLOUT (buffer full)\n");
LOGP(DDATENKLO, LOGL_DEBUG, "Reset POLLOUT (buffer full)\n");
datenklo->revents &= ~POLLOUT;
device_set_poll_events(datenklo->device, datenklo->revents);
}
@ -1227,7 +1229,7 @@ static void dk_flush_tx(void *inst)
{
datenklo_t *datenklo = (datenklo_t *)inst;
PDEBUG(DDATENKLO, DEBUG_INFO, "Terminal sends interrupt while writing, flushing TX buffer\n");
LOGP(DDATENKLO, LOGL_INFO, "Terminal sends interrupt while writing, flushing TX buffer\n");
flush_tx(datenklo);
}
@ -1244,7 +1246,7 @@ static void dk_unlock(void)
}
/* signal handler to exit */
void sighandler(int sigset)
static void sighandler(int sigset)
{
if (sigset == SIGHUP)
return;
@ -1257,9 +1259,9 @@ void sighandler(int sigset)
}
/* vtimer */
static void vtime_timeout(struct timer *timer)
static void vtime_timeout(void *data)
{
datenklo_t *datenklo = (datenklo_t *)timer->priv;
datenklo_t *datenklo = data;
/* check if there is enough data to read */
datenklo->vtimeout = 1;
@ -1270,7 +1272,7 @@ static void vtime_timeout(struct timer *timer)
void datenklo_init_global(void)
{
if (pthread_mutex_init(&mutex, NULL)) {
PDEBUG(DDATENKLO, DEBUG_ERROR, "Failed to init mutex.\n");
LOGP(DDATENKLO, LOGL_ERROR, "Failed to init mutex.\n");
exit(0);
}
}
@ -1282,7 +1284,7 @@ int datenklo_init(datenklo_t *datenklo, const char *dev_name, enum am791x_type a
tcflag_t flag;
cc_t *cc;
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Creating Datenklo instance.\n");
LOGP(DDATENKLO, LOGL_DEBUG, "Creating Datenklo instance.\n");
memset(datenklo, 0, sizeof(*datenklo));
@ -1332,7 +1334,7 @@ int datenklo_init(datenklo_t *datenklo, const char *dev_name, enum am791x_type a
datenklo->device = device_init(datenklo, dev_name, dk_open, dk_close, dk_read, dk_write, dk_ioctl_get, dk_ioctl_set, dk_flush_tx, dk_lock, dk_unlock);
if (!datenklo->device) {
PDEBUG(DDATENKLO, DEBUG_ERROR, "Failed to attach virtual device '%s' using cuse.\n", dev_name);
LOGP(DDATENKLO, LOGL_ERROR, "Failed to attach virtual device '%s' using cuse.\n", dev_name);
rc = -errno;
goto error;
}
@ -1342,7 +1344,7 @@ int datenklo_init(datenklo_t *datenklo, const char *dev_name, enum am791x_type a
datenklo->baudrate = cflag2baud(datenklo->termios.c_cflag);
rc = am791x_init(&datenklo->am791x, datenklo, am791x_type, datenklo->mc, datenklo->samplerate, tx_baud_rate(datenklo), rx_baud_rate(datenklo), cts, bcts, cd, bcd, td, btd, rd, brd);
if (rc < 0) {
PDEBUG(DDATENKLO, DEBUG_ERROR, "Failed to initialize AM791X modem chip.\n");
LOGP(DDATENKLO, LOGL_ERROR, "Failed to initialize AM791X modem chip.\n");
goto error;
}
@ -1352,16 +1354,16 @@ int datenklo_init(datenklo_t *datenklo, const char *dev_name, enum am791x_type a
datenklo->tx_fifo = calloc(datenklo->tx_fifo_size, 1);
datenklo->rx_fifo = calloc(datenklo->rx_fifo_size, 1);
if (!datenklo->tx_fifo || !datenklo->rx_fifo) {
PDEBUG(DDATENKLO, DEBUG_ERROR, "No mem!\n");
LOGP(DDATENKLO, LOGL_ERROR, "No mem!\n");
rc = -ENOMEM;
goto error;
}
timer_init(&datenklo->vtimer, vtime_timeout, datenklo);
osmo_timer_setup(&datenklo->vtimer, vtime_timeout, datenklo);
rc = uart_init(&datenklo->uart, datenklo, cflag2databits(datenklo->termios.c_cflag), cflag2parity(datenklo->termios.c_cflag), cflag2stopbits(datenklo->termios.c_cflag), tx, rx);
if (rc < 0) {
PDEBUG(DDATENKLO, DEBUG_ERROR, "Failed to initialize UART.\n");
LOGP(DDATENKLO, LOGL_ERROR, "Failed to initialize UART.\n");
goto error;
}
@ -1395,9 +1397,9 @@ int datenklo_open_audio(datenklo_t *datenklo, const char *audiodev, int buffer,
#ifdef HAVE_ALSA
/* init sound */
datenklo->audio = sound_open(audiodev, NULL, NULL, NULL, channels, 0.0, datenklo->samplerate, datenklo->buffer_size, 1.0, 1.0, 4000.0, 2.0);
datenklo->audio = sound_open(SOUND_DIR_DUPLEX, audiodev, NULL, NULL, NULL, channels, 0.0, datenklo->samplerate, datenklo->buffer_size, 1.0, 1.0, 4000.0, 2.0);
if (!datenklo->audio) {
PDEBUG(DDATENKLO, DEBUG_ERROR, "No sound device!\n");
LOGP(DDATENKLO, LOGL_ERROR, "No sound device!\n");
return -EIO;
}
#endif
@ -1405,28 +1407,28 @@ int datenklo_open_audio(datenklo_t *datenklo, const char *audiodev, int buffer,
if (write_rx_wave) {
rc = wave_create_record(&datenklo->wave_rx_rec, write_rx_wave, datenklo->samplerate, channels, 1.0);
if (rc < 0) {
PDEBUG(DDATENKLO, DEBUG_ERROR, "Failed to create WAVE recoding instance!\n");
LOGP(DDATENKLO, LOGL_ERROR, "Failed to create WAVE recoding instance!\n");
return rc;
}
}
if (write_tx_wave) {
rc = wave_create_record(&datenklo->wave_tx_rec, write_tx_wave, datenklo->samplerate, channels, 1.0);
if (rc < 0) {
PDEBUG(DDATENKLO, DEBUG_ERROR, "Failed to create WAVE recoding instance!\n");
LOGP(DDATENKLO, LOGL_ERROR, "Failed to create WAVE recoding instance!\n");
return rc;
}
}
if (read_rx_wave) {
rc = wave_create_playback(&datenklo->wave_rx_play, read_rx_wave, &datenklo->samplerate, &channels, 1.0);
if (rc < 0) {
PDEBUG(DDATENKLO, DEBUG_ERROR, "Failed to create WAVE playback instance!\n");
LOGP(DDATENKLO, LOGL_ERROR, "Failed to create WAVE playback instance!\n");
return rc;
}
}
if (read_tx_wave) {
rc = wave_create_playback(&datenklo->wave_tx_play, read_tx_wave, &datenklo->samplerate, &channels, 1.0);
if (rc < 0) {
PDEBUG(DDATENKLO, DEBUG_ERROR, "Failed to create WAVE playback instance!\n");
LOGP(DDATENKLO, LOGL_ERROR, "Failed to create WAVE playback instance!\n");
return rc;
}
}
@ -1520,15 +1522,23 @@ void datenklo_main(datenklo_t *datenklo, int loopback)
if (num_chan > 1)
process_auto_rts(datenklo->slave);
/* process timers */
process_timer();
/* Timers may only be processed in main thread, because libosmocore has timer lists for individual threads. */
if (datenklo->vtimer_us < 0)
osmo_timer_del(&datenklo->vtimer);
if (datenklo->vtimer_us > 0)
osmo_timer_schedule(&datenklo->vtimer, datenklo->vtimer_us / 1000000,datenklo->vtimer_us % 1000000);
datenklo->vtimer_us = 0;
am791x_add_del_timers(&datenklo->am791x);
osmo_select_main(1);
#ifdef HAVE_ALSA
count = sound_read(datenklo->audio, samples, datenklo->buffer_size, num_chan, rf_level_db);
if (count < 0) {
PDEBUG(DDSP, DEBUG_ERROR, "Failed to read RX data from audio device (rc = %d)\n", count);
LOGP(DDSP, LOGL_ERROR, "Failed to read RX data from audio device (rc = %d)\n", count);
if (count == -EPIPE) {
PDEBUG(DDATENKLO, DEBUG_ERROR, "Trying to recover!\n");
LOGP(DDATENKLO, LOGL_ERROR, "Trying to recover!\n");
continue;
}
break;
@ -1561,9 +1571,9 @@ void datenklo_main(datenklo_t *datenklo, int loopback)
count = samplerate / 1000;
#endif
if (count < 0) {
PDEBUG(DDSP, DEBUG_ERROR, "Failed to get number of samples in buffer (rc = %d)!\n", count);
LOGP(DDSP, LOGL_ERROR, "Failed to get number of samples in buffer (rc = %d)!\n", count);
if (count == -EPIPE) {
PDEBUG(DDATENKLO, DEBUG_ERROR, "Trying to recover!\n");
LOGP(DDATENKLO, LOGL_ERROR, "Trying to recover!\n");
continue;
}
break;
@ -1611,9 +1621,9 @@ void datenklo_main(datenklo_t *datenklo, int loopback)
/* write audio */
rc = sound_write(datenklo->audio, samples, power, count, NULL, NULL, num_chan);
if (rc < 0) {
PDEBUG(DDSP, DEBUG_ERROR, "Failed to write TX data to audio device (rc = %d)\n", rc);
LOGP(DDSP, LOGL_ERROR, "Failed to write TX data to audio device (rc = %d)\n", rc);
if (rc == -EPIPE) {
PDEBUG(DDATENKLO, DEBUG_ERROR, "Trying to recover!\n");
LOGP(DDATENKLO, LOGL_ERROR, "Trying to recover!\n");
continue;
}
break;
@ -1625,8 +1635,6 @@ next_char:
switch (c) {
case 3:
/* quit */
if (clear_console_text)
clear_console_text();
printf("CTRL+c received, quitting!\n");
quit = 1;
goto next_char;
@ -1655,10 +1663,6 @@ next_char:
pthread_mutex_lock(&mutex);
}
/* get rid of last entry */
if (clear_console_text)
clear_console_text();
/* reset terminal */
tcsetattr(0, TCSANOW, &term_orig);
@ -1668,15 +1672,18 @@ next_char:
signal(SIGTERM, SIG_DFL);
signal(SIGPIPE, SIG_DFL);
display_measurements_on(0);
display_wave_on(0);
pthread_mutex_unlock(&mutex);
}
/* cleanup function */
void datenklo_exit(datenklo_t *datenklo)
{
PDEBUG(DDATENKLO, DEBUG_DEBUG, "Destroying Datenklo instance.\n");
LOGP(DDATENKLO, LOGL_DEBUG, "Destroying Datenklo instance.\n");
timer_exit(&datenklo->vtimer);
osmo_timer_del(&datenklo->vtimer);
/* exit device */
if (datenklo->device)

View File

@ -52,7 +52,8 @@ typedef struct datenklo {
int auto_rts_cts; /* CTS was indicated */
int auto_rts_cd; /* CD was indicated */
int output_off; /* output stopped by flow control */
struct timer vtimer; /* VTIME timer */
struct osmo_timer_list vtimer; /* VTIME timer */
int vtimer_us; /* time to stat / flag to stop */
int vtimeout; /* when timeout has fired */
/* data fifos */

View File

@ -27,7 +27,7 @@
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "../libdebug/debug.h"
#include "../liblogging/logging.h"
#define __USE_GNU
#include <pthread.h>
#include <signal.h>
@ -122,7 +122,7 @@ static void cuse_read_interrupt(fuse_req_t req, void *data)
if (!device->read_locked)
device->lock_cb();
PDEBUG(DDEVICE, DEBUG_DEBUG, "%s received interrupt from client!\n", device->name);
LOGP(DDEVICE, LOGL_DEBUG, "%s received interrupt from client!\n", device->name);
if (device->read_req) {
device->read_req = NULL;
@ -167,7 +167,7 @@ static void cuse_device_read(fuse_req_t req, size_t size, off_t off, struct fuse
if (device->read_req) {
device->unlock_cb();
PDEBUG(DDEVICE, DEBUG_ERROR, "%s: Got another read(), while first read() has not been replied, please fix.\n", device->name);
LOGP(DDEVICE, LOGL_ERROR, "%s: Got another read(), while first read() has not been replied, please fix.\n", device->name);
fuse_reply_err(req, EBUSY);
return;
}
@ -182,7 +182,7 @@ static void cuse_device_read(fuse_req_t req, size_t size, off_t off, struct fuse
/* this means that we block until modem's read() returns 0 or positive value (in nonblocking io, we return -EAGAIN) */
if (!(fi->flags & O_NONBLOCK) && count == -EAGAIN) {
PDEBUG(DDEVICE, DEBUG_DEBUG, "%s has no data available, waiting for data, timer or interrupt.\n", device->name);
LOGP(DDEVICE, LOGL_DEBUG, "%s has no data available, waiting for data, timer or interrupt.\n", device->name);
device->read_req = req;
device->read_size = size;
@ -216,7 +216,7 @@ static void cuse_write_interrupt(fuse_req_t req, void *data)
if (!device->write_locked)
device->lock_cb();
PDEBUG(DDEVICE, DEBUG_DEBUG, "%s received interrupt from client!\n", device->name);
LOGP(DDEVICE, LOGL_DEBUG, "%s received interrupt from client!\n", device->name);
if (device->write_req) {
device->write_req = NULL;
@ -262,7 +262,7 @@ static void cuse_device_write(fuse_req_t req, const char *buf, size_t size, off_
if (device->write_req) {
device->unlock_cb();
PDEBUG(DDEVICE, DEBUG_ERROR, "%s: Got another write(), while first write() has not been replied, please fix.\n", device->name);
LOGP(DDEVICE, LOGL_ERROR, "%s: Got another write(), while first write() has not been replied, please fix.\n", device->name);
fuse_reply_err(req, EBUSY);
return;
}
@ -271,13 +271,13 @@ static void cuse_device_write(fuse_req_t req, const char *buf, size_t size, off_
/* this means that we block until modem's write() returns 0 or positive value (in nonblocking io, we return -EAGAIN) */
if (!(fi->flags & O_NONBLOCK) && count == -EAGAIN) {
PDEBUG(DDEVICE, DEBUG_DEBUG, "%s has no buffer space available, waiting for space or interrupt.\n", device->name);
LOGP(DDEVICE, LOGL_DEBUG, "%s has no buffer space available, waiting for space or interrupt.\n", device->name);
device->write_req = req;
device->write_size = size;
device->write_buf = malloc(size);
if (!buf) {
PDEBUG(DDEVICE, DEBUG_ERROR, "No memory!\n");
LOGP(DDEVICE, LOGL_ERROR, "No memory!\n");
exit(0);
}
memcpy(device->write_buf, buf, size);
@ -376,7 +376,7 @@ static void cuse_device_ioctl(fuse_req_t req, int cmd, void *arg, struct fuse_fi
}
break;
default:
PDEBUG(DDEVICE, DEBUG_NOTICE, "%s: receives unknown ioctl: 0x%x\n", device->name, cmd);
LOGP(DDEVICE, LOGL_NOTICE, "%s: receives unknown ioctl: 0x%x\n", device->name, cmd);
fuse_reply_err(req, EINVAL);
}
}
@ -432,7 +432,7 @@ static void cuse_device_flush(fuse_req_t req, struct fuse_file_info *fi)
(void)req;
(void)fi;
device_t *device = get_device_by_thread();
PDEBUG(DDEVICE, DEBUG_NOTICE, "%s: unhandled flush\n", device->name);
LOGP(DDEVICE, LOGL_NOTICE, "%s: unhandled flush\n", device->name);
}
static void cuse_device_fsync(fuse_req_t req, int datasync, struct fuse_file_info *fi)
@ -441,7 +441,7 @@ static void cuse_device_fsync(fuse_req_t req, int datasync, struct fuse_file_inf
(void)datasync;
(void)fi;
device_t *device = get_device_by_thread();
PDEBUG(DDEVICE, DEBUG_NOTICE, "%s: unhandled fsync\n", device->name);
LOGP(DDEVICE, LOGL_NOTICE, "%s: unhandled fsync\n", device->name);
}
@ -467,7 +467,7 @@ static void *device_child(void *arg)
const char *dev_info_argv[] = { dev_name };
struct cuse_info ci;
strncat(dev_name, device->name, sizeof(dev_name) - strlen(device->name) - 1);
strncat(dev_name, device->name, sizeof(dev_name) - strlen(dev_name) - 1);
memset(&ci, 0, sizeof(ci));
ci.dev_major = device->major;
@ -478,9 +478,9 @@ static void *device_child(void *arg)
device->thread_started = 1;
PDEBUG(DDEVICE, DEBUG_INFO, "Device '%s' started.\n", device->name);
LOGP(DDEVICE, LOGL_INFO, "Device '%s' started.\n", device->name);
cuse_lowlevel_main(argc, argv, &ci, &cuse_device_clop, NULL);
PDEBUG(DDEVICE, DEBUG_INFO, "Device '%s' terminated.\n", device->name);
LOGP(DDEVICE, LOGL_INFO, "Device '%s' terminated.\n", device->name);
device->thread_stopped = 1;
@ -496,7 +496,7 @@ void *device_init(void *inst, const char *name, int (*open)(void *inst, int flag
device = calloc(1, sizeof(*device));
if (!device) {
PDEBUG(DDEVICE, DEBUG_ERROR, "No memory!\n");
LOGP(DDEVICE, LOGL_ERROR, "No memory!\n");
errno = ENOMEM;
goto error;
}
@ -514,13 +514,13 @@ void *device_init(void *inst, const char *name, int (*open)(void *inst, int flag
rc = pthread_create(&device->thread, NULL, device_child, device);
if (rc < 0) {
PDEBUG(DDEVICE, DEBUG_ERROR, "Failed to create device thread!\n");
LOGP(DDEVICE, LOGL_ERROR, "Failed to create device thread!\n");
errno = -rc;
goto error;
}
pthread_getname_np(device->thread, tname, sizeof(tname));
strncat(tname, "-device", sizeof(tname) - 7 - 1);
strncat(tname, "-device", sizeof(tname) - strlen(tname) - 1);
tname[sizeof(tname) - 1] = '\0';
pthread_setname_np(device->thread, tname);

Some files were not shown because too many files have changed in this diff Show More