25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 
 
 
 

228 satır
6.4 KiB

  1. #include "plsr_position.h"
  2. #include <limits.h>
  3. #include <stddef.h>
  4. uint8_t PlsrPositionUnitCodeIsValid(uint8_t unitCode)
  5. {
  6. return ((unitCode == 0U) || (unitCode == 1U) || (unitCode == 3U)
  7. || (unitCode == 5U) || (unitCode == 7U))
  8. ? 1U
  9. : 0U;
  10. }
  11. uint8_t PlsrPositionUsesEquivalent(const PLSR_EQUIVALENT_CONFIG *config)
  12. {
  13. return ((config != NULL) && (config->unitCode != 0U)) ? 1U : 0U;
  14. }
  15. PLSR_RESULT PlsrPositionValidateEquivalent(
  16. const PLSR_EQUIVALENT_CONFIG *config)
  17. {
  18. if ((config == NULL)
  19. || (PlsrPositionUnitCodeIsValid(config->unitCode) == 0U))
  20. {
  21. return PLSR_RESULT_INVALID_S2;
  22. }
  23. if ((config->unitCode != 0U)
  24. && ((config->pulsesPerRevolution == 0UL)
  25. || (config->movementPerRevolution == 0UL)))
  26. {
  27. return PLSR_RESULT_INVALID_S2;
  28. }
  29. return PLSR_RESULT_OK;
  30. }
  31. PLSR_RESULT PlsrPositionUnitsToPulses(
  32. const PLSR_EQUIVALENT_CONFIG *config,
  33. int32_t units,
  34. int64_t remainder,
  35. int64_t *pulses,
  36. int64_t *newRemainder)
  37. {
  38. int64_t numerator;
  39. int64_t pulseValue;
  40. uint32_t denominator;
  41. if ((pulses == NULL) || (newRemainder == NULL)
  42. || (PlsrPositionValidateEquivalent(config) != PLSR_RESULT_OK))
  43. {
  44. return PLSR_RESULT_INVALID_ARGUMENT;
  45. }
  46. if (config->unitCode == 0U)
  47. {
  48. *pulses = units;
  49. *newRemainder = 0;
  50. return PLSR_RESULT_OK;
  51. }
  52. denominator = config->movementPerRevolution;
  53. if ((remainder <= -(int64_t)denominator)
  54. || (remainder >= (int64_t)denominator))
  55. {
  56. return PLSR_RESULT_INVALID_ARGUMENT;
  57. }
  58. /* int32 * uint32 本身落在 int64 范围内;仅余数相加需要边界检查。 */
  59. numerator = (int64_t)units
  60. * (int64_t)config->pulsesPerRevolution;
  61. if (((remainder > 0) && (numerator > INT64_MAX - remainder))
  62. || ((remainder < 0) && (numerator < INT64_MIN - remainder)))
  63. {
  64. return PLSR_RESULT_POSITION_OVERFLOW;
  65. }
  66. numerator += remainder;
  67. pulseValue = numerator / (int64_t)denominator;
  68. *newRemainder = numerator % (int64_t)denominator;
  69. *pulses = pulseValue;
  70. return PLSR_RESULT_OK;
  71. }
  72. PLSR_RESULT PlsrPositionAbsoluteUnitsToPulses(
  73. const PLSR_EQUIVALENT_CONFIG *config,
  74. int32_t units,
  75. int64_t *pulses)
  76. {
  77. int64_t ignoredRemainder;
  78. return PlsrPositionUnitsToPulses(config,
  79. units,
  80. 0,
  81. pulses,
  82. &ignoredRemainder);
  83. }
  84. static uint64_t PlsrPositionMagnitude(int64_t value)
  85. {
  86. return (value < 0) ? (uint64_t)(-(value + 1)) + 1ULL
  87. : (uint64_t)value;
  88. }
  89. PLSR_RESULT PlsrPositionPulsesToUnits(
  90. const PLSR_EQUIVALENT_CONFIG *config,
  91. int64_t pulses,
  92. int64_t *units)
  93. {
  94. uint64_t magnitude;
  95. uint64_t quotient;
  96. uint64_t remainder;
  97. uint64_t whole;
  98. uint64_t fraction;
  99. uint64_t scaled;
  100. uint64_t numerator;
  101. uint64_t denominator;
  102. if ((units == NULL)
  103. || (PlsrPositionValidateEquivalent(config) != PLSR_RESULT_OK))
  104. {
  105. return PLSR_RESULT_INVALID_ARGUMENT;
  106. }
  107. if (config->unitCode == 0U)
  108. {
  109. *units = pulses;
  110. return PLSR_RESULT_OK;
  111. }
  112. magnitude = PlsrPositionMagnitude(pulses);
  113. numerator = config->movementPerRevolution;
  114. denominator = config->pulsesPerRevolution;
  115. quotient = magnitude / denominator;
  116. remainder = magnitude % denominator;
  117. if ((quotient != 0ULL) && (numerator > UINT64_MAX / quotient))
  118. {
  119. return PLSR_RESULT_POSITION_OVERFLOW;
  120. }
  121. whole = quotient * numerator;
  122. /* remainder 与 numerator 均为 uint32 范围,乘积不会超过 uint64。 */
  123. fraction = (remainder * numerator) / denominator;
  124. if (whole > UINT64_MAX - fraction)
  125. {
  126. return PLSR_RESULT_POSITION_OVERFLOW;
  127. }
  128. scaled = whole + fraction;
  129. if ((pulses >= 0) && (scaled > (uint64_t)INT64_MAX))
  130. {
  131. return PLSR_RESULT_POSITION_OVERFLOW;
  132. }
  133. if ((pulses < 0) && (scaled > (UINT64_C(1) << 63U)))
  134. {
  135. return PLSR_RESULT_POSITION_OVERFLOW;
  136. }
  137. if ((pulses < 0) && (scaled == (UINT64_C(1) << 63U)))
  138. {
  139. *units = INT64_MIN;
  140. }
  141. else
  142. {
  143. *units = (pulses < 0) ? -(int64_t)scaled : (int64_t)scaled;
  144. }
  145. return PLSR_RESULT_OK;
  146. }
  147. static PLSR_RESULT PlsrPositionScaleUnsigned(uint32_t value,
  148. uint32_t numerator,
  149. uint32_t denominator,
  150. uint32_t *result)
  151. {
  152. uint64_t product;
  153. uint64_t scaled;
  154. if ((result == NULL) || (denominator == 0UL))
  155. {
  156. return PLSR_RESULT_INVALID_ARGUMENT;
  157. }
  158. product = (uint64_t)value * (uint64_t)numerator;
  159. /* 速度采用四舍五入;累计位置仍采用截断并由绝对累计避免漂移。 */
  160. scaled = product / denominator;
  161. if ((product % denominator) >= ((uint64_t)denominator + 1ULL) / 2ULL)
  162. {
  163. scaled++;
  164. }
  165. if (scaled > UINT32_MAX)
  166. {
  167. return PLSR_RESULT_POSITION_OVERFLOW;
  168. }
  169. *result = (uint32_t)scaled;
  170. return PLSR_RESULT_OK;
  171. }
  172. PLSR_RESULT PlsrPositionSpeedToPulseFrequency(
  173. const PLSR_EQUIVALENT_CONFIG *config,
  174. uint32_t speed,
  175. uint32_t *frequencyHz)
  176. {
  177. if ((frequencyHz == NULL)
  178. || (PlsrPositionValidateEquivalent(config) != PLSR_RESULT_OK))
  179. {
  180. return PLSR_RESULT_INVALID_ARGUMENT;
  181. }
  182. if (config->unitCode == 0U)
  183. {
  184. *frequencyHz = speed;
  185. return PLSR_RESULT_OK;
  186. }
  187. return PlsrPositionScaleUnsigned(speed,
  188. config->pulsesPerRevolution,
  189. config->movementPerRevolution,
  190. frequencyHz);
  191. }
  192. PLSR_RESULT PlsrPositionPulseFrequencyToSpeed(
  193. const PLSR_EQUIVALENT_CONFIG *config,
  194. uint32_t frequencyHz,
  195. uint32_t *speed)
  196. {
  197. if ((speed == NULL)
  198. || (PlsrPositionValidateEquivalent(config) != PLSR_RESULT_OK))
  199. {
  200. return PLSR_RESULT_INVALID_ARGUMENT;
  201. }
  202. if (config->unitCode == 0U)
  203. {
  204. *speed = frequencyHz;
  205. return PLSR_RESULT_OK;
  206. }
  207. return PlsrPositionScaleUnsigned(frequencyHz,
  208. config->movementPerRevolution,
  209. config->pulsesPerRevolution,
  210. speed);
  211. }