25 Mar 09:34
machctl: r24 - sys
Author: vedge
Date: 2009-03-25 05:34:44 -0300 (Wed, 25 Mar 2009)
New Revision: 24
Added:
sys/cnc_fixunssfdi.c
sys/cnc_quad.h
Modified:
sys/cnc.c
sys/cnc.h
sys/cnc_device.c
sys/cnc_devicevar.h
sys/cnc_estop.c
sys/cnc_estopvar.h
sys/cnc_math.c
sys/cnc_math.h
sys/cnc_servo.c
sys/cnc_servovar.h
sys/cnc_spindle.c
sys/cnc_spindlevar.h
sys/files.cnc
Log:
- rewrite MOVE op for proper n-axis support.
- implement JOG op (using registered mpg(4) devices).
- report execution status to cnclcd(4) and cncstatled(4) devices.
- new ioctls CNC_{GET,SET,CAL}TIMINGS.
Modified: sys/cnc.c
===================================================================
--- sys/cnc.c 2009-03-25 08:24:59 UTC (rev 23)
+++ sys/cnc.c 2009-03-25 08:34:44 UTC (rev 24)
<at> <at> -1,7 +1,5 <at> <at>
-/* $OpenBSD$ */
-
/*
- * Copyright (c) 2007 Hypertriton, Inc. <http://www.hypertriton.com/>
+ * Copyright (c) 2007-2009 Hypertriton, Inc. <http://www.hypertriton.com/>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
<at> <at> -46,21 +44,47 <at> <at>
#include <dev/gpio/gpiovar.h>
+#include <machine/bus.h>
+
#include "cnc_devicevar.h"
#include "cnc_servovar.h"
+#include "cnc_spindlevar.h"
#include "cnc_estopvar.h"
-#include "cnc_spindlevar.h"
+#include "cnc_encodervar.h"
+#include "cnc_mpgvar.h"
+#include "cnc_statledvar.h"
+#include "cnc_lcdvar.h"
+
#include "cncvar.h"
+#include "servo.h"
+#include "spindle.h"
+#include "estop.h"
+#include "encoder.h"
+#include "mpg.h"
+#include "cnclcd.h"
+#include "cncstatled.h"
+
#define STEPMAX (INT64_MAX-1)
#define STEPLEN 20336 /* 20336 units = 1 step */
#define MAXSTEPS (STEPMAX/STEPLEN)
-cnc_real_t cnc_Vmax = 2000.0; /* maximum velocity (steps/sec) */
-u_long cnc_timebase = 0; /* delay loop calibration */
+struct cnc_kinlimits cnc_kinlimits = {
+ 20000, /* Max steps/sec */
+ 200000, /* Max steps/ms^2 */
+ 8000000 /* Max steps/ms^3 */
+};
+const char *cnc_axis_names[] = {
+ "X", "Y", "Z", /* Primary axes */
+ "U", "V", "W", /* Secondary axes */
+ "I", "J", "K", /* Arc center vectors */
+ "A", "B", "C" /* Rotary axes */
+};
+
const char *cnc_insn_names[] = {
"MOVE",
+ "JOG",
"SET_INTERP",
"SPINDLE_DIR",
"SPINDLE_SPEED",
<at> <at> -85,13 +109,22 <at> <at>
int cnc_opened;
TAILQ_HEAD(,cnc_insn) cnc_prog;
struct cnc_vector cnc_pos;
-struct cnc_device *cnc_servos[CNC_NAXES];
-struct cnc_device *cnc_spindles[CNC_MAX_SPINDLES];
-struct cnc_device *cnc_estops[CNC_MAX_ESTOPS];
-struct cnc_device *cnc_estop;
+struct cnc_timings cnc_timings;
+
+struct servo_softc *cnc_servos[CNC_MAX_SERVOS];
+struct spindle_softc *cnc_spindles[CNC_MAX_SPINDLES];
+struct estop_softc *cnc_estops[CNC_MAX_ESTOPS];
+struct encoder_softc *cnc_encoders[CNC_MAX_ENCODERS];
+struct mpg_softc *cnc_mpgs[CNC_MAX_MPGS];
+struct cnclcd_softc *cnc_lcds[CNC_MAX_LCDS];
+struct cncstatled_softc *cnc_status_led = NULL;
+
int cnc_nservos = 0;
int cnc_nspindles = 0;
int cnc_nestops = 0;
+int cnc_nencoders = 0;
+int cnc_nmpgs = 0;
+int cnc_nlcds = 0;
void
cncattach(int num)
<at> <at> -101,8 +134,6 <at> <at>
if (num > 1)
return;
- printf("cnc: STEPLEN=%u, Vmax = %d steps/s\n",
- (u_int)STEPLEN, (int)cnc_Vmax);
cnc_opened = 0;
pool_init(&cnc_insnpl, sizeof(struct cnc_insn), 0, 0, 0, "cncinsnpl",
NULL);
<at> <at> -111,11 +142,19 <at> <at>
for (i = 0; i < CNC_NAXES; i++)
cnc_pos.v[i] = 0;
+
+ cnc_timings.hz = 0;
+ cnc_timings.move_jog = 0;
}
int
cncdetach(struct device *self, int flags)
{
+#if NCNCLCD > 0
+ int i;
+ for (i = 0; i < cnc_nlcds; i++)
+ cnclcd_close(cnc_lcds[i]);
+#endif
cnc_prog_reset();
return (0);
}
<at> <at> -144,22 +183,12 <at> <at>
return (0);
}
-struct cnc_device *
-cnc_get_spindle(int id)
-{
- if (id < 0 || id >= cnc_nspindles) {
- return (NULL);
- }
- return (cnc_spindles[id]);
-}
-
int
cncwrite(dev_t dev, struct uio *uio, int ioflag)
{
const char *cause;
struct cnc_insn insn, *iNew;
u_int ip = 0;
- void *p;
while (uio->uio_resid > 0) {
int rv;
<at> <at> -178,6 +207,7 <at> <at>
* before it is executed.
*/
switch (insn.i_type) {
+#if NSERVO > 0
case CNC_MOVE:
if (cnc_vec_distance(&cnc_pos, &insn.i_pos) == 0) {
cause = "L=0";
<at> <at> -186,6 +216,14 <at> <at>
if (insn.i_Amax == 0) { cause = "Amax=0"; goto fail; }
if (insn.i_Jmax == 0) { cause = "Jmax=0"; goto fail; }
break;
+ case CNC_JOG:
+ break;
+#else
+ case CNC_MOVE:
+ case CNC_JOG:
+ cause = "no servo devices available";
+ goto fail;
+#endif /* NSERVO */
case CNC_SET_INTERP:
if (insn.i_interp_mode < 0 ||
insn.i_interp_mode >= CNC_INTERP_LAST) {
<at> <at> -193,8 +231,9 <at> <at>
goto fail;
}
break;
+#if NSPINDLE > 0
case CNC_SPINDLE_DIR:
- if (cnc_get_spindle(insn.i_spindle_id) == NULL) {
+ if (spindle_find(insn.i_spindle_id) == NULL) {
cause = "no such spindle";
goto fail;
}
<at> <at> -205,25 +244,37 <at> <at>
}
break;
case CNC_SPINDLE_SPEED:
- if ((p = cnc_get_spindle(insn.i_spindle_id)) == NULL) {
- cause = "no such spindle";
- goto fail;
- } else {
- struct spindle_softc *sc = p;
+ {
+ struct spindle_soft *sp;
- if (insn.i_spindle_speed > sc->sc_speed_max) {
- cause = "speed exceeds spindle limit";
+ if ((sp = spindle_find(insn.i_spindle_id)) != NULL) {
+ if (insn.i_spindle_speed > sp->sc_speed_max) {
+ cause = "requested speed exceeds "
+ "spindle capabilities";
+ goto fail;
+ }
+ } else {
+ cause = "no such spindle";
goto fail;
}
}
break;
case CNC_SPINDLE_START:
case CNC_SPINDLE_STOP:
- if ((p = cnc_get_spindle(insn.i_spindle_id)) == NULL) {
+ if (spindle_find(insn.i_spindle_id) == NULL) {
cause = "no such spindle";
goto fail;
}
break;
+#else /* NSPINDLE */
+ case CNC_SPINDLE_DIR:
+ case CNC_SPINDLE_SPEED:
+ case CNC_SPINDLE_START:
+ case CNC_SPINDLE_STOP:
+ cause = "no spindle devices available";
+ goto fail;
+#endif /* NSPINDLE */
+
default:
break;
}
<at> <at> -235,7 +286,7 <at> <at>
TAILQ_INSERT_TAIL(&cnc_prog, iNew, prog);
ip++;
}
- printf("cnc: added %u insns to queue\n", ip);
+ printf("cnc: added %u insns to program queue\n", ip);
return (0);
fail:
printf("%s[%d]: %s\n", cnc_insn_names[insn.i_type], ip, cause);
<at> <at> -254,8 +305,26 <at> <at>
ninsns++;
}
/* printf("cnc: deleted %u insns\n", ninsns); */
+#if NCNCSTATLED > 0
+ cncstatled_set(0);
+#endif
}
+void
+cnc_message(const char *msg)
+{
+#if NCNCLCD > 0
+ int i;
+ for (i = 0; i < cnc_nlcds; i++) {
+ struct cnclcd_softc *lcd = cnc_lcds[i];
+ if (lcd->sc_open) {
+ cnclcd_puts(lcd, msg);
+ cnclcd_putc(lcd, '\n');
+ }
+ }
+#endif
+}
+
int
cnc_prog_exec(void)
{
<at> <at> -263,102 +332,207 <at> <at>
u_int ninsns = 0;
int s;
+ s = splhigh();
+
+#if NCNCSTATLED > 0
+ /* Initialize error LEDs and establish communication with LCDs. */
+ cncstatled_set(0);
+#endif
+
+#if NCNCLCD > 0
+ {
+ int i;
+
+ for (i = 0; i < cnc_nlcds; i++) {
+ struct cnclcd_softc *lcd = cnc_lcds[i];
+
+ if (!lcd->sc_open &&
+ cnclcd_open(cnc_lcds[i], 9600, 7, CNCLCD_PEVEN, 1) == -1) {
+ printf("%s: cannot open\n", ((struct device *)lcd)->dv_xname);
+ continue;
+ }
+ cnclcd_puts(lcd, ((struct device *)lcd)->dv_xname);
+ cnclcd_putc(lcd, '\n');
+ }
+ }
+#endif
+
+ if (cnc_timings.hz == 0 || cnc_timings.move_jog == 0) {
+ printf("cnc: timings are not calibrated!\n");
+ goto fail;
+ }
if (cnc_nservos != CNC_NAXES) {
+ /* XXX */
printf("cnc: nservos=%d, but CNC_NAXES=%d\n", cnc_nservos,
CNC_NAXES);
- return (EIO);
+ goto fail;
}
-
- printf("cnc: executing program\n");
-
- s = splclock();
+ cnc_message("Executing program\n");
TAILQ_FOREACH(insn, &cnc_prog, prog) {
+ if (insn->i_type >= CNC_LAST_INSN) {
+ continue;
+ }
+ cnc_message(cnc_insn_names[insn->i_type]);
+ cnc_message("\n");
switch (insn->i_type) {
+#if NSERVO > 0
case CNC_MOVE:
if (cnc_move(insn) == -1) {
goto fail;
}
break;
+# if NMPG > 0
+ case CNC_JOG:
+ if (cnc_nmpgs < 1) {
+ printf("cnc: JOG: no MPGs are available\n");
+ goto fail;
+ }
+ if (insn->i_mult == 1) {
+ if (cnc_move_jog_singlestep(insn) == -1)
+ goto fail;
+ } else {
+ if (cnc_move_jog(insn, 0) == -1)
+ goto fail;
+ }
+ break;
+# endif /* NMPG */
+#endif /* NSERVO */
+
#if NSPINDLE > 0
case CNC_SPINDLE_START:
- spindle_start(cnc_spindles[insn->i_spindle_id], insn);
+ if (spindle_start(cnc_spindles[insn->i_spindle_id],
+ insn) == -1) {
+ goto fail;
+ }
break;
case CNC_SPINDLE_STOP:
- spindle_stop(cnc_spindles[insn->i_spindle_id], insn);
+ if (spindle_stop(cnc_spindles[insn->i_spindle_id],
+ insn) == -1) {
+ goto fail;
+ }
break;
case CNC_SPINDLE_SPEED:
- spindle_speed(cnc_spindles[insn->i_spindle_id], insn);
+ if (spindle_speed(cnc_spindles[insn->i_spindle_id],
+ insn) == -1) {
+ goto fail;
+ }
break;
-#endif
+#endif /* NSPINDLE */
+
default:
+ printf("cnc: illegal instruction 0x%x\n", insn->i_type);
break;
}
- printf("insn %u: type=%d\n", ninsns, insn->i_type);
ninsns++;
}
+#if 0
+ {
+ int i;
+
+ for (i = 0; i < cnc_nlcds; i++) {
+ struct cnclcd_softc *lcd = cnc_lcds[i];
+ if (lcd->sc_open)
+ cnclcd_close(lcd);
+ }
+ }
+#endif
splx(s);
return (0);
fail:
+#if NCNCSTATLED > 0
+ cncstatled_set(1);
+#endif
splx(s);
return (EIO);
}
-/*
- * Try to calibrate cnc_timebase to a value that will give us as
- * close as possible to 1 second. There is no portable way to do
- * this so we repeatedly benchmark results of a real delay loop
- * until the error is reduced to a minimum.
- *
- * This can take a while, but only needs to be run once on any
- * given machine.
- *
- * XXX the algorithm should be optimized based on the rate of change
- * in the results.
- */
-u_long
-cnc_calibrate_timebase(void)
+/* Calibrate the delay loop for 1Hz reference. */
+cnc_utime_t
+cnc_calibrate_hz(void)
{
+ const int maxIters = 100;
+ const cnc_utime_t tTgt = 1e6; /* 1s */
struct timeval tv1, tv2;
- long ds, du, d;
- u_long timebase = 10000000, i;
+ cnc_utime_t t, r, i;
+ cnc_time_t d;
int s, j;
+ /* Start from an arbitrary value. XXX TODO use cpu info */
+ r = 380000000U;
+
s = splhigh();
- printf("cnc: calibrating timebase...");
- for (j = 0; j < 500; j++) {
+ printf("cnc: calibrating delay loop for 1Hz (%d iters max)...",
+ maxIters);
+ for (j = 0; j < maxIters; j++) {
microtime(&tv1);
- for (i = 0; i < timebase; i++)
+ for (i = 0; i < r; i++)
;;
microtime(&tv2);
- ds = tv2.tv_sec - tv1.tv_sec;
- du = tv2.tv_usec - tv1.tv_usec;
- printf(" %ld", 1000000-du);
- if (ds < 0) {
- timebase += 1000000;
- } else if (ds > 0) {
- timebase -= 1000000;
- } else if (ds == 0 && du < 1000000) {
- d = 1000000 - du;
- timebase += d*4;
+ t = (tv2.tv_sec - tv1.tv_sec)*1e6 +
+ (tv2.tv_usec - tv1.tv_usec);
+
+ printf(" %ld", tTgt-t);
+ if (t < tTgt) {
+ d = tTgt - t;
if (d < 10) { break; }
- } else if (ds == 0 && du > 1000000) {
- d = du - 1000000;
- timebase -= d*4;
+ r += d*4;
+ } else if (t > tTgt) {
+ d = t - tTgt;
if (d < 10) { break; }
+ r -= d*4;
} else {
break;
}
}
splx(s);
- printf("\n");
- return (timebase);
+ printf("...using %llu\n", r);
+ return (r);
}
+/* Benchmark cnc_move_jog(). */
+cnc_utime_t
+cnc_calibrate_move_jog(void)
+{
+#if NMPG > 0
+ struct timespec tv1, tv2;
+ struct cnc_insn insn;
+ cnc_utime_t r;
+ int i, s;
+
+ if (cnc_nmpgs < 1)
+ return (1);
+
+ printf("cnc: simulating cnc_move_jog()...");
+
+ insn.i_type = CNC_JOG;
+ insn.i_v0 = 100;
+ insn.i_F = 10000;
+ insn.i_Amax = 1234;
+ insn.i_Jmax = 1234;
+ insn.i_mult = 100;
+ for (i = 0; i < CNC_NAXES; i++)
+ cnc_pos.v[i] = 0.0;
+
+ /* Benchmark the routine using the system clock. */
+ s = splhigh();
+ nanotime(&tv1);
+ cnc_move_jog(&insn, 1);
+ nanotime(&tv2);
+ splx(s);
+
+ r = (cnc_utime_t)(tv2.tv_sec - tv1.tv_sec)*1e12 +
+ (tv2.tv_nsec - tv1.tv_nsec);
+ printf("...%lluns\n", r);
+ return (r);
+#else
+ return (1);
+#endif
+}
+
int
cncioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
{
- struct cnc_kinematics *kin;
cnc_vec_t *pos;
int i;
<at> <at> -376,8 +550,8 <at> <at>
case CNC_SETPOS:
pos = (cnc_vec_t *)data;
for (i = 0; i < CNC_NAXES; i++) {
- printf("cnc: axis %d: %lu -> %lu", i, cnc_pos.v[i],
- pos->v[i]);
+ printf("cnc: SETPOS axis#%d: %lu -> %lu\n", i,
+ cnc_pos.v[i], pos->v[i]);
cnc_pos.v[i] = pos->v[i];
}
return (0);
<at> <at> -390,27 +564,32 <at> <at>
case CNC_GETNESTOPS:
*(int *)data = cnc_nestops;
return (0);
+ case CNC_GETNENCODERS:
+ *(int *)data = cnc_nencoders;
+ return (0);
+ case CNC_GETNMPGS:
+ *(int *)data = cnc_nmpgs;
+ return (0);
case CNC_GETKINLIMITS:
- kin = (struct cnc_kinematics *)data;
-// kin->k_Ts = (int)cnc_Ts;
- kin->k_Vmax = (int)cnc_Vmax;
+ bcopy(&cnc_kinlimits, (void *)data, sizeof(struct cnc_kinlimits));
return (0);
case CNC_SETKINLIMITS:
- kin = (struct cnc_kinematics *)data;
- if (kin->k_Ts < 0 || kin->k_Vmax < 0) {
- return (EINVAL);
- }
-// cnc_Ts = (cnc_real_t)kin->k_Ts;
- cnc_Vmax = (cnc_real_t)kin->k_Vmax;
+ bcopy((const void *)data, &cnc_kinlimits, sizeof(struct cnc_kinlimits));
return (0);
- case CNC_GETTIMEBASE:
- *(u_long *)data = cnc_timebase;
+ case CNC_GETTIMINGS:
+ bcopy(&cnc_timings, (void *)data, sizeof(struct cnc_timings));
return (0);
- case CNC_SETTIMEBASE:
- cnc_timebase = *(u_long *)data;
+ case CNC_SETTIMINGS:
+ bcopy((const void *)data, &cnc_timings, sizeof(struct cnc_timings));
return (0);
- case CNC_CALTIMEBASE:
- *(u_long *)data = cnc_calibrate_timebase();
+ case CNC_CALTIMINGS:
+ if (cnc_timings.hz == 0) {
+ cnc_timings.hz = cnc_calibrate_hz();
+ }
+ if (cnc_timings.move_jog == 0) {
+ cnc_timings.move_jog = cnc_calibrate_move_jog();
+ }
+ bcopy(&cnc_timings, (void *)data, sizeof(struct cnc_timings));
return (0);
default:
break;
<at> <at> -418,180 +597,351 <at> <at>
return (ENODEV);
}
+#if NSERVO > 0
void
cnc_move_axis(enum cnc_axis axis, int dir)
{
servo_step(cnc_servos[axis], dir);
cnc_pos.v[axis] += dir;
}
+#endif
-/* Check whether an e-stop device is active. */
+/*
+ * General-purpose "update" callback. This is invoked periodically during
+ * program execution. If it returns -1, the program should abort.
+ */
int
-cnc_estop_raised(void)
+cnc_update(void)
{
- int i;
-
- for (i = 0; i < cnc_nestops; i++) {
- if (estop_get_state(cnc_estops[i])) {
- printf("%s: emergency stop\n",
- cnc_estops[i]->cd_dev.dv_xname);
- return (1);
- }
+#if NESTOP > 0
+ if (estop_raised()) {
+ printf("cnc: e-stop!\n");
+ return (-1);
}
+#endif
+#if NENCODER > 0
+ {
+ int i;
+ for (i = 0; i < cnc_nencoders; i++)
+ encoder_update(cnc_encoders[i]);
+ }
+#endif
return (0);
}
+#if NSERVO > 0
+
/*
- * Coordinated movement of the n axes to a target position in n-dimensional
- * space at the specified feed rate.
+ * Move a group of servo/stepper driven axes in a coordinated fashion at
+ * the specified velocity, subject to our kinematic limits (Amax/Jmax/F)..
*
- * TODO Specialized applications could use another algorithm to provide a
- * more constant velocity through simultaneous deceleration and acceleration
- * of the axes, at the cost of contour errors proportional to Ts.
+ * TODO Implement simultaneous acceleration/deceleration of axes at the
+ * cost of contour errors, for specialized applications.
*/
int
cnc_move(struct cnc_insn *insn)
{
- struct cnc_quintic_profile qprof;
+ struct cnc_quintic_profile Q;
cnc_real_t t;
-#if CNC_NAXES == 3
- cnc_pos_t x1 = cnc_pos.v[CNC_X];
- cnc_pos_t y1 = cnc_pos.v[CNC_Y];
- cnc_pos_t z1 = cnc_pos.v[CNC_Z];
- cnc_pos_t x2 = insn->i_pos.v[CNC_X];
- cnc_pos_t y2 = insn->i_pos.v[CNC_Y];
- cnc_pos_t z2 = insn->i_pos.v[CNC_Z];
- cnc_pos_t dx, dy, dz;
- cnc_pos_t x, y, z;
- int xdir, ydir, zdir;
-#endif
+ cnc_vec_t v1 = cnc_pos;
+ cnc_vec_t v2 = insn->i_pos;
+ cnc_vec_t d;
+ cnc_pos_t inc, incMin;
+ int dir[CNC_NAXES];
+ int i, nonzero = 0;
+ int axisMajor = 0;
+ cnc_pos_t vMajor = 0;
-#if CNC_NAXES == 3
- dx = abs(x2 - x1);
- dy = abs(y2 - y1);
- dz = abs(z2 - z1);
+ /*
+ * Compute the difference from the current to the new position,
+ * set axisMajor to the axis with the greatest displacement.
+ */
+ for (i = 0; i < CNC_NAXES; i++) {
+ d.v[i] = abs(v2.v[i] - v1.v[i]);
+ if (d.v[i] > vMajor) {
+ vMajor = d.v[i];
+ axisMajor = i;
+ }
+ dir[i] = (v2.v[i] > v1.v[i]) ? 1 : -1;
+ if (d.v[i] != 0) { nonzero++; }
+ }
+ if (!nonzero)
+ return (0); /* Already at target position */
- if (dx == 0 && dy == 0 && dz == 0)
- return (0);
+ /*
+ * Rescale the d[] values of the other axes to STEPLEN over the
+ * displacement of axisMajor.
+ */
+ for (i = 0; i < CNC_NAXES; i++) {
+ if (i != axisMajor)
+ d.v[i] = d.v[i]*STEPLEN/d.v[axisMajor];
+ }
- xdir = (x2 > x1) ? 1 : -1;
- ydir = (y2 > y1) ? 1 : -1;
- zdir = (z2 > z1) ? 1 : -1;
+ /* Compute the time constants for our quintic velocity profile. */
+ if (cnc_quintic_init(&Q,
+ (cnc_real_t)d.v[axisMajor],
+ (cnc_real_t)insn->i_v0,
+ (cnc_real_t)insn->i_F,
+ (cnc_real_t)insn->i_Amax,
+ (cnc_real_t)insn->i_Jmax)
+ == -1) {
+ goto fail;
+ }
- printf("MOVE: Delta=%ld,%ld,%ld\n", dx, dy, dz);
- printf("MOVE: Dir=%d,%d,%d\n", xdir, ydir, zdir);
- printf("MOVE: F = %d st/s, Amax = %d st/s^2, Jmax = %d st/s^3\n",
- insn->i_F, insn->i_Amax, insn->i_Jmax);
+ /*
+ * Enter the signal generation loop. We iterate over the displacement
+ * of the major axis.
+ */
+ for (inc=0, t=0.0;
+ inc < d.v[axisMajor] && t < MAXSTEPS;
+ inc++, t+=1.0) {
+ cnc_real_t v;
+ cnc_utime_t delay, j;
- if (dx >= dy && dx >= dz) {
- dy = dy*STEPLEN/dx;
- dz = dz*STEPLEN/dx;
- if (cnc_quintic_init(&qprof, insn, (cnc_real_t)dx) == -1) {
+ if (cnc_update() == -1)
goto fail;
- }
- for (x = 0, t = 0.0;
- x < dx && t < MAXSTEPS;
- x++, t+=1.0) {
- y = (dy*ydir*t)/STEPLEN;
- z = (dz*zdir*t)/STEPLEN;
- if (cnc_estop_raised()) {
- goto fail;
+
+ /* Increment the major axis once per iteration. */
+ cnc_move_axis(axisMajor, dir[axisMajor]);
+
+ /* Increment the other axes by their scaled intervals. */
+ for (i = 0; i < CNC_NAXES; i++) {
+ if (i != axisMajor) {
+ incMin = (dir[i]*d.v[i]*t)/STEPLEN;
+ if (v1.v[i]+incMin != cnc_pos.v[i])
+ cnc_move_axis(i, dir[i]);
}
- cnc_move_axis(CNC_X, xdir);
- if (y1+y != cnc_pos.v[CNC_Y]) {
- cnc_move_axis(CNC_Y, y);
- cnc_pos.v[CNC_Y] = y1+y;
- }
- if (z1+z != cnc_pos.v[CNC_Z]) {
- cnc_move_axis(CNC_Z, z);
- cnc_pos.v[CNC_Z] = z1+z;
- }
- cnc_move_delay(&qprof, t, (cnc_real_t)dx);
}
- } else if (dy >= dx && dy >= dz) {
- dx = dx*STEPLEN/dy;
- dz = dz*STEPLEN/dy;
- if (cnc_quintic_init(&qprof, insn, (cnc_real_t)dy) == -1) {
- goto fail;
+
+ /*
+ * Evaluate optimal velocity at t in steps/second, and
+ * enter the corresponding delay loop.
+ */
+ v = cnc_quintic_step(&Q,
+ t*(Q.Ta + Q.To)/((cnc_real_t)d.v[axisMajor]))*Q.F /
+ (Q.v0 + Q.v1 + Q.v2) +
+ Q.v0;
+ if (v > 0) {
+ delay = (cnc_utime_t)(cnc_timings.hz/v);
+ for (j = 0; j < delay; j++)
+ ;;
}
- for (y = 0, t = 0.0;
- y < dy && t < MAXSTEPS;
- y++, t+=1.0) {
- x = (dx*xdir*t)/STEPLEN;
- z = (dz*zdir*t)/STEPLEN;
- if (cnc_estop_raised()) {
- goto fail;
- }
- cnc_move_axis(CNC_Y, ydir);
- if (x1+x != cnc_pos.v[CNC_X]) {
- cnc_move_axis(CNC_X, x);
- cnc_pos.v[CNC_X] = x1+x;
- }
- if (z1+z != cnc_pos.v[CNC_Z]) {
- cnc_move_axis(CNC_Z, z);
- cnc_pos.v[CNC_Z] = z1+z;
- }
- cnc_move_delay(&qprof, t, (cnc_real_t)dy);
- }
- } else if (dz >= dx && dz >= dy) {
- dx = dx*STEPLEN/dz;
- dy = dy*STEPLEN/dz;
- if (cnc_quintic_init(&qprof, insn, (cnc_real_t)dz) == -1) {
- goto fail;
- }
- for (z = 0, t = 0.0;
- z < dz && t < MAXSTEPS;
- z++, t+=1.0) {
- x = (dx*xdir*t)/STEPLEN;
- y = (dy*ydir*t)/STEPLEN;
- if (cnc_estop_raised()) {
- goto fail;
- }
- cnc_move_axis(CNC_Z, zdir);
- if (x1+x != cnc_pos.v[CNC_X]) {
- cnc_move_axis(CNC_X, x);
- cnc_pos.v[CNC_X] = x1+x;
- }
- if (y1+y != cnc_pos.v[CNC_Y]) {
- cnc_move_axis(CNC_Y, y);
- cnc_pos.v[CNC_Y] = y1+y;
- }
- cnc_move_delay(&qprof, t, (cnc_real_t)dz);
- }
- } else {
- printf("MOVE: Bad case\n");
- goto fail;
}
-#endif
return (0);
fail:
- printf("MOVE: Aborted instruction\n");
+ printf("cnc: MOVE: Aborted instruction\n");
return (-1);
}
+#if NMPG > 0
/*
- * Enter a precisely-calculated loop that will give us the proper delay
- * between two steps.
+ * Manually control the servos with a MPG until estop is raised.
+ * The MPG pulses are translated directly to servo pulses.
*/
-void
-cnc_move_delay(const struct cnc_quintic_profile *q, cnc_real_t t, cnc_real_t L)
+int
+cnc_move_jog_singlestep(struct cnc_insn *insn)
{
- cnc_real_t v;
- u_long delay;
- u_long j;
+ int i;
- v = cnc_quintic_step(q, t*(q->Ta + q->To)/L)*q->F/(q->v0+q->v1+q->v2) +
- q->v0;
- delay = (u_long)(cnc_timebase/v);
- if (delay > cnc_timebase) {
- delay = cnc_timebase;
+ if (cnc_nmpgs < 1) {
+ printf("cnc: JOG: No MPGs\n");
+ return (-1);
}
-#if 1
- for (j = 0; j < delay; j++)
- ;;
-#else
- printf("[%lu] %s steps/sec (delay=%lu)\n", (u_long)t, cnc_fmt_real(v),
- delay);
+
+ /* Fetch the initial quadrature signal state. */
+ for (i = 0; i < cnc_nmpgs; i++)
+ mpg_jog_init(cnc_mpgs[i]);
+
+ /*
+ * Loop translating the quadrature signal to directly to step
+ * by step motion.
+ */
+ while (!estop_raised()) {
+ for (i = 0; i < cnc_nmpgs; i++) {
+ struct mpg_softc *mpg = cnc_mpgs[i];
+ struct mpg_axis *axis;
+ int axisIdx;
+
+ axisIdx = mpg_get_axis(mpg);
+ axis = &mpg->sc_axes[axisIdx];
+ axis->A = gpio_pin_read(mpg->sc_gpio, &mpg->sc_map, MPG_PIN_A);
+ axis->B = gpio_pin_read(mpg->sc_gpio, &mpg->sc_map, MPG_PIN_B);
+
+ if (axis->A == axis->Aprev &&
+ axis->B == axis->Bprev)
+ continue;
+
+ if (MPG_TRANSITION_CW(axis)) { cnc_move_axis(axisIdx, 1); }
+ if (MPG_TRANSITION_CCW(axis)) { cnc_move_axis(axisIdx, -1); }
+
+ axis->Aprev = axis->A;
+ axis->Bprev = axis->B;
+ }
+ }
+ return (0);
+}
+
+/*
+ * Variant of cnc_move() for JOG mode. We use the MPGs to manipulate a
+ * desired target position. The routine spins moving the axes to the
+ * target position following a quintic velocity profile.
+ */
+int
+cnc_move_jog(struct cnc_insn *insn, int simulate)
+{
+ struct mpg_softc *mpg;
+ struct cnc_quintic_profile Q, Qprev;
+ cnc_vec_t vTgt, vTgtLast;
+ cnc_real_t t = 0.0, dt = 0.0, L;
+ int dir, axis;
+ cnc_utime_t Telapsed = 0;
+ int moving = 0;
+/* int Tprint1 = 0; */
+
+ /* Initialize the MPG for jog. */
+ if (cnc_nmpgs < 1) {
+ printf("cnc: JOG: No MPGs\n");
+ return (-1);
+ }
+ mpg = cnc_mpgs[0]; /* TODO allow multiple mpgs */
+ mpg_jog_init(mpg);
+
+ /* Initialize the target position. */
+ vTgt = cnc_pos;
+ vTgtLast = vTgt;
+ Q.Ta = 0.0;
+ Q.To = 0.0;
+
+ /* Enter the jog loop. */
+ while (!estop_raised()) {
+ /*
+ * Use the MPG to control the target position, fetch
+ * the currently selected axis.
+ */
+ mpg_jog(mpg, &vTgt, insn->i_mult);
+ axis = mpg->sc_sel_axis;
+
+ /* Compute direction and distance to target. */
+ L = (cnc_real_t)(vTgt.v[axis] - cnc_pos.v[axis]);
+ if (L < 0.0) { L = -L; }
+ dir = (vTgt.v[axis] > cnc_pos.v[axis]) ? +1 : -1;
+
+#if 0
+ if (++Tprint1 > 10000) {
+ Tprint1 = 0;
+ printf("[t=%s/", cnc_fmt_real(t));
+ printf("%s] d=%lld (cnc_pos=%lld)\n",
+ cnc_fmt_real(Q.Ta+Q.To),
+ vTgt.v[axis] - cnc_pos.v[axis],
+ cnc_pos.v[axis]);
+ }
#endif
+ /*
+ * If the target position has changed, recompute the time
+ * constants and time increment.
+ */
+ if (!cnc_vec_same(&vTgtLast, &vTgt)) {
+ cnc_real_t t7prev;
+
+ if (!moving) {
+ moving = 1;
+ if (!simulate) {
+ printf("%s: JOG: Moving to %s=%lld\n",
+ ((struct device *)mpg)->dv_xname,
+ cnc_axis_names[axis], vTgt.v[axis]);
+ cnc_message("Moving ");
+ cnc_message(cnc_axis_names[axis]);
+ cnc_message("\n");
+ }
+ }
+ vTgtLast = vTgt;
+ Qprev = Q;
+ if (cnc_quintic_init(&Q, L,
+ insn->i_v0,
+ insn->i_F,
+ insn->i_Amax,
+ insn->i_Jmax) == -1) {
+ goto fail;
+ }
+ dt = (Q.Ta+Q.To)/L;
+
+ printf("cnc: Quintic: L=%s ", cnc_fmt_real(L));
+ printf("dt=%s ", cnc_fmt_real(dt));
+ printf("F=%s ", cnc_fmt_real(Q.F));
+ printf("v0=%s ", cnc_fmt_real(Q.v0));
+ printf("v1=%s ", cnc_fmt_real(Q.v1));
+ printf("v2=%s ", cnc_fmt_real(Q.v2));
+ printf("Aref=%s ", cnc_fmt_real(Q.Aref));
+ printf("[Ts=%s", cnc_fmt_real(Q.Ts));
+ printf(" Ta=%s", cnc_fmt_real(Q.Ta));
+ printf(" To=%s]\n", cnc_fmt_real(Q.To));
+
+ t = 0.0;
+ Telapsed = 0;
+ if (t7prev >= 1e-6) {
+ printf("cnc: Rescaling t for (Ta+To)=%s: ",
+ cnc_fmt_real(Q.Ta+Q.To));
+ t = t/t7prev*(Q.Ta+Q.To); /* Rescale time */
+ printf("t=%ss\n", cnc_fmt_real(t));
+ Telapsed = 0;
+ }
+ }
+
+ /*
+ * Move one step to the target position if the velocity profile
+ * has determined that this iteration must move one step.
+ */
+ if (moving) {
+ if (L > CNC_POS_ERROR) {
+ cnc_utime_t v; /* Steps/second */
+ int clipped = 0;
+
+ v = (cnc_utime_t)cnc_quintic_step(&Q, t);
+ if (v > (cnc_real_t)cnc_kinlimits.Fmax) {
+ v = (cnc_real_t)cnc_kinlimits.Fmax;
+ clipped = 1;
+ }
+ if (v < Q.v0) {
+ v = Q.v0;
+ clipped = =1;
+ }
+#if NCNCSTATLED > 0
+ cncstatled_set(clipped);
+#endif
+ /*
+ * Compare the estimated time elapsed (ns)
+ * to the current velocity (steps/sec).
+ */
+ if ((Telapsed += cnc_timings.move_jog) >
+ 1000000000UL/v) {
+ Telapsed = 0;
+ if (!simulate) {
+ cnc_move_axis(axis, dir);
+ } else {
+ cnc_pos.v[axis] += dir;
+ }
+ t += dt;
+ }
+ } else {
+ if (!simulate) {
+ printf("%s: JOG: Reached target %s=%lld ",
+ ((struct device *)mpg)->dv_xname,
+ cnc_axis_names[axis], cnc_pos.v[axis]);
+ printf("in %s seconds\n", cnc_fmt_real(t));
+ }
+ t = 0.0;
+ moving = 0;
+ }
+ }
+
+ if (simulate)
+ break;
+ }
+ return (0);
+fail:
+ printf("cnc: JOG: Aborted instruction\n");
+ return (-1);
}
+#endif /* NMPG > 0 */
+#endif /* NSERVO > 0 */
Modified: sys/cnc.h
===================================================================
--- sys/cnc.h 2009-03-25 08:24:59 UTC (rev 23)
+++ sys/cnc.h 2009-03-25 08:34:44 UTC (rev 24)
<at> <at> -1,4 +1,3 <at> <at>
-/* $OpenBSD$ */
/* Public domain */
#ifndef _SYS_CNC_H_
<at> <at> -7,23 +6,44 <at> <at>
#include <sys/stdint.h>
#define CNC_BUF_SIZE 1024 /* size of instruction buffer */
-#define CNC_MAX_AXES 3 /* max axes (min. 1) */
+#define CNC_MAX_AXES 3
#define CNC_NAXES CNC_MAX_AXES
-#define CNC_MAX_SPINDLES 2 /* max spindles */
-#define CNC_MAX_ESTOPS 13 /* max e-stops/limit switches */
+#define CNC_MAX_SERVOS 3
+#define CNC_MAX_SPINDLES 2
+#define CNC_MAX_ESTOPS 13
+#define CNC_MAX_ENCODERS 4
+#define CNC_MAX_MPGS 2
+#define CNC_MAX_LCDS 4
+
+/* Allowed position error (steps) */
+#define CNC_POS_ERROR 1e-6
+
enum cnc_axis {
- CNC_X, CNC_Y, CNC_Z,
- CNC_A, CNC_B, CNC_C
+ CNC_X = 0,
+ CNC_Y = 1,
+ CNC_Z = 2,
+ CNC_U = 3,
+ CNC_V = 4,
+ CNC_W = 5,
+ CNC_I = 6,
+ CNC_J = 7,
+ CNC_K = 8,
+ CNC_A = 9,
+ CNC_B = 10,
+ CNC_C = 11,
+ CNC_AXIS_LAST
};
typedef uint64_t cnc_step_t;
typedef int64_t cnc_pos_t;
typedef int64_t cnc_time_t;
+typedef int64_t cnc_utime_t;
enum cnc_insn_type {
/* servo(4) operations */
CNC_MOVE, /* coordinated move to given position */
+ CNC_JOG, /* enter jog mode (until estop) */
CNC_SET_INTERP, /* set interpolation mode */
/* spindle(4) operations */
CNC_SPINDLE_DIR, /* change current direction */
<at> <at> -71,23 +91,37 <at> <at>
* Kinematic limits. These values must be adjusted based on the physical
* limits of the motors and of the load they are driving.
*/
-struct cnc_kinematics {
- int k_Ts; /* third-order jerk limit (ms) */
- int k_Vmax; /* maximum velocity (steps/sec) */
+struct cnc_kinlimits {
+ cnc_utime_t Fmax; /* Maximum velocity (steps/sec) */
+ cnc_utime_t Amax; /* Maximum acceleration (steps/ms^2) */
+ cnc_utime_t Jmax; /* Maximum jerk (steps/ms^3) */
};
+/* Calibrated delay loop timings. */
+struct cnc_timings {
+ cnc_utime_t hz; /* 1Hz reference */
+ cnc_utime_t move_jog; /* Execution time of cnc_move_jog() */
+};
+
/* Program instruction */
struct cnc_insn {
enum cnc_insn_type i_type;
union {
- struct {
- cnc_vec_t i_pos; /* relative target coords */
- u_long i_v0; /* minimum velocity (steps/s) */
- u_long i_F; /* maximum velocity (steps/s) */
- u_long i_Amax; /* max acceleration (steps/ms^2) */
- u_long i_Jmax; /* max jerk (steps/ms^3) */
+ struct {
+ u_long i_v0; /* min steps/s */
+ u_long i_F; /* max steps/s */
+ u_long i_Amax; /* max steps/ms^2 */
+ u_long i_Jmax; /* max steps/ms^3 */
+ cnc_vec_t i_pos; /* target position */
} i_move;
struct {
+ u_long i_v0; /* min steps/s */
+ u_long i_F; /* max steps/s */
+ u_long i_Amax; /* max steps/ms^2 */
+ u_long i_Jmax; /* max steps/ms^3 */
+ int i_mult; /* MPG pulse multiplier */
+ } i_jog;
+ struct {
int i_id; /* name of spindle */
int i_dir; /* 1=CW, -1=CCW */
u_int i_speed; /* speed in RPM */
<at> <at> -107,6 +141,7 <at> <at>
#define i_v0 i_arg.i_move.i_v0
#define i_Amax i_arg.i_move.i_Amax
#define i_Jmax i_arg.i_move.i_Jmax
+#define i_mult i_arg.i_jog.i_mult
#define i_interp_mode i_arg.i_interp_mode
#define i_spindle_id i_arg.i_spindle.i_id
#define i_spindle_dir i_arg.i_spindle.i_dir
<at> <at> -125,11 +160,13 <at> <at>
#define CNC_SETPOS _IOWR('C', 3, struct cnc_vector)
#define CNC_GETNSERVOS _IOR('C', 4, int)
#define CNC_GETNSPINDLES _IOR('C', 5, int)
-#define CNC_GETKINLIMITS _IOR('C', 6, struct cnc_kinematics)
-#define CNC_SETKINLIMITS _IOWR('C', 7, struct cnc_kinematics)
-#define CNC_GETTIMEBASE _IOR('C', 8, u_long)
-#define CNC_SETTIMEBASE _IOWR('C', 9, u_long)
-#define CNC_CALTIMEBASE _IOWR('C', 10, u_long)
+#define CNC_GETKINLIMITS _IOR('C', 6, struct cnc_kinlimits)
+#define CNC_SETKINLIMITS _IOWR('C', 7, struct cnc_kinlimits)
+#define CNC_GETTIMINGS _IOR('C', 8, struct cnc_timings)
+#define CNC_SETTIMINGS _IOWR('C', 9, struct cnc_timings)
+#define CNC_CALTIMINGS _IOWR('C', 10, struct cnc_timings)
#define CNC_GETNESTOPS _IOR('C', 11, int)
+#define CNC_GETNENCODERS _IOR('C', 12, int)
+#define CNC_GETNMPGS _IOR('C', 13, int)
#endif /* !_SYS_CNC_H_ */
Modified: sys/cnc_device.c
===================================================================
--- sys/cnc_device.c 2009-03-25 08:24:59 UTC (rev 23)
+++ sys/cnc_device.c 2009-03-25 08:34:44 UTC (rev 24)
<at> <at> -1,7 +1,5 <at> <at>
-/* $OpenBSD$ */
-
/*
- * Copyright (c) 2007 Hypertriton, Inc. <http://www.hypertriton.com/>
+ * Copyright (c) 2007-2009 Hypertriton, Inc. <http://www.hypertriton.com/>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
<at> <at> -66,28 +64,52 <at> <at>
switch (type) {
case CNC_DEVICE_SERVO:
if ((cnc_nservos+1) <= CNC_NAXES) {
- printf(": axis %d\n", cnc_nservos);
- cnc_servos[cnc_nservos++] = cd;
+ printf(": axis #%d\n", cnc_nservos);
+ cnc_servos[cnc_nservos++] = (struct servo_softc *)cd;
} else {
printf(": ignored (bump CNC_NAXES)\n");
}
break;
case CNC_DEVICE_SPINDLE:
if ((cnc_nspindles+1) <= CNC_MAX_SPINDLES) {
- printf(": spindle %d\n", cnc_nspindles);
- cnc_spindles[cnc_nspindles++] = cd;
+ printf(": spindle #%d\n", cnc_nspindles);
+ cnc_spindles[cnc_nspindles++] = (struct spindle_softc *)cd;
} else {
printf(": ignored (bump CNC_MAX_SPINDLES)\n");
}
break;
case CNC_DEVICE_ESTOP:
if ((cnc_nestops+1) <= CNC_MAX_ESTOPS) {
- printf(": estop %d\n", cnc_nestops);
- cnc_estops[cnc_nestops++] = cd;
+ printf(": estop #%d\n", cnc_nestops);
+ cnc_estops[cnc_nestops++] = (struct estop_softc *)cd;
} else {
printf(": ignored (bump CNC_MAX_ESTOPS)\n");
}
break;
+ case CNC_DEVICE_ENCODER:
+ if ((cnc_nencoders+1) <= CNC_MAX_ENCODERS) {
+ printf(": encoder #%d\n", cnc_nencoders);
+ cnc_encoders[cnc_nencoders++] = (struct encoder_softc *)cd;
+ } else {
+ printf(": ignored (bump CNC_MAX_ENCODERS)\n");
+ }
+ break;
+ case CNC_DEVICE_MPG:
+ if ((cnc_nmpgs+1) <= CNC_MAX_MPGS) {
+ printf(": mpg #%d\n", cnc_nmpgs);
+ cnc_mpgs[cnc_nmpgs++] = (struct mpg_softc *)cd;
+ } else {
+ printf(": ignored (bump CNC_MAX_MPGS)\n");
+ }
+ break;
+ case CNC_DEVICE_LCD:
+ if ((cnc_nlcds+1) <= CNC_MAX_LCDS) {
+ printf(": lcd #%d\n", cnc_nlcds);
+ cnc_lcds[cnc_nlcds++] = (struct cnclcd_softc *)cd;
+ } else {
+ printf(": ignored (bump CNC_MAX_LCDS)\n");
+ }
+ break;
default:
printf(": unimplemented\n");
break;
Modified: sys/cnc_devicevar.h
===================================================================
--- sys/cnc_devicevar.h 2009-03-25 08:24:59 UTC (rev 23)
+++ sys/cnc_devicevar.h 2009-03-25 08:34:44 UTC (rev 24)
<at> <at> -1,4 +1,3 <at> <at>
-/* $OpenBSD$ */
/* Public domain */
enum cnc_device_type {
<at> <at> -7,7 +6,10 <at> <at>
CNC_DEVICE_SPINDLE, /* Machine spindle controller */
CNC_DEVICE_ATC, /* Automatic tool changer */
CNC_DEVICE_LASER, /* Laser power supply controller */
- CNC_DEVICE_PICKPLACE /* Pick and place controller */
+ CNC_DEVICE_PICKPLACE, /* Pick and place controller */
+ CNC_DEVICE_ENCODER, /* Position-sensing encoder (general-purpose) */
+ CNC_DEVICE_MPG, /* Manual pulse generator */
+ CNC_DEVICE_LCD /* Serial interface to text-based LCD */
};
struct cnc_device {
<at> <at> -24,3 +26,35 <at> <at>
int cnc_device_detach(void *);
int cnc_device_activate(void *);
+/* Attach routine: Map a standard input pin */
+#define CNC_MAP_INPUT(sc, n, name) \
+ do { \
+ int caps; \
+ caps = gpio_pin_caps((sc)->sc_gpio, &(sc)->sc_map, (n)); \
+ if (!(caps & GPIO_PIN_INPUT)) { \
+ printf(": pin#%d (%s) cannot be used for input\n", \
+ (n), (name)); \
+ goto fail; \
+ } \
+ printf(" %s[%d]", name, (sc)->sc_map.pm_map[n]); \
+ gpio_pin_ctl((sc)->sc_gpio, &(sc)->sc_map, (n), GPIO_PIN_INPUT); \
+ } while (/*CONSTCOND*/0)
+
+/* Attach routine: Map a standard output pin */
+#define CNC_MAP_OUTPUT(sc, n, name) \
+ do { \
+ int caps, ctl; \
+ caps = gpio_pin_caps((sc)->sc_gpio, &(sc)->sc_map, (n)); \
+ if (!(caps & GPIO_PIN_OUTPUT)) { \
+ printf(": pin#%d (%s) cannot drive output\n", \
+ (n), (name)); \
+ goto fail; \
+ } \
+ printf(" >%s[%d]", name, (sc)->sc_map.pm_map[n]); \
+ ctl = GPIO_PIN_OUTPUT; \
+ if (caps & GPIO_PIN_PUSHPULL) { \
+ ctl |= GPIO_PIN_PUSHPULL; \
+ } \
+ gpio_pin_ctl((sc)->sc_gpio, &(sc)->sc_map, (n), ctl); \
+ } while (/*CONSTCOND*/0)
+
Modified: sys/cnc_estop.c
===================================================================
--- sys/cnc_estop.c 2009-03-25 08:24:59 UTC (rev 23)
+++ sys/cnc_estop.c 2009-03-25 08:34:44 UTC (rev 24)
<at> <at> -1,7 +1,5 <at> <at>
-/* $OpenBSD$ */
-
/*
- * Copyright (c) 2007 Hypertriton, Inc. <http://www.hypertriton.com/>
+ * Copyright (c) 2007-2009 Hypertriton, Inc. <http://www.hypertriton.com/>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
<at> <at> -81,8 +79,11 <at> <at>
{
struct estop_softc *sc = (struct estop_softc *)self;
struct gpio_attach_args *ga = aux;
- int caps, ctl;
+ /* Generic CNC device initialization. */
+ if (cnc_device_attach(sc, CNC_DEVICE_ESTOP) == -1)
+ return;
+
sc->sc_flags = 0;
if (gpio_npins(ga->ga_mask) != ESTOP_NPINS) {
<at> <at> -96,18 +97,14 <at> <at>
printf(": can't map pins\n");
return;
}
-
- caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, ESTOP_PIN);
- if (!(caps & GPIO_PIN_INPUT)) {
- printf(": ESTOP pin is unable to read input\n");
- gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
- return;
- }
- printf(": ESTOP[%d]\n", sc->sc_map.pm_map[ESTOP_PIN]);
- ctl = GPIO_PIN_INPUT;
- if (caps & GPIO_PIN_PUSHPULL) { ctl |= GPIO_PIN_PUSHPULL; }
- gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, ESTOP_PIN, ctl);
- gpio_pin_write(sc->sc_gpio, &sc->sc_map, ESTOP_PIN, GPIO_PIN_LOW);
+
+ /* Map the input signal. */
+ CNC_MAP_INPUT(sc, ESTOP_PIN, "ESTOP");
+
+ printf("\n");
+ return;
+fail:
+ gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
}
int
<at> <at> -122,9 +119,22 <at> <at>
return (0);
}
+/* Return e-stop status. */
int
-estop_get_state(void *p)
+estop_get_state(struct estop_softc *sc)
{
- struct estop_softc *sc = p;
return (gpio_pin_read(sc->sc_gpio, &sc->sc_map, ESTOP_PIN));
}
+
+/* Return 1 if one of the registered e-stops are raised. */
+int
+estop_raised(void)
+{
+ int i;
+
+ for (i = 0; i < cnc_nestops; i++) {
+ if (estop_get_state(cnc_estops[i]))
+ return (1);
+ }
+ return (0);
+}
Modified: sys/cnc_estopvar.h
===================================================================
--- sys/cnc_estopvar.h 2009-03-25 08:24:59 UTC (rev 23)
+++ sys/cnc_estopvar.h 2009-03-25 08:34:44 UTC (rev 24)
<at> <at> -1,4 +1,3 <at> <at>
-/* $OpenBSD$ */
/* Public domain */
#define ESTOP_NPINS 1
<at> <at> -13,4 +12,5 <at> <at>
int __map[ESTOP_NPINS];
};
-int estop_get_state(void *);
+int estop_raised(void);
+int estop_get_state(struct estop_softc *);
Added: sys/cnc_fixunssfdi.c
===================================================================
--- sys/cnc_fixunssfdi.c (rev 0)
+++ sys/cnc_fixunssfdi.c 2009-03-25 08:34:44 UTC (rev 24)
<at> <at> -0,0 +1,93 <at> <at>
+/* $OpenBSD: fixunssfdi.c,v 1.5 2005/08/08 08:05:35 espie Exp $ */
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "cnc_quad.h"
+
+#define ONE_FOURTH ((int)1 << (INT_BITS - 2))
+#define ONE_HALF (ONE_FOURTH * 2.0)
+#define ONE (ONE_FOURTH * 4.0)
+
+/*
+ * Convert float to (unsigned) quad. We do most of our work in double,
+ * out of sheer paranoia.
+ *
+ * Not sure what to do with negative numbers---for now, anything out
+ * of range becomes UQUAD_MAX.
+ *
+ * N.B.: must use new ANSI syntax (sorry).
+ */
+u_quad_t
+__fixunssfdi(float f)
+{
+ double x, toppart;
+ union uu t;
+
+ if (f < 0)
+ return (UQUAD_MAX); /* ??? should be 0? ERANGE??? */
+#ifdef notdef /* this falls afoul of a GCC bug */
+ if (f >= UQUAD_MAX)
+ return (UQUAD_MAX);
+#else /* so we wire in 2^64-1 instead */
+ if (f >= 18446744073709551615.0) /* XXX */
+ return (UQUAD_MAX);
+#endif
+ x = f;
+ /*
+ * Get the upper part of the result. Note that the divide
+ * may round up; we want to avoid this if possible, so we
+ * subtract `1/2' first.
+ */
+ toppart = (x - ONE_HALF) / ONE;
+ /*
+ * Now build a u_quad_t out of the top part. The difference
+ * between x and this is the bottom part (this may introduce
+ * a few fuzzy bits, but what the heck). With any luck this
+ * difference will be nonnegative: x should wind up in the
+ * range [0..UINT_MAX]. For paranoia, we assume [INT_MIN..
+ * 2*UINT_MAX] instead.
+ */
+ t.ul[H] = (unsigned int)toppart;
+ t.ul[L] = 0;
+ x -= (double)t.uq;
+ if (x < 0) {
+ t.ul[H]--;
+ x += UINT_MAX;
+ }
+ if (x > UINT_MAX) {
+ t.ul[H]++;
+ x -= UINT_MAX;
+ }
+ t.ul[L] = (u_int)x;
+ return (t.uq);
+}
Modified: sys/cnc_math.c
===================================================================
--- sys/cnc_math.c 2009-03-25 08:24:59 UTC (rev 23)
+++ sys/cnc_math.c 2009-03-25 08:34:44 UTC (rev 24)
<at> <at> -1,4 +1,3 <at> <at>
-/* $OpenBSD$ */
/* Public domain */
#include <sys/param.h>
<at> <at> -83,6 +82,19 <at> <at>
return (cnc_vec_length(&vd));
}
+/* Return 1 if the two arguments are the same vector. */
+int
+cnc_vec_same(const cnc_vec_t *v1, const cnc_vec_t *v2)
+{
+ int i;
+
+ for (i = 0; i < CNC_NAXES; i++) {
+ if (v1->v[i] != v2->v[i])
+ return (0);
+ }
+ return (1);
+}
+
char *
cnc_fmt_real(cnc_real_t v)
{
Modified: sys/cnc_math.h
===================================================================
--- sys/cnc_math.h 2009-03-25 08:24:59 UTC (rev 23)
+++ sys/cnc_math.h 2009-03-25 08:34:44 UTC (rev 24)
<at> <at> -1,9 +1,10 <at> <at>
-/* $OpenBSD$ */
+/* Public domain */
typedef float cnc_real_t;
#define CNC_PI 3.14159265358979323846 /* pi */
#define CNC_PI_2 1.57079632679489661923 /* pi/2 */
+#define CNC_PI_P2 (CNC_PI*CNC_PI) /* pi^2 */
#define CNC_MSECS(s) ((u_long)(s*1e3))
double cnc_sin(double);
<at> <at> -11,11 +12,13 <at> <at>
double cnc_cbrt(double);
double cnc_log10(double);
double cnc_modf(double, double *);
-char *cnc_fmt_real(cnc_real_t);
-void cnc_vec_init(cnc_vec_t);
-void cnc_vec_sub(cnc_vec_t *, const cnc_vec_t *, const cnc_vec_t *);
-void cnc_vec_add(cnc_vec_t *, const cnc_vec_t *, const cnc_vec_t *);
+char *cnc_fmt_real(cnc_real_t);
+
+void cnc_vec_init(cnc_vec_t);
+void cnc_vec_sub(cnc_vec_t *, const cnc_vec_t *, const cnc_vec_t *);
+void cnc_vec_add(cnc_vec_t *, const cnc_vec_t *, const cnc_vec_t *);
cnc_real_t cnc_vec_dotprod(cnc_vec_t *, const cnc_vec_t *, const cnc_vec_t *);
cnc_real_t cnc_vec_length(const cnc_vec_t *);
cnc_real_t cnc_vec_distance(const cnc_vec_t *, const cnc_vec_t *);
+int cnc_vec_same(const cnc_vec_t *, const cnc_vec_t *);
Added: sys/cnc_quad.h
===================================================================
--- sys/cnc_quad.h (rev 0)
+++ sys/cnc_quad.h 2009-03-25 08:34:44 UTC (rev 24)
<at> <at> -0,0 +1,135 <at> <at>
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $OpenBSD: quad.h,v 1.6 2004/11/28 07:09:13 mickey Exp $
+ */
+
+/*
+ * Quad arithmetic.
+ *
+ * This library makes the following assumptions:
+ *
+ * - The type long long (aka quad_t) exists.
+ *
+ * - A quad variable is exactly twice as long as `int'.
+ *
+ * - The machine's arithmetic is two's complement.
+ *
+ * This library can provide 128-bit arithmetic on a machine with 128-bit
+ * quads and 64-bit ints, for instance, or 96-bit arithmetic on machines
+ * with 48-bit ints.
+ */
+
+#include <sys/types.h>
+#if !defined(_KERNEL) && !defined(_STANDALONE)
+#include <limits.h>
+#else
+#include <sys/limits.h>
+#endif
+
+/*
+ * Depending on the desired operation, we view a `long long' (aka quad_t) in
+ * one or more of the following formats.
+ */
+union uu {
+ quad_t q; /* as a (signed) quad */
+ u_quad_t uq; /* as an unsigned quad */
+ int sl[2]; /* as two signed ints */
+ u_int ul[2]; /* as two unsigned ints */
+};
+
+/*
+ * Define high and low parts of a quad_t.
+ */
+#define H _QUAD_HIGHWORD
+#define L _QUAD_LOWWORD
+
+/*
+ * Total number of bits in a quad_t and in the pieces that make it up.
+ * These are used for shifting, and also below for halfword extraction
+ * and assembly.
+ */
+#define QUAD_BITS (sizeof(quad_t) * CHAR_BIT)
+#define INT_BITS (sizeof(int) * CHAR_BIT)
+#define HALF_BITS (sizeof(int) * CHAR_BIT / 2)
+
+/*
+ * Extract high and low shortwords from longword, and move low shortword of
+ * longword to upper half of long, i.e., produce the upper longword of
+ * ((quad_t)(x) << (number_of_bits_in_int/2)). (`x' must actually be u_int.)
+ *
+ * These are used in the multiply code, to split a longword into upper
+ * and lower halves, and to reassemble a product as a quad_t, shifted left
+ * (sizeof(int)*CHAR_BIT/2).
+ */
+#define HHALF(x) ((u_int)(x) >> HALF_BITS)
+#define LHALF(x) ((u_int)(x) & (((int)1 << HALF_BITS) - 1))
+#define LHUP(x) ((u_int)(x) << HALF_BITS)
+
+/*
+ * XXX
+ * Compensate for gcc 1 vs gcc 2. Gcc 1 defines ?sh?di3's second argument
+ * as u_quad_t, while gcc 2 correctly uses int. Unfortunately, we still use
+ * both compilers.
+ */
+#if __GNUC_PREREQ__(2, 0) || defined(lint)
+typedef unsigned int qshift_t;
+#else
+typedef u_quad_t qshift_t;
+#endif
+
+quad_t __adddi3(quad_t, quad_t);
+quad_t __anddi3(quad_t, quad_t);
+quad_t __ashldi3(quad_t, qshift_t);
+quad_t __ashrdi3(quad_t, qshift_t);
+int __cmpdi2(quad_t, quad_t);
+quad_t __divdi3(quad_t, quad_t);
+quad_t __fixdfdi(double);
+quad_t __fixsfdi(float);
+u_quad_t __fixunsdfdi(double);
+u_quad_t __fixunssfdi(float);
+double __floatdidf(quad_t);
+float __floatdisf(quad_t);
+double __floatunsdidf(u_quad_t);
+quad_t __iordi3(quad_t, quad_t);
+quad_t __lshldi3(quad_t, qshift_t);
+quad_t __lshrdi3(quad_t, qshift_t);
+quad_t __moddi3(quad_t, quad_t);
+quad_t __muldi3(quad_t, quad_t);
+quad_t __negdi2(quad_t);
+quad_t __one_cmpldi2(quad_t);
+u_quad_t __qdivrem(u_quad_t, u_quad_t, u_quad_t *);
+quad_t __subdi3(quad_t, quad_t);
+int __ucmpdi2(u_quad_t, u_quad_t);
+u_quad_t __udivdi3(u_quad_t, u_quad_t );
+u_quad_t __umoddi3(u_quad_t, u_quad_t );
+quad_t __xordi3(quad_t, quad_t);
Modified: sys/cnc_servo.c
===================================================================
--- sys/cnc_servo.c 2009-03-25 08:24:59 UTC (rev 23)
+++ sys/cnc_servo.c 2009-03-25 08:34:44 UTC (rev 24)
<at> <at> -1,7 +1,5 <at> <at>
-/* $OpenBSD$ */
-
/*
- * Copyright (c) 2007 Hypertriton, Inc. <http://www.hypertriton.com/>
+ * Copyright (c) 2007-2009 Hypertriton, Inc. <http://www.hypertriton.com/>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
<at> <at> -79,11 +77,10 <at> <at>
{
struct servo_softc *sc = (struct servo_softc *)self;
struct gpio_attach_args *ga = aux;
- int caps, ctl;
/* Generic CNC device initialization. */
if (cnc_device_attach(sc, CNC_DEVICE_SERVO) == -1)
- goto fail;
+ return;
/* Check that we have enough pins */
if (gpio_npins(ga->ga_mask) != SERVO_NPINS) {
<at> <at> -100,32 +97,23 <at> <at>
return;
}
- /* Configure STEP pin (output). Initialize to LOW. */
- caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, SERVO_PIN_STEP);
- if (!(caps & GPIO_PIN_OUTPUT)) {
- printf(": STEP pin is unable to drive output\n");
- goto fail;
- }
- printf(": STEP[%d]", sc->sc_map.pm_map[SERVO_PIN_STEP]);
- ctl = GPIO_PIN_OUTPUT;
- if (caps & GPIO_PIN_PUSHPULL) { ctl |= GPIO_PIN_PUSHPULL; }
- gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, SERVO_PIN_STEP, ctl);
+ /* Configure step and direction outputs. */
+ CNC_MAP_OUTPUT(sc, SERVO_PIN_STEP, "STEP");
+ CNC_MAP_OUTPUT(sc, SERVO_PIN_DIR, "DIR");
+
+ /* Some motor controllers need an initial pulse. */
+ gpio_pin_write(sc->sc_gpio, &sc->sc_map, SERVO_PIN_DIR, GPIO_PIN_LOW);
gpio_pin_write(sc->sc_gpio, &sc->sc_map, SERVO_PIN_STEP, GPIO_PIN_LOW);
- sc->sc_step = 0;
-
- /* Configure DIR pin (output). Initialize to LOW. */
- caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, SERVO_PIN_DIR);
- if (!(caps & GPIO_PIN_OUTPUT)) {
- printf(": DIR pin is unable to drive output\n");
- goto fail;
- }
- printf(" DIR[%d]", sc->sc_map.pm_map[SERVO_PIN_DIR]);
- ctl = GPIO_PIN_OUTPUT;
- if (caps & GPIO_PIN_PUSHPULL) { ctl |= GPIO_PIN_PUSHPULL; }
- gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, SERVO_PIN_DIR, ctl);
+ delay(100000);
+ gpio_pin_write(sc->sc_gpio, &sc->sc_map, SERVO_PIN_DIR, GPIO_PIN_HIGH);
+ gpio_pin_write(sc->sc_gpio, &sc->sc_map, SERVO_PIN_STEP, GPIO_PIN_HIGH);
+ delay(100000);
gpio_pin_write(sc->sc_gpio, &sc->sc_map, SERVO_PIN_DIR, GPIO_PIN_LOW);
- sc->sc_dir = 0;
+ gpio_pin_write(sc->sc_gpio, &sc->sc_map, SERVO_PIN_STEP, GPIO_PIN_LOW);
+ sc->sc_step = 0;
+ sc->sc_dir = 0;
+
printf("\n");
return;
fail:
<at> <at> -145,10 +133,8 <at> <at>
}
void
-servo_set_dir(void *arg, int dir)
+servo_set_dir(struct servo_softc *sc, int dir)
{
- struct servo_softc *sc = arg;
-
if (sc->sc_dir != dir) {
sc->sc_dir = dir;
gpio_pin_write(sc->sc_gpio, &sc->sc_map, SERVO_PIN_DIR,
<at> <at> -157,71 +143,16 <at> <at>
}
void
-servo_step(void *arg, int dir)
+servo_step(struct servo_softc *sc, int dir)
{
- struct servo_softc *sc = arg;
-
if (sc->sc_dir != dir) {
sc->sc_dir = dir;
+ delay(1);
gpio_pin_write(sc->sc_gpio, &sc->sc_map, SERVO_PIN_DIR,
(dir == 1) ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
+ delay(1);
}
sc->sc_step = !sc->sc_step;
gpio_pin_write(sc->sc_gpio, &sc->sc_map, SERVO_PIN_STEP,
sc->sc_step ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
}
-
-#if 0
-void
-servo_accel_test(void *p)
-{
- struct servo_softc *sc = p;
- int j, k, delay;
- int slow = 8000;
- int fast = 800;
- int steady = 10000;
- int accel = 100;
- int decel = 100;
-
- printf("%s: velocity test\n", sc->sc_cdev.cd_dev.dv_xname);
-
- delay = slow;
- k = 0;
- while (1) {
- sc->sc_step = !sc->sc_step;
- gpio_pin_write(sc->sc_gpio, &sc->sc_map, SERVO_PIN_STEP,
- sc->sc_step ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
- for (j = 0; j < delay; j++)
- ;;
- if (++k == accel) {
- k = 0;
- if (delay > fast) {
- delay -= 10;
- } else {
- if (--steady == 0)
- goto next;
- }
- }
- }
-next:
- delay = fast;
- k = 0;
- while (1) {
- gpio_pin_write(sc->sc_gpio, &sc->sc_map, SERVO_PIN_STEP,
- sc->sc_step ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
- for (j = 0; j < delay; j++)
- ;;
- if (++k == decel) {
- k = 0;
- if (delay < slow) {
- delay += 10;
- } else {
- goto out;
- }
- }
- }
-out:
- printf("%s: velocity test done\n", sc->sc_cdev.cd_dev.dv_xname);
- return;
-}
-#endif
Modified: sys/cnc_servovar.h
===================================================================
--- sys/cnc_servovar.h 2009-03-25 08:24:59 UTC (rev 23)
+++ sys/cnc_servovar.h 2009-03-25 08:34:44 UTC (rev 24)
<at> <at> -14,5 +14,5 <at> <at>
int sc_dir; /* last direction */
};
-void servo_set_dir(void *, int);
-void servo_step(void *, int);
+void servo_set_dir(struct servo_softc *, int);
+void servo_step(struct servo_softc *, int);
Modified: sys/cnc_spindle.c
===================================================================
--- sys/cnc_spindle.c 2009-03-25 08:24:59 UTC (rev 23)
+++ sys/cnc_spindle.c 2009-03-25 08:34:44 UTC (rev 24)
<at> <at> -1,7 +1,5 <at> <at>
-/* $OpenBSD$ */
-
/*
- * Copyright (c) 2007 Hypertriton, Inc. <http://www.hypertriton.com/>
+ * Copyright (c) 2007-2009 Hypertriton, Inc. <http://www.hypertriton.com/>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
<at> <at> -80,7 +78,6 <at> <at>
{
struct spindle_softc *sc = (struct spindle_softc *)self;
struct gpio_attach_args *ga = aux;
- int caps, ctl;
/* Generic CNC device initialization. */
if (cnc_device_attach(sc, CNC_DEVICE_SPINDLE) == -1)
<at> <at> -100,59 +97,18 <at> <at>
printf(": can't map pins\n");
return;
}
-
- /* Initialize DIR pin to LOW (CW) */
- caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, SPINDLE_PIN_DIR);
- if (!(caps & GPIO_PIN_OUTPUT)) {
- printf(": DIR pin is unable to drive output\n");
- goto fail;
- }
- printf(": DIR[%d]", sc->sc_map.pm_map[SPINDLE_PIN_DIR]);
- ctl = GPIO_PIN_OUTPUT;
- if (caps & GPIO_PIN_PUSHPULL) { ctl |= GPIO_PIN_PUSHPULL; }
- gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, SPINDLE_PIN_DIR, ctl);
- gpio_pin_write(sc->sc_gpio, &sc->sc_map, SPINDLE_PIN_DIR, GPIO_PIN_LOW);
- sc->sc_dir = 1;
- /* Initialize INCREMENT pin to LOW. */
- caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, SPINDLE_PIN_INCREMENT);
- if (!(caps & GPIO_PIN_OUTPUT)) {
- printf(": INCREMENT pin is unable to drive output\n");
- goto fail;
- }
- printf(" INCREMENT[%d]", sc->sc_map.pm_map[SPINDLE_PIN_INCREMENT]);
- ctl = GPIO_PIN_OUTPUT;
- if (caps & GPIO_PIN_PUSHPULL) { ctl |= GPIO_PIN_PUSHPULL; }
- gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, SPINDLE_PIN_INCREMENT, ctl);
- gpio_pin_write(sc->sc_gpio, &sc->sc_map, SPINDLE_PIN_INCREMENT,
- GPIO_PIN_LOW);
+ /* Map the pins */
+ CNC_MAP_OUTPUT(sc, SPINDLE_PIN_DIR, "DIR");
+ CNC_MAP_OUTPUT(sc, SPINDLE_PIN_INCREMENT, "INCREMENT");
+ CNC_MAP_OUTPUT(sc, SPINDLE_PIN_DECREMENT, "DECREMENT");
+ CNC_MAP_INPUT(sc, SPINDLE_PIN_TACHO, "TACHO");
- /* Initialize DECREMENT pin to LOW. */
- caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, SPINDLE_PIN_DECREMENT);
- if (!(caps & GPIO_PIN_OUTPUT)) {
- printf(": DECREMENT pin is unable to drive output\n");
- goto fail;
- }
- printf(" DECREMENT[%d]", sc->sc_map.pm_map[SPINDLE_PIN_DECREMENT]);
- ctl = GPIO_PIN_OUTPUT;
- if (caps & GPIO_PIN_PUSHPULL) { ctl |= GPIO_PIN_PUSHPULL; }
- gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, SPINDLE_PIN_DECREMENT, ctl);
- gpio_pin_write(sc->sc_gpio, &sc->sc_map, SPINDLE_PIN_DECREMENT,
- GPIO_PIN_LOW);
+ /* Initialize outputs */
+ gpio_pin_write(sc->sc_gpio, &sc->sc_map, SPINDLE_PIN_DIR, GPIO_PIN_LOW);
+ gpio_pin_write(sc->sc_gpio, &sc->sc_map, SPINDLE_PIN_INCREMENT, GPIO_PIN_LOW);
+ gpio_pin_write(sc->sc_gpio, &sc->sc_map, SPINDLE_PIN_DECREMENT, GPIO_PIN_LOW);
- /* Configure TACHO pin for input. */
- caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, SPINDLE_PIN_TACHO);
- if (!(caps & GPIO_PIN_INPUT)) {
- printf(": TACHO pin is unable to read input\n");
- goto fail;
- }
- printf(" TACHO[%d]", sc->sc_map.pm_map[SPINDLE_PIN_TACHO]);
- ctl = GPIO_PIN_INPUT;
- gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, SPINDLE_PIN_TACHO, ctl);
- gpio_pin_write(sc->sc_gpio, &sc->sc_map, SPINDLE_PIN_TACHO,
- GPIO_PIN_LOW);
-
- /* Initialize the structure. */
sc->sc_speed = 0;
sc->sc_speed_tacho = 0;
sc->sc_speed_max = 3000; /* XXX configure */
<at> <at> -208,10 +164,8 <at> <at>
* speed, within error.
*/
int
-spindle_speed(void *p, struct cnc_insn *insn)
+spindle_speed(struct spindle_softc *sc, struct cnc_insn *insn)
{
- struct spindle_softc *sc = p;
-
if (insn.i_spindle_speed > sc->sc_speed_max) {
printf("%s: %u rpm exceeds spindle limit (%u)\n",
sc->sc_dev.dv_xname, insn.i_spindle_speed,
<at> <at> -226,10 +180,8 <at> <at>
/* Process CNC_SPINDLE_START instruction. */
/* XXX block until target speed is reached? */
int
-spindle_start(void *p, struct cnc_insn *insn)
+spindle_start(struct spindle_softc *sc, struct cnc_insn *insn)
{
- struct spindle_softc *sc = p;
-
/* TODO */
printf("%s: startup\n", sc->sc_dev.dv_xname);
return (0);
<at> <at> -238,66 +190,19 <at> <at>
/* Process CNC_SPINDLE_STOP instruction. */
/* XXX block until target speed is reached? */
int
-spindle_stop(void *p, struct cnc_insn *insn)
+spindle_stop(struct spindle_softc *sc, struct cnc_insn *insn)
{
- struct spindle_softc *sc = p;
-
/* TODO */
printf("%s: spindle stopped\n", sc->sc_dev.dv_xname);
return (0);
}
-#if 0
-void
-spindle_accel_test(void *p)
+/* Return a spindle device by name. */
+struct spindle_softc *
+spindle_find(int id)
{
- struct spindle_softc *sc = p;
- int j, k, delay;
- int slow = 8000;
- int fast = 800;
- int steady = 10000;
- int accel = 100;
- int decel = 100;
-
- printf("%s: velocity test\n", sc->sc_cdev.cd_dev.dv_xname);
-
- delay = slow;
- k = 0;
- while (1) {
- sc->sc_step = !sc->sc_step;
- gpio_pin_write(sc->sc_gpio, &sc->sc_map, SPINDLE_PIN_STEP,
- sc->sc_step ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
- for (j = 0; j < delay; j++)
- ;;
- if (++k == accel) {
- k = 0;
- if (delay > fast) {
- delay -= 10;
- } else {
- if (--steady == 0)
- goto next;
- }
- }
+ if (id < 0 || id >= cnc_nspindles) {
+ return (NULL);
}
-next:
- delay = fast;
- k = 0;
- while (1) {
- gpio_pin_write(sc->sc_gpio, &sc->sc_map, SPINDLE_PIN_STEP,
- sc->sc_step ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
- for (j = 0; j < delay; j++)
- ;;
- if (++k == decel) {
- k = 0;
- if (delay < slow) {
- delay += 10;
- } else {
- goto out;
- }
- }
- }
-out:
- printf("%s: velocity test done\n", sc->sc_cdev.cd_dev.dv_xname);
- return;
+ return (cnc_spindles[id]);
}
-#endif
Modified: sys/cnc_spindlevar.h
===================================================================
--- sys/cnc_spindlevar.h 2009-03-25 08:24:59 UTC (rev 23)
+++ sys/cnc_spindlevar.h 2009-03-25 08:34:44 UTC (rev 24)
<at> <at> -1,4 +1,3 <at> <at>
-/* $OpenBSD$ */
/* Public domain */
#define SPINDLE_NPINS 4
<at> <at> -18,6 +17,8 <at> <at>
u_int sc_speed_max; /* maximum allowed speed (rpm) */
};
-int spindle_speed(void *, struct cnc_insn *);
-int spindle_start(void *, struct cnc_insn *);
-int spindle_stop(void *, struct cnc_insn *);
+int spindle_speed(struct spindle_softc *, struct cnc_insn *);
+int spindle_start(struct spindle_softc *, struct cnc_insn *);
+int spindle_stop(struct spindle_softc *, struct cnc_insn *);
+struct spindle_softc *spindle_find(int);
+
Modified: sys/files.cnc
===================================================================
--- sys/files.cnc 2009-03-25 08:24:59 UTC (rev 23)
+++ sys/files.cnc 2009-03-25 08:34:44 UTC (rev 24)
<at> <at> -10,6 +10,7 <at> <at>
file dev/cnc/cnc_cbrt.c cnc needs-flag
file dev/cnc/cnc_log10.S cnc needs-flag
file dev/cnc/cnc_modf.c cnc needs-flag
+file dev/cnc/cnc_fixunssfdi.c cnc needs-flag
file dev/cnc/cnc_quintic.c cnc needs-flag
# Servo or stepping motor with clock/direction interface.
<at> <at> -31,3 +32,24 <at> <at>
device estop
attach estop at gpio
file dev/cnc/cnc_estop.c estop needs-flag
+
+# General-purpose position-sensing encoder.
+device encoder
+attach encoder at gpio
+file dev/cnc/cnc_encoder.c encoder needs-flag
+
+# Manual pulse generator with optional axis selection.
+device mpg
+attach mpg at gpio
+file dev/cnc/cnc_mpg.c mpg needs-flag
+
+# General-purpose status LED.
+device cncstatled
+attach cncstatled at gpio
+file dev/cnc/cnc_statled.c cncstatled needs-flag
+
+# Serial LCD interface (std. 8250/16[45]50 in polled mode).
+device cnclcd
+file dev/cnc/cnc_lcd.c cnclcd needs-flag
+attach cnclcd at isa with cnclcd_isa
+file dev/cnc/cnc_lcd_isa.c cnclcd_isa
RSS Feed