1 /*
2   This file is a part of unixcw project.
3   unixcw project is covered by GNU General Public License.
4 */
5 
6 #ifndef H_LIBCW_REC
7 #define H_LIBCW_REC
8 
9 
10 
11 
12 
13 #include <stdbool.h>
14 #include <sys/time.h> /* struct timeval */
15 
16 
17 
18 
19 
20 #include "libcw.h"
21 
22 
23 
24 
25 
26 /* Dot length magic number.
27 
28    From PARIS calibration, 1 dot length [us] = 1200000 / speed [wpm].
29 
30    This variable is used in generator code as well. */
31 enum { CW_DOT_CALIBRATION = 1200000 };
32 
33 
34 /* "RS" stands for "Receiver State" */
35 enum {
36 	RS_IDLE,          /* Representation buffer is empty and ready to accept data. */
37 	RS_MARK,          /* Mark. */
38 	RS_SPACE,         /* Space (inter-mark-space). */
39 	RS_EOC_GAP,       /* Gap after a character, without error (EOC = end-of-character). */
40 	RS_EOW_GAP,       /* Gap after a word, without error (EOW = end-of-word). */
41 	RS_EOC_GAP_ERR,   /* Gap after a character, with error. */
42 	RS_EOW_GAP_ERR    /* Gap after a word, with error. */
43 };
44 
45 
46 /* Does receiver initially adapt to varying speed of input data? */
47 enum { CW_REC_ADAPTIVE_MODE_INITIAL = false };
48 
49 
50 /* TODO: it would be interesting to track (in debug mode) relationship
51    between "speed threshold" and "noise threshold" parameters. */
52 enum { CW_REC_SPEED_THRESHOLD_INITIAL = (CW_DOT_CALIBRATION / CW_SPEED_INITIAL) * 2 };    /* Initial adaptive speed threshold. [us] */
53 enum { CW_REC_NOISE_THRESHOLD_INITIAL = (CW_DOT_CALIBRATION / CW_SPEED_MAX) / 2 };        /* Initial noise filter threshold. */
54 
55 
56 /* Receiver contains a fixed-length buffer for representation of
57    received data.  Capacity of the buffer is vastly longer than any
58    practical representation.  Don't know why, a legacy thing.
59 
60    Representation can be presented as a char string. This is the
61    maximal length of the string. This value does not include string's
62    ending NULL. */
63 enum { CW_REC_REPRESENTATION_CAPACITY = 256 };
64 
65 
66 /* TODO: what is the relationship between this constant and CW_REC_REPRESENTATION_CAPACITY?
67    Both have value of 256. Coincidence? I don't think so. */
68 enum { CW_REC_STATISTICS_CAPACITY = 256 };
69 
70 
71 /* Length of array used to calculate average length of a mark. Average
72    length of a mark is used in adaptive receiving mode to track speed
73    of incoming Morse data. */
74 enum { CW_REC_AVERAGING_ARRAY_LENGTH = 4 };
75 
76 
77 /* Types of receiver's timing statistics.
78    CW_REC_STAT_NONE must be zero so that the statistics buffer is initially empty. */
79 typedef enum {
80 	CW_REC_STAT_NONE = 0,
81 	CW_REC_STAT_DOT,           /* Dot mark. */
82 	CW_REC_STAT_DASH,          /* Dash mark. */
83 	CW_REC_STAT_IMARK_SPACE,   /* Inter-mark space. */
84 	CW_REC_STAT_ICHAR_SPACE    /* Inter-character space. */
85 } stat_type_t;
86 
87 
88 typedef struct {
89 	stat_type_t type;  /* Record type */
90 	int delta;         /* Difference between actual and ideal length of mark or space. [us] */
91 } cw_rec_statistics_t;
92 
93 
94 /* A moving averages structure - circular buffer. Used for calculating
95    averaged length ([us]) of dots and dashes. */
96 typedef struct {
97 	int buffer[CW_REC_AVERAGING_ARRAY_LENGTH];  /* Buffered mark lengths. */
98 	int cursor;                                 /* Circular buffer cursor. */
99 	int sum;                                    /* Running sum of lengths of marks. [us] */
100 	int average;                                /* Averaged length of a mark. [us] */
101 } cw_rec_averaging_t;
102 
103 
104 struct cw_rec_struct {
105 
106 	/* State of receiver state machine. */
107 	int state;
108 
109 
110 
111 	/* Essential parameters. */
112 	/* Changing values of speed, tolerance, gap or
113 	   is_adaptive_receive_mode will trigger a recalculation of
114 	   low level timing parameters. */
115 
116 	/* 'speed' is float instead of being 'int' on purpose.  It
117 	   makes adaptation to varying speed of incoming data more
118 	   smooth. This is especially important at low speeds, where
119 	   change/adaptation from (int) 5wpm to (int) 4wpm would
120 	   mean a sharp decrease by 20%. With 'float' data type the
121 	   adjustment of receive speeds is more gradual. */
122 	float speed;       /* [wpm] */
123 	int tolerance;
124 	int gap;         /* Inter-character-gap, similar as in generator. */
125 	bool is_adaptive_receive_mode;
126 	int noise_spike_threshold;
127 	/* Library variable which is automatically adjusted based on
128 	   incoming Morse data stream, rather than being settable by
129 	   the user.
130 
131 	   Not exactly a *speed* threshold, but for a lack of a better
132 	   name...
133 
134 	   When the library changes internally value of this variable,
135 	   it recalculates low level timing parameters too. */
136 	int adaptive_speed_threshold; /* [microseconds]/[us] */
137 
138 
139 
140 	/* Retained timestamps of mark's begin and end. */
141 	struct timeval mark_start;
142 	struct timeval mark_end;
143 
144 	/* Buffer for received representation (dots/dashes). This is a
145 	   fixed-length buffer, filled in as tone on/off timings are
146 	   taken. The buffer is vastly longer than any practical
147 	   representation.
148 
149 	   Along with it we maintain a cursor indicating the current
150 	   write position. */
151 	char representation[CW_REC_REPRESENTATION_CAPACITY + 1];
152 	int representation_ind;
153 
154 
155 
156 	/* Receiver's low-level timing parameters */
157 
158 	/* These are basic timing parameters which should be
159 	   recalculated each time client code demands changing some
160 	   higher-level parameter of receiver.  How these values are
161 	   calculated depends on receiving mode (fixed/adaptive). */
162 	int dot_len_ideal;        /* Length of an ideal dot. [microseconds]/[us] */
163 	int dot_len_min;          /* Minimal length of mark that will be identified as dot. [us] */
164 	int dot_len_max;          /* Maximal length of mark that will be identified as dot. [us] */
165 
166 	int dash_len_ideal;       /* Length of an ideal dash. [us] */
167 	int dash_len_min;         /* Minimal length of mark that will be identified as dash. [us] */
168 	int dash_len_max;         /* Maximal length of mark that will be identified as dash. [us] */
169 
170 	int eom_len_ideal;        /* Ideal end of mark, for stats. [us] */
171 	int eom_len_min;          /* Shortest end of mark allowable. [us] */
172 	int eom_len_max;          /* Longest end of mark allowable. [us] */
173 
174 	int eoc_len_ideal;        /* Ideal end of char, for stats. [us] */
175 	int eoc_len_min;          /* Shortest end of char allowable. [us] */
176 	int eoc_len_max;          /* Longest end of char allowable. [us] */
177 
178 	/* These two fields have the same function as in
179 	   cw_gen_t. They are needed in function re-synchronizing
180 	   parameters. */
181 	int additional_delay;     /* More delay at the end of a char. [us] */
182 	int adjustment_delay;     /* More delay at the end of a word. [us] */
183 
184 
185 
186 	/* Are receiver's parameters in sync?
187 	   After changing receiver's essential parameters, its
188 	   low-level timing parameters need to be re-calculated. This
189 	   is a flag that shows when this needs to be done. */
190 	bool parameters_in_sync;
191 
192 
193 
194 	/* Receiver statistics.
195 	   A circular buffer of entries indicating the difference
196 	   between the actual and the ideal length of received mark or
197 	   space, tagged with the type of statistic held, and a
198 	   circular buffer pointer. */
199 	cw_rec_statistics_t statistics[CW_REC_STATISTICS_CAPACITY];
200 	int statistics_ind;
201 
202 
203 
204 	/* Data structures for calculating averaged length of dots and
205 	   dashes. The averaged lengths are used for adaptive tracking
206 	   of receiver's speed (tracking of speed of incoming data). */
207 	cw_rec_averaging_t dot_averaging;
208 	cw_rec_averaging_t dash_averaging;
209 };
210 
211 
212 typedef struct cw_rec_struct cw_rec_t;
213 
214 
215 
216 
217 
218 /* Creator and destructor. */
219 cw_rec_t *cw_rec_new_internal(void);
220 void      cw_rec_delete_internal(cw_rec_t **rec);
221 
222 /* Main receive functions. */
223 int cw_rec_mark_begin_internal(cw_rec_t *rec, const struct timeval *timestamp);
224 int cw_rec_mark_end_internal(cw_rec_t *rec, const struct timeval *timestamp);
225 int cw_rec_add_mark_internal(cw_rec_t *rec, const struct timeval *timestamp, char mark);
226 
227 /* Helper receive functions. */
228 int  cw_rec_poll_representation_internal(cw_rec_t *rec, const struct timeval *timestamp, char *representation, bool *is_end_of_word, bool *is_error);
229 int  cw_rec_poll_character_internal(cw_rec_t *rec, const struct timeval *timestamp, char *c, bool *is_end_of_word, bool *is_error);
230 void cw_rec_clear_buffer_internal(cw_rec_t *rec);
231 
232 /* Setters of receiver's essential parameters. */
233 int  cw_rec_set_speed_internal(cw_rec_t *rec, int new_value);
234 int  cw_rec_set_tolerance_internal(cw_rec_t *rec, int new_value);
235 int  cw_rec_set_gap_internal(cw_rec_t *rec, int new_value);
236 int  cw_rec_set_noise_spike_threshold_internal(cw_rec_t *rec, int new_value);
237 void cw_rec_set_adaptive_mode_internal(cw_rec_t *rec, bool adaptive);
238 
239 /* Getters of receiver's essential parameters. */
240 float cw_rec_get_speed_internal(cw_rec_t *rec);
241 int   cw_rec_get_tolerance_internal(cw_rec_t *rec);
242 /* int   cw_rec_get_gap_internal(cw_rec_t *rec); */
243 int   cw_rec_get_noise_spike_threshold_internal(cw_rec_t *rec);
244 bool  cw_rec_get_adaptive_mode_internal(cw_rec_t *rec);
245 
246 /* Receiver's reset functions. */
247 void cw_rec_reset_receive_parameters_internal(cw_rec_t *rec);
248 void cw_rec_reset_receive_statistics_internal(cw_rec_t *rec);
249 void cw_rec_reset_internal(cw_rec_t *rec);
250 
251 /* Other helper functions. */
252 void cw_rec_sync_parameters_internal(cw_rec_t *rec);
253 void cw_rec_get_parameters_internal(cw_rec_t *rec,
254 				    int *dot_len_ideal, int *dash_len_ideal,
255 				    int *dot_len_min, int *dot_len_max,
256 				    int *dash_len_min, int *dash_len_max,
257 				    int *eom_len_min,
258 				    int *eom_len_max,
259 				    int *eom_len_ideal,
260 				    int *eoc_len_min,
261 				    int *eoc_len_max,
262 				    int *eoc_len_ideal,
263 				    int *adaptive_threshold);
264 void cw_rec_get_statistics_internal(cw_rec_t *rec, double *dot_sd, double *dash_sd,
265 				    double *element_end_sd, double *character_end_sd);
266 int cw_rec_get_buffer_length_internal(cw_rec_t *rec);
267 int cw_rec_get_receive_buffer_capacity_internal(void);
268 
269 
270 
271 
272 
273 #ifdef LIBCW_UNIT_TESTS
274 
275 unsigned int test_cw_rec_identify_mark_internal(void);
276 unsigned int test_cw_rec_with_base_data_fixed(void);
277 unsigned int test_cw_rec_with_random_data_fixed(void);
278 unsigned int test_cw_rec_with_random_data_adaptive(void);
279 unsigned int test_cw_get_receive_parameters(void);
280 
281 #endif /* #ifdef LIBCW_UNIT_TESTS */
282 
283 
284 
285 
286 
287 #endif /* #ifndef H_LIBCW_REC */
288