Compare commits

...

29 Commits

Author SHA1 Message Date
Jaroslav Kysela ac318f2b8c fix1 2018-10-21 15:57:02 +02:00
Jaroslav Kysela c57118c568 upgrade-fw: use tar balls from github releases 2018-10-21 15:46:22 +02:00
Jaroslav Kysela 61f769b0a5 add binaries satip-axe-201810171851-15 2018-10-17 19:11:40 +02:00
Jaroslav Kysela a000ec29ba update README (build 15) 2018-10-17 19:00:27 +02:00
Jaroslav Kysela f397fdaf6c another minisatip8 fix 2018-10-17 18:50:26 +02:00
Jaroslav Kysela 7078b99048 Revert "fix new dropbear build"
This reverts commit 3ee63f168e.
2018-10-17 17:34:13 +02:00
Jaroslav Kysela 9a60791649 Revert "updated dropbear to 2018.76"
This reverts commit dbce4ca82b.
2018-10-17 17:34:06 +02:00
Jaroslav Kysela 3ee63f168e fix new dropbear build 2018-10-17 17:33:59 +02:00
Jaroslav Kysela e983b7d842 minisatip8: ignore wrong PIDs (VDR sends PID 65535!) 2018-10-17 17:11:51 +02:00
Jaroslav Kysela dbce4ca82b updated dropbear to 2018.76 2018-10-17 17:11:51 +02:00
Jaroslav Kysela 5affe3cd94 oscam: update to 11434 2018-10-17 17:11:50 +02:00
Jaroslav Kysela caecc4b044 minisatip8: improve status/signal reporting, default is threaded mode now 2018-10-17 17:11:50 +02:00
Jaroslav Kysela 85a07ae86b i2c_mangle: always set PLS code and mode, it's independent from MIS 2018-10-17 17:11:50 +02:00
Jaroslav Kysela c4875893a3 i2c_mangle: always set PLS code and mode, it's independent from MIS 2018-10-13 10:34:46 +02:00
Jaroslav Kysela fb0fd9fdbb minisatip8: more multistream fixes (add PLS ROOT mode support) 2018-10-13 00:51:02 +02:00
Jaroslav Kysela 47de7247b5 i2c_mangle: allow to set PLS mode, too 2018-10-13 00:48:30 +02:00
Jaroslav Kysela 6c7c2fb61e i2c_mangle: fix msi -> mis typo 2018-10-12 11:24:41 +02:00
Jaroslav Kysela 83d670b4c8 updated minisatip8 - multistream, diseqc address 2018-10-12 11:24:41 +02:00
perexg 9c91484e29 Update README 2018-10-12 11:24:40 +02:00
perexg da33b45c9d Update README.md 2018-10-12 11:24:40 +02:00
Jaroslav Kysela a0060a0d3a i2c_mangle module: add support for mis/pls settings (multistream) 2018-10-12 09:23:30 +02:00
Jaroslav Kysela 41964656ff dist/README: add note that releases are on github now 2018-10-08 17:40:20 +02:00
Jaroslav Kysela 495bc2efe4 README.md sync 2018-10-08 17:38:30 +02:00
Oliver Kurz 8f633628b9 Delete outdated firmware images which are better provided by github releases 2018-10-08 16:59:00 +02:00
Oliver Kurz 85f777c078 dist: Add notes regarding automount, missing web interface and DLNA 2018-10-08 16:58:42 +02:00
Jaroslav Kysela 516c4b1cb6 minisatip.md: remove -S for minisatip8 in the first table 2018-09-25 13:38:47 +02:00
Jaroslav Kysela 69febad731 added multicast-rtp-2.tar.gz and Python-3.5.6-1.tar.gz 2018-09-25 11:16:42 +02:00
Jaroslav Kysela 686cf548a7 fix python3-makefile.patch 2018-09-25 11:16:42 +02:00
Jaroslav Kysela 6b3ee4236f upgrade multicast-rtp, upgrade to python 3.5.6, upgrade oscam to 11432
Thanks to @lars18th on github for the multicast-rtp improvement.
2018-09-25 11:16:13 +02:00
19 changed files with 1335 additions and 157 deletions

View File

