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