new file mode 100644
@@ -0,0 +1,8 @@
+all:
+ @echo Nothing to be made.
+
+clean:
+ rm -f *~ *.o *.d
+
+install:
+ @echo Nothing to be made.
new file mode 100644
@@ -0,0 +1,83 @@
+#ifndef DFS_H
+#define DFS_H
+/*
+ * Copyright 2011, Neratec Solutions AG, <zefir.kurtisi@neratec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/**
+ * DOC: Introduction
+ *
+ * DFS radar detector interface
+ *
+ * This is a proposal for a common DFS pattern detector interface.
+ *
+ * It should be used by devices that are able to detect radar pulses and need
+ * pattern matching (as defined by ETSI, FCC, JP regulatories).
+ *
+ */
+
+#include <stdint.h>
+
+/* TODO: move those to more common place */
+enum dfs_domain {
+ DFS_FCC_DOMAIN = 1, /* FCC dfs domain */
+ DFS_ETSI_DOMAIN = 2, /* ETSI dfs domain */
+ DFS_JP_DOMAIN = 3, /* Japan dfs domain */
+};
+
+/**
+ * struct pulse_event - events fed to the dfs handler
+ *
+ * @ts: absolute time stamp for start of pulse in [us] (e.g. as TSF)
+ * @freq: channel frequency in [MHz]
+ * @width: pulse width in [us]
+ *
+ */
+struct pulse_event {
+ uint64_t ts;
+ uint16_t freq;
+ uint8_t width;
+};
+
+
+/**
+ * struct dfs_handler - DFS handler pseudo-OO interface
+ *
+ * @exit: terminate DFS handler and release all resources
+ * @add_pulse: add given pulse event to detector lines
+ * returns 1 if added event triggered a pattern match
+ * @data: private instance data
+ *
+ */
+struct dfs_handler {
+ /* VFT */
+ void (*exit)(struct dfs_handler *_this);
+ int (*add_pulse)(struct dfs_handler *_this, struct pulse_event *event);
+
+ /* private data */
+ struct dfs_data *data;
+};
+
+/**
+ * dfs_handler_init - DFS handler constructor
+ *
+ * @dfs_domain: DFS domain to detect radar patterns for
+ *
+ * A DFS handler instance is allocated via this constructor.
+ * On success the pointer to the fully initialized handler is returned that
+ * can be fed with radar pulses during its lifetime. Allocated resources are
+ * released upon calling the destructor.
+ *
+ * On failure NULL is returned.
+ */
+struct dfs_handler *dfs_handler_init(enum dfs_domain dfs_domain);
+
+/* only one global DFS handler instance enough for proof-of-concept */
+extern struct dfs_handler *global_dfs_handler;
+
+
+#endif /* DFS_H */
new file mode 100644
@@ -0,0 +1,15 @@
+#include "dfs_debug.h"
+
+#define USE_FULL_DEBUG 0
+
+uint32_t dfs_debug_level = 0
+ | DFS_DEBUG_ERROR
+ | DFS_DEBUG_WARN
+ | DFS_DEBUG_INFO
+#if USE_FULL_DEBUG
+ | DFS_DEBUG_TRACE
+ | DFS_DEBUG_LOG
+#endif
+;
+
+char dbg_buff[MAX_DEBUG_SPRINTF + 1] = {0};
new file mode 100644
@@ -0,0 +1,110 @@
+#ifndef DFS_DEBUG_H
+#define DFS_DEBUG_H
+
+#include <stdint.h>
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+
+#define DFS_DPRINTK(LEVEL, FMT, ...) \
+do { \
+ if ((LEVEL) & dfs_debug_level) \
+ printk(FMT, ##__VA_ARGS__); \
+} while (0)
+
+#define ASSERT(expr) \
+if (unlikely(!(expr))) { \
+ panic(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \
+ #expr, __SHORT_FILE__, __func__, __LINE__); \
+}
+#else
+#include <string.h>
+#include <stdio.h>
+
+#define DFS_DPRINTK(LEVEL, FMT, ...) \
+do { \
+ if ((LEVEL) & dfs_debug_level) \
+ printf(FMT, ##__VA_ARGS__); \
+} while (0)
+
+#define ASSERT(expr) \
+do { \
+ if (!(expr)) { \
+ printf("Assertion failed! %s,%s,%s,line=%d\n", \
+ #expr, __SHORT_FILE__, __func__, __LINE__); \
+ } \
+} while (0)
+
+#endif
+
+enum {
+ DFS_DEBUG_ERROR = 0x000100,
+ DFS_DEBUG_WARN = 0x000200,
+ DFS_DEBUG_INFO = 0x000400,
+ DFS_DEBUG_TRACE = 0x000800,
+ DFS_DEBUG_LOG = 0x001000,
+};
+
+extern uint32_t dfs_debug_level;
+#define MAX_DEBUG_SPRINTF 511
+extern char dbg_buff[MAX_DEBUG_SPRINTF + 1];
+
+#define __SHORT_FILE__ \
+ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
+
+
+
+#define DTRACE(...) \
+do { \
+ DFS_DPRINTK(DFS_DEBUG_TRACE, "TRACE: %s\n", __func__); \
+} while (0)
+
+#define DLOG(FMT, ...) \
+do { \
+ snprintf(dbg_buff, MAX_DEBUG_SPRINTF, "LOG: %s\n", FMT); \
+ DFS_DPRINTK(DFS_DEBUG_LOG, dbg_buff, ##__VA_ARGS__); \
+} while (0)
+
+#define DINFO(FMT, ...) \
+do { \
+ snprintf(dbg_buff, MAX_DEBUG_SPRINTF, "INFO: %s\n", FMT); \
+ DFS_DPRINTK(DFS_DEBUG_INFO, dbg_buff, ##__VA_ARGS__); \
+} while (0)
+
+#define DWARN(FMT, ...) \
+do { \
+ snprintf(dbg_buff, MAX_DEBUG_SPRINTF, \
+ "WARN: %s: %s\n", __func__, FMT); \
+ DFS_DPRINTK(DFS_DEBUG_WARN, dbg_buff, ##__VA_ARGS__); \
+} while (0)
+
+#define DERROR(FMT, ...) \
+do { \
+ snprintf(dbg_buff, MAX_DEBUG_SPRINTF, \
+ "WARN: %s: %s\n", __func__, FMT); \
+ DFS_DPRINTK(DFS_DEBUG_ERROR, dbg_buff, ##__VA_ARGS__); \
+} while (0)
+
+#define DFATAL(FMT, ...) \
+do { \
+ snprintf(dbg_buff, MAX_DEBUG_SPRINTF, \
+ "FATAL: %s: %s\n", __func__, FMT); \
+ DFS_DPRINTK(DFS_DEBUG_ERROR, dbg_buff, ##__VA_ARGS__); \
+} while (0)
+
+
+#define DINIT(FMT, ...) \
+do { \
+ snprintf(dbg_buff, MAX_DEBUG_SPRINTF, \
+ "INIT: %s: %s\n", __func__, FMT); \
+ DFS_DPRINTK(DFS_DEBUG_ERROR, dbg_buff, ##__VA_ARGS__); \
+} while (0)
+
+#define DINFO_OK(FMT, ...) \
+do { \
+ snprintf(dbg_buff, MAX_DEBUG_SPRINTF, "OK: %s: %s\n", __func__, FMT); \
+ DFS_DPRINTK(DFS_DEBUG_INFO, dbg_buff, ##__VA_ARGS__); \
+} while (0)
+
+
+#endif /* DFS_DEBUG_H */
new file mode 100644
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2011, Neratec Solutions AG, <zefir.kurtisi@neratec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdlib.h>
+
+#include "dfs.h"
+#include "dfs_debug.h"
+#include "dfs_pattern_detector.h"
+
+
+/**
+ * struct dfs_data - DFS handler private data
+ *
+ * @dfs_handler: instance back-reference
+ * @dfs_domain: DFS domain the handler is currently working
+ * @pattern_detector: instance reference to pattern detector
+ */
+struct dfs_data {
+ struct dfs_handler *dfs_handler;
+ enum dfs_domain dfs_domain;
+ struct dfs_pattern_detector *pattern_detector;
+};
+
+
+
+/* Destructor */
+static void dh_exit(struct dfs_handler *_this)
+{
+ ASSERT(_this != NULL);
+
+ if (_this->data != NULL) {
+ struct dfs_data *dfs_data = _this->data;
+ if (dfs_data->pattern_detector != NULL)
+ dfs_data->pattern_detector->
+ exit(dfs_data->pattern_detector);
+ free(dfs_data);
+ _this->data = NULL;
+ }
+ free(_this);
+}
+
+static int dh_add_pulse(struct dfs_handler *_this, struct pulse_event *event)
+{
+ int detector_result;
+ struct dfs_data *dfs_data;
+ DTRACE();
+ ASSERT((_this != NULL) && (_this->data != NULL));
+
+ dfs_data = _this->data;
+ detector_result = dfs_data->pattern_detector->
+ add_pulse(dfs_data->pattern_detector, event);
+ if (detector_result == RADAR_DETECTED) {
+ DINIT("found radar");
+ return 1;
+ }
+ return 0;
+}
+
+static struct dfs_handler default_dfs_handler = {
+ .exit = dh_exit,
+ .add_pulse = dh_add_pulse,
+};
+
+/* Constructor */
+struct dfs_handler *dfs_handler_init(enum dfs_domain dfs_domain)
+{
+ struct dfs_handler *_this;
+ struct dfs_data *dfs_data;
+ int sz = sizeof(struct dfs_handler);
+ _this = malloc(sz);
+
+ if (_this == NULL) {
+ DFATAL("dfs_handler allocation failed");
+ return NULL;
+ }
+
+ *_this = default_dfs_handler;
+
+
+ sz = sizeof(struct dfs_data);
+ dfs_data = malloc(sz);
+ if (dfs_data == NULL) {
+ DFATAL("dfs_data allocation failed");
+ goto failed;
+ }
+
+ memset(dfs_data, 0, sz);
+
+ _this->data = dfs_data;
+ dfs_data->pattern_detector = dfs_pattern_detector_init(dfs_domain);
+ if (dfs_data->pattern_detector == NULL) {
+ DFATAL("detector_init() failed!");
+ goto failed;
+ }
+ _this->data->dfs_domain = dfs_domain;
+ _this->data->dfs_handler = _this;
+
+ DINIT("ok");
+ return _this;
+
+failed:
+ _this->exit(_this);
+ return NULL;
+}
new file mode 100644
@@ -0,0 +1,568 @@
+/*
+ * Copyright 2011, Neratec Solutions AG, <zefir.kurtisi@neratec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdlib.h>
+
+#include "dfs_pattern_detector.h"
+#include "dfs_debug.h"
+#include "dfs.h"
+
+#include "dfs_radar_types.h"
+
+
+/*
+ * Abbreviations used (based on regulatory specs):
+ * * prf: pulse repetition frequency [Hz]
+ * * pri: pulse repetition interval = 1/prf, here used as [us]
+ * * ppb: pulses per burst
+ */
+
+
+#define DELTA(X, Y) ((X < Y) ? (Y-X) : (X-Y))
+
+/* number of deviation of radar time in usecs tolerated on both sides
+ * TODO: this might need to be HW-dependent
+ */
+#define MAX_PRI_TOLERANCE 10
+
+
+/**
+ * struct radar_specs - specifies a radar pattern type
+ *
+ * @type_id: pattern type, as defined by ETSI / FCC
+ * @width_min: minimum radar pulse width in [us]
+ * @width_max: maximum radar pulse width in [us]
+ * @pri_min: minimum pulse repetition interval in [us] (including tolerance)
+ * @pri_max: minimum pri in [us] (including tolerance)
+ * @num_pri: maximum number of different pri for this type
+ * @ppb: pulses per bursts for this type
+ * @ppb_thresh: number of pulses required to trigger detection
+ * @max_dur: absolute max duration of pattern: num_pri * pri_max * ppb
+ *
+ * Characteristics of each radar pattern type are calculated at initialization
+ * based on radar test signal types defined by the chosen regulatory.
+ * They remain unchanged thereafter.
+ */
+struct radar_specs {
+ unsigned int type_id;
+ unsigned int width_min;
+ unsigned int width_max;
+ unsigned int pri_min;
+ unsigned int pri_max;
+ unsigned int num_pri;
+ unsigned int ppb;
+ unsigned int ppb_thresh;
+ unsigned int max_dur;
+};
+
+
+/* so far, maximum prf number is 3 for ETSI types 5 and 6 */
+#define MAX_PRF_NUM 3
+
+/**
+ * struct radar_stats - detector statistics updated on each pulse
+ *
+ * @pri_count: number of pri used for this pattern type so far
+ * @pri: array of pris in use
+ * @matching_pulse_count: number of pulses detected correctly so far
+ * @missed_pulse_count: number of pulses assumed as lost so far
+ * @false_pulse_count: number of invalid / false pulses so far
+ * @first_ts: timestamp of first valid pulse for this type
+ * @last_ts: timestamp of last valid pulse for this type
+ *
+ * The statistics reflect the current state of the related detector line.
+ *
+ * Detection is performed in place updating the affected detector lines
+ * whenever a pulse is added. The algorithm operates without keeping track
+ * of the pulse history but requires only the statistics collected so far.
+ *
+ * Statistical decisions are made based on the numbers for matching,
+ * missed, and false pulses count.
+ */
+struct radar_stats {
+ uint32_t pri_count;
+ uint32_t pri[MAX_PRF_NUM];
+ uint32_t matching_pulse_count;
+ uint32_t missed_pulse_count;
+ uint32_t false_pulse_count;
+ uint64_t first_ts;
+ uint64_t last_ts;
+};
+
+/**
+ * struct dfs_channels - DFS channels' frequencies, assumed constant
+ */
+static const uint16_t dfs_channels[] = {
+ 5260, 5280, 5300, 5320,
+ 5500, 5520, 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680, 5700,
+};
+#define NUM_DFS_CHANNELS (sizeof(dfs_channels)/sizeof(dfs_channels[0]))
+
+
+/**
+ * struct detector_line - detector line for one specific dfs pattern type
+ *
+ * @specs: dfs pattern type specification
+ * @stats: array of statistics for for all DFS channels
+ *
+ * Each detector line consists of a constant radar type specification and
+ * an array of statistics for all DFS channels.
+ */
+struct detector_line {
+ struct radar_specs specs;
+ struct radar_stats stats[NUM_DFS_CHANNELS];
+};
+
+
+/**
+ * struct pattern_detector_data - private instance data
+ *
+ * @num_detector_elements: number of different radar types
+ * @radar_detectors: array of num_detector_elements detector lines
+ * @min_valid_width: combined min of valid pulse widths
+ * @max_valid_width: combined max of valid pulse widths
+ * @min_valid_pri: combined min of valid pris
+ * @max_valid_pri: combined max of valid pris
+ * @max_radar_dur: combined max duration of radar patterns
+ * @first_pulse_ts: timestamp of first pulse after detector reset
+ * @last_pulse_ts: timestamp of last valid pulse
+ * @last_pulse_rssi: rssi of last pulse
+ *
+ * For global range checking dfs_pattern_detector instances are initialized
+ * with a pre-calculated set of global limits that combine the limits of
+ * all detector lines.
+ */
+struct pattern_detector_data {
+ uint32_t num_detector_elements;
+ struct detector_line *radar_detectors;
+ uint32_t min_valid_width;
+ uint32_t max_valid_width;
+ uint32_t min_valid_pri;
+ uint32_t max_valid_pri;
+ uint32_t max_radar_dur;
+ uint64_t first_pulse_ts;
+ uint64_t last_pulse_ts;
+ uint32_t last_pulse_rssi;
+};
+
+/**
+ * get_dfs_channel_idx - (private) find DFS channel index for given frequency
+ *
+ * @freq: frequency to search for
+ *
+ * Returns -1 if not found.
+ */
+static int get_dfs_channel_idx(uint16_t freq)
+{
+ int i;
+ for (i = 0; i < NUM_DFS_CHANNELS; i++)
+ if (dfs_channels[i] == freq)
+ return i;
+ return -1;
+}
+
+/**
+ * reset_detector_element - (private) reset one detector element
+ *
+ * @rs: radar statistics to reset
+ * @ts: time stamp to be reset to
+ *
+ * Resets the statistics for one pattern type of one channel. Sets the
+ * timestamp for the last valid pulse to given value.
+ */
+static void reset_detector_element(struct radar_stats *rs, uint64_t ts)
+{
+ memset(rs, 0, sizeof(struct radar_stats));
+ rs->last_ts = ts;
+}
+
+
+/**
+ * detector_reset - (private) reset all detector lines for a given channel
+ *
+ * @pd_data: instance data ptr
+ * @dfs_channel_idx: DFS channel index to be reset
+ *
+ * Resets the statistics for all pattern types of one given channel.
+ */
+static void detector_reset(struct pattern_detector_data *pd_data,
+ int dfs_channel_idx)
+{
+ int i;
+ uint64_t ts = pd_data->last_pulse_ts;
+ DTRACE();
+ for (i = 0; i < pd_data->num_detector_elements; i++) {
+ struct radar_stats *rs;
+ rs = &pd_data->radar_detectors[i].stats[dfs_channel_idx];
+ reset_detector_element(rs, ts);
+ }
+}
+
+
+/**
+ * check_pulse_lost - (private) check potentially lost pulses
+ *
+ * @rs: radar stats to be checked
+ * @delta_ts: pulse interval to be checked
+ *
+ * In case we missed some pulse '.' in a row of valid pulses '|', we try to
+ * reconstruct them by checking for delta_ts being a multiple of the pri.
+ *
+ * Assume we were fed with a pattern like
+ * | | . . |
+ * Evaluating the last pulse we check if the last interval is a multiple of our
+ * pri and in that case return 2 as the number of (potentially) lost pulses.
+ *
+ * The global check if the last interval exceeds the max duration of this
+ * pattern type is performed by the caller.
+ *
+ */
+static int check_pulse_lost(struct radar_stats *rs, uint32_t delta_ts)
+{
+ int lost_pulses = 0;
+
+ if (rs->pri_count == 1) {
+ /* check constant pri patterns */
+ uint32_t pri = rs->pri[0];
+ while (delta_ts > pri) {
+ /* we already checked that we are within valid duration
+ * => won't loop too long */
+ lost_pulses++;
+ delta_ts -= pri;
+ }
+
+ if (DELTA(pri, delta_ts) <= MAX_PRI_TOLERANCE)
+ return lost_pulses;
+
+ return 0;
+ } else {
+ /* TODO: check staggered radar patterns
+ here we need to support
+ * single burst / packet based and
+ * single burst / single pulse
+ staggered PRF radar test signals
+ */
+ }
+ return 0;
+}
+
+/**
+ * detector_check_match - (private) check for pattern match
+ *
+ * @rp: radar specs to be checked
+ * @rs: radar stats to be checked
+ * @delta_ts: pulse interval to be checked
+ *
+ * Returns 1 on match
+ */
+static int detector_check_match(struct radar_specs *rp, struct radar_stats *rs)
+{
+
+ if (rs->matching_pulse_count >= rp->ppb_thresh) {
+ DINIT("XXXXXXXXXXXXXXXXXXXXXXX MATCH on type %d", rp->type_id);
+ return 1;
+ }
+ return 0;
+}
+
+static int detector_check_pri(struct radar_specs *rp, struct radar_stats *rs,
+ uint32_t delta_ts)
+{
+ int lost_pulses;
+
+ int pri_num;
+ DLOG("OK: delta_ts=%d <= max_dur[%d]=%d",
+ delta_ts, rp->type_id, rp->max_dur);
+ for (pri_num = 0; pri_num < rs->pri_count; pri_num++) {
+ if (DELTA(delta_ts, rs->pri[pri_num]) < MAX_PRI_TOLERANCE) {
+ rs->matching_pulse_count++;
+ DLOG("delta_ts=%d matches pri_num[%d][%d] => "
+ "matching_pulse_count = %d", delta_ts,
+ rp->type_id, pri_num, rs->matching_pulse_count);
+ if (detector_check_match(rp, rs))
+ return 1;
+ /* we only take the first match */
+ return 0;
+ }
+ lost_pulses = check_pulse_lost(rs, delta_ts);
+ if (lost_pulses > 0) {
+ rs->matching_pulse_count += lost_pulses + 1;
+ DLOG("[%d] assuming %d lost pulses => "
+ "matching_pulse_count = %d",
+ rp->type_id, lost_pulses,
+ rs->matching_pulse_count);
+ if (detector_check_match(rp, rs))
+ return 1;
+ return 0;
+ }
+ DLOG("delta_ts=%d not multiple of [%d] = %d",
+ delta_ts, rp->type_id, rs->pri[0]);
+ reset_detector_element(rs, rs->last_ts);
+ return 0;
+
+ }
+ if (rs->pri_count >= rp->num_pri) {
+ rs->false_pulse_count++;
+ } else {
+ /* pri was not found in the current array, add it as new */
+ rs->pri[rs->pri_count++] = delta_ts;
+ rs->matching_pulse_count += 2;
+ DLOG("added new pri[%d][%d]=%d",
+ rp->type_id, rs->pri_count-1, delta_ts);
+ }
+ return 0;
+}
+
+static int detector_check_pulse_ts(struct radar_specs *rp,
+ struct radar_stats *rs, uint64_t ts)
+{
+ uint32_t delta_ts;
+
+ DTRACE();
+ delta_ts = ts - rs->last_ts;
+ DLOG("[%d]: ts=%llu, last_ts=%llu, delta_ts=%d, pri_min=%d, pri_max=%d,"
+ "max_dur=%d", rp->type_id, ts, rs->last_ts, delta_ts,
+ rp->pri_min, rp->pri_max, rp->max_dur);
+ if (delta_ts >= rp->pri_min) {
+ DLOG("OK: delta_ts >= pri_min");
+ if (delta_ts <= rp->max_dur) {
+ /* this one is for us */
+ rs->last_ts = ts;
+ return detector_check_pri(rp, rs, delta_ts);
+ } else {
+ DLOG("NOK: delta_ts=%d > max_dur[%d]=%d",
+ delta_ts, rp->type_id, rp->max_dur);
+ }
+ } else
+ DLOG("delta_ts=%d < pri_min[%d]=%d",
+ delta_ts, rp->type_id, rp->pri_min);
+ /* if for some reason this radar was not for me, safely reset stats
+ * since this pulse invalidates all previous
+ */
+ reset_detector_element(rs, ts);
+ return 0;
+}
+
+
+static uint32_t freq_to_usec(uint32_t freq)
+{
+ return 1000000 / freq;
+}
+
+/* percentage of ppb threshold to trigger detection */
+#define MIN_PPB_THRESH 66
+#define PPB_THRESH(X) ((X*MIN_PPB_THRESH + 50) / 100)
+
+static void dpd_exit(struct dfs_pattern_detector *_this)
+{
+ if (_this->data != NULL) {
+ if (_this->data->radar_detectors != NULL)
+ free(_this->data->radar_detectors);
+ free(_this->data);
+ }
+ free(_this);
+}
+
+static enum dfs_detector_result dpd_add_pulse(
+ struct dfs_pattern_detector *_this, struct pulse_event *event)
+{
+ int detector_result = NO_DETECTION;
+ struct pattern_detector_data *pd_data = _this->data;
+ uint64_t delta_ts = event->ts - pd_data->last_pulse_ts;
+ uint32_t width = event->width;
+ int dfs_channel_idx;
+ DTRACE();
+
+ DINFO("e->width=%d, e->ts=%llu, delta_ts=%llu, e->freq=%d",
+ event->width, event->ts, delta_ts, event->freq);
+
+ dfs_channel_idx = get_dfs_channel_idx(event->freq);
+ if (dfs_channel_idx < 0) {
+ DERROR("pulse_event.freq=%d is no DFS frequency, dropping");
+ return PULSE_DROPPED;
+ }
+
+ /* global condition checks */
+
+ /* condition: pulse width inside valid range? */
+ if ((width > pd_data->max_valid_width) ||
+ (width < pd_data->min_valid_width)) {
+ DINFO("pulse width %d outside valid range [%d, %d], dropping",
+ width, pd_data->min_valid_pri, pd_data->max_valid_pri);
+ return PULSE_DROPPED;
+ }
+
+ pd_data->last_pulse_ts = event->ts;
+
+ /* condition: pulse interval < max allowed pattern duration */
+ if (delta_ts > pd_data->max_radar_dur) {
+ DINFO("pulse with delta_ts=%llu > max_radar_dur=%d, resetting",
+ delta_ts, pd_data->max_radar_dur);
+ detector_reset(pd_data, dfs_channel_idx);
+ return NO_DETECTION;
+ }
+
+ /* condition: pulse interval larger that min allowed pri
+ * NOTE: we are not checking against max allowed pri to
+ * allow for coverage of multiple pris
+ */
+ if (delta_ts >= pd_data->min_valid_pri) {
+ int i;
+
+ /* do type individual pattern matching */
+ for (i = 0; i < pd_data->num_detector_elements; i++) {
+ struct radar_specs *rp;
+ rp = &pd_data->radar_detectors[i].specs;
+ /* condition: width within type specific width range */
+ if (width >= rp->width_min && width <= rp->width_max) {
+ struct radar_stats *rs;
+ rs = &pd_data->radar_detectors[i].
+ stats[dfs_channel_idx];
+ if (detector_check_pulse_ts(rp,
+ rs, event->ts)) {
+ detector_result = RADAR_DETECTED;
+ /* stop here, don't care if further
+ * patterns might also match */
+ break;
+ }
+ }
+ }
+ if (detector_result == RADAR_DETECTED) {
+ /* radar pattern found -> reset detector line */
+ detector_reset(pd_data, dfs_channel_idx);
+ }
+ return detector_result;
+ } else
+ DINFO("pulse with delta_ts=%llu outside valid pri-range "
+ "[%d, %d], resetting", delta_ts,
+ pd_data->min_valid_pri, pd_data->max_valid_pri);
+ return 0;
+}
+
+
+/* our base VFT */
+static struct dfs_pattern_detector dpd_default_vft = {
+ .exit = dpd_exit,
+ .add_pulse = dpd_add_pulse,
+};
+
+
+static void print_detector_specs(struct pattern_detector_data *pd_data)
+{
+ int i;
+ for (i = 0; i < pd_data->num_detector_elements; i++) {
+ struct radar_specs *rs = &pd_data->radar_detectors[i].specs;
+ DINIT("Initialized radar pattern type %d", i);
+ DINIT(" rs->type_id = %d", rs->type_id);
+ DINIT(" rs->width_min = %d", rs->width_min);
+ DINIT(" rs->width_max = %d", rs->width_max);
+ DINIT(" rs->pri_min = %d", rs->pri_min);
+ DINIT(" rs->pri_max = %d", rs->pri_max);
+ DINIT(" rs->num_pri = %d", rs->num_pri);
+ DINIT(" rs->ppb_thresh = %d", rs->ppb_thresh);
+ DINIT(" rs->max_dur = %d", rs->max_dur);
+ }
+ DINIT("valid ranges: width=[%d, %d], pri=[%d, %d], dur=%d",
+ pd_data->min_valid_width, pd_data->max_valid_width,
+ pd_data->min_valid_pri, pd_data->max_valid_pri,
+ pd_data->max_radar_dur);
+}
+
+
+/* allocate and initialize object data */
+static struct pattern_detector_data *setup_detector_data(struct radar_type *rt)
+{
+ int i;
+ struct pattern_detector_data *pd_data;
+ int sz = sizeof(struct pattern_detector_data);
+ pd_data = malloc(sz);
+ if (pd_data == NULL) {
+ DERROR("allocation of pattern_detector_data failed");
+ return NULL;
+ }
+
+ memset(pd_data, 0, sz);
+
+ sz = sizeof(struct detector_line) * rt->num_radar_types;
+ pd_data->radar_detectors = malloc(sz);
+ if (pd_data->radar_detectors == NULL) {
+ DERROR("allocation of radar_detectors failed");
+ return NULL;
+ }
+ memset(pd_data->radar_detectors, 0, sz);
+
+ pd_data->num_detector_elements = rt->num_radar_types;
+ pd_data->min_valid_width = (uint32_t) -1;
+ pd_data->max_valid_width = 0;
+ pd_data->min_valid_pri = (uint32_t) -1;
+ pd_data->max_valid_pri = 0;
+ pd_data->max_radar_dur = 0;
+
+ for (i = 0; i < rt->num_radar_types; i++) {
+ struct radar_signal_type *rst = &rt->radar_types[i];
+ struct radar_specs *rs = &pd_data->radar_detectors[i].specs;
+ DINIT("Initializing type %d", i);
+ rs->type_id = rst->type_id;
+ rs->width_min = rst->width_min;
+ rs->width_max = rst->width_max;
+ rs->pri_min = freq_to_usec(rst->pps_max) - MAX_PRI_TOLERANCE;
+ rs->pri_max = freq_to_usec(rst->pps_min) + MAX_PRI_TOLERANCE;
+ rs->num_pri = rst->num_pri;
+ rs->ppb = rst->ppb;
+ rs->ppb_thresh = PPB_THRESH(rst->ppb);
+ rs->max_dur = rs->pri_max * rst->ppb * rst->num_pri;
+
+ if (rs->width_min < pd_data->min_valid_width)
+ pd_data->min_valid_width = rs->width_min;
+ if (rs->width_max > pd_data->max_valid_width)
+ pd_data->max_valid_width = rs->width_max;
+ if (rs->pri_min < pd_data->min_valid_pri)
+ pd_data->min_valid_pri = rs->pri_min;
+ if (rs->pri_max > pd_data->max_valid_pri)
+ pd_data->max_valid_pri = rs->pri_max;
+ if (rs->max_dur > pd_data->max_radar_dur)
+ pd_data->max_radar_dur = rs->max_dur;
+ }
+ print_detector_specs(pd_data);
+ return pd_data;
+}
+
+
+struct dfs_pattern_detector *dfs_pattern_detector_init(
+ enum dfs_domain dfs_domain)
+{
+ int i;
+ struct dfs_pattern_detector *_this;
+ struct radar_type *rt;
+
+ /* find supported radar type */
+ for (i = 0; /* nothing */; i++) {
+ rt = supported_radar_types[i];
+ if (rt == NULL) {
+ DERROR("non-supported dfs-domain %d", dfs_domain);
+ return NULL;
+ }
+ if (rt->dfs_id == dfs_domain)
+ break;
+ }
+ /* allocate object instance */
+ _this = malloc(sizeof(struct dfs_pattern_detector));
+ if (_this == NULL) {
+ DERROR("allocation of dfs_pattern_detector failed");
+ return NULL;
+ }
+ *_this = dpd_default_vft;
+
+ /* allocate and initialize object data */
+ _this->data = setup_detector_data(rt);
+ if (_this->data == NULL) {
+ _this->exit(_this);
+ return NULL;
+ }
+ return _this;
+}
new file mode 100644
@@ -0,0 +1,46 @@
+#ifndef DFS_PATTERN_DETECTOR_H
+#define DFS_PATTERN_DETECTOR_H
+
+#include "dfs.h"
+
+
+/**
+ * enum dfs_detector_result - DFS detector result after adding pulse
+ *
+ * Feeding a potential radar pulse to the detector might result in:
+ * @NO_DETECTION: pulse added, but no detection so far
+ * @RADAR_DETECTED: pulse added, pattern matched => radar detected
+ * @PULSE_DROPPED: pulse not added, outside valid pattern ranges
+ */
+enum dfs_detector_result {
+ NO_DETECTION,
+ RADAR_DETECTED,
+ PULSE_DROPPED,
+};
+
+/**
+ * struct dfs_pattern_detector - pseudo-OO DFS pattern detector class
+ *
+ * A DFS pattern detector object is instantiated with its constructor that
+ * returns ptr to initialized object.
+ *
+ * The VFT so far needs only two public methods:
+ * @exit: destructor
+ * @add_pulse: adds radar pulse to detector
+ *
+ * All data is private.
+ */
+struct dfs_pattern_detector {
+ /* VFT */
+ void (*exit)(struct dfs_pattern_detector *_this);
+ enum dfs_detector_result (*add_pulse)
+ (struct dfs_pattern_detector *_this, struct pulse_event *pe);
+
+ /* private data */
+ struct pattern_detector_data *data;
+};
+
+/* Constructor */
+struct dfs_pattern_detector *dfs_pattern_detector_init(enum dfs_domain);
+
+#endif /* DFS_PATTERN_DETECTOR_H */
new file mode 100644
@@ -0,0 +1,48 @@
+#ifndef DFS_RADAR_TYPES_H
+#define DFS_RADAR_TYPES_H
+
+#include "dfs.h"
+
+struct radar_signal_type {
+ unsigned int type_id;
+ unsigned int width_min;
+ unsigned int width_max;
+ unsigned int pps_min;
+ unsigned int pps_max;
+ unsigned int num_pri;
+ unsigned int ppb;
+};
+
+static struct radar_signal_type etsi_radar_ref_types_v15[] = {
+ { 0, 0, 1, 700, 700, 1, 18, },
+ { 1, 0, 5, 200, 1000, 1, 10, },
+ { 2, 0, 15, 200, 1600, 1, 15, },
+ { 3, 0, 15, 2300, 4000, 1, 25, },
+ { 4, 20, 30, 2000, 4000, 1, 20, },
+ { 5, 0, 2, 300, 400, 3, 10, },
+ { 6, 0, 2, 400, 1200, 3, 15, },
+};
+
+struct radar_type {
+ uint32_t dfs_id;
+ uint32_t num_radar_types;
+ struct radar_signal_type *radar_types;
+};
+
+static struct radar_type etsi_radar_types_v15 = {
+ .dfs_id = DFS_ETSI_DOMAIN,
+ .num_radar_types = sizeof(etsi_radar_ref_types_v15) /
+ sizeof(struct radar_signal_type),
+ .radar_types = etsi_radar_ref_types_v15,
+};
+
+
+static struct radar_type *supported_radar_types[] = {
+ &etsi_radar_types_v15,
+ 0,
+};
+
+
+
+#endif /* DFS_RADAR_TYPES_H */
+