#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/time.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <pthread.h>
#include <linux/ppdev.h>
#include <linux/parport.h>
#include "logerr.h"
#include "motion.h"
Classes | |
struct | Devicestate |
The bit pattern currently applied to the parallel port data register. More... | |
struct | Axismapping |
Logical to physical axis mapping. More... | |
struct | Stagelocation |
Coordinates representing a position along multiple axes. More... | |
struct | Stagecontrol |
Grouping of definitions for one parallel port and all its dependent axes. More... | |
struct | Translation |
Everything needed to control a translational stage axis. More... | |
Defines | |
#define | resting_condition(a) |
Typedefs | |
typedef const char * | stagelabelp_t |
All the stage axis labels are immutable strings. | |
typedef const unsigned char | axistates_t |
Representation of bit patterns controlling the stepper motor phases. | |
Enumerations | |
enum | stagecommandflags { STAGE_DEAD = 0, STAGE_LIVE = 1, STAGE_COMMANDABLE = 1<<1, STAGE_WATCHABLE = 1<<2 } |
Stage status flags. | |
Functions | |
axismappingp_t | newaxismapping (const unsigned int axes) |
Make a new logical to physical axis mapping table. | |
void | disposeaxismapping (axismappingp_t themap) |
Destroy a logical to physical axis mapping table. | |
void | setaxismapping (axismappingp_t themap, const unsigned int logical, const axismapentry_t physical) |
Change an entry in a logical to physical axis mapping table. | |
stagelocationp_t | newstagelocation (unsigned int axes) |
Make a new generalized stage coordinate vector. | |
void | disposestagelocation (stagelocationp_t theloc) |
Destroy a generalized stage coordinate vector. | |
void | setstagelocation (stagelocationp_t theloc, const unsigned int axisn, const coord_t newval) |
Change one coordinate in a generalized stage coordinate vector. | |
coord_t | getstagelocation (const stagelocationp_t theloc, const unsigned int axisn) |
Access one coordinate in a generalized stage coordinate vector. | |
stagecontrolp_t | newstage (const axismappingp_t themap) |
Initialize the data structures representing a stage (including the axes). | |
void | disposestage (stagecontrolp_t stage) |
Destroy a stage data structure (without checking to see if it is in use). | |
int | openstage (stagecontrolp_t stage, const char *path, const int flags) |
Connect to the physical port controlling the stage. | |
int | closestage (stagecontrolp_t stage) |
Halt control of the stage, without de-allocating all data structures. | |
int | movestage (stagecontrolp_t stage, const stagelocationp_t motn) |
Issue a request that the stage move to a particular position. | |
int | findstage (stagecontrolp_t stage, stagelocationp_t posn) |
Copy the various axis positions into a coordinate structure. | |
int | stageactive (stagecontrolp_t stage) |
Examine the stage to find if it is active. |
Some stages rely on the controlling computer to handle the low-level details of the motors that drive them, in contrast to those that dedicate an intelligent controller to these tasks, with which the controlling computer can communicate using some high-level protocol over something like a serial interface.
This particular implementation is for stages driven by stepper motors connected directly to parallel ports. Individual phases on the motor are either active or inactive depending on whether a particular bit on a parallel interface is asserted or not. The software can rotate the motor only by suppling a sequence of bit patterns that will cause the motor phases to activate and de-activate in the correct order. Apart from possibly microswitches that change input bits on the parallel interface when the stage reaches a home position, only a count of the steps moved by each motor gives any indication of the actual stage position. Individual motors drive each axis of the stage, but more than one motor may share a single port, provided we can assign each a distinct group of bits within the port.
We have based the low-level parallel port control on the ppdev
driver, which exposes the necessary details of the port to user-level programs under Linux. Unlike the Solaris version of the motion control code, this means we do not have to provide a custom-written kernel module; documentation for ppdev
is included as part of the Linux kernel source, and Tim Waugh (one of the original authors) provides a manual at http://people.redhat.com/twaugh/parport/html/parportguide.html for the Linux 2.4 kernel version. We rely on a Posix Threads implementation for two important aspects of the stage motion control: a distinct thread becomes responsible for handling each axis of the stage, and variations in the timeouts as the threads wait on condition variables determine the variations in the motor speed.
|
Value: ((a->pos == a->goalpos) && \ (a->delay >= a->maxdelay) && \ ((a->delta < 0) == (a->backlash == 0)) && \ ((a->delta > 0) == (a->backlash == a->maxlash))) |
|
Halt control of the stage, without de-allocating all data structures. This is the inverse of openstage(), returning to a state similar to that when the stage data structures were allocated but unused. We wait for stage activity to cease, cancel the controlling threads for each axis, place the port in a quiescent state, then close it.
|
|
Destroy a logical to physical axis mapping table.
|
|
Destroy a stage data structure (without checking to see if it is in use).
|
|
Destroy a generalized stage coordinate vector.
|
|
Copy the various axis positions into a coordinate structure. If the stage is at rest, this finds its current position; however if the axes are in motion the stage may have moved from the recorded position before this returns.
|
|
Access one coordinate in a generalized stage coordinate vector.
|
|
Issue a request that the stage move to a particular position.
|
|
Make a new logical to physical axis mapping table. The logical axes are numbered from 0 to axes - 1, and the physical axes are initially assigned the same numbers.
|
|
Initialize the data structures representing a stage (including the axes). The new stage is defined in terms of a logical to physical axis mapping, and we construct it by allocating not only the stage structure, but the structures that represent the physical port and the individual axes. However we leave to openstage() the task of opening the physical port and starting the threads responsible for controlling each axis.
|
|
Make a new generalized stage coordinate vector.
|
|
Connect to the physical port controlling the stage.
We need a stage data structure previously allocated by newstage() and a path that defines the physical port controlling the stage hardware (something like
|
|
Change an entry in a logical to physical axis mapping table.
|
|
Change one coordinate in a generalized stage coordinate vector.
|
|
Examine the stage to find if it is active. We try to acquire the lock on the stage structure, and immediately determine that the stage is busy if we can't acquire it, without examining anything else. As soon as we find an axis that's not in its resting state we also determine the stage must be busy, but test it again after waiting one polling interval (currently a hard-wired constant). However we release the lock before returning, so it's quite possible that the stage is busy again by the time this returns, if no other conditions are imposed.
|