value.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. #define _POSIX_C_SOURCE 200809L
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <math.h>
  6. #include "pcilib.h"
  7. #include "value.h"
  8. #include "error.h"
  9. #include "unit.h"
  10. #include "tools.h"
  11. void pcilib_clean_value(pcilib_t *ctx, pcilib_value_t *val) {
  12. if (!val) return;
  13. if (val->data) {
  14. free(val->data);
  15. val->data = NULL;
  16. }
  17. memset(val, 0, sizeof(pcilib_value_t));
  18. }
  19. int pcilib_copy_value(pcilib_t *ctx, pcilib_value_t *dst, const pcilib_value_t *src) {
  20. if (dst->type != PCILIB_TYPE_INVALID)
  21. pcilib_clean_value(ctx, dst);
  22. memcpy(dst, src, sizeof(pcilib_value_t));
  23. if ((src->size)&&(src->data)) {
  24. dst->data = malloc(src->size);
  25. if (!dst->data) {
  26. dst->type = PCILIB_TYPE_INVALID;
  27. return PCILIB_ERROR_MEMORY;
  28. }
  29. memcpy(dst->data, src->data, src->size);
  30. }
  31. return 0;
  32. }
  33. int pcilib_set_value_from_float(pcilib_t *ctx, pcilib_value_t *value, double fval) {
  34. pcilib_clean_value(ctx, value);
  35. value->type = PCILIB_TYPE_DOUBLE;
  36. value->fval = fval;
  37. return 0;
  38. }
  39. int pcilib_set_value_from_int(pcilib_t *ctx, pcilib_value_t *value, long ival) {
  40. pcilib_clean_value(ctx, value);
  41. value->type = PCILIB_TYPE_LONG;
  42. value->ival = ival;
  43. return 0;
  44. }
  45. int pcilib_set_value_from_register_value(pcilib_t *ctx, pcilib_value_t *value, pcilib_register_value_t regval) {
  46. return pcilib_set_value_from_int(ctx, value, regval);
  47. }
  48. int pcilib_set_value_from_static_string(pcilib_t *ctx, pcilib_value_t *value, const char *str) {
  49. pcilib_clean_value(ctx, value);
  50. value->type = PCILIB_TYPE_STRING;
  51. value->sval = str;
  52. return 0;
  53. }
  54. int pcilib_set_value_from_string(pcilib_t *ctx, pcilib_value_t *value, const char *str) {
  55. size_t len;
  56. pcilib_clean_value(ctx, value);
  57. len = strlen(str) + 1;
  58. if (len < sizeof(value->str)) {
  59. memcpy(value->str, str, len);
  60. value->sval = value->str;
  61. } else {
  62. value->data = (void*)strdup(str);
  63. if (!value->data) return PCILIB_ERROR_MEMORY;
  64. value->size = strlen(str) + 1;
  65. value->sval = value->data;
  66. }
  67. value->type = PCILIB_TYPE_STRING;
  68. return 0;
  69. }
  70. double pcilib_get_value_as_float(pcilib_t *ctx, const pcilib_value_t *val, int *ret) {
  71. int err;
  72. double res;
  73. pcilib_value_t copy = {0};
  74. err = pcilib_copy_value(ctx, &copy, val);
  75. if (err) {
  76. if (ret) *ret = err;
  77. return 0.;
  78. }
  79. err = pcilib_convert_value_type(ctx, &copy, PCILIB_TYPE_DOUBLE);
  80. if (err) {
  81. if (ret) *ret = err;
  82. return 0.;
  83. }
  84. if (ret) *ret = 0;
  85. res = copy.fval;
  86. pcilib_clean_value(ctx, &copy);
  87. return res;
  88. }
  89. long pcilib_get_value_as_int(pcilib_t *ctx, const pcilib_value_t *val, int *ret) {
  90. int err;
  91. long res;
  92. pcilib_value_t copy = {0};
  93. err = pcilib_copy_value(ctx, &copy, val);
  94. if (err) {
  95. if (ret) *ret = err;
  96. return 0;
  97. }
  98. err = pcilib_convert_value_type(ctx, &copy, PCILIB_TYPE_LONG);
  99. if (err) {
  100. if (ret) *ret = err;
  101. return 0;
  102. }
  103. if (ret) *ret = 0;
  104. res = copy.ival;
  105. pcilib_clean_value(ctx, &copy);
  106. return res;
  107. }
  108. pcilib_register_value_t pcilib_get_value_as_register_value(pcilib_t *ctx, const pcilib_value_t *val, int *ret) {
  109. int err;
  110. pcilib_register_value_t res;
  111. pcilib_value_t copy = {0};
  112. err = pcilib_copy_value(ctx, &copy, val);
  113. if (err) {
  114. if (ret) *ret = err;
  115. return 0.;
  116. }
  117. err = pcilib_convert_value_type(ctx, &copy, PCILIB_TYPE_LONG);
  118. if (err) {
  119. if (ret) *ret = err;
  120. return 0.;
  121. }
  122. if (ret) *ret = 0;
  123. res = copy.ival;
  124. if (copy.ival < 0)
  125. pcilib_warning("Data corruption while converting negative polymorph value (%li) to the register type, result %u", copy.ival, res);
  126. pcilib_clean_value(ctx, &copy);
  127. return res;
  128. }
  129. /*
  130. double pcilib_value_get_float(pcilib_value_t *val) {
  131. pcilib_value_t copy;
  132. if (val->type == PCILIB_TYPE_DOUBLE)
  133. return val->fval;
  134. err = pcilib_copy_value(&copy, val);
  135. if (err) ???
  136. }
  137. long pcilib_value_get_int(pcilib_value_t *val) {
  138. }
  139. */
  140. int pcilib_convert_value_unit(pcilib_t *ctx, pcilib_value_t *val, const char *unit_name) {
  141. if (val->type == PCILIB_TYPE_INVALID) {
  142. pcilib_error("Can't convert uninitialized value");
  143. return PCILIB_ERROR_NOTINITIALIZED;
  144. }
  145. if ((val->type != PCILIB_TYPE_DOUBLE)&&(val->type != PCILIB_TYPE_LONG)) {
  146. pcilib_error("Can't convert value of type %u, only values with integer and float types can be converted to different units", val->type);
  147. return PCILIB_ERROR_INVALID_ARGUMENT;
  148. }
  149. if (!val->unit) {
  150. pcilib_error("Can't convert value with the unspecified unit");
  151. return PCILIB_ERROR_INVALID_ARGUMENT;
  152. }
  153. pcilib_unit_t unit = pcilib_find_unit_by_name(ctx, val->unit);
  154. if (unit == PCILIB_UNIT_INVALID) {
  155. pcilib_error("Can't convert unrecognized unit %s", val->unit);
  156. return PCILIB_ERROR_NOTFOUND;
  157. }
  158. return pcilib_transform_unit_by_name(ctx, unit_name, val);
  159. }
  160. int pcilib_convert_value_type(pcilib_t *ctx, pcilib_value_t *val, pcilib_value_type_t type) {
  161. if (val->type == PCILIB_TYPE_INVALID) {
  162. pcilib_error("Can't convert uninitialized value");
  163. return PCILIB_ERROR_NOTINITIALIZED;
  164. }
  165. switch (type) {
  166. case PCILIB_TYPE_STRING:
  167. switch (val->type) {
  168. case PCILIB_TYPE_STRING:
  169. return 0;
  170. case PCILIB_TYPE_DOUBLE:
  171. sprintf(val->str, (val->format?val->format:"%lf"), val->fval);
  172. val->format = NULL;
  173. break;
  174. case PCILIB_TYPE_LONG:
  175. sprintf(val->str, (val->format?val->format:"%li"), val->ival);
  176. val->format = NULL;
  177. break;
  178. default:
  179. return PCILIB_ERROR_NOTSUPPORTED;
  180. }
  181. val->sval = val->str;
  182. break;
  183. case PCILIB_TYPE_DOUBLE:
  184. switch (val->type) {
  185. case PCILIB_TYPE_STRING:
  186. if (sscanf(val->sval, "%lf", &val->fval) != 1) {
  187. pcilib_warning("Can't convert string (%s) to float", val->sval);
  188. return PCILIB_ERROR_INVALID_DATA;
  189. }
  190. val->format = NULL;
  191. break;
  192. case PCILIB_TYPE_DOUBLE:
  193. return 0;
  194. case PCILIB_TYPE_LONG:
  195. val->fval = val->ival;
  196. val->format = NULL;
  197. break;
  198. default:
  199. return PCILIB_ERROR_NOTSUPPORTED;
  200. }
  201. break;
  202. case PCILIB_TYPE_LONG:
  203. switch (val->type) {
  204. case PCILIB_TYPE_STRING:
  205. if (pcilib_isnumber(val->sval)) {
  206. if (sscanf(val->sval, "%li", &val->ival) != 1) {
  207. pcilib_warning("Can't convert string (%s) to int", val->sval);
  208. return PCILIB_ERROR_INVALID_DATA;
  209. }
  210. val->format = NULL;
  211. } else if (pcilib_isxnumber(val->sval)) {
  212. if (sscanf(val->sval, "%lx", &val->ival) != 1) {
  213. pcilib_warning("Can't convert string (%s) to int", val->sval);
  214. return PCILIB_ERROR_INVALID_DATA;
  215. }
  216. val->format = "0x%lx";
  217. } else {
  218. pcilib_warning("Can't convert string (%s) to int", val->sval);
  219. return PCILIB_ERROR_INVALID_DATA;
  220. }
  221. break;
  222. case PCILIB_TYPE_DOUBLE:
  223. if (val->fval != round(val->fval))
  224. pcilib_info("Precision is lost while converting float value %lf to integer %.0lf", val->fval, round(val->fval));
  225. val->ival = round(val->fval);
  226. val->format = NULL;
  227. break;
  228. case PCILIB_TYPE_LONG:
  229. return 0;
  230. default:
  231. return PCILIB_ERROR_NOTSUPPORTED;
  232. }
  233. break;
  234. default:
  235. return PCILIB_ERROR_NOTSUPPORTED;
  236. }
  237. val->type = type;
  238. return 0;
  239. }