#include "plsr_position.h" #include #include uint8_t PlsrPositionUnitCodeIsValid(uint8_t unitCode) { return ((unitCode == 0U) || (unitCode == 1U) || (unitCode == 3U) || (unitCode == 5U) || (unitCode == 7U)) ? 1U : 0U; } uint8_t PlsrPositionUsesEquivalent(const PLSR_EQUIVALENT_CONFIG *config) { return ((config != NULL) && (config->unitCode != 0U)) ? 1U : 0U; } PLSR_RESULT PlsrPositionValidateEquivalent( const PLSR_EQUIVALENT_CONFIG *config) { if ((config == NULL) || (PlsrPositionUnitCodeIsValid(config->unitCode) == 0U)) { return PLSR_RESULT_INVALID_S2; } if ((config->unitCode != 0U) && ((config->pulsesPerRevolution == 0UL) || (config->movementPerRevolution == 0UL))) { return PLSR_RESULT_INVALID_S2; } return PLSR_RESULT_OK; } PLSR_RESULT PlsrPositionUnitsToPulses( const PLSR_EQUIVALENT_CONFIG *config, int32_t units, int64_t remainder, int64_t *pulses, int64_t *newRemainder) { int64_t numerator; int64_t pulseValue; uint32_t denominator; if ((pulses == NULL) || (newRemainder == NULL) || (PlsrPositionValidateEquivalent(config) != PLSR_RESULT_OK)) { return PLSR_RESULT_INVALID_ARGUMENT; } if (config->unitCode == 0U) { *pulses = units; *newRemainder = 0; return PLSR_RESULT_OK; } denominator = config->movementPerRevolution; if ((remainder <= -(int64_t)denominator) || (remainder >= (int64_t)denominator)) { return PLSR_RESULT_INVALID_ARGUMENT; } /* int32 * uint32 本身落在 int64 范围内;仅余数相加需要边界检查。 */ numerator = (int64_t)units * (int64_t)config->pulsesPerRevolution; if (((remainder > 0) && (numerator > INT64_MAX - remainder)) || ((remainder < 0) && (numerator < INT64_MIN - remainder))) { return PLSR_RESULT_POSITION_OVERFLOW; } numerator += remainder; pulseValue = numerator / (int64_t)denominator; *newRemainder = numerator % (int64_t)denominator; *pulses = pulseValue; return PLSR_RESULT_OK; } PLSR_RESULT PlsrPositionAbsoluteUnitsToPulses( const PLSR_EQUIVALENT_CONFIG *config, int32_t units, int64_t *pulses) { int64_t ignoredRemainder; return PlsrPositionUnitsToPulses(config, units, 0, pulses, &ignoredRemainder); } static uint64_t PlsrPositionMagnitude(int64_t value) { return (value < 0) ? (uint64_t)(-(value + 1)) + 1ULL : (uint64_t)value; } PLSR_RESULT PlsrPositionPulsesToUnits( const PLSR_EQUIVALENT_CONFIG *config, int64_t pulses, int64_t *units) { uint64_t magnitude; uint64_t quotient; uint64_t remainder; uint64_t whole; uint64_t fraction; uint64_t scaled; uint64_t numerator; uint64_t denominator; if ((units == NULL) || (PlsrPositionValidateEquivalent(config) != PLSR_RESULT_OK)) { return PLSR_RESULT_INVALID_ARGUMENT; } if (config->unitCode == 0U) { *units = pulses; return PLSR_RESULT_OK; } magnitude = PlsrPositionMagnitude(pulses); numerator = config->movementPerRevolution; denominator = config->pulsesPerRevolution; quotient = magnitude / denominator; remainder = magnitude % denominator; if ((quotient != 0ULL) && (numerator > UINT64_MAX / quotient)) { return PLSR_RESULT_POSITION_OVERFLOW; } whole = quotient * numerator; /* remainder 与 numerator 均为 uint32 范围,乘积不会超过 uint64。 */ fraction = (remainder * numerator) / denominator; if (whole > UINT64_MAX - fraction) { return PLSR_RESULT_POSITION_OVERFLOW; } scaled = whole + fraction; if ((pulses >= 0) && (scaled > (uint64_t)INT64_MAX)) { return PLSR_RESULT_POSITION_OVERFLOW; } if ((pulses < 0) && (scaled > (UINT64_C(1) << 63U))) { return PLSR_RESULT_POSITION_OVERFLOW; } if ((pulses < 0) && (scaled == (UINT64_C(1) << 63U))) { *units = INT64_MIN; } else { *units = (pulses < 0) ? -(int64_t)scaled : (int64_t)scaled; } return PLSR_RESULT_OK; } static PLSR_RESULT PlsrPositionScaleUnsigned(uint32_t value, uint32_t numerator, uint32_t denominator, uint32_t *result) { uint64_t product; uint64_t scaled; if ((result == NULL) || (denominator == 0UL)) { return PLSR_RESULT_INVALID_ARGUMENT; } product = (uint64_t)value * (uint64_t)numerator; /* 速度采用四舍五入;累计位置仍采用截断并由绝对累计避免漂移。 */ scaled = product / denominator; if ((product % denominator) >= ((uint64_t)denominator + 1ULL) / 2ULL) { scaled++; } if (scaled > UINT32_MAX) { return PLSR_RESULT_POSITION_OVERFLOW; } *result = (uint32_t)scaled; return PLSR_RESULT_OK; } PLSR_RESULT PlsrPositionSpeedToPulseFrequency( const PLSR_EQUIVALENT_CONFIG *config, uint32_t speed, uint32_t *frequencyHz) { if ((frequencyHz == NULL) || (PlsrPositionValidateEquivalent(config) != PLSR_RESULT_OK)) { return PLSR_RESULT_INVALID_ARGUMENT; } if (config->unitCode == 0U) { *frequencyHz = speed; return PLSR_RESULT_OK; } return PlsrPositionScaleUnsigned(speed, config->pulsesPerRevolution, config->movementPerRevolution, frequencyHz); } PLSR_RESULT PlsrPositionPulseFrequencyToSpeed( const PLSR_EQUIVALENT_CONFIG *config, uint32_t frequencyHz, uint32_t *speed) { if ((speed == NULL) || (PlsrPositionValidateEquivalent(config) != PLSR_RESULT_OK)) { return PLSR_RESULT_INVALID_ARGUMENT; } if (config->unitCode == 0U) { *speed = frequencyHz; return PLSR_RESULT_OK; } return PlsrPositionScaleUnsigned(frequencyHz, config->movementPerRevolution, config->pulsesPerRevolution, speed); }