1 // =====================================================================
2 //
3 //  time_table.cxx
4 //
5 //  Author(s):
6 //    Robert Stiles, KK5VD, Copyright (C) 2013, 2014
7 //
8 // This file is part of FLAMP and FLMSG.
9 //
10 // This is free software; you can redistribute it and/or modify
11 // it under the terms of the GNU General Public License as published by
12 // the Free Software Foundation; either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // This software is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 //
23 // =====================================================================
24 
25 
26 // Doxygen
27 /** ********************************************************
28  \page page_modem_timing_table Modem Timing Table Structure
29 
30 	A table and functions to calculate the number of seconds or
31 	minutes needed to transmit a string of data.
32 
33  \par char *modem_name
34 	The string ID of the modem.<br>
35 	Example:<br>
36 	8PSK125, 8PSK250, etc. <br>
37 
38  \par float scale
39 	A value used to scale the resulting toble in an attemp to adjust for
40 	errors. However, because of the differential errors for each charater
41 	and overhead time, it's not recommended for use.
42 
43  \par float overhead
44  	Each modem contains a leading and trailing pre/postamble. The time for
45 	both a accumulated and stored in this variable.
46 
47  \par table[256]
48  	Floating point representation of the amount of time it takes to
49 	transmit the character in seconds. Character value range 0 to 255.
50 
51  \verbatim
52  	typedef struct {
53 		char *mode_name;
54 		float scale;
55 		float overhead;
56 		float table[256];
57 	} MODE_TIME_TABLE;
58 
59 	static MODE_TIME_TABLE mode_time_table[] = {
60 		{
61 			(char *) "8PSK125", 1.0, 2.973000,
62  			{
63  				0.058500, 0.058875, 0.058500, 0.058500, 0.058875, 0.058500, 0.058500, 0.058875,
64  				0.042500, 0.058500, 0.058875, 0.058500, 0.058500, 0.042875, 0.058500, 0.058500,
65  				0.058875, 0.058500, 0.058500, 0.058875, 0.058500, 0.058500, 0.058875, 0.058500,
66  				0.058500, 0.058875, 0.058500, 0.058500, 0.058875, 0.058500, 0.063625, 0.064312,
67  				0.016000, 0.047625, 0.048313, 0.053437, 0.053062, 0.053437, 0.053437, 0.047625,
68 				...
69 			},...
70 		},...
71 	};
72 
73 \endverbatim
74 
75  ***********************************************************/
76 
77 #include <math.h>
78 
79 #include "debug.h"
80 #include "time_table.h"
81 #include "time_table_dat.cxx"
82 
83 #include "status.h"
84 
85 static float time_length(MODE_TIME_TABLE *mTable, const char *string, int length);
86 static int str_cnt(char * str, int count_limit);
87 
88 /** ********************************************************
89  * \brief Determine the length of the string with a count
90  * limitation.
91  * \return signed integer. The number of characters in the
92  * array not to excede count limit.
93  ***********************************************************/
str_cnt(char * str,int count_limit)94 static int str_cnt(char * str, int count_limit)
95 {
96 	if(!str || (count_limit < 1))
97 		return 0;
98 
99 	int value = 0;
100 
101 	for(int index = 0; index < count_limit; index++) {
102 		if(str[index] == 0) break;
103 		value++;
104 	}
105 
106 	return value;
107 }
108 
109 /** ********************************************************
110  * \brief Calulate the time it take to transmit the given
111  * text with the selected modem.
112  ***********************************************************/
time_length(MODE_TIME_TABLE * mTable,const char * string,int length)113 static float time_length(MODE_TIME_TABLE *mTable, const char *string, int length)
114 {
115 	unsigned int character = 0;
116 	float accum = 0.0;
117 
118 	while (length > 0) {
119 		character = (unsigned int) *string++;
120 		character &= 0xFF;
121 		accum += mTable->table[character];
122 		length--;
123 	}
124 
125 	return (accum * mTable->scale);
126 }
127 
128 /** ********************************************************
129  * \brief Returns the time it take to transmit the given
130  * text with the selected modem. 'C' interface.
131  * \return float Duration in seconds.
132  ***********************************************************/
seconds_from_c_string(const char * mode,const char * string,int length,float * overhead)133 float seconds_from_c_string(const char *mode, const char *string, int length, float *overhead)
134 {
135 	int mode_index = 0;
136 	int max_mode_name = 16;
137 	int mode_count = sizeof(mode_time_table) / sizeof(MODE_TIME_TABLE);
138 	static int last_mode = 0;
139 
140 	if(!mode || !string || length < 1) return 0.0;
141 
142 	if(strncmp(mode, mode_time_table[last_mode].mode_name, max_mode_name) == 0) {
143 		if(overhead) {
144 			*overhead = mode_time_table[last_mode].overhead;
145 		}
146 		return time_length(&mode_time_table[last_mode], string, length);
147 	} else {
148 		for(mode_index = 0; mode_index < mode_count; mode_index++) {
149 			if(strncmp((char *) mode, (char *) mode_time_table[mode_index].mode_name, max_mode_name) == 0) {
150 				last_mode = mode_index;
151 				if(overhead) {
152 					*overhead = mode_time_table[last_mode].overhead;
153 				}
154 				return time_length(&mode_time_table[mode_index], string, length);
155 			}
156 		}
157 	}
158 	return 0.0;
159 }
160 
161 /** ********************************************************
162  * \brief Returns the time it take to transmit the given
163  * text with the selected modem. 'C' interface.
164  * \return float Duration in minutes.
165  ***********************************************************/
minutes_from_c_string(const char * mode,const char * string,int length,float * overhead)166 float minutes_from_c_string(const char *mode, const char *string, int length, float *overhead)
167 {
168 	float time = 0.0;
169 
170 	time = seconds_from_c_string(mode, string, length, overhead) / 60.0;
171 	if(overhead)
172 		*overhead /= 60.0;
173 	return time;
174 }
175 
176 /** ********************************************************
177  * \brief Returns the time it take to transmit the given
178  * text with the selected modem. 'C++' std::string interface.
179  * \return float Duration in seconds.
180  ***********************************************************/
seconds_from_string(std::string mode,std::string & str,float * overhead)181 float seconds_from_string(std::string mode, std::string& str, float *overhead)
182 {
183 	try {
184 		return seconds_from_c_string(mode.c_str(), str.c_str(), str.length(), overhead);
185 	} catch ( ... ) {
186 		LOG_ERROR("%s", "String Ref Error");
187 		return 0.0;
188 	}
189 }
190 
191 /** ********************************************************
192  * \brief Returns the time it take to transmit the given
193  * text with the selected modem. 'C++' std::string interface.
194  * \return float Duration in minutes.
195  ***********************************************************/
minutes_from_string(std::string mode,std::string & str,float * overhead)196 float minutes_from_string(std::string mode, std::string& str, float *overhead)
197 {
198 	float time = 0.0;
199 	try {
200 		time = seconds_from_c_string(mode.c_str(), str.c_str(), str.length(), overhead) / 60.0;
201 		if(overhead)
202 			*overhead /= 60.0;
203 	} catch ( ... ) {
204 		LOG_ERROR("%s", "String Ref Error");
205 		return 0.0;
206 	}
207 
208 	return time;
209 }
210 
211 /** ********************************************************
212  * \brief Search the modem table for a modem string match.
213  * 'C++' std::string interface.
214  * \return bool Match found = true.
215  ***********************************************************/
modem_available(std::string modem)216 bool modem_available(std::string modem)
217 {
218 	if(modem.empty())
219 		return false;
220 	return modem_available((char *) modem.c_str(), (int) modem.size());
221 }
222 
223 
224 /** ********************************************************
225  * \brief Search the modem table for a modem string match.
226  * 'C' interface.
227  * \return bool Match found = true.
228  ***********************************************************/
modem_available(char * modem,int search_limit)229 bool modem_available(char *modem, int search_limit)
230 {
231 	if(!modem || (search_limit < 1))
232 		return false;
233 
234 	int mode_count = (int) sizeof(mode_time_table) / sizeof(MODE_TIME_TABLE);
235 	int index = 0;
236 	int results = 0;
237 	bool found = false;
238 
239 	for(index = 0; index < mode_count; index++) {
240 		results = strncmp(modem, mode_time_table[index].mode_name, search_limit);
241 		if(results == 0) {
242 			results = str_cnt(mode_time_table[index].mode_name, 16);
243 			if(results == search_limit) {
244 				found = true;
245 				break;
246 			}
247 		}
248 	}
249 
250 	return found;
251 }
252 
253 /** ********************************************************
254  * \brief Return the number of table entires.
255  * \return integer
256  ***********************************************************/
mode_table_count(void)257 int mode_table_count(void)
258 {
259 	return (int) sizeof(mode_time_table) / sizeof(MODE_TIME_TABLE);
260 }
261 
262 /** ********************************************************
263  * \brief Return modem ID string at position 'x' in the
264  * Table.
265  * \return char *.
266  ***********************************************************/
modem_at_index(int index)267 char * modem_at_index(int index)
268 {
269 	static char modem_name[] = "Bad Index";
270 
271 	int index_limit = mode_table_count();
272 
273 	if(index < 0 || index >= index_limit)
274 		return (char *) &modem_name[0];
275 
276 	return (char *) mode_time_table[index].mode_name;
277 }
278 
279 /** ********************************************************
280  * \brief Return duration of mode TxID in seconds
281  *        0 if mode not in table
282  * TxID is either 25 or 50 symbols in duration
283  ***********************************************************/
rsid_duration(std::string modem)284 float rsid_duration(std::string modem)
285 {
286 	size_t mode_count = sizeof(mode_time_table) / sizeof(*mode_time_table);
287 
288 	for( size_t index = 0; index < mode_count; index++) {
289 		if (modem == mode_time_table[index].mode_name)
290 			return round(mode_time_table[index].rsid_symbols * 25 * 0.09288);
291 	}
292 	return 0;
293 }
294 
295