libsigrok
|
00001 /* 00002 * This file is part of the sigrok project. 00003 * 00004 * Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de> 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00019 */ 00020 00021 #include <stdint.h> 00022 #include <stdlib.h> 00023 #include <string.h> 00024 #include "sigrok.h" 00025 #include "sigrok-internal.h" 00026 00027 /** 00028 * Convert a numeric samplerate value to its "natural" string representation. 00029 * 00030 * E.g. a value of 3000000 would be converted to "3 MHz", 20000 to "20 kHz", 00031 * 31500 would become "31.5 kHz". 00032 * 00033 * @param samplerate The samplerate in Hz. 00034 * 00035 * @return A g_try_malloc()ed string representation of the samplerate value, 00036 * or NULL upon errors. The caller is responsible to g_free() the 00037 * memory. 00038 */ 00039 SR_API char *sr_samplerate_string(uint64_t samplerate) 00040 { 00041 char *o; 00042 uint64_t s = samplerate; 00043 00044 if ((s >= SR_GHZ(1)) && (s % SR_GHZ(1) == 0)) { 00045 o = g_strdup_printf("%" PRIu64 " GHz", s / SR_GHZ(1)); 00046 } else if ((s >= SR_GHZ(1)) && (s % SR_GHZ(1) != 0)) { 00047 o = g_strdup_printf("%" PRIu64 ".%" PRIu64 " GHz", 00048 s / SR_GHZ(1), s % SR_GHZ(1)); 00049 } else if ((s >= SR_MHZ(1)) && (s % SR_MHZ(1) == 0)) { 00050 o = g_strdup_printf("%" PRIu64 " MHz", s / SR_MHZ(1)); 00051 } else if ((s >= SR_MHZ(1)) && (s % SR_MHZ(1) != 0)) { 00052 o = g_strdup_printf("%" PRIu64 ".%" PRIu64 " MHz", 00053 s / SR_MHZ(1), s % SR_MHZ(1)); 00054 } else if ((s >= SR_KHZ(1)) && (s % SR_KHZ(1) == 0)) { 00055 o = g_strdup_printf("%" PRIu64 " kHz", s / SR_KHZ(1)); 00056 } else if ((s >= SR_KHZ(1)) && (s % SR_KHZ(1) != 0)) { 00057 o = g_strdup_printf("%" PRIu64 ".%" PRIu64 " kHz", 00058 s / SR_KHZ(1), s % SR_KHZ(1)); 00059 } else { 00060 o = g_strdup_printf("%" PRIu64 " Hz", s); 00061 } 00062 00063 if (!o) { 00064 sr_err("strutil: %s: Error creating samplerate string.", 00065 __func__); 00066 return NULL; 00067 } 00068 00069 return o; 00070 } 00071 00072 /** 00073 * Convert a numeric frequency value to the "natural" string representation 00074 * of its period. 00075 * 00076 * E.g. a value of 3000000 would be converted to "3 us", 20000 to "50 ms". 00077 * 00078 * @param frequency The frequency in Hz. 00079 * 00080 * @return A g_try_malloc()ed string representation of the frequency value, 00081 * or NULL upon errors. The caller is responsible to g_free() the 00082 * memory. 00083 */ 00084 SR_API char *sr_period_string(uint64_t frequency) 00085 { 00086 char *o; 00087 int r; 00088 00089 /* Allocate enough for a uint64_t as string + " ms". */ 00090 if (!(o = g_try_malloc0(30 + 1))) { 00091 sr_err("strutil: %s: o malloc failed", __func__); 00092 return NULL; 00093 } 00094 00095 if (frequency >= SR_GHZ(1)) 00096 r = snprintf(o, 30, "%" PRIu64 " ns", frequency / 1000000000); 00097 else if (frequency >= SR_MHZ(1)) 00098 r = snprintf(o, 30, "%" PRIu64 " us", frequency / 1000000); 00099 else if (frequency >= SR_KHZ(1)) 00100 r = snprintf(o, 30, "%" PRIu64 " ms", frequency / 1000); 00101 else 00102 r = snprintf(o, 30, "%" PRIu64 " s", frequency); 00103 00104 if (r < 0) { 00105 /* Something went wrong... */ 00106 g_free(o); 00107 return NULL; 00108 } 00109 00110 return o; 00111 } 00112 00113 /** 00114 * Parse a trigger specification string. 00115 * 00116 * @param dev The device for which the trigger specification is intended. 00117 * @param triggerstring The string containing the trigger specification for 00118 * one or more probes of this device. Entries for multiple probes are 00119 * comma-separated. Triggers are specified in the form key=value, 00120 * where the key is a probe number (or probe name) and the value is 00121 * the requested trigger type. Valid trigger types currently 00122 * include 'r' (rising edge), 'f' (falling edge), 'c' (any pin value 00123 * change), '0' (low value), or '1' (high value). 00124 * Example: "1=r,sck=f,miso=0,7=c" 00125 * 00126 * @return Pointer to a list of trigger types (strings), or NULL upon errors. 00127 * The pointer list (if non-NULL) has as many entries as the 00128 * respective device has probes (all physically available probes, 00129 * not just enabled ones). Entries of the list which don't have 00130 * a trigger value set in 'triggerstring' are NULL, the other entries 00131 * contain the respective trigger type which is requested for the 00132 * respective probe (e.g. "r", "c", and so on). 00133 */ 00134 SR_API char **sr_parse_triggerstring(struct sr_dev *dev, 00135 const char *triggerstring) 00136 { 00137 GSList *l; 00138 struct sr_probe *probe; 00139 int max_probes, probenum, i; 00140 char **tokens, **triggerlist, *trigger, *tc, *trigger_types; 00141 gboolean error; 00142 00143 max_probes = g_slist_length(dev->probes); 00144 error = FALSE; 00145 00146 if (!(triggerlist = g_try_malloc0(max_probes * sizeof(char *)))) { 00147 sr_err("strutil: %s: triggerlist malloc failed", __func__); 00148 return NULL; 00149 } 00150 00151 tokens = g_strsplit(triggerstring, ",", max_probes); 00152 00153 trigger_types = dev->driver->dev_info_get(0, SR_DI_TRIGGER_TYPES); 00154 if (!trigger_types) { 00155 sr_err("strutil: %s: Device doesn't support any triggers.", 00156 __func__); 00157 return NULL; 00158 } 00159 00160 for (i = 0; tokens[i]; i++) { 00161 if (tokens[i][0] < '0' || tokens[i][0] > '9') { 00162 /* Named probe */ 00163 probenum = 0; 00164 for (l = dev->probes; l; l = l->next) { 00165 probe = (struct sr_probe *)l->data; 00166 if (probe->enabled 00167 && !strncmp(probe->name, tokens[i], 00168 strlen(probe->name))) { 00169 probenum = probe->index; 00170 break; 00171 } 00172 } 00173 } else { 00174 probenum = strtol(tokens[i], NULL, 10); 00175 } 00176 00177 if (probenum < 1 || probenum > max_probes) { 00178 sr_err("strutil: Invalid probe (%d).", probenum); 00179 error = TRUE; 00180 break; 00181 } 00182 00183 if ((trigger = strchr(tokens[i], '='))) { 00184 for (tc = ++trigger; *tc; tc++) { 00185 if (strchr(trigger_types, *tc) == NULL) { 00186 sr_err("strutil: Unsupported trigger " 00187 "type '%c'.", *tc); 00188 error = TRUE; 00189 break; 00190 } 00191 } 00192 if (!error) 00193 triggerlist[probenum - 1] = g_strdup(trigger); 00194 } 00195 } 00196 g_strfreev(tokens); 00197 00198 if (error) { 00199 for (i = 0; i < max_probes; i++) 00200 g_free(triggerlist[i]); 00201 g_free(triggerlist); 00202 triggerlist = NULL; 00203 } 00204 00205 return triggerlist; 00206 } 00207 00208 /** 00209 * Convert a "natural" string representation of a size value to uint64_t. 00210 * 00211 * E.g. a value of "3k" or "3 K" would be converted to 3000, a value 00212 * of "15M" would be converted to 15000000. 00213 * 00214 * Value representations other than decimal (such as hex or octal) are not 00215 * supported. Only 'k' (kilo), 'm' (mega), 'g' (giga) suffixes are supported. 00216 * Spaces (but not other whitespace) between value and suffix are allowed. 00217 * 00218 * @param sizestring A string containing a (decimal) size value. 00219 * @param size Pointer to uint64_t which will contain the string's size value. 00220 * 00221 * @return SR_OK upon success, SR_ERR upon errors. 00222 */ 00223 SR_API int sr_parse_sizestring(const char *sizestring, uint64_t *size) 00224 { 00225 int multiplier, done; 00226 char *s; 00227 00228 *size = strtoull(sizestring, &s, 10); 00229 multiplier = 0; 00230 done = FALSE; 00231 while (s && *s && multiplier == 0 && !done) { 00232 switch (*s) { 00233 case ' ': 00234 break; 00235 case 'k': 00236 case 'K': 00237 multiplier = SR_KHZ(1); 00238 break; 00239 case 'm': 00240 case 'M': 00241 multiplier = SR_MHZ(1); 00242 break; 00243 case 'g': 00244 case 'G': 00245 multiplier = SR_GHZ(1); 00246 break; 00247 default: 00248 done = TRUE; 00249 s--; 00250 } 00251 s++; 00252 } 00253 if (multiplier > 0) 00254 *size *= multiplier; 00255 00256 if (*s && strcasecmp(s, "Hz")) 00257 return SR_ERR; 00258 00259 return SR_OK; 00260 } 00261 00262 /** 00263 * Convert a "natural" string representation of a time value to an 00264 * uint64_t value in milliseconds. 00265 * 00266 * E.g. a value of "3s" or "3 s" would be converted to 3000, a value 00267 * of "15ms" would be converted to 15. 00268 * 00269 * Value representations other than decimal (such as hex or octal) are not 00270 * supported. Only lower-case "s" and "ms" time suffixes are supported. 00271 * Spaces (but not other whitespace) between value and suffix are allowed. 00272 * 00273 * @param timestring A string containing a (decimal) time value. 00274 * @return The string's time value as uint64_t, in milliseconds. 00275 * 00276 * TODO: Error handling. 00277 * TODO: Add support for "m" (minutes) and others. 00278 * TODO: picoseconds? 00279 * TODO: Allow both lower-case and upper-case. 00280 */ 00281 SR_API uint64_t sr_parse_timestring(const char *timestring) 00282 { 00283 uint64_t time_msec; 00284 char *s; 00285 00286 time_msec = strtoull(timestring, &s, 10); 00287 if (time_msec == 0 && s == timestring) 00288 return 0; 00289 00290 if (s && *s) { 00291 while (*s == ' ') 00292 s++; 00293 if (!strcmp(s, "s")) 00294 time_msec *= 1000; 00295 else if (!strcmp(s, "ms")) 00296 ; /* redundant */ 00297 else 00298 return 0; 00299 } 00300 00301 return time_msec; 00302 } 00303 00304 SR_API gboolean sr_parse_boolstring(const char *boolstr) 00305 { 00306 if (!boolstr) 00307 return FALSE; 00308 00309 if (!g_ascii_strncasecmp(boolstr, "true", 4) || 00310 !g_ascii_strncasecmp(boolstr, "yes", 3) || 00311 !g_ascii_strncasecmp(boolstr, "on", 2) || 00312 !g_ascii_strncasecmp(boolstr, "1", 1)) 00313 return TRUE; 00314 00315 return FALSE; 00316 }