#include "rtapi.h"
#include "rtapi_app.h"
#include "hal.h"
#include <float.h>
#include "rtapi_math.h"
#define MAX_CHAN 16
#define MAX_CYCLE 18
#define USER_STEP_TYPE 13
MODULE_AUTHOR("John Kasunich");
MODULE_DESCRIPTION("Step Pulse Generator for EMC HAL");
MODULE_LICENSE("GPL");
int step_type[] = { [0 ... MAX_CHAN-1] = -1 } ;
RTAPI_MP_ARRAY_INT(step_type,MAX_CHAN,"stepping types for up to 16 channels");
char *ctrl_type[MAX_CHAN];
RTAPI_MP_ARRAY_STRING(ctrl_type,MAX_CHAN,"control type (pos or vel) for up to 16 channels");
int user_step_type[] = { [0 ... MAX_CYCLE-1] = -1 };
RTAPI_MP_ARRAY_INT(user_step_type, MAX_CYCLE,
"lookup table for user-defined step type");
typedef struct {
unsigned int timer1;
unsigned int timer2;
unsigned int timer3;
int hold_dds;
long addval;
volatile long long accum;
hal_s32_t rawcount;
int curr_dir;
int state;
hal_bit_t *enable;
long target_addval;
long deltalim;
hal_u32_t step_len;
hal_u32_t dir_hold_dly;
hal_u32_t dir_setup;
int step_type;
int cycle_max;
int num_phases;
hal_bit_t *phase[5];
const unsigned char *lut;
int pos_mode;
hal_u32_t step_space;
double old_pos_cmd;
hal_s32_t *count;
hal_float_t pos_scale;
double old_scale;
double scale_recip;
hal_float_t *vel_cmd;
hal_float_t *pos_cmd;
hal_float_t *pos_fb;
hal_float_t freq;
hal_float_t maxvel;
hal_float_t maxaccel;
hal_u32_t old_step_len;
hal_u32_t old_step_space;
hal_u32_t old_dir_hold_dly;
hal_u32_t old_dir_setup;
int printed_error;
} stepgen_t;
static stepgen_t *stepgen_array;
static unsigned char master_lut[][MAX_CYCLE] = {
{1, 3, 2, 0, 0, 0, 0, 0, 0, 0},
{1, 2, 4, 0, 0, 0, 0, 0, 0, 0},
{1, 3, 2, 6, 4, 5, 0, 0, 0, 0},
{1, 2, 4, 8, 0, 0, 0, 0, 0, 0},
{3, 6, 12, 9, 0, 0, 0, 0, 0, 0},
{1, 7, 14, 8, 0, 0, 0, 0, 0, 0},
{5, 6, 10, 9, 0, 0, 0, 0, 0, 0},
{1, 3, 2, 6, 4, 12, 8, 9, 0, 0},
{1, 5, 7, 6, 14, 10, 8, 9, 0, 0},
{1, 2, 4, 8, 16, 0, 0, 0, 0, 0},
{3, 6, 12, 24, 17, 0, 0, 0, 0, 0},
{1, 3, 2, 6, 4, 12, 8, 24, 16, 17},
{3, 7, 6, 14, 12, 28, 24, 25, 17, 19},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};
static unsigned char cycle_len_lut[] =
{ 4, 3, 6, 4, 4, 4, 4, 8, 8, 5, 5, 10, 10, 0 };
static unsigned char num_phases_lut[] =
{ 2, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 0, };
#define MAX_STEP_TYPE 15
#define STEP_PIN 0
#define DIR_PIN 1
#define UP_PIN 0
#define DOWN_PIN 1
#define PICKOFF 28
static int comp_id;
static int num_chan = 0;
static long periodns;
static long old_periodns;
static double periodfp;
static double freqscale;
static double accelscale;
static long old_dtns;
static double dt;
static double recip_dt;
typedef enum CONTROL { POSITION, VELOCITY, INVALID } CONTROL;
static int export_stepgen(int num, stepgen_t * addr, int step_type, int pos_mode);
static void make_pulses(void *arg, long period);
static void update_freq(void *arg, long period);
static void update_pos(void *arg, long period);
static int setup_user_step_type(void);
static CONTROL parse_ctrl_type(const char *ctrl);
int rtapi_app_main(void)
{
int n, retval;
retval = setup_user_step_type();
if(retval < 0) {
return retval;
}
for (n = 0; n < MAX_CHAN && step_type[n] != -1 ; n++) {
if ((step_type[n] > MAX_STEP_TYPE) || (step_type[n] < 0)) {
rtapi_print_msg(RTAPI_MSG_ERR,
"STEPGEN: ERROR: bad stepping type '%i', axis %i\n",
step_type[n], n);
return -1;
}
if(parse_ctrl_type(ctrl_type[n]) == INVALID) {
rtapi_print_msg(RTAPI_MSG_ERR,
"STEPGEN: ERROR: bad control type '%s' for axis %i (must be 'p' or 'v')\n",
ctrl_type[n], n);
return -1;
}
num_chan++;
}
if (num_chan == 0) {
rtapi_print_msg(RTAPI_MSG_ERR,
"STEPGEN: ERROR: no channels configured\n");
return -1;
}
old_periodns = periodns = 50000;
old_dtns = 1000000;
periodfp = periodns * 0.000000001;
freqscale = (1L << PICKOFF) * periodfp;
accelscale = freqscale * periodfp;
dt = old_dtns * 0.000000001;
recip_dt = 1.0 / dt;
comp_id = hal_init("stepgen");
if (comp_id < 0) {
rtapi_print_msg(RTAPI_MSG_ERR,
"STEPGEN: ERROR: hal_init() failed\n");
return -1;
}
stepgen_array = hal_malloc(num_chan * sizeof(stepgen_t));
if (stepgen_array == 0) {
rtapi_print_msg(RTAPI_MSG_ERR,
"STEPGEN: ERROR: hal_malloc() failed\n");
hal_exit(comp_id);
return -1;
}
for (n = 0; n < num_chan; n++) {
retval = export_stepgen(n, &(stepgen_array[n]),
step_type[n], (parse_ctrl_type(ctrl_type[n]) == POSITION));
if (retval != 0) {
rtapi_print_msg(RTAPI_MSG_ERR,
"STEPGEN: ERROR: stepgen %d var export failed\n", n);
hal_exit(comp_id);
return -1;
}
}
retval = hal_export_funct("stepgen.make-pulses", make_pulses,
stepgen_array, 0, 0, comp_id);
if (retval != 0) {
rtapi_print_msg(RTAPI_MSG_ERR,
"STEPGEN: ERROR: makepulses funct export failed\n");
hal_exit(comp_id);
return -1;
}
retval = hal_export_funct("stepgen.update-freq", update_freq,
stepgen_array, 1, 0, comp_id);
if (retval != 0) {
rtapi_print_msg(RTAPI_MSG_ERR,
"STEPGEN: ERROR: freq update funct export failed\n");
hal_exit(comp_id);
return -1;
}
retval = hal_export_funct("stepgen.capture-position", update_pos,
stepgen_array, 1, 0, comp_id);
if (retval != 0) {
rtapi_print_msg(RTAPI_MSG_ERR,
"STEPGEN: ERROR: pos update funct export failed\n");
hal_exit(comp_id);
return -1;
}
rtapi_print_msg(RTAPI_MSG_INFO,
"STEPGEN: installed %d step pulse generators\n", num_chan);
hal_ready(comp_id);
return 0;
}
void rtapi_app_exit(void)
{
hal_exit(comp_id);
}
static void make_pulses(void *arg, long period)
{
stepgen_t *stepgen;
long old_addval, target_addval, new_addval, step_now;
int n, p;
unsigned char outbits;
periodns = period;
stepgen = arg;
for (n = 0; n < num_chan; n++) {
if ( stepgen->timer1 > 0 ) {
if ( stepgen->timer1 > periodns ) {
stepgen->timer1 -= periodns;
} else {
stepgen->timer1 = 0;
}
}
if ( stepgen->timer2 > 0 ) {
if ( stepgen->timer2 > periodns ) {
stepgen->timer2 -= periodns;
} else {
stepgen->timer2 = 0;
}
}
if ( stepgen->timer3 > 0 ) {
if ( stepgen->timer3 > periodns ) {
stepgen->timer3 -= periodns;
} else {
stepgen->timer3 = 0;
stepgen->hold_dds = 0;
}
}
if ( !stepgen->hold_dds && *(stepgen->enable) ) {
old_addval = stepgen->addval;
target_addval = stepgen->target_addval;
if (stepgen->deltalim != 0) {
if (target_addval > (old_addval + stepgen->deltalim)) {
new_addval = old_addval + stepgen->deltalim;
} else if (target_addval < (old_addval - stepgen->deltalim)) {
new_addval = old_addval - stepgen->deltalim;
} else {
new_addval = target_addval;
}
} else {
new_addval = target_addval;
}
stepgen->addval = new_addval;
if (((new_addval >= 0) && (old_addval < 0)) ||
((new_addval < 0) && (old_addval >= 0))) {
if ( stepgen->timer3 != 0 ) {
stepgen->hold_dds = 1;
}
}
}
if ( !stepgen->hold_dds && *(stepgen->enable) ) {
step_now = stepgen->accum;
stepgen->accum += stepgen->addval;
step_now ^= stepgen->accum;
step_now &= (1L << PICKOFF);
stepgen->rawcount = stepgen->accum >> PICKOFF;
} else {
step_now = 0;
}
if ( stepgen->timer2 == 0 ) {
if ( stepgen->addval > 0 ) {
stepgen->curr_dir = 1;
} else if ( stepgen->addval < 0 ) {
stepgen->curr_dir = -1;
}
}
if ( step_now ) {
stepgen->timer1 = stepgen->step_len;
stepgen->timer2 = stepgen->timer1 + stepgen->dir_hold_dly;
stepgen->timer3 = stepgen->timer2 + stepgen->dir_setup;
if ( stepgen->step_type >= 2 ) {
stepgen->state += stepgen->curr_dir;
if ( stepgen->state < 0 ) {
stepgen->state = stepgen->cycle_max;
} else if ( stepgen->state > stepgen->cycle_max ) {
stepgen->state = 0;
}
}
}
if (stepgen->step_type == 0) {
if ( stepgen->timer1 != 0 ) {
*(stepgen->phase[STEP_PIN]) = 1;
} else {
*(stepgen->phase[STEP_PIN]) = 0;
}
if ( stepgen->curr_dir < 0 ) {
*(stepgen->phase[DIR_PIN]) = 1;
} else {
*(stepgen->phase[DIR_PIN]) = 0;
}
} else if (stepgen->step_type == 1) {
if ( stepgen->timer1 != 0 ) {
if ( stepgen->curr_dir < 0 ) {
*(stepgen->phase[UP_PIN]) = 0;
*(stepgen->phase[DOWN_PIN]) = 1;
} else {
*(stepgen->phase[UP_PIN]) = 1;
*(stepgen->phase[DOWN_PIN]) = 0;
}
} else {
*(stepgen->phase[UP_PIN]) = 0;
*(stepgen->phase[DOWN_PIN]) = 0;
}
} else {
outbits = (stepgen->lut)[stepgen->state];
for (p = 0; p < stepgen->num_phases; p++) {
*(stepgen->phase[p]) = outbits & 1;
outbits >>= 1;
}
}
stepgen++;
}
}
static void update_pos(void *arg, long period)
{
long long int accum_a, accum_b;
stepgen_t *stepgen;
int n;
stepgen = arg;
for (n = 0; n < num_chan; n++) {
do {
accum_a = stepgen->accum;
accum_b = stepgen->accum;
} while ( accum_a != accum_b );
*(stepgen->count) = accum_a >> PICKOFF;
if (stepgen->pos_scale != stepgen->old_scale) {
stepgen->old_scale = stepgen->pos_scale;
if ((stepgen->pos_scale < 1e-20)
&& (stepgen->pos_scale > -1e-20)) {
stepgen->pos_scale = 1.0;
}
stepgen->scale_recip = (1.0 / (1L << PICKOFF)) / stepgen->pos_scale;
}
*(stepgen->pos_fb) = (double)(accum_a-(1<< (PICKOFF-1))) * stepgen->scale_recip;
stepgen++;
}
}
static unsigned long ulceil(unsigned long value, unsigned long increment)
{
if ( value == 0 ) {
return 0;
}
return increment*(((value-1)/increment)+1);
}
static void update_freq(void *arg, long period)
{
stepgen_t *stepgen;
int n, newperiod;
long min_step_period;
long long int accum_a, accum_b;
double pos_cmd, vel_cmd, curr_pos, curr_vel, avg_v, max_freq, max_ac;
double match_ac, match_time, est_out, est_cmd, est_err, dp, dv, new_vel;
double desired_freq;
newperiod = 0;
if (periodns != old_periodns) {
old_periodns = periodns;
periodfp = periodns * 0.000000001;
freqscale = (1L << PICKOFF) * periodfp;
accelscale = freqscale * periodfp;
newperiod = 1;
}
if (period != old_dtns) {
old_dtns = period;
dt = period * 0.000000001;
recip_dt = 1.0 / dt;
}
stepgen = arg;
for (n = 0; n < num_chan; n++) {
if (stepgen->pos_scale != stepgen->old_scale) {
stepgen->old_scale = stepgen->pos_scale;
if ((stepgen->pos_scale < 1e-20)
&& (stepgen->pos_scale > -1e-20)) {
stepgen->pos_scale = 1.0;
}
stepgen->scale_recip = (1.0 / (1L << PICKOFF)) / stepgen->pos_scale;
}
if ( newperiod ) {
stepgen->old_step_len = ~0;
stepgen->old_step_space = ~0;
stepgen->old_dir_hold_dly = ~0;
stepgen->old_dir_setup = ~0;
}
if ( stepgen->step_len != stepgen->old_step_len ) {
if ( stepgen->step_len == 0 ) {
stepgen->step_len = 1;
}
stepgen->old_step_len = ulceil(stepgen->step_len, periodns);
stepgen->step_len = stepgen->old_step_len;
}
if ( stepgen->step_space != stepgen->old_step_space ) {
stepgen->old_step_space = ulceil(stepgen->step_space, periodns);
stepgen->step_space = stepgen->old_step_space;
}
if ( stepgen->dir_setup != stepgen->old_dir_setup ) {
stepgen->old_dir_setup = ulceil(stepgen->dir_setup, periodns);
stepgen->dir_setup = stepgen->old_dir_setup;
}
if ( stepgen->dir_hold_dly != stepgen->old_dir_hold_dly ) {
if ( (stepgen->dir_hold_dly + stepgen->dir_setup) == 0 ) {
if ( stepgen->step_type < 2 ) {
stepgen->dir_hold_dly = 1;
}
}
stepgen->old_dir_hold_dly = ulceil(stepgen->dir_hold_dly, periodns);
stepgen->dir_hold_dly = stepgen->old_dir_hold_dly;
}
if (*stepgen->enable == 0) {
if ( stepgen->pos_mode ) {
stepgen->old_pos_cmd = *stepgen->pos_cmd * stepgen->pos_scale;
}
stepgen->freq = 0;
stepgen->addval = 0;
stepgen->target_addval = 0;
stepgen++;
continue;
}
min_step_period = stepgen->step_len + stepgen->step_space;
max_freq = 1.0 / (min_step_period * 0.000000001);
if (stepgen->maxvel <= 0.0) {
stepgen->maxvel = 0.0;
} else {
desired_freq = stepgen->maxvel * fabs(stepgen->pos_scale);
if (desired_freq > max_freq) {
if(!stepgen->printed_error) {
rtapi_print_msg(RTAPI_MSG_ERR,
"STEPGEN: Channel %d: The requested maximum velocity of %d steps/sec is too high.\n",
n, (int)desired_freq);
rtapi_print_msg(RTAPI_MSG_ERR,
"STEPGEN: The maximum possible frequency is %d steps/second\n",
(int)max_freq);
stepgen->printed_error = 1;
}
stepgen->maxvel = max_freq / fabs(stepgen->pos_scale);
} else {
max_freq = stepgen->maxvel * fabs(stepgen->pos_scale);
}
}
max_ac = max_freq * recip_dt;
if (stepgen->maxaccel <= 0.0) {
stepgen->maxaccel = 0.0;
} else {
if ((stepgen->maxaccel * fabs(stepgen->pos_scale)) > max_ac) {
stepgen->maxaccel = max_ac / fabs(stepgen->pos_scale);
} else {
max_ac = stepgen->maxaccel * fabs(stepgen->pos_scale);
}
}
if ( stepgen->pos_mode ) {
pos_cmd = *stepgen->pos_cmd * stepgen->pos_scale;
vel_cmd = (pos_cmd - stepgen->old_pos_cmd) * recip_dt;
stepgen->old_pos_cmd = pos_cmd;
do {
accum_a = stepgen->accum;
accum_b = stepgen->accum;
} while ( accum_a != accum_b );
curr_pos = (accum_a-(1<< (PICKOFF-1))) * (1.0 / (1L << PICKOFF));
curr_vel = stepgen->freq;
if (vel_cmd > curr_vel) {
match_ac = max_ac;
} else {
match_ac = -max_ac;
}
match_time = (vel_cmd - curr_vel) / match_ac;
avg_v = (vel_cmd + curr_vel) * 0.5;
est_out = curr_pos + avg_v * match_time;
est_cmd = pos_cmd + vel_cmd * (match_time - 1.5 * dt);
est_err = est_out - est_cmd;
if (match_time < dt) {
if (fabs(est_err) < 0.0001) {
new_vel = vel_cmd;
} else {
new_vel = vel_cmd - 0.5 * est_err * recip_dt;
if (new_vel > (curr_vel + max_ac * dt)) {
new_vel = curr_vel + max_ac * dt;
} else if (new_vel < (curr_vel - max_ac * dt)) {
new_vel = curr_vel - max_ac * dt;
}
}
} else {
dv = -2.0 * match_ac * dt;
dp = dv * match_time;
if (fabs(est_err + dp * 2.0) < fabs(est_err)) {
match_ac = -match_ac;
}
new_vel = curr_vel + match_ac * dt;
}
if (new_vel > max_freq) {
new_vel = max_freq;
} else if (new_vel < -max_freq) {
new_vel = -max_freq;
}
} else {
vel_cmd = *(stepgen->vel_cmd) * stepgen->pos_scale;
if (vel_cmd > max_freq) {
vel_cmd = max_freq;
} else if (vel_cmd < -max_freq) {
vel_cmd = -max_freq;
}
dv = max_ac * dt;
if ( vel_cmd > (stepgen->freq + dv) ) {
new_vel = stepgen->freq + dv;
} else if ( vel_cmd < (stepgen->freq - dv) ) {
new_vel = stepgen->freq - dv;
} else {
new_vel = vel_cmd;
}
}
stepgen->freq = new_vel;
stepgen->target_addval = stepgen->freq * freqscale;
stepgen->deltalim = max_ac * accelscale;
stepgen++;
}
}
static int export_stepgen(int num, stepgen_t * addr, int step_type, int pos_mode)
{
int n, retval, msg;
msg = rtapi_get_msg_level();
rtapi_set_msg_level(RTAPI_MSG_WARN);
retval = hal_param_s32_newf(HAL_RO, &(addr->rawcount), comp_id,
"stepgen.%d.rawcounts", num);
if (retval != 0) { return retval; }
retval = hal_pin_s32_newf(HAL_OUT, &(addr->count), comp_id,
"stepgen.%d.counts", num);
if (retval != 0) { return retval; }
retval = hal_param_float_newf(HAL_RW, &(addr->pos_scale), comp_id,
"stepgen.%d.position-scale", num);
if (retval != 0) { return retval; }
if ( pos_mode ) {
retval = hal_pin_float_newf(HAL_IN, &(addr->pos_cmd), comp_id,
"stepgen.%d.position-cmd", num);
} else {
retval = hal_pin_float_newf(HAL_IN, &(addr->vel_cmd), comp_id,
"stepgen.%d.velocity-cmd", num);
}
if (retval != 0) { return retval; }
retval = hal_pin_bit_newf(HAL_IN, &(addr->enable), comp_id,
"stepgen.%d.enable", num);
if (retval != 0) { return retval; }
retval = hal_pin_float_newf(HAL_OUT, &(addr->pos_fb), comp_id,
"stepgen.%d.position-fb", num);
if (retval != 0) { return retval; }
retval = hal_param_float_newf(HAL_RO, &(addr->freq), comp_id,
"stepgen.%d.frequency", num);
if (retval != 0) { return retval; }
retval = hal_param_float_newf(HAL_RW, &(addr->maxvel), comp_id,
"stepgen.%d.maxvel", num);
if (retval != 0) { return retval; }
retval = hal_param_float_newf(HAL_RW, &(addr->maxaccel), comp_id,
"stepgen.%d.maxaccel", num);
if (retval != 0) { return retval; }
retval = hal_param_u32_newf(HAL_RW, &(addr->step_len), comp_id,
"stepgen.%d.steplen", num);
if (retval != 0) { return retval; }
if (step_type < 2) {
retval = hal_param_u32_newf(HAL_RW, &(addr->step_space),
comp_id, "stepgen.%d.stepspace", num);
if (retval != 0) { return retval; }
}
if ( step_type == 0 ) {
retval = hal_param_u32_newf(HAL_RW, &(addr->dir_setup),
comp_id, "stepgen.%d.dirsetup", num);
if (retval != 0) { return retval; }
retval = hal_param_u32_newf(HAL_RW, &(addr->dir_hold_dly),
comp_id, "stepgen.%d.dirhold", num);
if (retval != 0) { return retval; }
} else {
retval = hal_param_u32_newf(HAL_RW, &(addr->dir_hold_dly),
comp_id, "stepgen.%d.dirdelay", num);
if (retval != 0) { return retval; }
}
if ( step_type == 0 ) {
retval = hal_pin_bit_newf(HAL_OUT, &(addr->phase[STEP_PIN]),
comp_id, "stepgen.%d.step", num);
if (retval != 0) { return retval; }
*(addr->phase[STEP_PIN]) = 0;
retval = hal_pin_bit_newf(HAL_OUT, &(addr->phase[DIR_PIN]),
comp_id, "stepgen.%d.dir", num);
if (retval != 0) { return retval; }
*(addr->phase[DIR_PIN]) = 0;
} else if (step_type == 1) {
retval = hal_pin_bit_newf(HAL_OUT, &(addr->phase[UP_PIN]),
comp_id, "stepgen.%d.up", num);
if (retval != 0) { return retval; }
*(addr->phase[UP_PIN]) = 0;
retval = hal_pin_bit_newf(HAL_OUT, &(addr->phase[DOWN_PIN]),
comp_id, "stepgen.%d.down", num);
if (retval != 0) { return retval; }
*(addr->phase[DOWN_PIN]) = 0;
} else {
addr->num_phases = num_phases_lut[step_type - 2];
for (n = 0; n < addr->num_phases; n++) {
retval = hal_pin_bit_newf(HAL_OUT, &(addr->phase[n]),
comp_id, "stepgen.%d.phase-%c", num, n + 'A');
if (retval != 0) { return retval; }
*(addr->phase[n]) = 0;
}
}
addr->pos_scale = 1.0;
addr->old_scale = 0.0;
addr->scale_recip = 0.0;
addr->freq = 0.0;
addr->maxvel = 0.0;
addr->maxaccel = 0.0;
addr->step_type = step_type;
addr->pos_mode = pos_mode;
addr->step_len = 1;
if ( step_type < 2 ) {
addr->step_space = 1;
} else {
addr->step_space = 0;
}
if ( step_type == 0 ) {
addr->dir_hold_dly = 1;
addr->dir_setup = 1;
} else {
addr->dir_hold_dly = 1;
addr->dir_setup = 0;
}
addr->old_step_len = ~0;
addr->old_step_space = ~0;
addr->old_dir_hold_dly = ~0;
addr->old_dir_setup = ~0;
if ( step_type >= 2 ) {
addr->cycle_max = cycle_len_lut[step_type - 2] - 1;
addr->lut = &(master_lut[step_type - 2][0]);
}
addr->timer1 = 0;
addr->timer2 = 0;
addr->timer3 = 0;
addr->hold_dds = 0;
addr->addval = 0;
addr->accum = 1 << (PICKOFF-1);
addr->rawcount = 0;
addr->curr_dir = 0;
addr->state = 0;
*(addr->enable) = 0;
addr->target_addval = 0;
addr->deltalim = 0;
addr->printed_error = 0;
addr->old_pos_cmd = 0.0;
*(addr->count) = 0;
*(addr->pos_fb) = 0.0;
if ( pos_mode ) {
*(addr->pos_cmd) = 0.0;
} else {
*(addr->vel_cmd) = 0.0;
}
rtapi_set_msg_level(msg);
return 0;
}
static int setup_user_step_type(void) {
int used_phases = 0;
int i = 0;
for(i=0; i<10 && user_step_type[i] != -1; i++) {
master_lut[USER_STEP_TYPE][i] = user_step_type[i];
used_phases |= user_step_type[i];
}
cycle_len_lut[USER_STEP_TYPE] = i;
if(used_phases & ~0x1f) {
rtapi_print_msg(RTAPI_MSG_ERR, "STEPGEN: ERROR: "
"bad user step type uses more than 5 phases");
return -EINVAL; }
if(used_phases & 0x10) num_phases_lut[USER_STEP_TYPE] = 5;
else if(used_phases & 0x8) num_phases_lut[USER_STEP_TYPE] = 4;
else if(used_phases & 0x4) num_phases_lut[USER_STEP_TYPE] = 3;
else if(used_phases & 0x2) num_phases_lut[USER_STEP_TYPE] = 2;
else if(used_phases & 0x1) num_phases_lut[USER_STEP_TYPE] = 1;
if(used_phases)
rtapi_print_msg(RTAPI_MSG_INFO,
"User step type has %d phases and %d steps per cycle\n",
num_phases_lut[USER_STEP_TYPE], i);
return 0;
}
static CONTROL parse_ctrl_type(const char *ctrl)
{
if(!ctrl || !*ctrl || *ctrl == 'p' || *ctrl == 'P') return POSITION;
if(*ctrl == 'v' || *ctrl == 'V') return VELOCITY;
return INVALID;
}