From 4eaf27c75499bc3f79c261adba531937c57a5d0a Mon Sep 17 00:00:00 2001 From: JHCD Date: Sun, 28 Jun 2015 22:28:21 +0200 Subject: [PATCH] implemtation of new doubleAlarm-Filter You can set the number of historical entries the filter will check and the time ignoring the id in case of a double alarm --- config/config.template.ini | 15 +-- includes/decoders/fms.py | 147 ++++++++++----------- includes/decoders/poc.py | 262 ++++++++++++++++++------------------- includes/decoders/zvei.py | 167 +++++++++++------------ includes/globals.py | 12 +- 5 files changed, 287 insertions(+), 316 deletions(-) diff --git a/config/config.template.ini b/config/config.template.ini index 6162d51..7f354fd 100644 --- a/config/config.template.ini +++ b/config/config.template.ini @@ -25,26 +25,25 @@ useRegExFilter = 0 # You have to be enabled it for every typ in the sections below too useDescription = 0 -[FMS] -# time to ignore same alarm in a row (sek) +# for double check save the last n IDs +# it is used in combination with double_ignore_time +# 1 is required if you want to use the double alarm filter +double_ignore_entries = 10 + +#time to ignore same alarm (only ID is checked) (sek) double_ignore_time = 5 +[FMS] # look-up-table for adding a description # turn on functionality (0|1) idDescribed = 0 [ZVEI] -# time to ignore same alarm in a row (sek) -double_ignore_time = 5 - # look-up-table for adding a description # turn on functionality (0|1) idDescribed = 0 [POC] -# time to ignore same alarm in a row (sek) -double_ignore_time = 5 - # some very simple filters: # Allow only this RICs (empty: allow all, separator ",") # f.e.: allow_ric = 1234566,1234567,1234568 diff --git a/includes/decoders/fms.py b/includes/decoders/fms.py index ee0329f..17c2453 100644 --- a/includes/decoders/fms.py +++ b/includes/decoders/fms.py @@ -1,78 +1,71 @@ -#!/usr/bin/python -# -*- coding: cp1252 -*- - -""" -FMS Decoder - -@author: Bastian Schroll - -@requires: Configuration has to be set in the config.ini -""" - -import logging # Global logger -import time # timestamp for doublealarm -import re # Regex for validation - -from includes import globals # Global variables - -## -# -# FMS decoder function -# validate -> check double alarm -> log -# -def decode(freq, decoded): - """ - Export FMS Information from Multimon-NG RAW String and call alarmHandler.processAlarm() - - @type freq: string - @param freq: frequency of the SDR Stick - @type decoded: string - @param decoded: RAW Information from Multimon-NG - - @requires: Configuration has to be set in the config.ini - - @return: nothing - @exception: Exception if FMS decode failed - """ - timestamp = int(time.time()) # Get Timestamp - - fms_service = decoded[19] # Organisation - fms_country = decoded[36] # Bundesland - fms_location = decoded[65:67] # Ort - fms_vehicle = decoded[72:76] # Fahrzeug - fms_status = decoded[84] # Status - fms_direction = decoded[101] # Richtung - fms_directionText = decoded[103:110] # Richtung (Text) - fms_tsi = decoded[114:117] # Taktische Kruzinformation - - if "CRC correct" in decoded: #check CRC is correct - fms_id = fms_service+fms_country+fms_location+fms_vehicle+fms_status+fms_direction # build FMS id - # if FMS is valid - if re.search("[0-9a-f]{8}[0-9a-f]{1}[01]{1}", fms_id): - # check for double alarm - if fms_id == globals.fms_id_old and timestamp < globals.fms_time_old + globals.config.getint("FMS", "double_ignore_time"): - logging.info("FMS double alarm: %s within %s second(s)", globals.fms_id_old, timestamp-globals.fms_time_old) - # in case of double alarm, fms_double_ignore_time set new - globals.fms_time_old = timestamp - else: - logging.info("FMS:%s Status:%s Richtung:%s TSI:%s", fms_id[0:8], fms_status, fms_direction, fms_tsi) - data = {"fms":fms_id[0:8], "status":fms_status, "direction":fms_direction, "directionText":fms_directionText, "tsi":fms_tsi, "description":fms_id[0:8]} - # If enabled, look up description - if globals.config.getint("FMS", "idDescribed"): - from includes import descriptionList - data["description"] = descriptionList.getDescription("FMS", fms_id[0:8]) - # processing the alarm - try: - from includes import alarmHandler - alarmHandler.processAlarm("POC",freq,data) - except: - logging.error("processing alarm failed") - logging.debug("processing alarm failed", exc_info=True) - pass - # in every time save old data for double alarm - globals.fms_id_old = fms_id #save last id - globals.fms_time_old = timestamp #save last time - else: - logging.warning("No valid FMS: %s", fms_id) - else: +#!/usr/bin/python +# -*- coding: cp1252 -*- + +""" +FMS Decoder + +@author: Bastian Schroll + +@requires: Configuration has to be set in the config.ini +""" + +import logging # Global logger +import re # Regex for validation + +from includes import globals # Global variables +from includes import doubleFilter # double alarm filter + +## +# +# FMS decoder function +# validate -> check double alarm -> log +# +def decode(freq, decoded): + """ + Export FMS Information from Multimon-NG RAW String and call alarmHandler.processAlarm() + + @type freq: string + @param freq: frequency of the SDR Stick + @type decoded: string + @param decoded: RAW Information from Multimon-NG + + @requires: Configuration has to be set in the config.ini + + @return: nothing + @exception: Exception if FMS decode failed + """ + fms_service = decoded[19] # Organisation + fms_country = decoded[36] # Bundesland + fms_location = decoded[65:67] # Ort + fms_vehicle = decoded[72:76] # Fahrzeug + fms_status = decoded[84] # Status + fms_direction = decoded[101] # Richtung + fms_directionText = decoded[103:110] # Richtung (Text) + fms_tsi = decoded[114:117] # Taktische Kruzinformation + + if "CRC correct" in decoded: #check CRC is correct + fms_id = fms_service+fms_country+fms_location+fms_vehicle+fms_status+fms_direction # build FMS id + # if FMS is valid + if re.search("[0-9a-f]{8}[0-9a-f]{1}[01]{1}", fms_id): + # check for double alarm + if doubleFilter.checkID("FMS", fms_id): + logging.info("FMS:%s Status:%s Richtung:%s TSI:%s", fms_id[0:8], fms_status, fms_direction, fms_tsi) + data = {"fms":fms_id[0:8], "status":fms_status, "direction":fms_direction, "directionText":fms_directionText, "tsi":fms_tsi, "description":fms_id[0:8]} + # If enabled, look up description + if globals.config.getint("FMS", "idDescribed"): + from includes import descriptionList + data["description"] = descriptionList.getDescription("FMS", fms_id[0:8]) + # processing the alarm + try: + from includes import alarmHandler + alarmHandler.processAlarm("FMS", freq, data) + except: + logging.error("processing alarm failed") + logging.debug("processing alarm failed", exc_info=True) + pass + # in every time save old data for double alarm + doubleFilter.newEntry(fms_id) + else: + logging.warning("No valid FMS: %s", fms_id) + else: logging.warning("FMS CRC incorrect") \ No newline at end of file diff --git a/includes/decoders/poc.py b/includes/decoders/poc.py index b0ab005..c8dee0d 100644 --- a/includes/decoders/poc.py +++ b/includes/decoders/poc.py @@ -1,135 +1,129 @@ -#!/usr/bin/python -# -*- coding: cp1252 -*- - -""" -POCSAG Decoder - -@author: Bastian Schroll -@author: Jens Herrmann - -@requires: Configuration has to be set in the config.ini -""" - -import logging # Global logger -import time # timestamp for doublealarm -import re # Regex for validation - -from includes import globals # Global variables - -## -# -# Simple local filter -# -def isAllowed(poc_id): - """ - Simple Filter Functions (Allowed, Denied and Range) - - @type poc_id: string - @param poc_id: POCSAG Ric - - @requires: Configuration has to be set in the config.ini - - @return: True if the Ric is allowed, other False - @exception: none - """ - # 1.) If allowed RICs is set, only they will path, - # If RIC is the right one return True, else False - if globals.config.get("POC", "allow_ric"): - if poc_id in globals.config.get("POC", "allow_ric"): - logging.info("RIC %s is allowed", poc_id) - return True - else: - logging.info("RIC %s is not in the allowed list", poc_id) - return False - # 2.) If denied RIC, return False - elif poc_id in globals.config.get("POC", "deny_ric"): - logging.info("RIC %s is denied by config.ini", poc_id) - return False - # 3.) Check Range, return False if outside def. range - elif int(poc_id) < globals.config.getint("POC", "filter_range_start"): - logging.info("RIC %s out of filter range (start)", poc_id) - return False - elif int(poc_id) > globals.config.getint("POC", "filter_range_end"): - logging.info("RIC %s out of filter range (end)", poc_id) - return False - return True - -## -# -# POCSAG decoder function -# validate -> check double alarm -> log -# -def decode(freq, decoded): - """ - Export POCSAG Information from Multimon-NG RAW String and call alarmHandler.processAlarm() - - @type freq: string - @param freq: frequency of the SDR Stick - @type decoded: string - @param decoded: RAW Information from Multimon-NG - - @requires: Configuration has to be set in the config.ini - - @return: nothing - @exception: Exception if POCSAG decode failed - """ - bitrate = 0 - timestamp = int(time.time())#Get Timestamp - - if "POCSAG512:" in decoded: - bitrate = 512 - poc_id = decoded[20:27].replace(" ", "").zfill(7) - poc_sub = decoded[39].replace("3", "4").replace("2", "3").replace("1", "2").replace("0", "1") - - elif "POCSAG1200:" in decoded: - bitrate = 1200 - poc_id = decoded[21:28].replace(" ", "").zfill(7) - poc_sub = decoded[40].replace("3", "4").replace("2", "3").replace("1", "2").replace("0", "1") - - elif "POCSAG2400:" in decoded: - bitrate = 2400 - poc_id = decoded[21:28].replace(" ", "").zfill(7) - poc_sub = decoded[40].replace("3", "4").replace("2", "3").replace("1", "2").replace("0", "1") - - if bitrate is 0: - logging.warning("POCSAG Bitrate not found") - logging.debug(" - (%s)", decoded) - else: - logging.debug("POCSAG Bitrate: %s", bitrate) - - if "Alpha:" in decoded: #check if there is a text message - poc_text = decoded.split('Alpha: ')[1].strip().rstrip('').strip() - else: - poc_text = "" - - if re.search("[0-9]{7}", poc_id): #if POC is valid - if isAllowed(poc_id): - # check for double alarm - if poc_id == globals.poc_id_old and timestamp < globals.poc_time_old + globals.config.getint("POC", "double_ignore_time"): - logging.info("POCSAG%s double alarm: %s within %s second(s)", bitrate, globals.poc_id_old, timestamp-globals.poc_time_old) - # in case of double alarm, poc_double_ignore_time set new - globals.poc_time_old = timestamp - else: - logging.info("POCSAG%s: %s %s %s ", bitrate, poc_id, poc_sub, poc_text) - data = {"ric":poc_id, "function":poc_sub, "msg":poc_text, "bitrate":bitrate, "description":poc_id} - # Add function as character a-d to dataset - data["functionChar"] = data["function"].replace("1", "a").replace("2", "b").replace("3", "c").replace("4", "d") - # If enabled, look up description - if globals.config.getint("POC", "idDescribed"): - from includes import descriptionList - data["description"] = descriptionList.getDescription("POC", poc_id) - # processing the alarm - try: - from includes import alarmHandler - alarmHandler.processAlarm("POC",freq,data) - except: - logging.error("processing alarm failed") - logging.debug("processing alarm failed", exc_info=True) - pass - # in every time save old data for double alarm - globals.poc_id_old = poc_id #save last id - globals.poc_time_old = timestamp #save last time - else: - logging.debug("POCSAG%s: %s is not allowed", bitrate, poc_id) - else: +#!/usr/bin/python +# -*- coding: cp1252 -*- + +""" +POCSAG Decoder + +@author: Bastian Schroll +@author: Jens Herrmann + +@requires: Configuration has to be set in the config.ini +""" + +import logging # Global logger +import re # Regex for validation + +from includes import globals # Global variables +from includes import doubleFilter # double alarm filter + +## +# +# Simple local filter +# +def isAllowed(poc_id): + """ + Simple Filter Functions (Allowed, Denied and Range) + + @type poc_id: string + @param poc_id: POCSAG Ric + + @requires: Configuration has to be set in the config.ini + + @return: True if the Ric is allowed, other False + @exception: none + """ + # 1.) If allowed RICs is set, only they will path, + # If RIC is the right one return True, else False + if globals.config.get("POC", "allow_ric"): + if poc_id in globals.config.get("POC", "allow_ric"): + logging.info("RIC %s is allowed", poc_id) + return True + else: + logging.info("RIC %s is not in the allowed list", poc_id) + return False + # 2.) If denied RIC, return False + elif poc_id in globals.config.get("POC", "deny_ric"): + logging.info("RIC %s is denied by config.ini", poc_id) + return False + # 3.) Check Range, return False if outside def. range + elif int(poc_id) < globals.config.getint("POC", "filter_range_start"): + logging.info("RIC %s out of filter range (start)", poc_id) + return False + elif int(poc_id) > globals.config.getint("POC", "filter_range_end"): + logging.info("RIC %s out of filter range (end)", poc_id) + return False + return True + +## +# +# POCSAG decoder function +# validate -> check double alarm -> log +# +def decode(freq, decoded): + """ + Export POCSAG Information from Multimon-NG RAW String and call alarmHandler.processAlarm() + + @type freq: string + @param freq: frequency of the SDR Stick + @type decoded: string + @param decoded: RAW Information from Multimon-NG + + @requires: Configuration has to be set in the config.ini + + @return: nothing + @exception: Exception if POCSAG decode failed + """ + bitrate = 0 + + if "POCSAG512:" in decoded: + bitrate = 512 + poc_id = decoded[20:27].replace(" ", "").zfill(7) + poc_sub = decoded[39].replace("3", "4").replace("2", "3").replace("1", "2").replace("0", "1") + + elif "POCSAG1200:" in decoded: + bitrate = 1200 + poc_id = decoded[21:28].replace(" ", "").zfill(7) + poc_sub = decoded[40].replace("3", "4").replace("2", "3").replace("1", "2").replace("0", "1") + + elif "POCSAG2400:" in decoded: + bitrate = 2400 + poc_id = decoded[21:28].replace(" ", "").zfill(7) + poc_sub = decoded[40].replace("3", "4").replace("2", "3").replace("1", "2").replace("0", "1") + + if bitrate is 0: + logging.warning("POCSAG Bitrate not found") + logging.debug(" - (%s)", decoded) + else: + logging.debug("POCSAG Bitrate: %s", bitrate) + + if "Alpha:" in decoded: #check if there is a text message + poc_text = decoded.split('Alpha: ')[1].strip().rstrip('').strip() + else: + poc_text = "" + + if re.search("[0-9]{7}", poc_id): #if POC is valid + if isAllowed(poc_id): + # check for double alarm + if doubleFilter.checkID("POC", poc_id): + logging.info("POCSAG%s: %s %s %s ", bitrate, poc_id, poc_sub, poc_text) + data = {"ric":poc_id, "function":poc_sub, "msg":poc_text, "bitrate":bitrate, "description":poc_id} + # Add function as character a-d to dataset + data["functionChar"] = data["function"].replace("1", "a").replace("2", "b").replace("3", "c").replace("4", "d") + # If enabled, look up description + if globals.config.getint("POC", "idDescribed"): + from includes import descriptionList + data["description"] = descriptionList.getDescription("POC", poc_id) + # processing the alarm + try: + from includes import alarmHandler + alarmHandler.processAlarm("POC", freq, data) + except: + logging.error("processing alarm failed") + logging.debug("processing alarm failed", exc_info=True) + pass + # in every time save old data for double alarm + doubleFilter.newEntry(poc_id) + else: + logging.debug("POCSAG%s: %s is not allowed", bitrate, poc_id) + else: logging.warning("No valid POCSAG%s RIC: %s", bitrate, poc_id) \ No newline at end of file diff --git a/includes/decoders/zvei.py b/includes/decoders/zvei.py index ca4dea4..39afcbf 100644 --- a/includes/decoders/zvei.py +++ b/includes/decoders/zvei.py @@ -1,88 +1,81 @@ -#!/usr/bin/python -# -*- coding: cp1252 -*- - -""" -ZVEI Decoder - -@author: Bastian Schroll - -@requires: Configuration has to be set in the config.ini -""" - -import logging # Global logger -import time # timestamp for doublealarm -import re # Regex for validation - -from includes import globals # Global variables - -## -# -# Local function to remove the 'F' -# -def removeF(zvei): - """ - Resolve the F from the repeat Tone - - @type zvei: string - @param zvei: ZVEI Information - - @return: ZVEI without F - @exception: none - """ - if "F" in zvei: - zvei_old = zvei - for i in range(1, 5): - if zvei[i] == "F": - zvei = zvei.replace("F",zvei[i-1],1) - logging.debug("resolve F: %s -> %s", zvei_old, zvei) - return zvei - -## -# -# ZVEI decoder function -# validate -> check double alarm -> log -# -def decode(freq, decoded): - """ - Export ZVEI Information from Multimon-NG RAW String and call alarmHandler.processAlarm() - - @type freq: string - @param freq: frequency of the SDR Stick - @type decoded: string - @param decoded: RAW Information from Multimon-NG - - @requires: Configuration has to be set in the config.ini - - @return: nothing - @exception: Exception if ZVEI decode failed - """ - timestamp = int(time.time()) # Get Timestamp - - zvei_id = decoded[7:12] # ZVEI Code - zvei_id = removeF(zvei_id) # resolve F - if re.search("[0-9]{5}", zvei_id): # if ZVEI is valid - # check for double alarm - if zvei_id == globals.zvei_id_old and timestamp < globals.zvei_time_old + globals.config.getint("ZVEI", "double_ignore_time"): - logging.info("ZVEI double alarm: %s within %s second(s)", globals.zvei_id_old, timestamp-globals.zvei_time_old) - # in case of double alarm, zvei_double_ignore_time set new - globals.zvei_time_old = timestamp - else: - logging.info("5-Ton: %s", zvei_id) - data = {"zvei":zvei_id, "description":zvei_id} - # If enabled, look up description - if globals.config.getint("ZVEI", "idDescribed"): - from includes import descriptionList - data["description"] = descriptionList.getDescription("ZVEI", zvei_id) - # processing the alarm - try: - from includes import alarmHandler - alarmHandler.processAlarm("POC",freq,data) - except: - logging.error("processing alarm failed") - logging.debug("processing alarm failed", exc_info=True) - pass - # in every time save old data for double alarm - globals.zvei_id_old = zvei_id # save last id - globals.zvei_time_old = timestamp # save last time - else: +#!/usr/bin/python +# -*- coding: cp1252 -*- + +""" +ZVEI Decoder + +@author: Bastian Schroll + +@requires: Configuration has to be set in the config.ini +""" + +import logging # Global logger +import re # Regex for validation + +from includes import globals # Global variables +from includes import doubleFilter # double alarm filter + +## +# +# Local function to remove the 'F' +# +def removeF(zvei): + """ + Resolve the F from the repeat Tone + + @type zvei: string + @param zvei: ZVEI Information + + @return: ZVEI without F + @exception: none + """ + if "F" in zvei: + zvei_old = zvei + for i in range(1, 5): + if zvei[i] == "F": + zvei = zvei.replace("F",zvei[i-1],1) + logging.debug("resolve F: %s -> %s", zvei_old, zvei) + return zvei + +## +# +# ZVEI decoder function +# validate -> check double alarm -> log +# +def decode(freq, decoded): + """ + Export ZVEI Information from Multimon-NG RAW String and call alarmHandler.processAlarm() + + @type freq: string + @param freq: frequency of the SDR Stick + @type decoded: string + @param decoded: RAW Information from Multimon-NG + + @requires: Configuration has to be set in the config.ini + + @return: nothing + @exception: Exception if ZVEI decode failed + """ + zvei_id = decoded[7:12] # ZVEI Code + zvei_id = removeF(zvei_id) # resolve F + if re.search("[0-9]{5}", zvei_id): # if ZVEI is valid + # check for double alarm + if doubleFilter.checkID("ZVEI", zvei_id): + logging.info("5-Ton: %s", zvei_id) + data = {"zvei":zvei_id, "description":zvei_id} + # If enabled, look up description + if globals.config.getint("ZVEI", "idDescribed"): + from includes import descriptionList + data["description"] = descriptionList.getDescription("ZVEI", zvei_id) + # processing the alarm + try: + from includes import alarmHandler + alarmHandler.processAlarm("ZVEI", freq, data) + except: + logging.error("processing alarm failed") + logging.debug("processing alarm failed", exc_info=True) + pass + # in every time save old data for double alarm + doubleFilter.newEntry(zvei_id) + else: logging.warning("No valid ZVEI: %s", zvei_id) \ No newline at end of file diff --git a/includes/globals.py b/includes/globals.py index 1e5750a..f4ab2d8 100644 --- a/includes/globals.py +++ b/includes/globals.py @@ -14,14 +14,7 @@ script_path = "" log_path = "" # double alarm -fms_id_old = 0 -fms_time_old = 0 - -zvei_id_old = 0 -zvei_time_old = 0 - -poc_id_old = 0 -poc_time_old = 0 +doubleList = [] # pluginLoader pluginList = {} @@ -32,5 +25,4 @@ filterList = [] # idDescribing fmsDescribtionList = {} zveiDescribtionList = {} -ricDescribtionList = {} - +ricDescribtionList = {} \ No newline at end of file