@ -69,18 +69,18 @@ NANO_FILENAME=$(NANO).tar.gz
NANO_DOWNLOAD=http://www.nano-editor.org/dist/v2.8/$(NANO_FILENAME) NANO_DOWNLOAD=http://www.nano-editor.org/dist/v2.8/$(NANO_FILENAME)
PYTHON3_VERSION0=3.5 PYTHON3_VERSION0=3.5
PYTHON3_VERSION=$(PYTHON3_VERSION0).3 PYTHON3_VERSION=$(PYTHON3_VERSION0).6
PYTHON3=Python-$(PYTHON3_VERSION) PYTHON3=Python-$(PYTHON3_VERSION)
PYTHON3_PACKAGE_NAME=$(PYTHON3)-1 PYTHON3_PACKAGE_NAME=$(PYTHON3)-1
PYTHON3_FILENAME=$(PYTHON3).tgz PYTHON3_FILENAME=$(PYTHON3).tgz
PYTHON3_DOWNLOAD=https://www.python.org/ftp/python/$(PYTHON3_VERSION)/$(PYTHON3_FILENAME) PYTHON3_DOWNLOAD=https://www.python.org/ftp/python/$(PYTHON3_VERSION)/$(PYTHON3_FILENAME)
MULTICAST_RTP_PACKAGE_NAME=multicast-rtp-1 MULTICAST_RTP_PACKAGE_NAME=multicast-rtp-2
TVHEADEND_COMMIT=master TVHEADEND_COMMIT=master
# 10663 10937 11234 # 10663 10937 11234 11398
OSCAM_REV=11398 OSCAM_REV=11434
define GIT_CLONE define GIT_CLONE
@mkdir -p apps/host @mkdir -p apps/host
@ -161,7 +161,7 @@ fs.cpio: $(CPIO_SRCS)
$(foreach f,$(notdir $(wildcard apps/minisatip8/html/*)), -e "apps/minisatip8/html/$f:usr/share/minisatip8/html/$f") \ $(foreach f,$(notdir $(wildcard apps/minisatip8/html/*)), -e "apps/minisatip8/html/$f:usr/share/minisatip8/html/$f") \
-e "apps/$(NANO)/src/nano:usr/bin/nano" \ -e "apps/$(NANO)/src/nano:usr/bin/nano" \
-e "apps/mtd-utils/nandwrite:usr/sbin/nandwrite2" \ -e "apps/mtd-utils/nandwrite:usr/sbin/nandwrite2" \
-e "apps/oscam-svn/Distribution/oscam-1.20-unstable_svn$(OSCAM_REV)-sh4-linux:sbin/oscamd" -e "apps/oscam-svn/Distribution/oscam-1.20_svn$(OSCAM_REV)-sh4-linux:sbin/oscamd"
.PHONY: fs-list .PHONY: fs-list
fs-list: fs-list:

View File

@ -5,47 +5,23 @@ A firmware with minisatip for Inverto IDL-400s/Grundig GSS.BOX/Telestar Digibit
[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](http://paypal.me/perex) [![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](http://paypal.me/perex)
The firmware contains various versions of [minisatip](https://github.com/catalinii/minisatip)
which is tuned to get the best performance on this hardware. There are many extensions for
the complex hobby satellite reception (like free input mode - use any tuner with any physical input,
DVB-S2 multistream support etc.).
There is no DLNA server, but there is HTTP and FTP server to server for
example m3u playlists to clients.
Releases: Releases:
--------- ---------
- download from [github releases](https://github.com/perexg/satip-axe/releases)
- see to [dist](https://github.com/perexg/satip-axe/tree/master/dist) directory - README file - see to [dist](https://github.com/perexg/satip-axe/tree/master/dist) directory - README file
- a TTL USB serial is not required to boot this precompiled firmware - a TTL USB serial is not required to boot this precompiled firmware
from the USB stick or an installation to the internal flash from the USB stick or an installation to the internal flash
A notes for developers (might be outdated): Developers:
------------------------------------------- -----------
Requirements: - see [debug](https://github.com/perexg/satip-axe/tree/master/debug)
- git, python
- STLinux 2.4 (all-sh4-glibc) - http://www.stlinux.com - installed to /opt/STM/STLinux-2.4/
- fakeroot package/tools
Compilation:
- just type 'make'
- kernel with rootfs is in kernel/arch/sh/boot/uImage.gz
Booting uImage.gz on Inverto IDL-400S/Grundig GSS.BOX/Telestar Digibit R1 from USB:
- connect TTL USB serial adapter to J3 connector (4 pins at the power supply)
- pin 1 = 3.6V (do not use), pin 2 = GND, pin 3 = RXD (STM CPU), pin 4 = TXD (STM CPU)
- parameters: 115200,8N1
- press 'Enter' when you turn on the box (you have only one second) to get 'idl4k> ' prompt
(it seems that 'Enter' is required also to enable the serial console)
- modify bootargs (optional - for original firmware)
set bootargs=console=ttyAS0,115200
- set debugfw environment variable
set debugfw "debugfw=usb start;usb start;fatload usb 0 0x84000000 uimage.gz;set bootargs console=ttyAS0,115200 bigphysarea=20000;bootm 0x84000000"
- you may type 'save' to store this settings permanently
- to execute the debugfw type 'run debugfw'
- note that the USB stick should be in the first (upper) USB connector
Configuration
- dhcp client, telnetd, dropbear (ssh daemon) and minisatip are active by default
- configuration is stored in /etc/sysconfig/config

37
debug/README.md Normal file
View File

@ -0,0 +1,37 @@
A notes for developers (might be outdated):
-------------------------------------------
Requirements:
- git, python
- STLinux 2.4 (all-sh4-glibc) - http://www.stlinux.com - installed to /opt/STM/STLinux-2.4/
- fakeroot package/tools
Compilation:
- just type 'make'
- kernel with rootfs is in kernel/arch/sh/boot/uImage.gz
Booting uImage.gz on Inverto IDL-400S/Grundig GSS.BOX/Telestar Digibit R1 from USB:
- connect TTL USB serial adapter to J3 connector (4 pins at the power supply)
- pin 1 = 3.6V (do not use), pin 2 = GND, pin 3 = RXD (STM CPU), pin 4 = TXD (STM CPU)
- parameters: 115200,8N1
- press 'Enter' when you turn on the box (you have only one second) to get 'idl4k> ' prompt
(it seems that 'Enter' is required also to enable the serial console)
- modify bootargs (optional - for original firmware)
set bootargs=console=ttyAS0,115200
- set debugfw environment variable
set debugfw "debugfw=usb start;usb start;fatload usb 0 0x84000000 uimage.gz;set bootargs console=ttyAS0,115200 bigphysarea=20000;bootm 0x84000000"
- you may type 'save' to store this settings permanently
- to execute the debugfw type 'run debugfw'
- note that the USB stick should be in the first (upper) USB connector
Configuration
- dhcp client, telnetd, dropbear (ssh daemon) and minisatip are active by default
- configuration is stored in /etc/sysconfig/config

17
dist/README vendored
View File

@ -79,6 +79,7 @@ Customization:
- if /etc/sysconfig/profile script exists, it is executed at login - if /etc/sysconfig/profile script exists, it is executed at login
- writeable ftp - copy /etc/inetd.conf to /etc/sysconfig/inetd.conf and - writeable ftp - copy /etc/inetd.conf to /etc/sysconfig/inetd.conf and
add -w argument to the ftpd daemon add -w argument to the ftpd daemon
- flash drives are automounted on /media
httpd: httpd:
------ ------
@ -200,6 +201,11 @@ Notes:
- the original firmware uses fw1-nand0 flash region (32M) - the original firmware uses fw1-nand0 flash region (32M)
- the satip-axe firmware uses fw2-nand0 flash region (32M) - the satip-axe firmware uses fw2-nand0 flash region (32M)
- data block is named data-nand0 - uses rest of flash - data block is named data-nand0 - uses rest of flash
- the original firmware provides a web interface for administration, the
satip-axe uses local files for configuration.
- the original firmware provides a DLNA server. Within satip-axe the http
server can be used to provide for example channels maps in the form of
.m3u files
Disclaimer: Disclaimer:
----------- -----------
@ -244,19 +250,24 @@ Bugs:
History: History:
-------- --------
satip-axe-2018 - ?? satip-axe-201810211549-15 - Sun Oct 21 2018
- moved the releases (firmware files) to github
- added minisatip8 - added minisatip8
- theaded mode is turned on by default (use -T to toggle)
- updated minisatip code (latest minisatip 0.7.16) - updated minisatip code (latest minisatip 0.7.16)
- note that some options were removed (-M) or added (-2) - note that some options were removed (-M) or added (-2)
- follow /etc/config.default and this file - follow /etc/config.default and this file
- fixed reported VDR problem (issue #108) - fixed reported VDR problems (issue #108)
- added DVB-S2 multistream support
- fixed the improper tuner release problem for complex diseqc settings - fixed the improper tuner release problem for complex diseqc settings
where one input is used by multiple tuners (minisatip7 and minisatip8) where one input is used by multiple tuners (minisatip7 and minisatip8)
- added SYSLOGD_OPTS to pass extra options to syslog - added SYSLOGD_OPTS to pass extra options to syslog
- modified net.ipv4.tcp_wmem (issue #102) - modified net.ipv4.tcp_wmem (issue #102)
- increased net.core.wmem_max=12582912 , it might help to prevent - increased net.core.wmem_max=12582912 , it might help to prevent
the UDP packet loss (issue #88) the UDP packet loss (issue #88)
- fixed time sync (ntpd) issue when DHCP is used (issue #109) - partly fixed time sync (ntpd) issue when DHCP is used (issue #109)
- upgraded python to 3.5.6 (package)
- upgraded oscam to rev.11434
satip-axe-201705251044-14 - Wed Jun 7 2017 satip-axe-201705251044-14 - Wed Jun 7 2017
- kernel modules from idl4k-1.25.0.157 (frontend + demux) - kernel modules from idl4k-1.25.0.157 (frontend + demux)

2
dist/minisatip.md vendored
View File

@ -11,7 +11,7 @@ NOTE: Some options identifiers were changed between minisatip5 and minisatip7:
minisatip7,8 | minisatip5/minisatip | description minisatip7,8 | minisatip5/minisatip | description
-------------|----------------------|----------------------------------- -------------|----------------------|-----------------------------------
-7 | -L | tuner linking -7 | -L | tuner linking
-9 | -X | unicable input (-S for minisatip8) -9 | -X | unicable input
-W | -P | AXE power -W | -P | AXE power
-8 | -Z | quattro hiband mode -8 | -Z | quattro hiband mode

BIN
dist/packages/Python-3.5.6-1.tar.gz vendored Normal file

Binary file not shown.

BIN
dist/packages/multicast-rtp-2.tar.gz vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
dist/satip-axe-201810211549-15.usb vendored Normal file

Binary file not shown.

View File

@ -1,11 +1,12 @@
#!/bin/sh #!/bin/sh
FILE="$1" FILE="$1"
DOWNLOAD=""
MTDDEV="/dev/mtd3" MTDDEV="/dev/mtd3"
SAFEFILE="/root/new.fw" SAFEFILE="/root/new.fw"
CHECKSTR="Linux-2.6.32.42_stm24_0208-idl4k" CHECKSTR="Linux-2.6.32.42_stm24_0208-idl4k"
GITHUB1="https://github.com/perexg/satip-axe/tree/master/dist"
GITHUB2="https://github.com/perexg/satip-axe/blob/master/dist/$FILE?raw=true" GITHUB1="https://api.github.com/repos/perexg/satip-axe/releases"
if test "$PWD" != "/root" -a "$PWD" != "/"; then if test "$PWD" != "/root" -a "$PWD" != "/"; then
echo "Run this utility from / or /root directory" echo "Run this utility from / or /root directory"
@ -17,23 +18,65 @@ if test "$FILE" = "-h" -o "$FILE" = "--help"; then
exit 1 exit 1
fi fi
if test -z "$FILE"; then if ! test -r "$FILE"; then
echo "Trying to fetch the list of available firmware files:" if test -z "$FILE"; then
if ! wget -q -O /root/list.txt "$GITHUB1"; then echo "Trying to fetch the list of available firmware files:"
else
echo "Trying to fetch the URL for the firmware:"
fi
if ! wget -q -O /root/list.json "$GITHUB1"; then
echo "FAILED" echo "FAILED"
exit 1 exit 1
fi fi
grep -o -E ">satip-axe-.*.fw<" /root/list.txt | grep -o -E "satip-axe.*.fw" cat /root/list.json | grep -E '("name"|"browser_download_url")' | \
rm /root/list.txt grep -v -E '"name":.*.tgz' | \
exit 0 while IFS="\n" read line
do
case "$line" in
\ *\"name\":*)
name=$(echo "$line" | cut -d '"' -f 4)
;;
\ *\"browser_download_url\":*)
fw=$(echo "$line" | cut -d '/' -f 9 | cut -d '"' -f 1 | cut -d '.' -f 1)
fw="$fw.fw"
if test -z "$FILE"; then
printf "%-40s : %s\n" "$name" "$fw"
else
if test "$FILE" = "$fw"; then
f=$(echo "$line" | cut -d '"' -f 4)
echo "$f" > /root/url.txt
printf " %s\n" "$f"
fi
fi
name=''
;;
esac
done
rm /root/list.json
if test -z "$FILE"; then
exit 0
fi
if test -r /root/url.txt; then
DOWNLOAD=$(cat /root/url.txt)
fi
fi fi
if ! test -r "$FILE"; then if test -n "$DOWNLOAD"; then
echo "Downloading $FILE:" echo "Downloading $FILE from $DOWNLOAD to $SAFEFILE:"
if ! wget -O "$SAFEFILE" "$GITHUB2/$FILE"; then if ! wget -O - "$DOWNLOAD" | tar xOzf - "$FILE" > "$SAFEFILE"; then
echo "Unable to fetch firmware file $GITHUB2" echo "Unable to fetch firmware file $DOWNLOAD / $FILE"
exit 1 exit 1
fi fi
if ! test -r "$SAFEFILE"; then
echo "Unable to fetch firmware file $DOWNLOAD / $FILE"
exit 1
fi
FILESIZE=$(stat -c "%s" "$SAFEFILE")
if test -z "$FILESIZE" -o $FILESIZE -le 0; then
echo "Download failed (wrong file size)!"
else
echo "Downloaded firmware $FILE (file $SAFEFILE size $FILESIZE bytes)..."
fi
FILE="$SAFEFILE" FILE="$SAFEFILE"
fi fi
@ -69,7 +112,7 @@ while test 1 -eq 1; do
nanddump -f "$SAFEFILE.old" -l "$FILESIZE" "$MTDDEV" nanddump -f "$SAFEFILE.old" -l "$FILESIZE" "$MTDDEV"
FILESIZE2=$(stat -c "%s" "$SAFEFILE.old") FILESIZE2=$(stat -c "%s" "$SAFEFILE.old")
if test "$FILESIZE" -gt "$FILESIZE2"; then if test "$FILESIZE" -gt "$FILESIZE2"; then
echo "Unable to verify (file sizes does not match - $FILESIZE > $FILESIZE2" echo "Unable to verify (file sizes does not match - $FILESIZE > $FILESIZE2)"
exit 1 exit 1
fi fi
if ! dd if=/dev/null seek="$FILESIZE" bs=1 of="$SAFEFILE.old" 2> /dev/null; then if ! dd if=/dev/null seek="$FILESIZE" bs=1 of="$SAFEFILE.old" 2> /dev/null; then
@ -78,7 +121,7 @@ while test 1 -eq 1; do
fi fi
FILESIZE2=$(stat -c "%s" "$SAFEFILE.old") FILESIZE2=$(stat -c "%s" "$SAFEFILE.old")
if test "$FILESIZE" != "$FILESIZE2"; then if test "$FILESIZE" != "$FILESIZE2"; then
echo "Unable to verify (file sizes does not match - $FILESIZE != $FILESIZE2" echo "Unable to verify (file sizes does not match - $FILESIZE != $FILESIZE2)"
exit 1 exit 1
fi fi
result=$(diff "$SAFEFILE.old" "$SAFEFILE") result=$(diff "$SAFEFILE.old" "$SAFEFILE")

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
--- Makefile.orig 2017-05-03 16:45:40.962475569 +0200 --- Makefile.orig 2018-09-25 11:01:33.853198226 +0200
+++ Makefile 2017-05-03 16:48:52.644079190 +0200 +++ Makefile 2018-09-25 11:07:57.416371544 +0200
@@ -618,7 +618,7 @@ @@ -587,7 +587,7 @@
*) quiet="";; \ *) quiet="";; \
esac; \ esac; \
$(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' OPT='$(OPT)' \ $(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' OPT='$(OPT)' \
@ -9,7 +9,7 @@
$(PYTHON_FOR_BUILD) $(srcdir)/setup.py $$quiet build $(PYTHON_FOR_BUILD) $(srcdir)/setup.py $$quiet build
# Build static library # Build static library
@@ -728,17 +728,19 @@ @@ -697,6 +697,8 @@
############################################################################ ############################################################################
# Importlib # Importlib
@ -18,30 +18,35 @@
Programs/_freeze_importlib.o: Programs/_freeze_importlib.c Makefile Programs/_freeze_importlib.o: Programs/_freeze_importlib.c Makefile
Programs/_freeze_importlib: Programs/_freeze_importlib.o $(LIBRARY_OBJS_OMIT_FROZEN) Programs/_freeze_importlib: Programs/_freeze_importlib.o $(LIBRARY_OBJS_OMIT_FROZEN)
$(LINKCC) $(PY_LDFLAGS) -o $@ Programs/_freeze_importlib.o $(LIBRARY_OBJS_OMIT_FROZEN) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST) @@ -706,12 +708,12 @@
regen-importlib: Programs/_freeze_importlib
Python/importlib_external.h: # $(srcdir)/Lib/importlib/_bootstrap_external.py Programs/_freeze_importlib # Regenerate Python/importlib_external.h
# from Lib/importlib/_bootstrap_external.py using _freeze_importlib
- ./Programs/_freeze_importlib \ - ./Programs/_freeze_importlib \
+ $(FREEZE_IMPORTLIB) \ + $(FREEZE_IMPORTLIB) \
$(srcdir)/Lib/importlib/_bootstrap_external.py Python/importlib_external.h $(srcdir)/Lib/importlib/_bootstrap_external.py \
$(srcdir)/Python/importlib_external.h
Python/importlib.h: # $(srcdir)/Lib/importlib/_bootstrap.py Programs/_freeze_importlib # Regenerate Python/importlib.h from Lib/importlib/_bootstrap.py
# using _freeze_importlib
- ./Programs/_freeze_importlib \ - ./Programs/_freeze_importlib \
+ $(FREEZE_IMPORTLIB) \ + $(FREEZE_IMPORTLIB) \
$(srcdir)/Lib/importlib/_bootstrap.py Python/importlib.h $(srcdir)/Lib/importlib/_bootstrap.py \
$(srcdir)/Python/importlib.h
@@ -778,11 +780,8 @@
@@ -805,9 +807,6 @@ $(IO_OBJS): $(IO_H)
$(GRAMMAR_C): # $(GRAMMAR_H)
touch $(GRAMMAR_C)
-$(PGEN): $(PGENOBJS) -$(PGEN): $(PGENOBJS)
- $(CC) $(OPT) $(PY_LDFLAGS) $(PGENOBJS) $(LIBS) -o $(PGEN) - $(CC) $(OPT) $(PY_LDFLAGS) $(PGENOBJS) $(LIBS) -o $(PGEN)
- -
Parser/grammar.o: $(srcdir)/Parser/grammar.c \ .PHONY: regen-grammar
$(srcdir)/Include/token.h \ -regen-grammar: $(PGEN)
$(srcdir)/Include/grammar.h +regen-grammar:
@@ -1620,7 +1619,7 @@ # Regenerate Include/graminit.h and Python/graminit.c
# from Grammar/Grammar using pgen
@$(MKDIR_P) Include
@@ -1625,7 +1624,7 @@
rm -rf $(COVERAGE_REPORT) rm -rf $(COVERAGE_REPORT)
clobber: clean profile-removal clobber: clean profile-removal

View File

@ -14,6 +14,8 @@
#define STV6120_1 (0xc0 >> 1) #define STV6120_1 (0xc0 >> 1)
#define STV6120_2 (0xc6 >> 1) #define STV6120_2 (0xc6 >> 1)
#define STV0900_1 (0xd0 >> 1)
#define STV0900_2 (0xd2 >> 1)
extern int (*i2c_transfer_mangle)(struct i2c_adapter *adap, struct i2c_msg *msg, int num); extern int (*i2c_transfer_mangle)(struct i2c_adapter *adap, struct i2c_msg *msg, int num);
int i2c_transfer2(struct i2c_adapter *adap, struct i2c_msg *msg, int num); int i2c_transfer2(struct i2c_adapter *adap, struct i2c_msg *msg, int num);
@ -22,17 +24,34 @@ static struct i2c_adapter *i2c_adapter0;
static int i2c_mangle_enable = 1; static int i2c_mangle_enable = 1;
static int i2c_mangle_debug = 0; static int i2c_mangle_debug = 0;
static int stv6120_gain = 8; static int stv6120_gain = 8;
static int stv0900_mis[4] = { -1, -1, -1, -1 };
static int stv0900_pls[4] = { 1, 1, 1, 1 }; /* ROOT code 1 is equal to GOLD code 0 */
static void i2c_transfer_axe_dump(struct i2c_msg *msgs, int num) static void i2c_transfer_axe_dump(struct i2c_msg *msgs, int num)
{ {
struct i2c_msg *m;
int ret; int ret;
u8 *b;
for (ret = 0; ret < num; ret++) { for (ret = 0; ret < num; ret++) {
m = msgs + ret;
b = m->buf;
printk("i2c master_xfer[%d] %c, addr=0x%02x, " printk("i2c master_xfer[%d] %c, addr=0x%02x, "
"len=%d%s, flags=0x%x\n", ret, (msgs[ret].flags & I2C_M_RD) "len=%d%s, flags=0x%04x, "
? 'R' : 'W', msgs[ret].addr, msgs[ret].len, "data[%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x]\n",
(msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "", ret,
msgs[ret].flags); (m->flags & I2C_M_RD) ? 'R' : 'W',
m->addr, m->len,
(m->flags & I2C_M_RECV_LEN) ? "+" : "",
m->flags,
m->len > 0 ? b[0] : 0,
m->len > 1 ? b[1] : 0,
m->len > 2 ? b[2] : 0,
m->len > 3 ? b[3] : 0,
m->len > 4 ? b[4] : 0,
m->len > 5 ? b[5] : 0,
m->len > 6 ? b[6] : 0,
m->len > 7 ? b[7] : 0);
} }
} }
@ -48,7 +67,60 @@ static void mangle(u8 *dst, struct i2c_msg *m, int i, int val, int shift, int ma
m->buf = dst; m->buf = dst;
} }
static void i2c_transfer_axe_mangle(struct i2c_msg *msgs, int num) #define REG_SET3(b1, b2, b3) \
do { buf[num][0] = b1; buf[num][1] = b2; buf[num][2] = b3; num++; } while (0)
static void demod_set_pls_and_mis(struct i2c_adapter *adap, struct i2c_msg *src, int p)
{
struct i2c_msg m[6];
u8 buf[6][3];
int num = 0, r, mis, idx = p ? 1 : 0;
u32 pls;
u8 iaddr = p ? 0xf3 : 0xf5;
switch (src->addr) {
case STV0900_1: idx += 0; break;
case STV0900_2: idx += 2; break;
default: return;
}
mis = stv0900_mis[idx];
if (mis >= 0 && mis <= 255) {
/* PDELCTRL1 - enable filter */
REG_SET3(iaddr, 0x50, 0x20);
/* ISIENTRY */
REG_SET3(iaddr, 0x5e, mis);
/* ISIBITENA */
REG_SET3(iaddr, 0x5f, 0xff);
} else {
/* SWRST */
REG_SET3(iaddr, 0x72, 0xd1);
/* PDELCTRL1 - disable filter */
REG_SET3(iaddr, 0x50, 0x00);
}
/* set PLS code and mode (upper three bits) */
pls = stv0900_pls[idx];
REG_SET3(iaddr-1, 0xae, pls); /* PLROOT0 */
REG_SET3(iaddr-1, 0xad, pls >> 8); /* PLROOT1 */
REG_SET3(iaddr-1, 0xac, (pls >> 16) & 0x0f); /* PLROOT3 */
if (i2c_mangle_debug & 4)
printk("i2c idx=%d: pls=%d mode=%d mis=%d\n", idx,
pls & 0x3ffff, (pls >> 18) & 3, mis);
for (r = 0; r < num; r++) {
m[r] = *src;
m[r].len = 3;
m[r].buf = buf[r];
}
if (i2c_mangle_debug & 1)
i2c_transfer_axe_dump(m, num);
r = i2c_transfer2(adap, m, num);
if (r < 0)
printk("i2c mangle demod pls and mis error! (%d)\n", r);
}
static void i2c_transfer_axe_mangle(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{ {
static u8 mbuf[4][32]; static u8 mbuf[4][32];
struct i2c_msg *m; struct i2c_msg *m;
@ -58,20 +130,27 @@ static void i2c_transfer_axe_mangle(struct i2c_msg *msgs, int num)
m = msgs + ret; m = msgs + ret;
if (m->len < 1 || (m->flags & I2C_M_RD) != 0) if (m->len < 1 || (m->flags & I2C_M_RD) != 0)
continue; continue;
if (m->addr == STV6120_1 || m->addr == STV6120_2) if (m->addr == STV6120_1 || m->addr == STV6120_2) {
for (r = m->buf[0], i = 1; i < m->len; i++, r++) for (r = m->buf[0], i = 1; i < m->len; i++, r++)
if (r == 0x01 || r == 0x0b) if (r == 0x01 || r == 0x0b)
mangle(mbuf[ret], m, i, stv6120_gain, 0, 0x0f); mangle(mbuf[ret], m, i, stv6120_gain, 0, 0x0f);
} else if (m->addr == STV0900_1 || m->addr == STV0900_2) {
/* inject pls/mis settings before TSCFGH path merger reset */
if (m->flags == 0 && m->len == 3 &&
(m->buf[0] == 0xf3 || m->buf[0] == 0xf5) &&
m->buf[1] == 0x72 && m->buf[2] == 0xd1)
demod_set_pls_and_mis(adap, m, m->buf[0] == 0xf3);
}
} }
} }
static int i2c_transfer_axe(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) static int i2c_transfer_axe(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{ {
if (adap == i2c_adapter0) { if (adap == i2c_adapter0) {
if (i2c_mangle_enable)
i2c_transfer_axe_mangle(adap, msgs, num);
if (i2c_mangle_debug & 1) if (i2c_mangle_debug & 1)
i2c_transfer_axe_dump(msgs, num); i2c_transfer_axe_dump(msgs, num);
if (i2c_mangle_enable)
i2c_transfer_axe_mangle(msgs, num);
} }
return i2c_transfer2(adap, msgs, num); return i2c_transfer2(adap, msgs, num);
} }
@ -140,6 +219,166 @@ static DEVICE_ATTR(stv6120_gain, 0644,
stv6120_gain_show, stv6120_gain_show,
stv6120_gain_store); stv6120_gain_store);
static ssize_t stv0900_mis1_show
(struct device *dev, struct device_attribute *attr, char *page)
{
return sprintf(page, "%i\n", stv0900_mis[0]);
}
static ssize_t stv0900_mis1_store
(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int val = 0;
if (sscanf(buf, "%i", &val) != 1)
return -EINVAL;
stv0900_mis[0] = val;
return count;
}
static DEVICE_ATTR(stv0900_mis1, 0644,
stv0900_mis1_show,
stv0900_mis1_store);
static ssize_t stv0900_mis2_show
(struct device *dev, struct device_attribute *attr, char *page)
{
return sprintf(page, "%i\n", stv0900_mis[1]);
}
static ssize_t stv0900_mis2_store
(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int val = 0;
if (sscanf(buf, "%i", &val) != 1)
return -EINVAL;
stv0900_mis[1] = val;
return count;
}
static DEVICE_ATTR(stv0900_mis2, 0644,
stv0900_mis2_show,
stv0900_mis2_store);
static ssize_t stv0900_mis3_show
(struct device *dev, struct device_attribute *attr, char *page)
{
return sprintf(page, "%i\n", stv0900_mis[2]);
}
static ssize_t stv0900_mis3_store
(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int val = 0;
if (sscanf(buf, "%i", &val) != 1)
return -EINVAL;
stv0900_mis[2] = val;
return count;
}
static DEVICE_ATTR(stv0900_mis3, 0644,
stv0900_mis3_show,
stv0900_mis3_store);
static ssize_t stv0900_mis4_show
(struct device *dev, struct device_attribute *attr, char *page)
{
return sprintf(page, "%i\n", stv0900_mis[3]);
}
static ssize_t stv0900_mis4_store
(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int val = 0;
if (sscanf(buf, "%i", &val) != 1)
return -EINVAL;
stv0900_mis[3] = val;
return count;
}
static DEVICE_ATTR(stv0900_mis4, 0644,
stv0900_mis4_show,
stv0900_mis4_store);
static ssize_t stv0900_pls1_show
(struct device *dev, struct device_attribute *attr, char *page)
{
return sprintf(page, "%i\n", stv0900_pls[0]);
}
static ssize_t stv0900_pls1_store
(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int val = 0;
if (sscanf(buf, "%i", &val) != 1)
return -EINVAL;
stv0900_pls[0] = val;
return count;
}
static DEVICE_ATTR(stv0900_pls1, 0644,
stv0900_pls1_show,
stv0900_pls1_store);
static ssize_t stv0900_pls2_show
(struct device *dev, struct device_attribute *attr, char *page)
{
return sprintf(page, "%i\n", stv0900_pls[1]);
}
static ssize_t stv0900_pls2_store
(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int val = 0;
if (sscanf(buf, "%i", &val) != 1)
return -EINVAL;
stv0900_pls[1] = val;
return count;
}
static DEVICE_ATTR(stv0900_pls2, 0644,
stv0900_pls2_show,
stv0900_pls2_store);
static ssize_t stv0900_pls3_show
(struct device *dev, struct device_attribute *attr, char *page)
{
return sprintf(page, "%i\n", stv0900_pls[2]);
}
static ssize_t stv0900_pls3_store
(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int val = 0;
if (sscanf(buf, "%i", &val) != 1)
return -EINVAL;
stv0900_pls[2] = val;
return count;
}
static DEVICE_ATTR(stv0900_pls3, 0644,
stv0900_pls3_show,
stv0900_pls3_store);
static ssize_t stv0900_pls4_show
(struct device *dev, struct device_attribute *attr, char *page)
{
return sprintf(page, "%i\n", stv0900_pls[3]);
}
static ssize_t stv0900_pls4_store
(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int val = 0;
if (sscanf(buf, "%i", &val) != 1)
return -EINVAL;
stv0900_pls[3] = val;
return count;
}
static DEVICE_ATTR(stv0900_pls4, 0644,
stv0900_pls4_show,
stv0900_pls4_store);
static void sysfs_create_entries(void) static void sysfs_create_entries(void)
{ {
struct kobject *kobj = &i2c_adapter0->dev.kobj; struct kobject *kobj = &i2c_adapter0->dev.kobj;
@ -147,6 +386,14 @@ static void sysfs_create_entries(void)
sysfs_create_file(kobj, &dev_attr_i2c_mangle_enable.attr); sysfs_create_file(kobj, &dev_attr_i2c_mangle_enable.attr);
sysfs_create_file(kobj, &dev_attr_i2c_mangle_debug.attr); sysfs_create_file(kobj, &dev_attr_i2c_mangle_debug.attr);
sysfs_create_file(kobj, &dev_attr_stv6120_gain.attr); sysfs_create_file(kobj, &dev_attr_stv6120_gain.attr);
sysfs_create_file(kobj, &dev_attr_stv0900_mis1.attr);
sysfs_create_file(kobj, &dev_attr_stv0900_mis2.attr);
sysfs_create_file(kobj, &dev_attr_stv0900_mis3.attr);
sysfs_create_file(kobj, &dev_attr_stv0900_mis4.attr);
sysfs_create_file(kobj, &dev_attr_stv0900_pls1.attr);
sysfs_create_file(kobj, &dev_attr_stv0900_pls2.attr);
sysfs_create_file(kobj, &dev_attr_stv0900_pls3.attr);
sysfs_create_file(kobj, &dev_attr_stv0900_pls4.attr);
} }
static void sysfs_remove_entries(void) static void sysfs_remove_entries(void)
@ -156,6 +403,14 @@ static void sysfs_remove_entries(void)
sysfs_remove_file(kobj, &dev_attr_i2c_mangle_enable.attr); sysfs_remove_file(kobj, &dev_attr_i2c_mangle_enable.attr);
sysfs_remove_file(kobj, &dev_attr_i2c_mangle_debug.attr); sysfs_remove_file(kobj, &dev_attr_i2c_mangle_debug.attr);
sysfs_remove_file(kobj, &dev_attr_stv6120_gain.attr); sysfs_remove_file(kobj, &dev_attr_stv6120_gain.attr);
sysfs_remove_file(kobj, &dev_attr_stv0900_mis1.attr);
sysfs_remove_file(kobj, &dev_attr_stv0900_mis2.attr);
sysfs_remove_file(kobj, &dev_attr_stv0900_mis3.attr);
sysfs_remove_file(kobj, &dev_attr_stv0900_mis4.attr);
sysfs_remove_file(kobj, &dev_attr_stv0900_pls1.attr);
sysfs_remove_file(kobj, &dev_attr_stv0900_pls2.attr);
sysfs_remove_file(kobj, &dev_attr_stv0900_pls3.attr);
sysfs_remove_file(kobj, &dev_attr_stv0900_pls4.attr);
} }
/* /*

View File

@ -2,6 +2,7 @@
# #
# Tiny SAT>IP client which activates multicast streaming. # Tiny SAT>IP client which activates multicast streaming.
# #
# Use command line parameters of
# Create /etc/sysconfig/multicast file with syntax: # Create /etc/sysconfig/multicast file with syntax:
# #
# <mport>:<satip-params> # <mport>:<satip-params>
@ -9,12 +10,12 @@
# You can modify this file when the program is active and # You can modify this file when the program is active and
# reload the configuration using the SIGHUP signal. # reload the configuration using the SIGHUP signal.
# #
# Example: # Configuration Example:
# #
# # Channel 1 on multicast port 5554, using first tuner (fe=1) # # Channel 1 on multicast port 5554, using first orbital position
# 5554:fe=1&src=1&freq=12525&sr=27500&\ # 5554:src=1&freq=11347&pol=v&ro=0.35&msys=dvbs2&\
# msys=dvbs&mtype=qpsk&pol=v&fec=34&\ # mtype=8psk&plts=on&sr=22000&fec=23&\
# pids=0,1,16,17,18,52,57,100,104,165,299,1029,3002,3003 # pids=0,17,18,6600,6610,6620,6630
# #
# The SAT>IP parameters should match the SAT>IP specification: # The SAT>IP parameters should match the SAT>IP specification:
# http://www.satip.info/resources # http://www.satip.info/resources
@ -23,27 +24,100 @@
# option -r <ipv4_mcast> or --remote-rtp <ipv4_mcast>. By default, # option -r <ipv4_mcast> or --remote-rtp <ipv4_mcast>. By default,
# this address is 239.255.255.250. # this address is 239.255.255.250.
# #
# Command-line example:
#
# ./multicast-rtp \
# -s 192.168.1.100:554 -d 239.0.0.1 -p 5554 \
# -u "src=1&freq=11347&pol=v&ro=0.35&msys=dvbs2&mtype=8psk&plts=on&sr=22000&fec=23&pids=0,17,18,6600,6610,6620,6630"
#
# Note: The SAT>IP server needs to support "target" spoofing
# and multicast address as "unicast" (minisatip project does it)
#
import os import os
import signal import signal
import functools import functools
import asyncio import asyncio
import syslog import syslog
import argparse,sys
import signal
VERSION='0.1' VERSION='0.2'
SYSLOG=False
SERVER='127.0.0.1:554' SERVER='127.0.0.1:554'
CONFIG='/etc/sysconfig/multicast' CONFIG=''
SYSLOG=True REQUEST=''
if not os.path.exists('/etc/init.d/axe-settings'): TARGET_ADDR=''
SERVER='gssbox1:554' TARGET_PORT=0
CONFIG='multicast' USE_CONFIG=True
SYSLOG=False QUIET=False
#
# Command line parameters
#
parser = argparse.ArgumentParser(description='Request multicast streaming from a SAT>IP server.')
parser.add_argument('-q', '--quiet', dest='quiet',
action='store_true',
help='quiet display option')
parser.add_argument('-l', '--syslog', dest='syslog',
action='store_true',
help='enable System LOG')
parser.add_argument('-s', '--server', dest='server',
required=True,
help='server to connect')
parser.add_argument('-d', '--destination', dest='addr',
default='',
help='target address (Note: Only if server accept it!)')
parser.add_argument('-p', '--port', dest='port', type=int,
default=10000,
help='target port (default: 10000)')
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('-u', '--uri', dest='uri',
default='',
help='URI to request')
group.add_argument('-c', '--config', dest='config',
default='/etc/sysconfig/multicast',
help='config file with static multicast streams (default: /etc/sysconfig/multicast)')
args = parser.parse_args()
SYSLOG = args.syslog
if args.port > 0 and args.port < 65536 :
TARGET_PORT = args.port
else :
parser.print_help()
sys.exit()
if len(args.server) > 0 :
SERVER = args.server
else :
parser.print_help()
sys.exit()
if len(args.uri) > 0 :
REQUEST = args.uri
elif len(args.config) > 0 :
CONFIG = args.config
else :
parser.print_help()
sys.exit()
TARGET_ADDR = args.addr
QUIET = args.quiet
if len(REQUEST) > 0 :
USE_CONFIG = False
# #
# #
# #
def log(msg): def log(msg):
if QUIET :
return
if SYSLOG: if SYSLOG:
syslog.syslog(msg) syslog.syslog(msg)
else: else:
@ -80,14 +154,19 @@ class RTSP_Protocol:
s = 'rtsp://%s:%d/?%s' % (peer[0], peer[1], self.params) s = 'rtsp://%s:%d/?%s' % (peer[0], peer[1], self.params)
log('%d (open): %s' % (self.mport, s)) log('%d (open): %s' % (self.mport, s))
msg = 'SETUP ' + s + ' RTSP/1.0\r\n' msg = 'SETUP ' + s + ' RTSP/1.0\r\n'
msg += 'Transport: RTP/AVP;multicast;port=%d-%d\r\n' % (self.mport, self.mport + 1) if len(REQUEST) > 0 :
msg += 'Transport: RTP/AVP;unicast;destination=%s;client_port=%d-%d\r\n' % (TARGET_ADDR, self.mport, self.mport + 1)
else :
msg += 'Transport: RTP/AVP;multicast;port=%d-%d\r\n' % (self.mport, self.mport + 1)
msg += 'CSeq: 1\r\n\r\n' msg += 'CSeq: 1\r\n\r\n'
log(' -----> : %s' % msg)
transport.write(msg.encode()) transport.write(msg.encode())
self.action = 'PLAY' self.action = 'PLAY'
def data_received(self, data): def data_received(self, data):
if not self.transport: if not self.transport:
return return
log(' <----- : %s' % data)
lines = data.decode("utf-8").splitlines() lines = data.decode("utf-8").splitlines()
if lines[0] != 'RTSP/1.0 200 OK': if lines[0] != 'RTSP/1.0 200 OK':
return self.retry() return self.retry()
@ -131,6 +210,10 @@ class RTSP_Protocol:
self.cseq = 2 self.cseq = 2
elif self.action == 'OPTIONS' and self.cseq == 2: elif self.action == 'OPTIONS' and self.cseq == 2:
log('%d (play): OK' % self.mport) log('%d (play): OK' % self.mport)
elif self.action == 'TEARDOWN':
log('%d (close): OK' % self.mport)
self.retry()
return
def options(self): def options(self):
if not self.transport: if not self.transport:
@ -144,6 +227,19 @@ class RTSP_Protocol:
self.transport.write(msg.encode()) self.transport.write(msg.encode())
self.client.loop.call_at(loop.time() + self.timeout/2, self.options) self.client.loop.call_at(loop.time() + self.timeout/2, self.options)
def teardown(self):
self.action = 'TEARDOWN'
if not self.transport:
return
peer = self.transport._sock.getpeername()
log('%d (teardown): Session %s, streamID %d' % (self.mport, self.session, self.streamID))
self.cseq += 1
msg = 'TEARDOWN rtsp://%s:%d/stream=%d RTSP/1.0\r\n' % (peer[0], peer[1], self.streamID)
msg += 'Session: %s\r\n' % self.session
msg += 'CSeq: %d\r\n\r\n' % self.cseq
self.transport.write(msg.encode())
self.client.loop.call_at(loop.time() + 1, self.retry)
def eof_received(self): def eof_received(self):
self.connection_lost(None) self.connection_lost(None)
@ -159,7 +255,7 @@ class RTSP_Protocol:
def fatal(self): def fatal(self):
if self.transport: if self.transport:
self.transport.close() self.teardown()
self.client.protocol = None self.client.protocol = None
self.client.fatal() self.client.fatal()
@ -195,7 +291,7 @@ class RTSP_Client:
log("Remove multicast client: %s" % self.params) log("Remove multicast client: %s" % self.params)
self.dead = True self.dead = True
if self.protocol: if self.protocol:
self.protocol.fatal() self.protocol.teardown()
self.clients.remove_client(self) self.clients.remove_client(self)
# #
@ -207,8 +303,12 @@ class RTSP_Clients:
def __init__(self, loop): def __init__(self, loop):
self.loop = loop self.loop = loop
self.clients = [] self.clients = []
self.parse_config_file() if USE_CONFIG :
hupfcn = lambda: self.parse_config_file() self.parse_config_file()
hupfcn = lambda: self.parse_config_file()
else :
self.parse_request()
hupfcn = lambda: self.parse_request()
loop.add_signal_handler(signal.SIGHUP, loop.add_signal_handler(signal.SIGHUP,
functools.partial(hupfcn)) functools.partial(hupfcn))
@ -224,6 +324,23 @@ class RTSP_Clients:
return return
self.clients.append(RTSP_Client(self, params)) self.clients.append(RTSP_Client(self, params))
async def close_all(self):
for c in self.clients:
c.fatal()
def parse_request(self):
# mark clients
for c in self.clients:
c.deleteme = True
# parse command line
l = str(TARGET_PORT) + ':' + REQUEST
#print("parse_request: " + l)
self.add_client(l)
# remove marked clients
for c in self.clients:
if c.deleteme:
self.remove_client(c)
def parse_config_file(self): def parse_config_file(self):
# mark clients # mark clients
for c in self.clients: for c in self.clients:
@ -251,17 +368,43 @@ class RTSP_Clients:
self.remove_client(c) self.remove_client(c)
# #
# configuration file # configuration
# #
if SYSLOG: if SYSLOG:
syslog.openlog('multicast-rtp', 0, syslog.LOG_LOCAL7) syslog.openlog('multicast-rtp', 0, syslog.LOG_LOCAL7)
silent = QUIET
if QUIET :
QUIET = False
log('Version %s' % VERSION) log('Version %s' % VERSION)
log('SERVER: %s' % SERVER)
log('CONFIG: %s' % CONFIG)
log('TARGET: %s:%d' % (TARGET_ADDR, TARGET_PORT))
log('REQUEST: %s' % REQUEST)
log('------------')
if silent :
log(' Start.')
QUIET = True
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
loop.add_signal_handler(signal.SIGTERM, signal.getsignal(signal.SIGINT))
clients = RTSP_Clients(loop) clients = RTSP_Clients(loop)
try: try:
loop.run_forever() loop.run_forever()
except (KeyboardInterrupt, SystemExit) as e:
## Send TEARDOWN before exit!
log(' Closing.')
loop.run_until_complete(clients.close_all())
loop.run_until_complete(asyncio.sleep(1.0))
except:
print('*******')
finally: finally:
QUIET = False
log(' Stop.')
loop.close() loop.close()
if SYSLOG: if SYSLOG:
syslog.closelog() syslog.closelog()
sys.exit(0)