ODR-DabMux-4.4.1/ 0000755 0001750 0001750 00000000000 14465705070 012336 5 ustar robin robin ODR-DabMux-4.4.1/NEWS 0000644 0001750 0001750 00000000000 14465705070 013023 0 ustar robin robin ODR-DabMux-4.4.1/LICENCE 0000644 0001750 0001750 00000002457 14465705070 013333 0 ustar robin robin LICENSING
=========
Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Her Majesty
the Queen in Right of Canada (Communications Research Center Canada)
Copyright (C) 2020
Matthias P. Braendli, http://www.opendigitalradio.org
This file is part of ODR-DabMux. ODR-DabMux is a fork of CRC-DabMux,
which was developed by the Communications Research Center Canada.
ODR-DabMux 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.
ODR-DabMux 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 ODR-DabMux. If not, see .
KA9Q FEC routines
-----------------
lib/fec/ contains code from KA9Q's fec library. Please see
lib/fec/README.md and lib/fec/LICENSING
Other parts
-----------
lib/edi/PFT.{hpp,cpp} are APACHE 2.0 licensed.
lib/charset contains a BSD-licensed UTF-8 library.
lib/zmq.hpp is BSD-licensed.
The farsync driver in lib/farsync is GPLv2+ licensed.
ODR-DabMux-4.4.1/INSTALL.md 0000644 0001750 0001750 00000007174 14465705070 013777 0 ustar robin robin You have 3 ways to install odr-dabmux on your host:
# Using binary debian packages
If your host is running a debian-based OS and its cpu is one of amd64, arm64 or arm/v7, then you can install odr-dabmux using the standard debian packaging system:
1. Update the debian apt repository list:
```
curl -fsSL http://debian.opendigitalradio.org/odr.asc | sudo tee /etc/apt/trusted.gpg.d/odr.asc 1>/dev/null
curl -fsSL http://debian.opendigitalradio.org/odr.list | sudo tee /etc/apt/sources.list.d/odr.list 1>/dev/null
```
1. Refresh the debian packages list:
```
apt update
```
1. Install odr-audioenc:
```
sudo apt install --yes odr-dabmux
```
**Attention**: odr-dabmux (4.2.1-1) does not include the Mux Web Management GUI
# Using the dab-scripts
You can compile odr-dabmux as well as the other main components of the mmbTools set with an installation script:
1. Clone the dab-scripts repository:
```
git clone https://github.com/opendigitalradio/dab-scripts.git
```
1. Follow the [instructions](https://github.com/Opendigitalradio/dab-scripts/tree/master/install)
# Compiling manually
Unlike the 2 previous options, this one allows you to compile odr-dabmux with the features you really need.
## Dependencies
### Debian Bullseye-based OS:
```
# Required packages
## C++11 compiler
sudo apt-get install --yes build-essential automake libtool
## ZeroMQ
sudo apt-get install --yes libzmq3-dev libzmq5
## Boost 1.48 or later
sudo apt-get install --yes libboost-system-dev
# optional packages
## cURL to download the TAI-UTC bulletin, needed for timestamps in EDI output
sudo apt-get install --yes libcurl4-openssl-dev
```
### Dependencies on other linux distributions
For CentOS, in addition to the packages needed to install a compiler, install the packages:
boost-devel libcurl-devel zeromq-devel
Third-party RPM packages are maintained by RaBe, and are built by the
[openSUSE Build Service](https://build.opensuse.org/project/show/home:radiorabe:dab).
For questions regarding these packages, please get in touch with the maintainer of
the [radio RaBe repository](https://github.com/radiorabe/).
For openSUSE, mnhauke is maintaining packages, also built using
[OBS](https://build.opensuse.org/project/show/home:mnhauke:ODR-mmbTools).
## Compilation
The *master* branch in the repository always points to the
latest release. If you are looking for a new feature or bug-fix
that did not yet make its way into a release, you can clone the
*next* branch from the repository.
1. Clone this repository:
```
# stable version:
git clone https://github.com/Opendigitalradio/ODR-DabMux.git
# or development version (at your own risk):
git clone https://github.com/Opendigitalradio/ODR-DabMux.git -b next
```
1. Configure the project
```
cd ODR-DabMux
./bootstrap
./configure
```
1. Compile and install:
```
make
sudo make install
```
Notes:
- It is advised to run the bootstrap and configure steps again every time you pull updates from the repository.
- The configure script can be launched with a variety of options. Run `./configure --help` to display a complete list
# Develop on OSX and FreeBSD
If you want to develop on OSX platform install the necessary build tools
and dependencies with brew
brew install boost zeromq automake curl
On FreeBSD, pkg installs all dependencies to /usr/local, but the build
tools will not search there by default. Set the following environment variables
before calling ./configure
LDFLAGS="-L/usr/local/lib"
CFLAGS="-I/usr/local/include"
CXXFLAGS="-I/usr/local/include"
On both systems, RAW output is not available. Note that these systems
are not tested regularly.
ODR-DabMux-4.4.1/doc/ 0000755 0001750 0001750 00000000000 14465705070 013103 5 ustar robin robin ODR-DabMux-4.4.1/doc/remote_control.txt 0000644 0001750 0001750 00000010614 14465705070 016701 0 ustar robin robin Telnet Remote Control
=====================
ODR-DabMux can be configured to set up a simple telnet remote control that can
be used to modify some parameters without restarting the multiplexer. The same
functionality available through telnet is also available over a ZeroMQ REQ/REP
socket, to make automation easier.
The server only listens on localhost for security reasons. Remote access should
be done using a VPN or SSH port forwarding.
The principle is that parts of ODR-DabMux which have modifiable parameters
register themselves as remote-controllable modules, and also register
parameters. Each parameter has a value, that can be read/written using the
get/set commands.
The interface is quite simple, and supports the following commands:
> help
list
* Lists the modules that are loaded and their parameters
show MODULE
* Lists all parameters and their values from module MODULE
get MODULE PARAMETER
* Gets the value for the specified PARAMETER from module MODULE
set MODULE PARAMETER VALUE
* Sets the value for the PARAMETER ofr module MODULE
quit
* Terminate this session
Example
=======
In this example, there is one service whose unique id (set in the configuration
file) is 'srv-fb', one subchannel with uid 'sub-fb' and one component 'comp-fb'.
The command 'list' will show all exported parameters, and a small description:
> list
srv-fb
label : Label and shortlabel [label,short]
sub-fb
buffer : Size of the input buffer [aac superframes]
enable : If the input is enabled. Set to zero to empty the buffer.
comp-fb
label : Label and shortlabel [label,short]
The indication in square brackets can help you understand the format of the
values, or the units used. e.g. for AAC subchannels, the 'buffer' parameter
has values that are counted in number of AAC superframes. It is implicit that a
number is meant.
In contrast to this, the 'label' parameters of both services and components take
a "label,short-label" pair, separated by a comma.
Binary values accept the value 0 as false, and 1 as true.
Remarks concerning specific modules
===================================
ZMQ input
---------
The ZMQ input (both for MPEG and AAC+) export a 'buffer' parameter which
defines how many frames must be in the buffer *before* the input starts
streaming.
If you increase the size of the buffer, it will not fill up by itself (unless
there is a clock drift between the mux and the encoder).
In order to force the buffer to fill up, disable the input by setting 'enable'
to 0, and, once the buffer is empty, re-enable it. It will fill to the desired
value.
Labels (Components and Services)
--------------------------------
The restrictions on short-labels, namely that they can only consist of letters
appearing in the labels, and that they must be maximum 8 characters long, are
verified by the 'label' parameters.
If you try to set an invalid label/short-label combination, you will get an
error, and the label is unchanged:
example:
> set comp-fb label Programme1,prog1
comp-fb short label prog1 is not subset of label 'Programme1'
example:
> set comp-fb label Programme1,Programme
comp-fb short label Programme is too long (max 8 characters)
Announcements
-------------
Announcements can be triggered by the remote control in two ways. For a
specific announcement, its active parameter can be toggled which will
immediately signal it accordingly. Or the start time or stop time can be set to
trigger signalling changes in the future.
Direct setting:
> set my_announcement active 1
ok
Deferred setting:
The "start_in" and a "stop_in" parameters both accept a value in milliseconds.
They can either be set, and when you read them back you will see the timeout go
down to zero; or they can be "not set" if you never set them or if the timeout
expired. It is also possible to set both "start_in" and "stop_in" to trigger
both a start and stop in the future.
The timeout expiry will then influence the "active" parameter internally, ensuring
that the "active" parameter always represents the current state of the
signalling.
> set my_announcement start_in 10000
ok
> show my_announcement
active: 0
start_in: 7313
stop_in: Not set
> show my_announcement
active: 0
start_in: 1244
stop_in: Not set
> show my_announcement
active: 1
start_in: Not set
stop_in: Not set
ODR-DabMux-4.4.1/doc/servicelinking.mux 0000644 0001750 0001750 00000016133 14465705070 016656 0 ustar robin robin ; This is an example configuration file that illustrates
; how to define service linking
; More information about the usage of the tools is available
; in the guide, which can be found on the
; www.opendigitalradio.org website.
;
general {
dabmode 1
nbframes 20000
syslog false
tist false
managementport 12720
}
remotecontrol {
telnetport 12721
}
; Service linking sets
linking {
; Every child section declares one linkage sets according to
; TS 103 176 Clause 5.2.3 "Linkage sets". This information will
; be encoded in FIG 0/6
set-fu {
; Linkage Set Number is a 12-bit number that identifies the linkage set
; in a country (requires coordination between multiplex operators in a country)
; (mandatory)
lsn 0xabc
; Hard link means that all services carry the same programme, soft links means
; that the programmes are related in some way. (default true)
hard true
; Linkage actuator flag. Set to false to disable a link
active true
; Whether this linkage set affects only one country or several. Linkage sets that
; include AMSS or DRM services need to have this set to true. (default false)
; Linkage sets whose key service has a different ECC than the ensemble ECC need to
; set this to true.
international false
; If the keyservice and list are absent, a FIG with an empty list will be transmitted for
; this linkage set. This instructs receivers to delete their corresponding database entry
; (Change Event Indicator for FIG0/6)
; Every linkage set has to contain a service from the current ensemble. keyservice may be omitted.
keyservice srv-fu
; List of services to be included (mandatory if keyservice given)
list {
; Every service has a uid that can be used as a human-readable description
; The first example is a link to a DAB service on another ensemble.
fu-on-my-friends-mux {
; Possible options: dab, fm, drm, amss (mandatory)
type dab
; if type is dab, the id is a DAB service ID (mandatory)
id 0x8daf
; Since this link set has international false, we do not need to specify
; the ECC. With internation true, the following would be needed
; (mandatory if internation true)
;ecc 0xec
}
; The second example is a link to an FM transmission
fu-on-fm {
; Possible options: dab, fm, drm, amss
type fm
; if type is fm, the id is a PI-code
id 0x1A2B
; Also here, ECC declaration is not required
}
}
}
; And now an international true to test more options
set-ri {
lsn 0xdef
hard soft
international true
keyservice srv-ri
list {
ri-on-drm {
type drm
id 0x1298
ecc 0xec
}
ri-on-amss {
type amss
id 0x1A2B
ecc 0xea
}
ri-on-fm {
type fm
id 0x4C5D
ecc 0x4f
}
}
}
}
; According to ETSI TR 101 496-2 Clause 3.6.10.
; Each entry corresponds to one frequence information
; database entry. The multiplexer then transmits this
; information inside FIG 0/21 defined in
; ETSI EN 300 401 Clause 8.1.8
frequency_information {
fi_dab_4fff {
; The database key comprises oe, range_modulation and
; either eid, pi_code, drm_id or amss_id.
; The database key must be unique among all the fi entries.
; RegionId and signalling FI for data services are not implemented.
oe false
range_modulation dab
eid 0x4fff
continuity true
frequencies {
freq_a {
signal_mode_1 true
adjacent true
frequency 234.208
}
freq_b {
signal_mode_1 true
adjacent true
frequency 188.928
}
freq_c {
signal_mode_1 true
adjacent false
frequency 230.784
}
}
}
fi_fm_1234 {
oe false
range_modulation fm
pi_code 0x1234
continuity true
frequencies "87.6 105.2"
}
fi_dab_4fee {
oe true
range_modulation dab
eid 0x4fee
continuity true
frequencies {
freq_a {
signal_mode_1 true
adjacent false
frequency 230.784
}
}
}
fi_drm_12ab45 {
oe false
range_modulation drm
drm_id 0x12ab45
continuity true
frequencies "15.21 22.4"
}
fi_amss_33cc88 {
range_modulation amss
amss_id 0x33cc88
continuity true
frequencies "14.8"
}
}
; We can announce the presence of a service in another ensemble using FIG0/24,
; both for services we carry in this ensemble (OE=0) and for services that
; only exist in another ensemble (OE=1)
other-services {
; you can freely chose the unique id
srv-fu {
; If this ensemble contains a service with this id, OE will be set to 0.
; Otherwise, OE=1
id 0x8daa
; If this service is present in other ensembles, it can be announced
; through FIG0/24. other_ensembles is a comma separated list of
; ensemble IDs (decimal or hexadecimal with 0x prefix).
; Add the current ensemble Id to the list if you carry this service too.
other_ensembles "0x4ffe,0x4ffd,0x4fff"
}
; For a more efficient usage of the FIC capacity, it is better to first enumerate
; the services that we carry in the ensemble (OE=0), followed by the foreign services.
; This avoids having to send FIG0 headers every time the OE flag switches.
srv-foreign {
id 0x8daf
other_ensembles "0x4ffd"
; Only Audio type services are supported
}
}
; For information about the ensemble, service, subchannels, components and outputs,
; please see doc/example.mux and doc/advanced.mux
ensemble {
id 0x4fff
ecc 0xec
local-time-offset auto
label "OpenDigitalRadio"
shortlabel "ODR"
}
services {
srv-fu {
id 0x8daa
label "Funk"
}
srv-ri {
id 0x8dab
label "Rick"
}
}
subchannels {
sub-fu {
type dabplus
inputfile "tcp://*:9000"
bitrate 96
id 1
protection 3
zmq-buffer 40
zmq-prebuffering 20
}
sub-ri {
type dabplus
inputfile "tcp://*:9001"
bitrate 96
id 2
protection 3
zmq-buffer 40
zmq-prebuffering 20
}
}
components {
comp-fu {
service srv-fu
subchannel sub-fu
}
comp-ri {
service srv-ri
subchannel sub-ri
}
}
outputs {
file "file://./test.eti?type=raw"
;throttle "simul://"
}
ODR-DabMux-4.4.1/doc/STATS.md 0000644 0001750 0001750 00000002375 14465705070 014332 0 ustar robin robin Stats available through Management Server
=========================================
Interface
---------
The management server makes statistics about the inputs available through a ZMQ request/reply socket.
The `show_dabmux_stats.py` illustrates how to access this information.
Meaning of values
-----------------
`max` and `min` indicate input buffer fullness in bytes.
`under` and `over` count the number of buffer underruns and overruns.
`audio L` and `audio R` show the maximum audio level in dBFS over the last 500ms.
`peak L` and `audio R` show the max audio level in dBFS over the last 5 minutes.
The audio levels are measured in the audio encoder and carried in the EDI
`ODRa` TAG, or in the ZMQ metadata. Otherwise ODR-DabMux would have to decode
all audio contributions to measure the audio level.
`State` is either NoData, Unstable, Silence, Streaming.
Unstable means that underruns or overruns have occurred in the previous 30 minutes.
Silence means the stream is working, but audio levels are always below -50dBFS.
`version` and `uptime` are fields directly coming from the contribution source,
and are only supported for the EDI input. These are carried over EDI using custom
TAG `ODRv` (see function `parse_odr_version_data` in `lib/edi/common.cpp`).
ODR-DabMux-4.4.1/doc/advanced.mux 0000644 0001750 0001750 00000046163 14465705070 015415 0 ustar robin robin ; This is an advanced configuration example for ODR-DabMux,
; that documents more options that the simple example.mux
; More information about the usage of the tools is available
; in the guide, which can be found on the
; www.opendigitalradio.org website.
;
; The format is called INFO format, and defined by boost property_tree:
; http://www.boost.org/doc/libs/1_41_0/doc/html/boost_propertytree/parsers.html#boost_propertytree.parsers.info_parser
; It consists of six mandatory sections, whose relative order in this
; file are of no importance.
; The general section defines global multiplex parameters.
general {
; the DAB Transmission mode (values 1-4 accepted)
dabmode 1
; the number of ETI frames to generate (set to 0 to get an unlimited number)
nbframes 10
; boolean fileds can accept either false or true as values:
; Enable logging to syslog
syslog false
; Write the SCCA field useful for the Factum ETI analyser
writescca false
; Enable timestamp definition necessary for SFN
; This also enables time encoding using the MNSC and in EDI.
tist false
; On startup, the timestamp is initialised to system time. If you want
; to add an offset, uncomment the following line and give a number
; in seconds.
; tist_offset 0
; The management server is a simple TCP server that can present
; statistics data (buffers, overruns, underruns, etc)
; which can then be graphed a tool like Munin
; The doc/stats_dabmux_multi.py tool is a suitable
; plugin for that. The data fields are documented in doc/STATS.md
; If the port is zero, or the line commented, the server
; is not started.
managementport 12720
}
remotecontrol {
; enable the telnet remote control server on the given port
; This server allows you to read and define parameters that
; some features export. It is only accessible from localhost.
; Set the port to 0 to disable the server
telnetport 12721
; the remote control server makes use of the unique identifiers
; for the subchannels, services and components. Make sure you
; chose them so that you can identify them.
}
; Some ensemble parameters
ensemble {
; Example for Switzerland, with country id=4 and ECC=E1
id 0x4fff ; you can also use decimal if you want
ecc 0xe1 ; Extended Country Code
local-time-offset auto ; autmatically calculate from system local time
; or
;local-time-offset 1 ; in hours, supports half-hour offsets
international-table 1 ; See TS 101 756 clause 5.7
; 1 corresponds to the PTy used in RDS
; 2 corresponds to program types used in north america
; Enable FIG0/7, which specifies that the ensemble is compliant to EN 300 401 version 2.
; For more options see doc/advanced.mux
reconfig-counter hash
; all labels are maximum 16 characters in length
label "OpenDigitalRadio"
; The short label is built from the label by erasing letters, and cannot
; be longer than 8 characters. If omitted, it will be truncated from the
; label
shortlabel "ODR"
; Announcement settings for FIG0/19.
announcements {
test_announcement {
cluster 1
flags {
Traffic true
}
subchannel sub-fu
}
}
}
; Definition of DAB services
services {
; Each service has it's own unique identifier, that is
; used throughout the configuration file and for the RC.
srv-fu {
id 0x4daa
label "Funk"
shortlabel "Fu"
; Programme Type, according to the chosen international-table above.
pty 0
; chose between static and dynamic PTy
; static means the PTy represents to overall genre of the programme.
; dynamic means the PTy follows the various items within a programme.
; Use the RC interface to modify at runtime.
; See EN 300 401 Clause 8.1.5
pty-sd static
language 0
; also supports id
; List of announcement switching flags signalled in FIG 0/18
; This lists all possible announcements. If one is left out, it is disabled.
announcements {
Alarm false
Traffic true
Travel false
Warning false
News false
Weather false
Event false
Special false
ProgrammeInfo false
Sports false
Finance false
; a comma separated list of clusters in which the service belongs to
; cluster id 255 is not specified here and is ignored (for FIG 0/18)
clusters "1,2"
}
}
srv-ri {
; If your ensemble contains a service from another country,
; specify its ECC here. Example is for Italy, country id=5, ECC=E0
id 0x5dab
ecc 0xe0
label "rick"
}
srv-lu {
id 0x4dac
label "Lu"
; pty, language, shortlabel and id can be omitted, and will take default values
}
}
; The subchannels are defined in the corresponding section.
; supported types are : audio, data, enhancedpacket,
; dabplus, packet
;
; Type 'packet' expects to receive data in the format described
; in EN 300 401 Clause 5.3.2.
;
; 'enhancedpacket' mode will calculate FEC for MSC packet mode
; as described in EN 300 401 Clause 5.3.5.
;
; 'data' will read from the source and write it unmodified into
; the MSC.
subchannels {
sub-fu {
type audio
bitrate 128
id 10
; type audio subchannels automatically use
; UEP, unless the bitrate is 8, 16, 24, 40 or 144kbit/s
; (EN 300 401 Clause 6.2.1)
; this can be overridden with the option protection-profile
protection-profile EEP_A
; supported options: UEP (use only for type audio!)
; EEP_A (for all bitrates)
; EEP_B (bitrates multiple of 32kbit/s)
; Set the protection level, possible values depend
; on the protection profile:
; UEP profile: 1 to 5; EEP profiles: 1 to 4
protection 4
; example file input
inputproto file
inputuri "funk.mp2"
nonblock false
}
sub-lu {
type dabplus
bitrate 96
id 3
protection 3
; EXPERIMENTAL!
; Receive STI-D(LI) carried in STI(PI, X) inside RTP using UDP.
; This is intended to be compatible with AVT audio encoders.
; EXPERIMENTAL!
inputproto sti
inputuri "rtp://127.0.0.1:32010"
}
sub-ri {
type dabplus
bitrate 96
id 1
protection 1
; example file input
;inputuri "rick.dabp"
; example zmq input:
; Accepts connections to port 9000 from any interface.
inputproto zmq
inputuri "tcp://*:9000"
; ZMQ specific options, mandatory:
; Maximum size of input buffer, in AAC frames (24ms)
; when this buffer size is reached, some frames will be
; discarded to get the size again below this value.
; As the present implementation discards entire AAC superframes,
; (5 frames = 120ms) the effect will clearly be audible.
zmq-buffer 40
; At startup or after an underrun, the buffer is filled to this
; amount of AAC frames before streaming starts.
zmq-prebuffering 20
; In an ideal scenario, where the input rate exactly corresponds
; to the rate at which the frames are consumed by dabmux, you
; see the buffer level staying around the zmq-prebuffering value.
; Network latency jitter can make it temporarily go lower or higher.
; Encoder clock drift will make the buffer either slowly fill or
; empty, which will create intermittent glitches.
; the ZMQ inputs support encryption using the CURVE method.
; The multiplexer must have a public and a private key, which
; can be shared among several zmq inputs.
;
; each encoder also has a public and private key, and the
; encoder *public* key has to be known to the multiplexer.
; Using this system, the multiplexer can be sure that
; only the encoder possessing the right secret key can
; connect here. This inhibits third parties to hijack the
; input.
; by default, it is disabled, set encryption to 1 to enable
encryption true
; the multiplexer key pair. Keep these secret.
secret-key "keys/mux.sec"
public-key "keys/mux.pub"
; The public key from the encoder. Only the encoder you want
; to accept must know the corresponding secret key.
encoder-key "keys/encoder1.pub"
; key pairs can be generated using the zmqinput-keygen tool.
}
; 'prbs' will generate a pseudorandom bit sequence according to
; ETS 300 799 Clause G.2.1. This is useful for testing purposes and
; measurement of bit error rate.
sub-prbs {
type data
bitrate 16
id 5
protection 3
; Use the default PRBS polynomial.
inputproto prbs
inputuri "prbs://"
; To use another polynomial, set it in the url as hexadecimal
; The default polynomial is G(x) = x^20 + x^17 + 1, represented as
; (1 << 20) + (1 << 17) + (1 << 0) = 0x120001
;inputuri "prbs://:0x120001
}
; An example using 'enhancedpacket' to send out epg data
; See http://wiki.opendigitalradio.org/How_to_configure_SPI_(Service_and_Programme_Information)_for_ODR-DabMux
sub-data {
id 6
type enhancedpacket
; Settings this flag to true makes ODR-DabMux preload the entire file contents into memory
; This allows you to replace the file contents while the current file data still gets transmitted to the
; end.
load_entire_file true
inputfile "./epg.dat"
protection 1
bitrate 32
}
}
; For now, each component links one service to one subchannel
components {
; the component unique identifiers are used for the RC.
comp-fu {
; specifies audio -or- packet type, defaults to zero when not given
; audio: foreground=0, background=1, multi-channel=2
; data: unspecified=0, TMC=1, EWS=2, ITTS=3, paging=4, TDC=5, IP=59, MOT=60, proprietary=61
type 0
; According to specification, you should not define component labels if
; the service is only used in one component. The service label is sufficient
; in that case.
;label "funk"
;shortlabel "fu"
service srv-fu
subchannel sub-fu
; FIG 0/13 user application was previously configured using the figtype setting, which
; allowed only a single user application.
; Now more than one user application can be defined per component, using the
; Using the 'user-applications' section, several can be defined per component.
; Do not use both figtype and user-applications.
; If both slideshow (TS 101 499) and SPI (TS 102 818) are carried in PAD, the following
; needs to be set for FIG 0/13 to be transmitted correctly.
; The same section is also applicable to packet services.
user-applications {
; Add uaType 0x2 with X-PAD App Type = 12 and empty user application data
userapp "slideshow"
; Add uaType 0x7 with X-PAD App Type = 16 and user application data = "Basic profile"
userapp "spi"
; Broadcast website, add uaType 0x3 and user application data
; 0x01 "basic integrated receiver profile" and
; 0xFF "unrestricted profile"
; Only for packet-mode, not X-PAD.
userapp "website"
}
; Deprecated figtype setting:
figtype 0x2
; defines the User Application Type according to TS 101 756 Table 16:
; 0x2 : MOT Slideshow
; 0x3 : MOT Broadcast Web Site
; 0x4 : TPEG
; 0x5 : DGPS
; 0x6 : TMC
; 0x7 : EPG
; 0x8 : DAB Java
; 0x44a : Journaline
; If not defined, the FIG 0/13 is not transmitted for this component
; for packet components, set the packet address (mandatory)
;address
; Whether to use data groups
;datagroup false
; (defaults to false)
; You should normally set 'datagroup true'
; if your packet mode subchannel is transferring an MOT application such
; as SPI/EPG or Slideshow.
; If you specify the user-application "spi", FIG0/13 will set the user application data to "basic profile"
}
; If a service is used in more than one component, the primary component has to
; be placed above the secondary component(s) to ensure that the SCIdS field of FIG0/8
; is zero for the primary service component. (New in EN 300 401 V2.1.1)
comp-lu {
service srv-lu
subchannel sub-lu
user-applications {
userapp "slideshow"
}
}
comp-ri {
service srv-ri
subchannel sub-ri
user-applications {
userapp "slideshow"
}
}
}
outputs {
; The unique-id can be used by the remote control or the statistics server
; to identify the output
; Important! For real-time operation, you need to have exactly one
; output that applies back-pressure to ODR-DabMux, otherwise it will run
; at the highest possible rate on your system!
;
; For an output to a pipe, the data consumer at the other end of the pipe
; will dictate the multiplexing rate to ODR-DabMux.
;
; If you use the zmq or EDI outputs, you must also enable a simul:// output!
;supported output types for file and fifo outputs are
; raw, framed and streamed
;
; Please see doc/dab_output_formats.txt
;stdout "fifo:///dev/stdout?type=raw"
; Throttle output to real-time (one ETI frame every 24ms)
throttle "simul://"
edi {
; If TIST is enabled, requires leap-second information (see example.mux)
destinations {
; The names you give to the destinations have no meaning,
; but have to be unique. You can give them meaningful names to help
; you identify the outputs.
example_unicast {
; example for unicast EDI over UDP
; for unicast EDI, do not set source
protocol udp
sourceport 13000
destination "192.168.23.23"
port 12000
; For compatibility: if port is not specified in the destination itself,
; it is taken from the parent 'destinations' block.
}
example_multicast {
; example for multicast EDI, the source IP is required
; so that the data is sent on the correct ethernet interface
protocol udp
source "192.168.0.50"
sourceport 13000
destination "232.20.10.1"
port 12000
; The multicast TTL has to be adapted according to your network
ttl 1
}
example_tcp {
; example for EDI TCP server. TCP is reliable, so it is counterproductive to
; use FEC. Using PFT also brings no benefit.
protocol tcp
listenport 13000
; For every connected endpoint, a queue is created. If the queue overflows, we
; assume the endpoint has a problem, and we close the connection. This sets
; the max queue size in number of frames. With PFT disabled, one frame is generated
; every 24ms. With PFT enabled, it depends on fragmentation and FEC settings.
;
; default value: 500 frames, without PFT: 12s worth of EDI data
;max_frames_queued 500
}
}
; The settings below apply to all destinations
; Enable the PFT subsystem. If false, AFPackets are sent.
; PFT is not necessary when using TCP.
enable_pft false
; How many lost fragments can be recovered by Reed-Solomon.
; Requires enable_pft true.
;
; If set to 0, the PFT subsystem will only do Fragmentation and
; Transport, but no Reed Solomon.
; See ETSI TS 102 821, Clause 7 "PFT Layer", Figure 10. ODR-DabMux
; supports "Fragmentation and Transportation" and "Reed-Solomon and
; Transportation".
fec 2
; Spread and interleave fragments from several EDI frames so as to reduce the
; probability of errors when several UDP packets are lost in bursts.
; This comes at the cost of larger overall latency between multiplexing
; and modulation.
;
; Configure the packet spreader/interleaver through a percentage:
; 0% send all fragments at once,
; 100% spread over 24ms,
; >100% spread and interleave. Default 95%
packet_spread 95
; Length of a RS chunk, can be overridden
;default=207
;chunk_len 207
; Save the packets sent over Ethernet to the file ./edi.debug
dump false
; show more debugging info
verbose false
; (optional) set the kind of alignment to use in TAG Packets
; 0: no padding
; 8: pad to eight bytes (default)
; above 8: insert *dmy TAG Item to pad to given size in bytes
;tagpacket_alignment 8
}
; Other outputs:
; ZeroMQ output example, new configuration format. Several
; zeromq blocks can be added here.
; This output does not back-pressure the multiplexer.
;zeromq {
; Listen on all interfaces, on port 9100
;endpoint "tcp://*:9100"
; Transmit backward compatible metadata containing
; EDI time and UTC offset when TIST is enabled.
;
; If TIST is enabled, requires leap-second information (see example.mux)
;
; WARNING! requires ODR-DabMux to be compiled with
; cURL support, and this will enable leap second download
; as for the EDI output!
;allowmetadata true
;}
; Legacy format for ZeroMQ output example. See example.mux
; for newer format.
;zmq "zmq+tcp://*:9100"
; Output ETI-over-TCP. This is like piping a RAW ETI NI data stream
; into a TCP socket, except that the output can handle simultaneous
; connections. Not suitable for SFN use because timestamps are incomplete.
; 0.0.0.0 means "listen on all interfaces"
; This output does not back-pressure the multiplexer.
;tcp "tcp://0.0.0.0:9200"
; UDP send to host:port, simple example for unicast
;net_udp "udp://host:port"
; example with source and TTL specification for multicast
;net_udp "udp://237.10.0.230:7000?src=10.0.1.125&ttl=1"
; RAW for farsync ETI card
;farsync "raw://sync0"
; the output also supports two parameters:
; clocking=master and clocking=slave
;
; and extsyncclock which enables external clock sync. Its value is the
; external clock frequency in Hz.
; Example:
;farsync "raw://sync0?clocking=master&extsyncclock=10000000"
}
ODR-DabMux-4.4.1/doc/example.mux 0000644 0001750 0001750 00000030007 14465705070 015271 0 ustar robin robin ; This is an example configuration file that illustrates
; the structure of the configuration.
; It doesn't show all possible options. A more detailed example
; is available in doc/advanced.mux
;
; The configuration file can also be given in JSON format, an
; example is given in doc/example.json
;
; It contains two services, one DAB and one DAB+, and also shows
; both the file input useful for offline processing, and the
; EDI input useful in a 24/7 scenario.
; More information about the usage of the tools is available
; in the guide, which can be found on the
; www.opendigitalradio.org website.
;
; As you can see, comments are defined by semicolons.
;
; It consists of six mandatory sections, whose relative order in this
; file are of no importance.
; The general section defines global multiplex parameters.
general {
; the DAB Transmission mode (values 1-4 accepted)
dabmode 1
; the number of ETI frames to generate (set to 0 to get an unlimited number)
nbframes 10
; boolean fields can accept either false or true as values:
; Set to true to enable logging to syslog
syslog false
; Enable timestamp definition necessary for SFN
; This also enables time encoding using the MNSC.
;
; When TIST is enabled, and either EDI or a ZMQ output with metadata is used,
; ODR-DabMux will download leap-second information from the IETF website,
; and cache it locally in /var/tmp. It will refresh the data by itself
; before it expires.
;
; If it cannot load this information, ODR-DabMux cannot start up!
;
; If your system doesn't have access to internet, you have to take care
; to create the file before ODR-DabMux startup. Get it from
; http://www.ietf.org/timezones/data/leap-seconds.list
; and save it to
; /var/tmp/odr-dabmux-leap-seconds.cache
; Refresh the file before expiry otherwise ODR-DabMux will abort!
;
; Use the RC interface 'get clocktai expiry' command to check how long
; your file is still valid.
tist false
; On startup, the timestamp is initialised to system time. If you want
; to add an offset, uncomment the following line and give a number
; in seconds.
; tist_offset 0
; The URLs used to fetch the TAI bulletin can be overridden if needed.
; URLs are given as a pipe-separated list, and the default value is:
;tai_clock_bulletins "https://www.ietf.org/timezones/data/leap-seconds.list|https://raw.githubusercontent.com/eggert/tz/master/leap-seconds.list"
;
; You may also use a file:// URL if you take care of updating the file
; yourself and store it locally.
; The management server is a simple TCP server that can present
; statistics data (buffers, overruns, underruns, etc)
; which can then be graphed a tool like Munin
; The doc/stats_dabmux_multi.py tool is a suitable
; plugin for that. The data fields are documented in doc/STATS.md
; If the port is zero, or the line commented, the server
; is not started.
managementport 12720
; At startup, run the command and abort if is it not returning 0.
; This may be a script. Useful for checking if the NTP client on your
; system has had time to setup the clock.
;startupcheck "chronyc waitsync 10 0.01"
;startupcheck "ntp-wait -fv"
}
remotecontrol {
; enable the telnet remote control server on the given port
; This server allows you to read and define parameters that
; some features export. It is only accessible from localhost.
; Set the port to 0 to disable the server
telnetport 12721
; The remote control is also accessible through a ZMQ REQ/REP socket,
; and is useful for machine-triggered interactions. It supports the
; same commands as the telnet RC.
; The example code in doc/zmq_remote.py illustrates how to use this rc.
; To disable the zeromq endpoint, remove the zmqendpoint line.
; By specifying "lo" in the URL, we make the server only accessible
; from localhost. You can write tcp://*:12722 to make it accessible
; on all interfaces.
zmqendpoint tcp://lo:12722
; the remote control server makes use of the unique identifiers
; for the subchannels, services and components. Make sure you
; chose them so that you can identify them.
}
; Some ensemble parameters
ensemble {
; A unique 16-bit id is allocated to the ensemble and allows unambiguous
; identification of the ensemble when associated with the ensemble ECC.
; The id normally starts with the coutry id. (See ETSI TS 101 756)
; Example for Switzerland, with country id=4 and ECC=E1
id 0x4fff ; you can also use decimal if you want
ecc 0xe1 ; Extended Country Code
local-time-offset auto ; autmatically calculate from system local time
; or
;local-time-offset 1 ; in hours, supports half-hour offsets
; The presence of reconfig-counter enables FIG0/7, which specifies that
; the ensemble is compliant to EN 300 401 version 2.
; You can either set a number which will be used for the Count field in FIG0/7,
;reconfig-counter 23
; or set
reconfig-counter hash
; to let ODR-DabMux calculate a hash that depends on your multiplex configuration,
; ensuring that when you change the configuration, the FIG 0/7 Count also changes
;
; Leave the option commented-out if you do not wish to transmit FIG 0/7.
; If you want to run your machine in UTC time, but still take advantage of the
; automatic calculation of the local time offset, set the environment variable TZ
; to your timezone (e.g. TZ=Europe/Rome) before you launch ODR-DabMux
; FIG1 labels are given with the 'label' and 'shortlabel' keys.
;
; All labels are maximum 16 characters in length.
; Labels that are valid utf-8 will be converted to EBU Latin Character set
; as defined in ETSI TS 101 756, in Annex C. If it's not valid utf-8, the
; label is taken as-is, byte per byte. Characters that cannot be
; represented in EBU Latin will be replaced by a space character.
label "OpenDigitalRadio"
; The short label is built from the label by erasing letters, and cannot
; be longer than 8 characters. If omitted, it will be truncated from the
; label
shortlabel "ODR"
; The FIG2 label can be up to 16 characters long, and is in UTF-8.
;fig2_label "ÓpêñÐigıtålRadiō"
; FIG2 labels can either be sent with a character field (old spec)
; or with a text control (new draftETSI TS 103 176 v2.2.1).
; If unspecified, defaults to setting the text control with the values
; shown in the example below.
;
;fig2_label_character_flag "0xFF00"
;
;fig2_label_text_control {
; bidi false
; base_direction "LTR"
; contextual false
; combining false
;}
}
; Definition of DAB services
services {
; Each service has it's own unique identifier, that is
; used throughout the configuration file and for the RC.
srv-fu {
id 0x4daa
label "Fünk"
; You can define a shortlabel and a fig2_label too.
}
srv-ri {
; If your ensemble contains a service from another country,
; specify its ECC here. Example is for Italy, country id=5, ECC=E0
id 0x5dab
ecc 0xe0
label "Rick"
}
}
subchannels {
sub-fu {
; This is our DAB programme, using a file input
type audio
bitrate 128
id 10
protection 3
inputfile "funk.mp2"
}
sub-bla {
type audio
bitrate 96
id 1
protection 1
; for audio and dabplus, EDI input is available. It supports TCP server and UDP
inputproto edi
; Accepts connection to port 9001 from any interface. Prefer disabling PFT when using TCP.
inputuri "tcp://0.0.0.0:9001"
; For UDP, PFT should be enabled at the sender.
; Unicast UDP input:
;inputuri "udp://:9001"
; Multicast UDP input:
;inputuri "udp://@239.10.0.1:9001"
; Two buffer-management types are available: prebuffering and timestamped.
; prebuffering will accumulate a few frames before it starts streaming, and each
; time there is a buffer underrun (similar to how the ZMQ input works)
;
; timestamped takes into account the TIST inside EDI and inserts the encoded
; audio frame into the ETI frame with the same timestamp
buffer-management prebuffering
; In an ideal scenario, where the input rate exactly corresponds
; to the rate at which the frames are consumed by dabmux, you
; see the buffer level staying around the prebuffering value.
; Network latency jitter can make it temporarily go lower or higher.
; Encoder clock drift will make the buffer either slowly fill or
; empty, which will create intermittent glitches.
; Maximum size of input buffer, in frames (24ms)
; when this buffer size is reached, some frames will be
; discarded to get the size again below this value.
buffer 40
; At startup or after an underrun, the buffer is filled to this
; amount of frames before streaming starts.
prebuffering 20
}
sub-ri {
; This is our DAB+ programme, using a ZeroMQ input
type dabplus
bitrate 96
id 1
protection 3
; Accepts connections to port 9000 from any interface.
; Use ODR-AudioEnc as encoder, accepts only connection
; from the local machine.
inputproto edi
inputuri "tcp://127.0.0.1:9000"
buffer-management timestamped
; When using timestamped, the prebuffering is without effect.
; The buffer setting however still dictates the maximum buffer size, to
; avoid runaway memory usage in case of issues.
buffer 500
; 500 * 24ms = 12 seconds
; Specify the additional delay in milliseconds to add to the TIST. Positive values
; mean the content will be inserted later.
tist-delay 10
}
}
; In our simple example, each component links one service to one subchannel
components {
; the component unique identifiers are used for the RC.
comp-fu {
; According to specification, you should not define component labels if
; the service is only used in one component. The service label is sufficient
; in that case.
service srv-fu
subchannel sub-fu
}
comp-ri {
service srv-ri
subchannel sub-ri
; If the programme contains slideshow, please also specify the user-application:
user-applications {
userapp "slideshow"
}
}
}
; A list of outputs
outputs {
; The unique-id can be used by the remote control or the statistics server
; to identify the output
; Output RAW ETI NI to standard output
stdout "fifo:///dev/stdout?type=raw"
edi {
; Example EDI-over-TCP output
; If TIST is enabled, requires leap-second information
destinations {
example_tcp {
protocol tcp
listenport 13000
; (Optional) When a new client connects, it will receive a pre-roll burst of EDI data, so that it can quickly fill
; its buffers. The value given is the duration of the pre-roll in seconds.
; It makes sense to have a value slightly larger than tist-offset to ensure the destination will receive
; data that will allow it to start transmitting immediately.
;preroll-burst 2.0
}
}
}
; Throttle output to real-time (one ETI frame every 24ms)
throttle "simul://"
; Important! For real-time operation, you need to have exactly one
; output that applies back-pressure to ODR-DabMux, otherwise it will run
; at the highest possible rate on your system!
;
; For an output to a pipe, the data consumer at the other end of the pipe
; will dictate the multiplexing rate to ODR-DabMux.
;
; If you use the EDI output, you must also enable a simul:// output!
; More options are given in doc/advanced.mux
}
ODR-DabMux-4.4.1/doc/stats_zmq2edi_munin.py 0000644 0001750 0001750 00000011673 14465705070 017464 0 ustar robin robin #!/usr/bin/env python3
#
# A munin plugin for ODR-ZMQ2EDI
#
# Reads the logfile, and the previously rotated logfile (suffixed by .1) and
# analyses the output. Generates a graph with percentage of frames late, and a
# graph with min/max wait time.
#
# Copy this to /etc/munin/plugins/stats_zmq2edi_munin
# and make it executable (chmod +x)
#
# Then make sure that zmq2edi log output gets written to LOGFILE below,
# and setup up a logrotate script to rotate the log. The rotated log
# filename must be appended with .1
# Every six seconds a line is output. We are polled in 5 min = 300s intervals
NUM_LINES = int(300 / 6)
LOGFILE = "/var/log/supervisor/zmq2edi.log"
import time
import sys
import os
import re
munin_config = """
multigraph wait_time_zmq2edi
graph_title zmq2edi wait_time
graph_order high low
graph_args --base 1000
graph_vlabel max/min wait times during last ${graph_period}
graph_category zmq2edi
graph_info This graph shows the min and max wait times
high.info Max wait time
high.label Max wait time ms
high.min 0
high.warning 1:
low.info Min wait time
low.label Min wait time ms
low.min -6000
low.warning 1:
multigraph late_packets_zmq2edi
graph_title EDI packets delivered too late
graph_order late
graph_args --base 1000
graph_vlabel late packets during last ${graph_period}
graph_category zmq2edi
graph_info This graph shows the number late EDI packets (250 packets = 6 seconds)
late.info Number of late packets
late.label Number of late packets
late.min 0
late.max %s
late.warning 0:0
""" % (NUM_LINES * 250,)
def parse_logs():
# example lines:
# Buffering time statistics [milliseconds]: min: 907.799 max: 981.409 mean: 944.335 stdev: 26.827 late: 0 of 250 (0%)
# Values might also be in scientific form, e.g. -1.80938e+07
re_logline = re.compile(r"""Buffering time statistics.* min: (.+) max: (.+) mean: (.+) stdev: (.+) late: (.+) of 250""", flags=re.ASCII)
# The following lines are output at startup and during a reset respectively:
startup_pattern = "starting up"
backoff_pattern = "Backoff"
lines = []
# Check that the file exists and was last written to in the previous 2* 6s,
# otherwise assume the tool isn't running
if not os.path.exists(LOGFILE) or (time.time() - os.stat(LOGFILE).st_mtime) > 12:
num_late = None
t_min_period = None
t_max_period = None
else:
# Keep only the last NUM_LINES
# Read the previously rotated logfile too to make sure we have enough data
for fname in [LOGFILE+ ".1", LOGFILE]:
if os.path.exists(fname):
with open(fname, "r") as fd:
for line in fd:
lines.append(line)
if len(lines) > NUM_LINES:
del lines[0]
# Calculate min, max over the whole period, and sum the number of late
num_late = 0
t_min_period = None
t_max_period = None
num_statistics = 0
for line in lines:
if startup_pattern in line:
num_late += 250
elif backoff_pattern in line:
num_late += 250
else:
match = re_logline.search(line)
if match:
num_statistics += 1
t_min = float(match.group(1))
t_max = float(match.group(2))
t_mean = float(match.group(3))
stdev = float(match.group(4))
late = int(match.group(5))
if t_min_period is None or t_min < t_min_period:
t_min_period = t_min
if t_max_period is None or t_max > t_max_period:
t_max_period = t_max
if num_late is None:
num_late = 0
num_late += late
# The min can take extremely low values, we clamp it here to -6 seconds
# to keep the graph readable
if t_min_period is not None and t_min_period < -6000:
t_min_period = -6000
return num_late, round(t_min_period) if t_min_period is not None else None, round(t_max_period) if t_max_period is not None else None
def muninify(value):
""" According to http://guide.munin-monitoring.org/en/latest/develop/plugins/plugin-concise.html#plugin-concise
"If the plugin - for any reason - has no value to report, then it may send the value U for undefined."
"""
return 'U' if value is None else value
# No arguments means that munin wants values
if len(sys.argv) == 1:
num_late, t_min, t_max = parse_logs()
munin_values = "multigraph wait_time_zmq2edi\n"
munin_values += "high.value {}\n".format(muninify(t_max))
munin_values += "low.value {}\n".format(muninify(t_min))
munin_values += "multigraph late_packets_zmq2edi\n"
munin_values += "late.value {}\n".format(muninify(num_late))
print(munin_values)
elif len(sys.argv) == 2 and sys.argv[1] == "config":
print(munin_config)
else:
sys.exit(1)
ODR-DabMux-4.4.1/doc/retodrs.pl 0000644 0001750 0001750 00000050463 14465705070 015132 0 ustar robin robin #!/usr/bin/perl -w
#
# RETrieve_Open_Digital_Radio_Status, retodrs:
# Retrieve the status and statistics of an Opendigitalradio service and report
# the results to Xymon. The information is retrieved from the management server
# within ODR-DabMux.
#
# NOTE: This script MUST be run on the same machine as DabMux is running! The
# management server within DabMux is only accessible from localhost.
# Moreover, the check on availability only works for localhost.
#
# Written by W.J.M. Nelis, wim.nelis@ziggo.nl, 2016.12
#
use strict ;
use Time::Piece ; # Format time
use ZMQ::LibZMQ3 ; # Message passing
use ZMQ::Constants qw(ZMQ_REQ) ;
use JSON::PP ; # Decode server message
#
# Installation constants.
# -----------------------
#
my $XyDisp = $ENV{XYMSRV} ; # Name of monitor server
my $XySend = $ENV{XYMON} ; # Monitor interface program
my $FmtDate = "%Y.%m.%d %H:%M:%S" ; # Default date format
$FmtDate = $ENV{XYMONDATEFORMAT} if exists $ENV{XYMONDATEFORMAT} ;
my $HostName= 'OzoNop' ; # 'Source' of this test
my $TestName= 'odr_mux' ; # Test name
my $XyInfo = "hostinfo host=$HostName" ; # Extract host info from xymon
my @ColourOf= ( 'red', 'yellow', 'clear', 'green' ) ;
#
# Define the URL to access the management server in DabMux. The access is
# limited to access from localhost!
#
my $ODRMgmtSrvr= 'tcp://127.0.0.1:12720' ; # URL of server
#
# Define the parameters to show in the table and how to enter them in an RRD.
# From this definition a list of counter-like variables is compiled in hash
# %Counters. The values of these variables need to be saved from one pass of
# this script to the next.
#
my @Params= (
# OdrName TableName RrdDefinition
[ 'state' , 'State' , '' ],
[ 'peak_left' , 'Peak left [dB]' , 'DS:PeakLeft:GAUGE:600:-100:100' ],
[ 'peak_right' , 'Peak right [dB]', 'DS:PeakRight:GAUGE:600:-100:100' ],
[ 'num_underruns', '' , 'DS:Underrun:DERIVE:600:0:U' ],
[ 'num_overruns' , '' , 'DS:Overrun:DERIVE:600:0:U' ],
[ 'rate_underruns', 'Underrun [/s]' , '' ],
[ 'rate_overruns' , 'Overrun [/s]' , '' ],
[ 'min_fill' , '' , 'DS:BufferMin:GAUGE:600:-1:U' ],
[ 'max_fill' , '' , 'DS:BufferMax:GAUGE:600:0:U' ]
) ;
my %Counters= () ;
foreach ( @Params ) {
next unless $$_[2] =~ m/DERIVE/ ;
$Counters{$$_[0]}= $$_[0] ; # Save name of counter-like variable
$Counters{$$_[0]}=~ s/^num_/rate_/ ; # Build name of derived variable
} # of foreach
#
# Define the thresholds for the various DabMux statistics and any derived
# value.
#
my %Thresholds= (
state => { red => qr/^(?:NoData)$/ },
rate_underruns => { red => '20.0'},
rate_overruns => { red => '20.0'},
# peak_left => { yellow => ['< -80', '80'] },
# peak_right => { yellow => ['< -80', '80'] }
) ;
#
# Define the name of the file to hold the values of the counter-type variables.
#
my $SaveFile= '/usr/lib/xymon/client/ext/retodrs.sav' ;
#
# Global variables.
# -----------------
#
my $Now= localtime ; # Timestamp of tests
$Now= $Now->strftime( $FmtDate ) ;
my $Colour= $#ColourOf ; # Test status
my $Result= '' ; # Message to sent to Xymon
my %HostInfo ; # Host information from xymon
my %Table0= () ; # Tables with results
my %Table1= () ;
my @SubChannel= () ; # Subchannel assignment
my %SubChannel= () ; # in both directions
my %ErrMsg ; # Error messages
$ErrMsg{$_}= [] foreach ( @ColourOf ) ;
my ($CurTime,$PrvTime) ; # Times of measurement
my %Prev= () ; # Variables in previous pass
#
# Save an error message in intermediate list %ErrMsg. Function InformXymon will
# move these messages to the start of the xymon status message.
#
sub LogError($$) {
my $clr= shift ; # Status/colour of message
my $msg= shift ; # Error message
return unless defined $msg ;
return unless $msg ;
chomp $msg ; # Clean up message, just to be sure
$msg=~ s/^\s+// ; $msg=~ s/\s+$// ;
if ( exists $ErrMsg{$clr} ) {
push @{$ErrMsg{$clr}}, $msg ;
} else {
push @{$ErrMsg{clear}}, $msg ;
} # of else
} # of LogError
#
# Issue a message the the logfile. As this script is run periodically by Xymon,
# StdOut will be redirected to the logfile.
#
sub LogMessage {
my $Msg= shift ;
my @Time= (localtime())[0..5] ;
$Time[4]++ ; $Time[5]+= 1900 ;
chomp $Msg ;
printf "%4d%02d%02d %02d%02d%02d %s\n", reverse(@Time), $Msg ;
} # of LogMessage
sub max($$) { return $_[0] > $_[1] ? $_[0] : $_[1] ; }
sub min($$) { return $_[0] < $_[1] ? $_[0] : $_[1] ; }
#
# Function AnError is given a short description and a boolean value, whose value
# is false if the operation associated with the description failed. The result
# of this function is the opposite of the boolean value supplied. If failed, the
# description is entered in the error message list %ErrMsg, including the
# content of $!, if the latter is not empty.
#
sub AnError($$) {
if ( $_[1] ) {
return 0 ; # Return a false value
} else {
my $msg= $! ; # Retrieve any error message
if ( $msg eq '' ) {
LogError( 'clear', "$_[0] failed" ) ;
} else {
LogError( 'clear', "$_[0] failed:" ) ;
LogError( 'clear', " $msg" ) ;
} # of else
return 1 ; # Return a true value
} # of else
} # of AnError
#
# Function ApplyThresholds determines for which channels threshold checks should
# be performed. Then it checks the collected statistics against their
# thresholds, and sets the status of those statistics accordingly. The status of
# the statistics which are not checked against a threshold are set to 'clear'.
#
sub ApplyThresholds() {
my $hr ; # Reference in a multi-level hash
#
# Set flag ThresholdCheck at each subchannel. It is set to true if threshold
# checks should be performed.
#
if ( exists $HostInfo{select}{list} ) {
$hr= $HostInfo{select}{list} ;
$Table1{$_}{ThresholdCheck}= exists $$hr{$_} ? 1 : 0 foreach ( keys %Table1 ) ;
} else {
$Table1{$_}{ThresholdCheck}= 1 foreach ( keys %Table1 ) ;
} # of else
#
# Invoke function CheckValue for each pair {subchannel,statistic} for which a
# threshold check should and can be performed.
#
foreach my $sub ( keys %Table1 ) {
next unless $Table1{$sub}{ThresholdCheck} ;
$hr= $Table1{$sub} ; # Ref to subchannel info
foreach my $var ( keys %Thresholds ) {
next unless exists $$hr{$var} ;
CheckValue( $$hr{$var}, $Thresholds{$var} ) ;
} # of foreach
} # of foreach
} # of ApplyThresholds
#
# Function BuildMessage takes the the status and statistics in hash %Table and
# builds a message for Xymon.
#
sub BuildMessage() {
my $RrdMsg ; # RRD message
my $sub ; # Name of a sub channel
my ($Value,$Status) ; # Value and status of one statistic
my @Values ; # Values of one subchannel
my $hr ; # Reference into a hash
#
# Check the subchannel assignment against the list of named subchannels. They
# should match.
#
for ( my $i= 0 ; $i<= $#SubChannel ; $i++ ) {
$hr= $SubChannel[$i] ;
next unless defined $hr ;
next if exists $Table1{$hr} ;
$SubChannel[$i]= undef ;
delete $SubChannel{$hr} ;
} # of for
foreach my $sub ( sort keys %Table1 ) {
next if exists $SubChannel{$sub} ;
$hr= $#SubChannel + 1 ;
$SubChannel[$hr]= $sub ;
} # of foreach
#
# Build a table showing the services.
#
$Result = "
\n" ;
foreach ( sort keys %Table0 ) {
$Result.= " $_ | $Table0{$_} |
\n" ;
} # of foreach
$Result.= "
\n\n" ;
#
# Build the first part of the table to enter the statistics into RRD's and
# ultimately into graphs.
#
$RrdMsg = "\n" ;
$RrdMsg.= "" ;
$Result.= $RrdMsg ;
} # of BuildMessage
#
# Function CheckPortStatus checks if the TCP port to access the management
# server is available in listen mode. The function result is true if the TCP
# port is found in the listen state, false otherwise.
#
sub CheckPortStatus($) {
my $url= shift ; # The url to check
my $Found= 0 ; # Function result
my @F ; # Fields of a line image
my @netstat= `netstat -ln4` ; # Retrieve port status info
foreach ( @netstat ) {
chomp ;
@F= split ;
# next unless @F == 6 ;
# next unless $F[5] eq 'LISTEN' ;
next unless "$F[0]://$F[3]" eq $url ;
$Found= 1 ; # Port in listen state found
last ; # Terminate search
} # of foreach
return $Found ;
} # of CheckPortStatus
#
# Function CheckValue checks the value of a statistic against its threshold(s).
# A reference to the value and a reference to the threshold definition are
# passed.
#
sub CheckValue($$) {
my $vr= shift ; # Reference to the variable
my $tr= shift ; # Reference to the threshold descriptor
my $clr ;
$$vr{Status}= $#ColourOf ; # Default result
return if $$vr{Value} eq 'wait' ;
for ( my $i= $#ColourOf ; $i >= 0 ; $i-- ) {
$clr= $ColourOf[$i] ;
next unless exists $$tr{$clr} ;
if ( ref($$tr{$clr}) eq 'ARRAY' ) {
foreach ( @{$$tr{$clr}} ) {
if ( ref($_) eq 'Regexp' ) { # Text check
$$vr{Status}= $i if $$vr{Value} =~ m/$_/ ;
} elsif ( m/^[-+\d\.]+$/ ) { # Numeric upperbound
$$vr{Status}= $i if $$vr{Value} > $_ ;
} elsif ( m/^<\s*([-+\d\.]+)$/ ) { # Numeric lowerbound
$$vr{Status}= $i if $$vr{Value} < $1 ;
} # of elsif
} # of foreach
} else {
if ( ref($$tr{$clr}) eq 'Regexp' ) { # Text check
$$vr{Status}= $i if $$vr{Value} =~ m/$$tr{$clr}/ ;
} elsif ( $$tr{$clr} =~ m/^[-+\d\.]+$/ ) { # Numeric upperbound
$$vr{Status}= $i if $$vr{Value} > $$tr{$clr} ;
} elsif ( $$tr{$clr} =~ m/^<\s*([-+\d\.]+)$/ ) { # Numeric lowerbound
$$vr{Status}= $i if $$vr{Value} < $1 ;
} # of elsif
} # of else
} # of for
} # of CheckValue
#
# Function ComputeRates computes the the rate of change of the counter-like
# variables.
#
sub ComputeRates() {
my $hr ;
my $val ;
foreach my $sub ( keys %Table1 ) {
$hr= $Table1{$sub} ; # Ref into hash
foreach my $var ( keys %Counters ) {
$$hr{$Counters{$var}}{Value}= 'wait' ;
$$hr{$Counters{$var}}{State}= undef ;
if ( exists $Prev{$sub}{$var} and
defined $$hr{$var}{Value} and
defined $PrvTime ) {
if ( $$hr{$var}{Value} >= $Prev{$sub}{$var} ) {
$val= ( $$hr{$var}{Value} - $Prev{$sub}{$var} ) /
( $CurTime - $PrvTime ) ;
$$hr{$Counters{$var}}{Value}= sprintf( '%.2f', $val ) ;
} # of if
} # of if
} # of foreach
} # of foreach
} # of ComputeRates
#
# Function GetOneReply sends the supplied request to the management server and
# returns the result as a reference to a hash. If something went wrong, the
# result will be undef and an (appropiate?) error message is entered in %ErrMsg.
#
sub GetOneReply($$) {
my $socket = shift ; # Socket object
my $request= shift ; # Request string
my $reqlng= length( $request ) ; # Length of request string
my $rc= zmq_send( $socket, $request, $reqlng ) ;
return undef if AnError( "Request \"$request\"", $rc == $reqlng ) ;
my $reply= zmq_recvmsg( $socket ) ;
return undef if AnError( "Reply on \"$request\"", defined $reply ) ;
$reply= decode_json( zmq_msg_data($reply) ) ; # Convert to Perl structure
return $reply ;
} # of GetOneReply
#
# Function GetStatistics retrieves both the status and the statistics from the
# server within the DabMux. The results are collected in hash %Table. Subhash
# %{$Table{0}} will contain the service information, %{$Table{1}} will contain
# the subchannel status and statistics.
#
sub GetStatistics() {
my ($ctxt,$socket) ; # Connection variables
my ($reply,$rv) ; # Request/reply variables
my ($hr,$vr) ; # Refs into multi-level hash
$CurTime= undef ; # No data collected yet
#
# Build a connection to the DabMux server.
#
$ctxt= zmq_ctx_new ;
return undef if AnError( 'Building context object', defined $ctxt ) ;
$socket= zmq_socket( $ctxt, ZMQ_REQ ) ;
return undef if AnError( 'Creating socket', defined $socket ) ;
$rv= zmq_connect( $socket, $ODRMgmtSrvr ) ;
return undef if AnError( 'Connecting to DabMux', $rv == 0 ) ;
$reply= GetOneReply( $socket, 'info' ) ;
return undef unless defined $reply ;
%Table0= %$reply ; # Save overview of services
my $Once= 1 ; # Loop control variable
while ( $Once ) {
$Once= 0 ; # Only one iteration.
#
# Retrieve the subchannel assignment.
#
$reply= GetOneReply( $socket, 'getptree' ) ;
if ( defined $reply ) {
foreach my $sub ( keys %{$$reply{subchannels}} ) {
$hr= $$reply{subchannels}{$sub} ;
next unless exists $$hr{id} ;
next unless $$hr{id} =~ m/^\d+$/ ;
$SubChannel[$$hr{id}]= $sub ;
$SubChannel{$sub}= $$hr{id} ;
} # of foreach
} else {
next ; # Skip rest of retrievals
} # of else
#
# Retrieve the status and the statistics.
#
$reply= GetOneReply( $socket, 'state' ) ;
if ( defined $reply ) {
foreach my $sub ( keys %$reply ) {
$Table1{$sub}= {} ; # Preset result area
$hr= $Table1{$sub} ;
foreach ( keys %{$$reply{$sub}} ) {
$$hr{$_}{Value} = $$reply{$sub}{$_} ;
$$hr{$_}{Status}= undef ;
} # of foreach
} # of foreach
} else {
next ; # Skip retrieval of statistics
} # of else
$reply= GetOneReply( $socket, 'values' ) ;
if ( defined $reply and exists $$reply{values} ) {
$CurTime= time ; # Save time of retrieval
foreach my $sub ( keys %{$$reply{values}} ) {
next unless exists $Table1{$sub} ;
next unless exists $$reply{values}{$sub}{inputstat} ;
$hr= $Table1{$sub} ; # Ref to destination
$vr= $$reply{values}{$sub}{inputstat} ; # Ref to source
foreach ( keys %$vr ) {
$$hr{$_}{Value} = $$vr{$_} ;
$$hr{$_}{Status}= undef ;
} # of foreach
} # of foreach
# } else {
# next ;
} # of else
#
# Terminate the connection to the DabMux server.
#
} continue {
$rv= zmq_close( $socket ) ;
AnError( 'Closing socket', $rv == 0 ) ;
return 0 ; # Return a defined value
} # of continue / while
} # of GetStatistics
#
# Function GetXymonHostInfo retrieves the configuration of host $HostName from
# the xymon configuration file hosts.cfg. If tag ODR is present, it is handled.
#
sub GetXymonHostInfo() {
%HostInfo= ( select => { default => '^.+$' } ) ; # Default result
my @Lines= `$XySend $XyDisp \"$XyInfo\"` ; # Retrieve host info
if ( @Lines != 1 ) { # Handle error condition
LogError( 'clear', 'Retrieval of host information from Xymon failed' ) ;
return ;
} # of if
my ($Tag)= $Lines[0] =~ m/\b(ODR[^\s\|]+)/ ; # Extract tag ODR
return unless defined $Tag ;
# return if $Tag eq 'ODR' ;
$Tag=~ s/^ODR\:// ; # Remove tag header
foreach my $sub ( split( /,/, $Tag ) ) {
if ( $sub =~ m/select\((.+)\)$/ ) {
$HostInfo{select}{list}{$_}= 0 foreach ( split(/;/,$1) ) ;
delete $HostInfo{select}{default} ;
} # of if
} # of foreach
} # of GetXymonHostInfo
#
# Function InformXymon sends the message, in global variable $Result, to the
# Xymon server. Any error messages in %ErrMsg are prepended to the message and
# the status (colour) of the message is adapted accordingly.
#
sub InformXymon() {
my $ErrMsg= '' ;
my $Clr ; # Colour of one sub-test
for ( my $i= 0 ; $i < @ColourOf ; $i++ ) {
$Clr= $ColourOf[$i] ;
next unless @{$ErrMsg{$Clr}} ;
$Colour= min( $Colour, $i ) ;
$ErrMsg.= "&$Clr $_\n" foreach ( @{$ErrMsg{$Clr}} ) ;
} # of foreach
$ErrMsg.= "\n" if $ErrMsg ;
$Colour= $ColourOf[$Colour] ;
$Result= "\"status $HostName.$TestName $Colour $Now\n" .
"Open Digital Radio DabMux status\n\n" .
"$ErrMsg$Result\"\n" ;
`$XySend $XyDisp $Result` ; # Inform Xymon
$Result= '' ; # Reset message parameters
$Colour= $#ColourOf ;
$ErrMsg{$_}= [] foreach ( @ColourOf ) ;
} # of InformXymon
#
# Function RestoreCounters restores the values of counter-like variables,
# collected in the previous pass of this script, in hash %Prev. However, if the
# information is too old, nothing is restored.
#
sub RestoreCounters() {
my @F ; # Fields in a line image
%Prev= () ; # Clear save area
$PrvTime= undef ;
unless ( open( FH, '<', $SaveFile ) ) {
LogError( 'yellow', "Can't read file $SaveFile : $!" ) ;
LogMessage( "Can't read file $SaveFile : $!" ) ;
return ;
} # of unless
while ( ) {
chomp ;
@F= split ;
if ( $F[0] eq 'Time' ) {
last unless ( time - $F[1] < 1000 ) ;
$PrvTime= $F[1] ;
} elsif ( $F[0] eq 'Counter' ) {
$Prev{$F[1]}{$F[2]}= $F[3] ;
} # of elsif
} # of while
close( FH ) ;
} # of RestoreCounters
# Function SaveCounters saves the counter-type variables in a file. They are
# retrieved in the next pass of this script, and will be used to calculate the
# rate in which these variables increase.
#
sub SaveCounters() {
#
# If the retrieval of the statistics failed, nothing should be saved. Perhaps
# the information saved at the (a?) previous pass is usable in the next pass.
#
return unless defined $CurTime ;
unless ( open( FH, '>', $SaveFile ) ) {
LogError( 'yellow', "Can't write file $SaveFile : $!" ) ;
LogMessage( "Can't write file $SaveFile : $!" ) ;
return ;
} # of unless
print FH "Time $CurTime\n" ;
foreach my $sub ( sort keys %Table1 ) {
foreach my $var ( sort keys %{$Table1{$sub}} ) {
next unless exists $Counters{$var} ;
next unless defined $Table1{$sub}{$var}{Value} ;
print FH "Counter $sub $var $Table1{$sub}{$var}{Value}\n" ;
} # of foreach
} # of foreach
close( FH ) ;
} # of SaveCounters
#
# MAIN PROGRAM.
# =============
#
unless ( CheckPortStatus($ODRMgmtSrvr) ) { # If server down,
LogMessage( "URL \"$ODRMgmtSrvr\" is not available" ) ;
LogError( 'red', 'Server is not available' ) ;
InformXymon ; # report error via xymon
exit ; # and stop
} # of unless
unless ( defined GetStatistics ) { # If retrieval fails,
InformXymon ; # report error via xymon
exit ; # and stop
} # of unless
GetXymonHostInfo ; # Retrieve additional host info
if ( keys %Counters ) {
RestoreCounters ; # Get counters from previous pass
ComputeRates ; # Compute their rate of change
SaveCounters ; # Save counters for next pass
} # of if
ApplyThresholds ; # Check for out-of-range values
BuildMessage ; # Build xymon message
InformXymon ; # Send message to xymon
ODR-DabMux-4.4.1/doc/stats_dabmux_munin.py 0000755 0001750 0001750 00000020273 14465705070 017370 0 ustar robin robin #!/usr/bin/env python
#
# present statistics from dabmux Stats Server and ZeroMQ RC
# to munin. Expects Stats server on port 12720 and ZeroMQ RC
# on port 12722.
#
# Copy this to /etc/munin/plugins/stats_dabmux_munin
# and make it executable (chmod +x)
import sys
import json
import zmq
import os
import re
config_top = """
multigraph clocktai_expiry
graph_title Time to expiry for TAI bulletin
graph_order expiry
graph_args --base 1000
graph_vlabel Number of seconds until expiry
graph_category dabmux
graph_info This graph shows the number of remaining seconds this bulletin is valid
expiry.info Seconds until expiry
expiry.label Seconds until expiry
expiry.min 0
expiry.warning {onemonth}:
""".format(onemonth=3600*24*30)
#default data type is GAUGE
config_template = """
multigraph buffers_{ident}
graph_title Contribution {ident} buffer
graph_order high low
graph_args --base 1000
graph_vlabel max/min buffer size bytes during last ${{graph_period}}
graph_category dabmux
graph_info This graph shows the high and low buffer sizes for the {ident} ZMQ input
high.info Max buffer size
high.label Max Buffer Bytes
high.min 0
high.warning 1:
low.info Min buffer size
low.label Min Buffer Bytes
low.min 0
low.warning 1:
multigraph over_underruns_{ident}
graph_title Contribution {ident} over/underruns
graph_order underruns overruns
graph_args --base 1000 --logarithmic
graph_vlabel number of underruns/overruns during last ${{graph_period}}
graph_category dabmux
graph_info This graph shows the number of under/overruns for the {ident} ZMQ input
underruns.info Number of underruns
underruns.label Number of underruns
underruns.min 0
underruns.warning 0:0
underruns.type COUNTER
overruns.info Number of overruns
overruns.label Number of overruns
overruns.min 0
overruns.warning 0:0
overruns.type COUNTER
multigraph audio_levels_{ident}
graph_title Contribution {ident} audio level (peak)
graph_order left left_slow right right_slow
graph_args --base 1000
graph_vlabel peak audio level during last ${{graph_period}}
graph_category encoders
graph_info This graph shows the audio level and peak of both channels of the {ident} ZMQ input
left.info Left channel audio level
left.label Left level
left.min -90
left.max 0
left.warning -40:0
left.critical -80:0
left_slow.info Left channel audio peak over last 5 minutes
left_slow.label Left peak
left_slow.min -90
left_slow.max 0
left_slow.warning -40:0
left_slow.critical -80:0
right.info Right channel audio level
right.label Right level
right.min -90
right.max 0
right.warning -40:0
right.critical -80:0
right_slow.info Right channel audio peak over last 5 minutes
right_slow.label Right peak
right_slow.min -90
right_slow.max 0
right_slow.warning -40:0
right_slow.critical -80:0
multigraph state_{ident}
graph_title State of contribution {ident}
graph_order state
graph_args --base 1000 --lower-limit 0 --upper-limit 5
graph_vlabel Current state of the input
graph_category dabmux
graph_info This graph shows the state for the {ident} ZMQ input
state.info Input state
state.label 0 Unknown, 1 NoData, 2 Unstable, 3 Silent, 4 Streaming
state.warning 4:4
state.critical 2:4
"""
ctx = zmq.Context()
class RCException(Exception):
pass
def do_transaction(command, sock):
"""To a send + receive transaction, quit whole program on timeout"""
sock.send(command.encode("utf-8"))
poller = zmq.Poller()
poller.register(sock, zmq.POLLIN)
socks = dict(poller.poll(1000))
if socks:
if socks.get(sock) == zmq.POLLIN:
return sock.recv().decode("utf-8")
sys.stderr.write("Could not receive data for command '{}'\n".format(command))
sys.exit(1)
def do_multipart_transaction(message_parts, sock):
"""To a send + receive transaction, quit whole program on timeout"""
if isinstance(message_parts, str):
sys.stderr.write("do_transaction expects a list!\n");
sys.exit(1)
for i, part in enumerate(message_parts):
if i == len(message_parts) - 1:
f = 0
else:
f = zmq.SNDMORE
sock.send(part, flags=f)
poller = zmq.Poller()
poller.register(sock, zmq.POLLIN)
socks = dict(poller.poll(1000))
if socks:
if socks.get(sock) == zmq.POLLIN:
rxpackets = sock.recv_multipart()
return rxpackets
raise RCException("Could not receive data for command '{}'\n".format(
message_parts))
def get_rc_value(module, name, sock):
try:
parts = do_multipart_transaction([b"get", module.encode(), name.encode()],
sock)
if len(parts) != 1:
sys.stderr.write("Received unexpected multipart message {}\n".format(
parts))
sys.exit(1)
return parts[0].decode()
except RCException as e:
print("get {} {} fail: {}".format(module, name, e))
return ""
def connect_to_stats():
"""Create a connection to the dabmux stats server
returns: the socket"""
sock = zmq.Socket(ctx, zmq.REQ)
sock.set(zmq.LINGER, 5)
sock.connect("tcp://localhost:12720")
version = json.loads(do_transaction("info", sock))
if not version['service'].startswith("ODR-DabMux"):
sys.stderr.write("Wrong version\n")
sys.exit(1)
return sock
def connect_to_rc():
"""Create a connection to the dabmux RC
returns: the socket"""
sock = zmq.Socket(ctx, zmq.REQ)
sock.set(zmq.LINGER, 5)
sock.connect("tcp://localhost:12722")
try:
ping_answer = do_multipart_transaction([b"ping"], sock)
if not ping_answer == [b"ok"]:
sys.stderr.write("Wrong answer to ping\n")
sys.exit(1)
except RCException as e:
print("connect failed because: {}".format(e))
sys.exit(1)
return sock
def handle_re(graph_name, re, rc_value, group_number=1):
match = re.search(rc_value)
if match:
return "{}.value {}\n".format(graph_name, match.group(group_number))
else:
return "{}.value U\n".format(graph_name)
if len(sys.argv) == 1:
munin_values = ""
sock_rc = connect_to_rc()
clocktai_expiry = get_rc_value("clocktai", "expiry", sock_rc)
re_clocktai_expiry = re.compile(r"(\d+)", re.X)
munin_values += "multigraph clocktai_expiry\n"
munin_values += handle_re("expiry", re_clocktai_expiry, clocktai_expiry)
sock_stats = connect_to_stats()
values = json.loads(do_transaction("values", sock_stats))['values']
for ident in values:
v = values[ident]['inputstat']
ident_ = ident.replace('-', '_')
munin_values += "multigraph buffers_{ident}\n".format(ident=ident_)
munin_values += "high.value {}\n".format(v['max_fill'])
munin_values += "low.value {}\n".format(v['min_fill'])
munin_values += "multigraph over_underruns_{ident}\n".format(ident=ident_)
munin_values += "underruns.value {}\n".format(v['num_underruns'])
munin_values += "overruns.value {}\n".format(v['num_overruns'])
munin_values += "multigraph audio_levels_{ident}\n".format(ident=ident_)
munin_values += "left.value {}\n".format(v['peak_left'])
munin_values += "right.value {}\n".format(v['peak_right'])
if 'peak_left_slow' in v:
# If ODR-DabMux is v2.0.0-3 or older, it doesn't export the slow peaks
munin_values += "left_slow.value {}\n".format(v['peak_left_slow'])
munin_values += "right_slow.value {}\n".format(v['peak_right_slow'])
if 'state' in v:
# If ODR-DabMux is v1.3.1-3 or older, it doesn't export state
re_state = re.compile(r"\w+ \((\d+)\)")
match = re_state.match(v['state'])
if match:
munin_values += "multigraph state_{ident}\n".format(ident=ident_)
munin_values += "state.value {}\n".format(match.group(1))
else:
sys.stderr.write("Cannot parse state '{}'\n".format(v['state']))
print(munin_values)
elif len(sys.argv) == 2 and sys.argv[1] == "config":
sock_stats = connect_to_stats()
config = json.loads(do_transaction("config", sock_stats))
munin_config = config_top
for conf in config['config']:
munin_config += config_template.format(ident=conf.replace('-', '_'))
print(munin_config)
else:
sys.stderr.write("Invalid command line arguments")
sys.exit(1)
ODR-DabMux-4.4.1/doc/dab_output_formats.txt 0000644 0001750 0001750 00000002103 14465705070 017541 0 ustar robin robin ODR-DabMux supports three output formats for the ETI stream.
The three formats are called 'framed', 'streamed' and 'raw'.
The framed format is used for saving a finite ETI stream into a file. Each frame does
not contain any padding, and the format can be described as follows:
uint32_t nbFrames
// for each frame
uint16_t frameSize
uint8_t data[ frameSize ]
When streaming data, in which case the number of frames is not known in advance,
the streamed format can be used. This format is identical to the first one except for the
missing nbFrames.
// for each frame
uint16_t frameSize
uint8_t data[ frameSize ]
The raw format corresponds to ETI(NI), where each frame has a constant size of 6144
Bytes. The padding in this case is necessary.
// for each frame
uint8_t data [6144]
In order to select the format, the following syntax for the -O option or the
output setting in the configuration file is:
file://filename?type=format
where format is one of framed, streamed or raw, e.g.
file:///tmp/mux.eti?type=raw
saves a raw ETI file to /tmp/mux.eti
ODR-DabMux-4.4.1/doc/show_dabmux_stats.py 0000755 0001750 0001750 00000005447 14465705070 017230 0 ustar robin robin #!/usr/bin/env python
#
# present statistics from dabmux Stats Server
# to standard output.
#
# If you are looking for munin integration, use
# ODR-DabMux/doc/stats_dabmux_multi.py
import sys
import json
import zmq
import os
ctx = zmq.Context()
def connect():
"""Create a connection to the dabmux stats server
returns: the socket"""
sock = zmq.Socket(ctx, zmq.REQ)
sock.connect("tcp://localhost:12720")
sock.send(b"info")
infojson = json.loads(sock.recv().decode("utf-8"))
sys.stderr.write("Statistics from ODR-DabMux {}\n".format(infojson['version']))
if not infojson['service'].startswith("ODR-DabMux"):
sys.stderr.write("This is not ODR-DabMux: {}\n".format(infojson['service']))
sys.exit(1)
return sock
if len(sys.argv) == 1:
sock = connect()
sock.send(b"values")
poller = zmq.Poller()
poller.register(sock, zmq.POLLIN)
socks = dict(poller.poll(1000))
if socks:
if socks.get(sock) == zmq.POLLIN:
data = sock.recv().decode("utf-8")
values = json.loads(data)['values']
tmpl = "{ident:20}{maxfill:>8}{minfill:>8}{under:>8}{over:>8}{audioleft:>8}{audioright:>8}{peakleft:>8}{peakright:>8}{state:>16}{version:>48}{uptime:>8}{offset:>8}"
print(tmpl.format(
ident="id",
maxfill="max",
minfill="min",
under="under",
over="over",
audioleft="audio L",
audioright="audio R",
peakleft="peak L",
peakright="peak R",
state="state",
version="version",
uptime="uptime",
offset="offset"))
for ident in sorted(values):
v = values[ident]['inputstat']
if 'state' not in v:
v['state'] = None
if 'version' not in v:
v['version'] = "Unknown"
if 'uptime' not in v:
v['uptime'] = "?"
print(tmpl.format(
ident=ident,
maxfill=v['max_fill'],
minfill=v['min_fill'],
under=v['num_underruns'],
over=v['num_overruns'],
audioleft=v['peak_left'],
audioright=v['peak_right'],
peakleft=v['peak_left_slow'],
peakright=v['peak_right_slow'],
state=v['state'],
version=v['version'],
uptime=v['uptime'],
offset=v['last_tist_offset']))
elif len(sys.argv) == 2 and sys.argv[1] == "config":
sock = connect()
sock.send(b"config")
config = json.loads(sock.recv().decode("utf-8"))
print(config['config'])
ODR-DabMux-4.4.1/doc/README.md 0000644 0001750 0001750 00000006162 14465705070 014367 0 ustar robin robin Description
===========
ODR-DabMux is a software multiplexer that generates an ETI stream from audio
and data streams. Because of its software based architecture, many typical DAB
services can be generated and multiplexed on a single PC platform with live or
pre-recorded sources.
A DAB multiplex configuration is composed of one ensemble. An ensemble is the
entity that receivers tune to and process. An ensemble contains several
services. A service is the listener-selectable output. Each service contains
one mandatory service component which is called primary component. An audio
primary component define a program service while a data primary component
define a data service. Service can contain additional components which are
called secondary components. Maximum total number of components is 12 for
program services and 11 for data services. A service component is a link to one
subchannel (or Fast Information Data Channel). A subchannel is the physical
space used within the common interleaved frame.
__________________________________________________
ENSEMBLE | ODR-Ensemble |
|__________________________________________________|
| | |
| | |
_______V______ _______V______ _______V______
SERVICES | ODR-Service1 | | ODR-Service2 | | ODR-Service3 |
|______________| |______________| |______________|
| | | | |______ |
| | | | | |
__V__ __V__ __V__ __V__ __V__ __V__
SERVICE | SC1 | | SC2 | | SC3 | | SC4 | | SC5 | | SC6 |
COMPONENTS |_____| |_____| |_____| |_____| |_____| |_____|
| | _____| | | ____|
| | | | | |
__________ __V________V__V______________V________V___V_______
| MCI | SI | | SubCh1 | SubCh9 | ... | SubCh3 | SubCh60 | ... |
|_____|____| |________|________|_______|________|_________|_____|
Fast Information Ch. Main Service Channel
COMMON INTERLEAVED FRAME
Files in this folder
====================
The configuration is given in a file, this folder contains examples.
A basic example is in the file *example.mux*, a more complete view of the
settings is available in *advanced.mux* and configuration settings related to
service linking are shown in *servicelinking.mux*
An explanation on how to use the remote control is in *remote_control.txt*, and
*zmq_remote.py* illustrates how to control ODR-DabMux using the ZMQ remote
control interface.
Two scripts are used for monitoring systems: *stats_dabmux_munin.py* for Munin,
and *retodrs.pl* for Xymon. You can use *show_dabmux_stats.py* to print the
statistics to console. The values are described in *STATS.md*
*DabMux.1* is an old manpage that describes the command line options that
existed in past versions. It is kept for archive.
ODR-DabMux-4.4.1/doc/zmq_remote.py 0000755 0001750 0001750 00000004745 14465705070 015654 0 ustar robin robin #!/usr/bin/env python
#
# This is an example program that illustrates
# how to interact with the zeromq remote control
#
# LICENSE: see bottom of file
import sys
import zmq
context = zmq.Context()
sock = context.socket(zmq.REQ)
poller = zmq.Poller()
poller.register(sock, zmq.POLLIN)
if len(sys.argv) < 2:
print("Usage: program url cmd [args...]")
sys.exit(1)
sock.connect(sys.argv[1])
message_parts = sys.argv[2:]
# first do a ping test
print("ping")
sock.send(b"ping")
socks = dict(poller.poll(1000))
if socks:
if socks.get(sock) == zmq.POLLIN:
data = sock.recv_multipart()
print("Received: {}".format(len(data)))
for i,part in enumerate(data):
print(" {}".format(part))
for i, part in enumerate(message_parts):
if i == len(message_parts) - 1:
f = 0
else:
f = zmq.SNDMORE
print("Send {}({}): '{}'".format(i, f, part))
sock.send(part.encode(), flags=f)
data = sock.recv_multipart()
print("Received: {}".format(len(data)))
for i,part in enumerate(data):
print(" RX {}: {}".format(i, part.decode().replace('\n',' ')))
else:
print("ZMQ error: timeout")
context.destroy(linger=5)
# This is free and unencumbered software released into the public domain.
#
# Anyone is free to copy, modify, publish, use, compile, sell, or
# distribute this software, either in source code form or as a compiled
# binary, for any purpose, commercial or non-commercial, and by any
# means.
#
# In jurisdictions that recognize copyright laws, the author or authors
# of this software dedicate any and all copyright interest in the
# software to the public domain. We make this dedication for the benefit
# of the public at large and to the detriment of our heirs and
# successors. We intend this dedication to be an overt act of
# relinquishment in perpetuity of all present and future rights to this
# software under copyright law.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#
# For more information, please refer to
ODR-DabMux-4.4.1/doc/example.json 0000644 0001750 0001750 00000004517 14465705070 015440 0 ustar robin robin {
"_comment": "This is the same as example.mux, but in JSON format. JSON doesn't really support comments, so please refer to the example.mux and advanced.mux for documentation of the settings",
"general": {
"dabmode": 1,
"nbframes": 0,
"syslog": false,
"tist": false,
"tist_offset": 0,
"managementport": 12720
},
"remotecontrol": {
"telnetport": 12721,
"zmqendpoint": "tcp://lo:12722"
},
"ensemble": {
"id": "0x4fff",
"ecc": "0xe1",
"local-time-offset": "auto",
"reconfig-counter": "hash",
"label": "OpenDigitalRadio",
"shortlabel": "ODR"
},
"services": {
"srv-fu": {
"id": "0x4daa",
"label": "Fünk"
},
"srv-ri": {
"id": "0x5dab",
"ecc": "0xe0",
"label": "Rick"
}
},
"subchannels": {
"sub-fu": {
"type": "audio",
"bitrate": 128,
"id": 10,
"protection": 3,
"inputfile": "funk.mp2"
},
"sub-bla": {
"type": "audio",
"bitrate": 96,
"id": 1,
"protection": 1,
"inputproto": "edi",
"inputuri": "tcp://0.0.0.0:9001",
"buffer-management": "prebuffering",
"buffer": 40,
"prebuffering": 20
},
"sub-ri": {
"type": "dabplus",
"bitrate": 96,
"id": 1,
"protection": 3,
"inputproto": "edi",
"inputuri": "tcp://127.0.0.1:9000",
"buffer-management": "timestamped",
"buffer": 500,
"tist-delay": 10
}
},
"components": {
"comp-fu": {
"service": "srv-fu",
"subchannel": "sub-fu"
},
"comp-ri": {
"service": "srv-ri",
"subchannel": "sub-ri",
"user-applications": {
"userapp": "slideshow"
}
}
},
"outputs": {
"throttle": "simul://",
"stdout": "fifo:///dev/stdout?type=raw",
"edi": {
"destinations": {
"example_tcp": {
"protocol": "tcp",
"listenport": 13000
}
}
}
}
}
ODR-DabMux-4.4.1/doc/TIMESTAMPS.rst 0000644 0001750 0001750 00000004572 14465705070 015333 0 ustar robin robin Some knowledge accumulated about timestamping
=============================================
The meaning of the timestamps changed between v2.3.1 and v3.0.0, this document gives some guidance about the interaction between different settings.
The following table tries to summarise the differences.
+-----------------------------+----------------------------------------------+-------------------------------------+-----------------------------------------------+
| ODR-DabMux version | Meaning of timestamp inside EDI | ODR-ZMQ2EDI wait time w | Offset that should be set in the mod |
+=============================+==============================================+=====================================+===============================================+
| Up to and including v2.3.1 | t_frame = t_mux (No offset in mux available) | positive, meaning delay after t_mux | Something larger than w + mod processing time |
+-----------------------------+----------------------------------------------+-------------------------------------+-----------------------------------------------+
| Later than v2.3.1 | t_frame = t_tx = t_mux + tist_offset | negative, meaning delay before t_tx | Something larger than mod processing time |
+-----------------------------+----------------------------------------------+-------------------------------------+-----------------------------------------------+
For historical reasons, ODR-DabMod decodes absolute timestamp from MNSC, not from “EDI seconds”.
The edilib tool decodes both EDI timestamp and MNSC, and can be used to verify both are identical.
Issues in ODR-DabMux v2.3.1
---------------------------
Running ODR-DabMux against the absolute timestamp firmware has uncovered a few issues:
* At startup, the UTCO was not properly applied to the EDI seconds. This offset was 5 seconds (TAI-UTC offset - 32s, see EDI spec);
* odr-zmq2edi did not compensate for UTCO, hiding the above issue;
* ODR-DabMux needs a configurable offset;
* (minor) MNSC and EDI timestamps did not use the same internal representation, making it difficult to prove that they encode the same value;
* (minor) odr-zmq2edi swapped endianness when regenerating EDI from ETI (minor because only ODR-DabMod considers MNSC, and usually isn't used with EDI);
**Important** Do not combine odr-zmq2edi with odr-dabmux of a different version!
ODR-DabMux-4.4.1/TODO.md 0000644 0001750 0001750 00000003117 14465705070 013427 0 ustar robin robin This TODO file lists ideas and features for future developments. They are
more or less ordered according to their benefit, but that is subjective
to some degree.
Unless written, no activity has been started on the topics.
Explicit Service Linking
------------------------
It is impossible to activate/deactive linkage sets. Commit 5c3c6d7 added
some code to transmit a FIG0/6 CEI, but this was subsequently reverted
because it was not tested enough.
Inputs for packet data
----------------------
It is currently unclear what input formats and sources work for packet data,
and which ones would make sense to add.
Also, there is no documentation on the possibilites of packet data.
Improvements for inputs
-----------------------
Add statistics to UDP input, in a similar way that ZeroMQ offers statistics.
This would mean we have to move the packet buffer from the operating system
into our own buffer, so that we can actually get the statistics.
Fix DMB input
-------------
The code that does interleaving and reed-solomon encoding for DMB is not used
anymore, and is untested. The relevant parts are `src/dabInputDmb*` and
`src/Dmb.cpp`
Communicate Leap Seconds
------------------------
Actually, we're supposed to say in FIG0/10 when there is a UTC leap second
upcoming, but since that's not trivial to find out because the POSIX time
concept is totally unaware of that, this is not done. We need to know for EDI
TIST, and the ClockTAI class can get the information from the Internet, but it
is not used in FIG0/10.
Implement FIG0/20 Service List
------------------------------
See ETSI TS 103 176
ODR-DabMux-4.4.1/.gitignore 0000644 0001750 0001750 00000000542 14465705070 014327 0 ustar robin robin *.o
*.Po
.*.swp
.directory
odr-dabmux
odr-zmq2farsync
odr-zmq2edi
zmqinput-keygen
src/dabOutput/.deps/
src/dabOutput/.dirstamp
aclocal.m4
build-aux
configure
Makefile.in
Makefile
autom4te.cache
config.h
config.log
config.status
lib/Makefile
src/Makefile
stamp-h1
config.h.in~
config.h.in
.deps
.dirstamp
*.plist
cscope.out
ctags
tags
.clang_complete
ODR-DabMux-4.4.1/configure.ac 0000644 0001750 0001750 00000014352 14465705070 014631 0 ustar robin robin # Copyright (C) 2008, 2009 Her Majesty the Queen in Right of Canada
# (Communications Research Center Canada)
#
# Copyright (C) 2023 Matthias P. Braendli, http://opendigitalradio.org
# This file is part of ODR-DabMux.
#
# ODR-DabMux 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.
#
# ODR-DabMux 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 ODR-DabMux. If not, see .
AC_PREREQ([2.69])
AC_INIT([ODR-DabMux],[4.4.1],[matthias.braendli@mpb.li])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4])
AC_CANONICAL_TARGET
AM_INIT_AUTOMAKE([-Wall foreign subdir-objects])
AC_CONFIG_SRCDIR([src/DabMux.cpp])
AC_CONFIG_HEADERS([config.h])
AM_SILENT_RULES([yes])
# Checks for programs.
AC_PROG_CXX
AC_PROG_CC
AM_PROG_CC_C_O
AC_PROG_INSTALL
AX_CXX_COMPILE_STDCXX(11,noext,mandatory)
# Checks for libraries.
AX_PTHREAD([], AC_MSG_ERROR([requires pthread]))
AX_BOOST_BASE([1.48.0], [], AC_MSG_ERROR([BOOST 1.48 or later is required]))
AX_BOOST_SYSTEM
# Checks for header files.
AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h sys/time.h unistd.h])
# Options
# Outputs
# FILE
AC_ARG_ENABLE([output_file],
[AS_HELP_STRING([--disable-output-file], [Disable FILE output])],
[], [enable_output_file=yes])
AS_IF([test "x$enable_output_file" = "xyes"],
[AC_DEFINE(HAVE_OUTPUT_FILE, [1], [Define if FILE output is enabled])])
# FIFO
AC_ARG_ENABLE([output_fifo],
[AS_HELP_STRING([--disable-output-fifo], [Disable FIFO output])],
[], [enable_output_fifo=yes])
AS_IF([test "x$enable_output_fifo" = "xyes"],
[AC_DEFINE(HAVE_OUTPUT_FIFO, [1], [Define if FIFO output is enabled])])
# UDP
AC_ARG_ENABLE([output_udp],
[AS_HELP_STRING([--disable-output-udp], [Disable UDP output])],
[], [enable_output_udp=yes])
AS_IF([test "x$enable_output_udp" = "xyes"],
[AC_DEFINE(HAVE_OUTPUT_UDP, [1], [Define if UDP output is enabled])])
# TCP
AC_ARG_ENABLE([output_tcp],
[AS_HELP_STRING([--disable-output-tcp], [Disable TCP output])],
[], [enable_output_tcp=yes])
AS_IF([test "x$enable_output_tcp" = "xyes"],
[AC_DEFINE(HAVE_OUTPUT_TCP, [1], [Define if TCP output is enabled])])
# RAW
AC_ARG_ENABLE([output_raw],
AS_HELP_STRING([--enable-output-raw], [Enable RAW output]))
AS_IF([test "x$enable_output_raw" = "xyes"],
[AC_DEFINE(HAVE_OUTPUT_RAW, [1], [Define if RAW output is enabled])])
# SIMUL
AC_ARG_ENABLE([output_simul],
[AS_HELP_STRING([--disable-output-simul], [Disable SIMUL output])],
[], [enable_output_simul=yes])
AS_IF([test "x$enable_output_simul" = "xyes"],
[AC_DEFINE(HAVE_OUTPUT_SIMUL, [1], [Define if SIMUL output is enabled])])
# EDI and ZMQ output metadata require TAI-UTC offset, which requires downloading the IETF TAI bulletin
AC_CHECK_LIB(curl, curl_easy_init)
have_curl=$ac_cv_lib_curl_curl_easy_init
AS_IF([test "x$have_curl" = "xyes"],
[AC_DEFINE(HAVE_CURL, [1], [Define if cURL is available])])
AS_IF([test "x$have_curl" = "xno"],
[AC_MSG_WARN([cURL not found, timestamps will not work])])
AC_LANG_PUSH([C++])
AX_CHECK_COMPILE_FLAG([-Wno-maybe-uninitialized], [CXXFLAGS="$CXXFLAGS -Wno-maybe-uninitialized"], [], ["-Werror"])
AX_CHECK_COMPILE_FLAG([-Wduplicated-cond], [CXXFLAGS="$CXXFLAGS -Wduplicated-cond"], [], ["-Werror"])
AX_CHECK_COMPILE_FLAG([-Wduplicated-branches], [CXXFLAGS="$CXXFLAGS -Wduplicated-branches"], [], ["-Werror"])
AX_CHECK_COMPILE_FLAG([-Wlogical-op], [CXXFLAGS="$CXXFLAGS -Wlogical-op"], [], ["-Werror"])
AX_CHECK_COMPILE_FLAG([-Wrestrict], [CXXFLAGS="$CXXFLAGS -Wrestrict"], [], ["-Werror"])
AX_CHECK_COMPILE_FLAG([-Wdouble-promotion], [CXXFLAGS="$CXXFLAGS -Wdouble-promotion"], [], ["-Werror"])
AX_CHECK_COMPILE_FLAG(["-Wformat=2"], [CXXFLAGS="$CXXFLAGS -Wformat=2"], [], ["-Werror"])
# Linux defines MSG_NOSIGNAL, some other systems have SO_NOSIGPIPE instead
AC_MSG_CHECKING(for MSG_NOSIGNAL)
AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[
#include
int f = MSG_NOSIGNAL;
]])],
[ AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_MSG_NOSIGNAL, 1, [Define this symbol if you have MSG_NOSIGNAL]) ],
[ AC_MSG_RESULT(no) ])
AC_MSG_CHECKING(for SO_NOSIGPIPE)
AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[
#include
int f = SO_NOSIGPIPE;
]])],
[ AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_SO_NOSIGPIPE, 1, [Define this symbol if you have SO_NOSIGPIPE]) ],
[ AC_MSG_RESULT(no) ])
AC_LANG_POP([C++])
# ZeroMQ
AX_ZMQ([4.0.0], [], AC_MSG_ERROR(ZeroMQ 4.0.0 is required))
AC_DEFINE([HAVE_INPUT_ZEROMQ], [1], [Define if ZeroMQ input is enabled])
AC_DEFINE([HAVE_OUTPUT_ZEROMQ], [1], [Define if ZeroMQ output is enabled])
AC_DEFINE([HAVE_ZEROMQ], [1], [Define if ZeroMQ enabled for rc])
# Do not build odr-zmq2farsync if no RAW output
AM_CONDITIONAL([HAVE_OUTPUT_RAW_TEST],
[test "x$enable_output_raw" = "xyes"])
AM_CONDITIONAL([IS_GIT_REPO], [test -d '.git'])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
echo
echo "***********************************************"
echo
echo "ZeroMQ management server enabled."
echo
echo "Inputs: prbs udp zmq fifo file"
echo
echo "Formats: raw mpeg packet dabplus dmb epm"
echo
echo "Outputs:"
enabled=""
disabled=""
for output in file fifo udp tcp raw simul
do
eval var=\$enable_output_$output
AS_IF([test "x$var" = "xyes"],
[enabled="$enabled $output"],
[disabled="$disabled $output"])
done
echo " Enabled: $enabled zmq"
echo " Disabled: $disabled"
if test "$have_curl" = "no" ; then
echo
echo "WARNING! cURL not found: ODR-DabMux will not support timestamps"
echo
fi
echo
echo "***********************************************"
echo
ODR-DabMux-4.4.1/lib/ 0000755 0001750 0001750 00000000000 14465705070 013104 5 ustar robin robin ODR-DabMux-4.4.1/lib/farsync/ 0000755 0001750 0001750 00000000000 14465705070 014551 5 ustar robin robin ODR-DabMux-4.4.1/lib/farsync/linux/ 0000755 0001750 0001750 00000000000 14465705070 015710 5 ustar robin robin ODR-DabMux-4.4.1/lib/farsync/linux/farsync.h 0000644 0001750 0001750 00000066474 14465705070 017547 0 ustar robin robin /*
* FarSync OEM driver for Linux
*
* Copyright (C) 2001-2012 FarSite Communications Ltd.
* www.farsite.co.uk
* $Id: farsync.h 1471 2013-09-10 08:01:11Z kevinc $
*
* 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
* 2 of the License, or (at your option) any later version.
*
* Author: R.J.Dunlop
*
* For the most part this file only contains structures and information
* that is visible to applications outside the driver. Shared memory
* layout etc is internal to the driver and described within farsync.c.
* Overlap exists in that the values used for some fields within the
* ioctl interface extend into the cards firmware interface so values in
* this file may not be changed arbitrarily.
*/
#define FST_NAME "fst" /* In debug/info etc */
#define FST_NDEV_NAME "sync" /* For net interface */
#define FST_DEV_NAME "farsync" /* For misc interfaces */
/* User version number
*
* This version number is incremented with each official release of the
* package and is a simplified number for normal user reference.
* Individual files are tracked by the version control system and may
* have individual versions (or IDs) that move much faster than the
* the release version as individual updates are tracked.
*/
#define FST_USER_VERSION "2.1.8"
#define FST_PATCH_LEVEL "02"
#ifdef __x86_64__
#define FST_PLATFORM "64bit"
#else
#define FST_PLATFORM "32bit"
#endif
#define FST_ADDITIONAL FST_BUILD_NO
#define FST_INCLUDES_CHAR
struct fst_device_stats
{
unsigned long rx_packets; /* total packets received */
unsigned long tx_packets; /* total packets transmitted */
unsigned long rx_bytes; /* total bytes received */
unsigned long tx_bytes; /* total bytes transmitted */
unsigned long rx_errors; /* bad packets received */
unsigned long tx_errors; /* packet transmit problems */
unsigned long rx_dropped; /* no space in linux buffers */
unsigned long tx_dropped; /* no space available in linux */
unsigned long multicast; /* multicast packets received */
unsigned long collisions;
/* detailed rx_errors: */
unsigned long rx_length_errors;
unsigned long rx_over_errors; /* receiver ring buff overflow */
unsigned long rx_crc_errors; /* recved pkt with crc error */
unsigned long rx_frame_errors;/* recv'd frame alignment error */
unsigned long rx_fifo_errors; /* recv'r fifo overrun */
unsigned long rx_missed_errors; /* receiver missed packet */
/* detailed tx_errors */
unsigned long tx_aborted_errors;
unsigned long tx_carrier_errors;
unsigned long tx_fifo_errors;
unsigned long tx_heartbeat_errors;
unsigned long tx_underrun_errors;
/* for cslip etc */
unsigned long rx_compressed;
unsigned long tx_compressed;
};
#define COM_STOP_BITS_1 0
#define COM_STOP_BITS_1_5 1
#define COM_STOP_BITS_2 2
#define COM_NO_PARITY 0
#define COM_ODD_PARITY 1
#define COM_EVEN_PARITY 2
#define COM_FORCE_PARITY_1 3
#define COM_FORCE_PARITY_0 4
#define COM_FLOW_CONTROL_NONE 1
#define COM_FLOW_CONTROL_RTSCTS 2
#define COM_FLOW_CONTROL_XONXOFF 3
struct fstioc_async_conf {
unsigned char flow_control;
unsigned char stop_bits;
unsigned char parity;
unsigned char word_length;
unsigned char xon_char;
unsigned char xoff_char;
};
/* Ioctl call command values
*
* The first three private ioctls are used by the sync-PPP module,
* allowing a little room for expansion we start our numbering at 10.
*/
#define FSTWRITE (SIOCDEVPRIVATE+4)
#define FSTCPURESET (SIOCDEVPRIVATE+5)
#define FSTCPURELEASE (SIOCDEVPRIVATE+6)
#define FSTGETCONF (SIOCDEVPRIVATE+7)
#define FSTSETCONF (SIOCDEVPRIVATE+8)
#define FSTSNOTIFY (SIOCDEVPRIVATE+9)
#define FSTGSTATE (SIOCDEVPRIVATE+10)
#define FSTSYSREQ (SIOCDEVPRIVATE+11)
#define FSTGETSHELL (SIOCDEVPRIVATE+12)
#define FSTSETMON (SIOCDEVPRIVATE+13)
#define FSTSETPORT (SIOCDEVPRIVATE+14)
#define FSTCMD (SIOCDEVPRIVATE+15)
/* FSTWRITE
*
* Used to write a block of data (firmware etc) before the card is running
*/
struct fstioc_write {
unsigned int size;
unsigned int offset;
unsigned char data[0];
};
struct fstioc_control_request {
#define FSCONTROLREQUEST_VERSION 1
__u32 uVersion; // Version of this structure
__u8 bDirection; // 1 ==> HostToDevice, 0 ==> DeviceToHost
__u8 byRequest;
__u16 wValue;
__u16 wIndex;
__u16 wDataLength;
__u8 Data[256];
};
/* FSTCPURESET and FSTCPURELEASE
*
* These take no additional data.
* FSTCPURESET forces the cards CPU into a reset state and holds it there.
* FSTCPURELEASE releases the CPU from this reset state allowing it to run,
* the reset vector should be setup before this ioctl is run.
*/
/* FSTGETCONF and FSTSETCONF
*
* Get and set a card/ports configuration.
* In order to allow selective setting of items and for the kernel to
* indicate a partial status response the first field "valid" is a bitmask
* indicating which other fields in the structure are valid.
* Many of the field names in this structure match those used in the
* firmware shared memory configuration interface and come originally from
* the NT header file Smc.h
*
* When used with FSTGETCONF this structure should be zeroed before use.
* This is to allow for possible future expansion when some of the fields
* might be used to indicate a different (expanded) structure.
*/
struct fstioc_info {
unsigned int valid; /* Bits of structure that are valid */
unsigned int nports; /* Number of serial ports */
unsigned int type; /* Type index of card */
unsigned int state; /* State of card */
unsigned int index; /* Index of port ioctl was issued on */
unsigned int smcFirmwareVersion;
unsigned long kernelVersion; /* What Kernel version we are working with */
unsigned short lineInterface; /* Physical interface type */
unsigned char proto; /* Line protocol */
unsigned char internalClock; /* 1 => internal clock, 0 => external */
unsigned int lineSpeed; /* Speed in bps */
unsigned int estLineSpeed; /* Estimated speed in bps */
unsigned int v24IpSts; /* V.24 control input status */
unsigned int v24OpSts; /* V.24 control output status */
unsigned short clockStatus; /* lsb: 0=> present, 1=> absent */
unsigned short cableStatus; /* lsb: 0=> present, 1=> absent */
unsigned short cardMode; /* lsb: LED id mode */
unsigned short debug; /* Debug flags */
unsigned char transparentMode; /* Not used always 0 */
unsigned char invertClock; /* Invert clock feature for syncing */
unsigned char asyncAbility ; /* The ability to do async */
unsigned char synthAbility; /* The ability to syth a clock */
unsigned char extendedClocking;/* New T4e clock modes */
unsigned char startingSlot; /* Time slot to use for start of tx */
unsigned char clockSource; /* External or internal */
unsigned char framing; /* E1, T1 or J1 */
unsigned char structure; /* unframed, double, crc4, f4, f12, */
/* f24 f72 */
unsigned char interface; /* rj48c or bnc */
unsigned char coding; /* hdb3 b8zs */
unsigned char lineBuildOut; /* 0, -7.5, -15, -22 */
unsigned char equalizer; /* short or lon haul settings */
unsigned char loopMode; /* various loopbacks */
unsigned char range; /* cable lengths */
unsigned char txBufferMode; /* tx elastic buffer depth */
unsigned char rxBufferMode; /* rx elastic buffer depth */
unsigned char losThreshold; /* Attenuation on LOS signal */
unsigned char idleCode; /* Value to send as idle timeslot */
unsigned int receiveBufferDelay; /* delay thro rx buffer timeslots */
unsigned int framingErrorCount; /* framing errors */
unsigned int codeViolationCount; /* code violations */
unsigned int crcErrorCount; /* CRC errors */
int lineAttenuation; /* in dB*/
unsigned short lossOfSignal;
unsigned short receiveRemoteAlarm;
unsigned short alarmIndicationSignal;
unsigned short _reserved[64];
unsigned char ignoreCarrier; /* If set transmit regardless of carrier state */
unsigned char numTxBuffers; /* No of tx buffers in card window */
unsigned char numRxBuffers; /* No of rx buffers in card window */
unsigned int txBufferSize; /* Size of tx buffers in card window */
unsigned int rxBufferSize; /* Size of rx buffers in card window */
unsigned char terminalType; /* Additional hdsl */
unsigned char annexType;
unsigned char encap;
unsigned char testMode;
unsigned char backoff;
unsigned char bLineProbingEnable;
unsigned char snrth;
unsigned char lpath;
unsigned short vpi;
unsigned short vci;
unsigned char activationStatus;
unsigned char noCommonModeStatus;
unsigned char transceiverStatus1;
unsigned char transceiverStatus2;
unsigned char lineLoss;
char signalQuality;
unsigned char nearEndBlockErrorCount;
char signalToNoiseRatio;
unsigned char erroredSecondCount;
unsigned char severelyErroredSecondCount;
unsigned char lossOfSyncWordSecondCount;
unsigned char unavailableSecondCount;
char frequencyDeviation;
char negotiatedPowerBackOff;
unsigned char negotiatedPSD;
unsigned char negotiatedBChannels;
unsigned char negotiatedZBits;
unsigned short negotiatedSyncWord;
unsigned char negotiatedStuffBits;
unsigned char chipVersion;
unsigned char firmwareVersion;
unsigned char romVersion;
unsigned short atmTxCellCount;
unsigned short atmRxCellCount;
unsigned short atmHecErrorCount;
unsigned int atmCellsDropped;
unsigned char transmitMSBFirst;
unsigned char receiveMSBFirst;
unsigned char xpldVersion;
unsigned char farEndCountryCode[2];
unsigned char farEndProviderCode[4];
unsigned char farEndVendorInfo[2];
unsigned char utopiaAtmStatus;
unsigned int termination;
unsigned int txRxStart;
unsigned char enableNRZIClocking; /* Ver 1 addition */
unsigned char lowLatency; /* Ver 1 addition */
struct fst_device_stats stats; /* Ver 1 addition */
struct fstioc_async_conf async_conf; /* Ver 2 addition */
unsigned char iocinfo_version; /* Ver 2 addition */
unsigned char extSyncClockEnable; /* Ver 3 addition */
unsigned char extSyncClockOffset; /* Ver 3 addition */
unsigned int extSyncClockRate; /* Ver 3 addition */
unsigned char ppsEnable; /* Ver 3 addition */
unsigned char ppsOffset; /* Ver 3 addition */
unsigned char cardRevMajor; /* Ver 4 addition */
unsigned char cardRevMinor; /* Ver 4 addition */
unsigned char cardRevBuild; /* Ver 4 addition */
unsigned int features; /* Ver 4 addition */
};
#define FST_MODE_HDLC 0
#define FST_MODE_TRANSPARENT 1
#define FST_MODE_BISYNC 2
#define FST_MODE_ASYNC 3
#define lowLatencyDisable 0
#define lowLatencyRx 1
#define lowLatencyTx 2
#define lowLatencyRxTx 3
/*
* FSTSNOTIFY
*
*/
#define FST_NOTIFY_OFF 0
#define FST_NOTIFY_ON 1
#define FST_NOTIFY_EXTENDED 2
#define FST_NOTIFY_BASIC_SIZE 2*sizeof(int)
/* FSTGSTATE
*
* Used to query why a state change message has been issued by the driver
* It could be because there was a change in line states or that the txq
* has reached an empty state
*/
struct fstioc_status {
int carrier_state;
int txq_length;
int rxq_length;
struct fst_device_stats stats;
};
/* FSTSYSREQ
*
* Used to provide a simple transparent command/repsonse interface between
* an application and the firmware running on the card
*/
struct fstioc_req {
unsigned short msg_type;
unsigned short msg_len;
unsigned short ret_code;
unsigned short i_reg_idx;
unsigned short value;
unsigned char u_msg[16];
unsigned char u_msg_reserved[16];
unsigned char u_reserved[4];
};
#define MSG_FIFO_DEF_SLAVE_1X 0x0001
#define MSG_FIFO_DEF_SLAVE_16X 0x0002
#define MSG_FIFO_DEF_MASTER 0x0003
#define MSG_FIFO_EEPROM_RD 0x769b
#define MSG_FIFO_EEPROM_WR 0xcd4a
#define RSP_FIFO_SUCCESS 0x0000
#define RSP_FIFO_FAILURE 0x0001
/* FSTSETMON
*
* Used to provide a simple monitoring data
*/
#define FSTIOC_MON_VERSION 0
#define FST_MON_RX 0
#define FST_MON_TX 1
struct fstioc_mon {
unsigned char version;
unsigned char tx_rx_ind;
unsigned int sequence;
unsigned long timestamp;
unsigned int length;
};
/* FSTSETPORT
*
* Used to provide a DSL port control
*/
#define FST_DSL_PORT_NORMAL 0
#define FST_DSL_PORT_ACTIVE 1
/* FSTCMD
*
* Used to read and write card data
*/
#define FSTCMD_GET_SERIAL 0
#define FSTCMD_SET_V24O 1
#define FSTCMD_GET_VERSION 2
#define FSTCMD_SET_VERSION 3
#define FSTCMD_GET_INTS 4
#define FSTCMD_RESET_INTS 5
#define FSTCMD_RESET_STATS 6
#define FSTCMD_SET_READV 7
#define FSTCMD_SET_CHAR 8
#define FSTCMD_GET_PRESERVE_SIGNALS 9
#define FSTCMD_SET_PRESERVE_SIGNALS 10
#define FSTCMD_SET_LATENCY 11
#define FSTCMD_UPDATE_CLOCK 12
#define FSTCMD_SET_CUSTOM_RATE 13
#ifdef __x86_64__
#define fstioc_info_sz_old 316
#define fstioc_info_sz_ver1 504
#define fstioc_info_sz_ver2 512
#define fstioc_info_sz_ver3 528
#define fstioc_info_sz_ver4 536
#define fstioc_info_sz_current sizeof(struct fstioc_info)
#else
#define fstioc_info_sz_old 312
#define fstioc_info_sz_ver1 408
#define fstioc_info_sz_ver2 416
#define fstioc_info_sz_ver3 428
#define fstioc_info_sz_ver4 436
#define fstioc_info_sz_current sizeof(struct fstioc_info)
#endif
#define FST_VERSION 4
#define FST_VERSION_CURRENT FST_VERSION
#define FST_VERSION_V3 3
#define FST_VERSION_V2 2
#define FST_VERSION_V1 1
#define FST_VERSION_OLD 0
#define FST_READV_NORMAL 0
#define FST_READV_SYNC 1
#define FST_READV_SYNC2 2
struct fstioc_char_data {
unsigned char queue_len;
unsigned char threshold;
unsigned char pad[14];
};
struct fstioc_latency_data {
unsigned int tx_size;
unsigned int rx_size;
unsigned int rate;
};
struct fstioc_cmd {
unsigned int version;
unsigned int command;
unsigned int status;
unsigned int input_data_len;
unsigned int output_data_len;
unsigned char * data_ptr;
};
#define FST_CUSTOM_RATE_CONFIG_VERSION 1
#define FST_CUSTOM_RATE_CONFIG_LENGTH (33+1)
#define FST_CUSTOM_RATE_CLOCK_SLAVE 0
#define FST_CUSTOM_RATE_CLOCK_LOW_SLAVE 1
#define FST_CUSTOM_RATE_CLOCK_LOW_MASTER 2
#define FST_CUSTOM_CLOCK_MULTIPLIER_1 1
#define FST_CUSTOM_CLOCK_MULTIPLIER_16 2
struct fstioc_custom_rate_config {
unsigned int version;
unsigned int rate;
unsigned int permanent;
unsigned int multiplier; /* 1 or 16 */
unsigned int clock_type; /* slave, low_slave, low_master */
char rate_info[FST_CUSTOM_RATE_CONFIG_LENGTH];
};
/* "valid" bitmask */
#define FSTVAL_NONE 0x00000000 /* Nothing valid (firmware not running).
* Slight misnomer. In fact nports,
* type, state and index will be set
* based on hardware detected.
*/
#define FSTVAL_OMODEM 0x0000001F /* First 5 bits correspond to the
* output status bits defined for
* v24OpSts
*/
#define FSTVAL_SPEED 0x00000020 /* internalClock, lineSpeed, clockStatus
*/
#define FSTVAL_CABLE 0x00000040 /* lineInterface, cableStatus */
#define FSTVAL_IMODEM 0x00000080 /* v24IpSts */
#define FSTVAL_CARD 0x00000100 /* nports, type, state, index,
* smcFirmwareVersion
*/
#define FSTVAL_PROTO 0x00000200 /* proto */
#define FSTVAL_MODE 0x00000400 /* cardMode */
#define FSTVAL_PHASE 0x00000800 /* Clock phase */
#define FSTVAL_TE1 0x00001000 /* T1E1 Configuration */
#define FSTVAL_BUFFERS 0x00002000 /* Tx and Rx buffer settings */
#define FSTVAL_DSL_S1 0x00004000 /* DSL-S1 Configuration */
#define FSTVAL_T4E 0x00008000 /* T4E Mk II Configuration */
#define FSTVAL_FLEX 0x00010000 /* FarSync Flex */
#define FSTVAL_ASYNC 0x00020000 /* Async config */
#define FSTVAL_DEBUG 0x80000000 /* debug */
#define FSTVAL_ALL 0x000FFFFF /* Note: does not include DEBUG flag */
/* "type" */
#define FST_TYPE_NONE 0 /* Probably should never happen */
#define FST_TYPE_T2P 1 /* T2P X21 2 port card */
#define FST_TYPE_T4P 2 /* T4P X21 4 port card */
#define FST_TYPE_T1U 3 /* T1U X21 1 port card */
#define FST_TYPE_T2U 4 /* T2U X21 2 port card */
#define FST_TYPE_T4U 5 /* T4U X21 4 port card */
#define FST_TYPE_TE1 6 /* T1E1 X21 1 port card */
#define FST_TYPE_DSL_S1 7 /* DSL-S1 card */
#define FST_TYPE_T4E 8 /* T4E Mk II */
#define FST_TYPE_FLEX1 9 /* FarSync Flex 1 port */
#define FST_TYPE_T4UE 10 /* T4UE 4 port PCI Express */
#define FST_TYPE_T2UE 11 /* T2UE 2 port PCI Express */
#define FST_TYPE_T4Ep 12 /* T4E+ 4 port card */
#define FST_TYPE_T2U_PMC 13 /* T2U_PMC 2 port PCI card */
#define FST_TYPE_TE1e 14 /* TE1e X21 1 port PCI Express */
#define FST_TYPE_T2Ee 15 /* T2Ee 2 port PCI Express */
#define FST_TYPE_T4Ee 16 /* T4Ee 4 port PCI Express */
#define FST_TYPE_FLEX2 17 /* FarSync Flex 1 port (v2) */
/* "family" */
#define FST_FAMILY_TXP 0 /* T2P or T4P */
#define FST_FAMILY_TXU 1 /* T1U or T2U or T4U */
/* "state" */
#define FST_UNINIT 0 /* Raw uninitialised state following
* system startup */
#define FST_RESET 1 /* Processor held in reset state */
#define FST_DOWNLOAD 2 /* Card being downloaded */
#define FST_STARTING 3 /* Released following download */
#define FST_RUNNING 4 /* Processor running */
#define FST_BADVERSION 5 /* Bad shared memory version detected */
#define FST_HALTED 6 /* Processor flagged a halt */
#define FST_IFAILED 7 /* Firmware issued initialisation failed
* interrupt
*/
/* "lineInterface" */
#define V24 1
#define X21 2
#define V35 3
#define X21D 4
#define NOCABLE 5
#define RS530_449 6
#define T1 7
#define E1 8
#define J1 9
#define SHDSL 10
#define RS485 11
#define UX35C 12
#define RS485_FDX 13
#ifndef IF_IFACE_SHDSL
#define IF_IFACE_SHDSL 0x1007 /* SHDSL (FarSite) */
#define IF_IFACE_RS530_449 0x1008 /* RS530_449 (FarSite) */
#define IF_IFACE_RS485 0x1009 /* RS485 (FarSite) */
#endif
#define IF_IFACE_RS485_FDX 0x100A /* RS485 Full Duplex (Farsite) */
#define IF_IFACE_UX35C 0x100B /* UX35C (Farsite) */
/* "proto" */
#define FST_HDLC 1 /* Cisco compatible HDLC */
#define FST_PPP 2 /* Sync PPP */
#define FST_MONITOR 3 /* Monitor only (raw packet reception) */
#define FST_RAW 4 /* Two way raw packets */
#define FST_GEN_HDLC 5 /* Using "Generic HDLC" module */
/* "internalClock" */
#define INTCLK 1
#define EXTCLK 0
/*
* The bit pattern for extendedClocking is
* 8 4 2 1 |8 4 2 1
* ec |ttrx tttx irx itx
*/
#define EXT_CLOCK_NONE 0x00
#define EXT_CLOCK_ERX_ETX 0x80
#define EXT_CLOCK_ERX_ITX 0x81
#define EXT_CLOCK_IRX_ETX 0x82
#define EXT_CLOCK_IRX_ITX 0x83
#define EXT_CLOCK_DTE_TT 0x84
#define EXT_CLOCK_DCE_TT 0x8B
/* "v24IpSts" bitmask */
#define IPSTS_CTS 0x00000001 /* Clear To Send (Indicate for X.21) */
#define IPSTS_INDICATE IPSTS_CTS
#define IPSTS_DSR 0x00000002 /* Data Set Ready (T2P Port A) */
#define IPSTS_DCD 0x00000004 /* Data Carrier Detect */
#define IPSTS_RI 0x00000008 /* Ring Indicator (T2P Port A) */
#define IPSTS_TMI 0x00000010 /* Test Mode Indicator (Not Supported)*/
/* "v24OpSts" bitmask */
#define OPSTS_RTS 0x00000001 /* Request To Send (Control for X.21) */
#define OPSTS_CONTROL OPSTS_RTS
#define OPSTS_DTR 0x00000002 /* Data Terminal Ready */
#define OPSTS_DSRS 0x00000004 /* Data Signalling Rate Select (Not
* Supported) */
#define OPSTS_SS 0x00000008 /* Select Standby (Not Supported) */
#define OPSTS_LL 0x00000010 /* Local Loop */
#define OPSTS_DCD 0x00000020 /* Only when DCD is enabled as an output */
#define OPSTS_RL 0x00000040 /* Remote Loop */
/* "cardMode" bitmask */
#define CARD_MODE_IDENTIFY 0x0001
/*
* TxRx Start Parameters
*/
#define START_TX 1
#define START_RX 2
#define START_TX_AND_RX (START_TX | START_RX)
#define START_DEFAULT START_TX_AND_RX
/*
* Constants for T1/E1 configuration
*/
/*
* Clock source
*/
#define CLOCKING_SLAVE 0
#define CLOCKING_MASTER 1
/*
* Framing
*/
#define FRAMING_E1 0
#define FRAMING_J1 1
#define FRAMING_T1 2
/*
* Structure
*/
#define STRUCTURE_UNFRAMED 0
#define STRUCTURE_E1_DOUBLE 1
#define STRUCTURE_E1_CRC4 2
#define STRUCTURE_E1_CRC4M 3
#define STRUCTURE_T1_4 4
#define STRUCTURE_T1_12 5
#define STRUCTURE_T1_24 6
#define STRUCTURE_T1_72 7
/*
* Interface
*/
#define INTERFACE_RJ48C 0
#define INTERFACE_BNC 1
/*
* Coding
*/
#define CODING_HDB3 0
#define CODING_NRZ 1
#define CODING_CMI 2
#define CODING_CMI_HDB3 3
#define CODING_CMI_B8ZS 4
#define CODING_AMI 5
#define CODING_AMI_ZCS 6
#define CODING_B8ZS 7
#define CODING_NRZI 8
#define CODING_FM0 9
#define CODING_FM1 10
#define CODING_MANCHESTER 11
#define CODING_DIFF_MANCHESTER 12
/*
* Line Build Out
*/
#define LBO_0dB 0
#define LBO_7dB5 1
#define LBO_15dB 2
#define LBO_22dB5 3
/*
* Range for long haul t1 > 655ft
*/
#define RANGE_0_133_FT 0
#define RANGE_0_40_M RANGE_0_133_FT
#define RANGE_133_266_FT 1
#define RANGE_40_81_M RANGE_133_266_FT
#define RANGE_266_399_FT 2
#define RANGE_81_122_M RANGE_266_399_FT
#define RANGE_399_533_FT 3
#define RANGE_122_162_M RANGE_399_533_FT
#define RANGE_533_655_FT 4
#define RANGE_162_200_M RANGE_533_655_FT
/*
* Receive Equaliser
*/
#define EQUALIZER_SHORT 0
#define EQUALIZER_LONG 1
/*
* Loop modes
*/
#define LOOP_NONE 0
#define LOOP_LOCAL 1
#define LOOP_PAYLOAD_EXC_TS0 2
#define LOOP_PAYLOAD_INC_TS0 3
#define LOOP_REMOTE 4
/*
* Buffer modes
*/
#define BUFFER_2_FRAME 0
#define BUFFER_1_FRAME 1
#define BUFFER_96_BIT 2
#define BUFFER_NONE 3
/*
* DSL Equipment types
*/
#define EQUIP_TYPE_REMOTE 0
#define EQUIP_TYPE_CENTRAL 1
/*
* DSL Operating modes
*/
#define ANNEX_A 1 /* US */
#define ANNEX_B 0 /* EU */
/*
* DSL ATM Encapsulation methods
*/
#define ENCAP_PPP 0
#define ENCAP_MPOA 1
#define MPOA_HEADER_LEN 8
/*
* DSL Test Modes
*/
#define TEST_MODE_NONE 0
#define TEST_MODE_DEFAULT TEST_MODE_NONE
#define TEST_MODE_ALTERNATING_SINGLE_PULSE 1
#define TEST_MODE_ANALOG_TRANSPARENT_LOOP 4
#define TEST_MODE_ANALOG_NON_TRANSPARENT_LOOP 8
#define TEST_MODE_TRANSMIT_SC_SR 9
#define TEST_MODE_TRANSMIT_TC_PAM_SCRONE 10
#define TEST_MODE_LINE_DRIVER_NO_SIGNAL 11
#define TEST_MODE_AGC_TO_LINE_DRIVER_LOOP 12
#define TEST_MODE_LOOP_TDM_TO_LINE 16
#define TEST_MODE_LOOP_PAYLOAD_TO_LINE 17
/* Debug support
*
* These should only be enabled for development kernels, production code
* should define FST_DEBUG=0 in order to exclude the code.
* Setting FST_DEBUG=1 will include all the debug code but in a disabled
* state, use the FSTSETCONF ioctl to enable specific debug actions, or
* FST_DEBUG can be set to prime the debug selection.
*/
#define FST_DEBUG 0x0000
#if FST_DEBUG
extern int fst_debug_mask; /* Bit mask of actions to debug, bits
* listed below. Note: Bit 0 is used
* to trigger the inclusion of this
* code, without enabling any actions.
*/
#define DBG_INIT 0x0002 /* Card detection and initialisation */
#define DBG_OPEN 0x0004 /* Open and close sequences */
#define DBG_PCI 0x0008 /* PCI config operations */
#define DBG_IOCTL 0x0010 /* Ioctls and other config */
#define DBG_INTR 0x0020 /* Interrupt routines (be careful) */
#define DBG_TX 0x0040 /* Packet transmission */
#define DBG_RX 0x0080 /* Packet reception */
#define DBG_CMD 0x0100 /* Port command issuing */
#define DBG_ATM 0x0200 /* ATM processing */
#define DBG_TTY 0x0400 /* PPPd processing */
#define DBG_USB 0x0800 /* USB device */
#define DBG_ASY 0x1000 /* Async functions */
#define DBG_FIFO 0x2000 /* Fifo functions */
#define DBG_ASS 0x0001 /* Assert like statements. Code that
* should never be reached, if you see
* one of these then I've been an ass
*/
#endif /* FST_DEBUG */
ODR-DabMux-4.4.1/lib/farsync/windows/ 0000755 0001750 0001750 00000000000 14465705070 016243 5 ustar robin robin ODR-DabMux-4.4.1/lib/farsync/windows/smcuser.h 0000644 0001750 0001750 00000036041 14465705070 020101 0 ustar robin robin /*******************************************************************************
*
* Program : FARSYNC
*
* File : smcuser.h
*
* Description : This common header file defines constants used throughout FarSync e.g. in
*
* 1) onboard software
* 2) PC driver (farsynct)
* 3) user-mode config apps
* 4) higher-level drivers (e.g. fswan)
*
* Modifications
*
* Version 2.0.0 18Jan01 WEB Created
* Version 2.2.0 18Jul01 WEB Certification candidate
* 22Oct01 MJD Added Transparent Mode Support - moved number and
* size of buffer definitions her from smc.h.
* 19Nov02 MJD Added X.21 Dual clock interface mode X21D - only
* for T1U/T2U/T4U.
* 28Nov02 MJD Added NOCABLE interface mode - only for T1U/T2U/
* T4U/T4P, used only by CDE when stopping a port.
* Version 3.0.0 08Oct03 MJD Added TE1 parameter constants
* Version 3.0.1 10Nov03 MJD Added tx/rxBufferMode constants for TE1.
* Version 3.0.2 03Nov04 MJD Added DSL #define's
* Version 3.0.3 24Feb05 WEB Add FS_CLOCK_SOURCE_xxx and FS_CT_BUS_xxx values
* Version 4.1.0 15Jun05 WEB Update TE1 typedefs
* Version 4.1.1 24Jun05 WEB Add T4E MkII defs
* Version 4.1.2 30Jun05 MJD Add FS_CT_BUS_FEED_FROM_OSCILLATOR define.
* Only define FS_CLOCK_SOURCE_PORT_A/B/C/D when
* T4EMKI defined (not available on T4EMKII).
* Version 4.1.3 07Jul05 MJD Add FS_CONFIG_IN_USE_XXX and FS_INDICATION_CLOCK_XXX
* values for T4E MkII.
* Version 4.1.4 08Jul05 MJD Added define for ANNEX_TYPE_AB (SHDSL)
* Version 4.1.5 14Jul05 WEB Rationalise clock reference defines
* Version 4.1.6 15Jul05 MJD Added FS_CCS_MASK_XXX defines
* Version 4.1.7 02Aug05 MJD Added FS_INDICATION_CLOCK_SWITCH_TO_PRIMARY define
*******************************************************************************/
#ifndef SMCUSER_H
#define SMCUSER_H
#ifndef UINT8
#define UINT8 unsigned char
#define INT8 char
#define INT32 long
#define UINT16 unsigned short
#define UINT32 unsigned long
#endif
#define MAX_PORTS 4 /* maximum ports on T4P - fixed don't change*/
/* Interface Types */
#define AUTO 0
#define V24 1
#define X21 2
#define V35 3
#define X21D 4
#define NOCABLE 5
#define RS530_449 6
/* Clock Sources */
#define INTCLK 1
#define EXTCLK 0
#define FS_CLOCK_REFERENCE_OSCILLATOR 0
#define FS_CLOCK_REFERENCE_PORT_A 1
#define FS_CLOCK_REFERENCE_PORT_B 2
#define FS_CLOCK_REFERENCE_PORT_C 3
#define FS_CLOCK_REFERENCE_PORT_D 4
#define FS_CLOCK_REFERENCE_CTBUS 5 /* note: this value does not differentiate between CTA or CTB */
#define FS_CLOCK_REFERENCE_CT_A 6
#define FS_CLOCK_REFERENCE_CT_B 7
#define FS_CT_BUS_MODE_SLAVE 0 /* FarSync card will act as SLAVE to the CT_BUS */
#define FS_CT_BUS_MODE_MASTER_A 1 /* FarSync card will act as MASTER to the CT_BUS_A */
#define FS_CT_BUS_MODE_MASTER_B 2 /* FarSync card will act as MASTER to the CT_BUS_B */
#define FS_CT_BUS_MODE_DEFAULT FS_CT_BUS_MODE_SLAVE
#define FS_CONFIG_IN_USE_PRIMARY 0 /* Primary clock reference is in use */
#define FS_CONFIG_IN_USE_BACKUP 1 /* Backup clock reference is in use */
#define FS_CONFIG_IN_USE_OSCILLATOR 2 /* Local oscillator clock reference is in use */
#define FS_CONFIG_IN_USE_DEFAULT FS_CONFIG_IN_USE_PRIMARY
// Indications to be signalled via the cardNotifications FIFO
#define FS_INDICATION_CLOCK_RATE_CHANGED 0x0080 /* 2 LSB's denote port A, B, C or D */
#define FS_INDICATION_CLOCK_OUT_OF_TOLERANCE1 0x0084
#define FS_INDICATION_CLOCK_IN_TOLERANCE1 0x0088
#define FS_INDICATION_CLOCK_SWITCH_TO_BACKUP 0x008c
#define FS_INDICATION_CLOCK_OUT_OF_TOLERANCE2 0x0090
#define FS_INDICATION_CLOCK_IN_TOLERANCE2 0x0094
#define FS_INDICATION_CLOCK_SWITCH_TO_OSC 0x0098
#define FS_INDICATION_CLOCK_SWITCH_TO_CTA 0x009c
#define FS_INDICATION_CLOCK_SWITCH_TO_CTB 0x00a0
#define FS_INDICATION_CLOCK_SWITCH_TO_PRIMARY 0x00a4
// Bit masks for isolating fields in uCurrentStatusSummary
#define FS_CSS_MASK_SLAVE_MASTER 0x0100 /* 0 = Slave, 1 = Master */
#define FS_CSS_MASK_CTA_CTB 0x0080 /* 0 = A, 1 = B */
#define FS_CSS_MASK_MASTER_SOURCE 0x0070 /* 000=A, 001=B, 010=C, 011=D, 100=LO */
#define FS_CSS_MASK_PORT_A_SOURCE 0x0008 /* 0 = CT, 1 = LO */
#define FS_CSS_MASK_PORT_B_SOURCE 0x0004 /* 0 = CT, 1 = LO */
#define FS_CSS_MASK_PORT_C_SOURCE 0x0002 /* 0 = CT, 1 = LO */
#define FS_CSS_MASK_PORT_D_SOURCE 0x0001 /* 0 = CT, 1 = LO */
/* Tx/Rx Start Parameters */
#define START_TX 1
#define START_RX 2
#define START_TX_AND_RX (START_TX | START_RX)
#define START_DEFAULT START_TX_AND_RX
// constants for t1/e1 service unit config
// =======================================
//
// dataRate
// rate is in bps: 8k - 1536/2048k (t1/e1), though n*64k is more usual
// e1: 0 - 1984k => framed (fractional), 2048k => unframed
// for e1 framed, bandwidth is allocated from the ninth bit of the frame
// sequentially
// for e1 unframed all 256 bits in the frame are used for data
// t1: 0 - 1536k => framed (fractional), no unframed mode in t1.
//
#define DATARATE_DEFAULT 64000L
// Clocking
//
#define CLOCKING_SLAVE 0
#define CLOCKING_DEFAULT CLOCKING_SLAVE
#define CLOCKING_MASTER 1
// Framing
//
#define FRAMING_E1 0
#define FRAMING_DEFAULT FRAMING_E1
#define FRAMING_J1 1
#define FRAMING_T1 2
// Structure
//
#define STRUCTURE_UNFRAMED 0
#define STRUCTURE_E1_DOUBLE 1
#define STRUCTURE_E1_CRC4 2
#define STRUCTURE_E1_DEFAULT STRUCTURE_E1_CRC4
#define STRUCTURE_DEFAULT STRUCTURE_E1_CRC4
#define STRUCTURE_E1_CRC4M 3
#define STRUCTURE_T1_4 4
#define STRUCTURE_T1_12 5
#define STRUCTURE_T1_24 6
#define STRUCTURE_T1_DEFAULT STRUCTURE_T1_24
#define STRUCTURE_T1_72 7
// Interface
// RJ48C is available for e1 and t1, BNC is only available for e1
//
#define INTERFACE_RJ48C 0
#define INTERFACE_DEFAULT INTERFACE_RJ48C
#define INTERFACE_BNC 1
// Coding
// hdb3 is the normal coding scheme for e1
// b8zs is the normal coding scheme for t1, though ami is sometimes used
//
#define CODING_HDB3 0
#define CODING_E1_DEFAULT CODING_HDB3
#define CODING_DEFAULT CODING_HDB3
#define CODING_NRZ 1
#define CODING_CMI 2
#define CODING_CMI_HDB3 3
#define CODING_CMI_B8ZS 4
#define CODING_AMI 5
#define CODING_AMI_ZCS 6
#define CODING_B8ZS 7
#define CODING_T1_DEFAULT CODING_B8ZS
// Line Build Out - for long haul t1 > 655ft (200m). Use with EQUALIZER_LONG.
// This parameter is ignored in e1 mode and t1/j1 short haul mode.
//
#define LBO_0dB 0
#define LBO_DEFAULT LBO_0dB
#define LBO_7dB5 1
#define LBO_15dB 2
#define LBO_22dB5 3
// Range - for short haul t1 < 655ft (200m). Use with EQUALIZER_SHORT.
// This parameter is ignored in e1 mode and t1/j1 long haul mode.
//
#define RANGE_0_133_FT 0
#define RANGE_DEFAULT RANGE_0_133_FT
#define RANGE_0_40_M RANGE_0_133_FT
#define RANGE_133_266_FT 1
#define RANGE_40_81_M RANGE_133_266_FT
#define RANGE_266_399_FT 2
#define RANGE_81_122_M RANGE_266_399_FT
#define RANGE_399_533_FT 3
#define RANGE_122_162_M RANGE_399_533_FT
#define RANGE_533_655_FT 4
#define RANGE_162_200_M RANGE_533_655_FT
// Receive Equalizer
// short haul -10dB
// long haul -43dB (E1), -36dB (T1)
// only -36dB can be met with 1.2 silicon, requires equalizer parameter RAM
// changes for 2.1 silicon
//
#define EQUALIZER_SHORT 0
#define EQUALIZER_DEFAULT EQUALIZER_SHORT
#define EQUALIZER_LONG 1
// Loop Mode
// Local Loop transmits normally and loops PCM data on the line side of the
// framers.
// Payload Loop receives normally and loops TS0-TS31 or TS1-31 (with TS0
// regenerated by FALC-56) to line on the PCM side of the framers.
// Remote Loop receives normally and loops line data after clock recovery
// the optional Jitter Attenuation is currently not enabled.
#define LOOP_NONE 0
#define LOOP_DEFAULT LOOP_NONE
#define LOOP_LOCAL 1
#define LOOP_PAYLOAD_EXC_TS0 2
#define LOOP_PAYLOAD_INC_TS0 3
#define LOOP_REMOTE 4
// Buffer Mode
// buffer_none bypasses the elastic buffer
//
#define BUFFER_2_FRAME 0
#define BUFFER_DEFAULT BUFFER_2_FRAME
#define BUFFER_1_FRAME 1
#define BUFFER_96_BIT 2
#define BUFFER_NONE 3
//
// Starting Timeslot (for fractional)
// E1 range 1 to 31, T1/J1 range 0 to 23
// Min/max values enforced by card. Actual speed may also be restricted if
// starting timeslot is too late in the frame.
// Parameter ignored in unchannelized mode
//
#define STARTING_DEFAULT 0
//
// LOS detection threshold
// level 0 allows LOS to be detected with larger signal levels
// level 7 allows LOS to be detected with smaller signal levels
// the recommended default setting is level 2 - which is selected
// by the card if LOS_DEFAULT is configured
//
#define LOS_DEFAULT 0
#define LOS_LEVEL_0 1
#define LOS_LEVEL_1 2
#define LOS_LEVEL_2 3
#define LOS_LEVEL_3 4
#define LOS_LEVEL_4 5
#define LOS_LEVEL_5 6
#define LOS_LEVEL_6 7
#define LOS_LEVEL_7 8
#define LOS_SHORT 0x20
#define LOS_LONG 0x70
//
// Idle code for unused timeslots
//
#define IDLE_HDLC_FLAG 0x7e
#define IDLE_CODE_DEFAULT IDLE_HDLC_FLAG
#define TRANSPARENT_MODE_DEFAULT FALSE
#define ENABLE_IDLE_CODE_DEFAULT FALSE
// constants for dsl service unit config
// =======================================
//
// dataRate (G.SHDSL)
// rate is in bps: 192kbps (3B + 0Z) - 2312kbps (36B + 1Z)
// in 8kbps steps, where B is 64kbps and Z is 8kbps
//
//
// Terminal Type
//
#define TERMINAL_TYPE_REMOTE 0
#define TERMINAL_TYPE_CENTRAL 1
//
// Test Mode
//
// For User Diagnostics:
//
// Analog Transparent Loop - loops from transmit line driver output to
// receive AGC input, bypassing the hybrid.
// Analog Non-Transparent Loop - loops transmit DAC back to receive AGC,
// bypassing transmit line driver and the hybrid.
//
// Others test modes are for Compliance Testing only
//
#define TEST_MODE_NONE 0
#define TEST_MODE_DEFAULT TEST_MODE_NONE
#define TEST_MODE_ALTERNATING_SINGLE_PULSE 1
#define TEST_MODE_ANALOG_TRANSPARENT_LOOP 4
#define TEST_MODE_ANALOG_NON_TRANSPARENT_LOOP 8
#define TEST_MODE_TRANSMIT_SC_SR 9
#define TEST_MODE_TRANSMIT_TC_PAM_SCRONE 10
#define TEST_MODE_LINE_DRIVER_NO_SIGNAL 11
#define TEST_MODE_AGC_TO_LINE_DRIVER_LOOP 12
#define TEST_MODE_LOOP_TDM_TO_LINE 16
#define TEST_MODE_LOOP_PAYLOAD_TO_LINE 17
//
// Annex Type A (US) or B (EU)
//
#define ANNEX_TYPE_B 0
#define ANNEX_TYPE_DEFAULT ANNEX_TYPE_B
#define ANNEX_TYPE_A 1
#define ANNEX_TYPE_AB 2
/* Small Buffers are used only for diagnostics */
#define NUM_SMALL_TX_BUFFER 2
#define NUM_SMALL_RX_BUFFER 8
#define LEN_SMALL_TX_BUFFER 256 /* max size is 8192 */
#define LEN_SMALL_RX_BUFFER 256
/* Large Buffers are used for SDMA data */
// MAX_TX/RX_BUFFER determines, at compile time, the maximum number of
// descriptors (hence buffers) per port for transmitter and receiver. Host can
// use any 2**N number of the descriptors between 1 and MAX_TX/RX_BUFFER, so
// some descriptors may be unused. Number of Buffers * Size of Buffers <=
// TX/RX_BUFFER_SPACE. Fewer buffers mean bigger buffers, more buffers mean
// smaller buffers.
#define MAX_TX_BUFFER 128
#define MAX_RX_BUFFER 128
// MAX_TX/RX_BUFFER_SPACE determines, at compile time, how much buffer space is
// available per port for transmitter and receiver. Buffer space is subdivided
// into 2**N buffers by host driver at runtime.
// Host can allocate 1 - MAX_TX/RX_BUFFER buffers.
// 0x10000 => 64KB for transmit, 64KB for receive; 4 ports => 512KB.
// MAX_TX/RX_BUFFER must be a 2**N multiple (for easy logic anlyser trigger).
#define TX_BUFFER_SPACE 0x10000
#define RX_BUFFER_SPACE 0x10000
/* Rx Descriptor bits */
#define FS_RX_DESC_ERR 0x4000
#define FS_RX_DESC_FRAM 0x2000
#define FS_RX_DESC_OFLO 0x1000
#define FS_RX_DESC_CRC 0x0800
#define FS_RX_DESC_HBUF 0x0400
#define FS_RX_DESC_ENP 0x0100
#define FS_RX_DESC_FRAM_ENP 0x2100
#define FS_RX_DESC_CRC_ENP 0x0900
#define NO_OF_DMA_CHANNELS 2
// The following structures require 2-byte packing.
// This file is used in a number of different environments.
// Windows SDCI applications should therefore include this file implicitly by explicitly
// including fscfg.h which enables the packing directive to be used.
#ifdef SMCUSER_PACKING
#if (SMCUSER_PACKING==1)
#pragma pack(push, 2)
#endif
typedef struct SU_CONFIG
{
UINT32 dataRate; // data rate in bps
UINT8 clocking; // master or slave
UINT8 framing; // E1, T1 or J1
UINT8 structure; // E1: unframed, double frame, CRC4; T1: F4, F12, F24 or F72
UINT8 iface; // RJ48C or BNC
UINT8 coding; // HDB3 or B8ZS + some other less used codes
UINT8 lineBuildOut; // 0, -7.5, -15, -22.5dB for t1 long haul only
UINT8 equalizer; // short or long haul settings
UINT8 transparentMode; // FALSE (hdlc) or TRUE transparent data
UINT8 loopMode; // various local, payload and remote loops for test
UINT8 range; // 0-133, 133-266, 266-399, 399-533, 533-655ft for t1 short haul only
UINT8 txBufferMode; // transmit elastic buffer depth: 0 (bypass), 96 bits, 1 frame or 2 frame
UINT8 rxBufferMode; // receive elastic buffer depth: 0 (bypass), 96 bits, 1 frame or 2 frame
UINT8 startingTimeSlot;// startingTimeSlot: E1 1-31, T1/J1 0-23
UINT8 losThreshold; // LOS Threshold: E1/T1/J1 0-7
UINT8 enableIdleCode; // Enable idle code for unused timeslots: TRUE, FALSE
UINT8 idleCode; // Idle code for unused timeslots: 0x00 - 0xff
UINT8 spare[44]; // adjust to keep structure size 64 bytes
} FS_TE1_CONFIG, *PFS_TE1_CONFIG;
typedef struct SU_STATUS
{
UINT32 receiveBufferDelay; // delay through receive bufffer time slots (0-63)
UINT32 framingErrorCounter; // count of framing errors
UINT32 codeViolationCounter; // count of code violations
UINT32 crcErrorCounter1; // count of CRC errors
INT32 lineAttenuation; // receive line attenuation in dB, -ve => unknown
BOOLEAN portStarted; //
BOOLEAN lossOfSignal; // LOS alarm
BOOLEAN receiveRemoteAlarm; // RRA alarm
BOOLEAN alarmIndicationSignal; // AIS alarm
UINT8 spare[40]; // adjust to keep structure size 64 bytes
} FS_TE1_STATUS, *PFS_TE1_STATUS;
#if (SMCUSER_PACKING==1)
#pragma pack(pop)
#endif
#else
#pragma message("!!! *** SMCUSER_PACKING not defined. Note: Windows SDCI apps should *** !!!")
#pragma message("!!! *** not include smcuser.h directly, use fscfg.h instead *** !!!")
#endif
#endif
ODR-DabMux-4.4.1/lib/farsync/windows/sdci.h 0000644 0001750 0001750 00000113244 14465705070 017343 0 ustar robin robin /*******************************************************************************
*
* Program : FarSync (generic)
*
* File : sdci.h
*
* Description : This header file is based on the Equates and Structure Layouts
* page of the SDCI section of the July '99 MSDN
*
* Modifications
*
* Version 2.1.0 01Mar01 WEB Add QuickStart and GetLinkInterface
* Version 2.2.0 18Jul01 WEB Certification candidate
* Version 2.2.1 07Aug01 JPG Add FarSyncReadSignals
* Version 2.2.2 03Sep01 WEB Extend USERDPC definition to include indication
* param instead of bReadIR
* 22Oct01 MJD Added Transparent Mode support - defined
* LinkOption_Transparent
* Version 3.0.0 12Sep02 WEB Add dma mode and cardinfoex support definitions
* Version 3.1.0 07Nov02 WEB Add interrupt handshake mode support definitions
* Version 3.2.0 09Dec02 WEB Add LinkOption_InvertRxClock
* Add ResetStats IOCTL and extended InterfaceRecord
* Complete CardInfoEx definition
* Version 3.3.0 30Apr04 WEB Extend CardInfoEx to include physical + IO address
* Version 3.3.1 03Mar05 WEB Removed SA_TxAbort which was previously incorrectly
* named
* Version 4.0.1 03Mar05 WEB Correct IOCTL_SDCI_xxx definitions. Now requires
* CTL_CODE to be defined i.e winioctl.h (user-mode) or
* wdm.h (kernel-mode) must be included before this file.
* Add USERDPC_INDICATION_TX, FarSyncSetUserDpcEx,
* IoctlCodeFarSyncSetPortConfig,
* IoctlCodeFarSyncGetPortConfig,
* IoctlCodeFarSyncSetSerialConfig,
* IoctlCodeFarSyncGetSerialConfig
* IoctlCodeFarSyncSetCTBusConfig &
* IoctlCodeFarSyncGetCTBusConfig
* Version 4.0.1.1 03Mar05 WEB Update FS_XXX_CONFIG structures
* Version 4.0.1.2 04Mar05 WEB Update error counter explanations,
* FarSync-specific error codes & further
* rationalisations
* Version 4.1.0.0 15Jun05 WEB Add TE1 and additional T4E definitions
* Add monitoring IOCTLs
* Version 4.1.0.1 02Aug05 MJD Added USERDPC_INDICATION_CLOCK_SWITCH_TO_PRIMARY
* Version 4.1.0.2 09Aug05 MJD Update FS_CLOCKING_STATUS to include uCTAInUse so
* that apps can tell which CT Bus the hardware is
* using in slave mode, structure version now 2.
* Version 4.2.0 12Sep05 WEB Add async and synth detection fields to
* FSCARDINFOEX
* SA_RxFrameTooBig is now supported by M1P
* Add FS_ERROR_INVALID_LENGTH definition
*
*******************************************************************************/
#ifndef __SDCI_H_
#define __SDCI_H_
/*****************************************************************************/
//
// There are the IOCTL code values used to communicate with the SDCI driver.
//
/*****************************************************************************/
#define IOCTL_SDCI_SetEvent CTL_CODE(0, (0x410 >> 2), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SDCI_SetLinkCharacteristics CTL_CODE(0, (0x420 >> 2), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SDCI_SetV24OutputStatus CTL_CODE(0, (0x430 >> 2), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SDCI_TransmitFrame CTL_CODE(0, (0x440 >> 2), METHOD_IN_DIRECT, FILE_ANY_ACCESS)
#define IOCTL_SDCI_AbortTransmit CTL_CODE(0, (0x450 >> 2), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SDCI_AbortReceiver CTL_CODE(0, (0x460 >> 2), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SDCI_OffBoardLoad CTL_CODE(0, (0x470 >> 2), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SDCI_GetV24Status CTL_CODE(0, (0x620 >> 2), METHOD_NEITHER, FILE_ANY_ACCESS)
#define IOCTL_SDCI_ReceiveFrame CTL_CODE(0, (0x630 >> 2), METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncReceiveFrame CTL_CODE(0, (0x630 >> 2), METHOD_NEITHER, FILE_ANY_ACCESS)
#define IOCTL_SDCI_ReadInterfaceRecord CTL_CODE(0, (0x640 >> 2), METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncReadInterfaceRecord CTL_CODE(0, (0x640 >> 2), METHOD_NEITHER, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncReadInterfaceRecordEx CTL_CODE(0, (0x650 >> 2), METHOD_NEITHER, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncSetLinkInterface CTL_CODE(0, (0x710 >> 2), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncSetUserDpc CTL_CODE(0, (0x720 >> 2), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncSetCardMode CTL_CODE(0, (0x730 >> 2), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncReadCardInfo CTL_CODE(0, (0x740 >> 2), METHOD_NEITHER, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncQuickStart CTL_CODE(0, (0x750 >> 2), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncGetLinkInterface CTL_CODE(0, (0x760 >> 2), METHOD_NEITHER, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncReadSignals CTL_CODE(0, (0x770 >> 2), METHOD_NEITHER, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncSetDMAMode CTL_CODE(0, (0x780 >> 2), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncGetDMAMode CTL_CODE(0, (0x790 >> 2), METHOD_NEITHER, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncReadCardInfoEx CTL_CODE(0, (0x7a0 >> 2), METHOD_NEITHER, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncSetHandShakeMode CTL_CODE(0, (0x7b0 >> 2), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncGetHandShakeMode CTL_CODE(0, (0x7c0 >> 2), METHOD_NEITHER, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncResetStats CTL_CODE(0, (0x7d0 >> 2), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncReadTE1Status CTL_CODE(0, (0x7e0 >> 2), METHOD_NEITHER, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncSetUserDpcEx CTL_CODE(0, (0x7f0 >> 2), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncSetPortConfig CTL_CODE(0, (0x810 >> 2), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncGetPortConfig CTL_CODE(0, (0x820 >> 2), METHOD_NEITHER, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncSetSerialConfig CTL_CODE(0, (0x830 >> 2), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncGetSerialConfig CTL_CODE(0, (0x840 >> 2), METHOD_NEITHER, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncSetCTBusConfig CTL_CODE(0, (0x850 >> 2), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncGetCTBusConfig CTL_CODE(0, (0x860 >> 2), METHOD_NEITHER, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncSetTE1Config CTL_CODE(0, (0x870 >> 2), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncGetTE1Config CTL_CODE(0, (0x880 >> 2), METHOD_NEITHER, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncSetCTBusBackupConfig CTL_CODE(0, (0x890 >> 2), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncGetCTBusBackupConfig CTL_CODE(0, (0x8a0 >> 2), METHOD_NEITHER, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncGetClockingStatus CTL_CODE(0, (0x8b0 >> 2), METHOD_NEITHER, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncSetMonitoring CTL_CODE(0, (0x8c0 >> 2), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SDCI_FarSyncGetMonitoringStatus CTL_CODE(0, (0x8d0 >> 2), METHOD_NEITHER, FILE_ANY_ACCESS)
#define IoctlCodeSetEvent IOCTL_SDCI_SetEvent
#define IoctlCodeSetLinkChar IOCTL_SDCI_SetLinkCharacteristics
#define IoctlCodeSetV24 IOCTL_SDCI_SetV24OutputStatus
#define IoctlCodeTxFrame IOCTL_SDCI_TransmitFrame
#define IoctlCodeAbortTransmit IOCTL_SDCI_AbortTransmit
#define IoctlCodeAbortReceiver IOCTL_SDCI_AbortReceiver
#define IoctlCodeOffBoardLoad IOCTL_SDCI_OffBoardLoad
#define IoctlCodeGetV24 IOCTL_SDCI_GetV24Status
#define IoctlCodeRxFrame IOCTL_SDCI_ReceiveFrame
#define IoctlCodeFarSyncRxFrame IOCTL_SDCI_FarSyncReceiveFrame
#define IoctlCodeReadInterfaceRecord IOCTL_SDCI_ReadInterfaceRecord
#define IoctlCodeFarSyncReadInterfaceRecord IOCTL_SDCI_FarSyncReadInterfaceRecord
#define IoctlCodeFarSyncReadInterfaceRecordEx IOCTL_SDCI_FarSyncReadInterfaceRecordEx
#define IoctlCodeFarSyncSetLinkInterface IOCTL_SDCI_FarSyncSetLinkInterface
#define IoctlCodeSetLinkInterface IoctlCodeFarSyncSetLinkInterface
#define IoctlCodeFarSyncSetUserDpc IOCTL_SDCI_FarSyncSetUserDpc
#define IoctlCodeFarSyncSetCardMode IOCTL_SDCI_FarSyncSetCardMode
#define IoctlCodeFarSyncReadCardInfo IOCTL_SDCI_FarSyncReadCardInfo
#define IoctlCodeFarSyncQuickStart IOCTL_SDCI_FarSyncQuickStart
#define IoctlCodeFarSyncGetLinkInterface IOCTL_SDCI_FarSyncGetLinkInterface
#define IoctlCodeFarSyncReadSignals IOCTL_SDCI_FarSyncReadSignals
#define IoctlCodeFarSyncSetDMAMode IOCTL_SDCI_FarSyncSetDMAMode
#define IoctlCodeFarSyncGetDMAMode IOCTL_SDCI_FarSyncGetDMAMode
#define IoctlCodeFarSyncReadCardInfoEx IOCTL_SDCI_FarSyncReadCardInfoEx
#define IoctlCodeFarSyncSetHandShakeMode IOCTL_SDCI_FarSyncSetHandShakeMode
#define IoctlCodeFarSyncGetHandShakeMode IOCTL_SDCI_FarSyncGetHandShakeMode
#define IoctlCodeFarSyncResetStats IOCTL_SDCI_FarSyncResetStats
#define IoctlCodeFarSyncReadTE1Status IOCTL_SDCI_FarSyncReadTE1Status
#define IoctlCodeFarSyncSetUserDpcEx IOCTL_SDCI_FarSyncSetUserDpcEx
#define IoctlCodeFarSyncSetPortConfig IOCTL_SDCI_FarSyncSetPortConfig
#define IoctlCodeFarSyncGetPortConfig IOCTL_SDCI_FarSyncGetPortConfig
#define IoctlCodeFarSyncSetSerialConfig IOCTL_SDCI_FarSyncSetSerialConfig
#define IoctlCodeFarSyncGetSerialConfig IOCTL_SDCI_FarSyncGetSerialConfig
#define IoctlCodeFarSyncSetCTBusConfig IOCTL_SDCI_FarSyncSetCTBusConfig
#define IoctlCodeFarSyncGetCTBusConfig IOCTL_SDCI_FarSyncGetCTBusConfig
#define IoctlCodeFarSyncSetTE1Config IOCTL_SDCI_FarSyncSetTE1Config
#define IoctlCodeFarSyncGetTE1Config IOCTL_SDCI_FarSyncGetTE1Config
#define IoctlCodeFarSyncSetCTBusBackupConfig IOCTL_SDCI_FarSyncSetCTBusBackupConfig
#define IoctlCodeFarSyncGetCTBusBackupConfig IOCTL_SDCI_FarSyncGetCTBusBackupConfig
#define IoctlCodeFarSyncGetClockingStatus IOCTL_SDCI_FarSyncGetClockingStatus
#define IoctlCodeFarSyncSetMonitoring IOCTL_SDCI_FarSyncSetMonitoring
#define IoctlCodeFarSyncGetMonitoringStatus IOCTL_SDCI_FarSyncGetMonitoringStatus
/*****************************************************************************/
/* Constants for the driver-specific IOCtl return codes. */
/*****************************************************************************/
#define CEDNODMA 0xff80 /* Warning (NO DMA!) from set link chrctrstcs */
/*****************************************************************************/
/* Equates for the link options byte 1. */
/*****************************************************************************/
#define CEL4WIRE 0x80
#define CELNRZI 0x40
#define CELPDPLX 0x20
#define CELSDPLX 0x10
#define CELCLOCK 0x08
#define CELDSRS 0x04
#define CELSTNBY 0x02
#define CELDMA 0x01
/*****************************************************************************/
/* Equates for the driver set link characteristics byte 1. */
/*****************************************************************************/
#define CED4WIRE 0x80
#define CEDNRZI 0x40
#define CEDHDLC 0x20
#define CEDFDPLX 0x10
#define CEDCLOCK 0x08
#define CEDDMA 0x04
#define CEDRSTAT 0x02
#define CEDCSTAT 0x01
/* Nicer names for NT-style code */
#define LinkOption_4Wire CED4WIRE
#define LinkOption_InvertRxClock CEDDMA
#define LinkOption_NRZI CEDNRZI
#define LinkOption_HDLC CEDHDLC
#define LinkOption_FullDuplex CEDFDPLX
#define LinkOption_InternalClock CEDCLOCK
#define LinkOption_DMA CEDDMA
#define LinkOption_ResetStatistics CEDRSTAT
#define LinkOption_Transparent CEDCSTAT
/*****************************************************************************/
/* Equates for the output V24 interface flags. */
/*****************************************************************************/
#define CED24RTS 0x01
#define CED24DTR 0x02
// #define CED24DRS 0x04- not used. 0x04 is instead used by DCD
// i.e. when configured as an output - see below
#define CED24SLS 0x08
#define CED24TST 0x10
/* Nicer names for NT-style code */
#define IR_OV24RTS CED24RTS
#define IR_OV24DTR CED24DTR
//#define IR_OV24DSRS CED24DRS
#define IR_OV24SlSt CED24SLS
#define IR_OV24Test CED24TST
/*****************************************************************************/
/* Equates for the input V24 interface flags. */
/*****************************************************************************/
#define CED24CTS 0x01
#define CED24DSR 0x02
#define CED24DCD 0x04
#define CED24RI 0x08
// CEDCR indicates the presense of a generic carrier i.e. independent of port type
// e.g. DCD for V.25, CTS for X.21
#define CEDCR 0x10
// Note: DCD can only be used as an output signal on a FarSync T4E
// and only then if a FarSyncSetSerialConfig has been previously
// issued for this port, with FsSerialConfig.uDCDOutput set to
// TRUE
/* Nicer names for NT-style code */
#define IR_IV24CTS CED24CTS
#define IR_IV24DSR CED24DSR
#define IR_IV24DCD CED24DCD
#define IR_IV24RI CED24RI
#define IR_IV24Test 0x10
/*****************************************************************************/
/* Structure for the device driver interface record. */
/*****************************************************************************/
#define CEDSTCRC 0 /* Frames received with incorrect CRC */
#define CEDSTOFL 1 /* Frames received longer than the maximum */
#define CEDSTUFL 2 /* Frames received less than 4 octets long */
#define CEDSTSPR 3 /* Frames received ending on a non-octet bndry */
#define CEDSTABT 4 /* Aborted frames received */
#define CEDSTTXU 5 /* Transmitter interrupt underruns */
#define CEDSTRXO 6 /* Receiver interrupt overruns */
#define CEDSTDCD 7 /* DCD (RLSD) lost during frame reception */
#define CEDSTCTS 8 /* CTS lost while transmitting */
#define CEDSTDSR 9 /* DSR drops */
#define CEDSTHDW 10 /* Hardware failures - adapter errors */
#define CEDSTMAX 11
#define SA_CRC_Error CEDSTCRC
#define SA_RxFrameTooBig CEDSTOFL
#define SA_RxFrameTooShort CEDSTUFL
#define SA_Spare CEDSTSPR
#define SA_RxAbort CEDSTABT
#define SA_TxUnderrun CEDSTTXU
#define SA_RxOverrun CEDSTRXO
#define SA_DCDDrop CEDSTDCD
#define SA_CTSDrop CEDSTCTS
#define SA_DSRDrop CEDSTDSR
#define SA_HardwareError CEDSTHDW
// FarSync-specific counters mapped to existing SDCI definitions
#define SA_FramingError SA_Spare
#define SA_RxError SA_HardwareError
#define SA_BufferUnavailable SA_DCDDrop
#define SA_Parity SA_CRC_Error
#define SA_Max_Stat CEDSTMAX
// ****************************************************************************************************
// FarSync supports the following counters. All other counter indices are not used by FarSync.
// SA_CRC_Error Sync & Async modes
// SA_FramingError Sync & Async modes
// SA_RxOverrun Sync & Async modes
// SA_RxAbort (Async) & (M1P Sync) modes only
// SA_RxError Sync mode only
// SA_TxUnderrun Sync mode only
// SA_RxFrameTooShort M1P Sync mode only
// SA_RxFrameTooBig Async mode (fifo overflow) & M1P Sync
// Note that
// 1) Async mode is currently only supported on the T4U - it is an optional extra feature
// 2) On a TxU an SA_RxError indicates a received abort OR a rx frame length error (too big OR too small)
// 3) On an M1P an SA_RxError indicates a alternative type of RxO as reported via SA_RxOverrun
// ****************************************************************************************************
/*****************************************************************************/
/* InterfaceRecord definition */
/* */
/* For use with: */
/* */
/* IoctlCodeReadInterfaceRecord, */
/* IoctlCodeFarSyncReadInterfaceRecord */
/* */
/*****************************************************************************/
typedef struct _INTERFACE_RECORD
{
int RxFrameCount; /* incremented after each frame rx'd */
int TxMaxFrSizeNow; /* max available frame size av. now */
/* (changes after each Tx DevIoctl */
/* to DD or after Tx completed) */
int StatusCount; /* How many status events have been */
/* triggered. */
UCHAR V24In; /* Last 'getv24 i/p' value got */
UCHAR V24Out; /* Last 'setv24 o/p' value set */
/* The values for the indexes into the link statistics array of the */
/* various types of statistic. */
int StatusArray[SA_Max_Stat];
} IR, * PIR;
/*****************************************************************************/
/* InterfaceRecordEx definition */
/* */
/* For use with: */
/* */
/* IoctlCodeFarSyncReadInterfaceRecordEx */
/* */
/*****************************************************************************/
typedef struct _INTERFACE_RECORD_EX
{
IR InterfaceRecord;
int StatusCount; /* How many status events have been */
ULONG OpenedCount;
ULONG TxRequestCount;
ULONG TxCompleteCount;
ULONG RxPostedCount;
ULONG RxCompleteCount;
} IREX, * PIREX;
/*****************************************************************************/
/* Set link characteristics parameter block definition */
/* */
/* For use with: */
/* */
/* IoctlCodeSetLinkChar */
/* */
/*****************************************************************************/
typedef struct _SLPARMS
{
int SLFrameSize; /* max frame size on link, should */
/* include 2-byte CRC - max is 8K */
LONG SLDataRate; /* not used by us - external clocks */
UCHAR SLOurAddress1; /* ) e.g C1/FF or 00/00 or 01/03 */
UCHAR SLOurAddress2; /* ) */
UCHAR SLLinkOptionsByte; /* see documentation & LinkOption_* */
UCHAR SLSpare1;
} SLPARMS, *PSLPARMS;
/*****************************************************************************/
/* Set link interface parameter block definition */
/* */
/* For use with: */
/* */
/* IoctlCodeFarSyncSetLinkInterface, */
/* IoctlCodeFarSyncGetLinkInterface */
/* */
/*****************************************************************************/
#pragma pack(push, 4) /* Note: sizeof(FsLinkIfParms) is expected to be 0x10 */
typedef struct _FSLINKIFPARMS
{
HANDLE Context; // context for completion routine - not used
USHORT MaxFrameSize; // maximum frame size - not used
USHORT Interface; // line interface:
ULONG BaudRate; // baud rate
UCHAR Reserved; // reserved
} FSLINKIFPARMS, * PFSLINKIFPARMS;
#pragma pack(pop)
// USER DPC DEFINITIONS - KERNEL-MODE ONLY
#define USERDPC_INDICATION_RX 0
#define USERDPC_INDICATION_SIGNAL 1
#define USERDPC_INDICATION_ERROR 2
#define USERDPC_INDICATION_TX 3 /* indicates that the number of tx buffers
in use by the card has changed - examine
*pUserDpcTxBuffersInUse for the current value */
// FarSync T4E clock notifications
#define USERDPC_INDICATION_CLOCK_RATE_CHANGED FS_INDICATION_CLOCK_RATE_CHANGED
#define USERDPC_INDICATION_CLOCK_OUT_OF_TOLERANCE1 FS_INDICATION_CLOCK_OUT_OF_TOLERANCE1
#define USERDPC_INDICATION_CLOCK_IN_TOLERANCE1 FS_INDICATION_CLOCK_IN_TOLERANCE1
#define USERDPC_INDICATION_CLOCK_SWITCH_TO_BACKUP FS_INDICATION_CLOCK_SWITCH_TO_BACKUP
#define USERDPC_INDICATION_CLOCK_OUT_OF_TOLERANCE2 FS_INDICATION_CLOCK_OUT_OF_TOLERANCE2
#define USERDPC_INDICATION_CLOCK_IN_TOLERANCE2 FS_INDICATION_CLOCK_IN_TOLERANCE2
#define USERDPC_INDICATION_CLOCK_SWITCH_TO_OSC FS_INDICATION_CLOCK_SWITCH_TO_OSC
#define USERDPC_INDICATION_CLOCK_SWITCH_TO_CTA FS_INDICATION_CLOCK_SWITCH_TO_CTA
#define USERDPC_INDICATION_CLOCK_SWITCH_TO_CTB FS_INDICATION_CLOCK_SWITCH_TO_CTB
#define USERDPC_INDICATION_CLOCK_SWITCH_TO_PRIMARY FS_INDICATION_CLOCK_SWITCH_TO_PRIMARY
// user DPC callback - kernel mode only
typedef VOID (*USERDPC)(PVOID /* caller's handle*/, unsigned char /* indication */);
/*****************************************************************************/
/* Set user dpc parameter block definition */
/* */
/* For use with: */
/* */
/* IoctlCodeFarSyncSetUserDpc , */
/* */
/*****************************************************************************/
#pragma pack(push, 4)
typedef struct _FSUSERDPCINFO
{
USERDPC fUserDpc; // callback address
PVOID pUserDpcParam; // param to supply in callback
} FSUSERDPCINFO, * PFSUSERDPCINFO;
/*****************************************************************************/
/* Extended set user dpc parameter block definition */
/* */
/* For use with: */
/* */
/* IoctlCodeFarSyncSetUserDpcEx , */
/* */
/* If used, this structure must be allocated in NonPaged memory. */
/* */
/*****************************************************************************/
typedef struct _FSUSERDPCINFOEX
{
FSUSERDPCINFO fUserDpcInfo;
long * pUserDpcTxBuffersInUse; // ref to a SDCI client-owned var that is used to maintain the number of tx buffers
// currently in use by the card.
} FSUSERDPCINFOEX, * PFSUSERDPCINFOEX;
#pragma pack(pop)
/*****************************************************************************/
/* Card mode parameter block definition */
/* */
/* For use with: */
/* */
/* IoctlCodeFarSyncSetCardMode , */
/* */
/*****************************************************************************/
#pragma pack(push, 4)
typedef struct _FSCARDMODE
{
BOOLEAN bIdentifyMode;
} FSCARDMODE, * PFSCARDMODE;
#pragma pack(pop)
/*****************************************************************************/
/* Card info parameter block definition */
/* */
/* For use with: */
/* */
/* IoctlCodeFarSyncReadCardInfo , */
/* */
/*****************************************************************************/
#pragma pack(push, 4)
typedef struct _FSCARDINFO
{
#define FSCARDINFO_VERSION 1
#define SERIAL_NO_LENGTH 8
ULONG uVersion; // Version of this structure
USHORT uDeviceId;
USHORT uSubSystemId;
ULONG uNumberOfPorts;
char szSerialNo[SERIAL_NO_LENGTH+1];
ULONG uMajorRevision;
ULONG uMinorRevision;
ULONG uBuildState;
ULONG uCPUSpeed;
ULONG uMode;
} FSCARDINFO, * PFSCARDINFO;
#pragma pack(pop)
/*****************************************************************************/
/* DMA mode parameter block definition */
/* */
/* For use with: */
/* */
/* IoctlCodeFarSyncSetDMAMode, */
/* IoctlCodeFarSyncGetDMAMode , */
/* */
/*****************************************************************************/
#pragma pack(push, 4)
typedef struct _FSDMAMODE
{
#define FSDMAMODE_VERSION 1
#define FSDMAMODE_OFF 1
#define FSDMAMODE_ON 2
#define FSDMAMODE_INTERMEDIATE 3 // use for processing rxs via intermediate buffer
ULONG uVersion; // Version of this structure
USHORT uTxDMAMode;
USHORT uRxDMAMode;
} FSDMAMODE, * PFSDMAMODE;
#pragma pack(pop)
/*****************************************************************************/
/* Interrupt handshake mode parameter block definition */
/* */
/* For use with: */
/* */
/* IoctlCodeFarSyncSetHandShakeMode, */
/* IoctlCodeFarSyncGetHandShakeMode */
/* */
/*****************************************************************************/
#pragma pack(push, 4)
typedef struct _FSHANDSHAKEMODE
{
#define FSHANDSHAKEMODE_VERSION 1
#define FSHANDSHAKEMODE_2 2
#define FSHANDSHAKEMODE_3 3
ULONG uVersion; // Version of this structure
USHORT uMode;
} FSHANDSHAKEMODE, * PFSHANDSHAKEMODE;
#pragma pack(pop)
/*****************************************************************************/
/* Extended card info parameter block definition */
/* */
/* For use with: */
/* */
/* IoctlCodeFarSyncReadCardInfoEx , */
/* */
/*****************************************************************************/
#pragma pack(push, 4)
typedef struct _FSCARDINFOEX
{
#define FSCARDINFOEX_VERSION 2
ULONG uVersion; // Version of this structure
char szDeviceName[32+8]; // Including aligned PADDING to allow for null-terminator
PVOID w_memory; // Virtual addresses of Adapter Resources
PVOID w_controlSpace;
PVOID w_localCfg;
PVOID w_ioSpace;
ULONG z_memory; // Lengths of Adapter Resources
ULONG z_controlSpace;
ULONG z_localCfg;
ULONG z_ioSpace;
ULONG uHiVersion;
ULONG uLoVersion;
ULONG uReservedA[30]; // these are reserved for FarSite's own use
PVOID p_memory; // physical address of window - T-Series cards
PVOID p_io; // main IO address of card
ULONG uExtendedClockingSupported; // are (T4E) clock synths available on the card?
ULONG uAsyncSupported; // does the card support async
ULONG uReservedB[28]; // these are currently unused
} FSCARDINFOEX, * PFSCARDINFOEX;
#pragma pack(pop)
/*****************************************************************************/
/* Port config parameter block definition */
/* */
/* For use with: */
/* */
/* IoctlCodeFarSyncSetPortConfig, */
/* IoctlCodeFarSyncGetPortConfig */
/* */
/*****************************************************************************/
#pragma pack(push, 4)
typedef struct _FS_PORT_CONFIG
{
#define FSPORTCONFIG_VERSION 2
ULONG uVersion; // Version of this structure
ULONG uPortTxNumBuffers; // 2,4,8,16,32,64,128
ULONG uPortRxNumBuffers; // 2,4,8,16,32,64,128
ULONG uPortTxBufferLength; // Min=2 Max=64*1024 Def= 8*1024
ULONG uPortRxBufferLength; // Min=2 Max=64*1024 Def= 8*1024
ULONG uPortTxDMA; // See fscfg.h for values i.e. FSDMAMODE_OFF=1, FSDMAMODE_ON=2
ULONG uPortRxDMA; // See fscfg.h for values i.e. FSDMAMODE_OFF=1, FSDMAMODE_ON=2
ULONG uPortStartTxRx; // See smcuser.h for values i.e. START_TX=1 | START_RX=2
ULONG uPortClockSource; // See smcuser.h for values i.e. FS_CLOCK_REFERENCE_xxx
// Currently only supported on T4E
ULONG uPortTxMSB; // FALSE ==> LSB (Default)
ULONG uPortRxMSB; // FALSE ==> LSB (Default)
ULONG uPortMaxTxsOutstanding;// read-only - indicates how many txs can be outstanding at a time
ULONG uReserved[52];
} FS_PORT_CONFIG, *PFS_PORT_CONFIG;
#pragma pack(pop)
/*****************************************************************************/
/* Serial config parameter block definition */
/* */
/* For use with: */
/* */
/* IoctlCodeFarSyncSetSerialConfig, */
/* IoctlCodeFarSyncGetSerialConfig */
/* */
/*****************************************************************************/
#pragma pack(push, 4)
typedef struct _FS_SERIAL_CONFIG
{
#define FSSERIALCONFIG_VERSION 2
ULONG uVersion; // Version of this structure
ULONG uPortInterface; // See fscfg.h for values e.g. FS_LINE_INTERFACE_X21
ULONG uPortRate;
ULONG uPortClocking; // See fscfg.h for values e.g. FS_LINE_CLOCKING_INTERNAL
ULONG uPortTransparentMode; // HDLC=0 Transparent=1
ULONG uPortInvertRxClock; // TRUE(1) or FALSE(0)
ULONG uPortEncoding; // See fscfg for values i.e. FS_PORT_ENCODING_xxx
// Currently only supported on M1P
// The following fields have been added in Version 2 of this structure and not be
// processed if uVersion = 1
ULONG uExtendedClocking; // subsequent fields only used if this is TRUE
ULONG uInternalTxClock;
ULONG uInternalRxClock;
ULONG uTerminalTxClock;
ULONG uTerminalRxClock;
ULONG uDCDOutput; // TRUE => DCD is an output
ULONG uEstimatedLineSpeed; // returned by FarSyncGetSerialConfig for T4E only
ULONG uReserved[54];
} FS_SERIAL_CONFIG, *PFS_SERIAL_CONFIG;
#pragma pack(pop)
/*****************************************************************************/
/* CTBus config parameter block definition */
/* */
/* For use with: */
/* */
/* IoctlCodeFarSyncSetCTBusConfig */
/* IoctlCodeFarSyncGetCTBusConfig */
/* */
/*****************************************************************************/
#pragma pack(push, 4)
typedef struct _FS_CT_BUS_CONFIG
{
#define FSCTBUSCONFIG_VERSION 2
ULONG uVersion; // Version of this structure
ULONG uCTBusMode; // See smcuser.h for values i.e. FS_CT_BUS_MODE_xxx
ULONG uCTBusFeed; // See smcuser.h for values i.e. FS_CT_BUS_FEED_xxx
ULONG uFallback; // TRUE=>auto switch if clock ref fails
ULONG uReserved[60];
} FS_CT_BUS_CONFIG, *PFS_CT_BUS_CONFIG;
#pragma pack(pop)
/*****************************************************************************/
/* Clocking Status block definition */
/* */
/* For use with: */
/* */
/* IoctlCodeFarSyncGetClockingStatus */
/* */
/*****************************************************************************/
#pragma pack(push, 4)
typedef struct _FS_CLOCKING_STATUS
{
#define FSCLOCKINGSTATUS_VERSION 2
ULONG uVersion; // Version of this structure
ULONG uPrimaryClockStatus; // 0=out-of-tolerance, 1=good
ULONG uBackupClockStatus; // 0=out-of-tolerance, 1=good
ULONG uCurrentConfigReference; // See smcuser.h for values i.e. FS_CT_CONFIG_xxx
ULONG uCTAStatus; // 0=out-of-tolerance, 1=good
ULONG uCTBStatus; // 0=out-of-tolerance, 1=good
USHORT uCurrentStatusSummary; // bit map status word describing clocking state/config
// see smcuser.h for bit definitions
USHORT uReserved1;
ULONG uCTAInUse; // 0=CTB, 1=CTA - shows which CT Bus the card
// has selected for the slave clock source
ULONG uReserved2[15];
} FS_CLOCKING_STATUS, *PFS_CLOCKING_STATUS;
#pragma pack(pop)
//######################################################################################################
//
// FarSync Error Return Codes
//
// These return codes will be passed back from the FarSync SDCI driver in the IoStatus.Status field of
// the IRP and (if the SDCI client is a user-mode app) will be passed through transparently to the app
// via GetLastError().
//
#define FS_ERROR_INVALID_INPUT_BUFFER_LENGTH 0xE0000001
#define FS_ERROR_INVALID_OUTPUT_BUFFER_LENGTH 0xE0000002
#define FS_ERROR_PRIMARY_IOCTL 0xE0000003
#define FS_ERROR_CARD_NOT_STARTED 0xE0000004
#define FS_ERROR_INVALID_CT_BUS_MODE 0xE0000005
#define FS_ERROR_INVALID_CT_BUS_FEED 0xE0000006
#define FS_ERROR_INVALID_IOCTL_FOR_PORTTYPE 0xE0000007
#define FS_ERROR_INVALID_LENGTH 0xE0000008
//######################################################################################################
#endif /* __SDCI_H_ */
ODR-DabMux-4.4.1/lib/farsync/windows/fscfg.h 0000644 0001750 0001750 00000055357 14465705070 017523 0 ustar robin robin /*******************************************************************************
*
* Program : FarSync (generic)
*
* File : fscfg.h
*
* Description : Common FarSync Configuration Definitions used through the
* FarSync PC-based modules
*
* Modifications
*
* Version 2.1.0 01Mar01 WEB Add device and port configuration values
* 09Mar01 WEB Add Fswan hwid
* Version 2.2.0 18Jul01 WEB Certification candidate
* 22Oct01 MJD Added Transparent Mode support - define
* names and values for Transparent Mode and
* Buffer Length parameters.
* Version 2.2.6 26Oct01 WEB Add name for devices use only for SDCI applications.
* Version 2.3.0 28Nov01 WEB Add minnow ids + DeviceIDToCardID map
* Version 2.3.1 08Apr02 WEB Change min buffer length from 62 to 2
* Version 2.3.2 27Aug02 WEB Rationalised
* Version 3.0.2 05Nov02 WEB Add 'U' to DeviceIDToCardID map
* Version 3.2.0 09Dec02 WEB Add Invert Rx Clock, Dual Clocking & DMA definitions
* Version 3.4.0 26Oct04 WEB Add fstap definitions
* Version 3.5.0 11Nov04 WEB Add te1 definitions
* Version 4.0.0 18Feb05 WEB Add configurable number and size of buffers, start
* tx/rx
* Version 4.0.1 03Mar05 WEB Add extended clocking definitions
* Version 4.0.2 17Mar05 WEB Correct FS_LINE_INTERFACE_MAX - should be V35
* Version 4.1.0 24Jun05 WEB Add new T4E defs
* Version 4.2.0 12Sep05 WEB Add FS_NDEVICE_CLASS i.e. support for T4E MkII
* Reduce FS_LINE_RATE_MIN to 300
*
*******************************************************************************/
#ifndef __FSCFG_H_
#define __FSCFG_H_
#define SMCUSER_PACKING 1
#include "smcuser.h" // Values also used in the adapter window interface */
// PCI IDs
#define FS_VENDOR_ID 0x1619
#define FS_DEVICE_CLASS 0x0400 // ie. 0400 .. 04FF
#define FS_TDEVICE_CLASS FS_DEVICE_CLASS
// FarSync card classes/Device ID ranges
#define FS_MDEVICE_CLASS 0x0500 // ie. 0500 .. 05FF
#define FS_VDEVICE_CLASS 0x0000 // ie. 0000 .. 00FF
#define FS_UDEVICE_CLASS 0x0600 // ie. 0600 .. 06FF
#define FS_EDEVICE_CLASS 0x1600 // ie. 1600 .. 16FF
#define FS_NDEVICE_CLASS 0x3600 // ie. 3600 .. 36FF
#define FS_DDEVICE_CLASS 0x1700 // ie. 1700 .. 17FF
#define FS_CARDID_MASK 0xFF00
// Class maps
struct _DEVICEIDTOCARDID// e.g. 0400 -> T, 0500 -> M, 0600 -> T
{
ULONG uDeviceID;
char cCardID;
};
#define DEVICEIDTOCARDID struct _DEVICEIDTOCARDID
#ifdef FS_DECLARE_CFG_ARRAYS
DEVICEIDTOCARDID DeviceIDToCardID[] = { {FS_TDEVICE_CLASS, 'T'},
{FS_MDEVICE_CLASS, 'M'},
{FS_VDEVICE_CLASS, 'V'},
{FS_UDEVICE_CLASS, 'T'},
{FS_EDEVICE_CLASS, 'T'},
{FS_DDEVICE_CLASS, 'D'},
{FS_NDEVICE_CLASS, 'T'}
};
typedef struct _DEVICEIDTOCARDID2
{
ULONG uDeviceID;
char cCardID;
} DEVICEIDTOCARDID2; // e.g. 0400 -> P, 0500 -> P, 0600 -> U
#endif
#ifdef FS_DECLARE_CFG_ARRAYS
DEVICEIDTOCARDID DeviceIDToCardID2[] = { {FS_TDEVICE_CLASS, 'P'},
{FS_MDEVICE_CLASS, 'P'},
{FS_VDEVICE_CLASS, 'P'},
{FS_UDEVICE_CLASS, 'U'},
{FS_EDEVICE_CLASS, 'E'},
{FS_DDEVICE_CLASS, 'S'},
{FS_NDEVICE_CLASS, 'E'}
};
#else
DEVICEIDTOCARDID DeviceIDToCardID2[];
#endif
#define FS_FSWAN_HWID "fsvbus\\FS_TXP-00" // must match value in .inf
#define FS_VBUS_PREFIX_U L"fsv"
// Limits required for adapter/port enumeration
#define FS_MAX_ADAPTERS 100
#define FS_MAX_SYNC_ADAPTERS 10
#define FS_MAX_PORTS MAX_PORTS
#define FS_MAX_DEVICE_NAME 32 // number of WCHARs required to accomodate the longest device name
// e.g. \Device\SYNCH, \DosDevices\SYNC1 or \DosDevices\FSPPP0006
#define FS_DEVICE_PREFIX "SYNC"
#define FS_DEVICE_PREFIX_U L"SYNC"
#define FS_PPP_DEVICE_NAME "FSPPP%s" // name of farsynct device when in ppp mode
#define FS_SDCI_DEVICE_NAME "SDCI%s" // name of farsynct device when in sdci mode
#define FS_PORT_DEVICE_NAME "PortDeviceName" // stores name of farsynct port to use
#define LFS_PORT_DEVICE_NAME L"PortDeviceName" // required for use in ndiswan driver
#define FS_MAX_PARAM_NAME 128 // max number of chars in FS_LINE_NAME_PARAM_NAME etc.
/* Line name values */
#define FS_LINE_NAME_PARAM_NAME "Port%u_%u_Name"
#define FS_LINE_NAME_MAX_CHARS 16
#define FS_LINE_NAME_DEF "FSWAN_%u"
#define FS_PORT_NAME_DEF "Port %c"
#define FS_PORT_NAME_PARAM_NAME "Port%u_Name"
/* Line interface values */
#define FS_LINE_INTERFACE_PARAM_NAME "Port%u_%u_Interface"
#define FS_LINE_INTERFACE_MIN V24
#define FS_LINE_INTERFACE_V24 V24
#define FS_LINE_INTERFACE_X21 X21
#define FS_LINE_INTERFACE_X21D X21D
#define FS_LINE_INTERFACE_V35 V35
#define FS_LINE_INTERFACE_RS530_449 RS530_449
// Note: Specifying MAX as X21D intentionally makes RS530_449 not accessible to the current client GUIs
#define FS_LINE_INTERFACE_MAX RS530_449
#define FS_LINE_INTERFACE_DEF X21
#define FS_LINE_INTERFACE_MAX_CHARS 7
#define FS_PORT_INTERFACE_PARAM_NAME "Port%u_Interface"
#define FS_PORT_INTERFACE_PARAM_NAME_U L"Port%u_Interface"
#ifdef FS_DECLARE_CFG_ARRAYS
char* szFsT4EInterfaceTypesTable[] = {"Auto", "V.24", "X.21", "V.35", "X.21 (Dual-Clocking)", "RS530/449", 0};
char* szFsT4EInterfaceTypesTable2[] = {"Auto", "V.24", "X.21", "V.35", "X.21D", "RS530", 0};
ULONG uFsT4EInterfaceTypesTableVals[] = {AUTO, V24, X21, V35, X21D, RS530_449, 0};
char* szFsInterfaceTypesTable[] = {"Auto", "V.24", "X.21", "V.35", "X.21 (Dual-Clocking)", 0};
char* szFsM1PInterfaceTypesTable[] = {"Auto", "V.24", "X.21", "V.35", 0};
#else
char* szFsT4EInterfaceTypesTable[];
char* szFsT4EInterfaceTypesTable2[];
ULONG uFsT4EInterfaceTypesTableVals[];
char* szFsInterfaceTypesTable[];
char* szFsM1PInterfaceTypesTable[];
#endif
/* Line rate values */
#define FS_LINE_RATE_PARAM_NAME "Port%u_%u_Rate"
#define FS_LINE_RATE_MIN 300
#define FS_LINE_RATE_MAX 8192000
#define FS_LINE_RATE_DEF 64000
#define FS_LINE_RATE_MAX_CHARS 7
#define FS_PORT_RATE_PARAM_NAME "Port%u_Rate"
#define FS_PORT_RATE_PARAM_NAME_U L"Port%u_Rate"
#ifdef FS_DECLARE_CFG_ARRAYS
ULONG uFsRateTable[] = {1200, 2400, 4800, 9600,
19200, 38400, 64000, 76800,
128000, 153600, 256000, 307200,
512000, 614400, 1024000, 2048000,
4096000, 8192000, 0 };
#else
ULONG uFsRateTable[];
#endif
/* Line clocking values */
#define FS_LINE_CLOCKING_PARAM_NAME "Port%u_%u_InternalClocking"
#define FS_LINE_CLOCKING_MIN EXTCLK
#define FS_LINE_CLOCKING_EXTERNAL EXTCLK
#define FS_LINE_CLOCKING_INTERNAL INTCLK
#define FS_LINE_CLOCKING_MAX INTCLK
#define FS_LINE_CLOCKING_DEF EXTCLK
#define FS_LINE_CLOCKING_MAX_CHARS 8
#define FS_PORT_CLOCKING_PARAM_NAME "Port%u_InternalClocking"
#define FS_PORT_CLOCKING_PARAM_NAME_U L"Port%u_InternalClocking"
#ifdef FS_DECLARE_CFG_ARRAYS
char* szFsClockingTypesTable[] = {"External", "Internal", 0}; // maps onto FALSE, TRUE
#else
char* szFsClockingTypesTable[];
#endif
/* Transparent mode values */
#define FS_LINE_TRANSPARENT_MIN FALSE
#define FS_LINE_TRANSPARENT_MAX TRUE
#define FS_LINE_TRANSPARENT_DEF FALSE
#define FS_PORT_TRANSPARENT_PARAM_NAME "Port%u_TransparentMode"
#define FS_PORT_TRANSPARENT_PARAM_NAME_U L"Port%u_TransparentMode"
/* HDLC/Transparent mode values */
#define FS_LINE_MODE_HDLC 0
#define FS_LINE_MODE_TRANSPARENT 1
#define FS_LINE_MODE_MIN FS_LINE_MODE_HDLC
#define FS_LINE_MODE_MAX FS_LINE_MODE_TRANSPARENT
#define FS_LINE_MODE_DEF FS_LINE_MODE_HDLC
#define FS_LINE_MODE_MAX_CHARS 12
#ifdef FS_DECLARE_CFG_ARRAYS
char* szFsModeTypesTable[] = {"HDLC", "Transparent", 0};
#else
char* szFsModeTypesTable[];
#endif
/* Buffer length values */
#define FS_LINE_BUFFER_MIN 2
#define FS_LINE_BUFFER_MAX 64*1024
#define FS_LINE_BUFFER_DEF 8*1024
#define FS_PORT_BUFFER_PARAM_NAME "Port%u_BufferLength"
#define FS_PORT_BUFFER_PARAM_NAME_U L"Port%u_BufferLength"
#define FS_PORT_TX_BUFFER_PARAM_NAME "Port%u_TxBufferLength"
#define FS_PORT_TX_BUFFER_PARAM_NAME_U L"Port%u_TxBufferLength"
#define FS_PORT_RX_BUFFER_PARAM_NAME "Port%u_RxBufferLength"
#define FS_PORT_RX_BUFFER_PARAM_NAME_U L"Port%u_RxBufferLength"
// Note: UNDEF values means that the vars are ignored (i.e. different from DEFault values)
/* Invert Rx clock values */
#define FS_PORT_INVERT_RX_CLOCK_MIN FALSE
#define FS_PORT_INVERT_RX_CLOCK_MAX TRUE
#define FS_PORT_INVERT_RX_CLOCK_DEF FALSE
#define FS_PORT_INVERT_RX_CLOCK_UNDEF 0xFFFFFFFF
#define FS_PORT_INVERT_RX_CLOCK_PARAM_NAME "Port%u_InvertRxClock"
#define FS_PORT_INVERT_RX_CLOCK_PARAM_NAME_U L"Port%u_InvertRxClock"
/* Dual Clocking values */
#define FS_PORT_DUAL_CLOCKING_DEF FALSE
#define FS_PORT_DUAL_CLOCKING_PARAM_NAME "Port%u_DualClocking"
#define FS_PORT_DUAL_CLOCKING_PARAM_NAME_U L"Port%u_DualClocking"
/* Tx DMA values */
#define FS_PORT_TX_DMA_UNDEF 0xFFFFFFFF
#define FS_PORT_TX_DMA_PARAM_NAME "Port%u_TxDMA"
#define FS_PORT_TX_DMA_PARAM_NAME_U L"Port%u_TxDMA"
/* Rx DMA values */
#define FS_PORT_RX_DMA_UNDEF 0xFFFFFFFF
#define FS_PORT_RX_DMA_PARAM_NAME "Port%u_RxDMA"
#define FS_PORT_RX_DMA_PARAM_NAME_U L"Port%u_RxDMA"
#define FS_PORT_DMA_MAX FSDMAMODE_ON
#define FS_PORT_DMA_MIN FSDMAMODE_OFF
#define FS_PORT_DMA_DEF FSDMAMODE_OFF
/* Number of Tx buffers */
#define FS_PORT_TX_NUM_BUFFERS_MIN 2
#define FS_PORT_TX_NUM_BUFFERS_MAX 128
#define FS_PORT_TX_NUM_BUFFERS_DEF 8
#define FS_PORT_TX_NUM_BUFFERS_UNDEF 0xFFFFFFFF
#define FS_PORT_TX_NUM_BUFFERS_PARAM_NAME "Port%u_TxNumBuffers"
#define FS_PORT_TX_NUM_BUFFERS_PARAM_NAME_U L"Port%u_TxNumBuffers"
/* Number of Rx buffers */
#define FS_PORT_RX_NUM_BUFFERS_MIN 2
#define FS_PORT_RX_NUM_BUFFERS_MAX 128
#define FS_PORT_RX_NUM_BUFFERS_DEF 8
#define FS_PORT_RX_NUM_BUFFERS_UNDEF 0xFFFFFFFF
#define FS_PORT_RX_NUM_BUFFERS_PARAM_NAME "Port%u_RxNumBuffers"
#define FS_PORT_RX_NUM_BUFFERS_PARAM_NAME_U L"Port%u_RxNumBuffers"
#ifdef FS_DECLARE_CFG_ARRAYS
char* szFsNumBuffersTable[] = {"2", "4", "8", "16", "32", "64", "128", 0};
#else
char* szFsNumBuffersTable[];
#endif
/* Encoding values */
#define FS_PORT_ENCODING_PARAM_NAME "Port%u_Encoding"
#define FS_PORT_ENCODING_PARAM_NAME_U L"Port%u_Encoding"
#define FS_PORT_ENCODING_NRZ 0x80
#define FS_PORT_ENCODING_NRZI 0xa0
#define FS_PORT_ENCODING_FM0 0xc0
#define FS_PORT_ENCODING_FM1 0xd0
#define FS_PORT_ENCODING_MAN 0xe0
#define FS_PORT_ENCODING_MIN FS_PORT_ENCODING_NRZ
#define FS_PORT_ENCODING_MAX FS_PORT_ENCODING_MAN
#define FS_PORT_ENCODING_DEF FS_PORT_ENCODING_NRZ
#ifdef FS_DECLARE_CFG_ARRAYS
char* szFsEncodingTypesTable[] = {"NRZ", "NRZI", "FM0", "FM1", "MAN", 0};
#else
char* szFsEncodingTypesTable[];
#endif
/* Registry Config Names */
#define FS_EVENT_SUBKEY_NAME "SYSTEM\\CurrentControlSet\\Services\\EventLog\\System\\farsynct"
#define EVENT_VAR_TYPES_SUPPORTED "TypesSupported"
#define EVENT_VAR_MESSAGE_FILE "EventMessageFile"
#define FS_MESSAGE_FILE "%SystemRoot%\\System32\\IOLOGMSG.DLL;%SystemRoot%\\System32\\Drivers\\farsynct.sys"
#define REG_SERVICES_ROOT_U L"\\REGISTRY\\Machine\\SYSTEM\\CurrentControlSet\\Services\\"
#define REG_MACHINE_ROOT_U L"\\REGISTRY\\Machine\\"
#define REG_FSWAN_CONFIG_PATH_U L"SOFTWARE\\FarSite\\FSWAN"
/* Pool Tags */
#define FARSYNCT_TAG1 '1TsF'
#define FARSYNCM_TAG1 '1PsF'
#define FSX25MDM_TAG1 '1MsF'
#define FSKUTL_TAG1 '1UsF'
#define FSWAN_TAG1 '1WsF'
#define FSWAN_TAG2 '2WsF'
/* fstap config */
#define FSTAP_DEVICENAME_PARAM_NAME "DeviceName"
#define FSTAP_PORT_PARAM_NAME "Port"
#define FSTAP_IGNORE_SIGNALS_DEF FALSE
#define FSTAP_IGNORE_SIGNALS_PARAM_NAME "IgnoreSignals"
#define FSTAP_ENABLE_MONITORING_DEF TRUE
#define FSTAP_ENABLE_MONITORING_PARAM_NAME "EnableMonitoring"
/* te1 config */
#define FS_PORT_FRAMING_MIN FRAMING_E1
#define FS_PORT_FRAMING_MAX FRAMING_T1
#define FS_PORT_FRAMING_PARAM_NAME "Port%u_Framing"
#define FS_PORT_FRAMING_PARAM_NAME_U L"Port%u_Framing"
#ifdef FS_DECLARE_CFG_ARRAYS
char* szFsFramingTypesTable[] = {"E1", "J1", "T1", 0};
#else
char* szFsFramingTypesTable[];
#endif
#define FS_PORT_ECLOCKING_MIN CLOCKING_SLAVE
#define FS_PORT_ECLOCKING_MAX CLOCKING_MASTER
#ifdef notreq
#define FS_PORT_ECLOCKING_PARAM_NAME "Port%u_Clocking"
#define FS_PORT_ECLOCKING_PARAM_NAME_U L"Port%u_Clocking"
#endif
#ifdef FS_DECLARE_CFG_ARRAYS
char* szFsEClockingTypesTable[] = {"Slave", "Master", 0};
#else
char* szFsEClockingTypesTable[];
#endif
#define FS_PORT_DATARATE_MIN 8000
#define FS_PORT_E1_DATARATE_MAX 2048000
#define FS_PORT_T1_DATARATE_MAX 1544000
#ifdef notreq
#define FS_PORT_DATARATE_PARAM_NAME "Port%u_DataRate"
#define FS_PORT_DATARATE_PARAM_NAME_U L"Port%u_DataRate"
#ifdef FS_DECLARE_CFG_ARRAYS
char* szFsDataRateTable[] = {"1", "2", 0};
#else
char* szFsDataRateTable[];
#endif
#endif
#define FS_PORT_STRUCTURE_MIN STRUCTURE_UNFRAMED
#define FS_PORT_STRUCTURE_MAX STRUCTURE_T1_72
#define FS_PORT_STRUCTURE_PARAM_NAME "Port%u_Structure"
#define FS_PORT_STRUCTURE_PARAM_NAME_U L"Port%u_Structure"
#define STRUCTURE_UNFRAMED 0
#define STRUCTURE_E1_DOUBLE 1
#define STRUCTURE_E1_CRC4 2
#define STRUCTURE_E1_DEFAULT STRUCTURE_E1_CRC4
#define STRUCTURE_DEFAULT STRUCTURE_E1_CRC4
#define STRUCTURE_E1_CRC4M 3
#define STRUCTURE_T1_4 4
#define STRUCTURE_T1_12 5
#define STRUCTURE_T1_24 6
#define STRUCTURE_T1_DEFAULT STRUCTURE_T1_24
#define STRUCTURE_T1_72 7
#ifdef FS_DECLARE_CFG_ARRAYS
char* szFsE1StructureTypesTable[] = {"Unframed", "Double", "CRC4", "CRC4M", 0};
int iFsE1StructureValuesTable[] = {STRUCTURE_UNFRAMED, STRUCTURE_E1_DOUBLE, STRUCTURE_E1_CRC4, STRUCTURE_E1_CRC4M, -1};
char* szFsT1StructureTypesTable[] = {"Unframed", "F4 (FT)", "F12 (D3/D4, SF)", "F24 (D5, Fe, ESF)", "F72 (SLC96)", 0};
int iFsT1StructureValuesTable[] = {STRUCTURE_UNFRAMED, STRUCTURE_T1_4, STRUCTURE_T1_12, STRUCTURE_T1_24, STRUCTURE_T1_72, -1};
#else
char* szFsE1StructureTypesTable[];
int iFsE1StructureValuesTable[];
char* szFsT1StructureTypesTable[];
int iFsT1StructureValuesTable[];
#endif
#define FS_PORT_IFACE_MIN INTERFACE_RJ48C
#define FS_PORT_IFACE_MAX INTERFACE_BNC
#define FS_PORT_IFACE_PARAM_NAME "Port%u_Iface"
#define FS_PORT_IFACE_PARAM_NAME_U L"Port%u_Iface"
#ifdef FS_DECLARE_CFG_ARRAYS
char* szFsE1IfaceTypesTable[] = {"RJ48C", "BNC", 0};
int iFsE1IfaceValuesTable[] = {INTERFACE_RJ48C, INTERFACE_BNC, -1};
char* szFsT1IfaceTypesTable[] = {"RJ48C", 0};
int iFsT1IfaceValuesTable[] = {INTERFACE_RJ48C, -1};
#else
char* szFsE1IfaceTypesTable[];
int iFsE1IfaceValuesTable[];
char* szFsT1IfaceTypesTable[];
int iFsT1IfaceValuesTable[];
#endif
#define FS_PORT_CODING_MIN CODING_HDB3
#define FS_PORT_CODING_MAX CODING_B8ZS
#define FS_PORT_CODING_PARAM_NAME "Port%u_Coding"
#define FS_PORT_CODING_PARAM_NAME_U L"Port%u_Coding"
#ifdef FS_DECLARE_CFG_ARRAYS
//char* szFsE1CodingTypesTable[] = {"HDB3", "NRZ", "CMI", "CMI-HDB3", "AMI", 0};
//int iFsE1CodingValuesTable[] = {CODING_HDB3, CODING_NRZ, CODING_CMI, CODING_CMI_HDB3, CODING_AMI, -1};
char* szFsE1CodingTypesTable[] = {"HDB3", "AMI", 0};
int iFsE1CodingValuesTable[] = {CODING_HDB3, CODING_AMI, -1};
//char* szFsT1CodingTypesTable[] = {"NRZ", "CMI", "CMI_B8ZS", "AMI", "AMI-ZCS", "B8ZS", 0};
//int iFsT1CodingValuesTable[] = {CODING_NRZ, CODING_CMI, CODING_CMI_B8ZS, CODING_AMI, CODING_AMI_ZCS, CODING_B8ZS, -1};
char* szFsT1CodingTypesTable[] = {"AMI", "AMI-ZCS", "B8ZS", 0};
int iFsT1CodingValuesTable[] = {CODING_AMI, CODING_AMI_ZCS, CODING_B8ZS, -1};
#else
char* szFsE1CodingTypesTable[];
int iFsE1CodingValuesTable[];
char* szFsT1CodingTypesTable[];
int iFsT1CodingValuesTable[];
#endif
#define FS_PORT_LBO_MIN LBO_0dB
#define FS_PORT_LBO_MAX LBO_22dB5
#define FS_PORT_LBO_PARAM_NAME "Port%u_LBO"
#define FS_PORT_LBO_PARAM_NAME_U L"Port%u_LBO"
#ifdef FS_DECLARE_CFG_ARRAYS
char* szFsLBOTypesTable[] = {"0", "7.5", "15", "22.5", 0};
#else
char* szFsLBOTypesTable[];
#endif
#define FS_PORT_EQUALIZER_MIN EQUALIZER_SHORT
#define FS_PORT_EQUALIZER_MAX EQUALIZER_LONG
#define FS_PORT_EQUALIZER_PARAM_NAME "Port%u_Equalizer"
#define FS_PORT_EQUALIZER_PARAM_NAME_U L"Port%u_Equalizer"
#ifdef FS_DECLARE_CFG_ARRAYS
char* szFsEqualizerTypesTable[] = {"Short", "Long", 0};
#else
char* szFsEqualizerTypesTable[];
#endif
#define FS_PORT_LOOP_MODE_MIN LOOP_NONE
#define FS_PORT_LOOP_MODE_MAX LOOP_REMOTE
#define FS_PORT_LOOP_MODE_PARAM_NAME "Port%u_LoopMode"
#define FS_PORT_LOOP_MODE_PARAM_NAME_U L"Port%u_LoopMode"
#ifdef FS_DECLARE_CFG_ARRAYS
char* szFsLoopModeTypesTable[] = {"None", "Local", "Payload (excl TS0)", "Payload (incl TS0)", "Remote", 0};
#else
char* szFsLoopModeTypesTable[];
#endif
#define FS_PORT_RANGE_MIN RANGE_0_40_M
#define FS_PORT_RANGE_MAX RANGE_162_200_M
#define FS_PORT_RANGE_PARAM_NAME "Port%u_Range"
#define FS_PORT_RANGE_PARAM_NAME_U L"Port%u_Range"
#ifdef FS_DECLARE_CFG_ARRAYS
char* szFsRangeTypesTable[] = {"0-133ft (0-40m)", "133-266ft (40-81m)", "266-399ft (81-122m)", "399-533ft (122-162m)", "533-655ft (162-200m)", 0};
#else
char* szFsRangeTypesTable[];
#endif
#define FS_PORT_BUFFER_MODE_MIN BUFFER_2_FRAME
#define FS_PORT_BUFFER_MODE_MAX BUFFER_NONE
#define FS_PORT_TX_BUFFER_MODE_PARAM_NAME "Port%u_TxBufferMode"
#define FS_PORT_TX_BUFFER_MODE_PARAM_NAME_U L"Port%u_TxBufferMode"
#define FS_PORT_RX_BUFFER_MODE_PARAM_NAME "Port%u_RxBufferMode"
#define FS_PORT_RX_BUFFER_MODE_PARAM_NAME_U L"Port%u_RxBufferMode"
#ifdef FS_DECLARE_CFG_ARRAYS
char* szFsBufferModeTypesTable[] = {"2 Frame", "1 Frame", "96 bit", "None", 0};
#else
char* szFsBufferModeTypesTable[];
#endif
#define FS_PORT_STARTING_TS_MIN 0
#define FS_PORT_STARTING_TS_MAX 31
#define FS_PORT_STARTING_TS_PARAM_NAME "Port%u_StartingTs"
#define FS_PORT_STARTING_TS_PARAM_NAME_U L"Port%u_StartingTs"
#ifdef FS_DECLARE_CFG_ARRAYS
char* szFsE1StartingTSTypesTable[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9",
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
"20", "21", "22", "23", "24", "25", "26", "27", "28", "29",
"30", "31",
0};
char* szFsT1StartingTSTypesTable[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
"20", "21", "22", "23",
0};
#else
char* szFsE1StartingTSTypesTable[];
char* szFsT1StartingTSTypesTable[];
#endif
#define FS_PORT_LOS_THRESHOLD_MIN 0
#define FS_PORT_LOS_THRESHOLD_MAX 7
#define FS_PORT_LOS_THRESHOLD_PARAM_NAME "Port%u_LOSThreshold"
#define FS_PORT_LOS_THRESHOLD_PARAM_NAME_U L"Port%u_LOSThreshold"
#ifdef FS_DECLARE_CFG_ARRAYS
char* szFsLOSThresholdTypesTable[] = { "0", "1", "2", "3", "4", "5", "6", "7", 0};
#else
char* szFsLOSThresholdTypesTable[];
#endif
#define FS_PORT_ENABLE_IDLE_CODE_MIN 0
#define FS_PORT_ENABLE_IDLE_CODE_MAX 1
#define FS_PORT_ENABLE_IDLE_CODE_PARAM_NAME "Port%u_EnableIdleCode"
#define FS_PORT_ENABLE_IDLE_CODE_PARAM_NAME_U L"Port%u_EnableIdleCode"
#define FS_PORT_IDLE_CODE_MIN 0
#define FS_PORT_IDLE_CODE_MAX 0xff
#define FS_PORT_IDLE_CODE_PARAM_NAME "Port%u_IdleCode"
#define FS_PORT_IDLE_CODE_PARAM_NAME_U L"Port%u_IdleCode"
#define FS_PORT_START_TXRX_MIN 0
#define FS_PORT_START_TXRX_DEF START_TX_AND_RX
#define FS_PORT_START_TXRX_MAX START_TX_AND_RX
#define FS_PORT_START_TXRX_PARAM_NAME "Port%u_StartTxRx"
#define FS_PORT_START_TXRX_PARAM_NAME_U L"Port%u_StartTxRx"
#define FS_PORT_CLOCK_SOURCE_MIN FS_CLOCK_REFERENCE_OSCILLATOR
#define FS_PORT_CLOCK_SOURCE_DEF FS_CLOCK_REFERENCE_OSCILLATOR
#define FS_PORT_CLOCK_SOURCE_MAX FS_CLOCK_REFERENCE_CTBUS
#define FS_PORT_CLOCK_SOURCE_PARAM_NAME "Port%u_ClockSource"
#define FS_PORT_CLOCK_SOURCE_PARAM_NAME_U L"Port%u_ClockSource"
#ifdef FS_DECLARE_CFG_ARRAYS
char* szFsClockSourceTable[] = {"Local Oscillator", "CT_BUS", 0};
#else
char* szFsClockSourceTable[];
#endif
#define FS_SERIAL_EXTENDED_CLOCKING_DEF FALSE
#define FS_SERIAL_EXTENDED_CLOCKING_PARAM_NAME "Port%u_ExtendedClocking"
#define FS_SERIAL_EXTENDED_CLOCKING_PARAM_NAME_U L"Port%u_ExtendedClocking"
#define FS_SERIAL_INT_TX_CLOCK_DEF FALSE
#define FS_SERIAL_INT_TX_CLOCK_PARAM_NAME "Port%u_InternalTxClock"
#define FS_SERIAL_INT_TX_CLOCK_PARAM_NAME_U L"Port%u_InternalTxClock"
#define FS_SERIAL_INT_RX_CLOCK_DEF FALSE
#define FS_SERIAL_INT_RX_CLOCK_PARAM_NAME "Port%u_InternalRxClock"
#define FS_SERIAL_INT_RX_CLOCK_PARAM_NAME_U L"Port%u_InternalRxClock"
#define FS_SERIAL_TERM_TX_CLOCK_DEF FALSE
#define FS_SERIAL_TERM_TX_CLOCK_PARAM_NAME "Port%u_TerminalTxClock"
#define FS_SERIAL_TERM_TX_CLOCK_PARAM_NAME_U L"Port%u_TerminalTxClock"
#define FS_SERIAL_TERM_RX_CLOCK_DEF FALSE
#define FS_SERIAL_TERM_RX_CLOCK_PARAM_NAME "Port%u_TerminalRxClock"
#define FS_SERIAL_TERM_RX_CLOCK_PARAM_NAME_U L"Port%u_TerminalRxClock"
#define FS_SERIAL_DCD_OUTPUT_DEF FALSE
#define FS_SERIAL_DCD_OUTPUT_PARAM_NAME "Port%u_DCDOutput"
#define FS_SERIAL_DCD_OUTPUT_PARAM_NAME_U L"Port%u_DCDOutput"
#define FS_PORT_MSB_DEF FALSE
#define FS_PORT_TX_MSB_PARAM_NAME "Port%u_TxMSB"
#define FS_PORT_TX_MSB_PARAM_NAME_U L"Port%u_TxMSB"
#define FS_PORT_RX_MSB_PARAM_NAME "Port%u_RxMSB"
#define FS_PORT_RX_MSB_PARAM_NAME_U L"Port%u_RxMSB"
#endif // __FSCFG_H_
ODR-DabMux-4.4.1/lib/zmq.hpp 0000644 0001750 0001750 00000161715 14465705070 014437 0 ustar robin robin /*
Copyright (c) 2016-2017 ZeroMQ community
Copyright (c) 2009-2011 250bpm s.r.o.
Copyright (c) 2011 Botond Ballo
Copyright (c) 2007-2009 iMatix Corporation
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef __ZMQ_HPP_INCLUDED__
#define __ZMQ_HPP_INCLUDED__
// macros defined if has a specific standard or greater
#if (defined(__cplusplus) && __cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1900)
#define ZMQ_CPP11
#endif
#if (defined(__cplusplus) && __cplusplus >= 201402L) || \
(defined(_HAS_CXX14) && _HAS_CXX14 == 1) || \
(defined(_HAS_CXX17) && _HAS_CXX17 == 1) // _HAS_CXX14 might not be defined when using C++17 on MSVC
#define ZMQ_CPP14
#endif
#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1)
#define ZMQ_CPP17
#endif
#if defined(ZMQ_CPP14)
#define ZMQ_DEPRECATED(msg) [[deprecated(msg)]]
#elif defined(_MSC_VER)
#define ZMQ_DEPRECATED(msg) __declspec(deprecated(msg))
#elif defined(__GNUC__)
#define ZMQ_DEPRECATED(msg) __attribute__((deprecated(msg)))
#endif
#if defined(ZMQ_CPP17)
#define ZMQ_NODISCARD [[nodiscard]]
#else
#define ZMQ_NODISCARD
#endif
#if defined(ZMQ_CPP11)
#define ZMQ_NOTHROW noexcept
#define ZMQ_EXPLICIT explicit
#define ZMQ_OVERRIDE override
#define ZMQ_NULLPTR nullptr
#define ZMQ_CONSTEXPR_FN constexpr
#define ZMQ_CONSTEXPR_VAR constexpr
#else
#define ZMQ_NOTHROW throw()
#define ZMQ_EXPLICIT
#define ZMQ_OVERRIDE
#define ZMQ_NULLPTR 0
#define ZMQ_CONSTEXPR_FN
#define ZMQ_CONSTEXPR_VAR const
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef ZMQ_CPP11
#include
#include
#include
#include
#endif
#ifdef ZMQ_CPP17
#ifdef __has_include
#if __has_include()
#include
#define ZMQ_HAS_OPTIONAL 1
#endif
#if __has_include()
#include
#define ZMQ_HAS_STRING_VIEW 1
#endif
#endif
#endif
/* Version macros for compile-time API version detection */
#define CPPZMQ_VERSION_MAJOR 4
#define CPPZMQ_VERSION_MINOR 6
#define CPPZMQ_VERSION_PATCH 0
#define CPPZMQ_VERSION \
ZMQ_MAKE_VERSION(CPPZMQ_VERSION_MAJOR, CPPZMQ_VERSION_MINOR, \
CPPZMQ_VERSION_PATCH)
// Detect whether the compiler supports C++11 rvalue references.
#if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) \
&& defined(__GXX_EXPERIMENTAL_CXX0X__))
#define ZMQ_HAS_RVALUE_REFS
#define ZMQ_DELETED_FUNCTION = delete
#elif defined(__clang__)
#if __has_feature(cxx_rvalue_references)
#define ZMQ_HAS_RVALUE_REFS
#endif
#if __has_feature(cxx_deleted_functions)
#define ZMQ_DELETED_FUNCTION = delete
#else
#define ZMQ_DELETED_FUNCTION
#endif
#elif defined(_MSC_VER) && (_MSC_VER >= 1900)
#define ZMQ_HAS_RVALUE_REFS
#define ZMQ_DELETED_FUNCTION = delete
#elif defined(_MSC_VER) && (_MSC_VER >= 1600)
#define ZMQ_HAS_RVALUE_REFS
#define ZMQ_DELETED_FUNCTION
#else
#define ZMQ_DELETED_FUNCTION
#endif
#if defined(ZMQ_CPP11) && !defined(__llvm__) && !defined(__INTEL_COMPILER) \
&& defined(__GNUC__) && __GNUC__ < 5
#define ZMQ_CPP11_PARTIAL
#elif defined(__GLIBCXX__) && __GLIBCXX__ < 20160805
//the date here is the last date of gcc 4.9.4, which
// effectively means libstdc++ from gcc 5.5 and higher won't trigger this branch
#define ZMQ_CPP11_PARTIAL
#endif
#ifdef ZMQ_CPP11
#ifdef ZMQ_CPP11_PARTIAL
#define ZMQ_IS_TRIVIALLY_COPYABLE(T) __has_trivial_copy(T)
#else
#include
#define ZMQ_IS_TRIVIALLY_COPYABLE(T) std::is_trivially_copyable::value
#endif
#endif
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3, 3, 0)
#define ZMQ_NEW_MONITOR_EVENT_LAYOUT
#endif
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 1, 0)
#define ZMQ_HAS_PROXY_STEERABLE
/* Socket event data */
typedef struct
{
uint16_t event; // id of the event as bitfield
int32_t value; // value is either error code, fd or reconnect interval
} zmq_event_t;
#endif
// Avoid using deprecated message receive function when possible
#if ZMQ_VERSION < ZMQ_MAKE_VERSION(3, 2, 0)
#define zmq_msg_recv(msg, socket, flags) zmq_recvmsg(socket, msg, flags)
#endif
// In order to prevent unused variable warnings when building in non-debug
// mode use this macro to make assertions.
#ifndef NDEBUG
#define ZMQ_ASSERT(expression) assert(expression)
#else
#define ZMQ_ASSERT(expression) (void) (expression)
#endif
namespace zmq
{
#ifdef ZMQ_CPP11
namespace detail
{
namespace ranges
{
using std::begin;
using std::end;
template
auto begin(T&& r) -> decltype(begin(std::forward(r)))
{
return begin(std::forward(r));
}
template
auto end(T&& r) -> decltype(end(std::forward(r)))
{
return end(std::forward(r));
}
} // namespace ranges
template using void_t = void;
template
using iter_value_t = typename std::iterator_traits::value_type;
template
using range_iter_t = decltype(
ranges::begin(std::declval::type &>()));
template
using range_value_t = iter_value_t>;
template struct is_range : std::false_type
{
};
template
struct is_range<
T,
void_t::type &>())
== ranges::end(std::declval::type &>()))>>
: std::true_type
{
};
} // namespace detail
#endif
typedef zmq_free_fn free_fn;
typedef zmq_pollitem_t pollitem_t;
class error_t : public std::exception
{
public:
error_t() : errnum(zmq_errno()) {}
virtual const char *what() const ZMQ_NOTHROW ZMQ_OVERRIDE { return zmq_strerror(errnum); }
int num() const { return errnum; }
private:
int errnum;
};
inline int poll(zmq_pollitem_t *items_, size_t nitems_, long timeout_ = -1)
{
int rc = zmq_poll(items_, static_cast(nitems_), timeout_);
if (rc < 0)
throw error_t();
return rc;
}
ZMQ_DEPRECATED("from 4.3.1, use poll taking non-const items")
inline int poll(zmq_pollitem_t const *items_, size_t nitems_, long timeout_ = -1)
{
return poll(const_cast(items_), nitems_, timeout_);
}
#ifdef ZMQ_CPP11
ZMQ_DEPRECATED("from 4.3.1, use poll taking non-const items")
inline int
poll(zmq_pollitem_t const *items, size_t nitems, std::chrono::milliseconds timeout)
{
return poll(const_cast(items), nitems, static_cast(timeout.count()));
}
ZMQ_DEPRECATED("from 4.3.1, use poll taking non-const items")
inline int poll(std::vector const &items,
std::chrono::milliseconds timeout)
{
return poll(const_cast(items.data()), items.size(), static_cast(timeout.count()));
}
ZMQ_DEPRECATED("from 4.3.1, use poll taking non-const items")
inline int poll(std::vector const &items, long timeout_ = -1)
{
return poll(const_cast(items.data()), items.size(), timeout_);
}
inline int
poll(zmq_pollitem_t *items, size_t nitems, std::chrono::milliseconds timeout)
{
return poll(items, nitems, static_cast(timeout.count()));
}
inline int poll(std::vector &items,
std::chrono::milliseconds timeout)
{
return poll(items.data(), items.size(), static_cast(timeout.count()));
}
inline int poll(std::vector &items, long timeout_ = -1)
{
return poll(items.data(), items.size(), timeout_);
}
#endif
inline void version(int *major_, int *minor_, int *patch_)
{
zmq_version(major_, minor_, patch_);
}
#ifdef ZMQ_CPP11
inline std::tuple version()
{
std::tuple v;
zmq_version(&std::get<0>(v), &std::get<1>(v), &std::get<2>(v));
return v;
}
#endif
class message_t
{
public:
message_t() ZMQ_NOTHROW
{
int rc = zmq_msg_init(&msg);
ZMQ_ASSERT(rc == 0);
}
explicit message_t(size_t size_)
{
int rc = zmq_msg_init_size(&msg, size_);
if (rc != 0)
throw error_t();
}
template message_t(ForwardIter first, ForwardIter last)
{
typedef typename std::iterator_traits::value_type value_t;
assert(std::distance(first, last) >= 0);
size_t const size_ =
static_cast(std::distance(first, last)) * sizeof(value_t);
int const rc = zmq_msg_init_size(&msg, size_);
if (rc != 0)
throw error_t();
std::copy(first, last, data());
}
message_t(const void *data_, size_t size_)
{
int rc = zmq_msg_init_size(&msg, size_);
if (rc != 0)
throw error_t();
memcpy(data(), data_, size_);
}
message_t(void *data_, size_t size_, free_fn *ffn_, void *hint_ = ZMQ_NULLPTR)
{
int rc = zmq_msg_init_data(&msg, data_, size_, ffn_, hint_);
if (rc != 0)
throw error_t();
}
#if defined(ZMQ_CPP11) && !defined(ZMQ_CPP11_PARTIAL)
template::value
&& ZMQ_IS_TRIVIALLY_COPYABLE(detail::range_value_t)
&& !std::is_same::value>::type>
explicit message_t(const Range &rng) :
message_t(detail::ranges::begin(rng), detail::ranges::end(rng))
{
}
#endif
#ifdef ZMQ_HAS_RVALUE_REFS
message_t(message_t &&rhs) ZMQ_NOTHROW : msg(rhs.msg)
{
int rc = zmq_msg_init(&rhs.msg);
ZMQ_ASSERT(rc == 0);
}
message_t &operator=(message_t &&rhs) ZMQ_NOTHROW
{
std::swap(msg, rhs.msg);
return *this;
}
#endif
~message_t() ZMQ_NOTHROW
{
int rc = zmq_msg_close(&msg);
ZMQ_ASSERT(rc == 0);
}
void rebuild()
{
int rc = zmq_msg_close(&msg);
if (rc != 0)
throw error_t();
rc = zmq_msg_init(&msg);
ZMQ_ASSERT(rc == 0);
}
void rebuild(size_t size_)
{
int rc = zmq_msg_close(&msg);
if (rc != 0)
throw error_t();
rc = zmq_msg_init_size(&msg, size_);
if (rc != 0)
throw error_t();
}
void rebuild(const void *data_, size_t size_)
{
int rc = zmq_msg_close(&msg);
if (rc != 0)
throw error_t();
rc = zmq_msg_init_size(&msg, size_);
if (rc != 0)
throw error_t();
memcpy(data(), data_, size_);
}
void rebuild(void *data_, size_t size_, free_fn *ffn_, void *hint_ = ZMQ_NULLPTR)
{
int rc = zmq_msg_close(&msg);
if (rc != 0)
throw error_t();
rc = zmq_msg_init_data(&msg, data_, size_, ffn_, hint_);
if (rc != 0)
throw error_t();
}
ZMQ_DEPRECATED("from 4.3.1, use move taking non-const reference instead")
void move(message_t const *msg_)
{
int rc = zmq_msg_move(&msg, const_cast(msg_->handle()));
if (rc != 0)
throw error_t();
}
void move(message_t &msg_)
{
int rc = zmq_msg_move(&msg, msg_.handle());
if (rc != 0)
throw error_t();
}
ZMQ_DEPRECATED("from 4.3.1, use copy taking non-const reference instead")
void copy(message_t const *msg_)
{
int rc = zmq_msg_copy(&msg, const_cast(msg_->handle()));
if (rc != 0)
throw error_t();
}
void copy(message_t &msg_)
{
int rc = zmq_msg_copy(&msg, msg_.handle());
if (rc != 0)
throw error_t();
}
bool more() const ZMQ_NOTHROW
{
int rc = zmq_msg_more(const_cast(&msg));
return rc != 0;
}
void *data() ZMQ_NOTHROW { return zmq_msg_data(&msg); }
const void *data() const ZMQ_NOTHROW
{
return zmq_msg_data(const_cast(&msg));
}
size_t size() const ZMQ_NOTHROW
{
return zmq_msg_size(const_cast(&msg));
}
ZMQ_NODISCARD bool empty() const ZMQ_NOTHROW
{
return size() == 0u;
}
template T *data() ZMQ_NOTHROW { return static_cast(data()); }
template T const *data() const ZMQ_NOTHROW
{
return static_cast(data());
}
ZMQ_DEPRECATED("from 4.3.0, use operator== instead")
bool equal(const message_t *other) const ZMQ_NOTHROW
{
return *this == *other;
}
bool operator==(const message_t &other) const ZMQ_NOTHROW
{
const size_t my_size = size();
return my_size == other.size() && 0 == memcmp(data(), other.data(), my_size);
}
bool operator!=(const message_t &other) const ZMQ_NOTHROW
{
return !(*this == other);
}
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3, 2, 0)
int get(int property_)
{
int value = zmq_msg_get(&msg, property_);
if (value == -1)
throw error_t();
return value;
}
#endif
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 1, 0)
const char *gets(const char *property_)
{
const char *value = zmq_msg_gets(&msg, property_);
if (value == ZMQ_NULLPTR)
throw error_t();
return value;
}
#endif
#if defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 0)
uint32_t routing_id() const
{
return zmq_msg_routing_id(const_cast(&msg));
}
void set_routing_id(uint32_t routing_id)
{
int rc = zmq_msg_set_routing_id(&msg, routing_id);
if (rc != 0)
throw error_t();
}
const char* group() const
{
return zmq_msg_group(const_cast(&msg));
}
void set_group(const char* group)
{
int rc = zmq_msg_set_group(&msg, group);
if (rc != 0)
throw error_t();
}
#endif
// interpret message content as a string
std::string to_string() const
{
return std::string(static_cast(data()), size());
}
#ifdef ZMQ_CPP17
// interpret message content as a string
std::string_view to_string_view() const noexcept
{
return std::string_view(static_cast(data()), size());
}
#endif
/** Dump content to string for debugging.
* Ascii chars are readable, the rest is printed as hex.
* Probably ridiculously slow.
* Use to_string() or to_string_view() for
* interpreting the message as a string.
*/
std::string str() const
{
// Partly mutuated from the same method in zmq::multipart_t
std::stringstream os;
const unsigned char *msg_data = this->data();
unsigned char byte;
size_t size = this->size();
int is_ascii[2] = {0, 0};
os << "zmq::message_t [size " << std::dec << std::setw(3)
<< std::setfill('0') << size << "] (";
// Totally arbitrary
if (size >= 1000) {
os << "... too big to print)";
} else {
while (size--) {
byte = *msg_data++;
is_ascii[1] = (byte >= 32 && byte < 127);
if (is_ascii[1] != is_ascii[0])
os << " "; // Separate text/non text
if (is_ascii[1]) {
os << byte;
} else {
os << std::hex << std::uppercase << std::setw(2)
<< std::setfill('0') << static_cast(byte);
}
is_ascii[0] = is_ascii[1];
}
os << ")";
}
return os.str();
}
void swap(message_t &other) ZMQ_NOTHROW
{
// this assumes zmq::msg_t from libzmq is trivially relocatable
std::swap(msg, other.msg);
}
ZMQ_NODISCARD zmq_msg_t *handle() ZMQ_NOTHROW { return &msg; }
ZMQ_NODISCARD const zmq_msg_t *handle() const ZMQ_NOTHROW { return &msg; }
private:
// The underlying message
zmq_msg_t msg;
// Disable implicit message copying, so that users won't use shared
// messages (less efficient) without being aware of the fact.
message_t(const message_t &) ZMQ_DELETED_FUNCTION;
void operator=(const message_t &) ZMQ_DELETED_FUNCTION;
};
inline void swap(message_t &a, message_t &b) ZMQ_NOTHROW
{
a.swap(b);
}
class context_t
{
public:
context_t()
{
ptr = zmq_ctx_new();
if (ptr == ZMQ_NULLPTR)
throw error_t();
}
explicit context_t(int io_threads_,
int max_sockets_ = ZMQ_MAX_SOCKETS_DFLT)
{
ptr = zmq_ctx_new();
if (ptr == ZMQ_NULLPTR)
throw error_t();
int rc = zmq_ctx_set(ptr, ZMQ_IO_THREADS, io_threads_);
ZMQ_ASSERT(rc == 0);
rc = zmq_ctx_set(ptr, ZMQ_MAX_SOCKETS, max_sockets_);
ZMQ_ASSERT(rc == 0);
}
#ifdef ZMQ_HAS_RVALUE_REFS
context_t(context_t &&rhs) ZMQ_NOTHROW : ptr(rhs.ptr) { rhs.ptr = ZMQ_NULLPTR; }
context_t &operator=(context_t &&rhs) ZMQ_NOTHROW
{
close();
std::swap(ptr, rhs.ptr);
return *this;
}
#endif
int setctxopt(int option_, int optval_)
{
int rc = zmq_ctx_set(ptr, option_, optval_);
ZMQ_ASSERT(rc == 0);
return rc;
}
int getctxopt(int option_) { return zmq_ctx_get(ptr, option_); }
~context_t() ZMQ_NOTHROW { close(); }
void close() ZMQ_NOTHROW
{
if (ptr == ZMQ_NULLPTR)
return;
int rc;
do {
rc = zmq_ctx_destroy(ptr);
} while (rc == -1 && errno == EINTR);
ZMQ_ASSERT(rc == 0);
ptr = ZMQ_NULLPTR;
}
// Be careful with this, it's probably only useful for
// using the C api together with an existing C++ api.
// Normally you should never need to use this.
ZMQ_EXPLICIT operator void *() ZMQ_NOTHROW { return ptr; }
ZMQ_EXPLICIT operator void const *() const ZMQ_NOTHROW { return ptr; }
operator bool() const ZMQ_NOTHROW { return ptr != ZMQ_NULLPTR; }
void swap(context_t &other) ZMQ_NOTHROW
{
std::swap(ptr, other.ptr);
}
private:
void *ptr;
context_t(const context_t &) ZMQ_DELETED_FUNCTION;
void operator=(const context_t &) ZMQ_DELETED_FUNCTION;
};
inline void swap(context_t &a, context_t &b) ZMQ_NOTHROW {
a.swap(b);
}
#ifdef ZMQ_CPP11
struct recv_buffer_size
{
size_t size; // number of bytes written to buffer
size_t untruncated_size; // untruncated message size in bytes
ZMQ_NODISCARD bool truncated() const noexcept
{
return size != untruncated_size;
}
};
#if defined(ZMQ_HAS_OPTIONAL) && (ZMQ_HAS_OPTIONAL > 0)
using send_result_t = std::optional;
using recv_result_t = std::optional;
using recv_buffer_result_t = std::optional;
#else
namespace detail
{
// A C++11 type emulating the most basic
// operations of std::optional for trivial types
template class trivial_optional
{
public:
static_assert(std::is_trivial::value, "T must be trivial");
using value_type = T;
trivial_optional() = default;
trivial_optional(T value) noexcept : _value(value), _has_value(true) {}
const T *operator->() const noexcept
{
assert(_has_value);
return &_value;
}
T *operator->() noexcept
{
assert(_has_value);
return &_value;
}
const T &operator*() const noexcept
{
assert(_has_value);
return _value;
}
T &operator*() noexcept
{
assert(_has_value);
return _value;
}
T &value()
{
if (!_has_value)
throw std::exception();
return _value;
}
const T &value() const
{
if (!_has_value)
throw std::exception();
return _value;
}
explicit operator bool() const noexcept { return _has_value; }
bool has_value() const noexcept { return _has_value; }
private:
T _value{};
bool _has_value{false};
};
} // namespace detail
using send_result_t = detail::trivial_optional;
using recv_result_t = detail::trivial_optional;
using recv_buffer_result_t = detail::trivial_optional;
#endif
namespace detail
{
template
constexpr T enum_bit_or(T a, T b) noexcept
{
static_assert(std::is_enum::value, "must be enum");
using U = typename std::underlying_type::type;
return static_cast(static_cast(a) | static_cast(b));
}
template
constexpr T enum_bit_and(T a, T b) noexcept
{
static_assert(std::is_enum::value, "must be enum");
using U = typename std::underlying_type::type;
return static_cast(static_cast(a) & static_cast(b));
}
template
constexpr T enum_bit_xor(T a, T b) noexcept
{
static_assert(std::is_enum::value, "must be enum");
using U = typename std::underlying_type::type;
return static_cast(static_cast(a) ^ static_cast(b));
}
template
constexpr T enum_bit_not(T a) noexcept
{
static_assert(std::is_enum::value, "must be enum");
using U = typename std::underlying_type::type;
return static_cast(~static_cast(a));
}
} // namespace detail
// partially satisfies named requirement BitmaskType
enum class send_flags : int
{
none = 0,
dontwait = ZMQ_DONTWAIT,
sndmore = ZMQ_SNDMORE
};
constexpr send_flags operator|(send_flags a, send_flags b) noexcept
{
return detail::enum_bit_or(a, b);
}
constexpr send_flags operator&(send_flags a, send_flags b) noexcept
{
return detail::enum_bit_and(a, b);
}
constexpr send_flags operator^(send_flags a, send_flags b) noexcept
{
return detail::enum_bit_xor(a, b);
}
constexpr send_flags operator~(send_flags a) noexcept
{
return detail::enum_bit_not(a);
}
// partially satisfies named requirement BitmaskType
enum class recv_flags : int
{
none = 0,
dontwait = ZMQ_DONTWAIT
};
constexpr recv_flags operator|(recv_flags a, recv_flags b) noexcept
{
return detail::enum_bit_or(a, b);
}
constexpr recv_flags operator&(recv_flags a, recv_flags b) noexcept
{
return detail::enum_bit_and(a, b);
}
constexpr recv_flags operator^(recv_flags a, recv_flags b) noexcept
{
return detail::enum_bit_xor(a, b);
}
constexpr recv_flags operator~(recv_flags a) noexcept
{
return detail::enum_bit_not(a);
}
// mutable_buffer, const_buffer and buffer are based on
// the Networking TS specification, draft:
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/n4771.pdf
class mutable_buffer
{
public:
constexpr mutable_buffer() noexcept : _data(nullptr), _size(0) {}
constexpr mutable_buffer(void *p, size_t n) noexcept : _data(p), _size(n)
{
#ifdef ZMQ_CPP14
assert(p != nullptr || n == 0);
#endif
}
constexpr void *data() const noexcept { return _data; }
constexpr size_t size() const noexcept { return _size; }
mutable_buffer &operator+=(size_t n) noexcept
{
// (std::min) is a workaround for when a min macro is defined
const auto shift = (std::min)(n, _size);
_data = static_cast(_data) + shift;
_size -= shift;
return *this;
}
private:
void *_data;
size_t _size;
};
inline mutable_buffer operator+(const mutable_buffer &mb, size_t n) noexcept
{
return mutable_buffer(static_cast(mb.data()) + (std::min)(n, mb.size()),
mb.size() - (std::min)(n, mb.size()));
}
inline mutable_buffer operator+(size_t n, const mutable_buffer &mb) noexcept
{
return mb + n;
}
class const_buffer
{
public:
constexpr const_buffer() noexcept : _data(nullptr), _size(0) {}
constexpr const_buffer(const void *p, size_t n) noexcept : _data(p), _size(n)
{
#ifdef ZMQ_CPP14
assert(p != nullptr || n == 0);
#endif
}
constexpr const_buffer(const mutable_buffer &mb) noexcept :
_data(mb.data()),
_size(mb.size())
{
}
constexpr const void *data() const noexcept { return _data; }
constexpr size_t size() const noexcept { return _size; }
const_buffer &operator+=(size_t n) noexcept
{
const auto shift = (std::min)(n, _size);
_data = static_cast(_data) + shift;
_size -= shift;
return *this;
}
private:
const void *_data;
size_t _size;
};
inline const_buffer operator+(const const_buffer &cb, size_t n) noexcept
{
return const_buffer(static_cast(cb.data())
+ (std::min)(n, cb.size()),
cb.size() - (std::min)(n, cb.size()));
}
inline const_buffer operator+(size_t n, const const_buffer &cb) noexcept
{
return cb + n;
}
// buffer creation
constexpr mutable_buffer buffer(void* p, size_t n) noexcept
{
return mutable_buffer(p, n);
}
constexpr const_buffer buffer(const void* p, size_t n) noexcept
{
return const_buffer(p, n);
}
constexpr mutable_buffer buffer(const mutable_buffer& mb) noexcept
{
return mb;
}
inline mutable_buffer buffer(const mutable_buffer& mb, size_t n) noexcept
{
return mutable_buffer(mb.data(), (std::min)(mb.size(), n));
}
constexpr const_buffer buffer(const const_buffer& cb) noexcept
{
return cb;
}
inline const_buffer buffer(const const_buffer& cb, size_t n) noexcept
{
return const_buffer(cb.data(), (std::min)(cb.size(), n));
}
namespace detail
{
template
struct is_buffer
{
static constexpr bool value =
std::is_same::value ||
std::is_same::value;
};
template struct is_pod_like
{
// NOTE: The networking draft N4771 section 16.11 requires
// T in the buffer functions below to be
// trivially copyable OR standard layout.
// Here we decide to be conservative and require both.
static constexpr bool value =
ZMQ_IS_TRIVIALLY_COPYABLE(T) && std::is_standard_layout::value;
};
template constexpr auto seq_size(const C &c) noexcept -> decltype(c.size())
{
return c.size();
}
template
constexpr size_t seq_size(const T (&/*array*/)[N]) noexcept
{
return N;
}
template
auto buffer_contiguous_sequence(Seq &&seq) noexcept
-> decltype(buffer(std::addressof(*std::begin(seq)), size_t{}))
{
using T = typename std::remove_cv<
typename std::remove_reference::type>::type;
static_assert(detail::is_pod_like::value, "T must be POD");
const auto size = seq_size(seq);
return buffer(size != 0u ? std::addressof(*std::begin(seq)) : nullptr,
size * sizeof(T));
}
template
auto buffer_contiguous_sequence(Seq &&seq, size_t n_bytes) noexcept
-> decltype(buffer_contiguous_sequence(seq))
{
using T = typename std::remove_cv<
typename std::remove_reference::type>::type;
static_assert(detail::is_pod_like::value, "T must be POD");
const auto size = seq_size(seq);
return buffer(size != 0u ? std::addressof(*std::begin(seq)) : nullptr,
(std::min)(size * sizeof(T), n_bytes));
}
} // namespace detail
// C array
template mutable_buffer buffer(T (&data)[N]) noexcept
{
return detail::buffer_contiguous_sequence(data);
}
template
mutable_buffer buffer(T (&data)[N], size_t n_bytes) noexcept
{
return detail::buffer_contiguous_sequence(data, n_bytes);
}
template const_buffer buffer(const T (&data)[N]) noexcept
{
return detail::buffer_contiguous_sequence(data);
}
template
const_buffer buffer(const T (&data)[N], size_t n_bytes) noexcept
{
return detail::buffer_contiguous_sequence(data, n_bytes);
}
// std::array
template mutable_buffer buffer(std::array &data) noexcept
{
return detail::buffer_contiguous_sequence(data);
}
template
mutable_buffer buffer(std::array &data, size_t n_bytes) noexcept
{
return detail::buffer_contiguous_sequence(data, n_bytes);
}
template
const_buffer buffer(std::array &data) noexcept
{
return detail::buffer_contiguous_sequence(data);
}
template
const_buffer buffer(std::array &data, size_t n_bytes) noexcept
{
return detail::buffer_contiguous_sequence(data, n_bytes);
}
template
const_buffer buffer(const std::array &data) noexcept
{
return detail::buffer_contiguous_sequence(data);
}
template
const_buffer buffer(const std::array &data, size_t n_bytes) noexcept
{
return detail::buffer_contiguous_sequence(data, n_bytes);
}
// std::vector
template
mutable_buffer buffer(std::vector &data) noexcept
{
return detail::buffer_contiguous_sequence(data);
}
template
mutable_buffer buffer(std::vector &data, size_t n_bytes) noexcept
{
return detail::buffer_contiguous_sequence(data, n_bytes);
}
template
const_buffer buffer(const std::vector &data) noexcept
{
return detail::buffer_contiguous_sequence(data);
}
template
const_buffer buffer(const std::vector &data, size_t n_bytes) noexcept
{
return detail::buffer_contiguous_sequence(data, n_bytes);
}
// std::basic_string
template
mutable_buffer buffer(std::basic_string &data) noexcept
{
return detail::buffer_contiguous_sequence(data);
}
template
mutable_buffer buffer(std::basic_string &data,
size_t n_bytes) noexcept
{
return detail::buffer_contiguous_sequence(data, n_bytes);
}
template
const_buffer buffer(const std::basic_string &data) noexcept
{
return detail::buffer_contiguous_sequence(data);
}
template
const_buffer buffer(const std::basic_string &data,
size_t n_bytes) noexcept
{
return detail::buffer_contiguous_sequence(data, n_bytes);
}
#if defined(ZMQ_HAS_STRING_VIEW) && (ZMQ_HAS_STRING_VIEW > 0)
// std::basic_string_view
template
const_buffer buffer(std::basic_string_view data) noexcept
{
return detail::buffer_contiguous_sequence(data);
}
template
const_buffer buffer(std::basic_string_view data, size_t n_bytes) noexcept
{
return detail::buffer_contiguous_sequence(data, n_bytes);
}
#endif
// Buffer for a string literal (null terminated)
// where the buffer size excludes the terminating character.
// Equivalent to zmq::buffer(std::string_view("...")).
template
constexpr const_buffer str_buffer(const Char (&data)[N]) noexcept
{
static_assert(detail::is_pod_like::value, "Char must be POD");
#ifdef ZMQ_CPP14
assert(data[N - 1] == Char{0});
#endif
return const_buffer(static_cast(data),
(N - 1) * sizeof(Char));
}
namespace literals
{
constexpr const_buffer operator"" _zbuf(const char* str, size_t len) noexcept
{
return const_buffer(str, len * sizeof(char));
}
constexpr const_buffer operator"" _zbuf(const wchar_t* str, size_t len) noexcept
{
return const_buffer(str, len * sizeof(wchar_t));
}
constexpr const_buffer operator"" _zbuf(const char16_t* str, size_t len) noexcept
{
return const_buffer(str, len * sizeof(char16_t));
}
constexpr const_buffer operator"" _zbuf(const char32_t* str, size_t len) noexcept
{
return const_buffer(str, len * sizeof(char32_t));
}
}
#endif // ZMQ_CPP11
namespace detail
{
class socket_base
{
public:
socket_base() ZMQ_NOTHROW : _handle(ZMQ_NULLPTR) {}
ZMQ_EXPLICIT socket_base(void *handle) ZMQ_NOTHROW : _handle(handle) {}
template void setsockopt(int option_, T const &optval)
{
setsockopt(option_, &optval, sizeof(T));
}
void setsockopt(int option_, const void *optval_, size_t optvallen_)
{
int rc = zmq_setsockopt(_handle, option_, optval_, optvallen_);
if (rc != 0)
throw error_t();
}
void getsockopt(int option_, void *optval_, size_t *optvallen_) const
{
int rc = zmq_getsockopt(_handle, option_, optval_, optvallen_);
if (rc != 0)
throw error_t();
}
template T getsockopt(int option_) const
{
T optval;
size_t optlen = sizeof(T);
getsockopt(option_, &optval, &optlen);
return optval;
}
void bind(std::string const &addr) { bind(addr.c_str()); }
void bind(const char *addr_)
{
int rc = zmq_bind(_handle, addr_);
if (rc != 0)
throw error_t();
}
void unbind(std::string const &addr) { unbind(addr.c_str()); }
void unbind(const char *addr_)
{
int rc = zmq_unbind(_handle, addr_);
if (rc != 0)
throw error_t();
}
void connect(std::string const &addr) { connect(addr.c_str()); }
void connect(const char *addr_)
{
int rc = zmq_connect(_handle, addr_);
if (rc != 0)
throw error_t();
}
void disconnect(std::string const &addr) { disconnect(addr.c_str()); }
void disconnect(const char *addr_)
{
int rc = zmq_disconnect(_handle, addr_);
if (rc != 0)
throw error_t();
}
bool connected() const ZMQ_NOTHROW { return (_handle != ZMQ_NULLPTR); }
#ifdef ZMQ_CPP11
ZMQ_DEPRECATED("from 4.3.1, use send taking a const_buffer and send_flags")
#endif
size_t send(const void *buf_, size_t len_, int flags_ = 0)
{
int nbytes = zmq_send(_handle, buf_, len_, flags_);
if (nbytes >= 0)
return static_cast(nbytes);
if (zmq_errno() == EAGAIN)
return 0;
throw error_t();
}
#ifdef ZMQ_CPP11
ZMQ_DEPRECATED("from 4.3.1, use send taking message_t and send_flags")
#endif
bool send(message_t &msg_,
int flags_ = 0) // default until removed
{
int nbytes = zmq_msg_send(msg_.handle(), _handle, flags_);
if (nbytes >= 0)
return true;
if (zmq_errno() == EAGAIN)
return false;
throw error_t();
}
template
#ifdef ZMQ_CPP11
ZMQ_DEPRECATED("from 4.4.1, use send taking message_t or buffer (for contiguous ranges), and send_flags")
#endif
bool send(T first, T last, int flags_ = 0)
{
zmq::message_t msg(first, last);
int nbytes = zmq_msg_send(msg.handle(), _handle, flags_);
if (nbytes >= 0)
return true;
if (zmq_errno() == EAGAIN)
return false;
throw error_t();
}
#ifdef ZMQ_HAS_RVALUE_REFS
#ifdef ZMQ_CPP11
ZMQ_DEPRECATED("from 4.3.1, use send taking message_t and send_flags")
#endif
bool send(message_t &&msg_,
int flags_ = 0) // default until removed
{
#ifdef ZMQ_CPP11
return send(msg_, static_cast(flags_)).has_value();
#else
return send(msg_, flags_);
#endif
}
#endif
#ifdef ZMQ_CPP11
send_result_t send(const_buffer buf, send_flags flags = send_flags::none)
{
const int nbytes =
zmq_send(_handle, buf.data(), buf.size(), static_cast(flags));
if (nbytes >= 0)
return static_cast(nbytes);
if (zmq_errno() == EAGAIN)
return {};
throw error_t();
}
send_result_t send(message_t &msg, send_flags flags)
{
int nbytes = zmq_msg_send(msg.handle(), _handle, static_cast(flags));
if (nbytes >= 0)
return static_cast(nbytes);
if (zmq_errno() == EAGAIN)
return {};
throw error_t();
}
send_result_t send(message_t &&msg, send_flags flags)
{
return send(msg, flags);
}
#endif
#ifdef ZMQ_CPP11
ZMQ_DEPRECATED("from 4.3.1, use recv taking a mutable_buffer and recv_flags")
#endif
size_t recv(void *buf_, size_t len_, int flags_ = 0)
{
int nbytes = zmq_recv(_handle, buf_, len_, flags_);
if (nbytes >= 0)
return static_cast(nbytes);
if (zmq_errno() == EAGAIN)
return 0;
throw error_t();
}
#ifdef ZMQ_CPP11
ZMQ_DEPRECATED("from 4.3.1, use recv taking a reference to message_t and recv_flags")
#endif
bool recv(message_t *msg_, int flags_ = 0)
{
int nbytes = zmq_msg_recv(msg_->handle(), _handle, flags_);
if (nbytes >= 0)
return true;
if (zmq_errno() == EAGAIN)
return false;
throw error_t();
}
#ifdef ZMQ_CPP11
ZMQ_NODISCARD
recv_buffer_result_t recv(mutable_buffer buf,
recv_flags flags = recv_flags::none)
{
const int nbytes =
zmq_recv(_handle, buf.data(), buf.size(), static_cast(flags));
if (nbytes >= 0) {
return recv_buffer_size{(std::min)(static_cast(nbytes), buf.size()),
static_cast(nbytes)};
}
if (zmq_errno() == EAGAIN)
return {};
throw error_t();
}
ZMQ_NODISCARD
recv_result_t recv(message_t &msg, recv_flags flags = recv_flags::none)
{
const int nbytes = zmq_msg_recv(msg.handle(), _handle, static_cast(flags));
if (nbytes >= 0) {
assert(msg.size() == static_cast(nbytes));
return static_cast(nbytes);
}
if (zmq_errno() == EAGAIN)
return {};
throw error_t();
}
#endif
#if defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 0)
void join(const char* group)
{
int rc = zmq_join(_handle, group);
if (rc != 0)
throw error_t();
}
void leave(const char* group)
{
int rc = zmq_leave(_handle, group);
if (rc != 0)
throw error_t();
}
#endif
ZMQ_NODISCARD void *handle() ZMQ_NOTHROW { return _handle; }
ZMQ_NODISCARD const void *handle() const ZMQ_NOTHROW { return _handle; }
ZMQ_EXPLICIT operator bool() const ZMQ_NOTHROW { return _handle != ZMQ_NULLPTR; }
// note: non-const operator bool can be removed once
// operator void* is removed from socket_t
ZMQ_EXPLICIT operator bool() ZMQ_NOTHROW { return _handle != ZMQ_NULLPTR; }
protected:
void *_handle;
};
} // namespace detail
#ifdef ZMQ_CPP11
enum class socket_type : int
{
req = ZMQ_REQ,
rep = ZMQ_REP,
dealer = ZMQ_DEALER,
router = ZMQ_ROUTER,
pub = ZMQ_PUB,
sub = ZMQ_SUB,
xpub = ZMQ_XPUB,
xsub = ZMQ_XSUB,
push = ZMQ_PUSH,
pull = ZMQ_PULL,
#if defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 0)
server = ZMQ_SERVER,
client = ZMQ_CLIENT,
radio = ZMQ_RADIO,
dish = ZMQ_DISH,
#endif
#if ZMQ_VERSION_MAJOR >= 4
stream = ZMQ_STREAM,
#endif
pair = ZMQ_PAIR
};
#endif
struct from_handle_t
{
struct _private {}; // disabling use other than with from_handle
ZMQ_CONSTEXPR_FN ZMQ_EXPLICIT from_handle_t(_private /*p*/) ZMQ_NOTHROW {}
};
ZMQ_CONSTEXPR_VAR from_handle_t from_handle = from_handle_t(from_handle_t::_private());
// A non-owning nullable reference to a socket.
// The reference is invalidated on socket close or destruction.
class socket_ref : public detail::socket_base
{
public:
socket_ref() ZMQ_NOTHROW : detail::socket_base() {}
#ifdef ZMQ_CPP11
socket_ref(std::nullptr_t) ZMQ_NOTHROW : detail::socket_base() {}
#endif
socket_ref(from_handle_t /*fh*/, void *handle) ZMQ_NOTHROW
: detail::socket_base(handle) {}
};
#ifdef ZMQ_CPP11
inline bool operator==(socket_ref sr, std::nullptr_t /*p*/) ZMQ_NOTHROW
{
return sr.handle() == nullptr;
}
inline bool operator==(std::nullptr_t /*p*/, socket_ref sr) ZMQ_NOTHROW
{
return sr.handle() == nullptr;
}
inline bool operator!=(socket_ref sr, std::nullptr_t /*p*/) ZMQ_NOTHROW
{
return !(sr == nullptr);
}
inline bool operator!=(std::nullptr_t /*p*/, socket_ref sr) ZMQ_NOTHROW
{
return !(sr == nullptr);
}
#endif
inline bool operator==(socket_ref a, socket_ref b) ZMQ_NOTHROW
{
return std::equal_to()(a.handle(), b.handle());
}
inline bool operator!=(socket_ref a, socket_ref b) ZMQ_NOTHROW
{
return !(a == b);
}
inline bool operator<(socket_ref a, socket_ref b) ZMQ_NOTHROW
{
return std::less()(a.handle(), b.handle());
}
inline bool operator>(socket_ref a, socket_ref b) ZMQ_NOTHROW
{
return b < a;
}
inline bool operator<=(socket_ref a, socket_ref b) ZMQ_NOTHROW
{
return !(a > b);
}
inline bool operator>=(socket_ref a, socket_ref b) ZMQ_NOTHROW
{
return !(a < b);
}
} // namespace zmq
#ifdef ZMQ_CPP11
namespace std
{
template<>
struct hash
{
size_t operator()(zmq::socket_ref sr) const ZMQ_NOTHROW
{
return hash()(sr.handle());
}
};
} // namespace std
#endif
namespace zmq
{
class socket_t : public detail::socket_base
{
friend class monitor_t;
public:
socket_t() ZMQ_NOTHROW
: detail::socket_base(ZMQ_NULLPTR)
, ctxptr(ZMQ_NULLPTR)
{
}
socket_t(context_t &context_, int type_)
: detail::socket_base(zmq_socket(static_cast(context_), type_))
, ctxptr(static_cast(context_))
{
if (_handle == ZMQ_NULLPTR)
throw error_t();
}
#ifdef ZMQ_CPP11
socket_t(context_t &context_, socket_type type_)
: socket_t(context_, static_cast(type_))
{
}
#endif
#ifdef ZMQ_HAS_RVALUE_REFS
socket_t(socket_t &&rhs) ZMQ_NOTHROW : detail::socket_base(rhs._handle), ctxptr(rhs.ctxptr)
{
rhs._handle = ZMQ_NULLPTR;
rhs.ctxptr = ZMQ_NULLPTR;
}
socket_t &operator=(socket_t &&rhs) ZMQ_NOTHROW
{
close();
std::swap(_handle, rhs._handle);
return *this;
}
#endif
~socket_t() ZMQ_NOTHROW { close(); }
operator void *() ZMQ_NOTHROW { return _handle; }
operator void const *() const ZMQ_NOTHROW { return _handle; }
void close() ZMQ_NOTHROW
{
if (_handle == ZMQ_NULLPTR)
// already closed
return;
int rc = zmq_close(_handle);
ZMQ_ASSERT(rc == 0);
_handle = ZMQ_NULLPTR;
}
void swap(socket_t &other) ZMQ_NOTHROW
{
std::swap(_handle, other._handle);
std::swap(ctxptr, other.ctxptr);
}
operator socket_ref() ZMQ_NOTHROW
{
return socket_ref(from_handle, _handle);
}
private:
void *ctxptr;
socket_t(const socket_t &) ZMQ_DELETED_FUNCTION;
void operator=(const socket_t &) ZMQ_DELETED_FUNCTION;
// used by monitor_t
socket_t(void *context_, int type_)
: detail::socket_base(zmq_socket(context_, type_))
, ctxptr(context_)
{
if (_handle == ZMQ_NULLPTR)
throw error_t();
}
};
inline void swap(socket_t &a, socket_t &b) ZMQ_NOTHROW {
a.swap(b);
}
ZMQ_DEPRECATED("from 4.3.1, use proxy taking socket_t objects")
inline void proxy(void *frontend, void *backend, void *capture)
{
int rc = zmq_proxy(frontend, backend, capture);
if (rc != 0)
throw error_t();
}
inline void
proxy(socket_ref frontend, socket_ref backend, socket_ref capture = socket_ref())
{
int rc = zmq_proxy(frontend.handle(), backend.handle(), capture.handle());
if (rc != 0)
throw error_t();
}
#ifdef ZMQ_HAS_PROXY_STEERABLE
ZMQ_DEPRECATED("from 4.3.1, use proxy_steerable taking socket_t objects")
inline void
proxy_steerable(void *frontend, void *backend, void *capture, void *control)
{
int rc = zmq_proxy_steerable(frontend, backend, capture, control);
if (rc != 0)
throw error_t();
}
inline void proxy_steerable(socket_ref frontend,
socket_ref backend,
socket_ref capture,
socket_ref control)
{
int rc = zmq_proxy_steerable(frontend.handle(), backend.handle(),
capture.handle(), control.handle());
if (rc != 0)
throw error_t();
}
#endif
class monitor_t
{
public:
monitor_t() : _socket(), _monitor_socket() {}
virtual ~monitor_t()
{
close();
}
#ifdef ZMQ_HAS_RVALUE_REFS
monitor_t(monitor_t &&rhs) ZMQ_NOTHROW : _socket(), _monitor_socket()
{
std::swap(_socket, rhs._socket);
std::swap(_monitor_socket, rhs._monitor_socket);
}
monitor_t &operator=(monitor_t &&rhs) ZMQ_NOTHROW
{
close();
_socket = socket_ref();
std::swap(_socket, rhs._socket);
std::swap(_monitor_socket, rhs._monitor_socket);
return *this;
}
#endif
void
monitor(socket_t &socket, std::string const &addr, int events = ZMQ_EVENT_ALL)
{
monitor(socket, addr.c_str(), events);
}
void monitor(socket_t &socket, const char *addr_, int events = ZMQ_EVENT_ALL)
{
init(socket, addr_, events);
while (true) {
check_event(-1);
}
}
void init(socket_t &socket, std::string const &addr, int events = ZMQ_EVENT_ALL)
{
init(socket, addr.c_str(), events);
}
void init(socket_t &socket, const char *addr_, int events = ZMQ_EVENT_ALL)
{
int rc = zmq_socket_monitor(socket.handle(), addr_, events);
if (rc != 0)
throw error_t();
_socket = socket;
_monitor_socket = socket_t(socket.ctxptr, ZMQ_PAIR);
_monitor_socket.connect(addr_);
on_monitor_started();
}
bool check_event(int timeout = 0)
{
assert(_monitor_socket);
zmq_msg_t eventMsg;
zmq_msg_init(&eventMsg);
zmq::pollitem_t items[] = {
{_monitor_socket.handle(), 0, ZMQ_POLLIN, 0},
};
zmq::poll(&items[0], 1, timeout);
if (items[0].revents & ZMQ_POLLIN) {
int rc = zmq_msg_recv(&eventMsg, _monitor_socket.handle(), 0);
if (rc == -1 && zmq_errno() == ETERM)
return false;
assert(rc != -1);
} else {
zmq_msg_close(&eventMsg);
return false;
}
#if ZMQ_VERSION_MAJOR >= 4
const char *data = static_cast(zmq_msg_data(&eventMsg));
zmq_event_t msgEvent;
memcpy(&msgEvent.event, data, sizeof(uint16_t));
data += sizeof(uint16_t);
memcpy(&msgEvent.value, data, sizeof(int32_t));
zmq_event_t *event = &msgEvent;
#else
zmq_event_t *event = static_cast(zmq_msg_data(&eventMsg));
#endif
#ifdef ZMQ_NEW_MONITOR_EVENT_LAYOUT
zmq_msg_t addrMsg;
zmq_msg_init(&addrMsg);
int rc = zmq_msg_recv(&addrMsg, _monitor_socket.handle(), 0);
if (rc == -1 && zmq_errno() == ETERM) {
zmq_msg_close(&eventMsg);
return false;
}
assert(rc != -1);
const char *str = static_cast(zmq_msg_data(&addrMsg));
std::string address(str, str + zmq_msg_size(&addrMsg));
zmq_msg_close(&addrMsg);
#else
// Bit of a hack, but all events in the zmq_event_t union have the same layout so this will work for all event types.
std::string address = event->data.connected.addr;
#endif
#ifdef ZMQ_EVENT_MONITOR_STOPPED
if (event->event == ZMQ_EVENT_MONITOR_STOPPED) {
zmq_msg_close(&eventMsg);
return false;
}
#endif
switch (event->event) {
case ZMQ_EVENT_CONNECTED:
on_event_connected(*event, address.c_str());
break;
case ZMQ_EVENT_CONNECT_DELAYED:
on_event_connect_delayed(*event, address.c_str());
break;
case ZMQ_EVENT_CONNECT_RETRIED:
on_event_connect_retried(*event, address.c_str());
break;
case ZMQ_EVENT_LISTENING:
on_event_listening(*event, address.c_str());
break;
case ZMQ_EVENT_BIND_FAILED:
on_event_bind_failed(*event, address.c_str());
break;
case ZMQ_EVENT_ACCEPTED:
on_event_accepted(*event, address.c_str());
break;
case ZMQ_EVENT_ACCEPT_FAILED:
on_event_accept_failed(*event, address.c_str());
break;
case ZMQ_EVENT_CLOSED:
on_event_closed(*event, address.c_str());
break;
case ZMQ_EVENT_CLOSE_FAILED:
on_event_close_failed(*event, address.c_str());
break;
case ZMQ_EVENT_DISCONNECTED:
on_event_disconnected(*event, address.c_str());
break;
#ifdef ZMQ_BUILD_DRAFT_API
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 3)
case ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL:
on_event_handshake_failed_no_detail(*event, address.c_str());
break;
case ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL:
on_event_handshake_failed_protocol(*event, address.c_str());
break;
case ZMQ_EVENT_HANDSHAKE_FAILED_AUTH:
on_event_handshake_failed_auth(*event, address.c_str());
break;
case ZMQ_EVENT_HANDSHAKE_SUCCEEDED:
on_event_handshake_succeeded(*event, address.c_str());
break;
#elif ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 1)
case ZMQ_EVENT_HANDSHAKE_FAILED:
on_event_handshake_failed(*event, address.c_str());
break;
case ZMQ_EVENT_HANDSHAKE_SUCCEED:
on_event_handshake_succeed(*event, address.c_str());
break;
#endif
#endif
default:
on_event_unknown(*event, address.c_str());
break;
}
zmq_msg_close(&eventMsg);
return true;
}
#ifdef ZMQ_EVENT_MONITOR_STOPPED
void abort()
{
if (_socket)
zmq_socket_monitor(_socket.handle(), ZMQ_NULLPTR, 0);
_socket = socket_ref();
}
#endif
virtual void on_monitor_started() {}
virtual void on_event_connected(const zmq_event_t &event_, const char *addr_)
{
(void) event_;
(void) addr_;
}
virtual void on_event_connect_delayed(const zmq_event_t &event_,
const char *addr_)
{
(void) event_;
(void) addr_;
}
virtual void on_event_connect_retried(const zmq_event_t &event_,
const char *addr_)
{
(void) event_;
(void) addr_;
}
virtual void on_event_listening(const zmq_event_t &event_, const char *addr_)
{
(void) event_;
(void) addr_;
}
virtual void on_event_bind_failed(const zmq_event_t &event_, const char *addr_)
{
(void) event_;
(void) addr_;
}
virtual void on_event_accepted(const zmq_event_t &event_, const char *addr_)
{
(void) event_;
(void) addr_;
}
virtual void on_event_accept_failed(const zmq_event_t &event_, const char *addr_)
{
(void) event_;
(void) addr_;
}
virtual void on_event_closed(const zmq_event_t &event_, const char *addr_)
{
(void) event_;
(void) addr_;
}
virtual void on_event_close_failed(const zmq_event_t &event_, const char *addr_)
{
(void) event_;
(void) addr_;
}
virtual void on_event_disconnected(const zmq_event_t &event_, const char *addr_)
{
(void) event_;
(void) addr_;
}
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 3)
virtual void on_event_handshake_failed_no_detail(const zmq_event_t &event_,
const char *addr_)
{
(void) event_;
(void) addr_;
}
virtual void on_event_handshake_failed_protocol(const zmq_event_t &event_,
const char *addr_)
{
(void) event_;
(void) addr_;
}
virtual void on_event_handshake_failed_auth(const zmq_event_t &event_,
const char *addr_)
{
(void) event_;
(void) addr_;
}
virtual void on_event_handshake_succeeded(const zmq_event_t &event_,
const char *addr_)
{
(void) event_;
(void) addr_;
}
#elif ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 1)
virtual void on_event_handshake_failed(const zmq_event_t &event_,
const char *addr_)
{
(void) event_;
(void) addr_;
}
virtual void on_event_handshake_succeed(const zmq_event_t &event_,
const char *addr_)
{
(void) event_;
(void) addr_;
}
#endif
virtual void on_event_unknown(const zmq_event_t &event_, const char *addr_)
{
(void) event_;
(void) addr_;
}
private:
monitor_t(const monitor_t &) ZMQ_DELETED_FUNCTION;
void operator=(const monitor_t &) ZMQ_DELETED_FUNCTION;
socket_ref _socket;
socket_t _monitor_socket;
void close() ZMQ_NOTHROW
{
if (_socket)
zmq_socket_monitor(_socket.handle(), ZMQ_NULLPTR, 0);
_monitor_socket.close();
}
};
#if defined(ZMQ_BUILD_DRAFT_API) && defined(ZMQ_CPP11) && defined(ZMQ_HAVE_POLLER)
// polling events
enum class event_flags : short
{
none = 0,
pollin = ZMQ_POLLIN,
pollout = ZMQ_POLLOUT,
pollerr = ZMQ_POLLERR,
pollpri = ZMQ_POLLPRI
};
constexpr event_flags operator|(event_flags a, event_flags b) noexcept
{
return detail::enum_bit_or(a, b);
}
constexpr event_flags operator&(event_flags a, event_flags b) noexcept
{
return detail::enum_bit_and(a, b);
}
constexpr event_flags operator^(event_flags a, event_flags b) noexcept
{
return detail::enum_bit_xor(a, b);
}
constexpr event_flags operator~(event_flags a) noexcept
{
return detail::enum_bit_not(a);
}
struct no_user_data;
// layout compatible with zmq_poller_event_t
template
struct poller_event
{
socket_ref socket;
#ifdef _WIN32
SOCKET fd;
#else
int fd;
#endif
T *user_data;
event_flags events;
};
template class poller_t
{
public:
using event_type = poller_event;
poller_t() : poller_ptr(zmq_poller_new())
{
if (!poller_ptr)
throw error_t();
}
template<
typename Dummy = void,
typename =
typename std::enable_if::value, Dummy>::type>
void add(zmq::socket_ref socket, event_flags events, T *user_data)
{
add_impl(socket, events, user_data);
}
void add(zmq::socket_ref socket, event_flags events)
{
add_impl(socket, events, nullptr);
}
void remove(zmq::socket_ref socket)
{
if (0 != zmq_poller_remove(poller_ptr.get(), socket.handle())) {
throw error_t();
}
}
void modify(zmq::socket_ref socket, event_flags events)
{
if (0
!= zmq_poller_modify(poller_ptr.get(), socket.handle(),
static_cast(events))) {
throw error_t();
}
}
size_t wait_all(std::vector &poller_events,
const std::chrono::milliseconds timeout)
{
int rc = zmq_poller_wait_all(
poller_ptr.get(),
reinterpret_cast(poller_events.data()),
static_cast(poller_events.size()),
static_cast(timeout.count()));
if (rc > 0)
return static_cast(rc);
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 3)
if (zmq_errno() == EAGAIN)
#else
if (zmq_errno() == ETIMEDOUT)
#endif
return 0;
throw error_t();
}
private:
struct destroy_poller_t
{
void operator()(void *ptr) noexcept
{
int rc = zmq_poller_destroy(&ptr);
ZMQ_ASSERT(rc == 0);
}
};
std::unique_ptr poller_ptr;
void add_impl(zmq::socket_ref socket, event_flags events, T *user_data)
{
if (0
!= zmq_poller_add(poller_ptr.get(), socket.handle(),
user_data, static_cast(events))) {
throw error_t();
}
}
};
#endif // defined(ZMQ_BUILD_DRAFT_API) && defined(ZMQ_CPP11) && defined(ZMQ_HAVE_POLLER)
inline std::ostream &operator<<(std::ostream &os, const message_t &msg)
{
return os << msg.str();
}
} // namespace zmq
#endif // __ZMQ_HPP_INCLUDED__
ODR-DabMux-4.4.1/lib/ReedSolomon.h 0000644 0001750 0001750 00000002777 14465705070 015520 0 ustar robin robin /*
Copyright (C) 2005, 2006, 2007, 2008, 2009 Her Majesty the Queen in Right
of Canada (Communications Research Center Canada)
Copyright (C) 2016
Matthias P. Braendli, matthias.braendli@mpb.li
http://www.opendigitalradio.org
*/
/*
This file is part of ODR-DabMux.
ODR-DabMux 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.
ODR-DabMux 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 ODR-DabMux. If not, see .
*/
#pragma once
#ifdef HAVE_CONFIG_H
# include
#endif
#include
#include
class ReedSolomon
{
public:
ReedSolomon(int N, int K,
bool reverse = false,
int gfpoly = 0x11d, int firstRoot = 0, int primElem = 1);
ReedSolomon(const ReedSolomon& other) = delete;
ReedSolomon operator=(const ReedSolomon& other) = delete;
~ReedSolomon();
void setReverse(bool state);
int encode(void* data, void* fec, size_t size);
int encode(void* data, size_t size);
private:
int m_N;
int m_K;
void* rsData;
bool reverse;
};
ODR-DabMux-4.4.1/lib/Log.cpp 0000644 0001750 0001750 00000013316 14465705070 014335 0 ustar robin robin /*
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
Her Majesty the Queen in Right of Canada (Communications Research
Center Canada)
Copyright (C) 2018
Matthias P. Braendli, matthias.braendli@mpb.li
http://www.opendigitalradio.org
*/
/*
This file is part of the ODR-mmbTools.
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 .
*/
#include
#include
#include
#include
#include
#include "Log.h"
using namespace std;
Logger::Logger()
{
m_io_thread = std::thread(&Logger::io_process, this);
}
Logger::~Logger() {
m_message_queue.trigger_wakeup();
m_io_thread.join();
std::lock_guard guard(m_backend_mutex);
backends.clear();
}
void Logger::register_backend(std::shared_ptr backend)
{
std::lock_guard guard(m_backend_mutex);
backends.push_back(backend);
}
void Logger::log(log_level_t level, const char* fmt, ...)
{
if (level == discard) {
return;
}
int size = 100;
std::string str;
va_list ap;
while (1) {
str.resize(size);
va_start(ap, fmt);
int n = vsnprintf((char *)str.c_str(), size, fmt, ap);
va_end(ap);
if (n > -1 && n < size) {
str.resize(n);
break;
}
if (n > -1)
size = n + 1;
else
size *= 2;
}
logstr(level, move(str));
}
void Logger::logstr(log_level_t level, std::string&& message)
{
if (level == discard) {
return;
}
log_message_t m(level, move(message));
m_message_queue.push(move(m));
}
void Logger::io_process()
{
while (1) {
log_message_t m;
try {
m_message_queue.wait_and_pop(m);
}
catch (const ThreadsafeQueueWakeup&) {
break;
}
auto message = m.message;
/* Remove a potential trailing newline.
* It doesn't look good in syslog
*/
if (message[message.length()-1] == '\n') {
message.resize(message.length()-1);
}
{
std::lock_guard guard(m_backend_mutex);
for (auto &backend : backends) {
backend->log(m.level, message);
}
if (m.level != log_level_t::trace) {
using namespace std::chrono;
time_t t = system_clock::to_time_t(system_clock::now());
cerr << put_time(std::gmtime(&t), "%Y-%m-%dZ%H:%M:%S") << " " << levels_as_str[m.level] << " " << message << endl;
}
}
}
}
LogLine Logger::level(log_level_t level)
{
return LogLine(this, level);
}
LogToFile::LogToFile(const std::string& filename) : name("FILE")
{
FILE* fd = fopen(filename.c_str(), "a");
if (fd == nullptr) {
fprintf(stderr, "Cannot open log file !");
throw std::runtime_error("Cannot open log file !");
}
log_file.reset(fd);
}
void LogToFile::log(log_level_t level, const std::string& message)
{
if (not (level == log_level_t::trace or level == log_level_t::discard)) {
const char* log_level_text[] = {
"DEBUG", "INFO", "WARN", "ERROR", "ALERT", "EMERG"};
// fprintf is thread-safe
fprintf(log_file.get(), SYSLOG_IDENT ": %s: %s\n",
log_level_text[(size_t)level], message.c_str());
fflush(log_file.get());
}
}
void LogToSyslog::log(log_level_t level, const std::string& message)
{
if (not (level == log_level_t::trace or level == log_level_t::discard)) {
int syslog_level = LOG_EMERG;
switch (level) {
case debug: syslog_level = LOG_DEBUG; break;
case info: syslog_level = LOG_INFO; break;
/* we don't have the notice level */
case warn: syslog_level = LOG_WARNING; break;
case error: syslog_level = LOG_ERR; break;
default: syslog_level = LOG_CRIT; break;
case alert: syslog_level = LOG_ALERT; break;
case emerg: syslog_level = LOG_EMERG; break;
}
syslog(syslog_level, SYSLOG_IDENT " %s", message.c_str());
}
}
LogTracer::LogTracer(const string& trace_filename) : name("TRACE")
{
etiLog.level(info) << "Setting up TRACE to " << trace_filename;
FILE* fd = fopen(trace_filename.c_str(), "a");
if (fd == nullptr) {
fprintf(stderr, "Cannot open trace file !");
throw std::runtime_error("Cannot open trace file !");
}
m_trace_file.reset(fd);
using namespace std::chrono;
auto now = steady_clock::now().time_since_epoch();
m_trace_micros_startup = duration_cast(now).count();
fprintf(m_trace_file.get(),
"0,TRACER,startup at %" PRIu64 "\n", m_trace_micros_startup);
}
void LogTracer::log(log_level_t level, const std::string& message)
{
if (level == log_level_t::trace) {
using namespace std::chrono;
const auto now = steady_clock::now().time_since_epoch();
const auto micros = duration_cast(now).count();
fprintf(m_trace_file.get(), "%" PRIu64 ",%s\n",
micros - m_trace_micros_startup,
message.c_str());
}
}
ODR-DabMux-4.4.1/lib/Socket.cpp 0000644 0001750 0001750 00000100520 14465705070 015036 0 ustar robin robin /*
Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Her Majesty the
Queen in Right of Canada (Communications Research Center Canada)
Copyright (C) 2022
Matthias P. Braendli, matthias.braendli@mpb.li
http://www.opendigitalradio.org
*/
/*
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 .
*/
#include "Socket.h"
#include
#include
#include
#include
#include
#include
#include
namespace Socket {
using namespace std;
void InetAddress::resolveUdpDestination(const std::string& destination, int port)
{
char service[NI_MAXSERV];
snprintf(service, NI_MAXSERV-1, "%d", port);
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
hints.ai_flags = 0;
hints.ai_protocol = 0;
struct addrinfo *result, *rp;
int s = getaddrinfo(destination.c_str(), service, &hints, &result);
if (s != 0) {
throw runtime_error(string("getaddrinfo failed: ") + gai_strerror(s));
}
for (rp = result; rp != nullptr; rp = rp->ai_next) {
// Take the first result
memcpy(&addr, rp->ai_addr, rp->ai_addrlen);
break;
}
freeaddrinfo(result);
if (rp == nullptr) {
throw runtime_error("Could not resolve");
}
}
string InetAddress::to_string() const
{
char received_from_str[64] = {};
sockaddr *addr = reinterpret_cast(&addr);
const char* ret = inet_ntop(AF_INET, addr, received_from_str, 63);
if (ret == nullptr) {
throw invalid_argument(string("Error converting InetAddress") + strerror(errno));
}
return ret;
}
UDPPacket::UDPPacket() { }
UDPPacket::UDPPacket(size_t initSize) :
buffer(initSize),
address()
{ }
UDPSocket::UDPSocket()
{
reinit(0, "");
}
UDPSocket::UDPSocket(int port)
{
reinit(port, "");
}
UDPSocket::UDPSocket(int port, const std::string& name)
{
reinit(port, name);
}
UDPSocket::UDPSocket(UDPSocket&& other)
{
m_sock = other.m_sock;
m_port = other.m_port;
other.m_port = 0;
other.m_sock = INVALID_SOCKET;
}
const UDPSocket& UDPSocket::operator=(UDPSocket&& other)
{
m_sock = other.m_sock;
m_port = other.m_port;
other.m_port = 0;
other.m_sock = INVALID_SOCKET;
return *this;
}
void UDPSocket::setBlocking(bool block)
{
int res = fcntl(m_sock, F_SETFL, block ? 0 : O_NONBLOCK);
if (res == -1) {
throw runtime_error(string("Can't change blocking state of socket: ") + strerror(errno));
}
}
void UDPSocket::reinit(int port)
{
return reinit(port, "");
}
void UDPSocket::reinit(int port, const std::string& name)
{
if (m_sock != INVALID_SOCKET) {
::close(m_sock);
}
m_port = port;
if (port == 0) {
// No need to bind to a given port, creating the
// socket is enough
m_sock = ::socket(AF_INET, SOCK_DGRAM, 0);
return;
}
char service[NI_MAXSERV];
snprintf(service, NI_MAXSERV-1, "%d", port);
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */
hints.ai_protocol = 0; /* Any protocol */
hints.ai_canonname = nullptr;
hints.ai_addr = nullptr;
hints.ai_next = nullptr;
struct addrinfo *result, *rp;
int s = getaddrinfo(name.empty() ? nullptr : name.c_str(),
port == 0 ? nullptr : service,
&hints, &result);
if (s != 0) {
throw runtime_error(string("getaddrinfo failed: ") + gai_strerror(s));
}
/* getaddrinfo() returns a list of address structures.
Try each address until we successfully bind(2).
If socket(2) (or bind(2)) fails, we (close the socket
and) try the next address. */
for (rp = result; rp != nullptr; rp = rp->ai_next) {
int sfd = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sfd == -1) {
continue;
}
if (::bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) {
m_sock = sfd;
break;
}
::close(sfd);
}
freeaddrinfo(result);
if (rp == nullptr) {
throw runtime_error("Could not bind");
}
}
void UDPSocket::close()
{
if (m_sock != INVALID_SOCKET) {
::close(m_sock);
}
m_sock = INVALID_SOCKET;
}
UDPSocket::~UDPSocket()
{
if (m_sock != INVALID_SOCKET) {
::close(m_sock);
}
}
UDPPacket UDPSocket::receive(size_t max_size)
{
UDPPacket packet(max_size);
socklen_t addrSize;
addrSize = sizeof(*packet.address.as_sockaddr());
ssize_t ret = recvfrom(m_sock,
packet.buffer.data(),
packet.buffer.size(),
0,
packet.address.as_sockaddr(),
&addrSize);
if (ret == SOCKET_ERROR) {
packet.buffer.resize(0);
// This suppresses the -Wlogical-op warning
#if EAGAIN == EWOULDBLOCK
if (errno == EAGAIN)
#else
if (errno == EAGAIN or errno == EWOULDBLOCK)
#endif
{
return 0;
}
throw runtime_error(string("Can't receive data: ") + strerror(errno));
}
packet.buffer.resize(ret);
return packet;
}
void UDPSocket::send(UDPPacket& packet)
{
const int ret = sendto(m_sock, packet.buffer.data(), packet.buffer.size(), 0,
packet.address.as_sockaddr(), sizeof(*packet.address.as_sockaddr()));
if (ret == SOCKET_ERROR && errno != ECONNREFUSED) {
throw runtime_error(string("Can't send UDP packet: ") + strerror(errno));
}
}
void UDPSocket::send(const std::vector& data, InetAddress destination)
{
const int ret = sendto(m_sock, data.data(), data.size(), 0,
destination.as_sockaddr(), sizeof(*destination.as_sockaddr()));
if (ret == SOCKET_ERROR && errno != ECONNREFUSED) {
throw runtime_error(string("Can't send UDP packet: ") + strerror(errno));
}
}
void UDPSocket::send(const std::string& data, InetAddress destination)
{
const int ret = sendto(m_sock, data.data(), data.size(), 0,
destination.as_sockaddr(), sizeof(*destination.as_sockaddr()));
if (ret == SOCKET_ERROR && errno != ECONNREFUSED) {
throw runtime_error(string("Can't send UDP packet: ") + strerror(errno));
}
}
void UDPSocket::joinGroup(const char* groupname, const char* if_addr)
{
ip_mreqn group;
if ((group.imr_multiaddr.s_addr = inet_addr(groupname)) == INADDR_NONE) {
throw runtime_error("Cannot convert multicast group name");
}
if (!IN_MULTICAST(ntohl(group.imr_multiaddr.s_addr))) {
throw runtime_error("Group name is not a multicast address");
}
if (if_addr) {
group.imr_address.s_addr = inet_addr(if_addr);
}
else {
group.imr_address.s_addr = htons(INADDR_ANY);
}
group.imr_ifindex = 0;
if (setsockopt(m_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &group, sizeof(group))
== SOCKET_ERROR) {
throw runtime_error(string("Can't join multicast group") + strerror(errno));
}
}
void UDPSocket::setMulticastSource(const char* source_addr)
{
struct in_addr addr;
if (inet_aton(source_addr, &addr) == 0) {
throw runtime_error(string("Can't parse source address") + strerror(errno));
}
if (setsockopt(m_sock, IPPROTO_IP, IP_MULTICAST_IF, &addr, sizeof(addr))
== SOCKET_ERROR) {
throw runtime_error(string("Can't set source address") + strerror(errno));
}
}
void UDPSocket::setMulticastTTL(int ttl)
{
if (setsockopt(m_sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl))
== SOCKET_ERROR) {
throw runtime_error(string("Can't set multicast ttl") + strerror(errno));
}
}
SOCKET UDPSocket::getNativeSocket() const
{
return m_sock;
}
int UDPSocket::getPort() const
{
return m_port;
}
void UDPReceiver::add_receive_port(int port, const string& bindto, const string& mcastaddr) {
UDPSocket sock;
if (IN_MULTICAST(ntohl(inet_addr(mcastaddr.c_str())))) {
sock.reinit(port, mcastaddr);
sock.setMulticastSource(bindto.c_str());
sock.joinGroup(mcastaddr.c_str(), bindto.c_str());
}
else {
sock.reinit(port, bindto);
}
m_sockets.push_back(move(sock));
}
vector UDPReceiver::receive(int timeout_ms)
{
constexpr size_t MAX_FDS = 64;
struct pollfd fds[MAX_FDS];
if (m_sockets.size() > MAX_FDS) {
throw std::runtime_error("UDPReceiver only supports up to 64 ports");
}
for (size_t i = 0; i < m_sockets.size(); i++) {
fds[i].fd = m_sockets[i].getNativeSocket();
fds[i].events = POLLIN;
}
int retval = poll(fds, m_sockets.size(), timeout_ms);
if (retval == -1 and errno == EINTR) {
throw Interrupted();
}
else if (retval == -1) {
std::string errstr(strerror(errno));
throw std::runtime_error("UDP receive with poll() error: " + errstr);
}
else if (retval > 0) {
vector received;
for (size_t i = 0; i < m_sockets.size(); i++) {
if (fds[i].revents & POLLIN) {
auto p = m_sockets[i].receive(2048); // This is larger than the usual MTU
ReceivedPacket rp;
rp.packetdata = move(p.buffer);
rp.received_from = move(p.address);
rp.port_received_on = m_sockets[i].getPort();
received.push_back(move(rp));
}
}
return received;
}
else {
throw Timeout();
}
}
TCPSocket::TCPSocket()
{
}
TCPSocket::~TCPSocket()
{
if (m_sock != -1) {
::close(m_sock);
}
}
TCPSocket::TCPSocket(TCPSocket&& other) :
m_sock(other.m_sock),
m_remote_address(move(other.m_remote_address))
{
if (other.m_sock != -1) {
other.m_sock = -1;
}
}
TCPSocket& TCPSocket::operator=(TCPSocket&& other)
{
swap(m_remote_address, other.m_remote_address);
m_sock = other.m_sock;
if (other.m_sock != -1) {
other.m_sock = -1;
}
return *this;
}
bool TCPSocket::valid() const
{
return m_sock != -1;
}
void TCPSocket::connect(const std::string& hostname, int port, int timeout_ms)
{
if (m_sock != INVALID_SOCKET) {
throw std::logic_error("You may only connect an invalid TCPSocket");
}
char service[NI_MAXSERV];
snprintf(service, NI_MAXSERV-1, "%d", port);
/* Obtain address(es) matching host/port */
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = 0;
hints.ai_protocol = 0;
struct addrinfo *result, *rp;
int s = getaddrinfo(hostname.c_str(), service, &hints, &result);
if (s != 0) {
throw runtime_error(string("getaddrinfo failed: ") + gai_strerror(s));
}
int flags = 0;
/* getaddrinfo() returns a list of address structures.
Try each address until we successfully connect(2).
If socket(2) (or connect(2)) fails, we (close the socket
and) try the next address. */
for (rp = result; rp != nullptr; rp = rp->ai_next) {
int sfd = ::socket(rp->ai_family, rp->ai_socktype,
rp->ai_protocol);
if (sfd == -1)
continue;
flags = fcntl(sfd, F_GETFL);
if (flags == -1) {
std::string errstr(strerror(errno));
throw std::runtime_error("TCP: Could not get socket flags: " + errstr);
}
if (fcntl(sfd, F_SETFL, flags | O_NONBLOCK) == -1) {
std::string errstr(strerror(errno));
throw std::runtime_error("TCP: Could not set O_NONBLOCK: " + errstr);
}
int ret = ::connect(sfd, rp->ai_addr, rp->ai_addrlen);
if (ret == 0) {
m_sock = sfd;
break;
}
if (ret == -1 and errno == EINPROGRESS) {
m_sock = sfd;
struct pollfd fds[1];
fds[0].fd = m_sock;
fds[0].events = POLLOUT;
int retval = poll(fds, 1, timeout_ms);
if (retval == -1) {
std::string errstr(strerror(errno));
::close(m_sock);
freeaddrinfo(result);
throw runtime_error("TCP: connect error on poll: " + errstr);
}
else if (retval > 0) {
int so_error = 0;
socklen_t len = sizeof(so_error);
if (getsockopt(m_sock, SOL_SOCKET, SO_ERROR, &so_error, &len) == -1) {
std::string errstr(strerror(errno));
::close(m_sock);
freeaddrinfo(result);
throw runtime_error("TCP: getsockopt error connect: " + errstr);
}
if (so_error == 0) {
break;
}
}
else {
::close(m_sock);
freeaddrinfo(result);
throw runtime_error("Timeout on connect");
}
break;
}
::close(sfd);
}
if (m_sock != INVALID_SOCKET) {
#if defined(HAVE_SO_NOSIGPIPE)
int val = 1;
if (setsockopt(m_sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val))
== SOCKET_ERROR) {
throw runtime_error("Can't set SO_NOSIGPIPE");
}
#endif
}
// Don't keep the socket blocking
if (fcntl(m_sock, F_SETFL, flags) == -1) {
std::string errstr(strerror(errno));
throw std::runtime_error("TCP: Could not set O_NONBLOCK: " + errstr);
}
freeaddrinfo(result);
if (rp == nullptr) {
throw runtime_error("Could not connect");
}
}
void TCPSocket::connect(const std::string& hostname, int port, bool nonblock)
{
if (m_sock != INVALID_SOCKET) {
throw std::logic_error("You may only connect an invalid TCPSocket");
}
char service[NI_MAXSERV];
snprintf(service, NI_MAXSERV-1, "%d", port);
/* Obtain address(es) matching host/port */
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = 0;
hints.ai_protocol = 0;
struct addrinfo *result, *rp;
int s = getaddrinfo(hostname.c_str(), service, &hints, &result);
if (s != 0) {
throw runtime_error(string("getaddrinfo failed: ") + gai_strerror(s));
}
/* getaddrinfo() returns a list of address structures.
Try each address until we successfully connect(2).
If socket(2) (or connect(2)) fails, we (close the socket
and) try the next address. */
for (rp = result; rp != nullptr; rp = rp->ai_next) {
int sfd = ::socket(rp->ai_family, rp->ai_socktype,
rp->ai_protocol);
if (sfd == -1)
continue;
if (nonblock) {
int flags = fcntl(sfd, F_GETFL);
if (flags == -1) {
std::string errstr(strerror(errno));
freeaddrinfo(result);
::close(sfd);
throw std::runtime_error("TCP: Could not get socket flags: " + errstr);
}
if (fcntl(sfd, F_SETFL, flags | O_NONBLOCK) == -1) {
std::string errstr(strerror(errno));
freeaddrinfo(result);
::close(sfd);
throw std::runtime_error("TCP: Could not set O_NONBLOCK: " + errstr);
}
}
int ret = ::connect(sfd, rp->ai_addr, rp->ai_addrlen);
if (ret != -1 or (ret == -1 and errno == EINPROGRESS)) {
m_sock = sfd;
break;
}
::close(sfd);
}
if (m_sock != INVALID_SOCKET) {
#if defined(HAVE_SO_NOSIGPIPE)
int val = 1;
if (setsockopt(m_sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val))
== SOCKET_ERROR) {
throw std::runtime_error("Can't set SO_NOSIGPIPE");
}
#endif
}
freeaddrinfo(result); /* No longer needed */
if (rp == nullptr) {
throw runtime_error("Could not connect");
}
}
void TCPSocket::enable_keepalive(int time, int intvl, int probes)
{
if (m_sock == INVALID_SOCKET) {
throw std::logic_error("You may not call enable_keepalive on invalid socket");
}
int optval = 1;
auto optlen = sizeof(optval);
if (setsockopt(m_sock, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) < 0) {
std::string errstr(strerror(errno));
throw std::runtime_error("TCP: Could not set SO_KEEPALIVE: " + errstr);
}
optval = time;
if (setsockopt(m_sock, SOL_TCP, TCP_KEEPIDLE, &optval, optlen) < 0) {
std::string errstr(strerror(errno));
throw std::runtime_error("TCP: Could not set TCP_KEEPIDLE: " + errstr);
}
optval = intvl;
if (setsockopt(m_sock, SOL_TCP, TCP_KEEPINTVL, &optval, optlen) < 0) {
std::string errstr(strerror(errno));
throw std::runtime_error("TCP: Could not set TCP_KEEPINTVL: " + errstr);
}
optval = probes;
if (setsockopt(m_sock, SOL_TCP, TCP_KEEPCNT, &optval, optlen) < 0) {
std::string errstr(strerror(errno));
throw std::runtime_error("TCP: Could not set TCP_KEEPCNT: " + errstr);
}
}
void TCPSocket::listen(int port, const string& name)
{
if (m_sock != INVALID_SOCKET) {
throw std::logic_error("You may only listen with an invalid TCPSocket");
}
char service[NI_MAXSERV];
snprintf(service, NI_MAXSERV-1, "%d", port);
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */
hints.ai_protocol = 0;
hints.ai_canonname = nullptr;
hints.ai_addr = nullptr;
hints.ai_next = nullptr;
struct addrinfo *result, *rp;
int s = getaddrinfo(name.empty() ? nullptr : name.c_str(), service, &hints, &result);
if (s != 0) {
throw runtime_error(string("getaddrinfo failed: ") + gai_strerror(s));
}
/* getaddrinfo() returns a list of address structures.
Try each address until we successfully bind(2).
If socket(2) (or bind(2)) fails, we (close the socket
and) try the next address. */
for (rp = result; rp != nullptr; rp = rp->ai_next) {
int sfd = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sfd == -1) {
continue;
}
int reuse_setting = 1;
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse_setting, sizeof(reuse_setting)) == -1) {
throw runtime_error("Can't reuse address");
}
if (::bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) {
m_sock = sfd;
break;
}
::close(sfd);
}
freeaddrinfo(result);
if (m_sock != INVALID_SOCKET) {
#if defined(HAVE_SO_NOSIGPIPE)
int val = 1;
if (setsockopt(m_sock, SOL_SOCKET, SO_NOSIGPIPE,
&val, sizeof(val)) < 0) {
throw std::runtime_error("Can't set SO_NOSIGPIPE");
}
#endif
int ret = ::listen(m_sock, 0);
if (ret == -1) {
throw std::runtime_error(string("Could not listen: ") + strerror(errno));
}
}
if (rp == nullptr) {
throw runtime_error("Could not bind");
}
}
void TCPSocket::close()
{
::close(m_sock);
m_sock = -1;
}
TCPSocket TCPSocket::accept(int timeout_ms)
{
if (timeout_ms == 0) {
InetAddress remote_addr;
socklen_t client_len = sizeof(remote_addr.addr);
int sockfd = ::accept(m_sock, remote_addr.as_sockaddr(), &client_len);
TCPSocket s(sockfd, remote_addr);
return s;
}
else {
struct pollfd fds[1];
fds[0].fd = m_sock;
fds[0].events = POLLIN;
int retval = poll(fds, 1, timeout_ms);
if (retval == -1) {
std::string errstr(strerror(errno));
throw std::runtime_error("TCP Socket accept error: " + errstr);
}
else if (retval > 0) {
InetAddress remote_addr;
socklen_t client_len = sizeof(remote_addr.addr);
int sockfd = ::accept(m_sock, remote_addr.as_sockaddr(), &client_len);
TCPSocket s(sockfd, remote_addr);
return s;
}
else {
TCPSocket s(-1);
return s;
}
}
}
ssize_t TCPSocket::sendall(const void *buffer, size_t buflen)
{
uint8_t *buf = (uint8_t*)buffer;
while (buflen > 0) {
/* On Linux, the MSG_NOSIGNAL flag ensures that the process
* would not receive a SIGPIPE and die.
* Other systems have SO_NOSIGPIPE set on the socket for the
* same effect. */
#if defined(HAVE_MSG_NOSIGNAL)
const int flags = MSG_NOSIGNAL;
#else
const int flags = 0;
#endif
ssize_t sent = ::send(m_sock, buf, buflen, flags);
if (sent < 0) {
return -1;
}
else {
buf += sent;
buflen -= sent;
}
}
return buflen;
}
ssize_t TCPSocket::send(const void* data, size_t size, int timeout_ms)
{
if (timeout_ms) {
struct pollfd fds[1];
fds[0].fd = m_sock;
fds[0].events = POLLOUT;
const int retval = poll(fds, 1, timeout_ms);
if (retval == -1) {
throw std::runtime_error(string("TCP Socket send error on poll(): ") + strerror(errno));
}
else if (retval == 0) {
// Timed out
return 0;
}
}
/* On Linux, the MSG_NOSIGNAL flag ensures that the process would not
* receive a SIGPIPE and die.
* Other systems have SO_NOSIGPIPE set on the socket for the same effect. */
#if defined(HAVE_MSG_NOSIGNAL)
const int flags = MSG_NOSIGNAL;
#else
const int flags = 0;
#endif
const ssize_t ret = ::send(m_sock, (const char*)data, size, flags);
if (ret == SOCKET_ERROR) {
throw std::runtime_error(string("TCP Socket send error: ") + strerror(errno));
}
return ret;
}
ssize_t TCPSocket::recv(void *buffer, size_t length, int flags)
{
ssize_t ret = ::recv(m_sock, buffer, length, flags);
if (ret == -1) {
if (errno == EINTR) {
throw Interrupted();
}
else {
std::string errstr(strerror(errno));
throw std::runtime_error("TCP receive error: " + errstr);
}
}
return ret;
}
ssize_t TCPSocket::recv(void *buffer, size_t length, int flags, int timeout_ms)
{
struct pollfd fds[1];
fds[0].fd = m_sock;
fds[0].events = POLLIN;
int retval = poll(fds, 1, timeout_ms);
if (retval == -1 and errno == EINTR) {
throw Interrupted();
}
else if (retval == -1) {
std::string errstr(strerror(errno));
throw std::runtime_error("TCP receive with poll() error: " + errstr);
}
else if (retval > 0 and (fds[0].revents & POLLIN)) {
ssize_t ret = ::recv(m_sock, buffer, length, flags);
if (ret == -1) {
if (errno == ECONNREFUSED) {
return 0;
}
std::string errstr(strerror(errno));
throw std::runtime_error("TCP receive after poll() error: " + errstr);
}
return ret;
}
else {
throw Timeout();
}
}
TCPSocket::TCPSocket(int sockfd) :
m_sock(sockfd),
m_remote_address()
{ }
TCPSocket::TCPSocket(int sockfd, InetAddress remote_address) :
m_sock(sockfd),
m_remote_address(remote_address)
{ }
void TCPClient::connect(const std::string& hostname, int port)
{
m_hostname = hostname;
m_port = port;
reconnect();
}
ssize_t TCPClient::recv(void *buffer, size_t length, int flags, int timeout_ms)
{
try {
ssize_t ret = m_sock.recv(buffer, length, flags, timeout_ms);
if (ret == 0) {
m_sock.close();
reconnect();
}
return ret;
}
catch (const TCPSocket::Interrupted&) {
return -1;
}
catch (const TCPSocket::Timeout&) {
return 0;
}
throw std::logic_error("unreachable");
}
void TCPClient::reconnect()
{
TCPSocket newsock;
m_sock = std::move(newsock);
m_sock.connect(m_hostname, m_port, true);
}
TCPConnection::TCPConnection(TCPSocket&& sock) :
queue(),
m_running(true),
m_sender_thread(),
m_sock(move(sock))
{
#if MISSING_OWN_ADDR
auto own_addr = m_sock.getOwnAddress();
auto addr = m_sock.getRemoteAddress();
etiLog.level(debug) << "New TCP Connection on port " <<
own_addr.getPort() << " from " <<
addr.getHostAddress() << ":" << addr.getPort();
#endif
m_sender_thread = std::thread(&TCPConnection::process, this);
}
TCPConnection::~TCPConnection()
{
m_running = false;
vector termination_marker;
queue.push(termination_marker);
if (m_sender_thread.joinable()) {
m_sender_thread.join();
}
}
void TCPConnection::process()
{
while (m_running) {
vector data;
queue.wait_and_pop(data);
if (data.empty()) {
// empty vector is the termination marker
m_running = false;
break;
}
try {
ssize_t remaining = data.size();
const uint8_t *buf = reinterpret_cast(data.data());
const int timeout_ms = 10; // Less than one ETI frame
while (m_running and remaining > 0) {
const ssize_t sent = m_sock.send(buf, remaining, timeout_ms);
if (sent < 0 or sent > remaining) {
throw std::logic_error("Invalid TCPSocket::send() return value");
}
remaining -= sent;
buf += sent;
}
}
catch (const std::runtime_error& e) {
m_running = false;
}
}
#if MISSING_OWN_ADDR
auto own_addr = m_sock.getOwnAddress();
auto addr = m_sock.getRemoteAddress();
etiLog.level(debug) << "Dropping TCP Connection on port " <<
own_addr.getPort() << " from " <<
addr.getHostAddress() << ":" << addr.getPort();
#endif
}
TCPDataDispatcher::TCPDataDispatcher(size_t max_queue_size, size_t buffers_to_preroll) :
m_max_queue_size(max_queue_size),
m_buffers_to_preroll(buffers_to_preroll)
{
}
TCPDataDispatcher::~TCPDataDispatcher()
{
m_running = false;
m_connections.clear();
m_listener_socket.close();
if (m_listener_thread.joinable()) {
m_listener_thread.join();
}
}
void TCPDataDispatcher::start(int port, const string& address)
{
m_listener_socket.listen(port, address);
m_running = true;
m_listener_thread = std::thread(&TCPDataDispatcher::process, this);
}
void TCPDataDispatcher::write(const vector& data)
{
if (not m_running) {
throw runtime_error(m_exception_data);
}
auto lock = unique_lock(m_mutex);
if (m_buffers_to_preroll > 0) {
m_preroll_queue.push_back(data);
if (m_preroll_queue.size() > m_buffers_to_preroll) {
m_preroll_queue.pop_front();
}
}
for (auto& connection : m_connections) {
connection.queue.push(data);
}
m_connections.remove_if( [&](const TCPConnection& conn){ return conn.queue.size() > m_max_queue_size; });
}
void TCPDataDispatcher::process()
{
try {
const int timeout_ms = 1000;
while (m_running) {
// Add a new TCPConnection to the list, constructing it from the client socket
auto sock = m_listener_socket.accept(timeout_ms);
if (sock.valid()) {
auto lock = unique_lock(m_mutex);
m_connections.emplace(m_connections.begin(), move(sock));
if (m_buffers_to_preroll > 0) {
for (const auto& buf : m_preroll_queue) {
m_connections.front().queue.push(buf);
}
}
}
}
}
catch (const std::runtime_error& e) {
m_exception_data = string("TCPDataDispatcher error: ") + e.what();
m_running = false;
}
}
TCPReceiveServer::TCPReceiveServer(size_t blocksize) :
m_blocksize(blocksize)
{
}
void TCPReceiveServer::start(int listen_port, const std::string& address)
{
m_listener_socket.listen(listen_port, address);
m_running = true;
m_listener_thread = std::thread(&TCPReceiveServer::process, this);
}
TCPReceiveServer::~TCPReceiveServer()
{
m_running = false;
if (m_listener_thread.joinable()) {
m_listener_thread.join();
}
}
shared_ptr TCPReceiveServer::receive()
{
shared_ptr buffer = make_shared();
m_queue.try_pop(buffer);
// we can ignore try_pop()'s return value, because
// if it is unsuccessful the buffer is not touched.
return buffer;
}
void TCPReceiveServer::process()
{
constexpr int timeout_ms = 1000;
constexpr int disconnect_timeout_ms = 10000;
constexpr int max_num_timeouts = disconnect_timeout_ms / timeout_ms;
while (m_running) {
auto sock = m_listener_socket.accept(timeout_ms);
int num_timeouts = 0;
while (m_running and sock.valid()) {
try {
vector buf(m_blocksize);
ssize_t r = sock.recv(buf.data(), buf.size(), 0, timeout_ms);
if (r < 0) {
throw logic_error("Invalid recv return value");
}
else if (r == 0) {
sock.close();
m_queue.push(make_shared());
break;
}
else {
buf.resize(r);
m_queue.push(make_shared(move(buf)));
}
}
catch (const TCPSocket::Interrupted&) {
break;
}
catch (const TCPSocket::Timeout&) {
num_timeouts++;
}
catch (const runtime_error& e) {
sock.close();
// TODO replace fprintf
fprintf(stderr, "TCP Receiver restarted after error: %s\n", e.what());
m_queue.push(make_shared());
}
if (num_timeouts > max_num_timeouts) {
sock.close();
m_queue.push(make_shared());
}
}
}
}
TCPSendClient::TCPSendClient(const std::string& hostname, int port) :
m_hostname(hostname),
m_port(port),
m_running(true)
{
m_sender_thread = std::thread(&TCPSendClient::process, this);
}
TCPSendClient::~TCPSendClient()
{
m_running = false;
m_queue.trigger_wakeup();
if (m_sender_thread.joinable()) {
m_sender_thread.join();
}
}
void TCPSendClient::sendall(const std::vector& buffer)
{
if (not m_running) {
throw runtime_error(m_exception_data);
}
m_queue.push(buffer);
if (m_queue.size() > MAX_QUEUE_SIZE) {
vector discard;
m_queue.try_pop(discard);
}
}
void TCPSendClient::process()
{
try {
while (m_running) {
if (m_is_connected) {
try {
vector incoming;
m_queue.wait_and_pop(incoming);
if (m_sock.sendall(incoming.data(), incoming.size()) == -1) {
m_is_connected = false;
m_sock = TCPSocket();
}
}
catch (const ThreadsafeQueueWakeup&) {
break;
}
}
else {
try {
m_sock.connect(m_hostname, m_port);
m_is_connected = true;
}
catch (const runtime_error& e) {
m_is_connected = false;
this_thread::sleep_for(chrono::seconds(1));
}
}
}
}
catch (const runtime_error& e) {
m_exception_data = e.what();
m_running = false;
}
}
}
ODR-DabMux-4.4.1/lib/RemoteControl.h 0000644 0001750 0001750 00000016375 14465705070 016065 0 ustar robin robin /*
Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012
Her Majesty the Queen in Right of Canada (Communications Research
Center Canada)
Copyright (C) 2019
Matthias P. Braendli, matthias.braendli@mpb.li
http://www.opendigitalradio.org
This module adds remote-control capability to some of the dabmux/dabmod modules.
*/
/*
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 .
*/
#pragma once
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#if defined(HAVE_ZEROMQ)
# include "zmq.hpp"
#endif
#include
#include