/* $FabBSD$ */ /* * Copyright (c) 2009 Hypertriton, Inc. * All rights reserved. * * 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. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 AUTHOR 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. */ /* * Program to control the cnc(4) interface. */ #include #include #include #include #include #include #include #include #include #include #include #include "pathnames.h" static const char *showopt_list[] = { "devices", "info", "limits", "position", "tools", NULL }; static const char *flushopt_list[] = { "info", NULL }; const char *device = _PATH_DEV_CNC; const char *timingsfile = _PATH_TIMINGS; const char *showopt = NULL; const char *flushopt = NULL; int devfd = -1; int quiet = 0; static void printusage(const char *optlist[]) { extern char *__progname; if (optlist != NULL) { const char **s = &optlist[0]; fprintf(stderr, "acceptable modifiers: "); while (*s != NULL) { fputs(*s, stderr); fputc(' ', stderr); s++; } fputc('\n', stderr); } else { fprintf(stderr, "usage: %s [-qCc] [-c timingfile] " "[-s modifier] [-F modifier] [-p coords]" "\n", __progname); } exit(1); } static const char * lookup_option(char *cmd, const char **list) { if (cmd != NULL && *cmd) { for (; *list; list++) if (!strncmp(cmd, *list, strlen(cmd))) return (*list); } return (NULL); } static int calibrate_timings(void) { struct cnc_timings t; FILE *f; t.hz = 0; if ((f = fopen(_PATH_TIMINGS, "r")) != NULL) { char buf[128], *s = &buf[0]; char *s1, *s2; fread(buf, sizeof(buf), 1, f); s1 = strsep(&s, "\n"); s2 = strsep(&s, "\n"); t.hz = (cnc_utime_t)strtoull(s1, (char **)NULL, 10); fclose(f); } if (ioctl(devfd, CNC_SETTIMINGS, &t) == -1) { err(1, "CNC_SETTIMINGS"); } if (t.hz == 0) { printf("Calibrating timings. This may take several minutes...\n"); if (ioctl(devfd, CNC_CALTIMINGS, &t) == -1) { err(1, "CNC_CALTIMINGS"); } printf("Saving timings to %s\n", _PATH_TIMINGS); if ((f = fopen(_PATH_TIMINGS, "w")) != NULL) { fprintf(f, "%llu\n", t.hz); fclose(f); } else { warn("%s", _PATH_TIMINGS); } } if (!quiet) { printf("Timings calibrated successfully (1Hz=%llu)\n", t.hz); } return ioctl(devfd, CNC_SETTIMINGS, &t); } int main(int argc, char *argv[]) { struct cnc_vector pos; char pb[128]; int ch; int do_cal = 0; if ((devfd = open(device, O_WRONLY)) == -1) err(1, "%s", device); while ((ch = getopt(argc, argv, "Cs:F:p:")) != -1) { switch (ch) { case 'C': do_cal = 1; break; case 's': if ((showopt = lookup_option(optarg, showopt_list)) == NULL) { warnx("Unknown show modifier '%s'", optarg); printusage(showopt_list); } break; case 'F': if ((flushopt = lookup_option(optarg, flushopt_list)) == NULL) { warnx("Unknown flush modifier '%s'", optarg); printusage(flushopt_list); } break; case 'q': quiet = 1; break; case 'p': if (!quiet) { if (ioctl(devfd, CNC_GETPOS, &pos) == -1) { errx(1, "CNC_GETPOS"); } cnc_vec_print(&pos, pb, sizeof(pb)); printf("%s -> %s\n", pb, optarg); } if (cnc_vec_parse(&pos, optarg) == -1) errx(1, "-p: %s", cnc_get_error()); if (ioctl(devfd, CNC_SETPOS, &pos) == -1) errx(1, "CNC_SETPOS"); break; default: printusage(NULL); } } if (argc == 0) printusage(NULL); if (do_cal) { calibrate_timings(); } else if (showopt) { switch (*showopt) { case 'p': { struct cnc_vector pos; char pb[128]; if (ioctl(devfd, CNC_GETPOS, &pos) == -1) { errx(1, "CNC_GETPOS"); } cnc_vec_print(&pos, pb, sizeof(pb)); fputs(pb, stdout); fputc('\n', stdout); } break; case 'd': { struct cnc_device_info di; if (ioctl(devfd, CNC_GETDEVICEINFO, &di) == -1) { errx(1, "CNC_GETDEVICEINFO"); } printf("Devices:\n"); printf(" %d servos\n", di.nservos); printf(" %d spindles\n", di.nspindles); printf(" %d estops\n", di.nestops); printf(" %d encoders\n", di.nencoders); printf(" %d MPGs\n", di.nmpgs); } break; case 'i': { struct cnc_stats st; if (ioctl(devfd, CNC_GETSTATS, &st) == -1) { errx(1, "CNC_GETSTATS"); } printf("Counters\n"); printf(" peak-velocity %lu\n", (u_long)st.peak_velocity); printf(" e-stops %lu\n", (u_long)st.estops); } break; case 'l': { struct cnc_kinlimits kl; if (ioctl(devfd, CNC_GETKINLIMITS, &kl) == -1) { errx(1, "CNC_GETKINLIMITS"); } printf("Kinematic limits\n"); printf(" max-velocity %lu\n", (u_long)kl.Fmax); printf(" max-accel %lu\n", (u_long)kl.Amax); printf(" max-jerk %lu\n", (u_long)kl.Jmax); } break; case 't': { struct cnc_tool t; int i, ntools; if (ioctl(devfd, CNC_GETNTOOLS, &ntools) == -1) { errx(1, "CNC_GETNTOOLS"); } printf("%d tools:\n", ntools); for (i = 0; i < ntools; i++) { t.idx = i; if (ioctl(devfd, CNC_GETTOOLINFO, &t) == -1) { errx(1, "CNC_GETTOOLINFO(%d)", t.idx); } cnc_tool_print(&t); } } break; } } else if (flushopt) { switch (*showopt) { case 'i': if (ioctl(devfd, CNC_CLRSTATS) == -1) errx(1, "CNC_CLRSTATS"); break; } } close(devfd); return (0); }