#include #include #include #include #if 0 #define PRINTF(...) printf(__VA_ARGS__) #else #define PRINTF(...) do {} while (0) #endif static unsigned int isqrt(unsigned long x) { unsigned int r; unsigned int b2 = 0x40000000; unsigned int b = 0x8000; while(x < b2) { b2 >>= 2; b >>= 1; } if (b == 0) return 0; r = b; b >>= 1; while(b > 0) { r += b; unsigned int t = r*r; if (t > x) { r -= b; } b >>=1; } return r; } #define ACC_FIRST_UP 0 #define ACC_K1_UP 1 #define ACC_LAST_UP 2 #define ACC_TOP 3 #define ACC_FIRST_DOWN 4 #define ACC_K1_DOWN 5 #define ACC_LAST_DOWN 6 #define ACC_END 7 typedef struct _AccDiff AccDiff; struct _AccDiff { long diff; unsigned long pos; }; static inline long base_acc(unsigned long t,unsigned long n, unsigned long l, unsigned long a_max) { long a; if (t >= n) { if (t >= n+l) { a = -a_max; } else { a = 0; } } else { a = a_max; } return a; } static AccDiff acc[ACC_END+1]; StepperResult stepper_move(unsigned int stepper_index, unsigned long *periodp, unsigned long a_max,unsigned long v_max, long s_end) { unsigned long start_period = *periodp; unsigned long s; unsigned long ds; unsigned long l; unsigned long da0; unsigned long k1 = 0; unsigned long n = (v_max+a_max-1)/a_max; unsigned long a_speed_adj = v_max - (n-1)*a_max; unsigned long s_res; long d; if (s_end >= 0) { s_res = s_end/2; } else { s_res = (-s_end)/2; } d = s_res - (long)a_max*(n*n-1) - (long)a_speed_adj; acc[ACC_END].diff = 0; acc[ACC_END].pos = UINT_MAX; if (d < 0) { l = 0; n = isqrt(s_res/a_max); if (n*(unsigned long long)n*a_max < s_res) n++; a_speed_adj = a_max; acc[ACC_LAST_UP].diff=0; acc[ACC_FIRST_DOWN].diff=0; } else { l = (d+v_max-1)/v_max; acc[ACC_LAST_UP].diff= a_speed_adj - a_max; acc[ACC_FIRST_DOWN].diff= a_max - a_speed_adj; } acc[ACC_LAST_UP].pos = n-1; acc[ACC_FIRST_DOWN].pos = n+l; s = a_max*(n*n-1) + a_speed_adj + l * (a_max*(n-1) + a_speed_adj); ds = s-s_res; da0 = ds/(2*n+l-1); acc[ACC_FIRST_UP].diff = -da0; acc[ACC_LAST_DOWN].diff = da0; acc[ACC_FIRST_UP].pos = 0; acc[ACC_LAST_DOWN].pos = 2*n+l-1; ds -= da0*(2*n+l-1); acc[ACC_K1_UP].diff = 0; acc[ACC_K1_DOWN].diff = 0; acc[ACC_K1_UP].pos = 0; acc[ACC_K1_DOWN].pos = 2*n+l-1; acc[ACC_TOP].diff = 0; acc[ACC_TOP].pos = n; if (ds > 0) { k1 = (2*n+l -ds)/2; if (k1 < n) { acc[ACC_K1_UP].diff = -1; acc[ACC_K1_DOWN].diff = 1; acc[ACC_K1_UP].pos = k1; acc[ACC_K1_DOWN].pos = 2*n+l-1 - k1; ds -= (2*(n-k1)+l-1); } if (ds > 0) { acc[ACC_LAST_UP].diff--; acc[ACC_TOP].diff = 1; acc[ACC_TOP].pos = n+ds-1; } } #if 0 { unsigned int k; PRINTF("n=%ld l=%ld a_max=%ld v_max=%ld s_res=%ld\n", n,l ,a_max, v_max, s_res); for (k = 0; k < 7; k++) { PRINTF(" %ld@%ld", acc[k].diff, acc[k].pos); } PRINTF("\n"); } #endif { StepperResult res; unsigned int k; unsigned long t = 0; long da = 0; long a_prev = ULONG_MAX; for (k = 0; k < ACC_END; k++) { long a; da += acc[k].diff; if (acc[k].pos != acc[k+1].pos) { /* Next position is different */ if (t != acc[k].pos) { a = base_acc(t,n,l,a_max); if (s_end < 0) a = -a; if (a_prev != a) { res = stepper_add_acc(stepper_index, t+start_period, a); if (res != STEPPER_OK) return res; PRINTF("%d: %ld@%ld\n", stepper_index, a, t+start_period); a_prev = a; } t = acc[k].pos; } a = da + base_acc(t,n,l,a_max); if (s_end < 0) a = -a; if (a_prev != a) { res = stepper_add_acc(stepper_index, t+start_period, a); if (res != STEPPER_OK) return res; PRINTF("%d: %ld@%ld\n", stepper_index, a, t+start_period); a_prev = a; } t++; da = 0; } } res = stepper_add_acc(stepper_index, t+start_period, 0); PRINTF("%d: %d@%ld\n", stepper_index, 0, t+start_period); if (res != STEPPER_OK) return res; *periodp += t; } return STEPPER_OK; }