Main Page | Data Structures | File List | Data Fields | Globals

siutils.c File Reference

Applied Motion Products Si Microstep Drive API Utility Functions. More...

#include "siutils.h"
#include <limits.h>

Functions

int SCLOpenPort (char *devname)
 Open a connection to an Si microstep drive comm port.

void SCLClosePort (int portFD)
 Close an open Si microstep drive comm port.

int SCLReadPort (int portFD, char *reply, long timeout)
 Read data from the Si microstep drive comm port.

int SCLSendQuery (int portFD, char *sclCmd, char *sclVal, long timeout)
 Query the Si microstep drive for the value of a parameter.

int SCLSendCommand (int portFD, char *sclCmd, char *errstr)
 Send a command to the Si microstep drive.

int SCLReqStatus (int portFD, char *errstr, long timeout)
 Query the Si microstep drive for the request status.

int SCLGetPos (int portFD, char *errstr, long timeout)
 Query the Si microstep drive for the immediate absolute position (IP).

int SCLGetDist (int portFD, char *errstr, long timeout)
 Query the Si microstep drive for the immediate distance (ID).

int SCLInStatus (int portFD, char *bitstr, long timeout)
 Query the Si microstep drive for the Input Status (IS).

int SCLReadStatus (char *bitstr, int *inbits, int ndata, char *ismask)
 Read and interpret a controller Input Status (IS) bit string.

void SCLAbort (int portFD)
 Abort a move (Stop/Kill).

int SCLGetParams (int portFD, si_drivepars_t *dpars, char *reply, long timeout)
 Query the Si microstep drive for all drive parameters.

int SCLHexToInt (char *hexstr)
 Convert Hexadecimal output from an Si microstep drive to decimal.

char * SCLStatus (int status)
 Convert SCL mechanism status codes into text.

int SCLSleep (long msec)
 Pause execution for a certain number of milliseconds.

double SCLTimeStamp (void)
 Create a numerical timestamp by reading the system clock.

void SCLUpper (char *str)
 Convert all characters in a string to uppercase.


Detailed Description

Applied Motion Products Si Microstep Drive API Utility Functions.

These functions handle basic serial port communications, creation and parsing of valid SCL command strings, reply handling, and basic low-level functions useful for working with the Applied Motion Product Si family of microstep stepper-motor controllers.

Designed to be self-contained, without dependences on any other OSU (or other) libraries.

The actual motion routines are the MechXXX functions, implemented in mechanism.c. They use a common mechanism configuration struct, si_mechanism. A very large number of possible mechanism configurations are encapsulated within this struct and set of functions.


Function Documentation

int SCLOpenPort char *  devname  ) 
 

Open a connection to an Si microstep drive comm port.

Parameters:
devname Device name of the comm port to open
Returns:
File descriptor of the open comm port connection, or -1 if an error.
Performs the necessary initialization functions to open a comm port to an Si microstep drive. The device name syntax is as follows:
     /dev/ttyXX#  = regular serial port (tty port)
     host:port    = network serial port server address (IP and port #).
  
The former is for a microstep drive connected to a direct serial port, or to a virtual serial port (e.g., on a remote terminal server like a Comtrol DeviceMaster RTS using a virtual serial port device driver). The latter is for a direct network socket connection to a remote serial port server (e.g., a Comtrol RTS configured as a socket server).

For socket communications with a network serial port server, we use INET streams (SOCK_STREAM) with a persistent client connection. This is pretty much standard for most devices on the market.

For a regular serial port, we set the attributes to 9600 baud, 8 data bits, 1 stop bit, and no parity as required by the Si microstep drive's serial port.

See also:
SCLClosePort()

void SCLClosePort int  portFD  ) 
 

Close an open Si microstep drive comm port.

Parameters:
portFD File descriptor of the microstep drive's comm port
Simple wrapper for close(). Doesn't do much now, but it does provide for future expansion if we want close to do more.

See also:
SCLOpenPort()

int SCLReadPort int  portFD,
char *  reply,
long  timeout
 

Read data from the Si microstep drive comm port.

Parameters:
portFD File descriptor of the microstep drive's comm port
reply Character string to contain the output
timeout Wait timeout seconds for input
Returns:
The number of characters read, or <0 if an error. -1 on error or timeout, with reply containing the error message text.
Uses select() to read data from the specified comm port file descriptor with the timeout interval specified. Note that because we could be reading a stream rather than a line-buffered source (e.g., portFD points to a socket stream to a network serial port server like a Comtrol DeviceMaster RTS instead of a regular direct serial port), the data could come in bursts depending on the system state and stream synchronization. As such we read in chunks of data w/o blocking until we have read everything from the port, which means looking for the \r (ASCII 13 = Ctrl+M) terminator. This makes the logic tricky, but robust against most comm glitches. Use of a timeout allows us to break out of cases where the message is unterminated because of a comm fault, not because of the usual stream buffering/sync issues.

Note:
If select() is interrupted by Ctrl+C, it returns an error message in the reply string.

int SCLSendQuery int  portFD,
char *  sclCmd,
char *  sclVal,
long  timeout
 

Query the Si microstep drive for the value of a parameter.

Parameters:
portFD File descriptor of the Si microstep drive's comm port
sclCmd Character string with the parameter query command
sclVal Character string to contain the parameter query response
timeout Wait timeout seconds for a reply
Returns:
The number of characters read, or <0 if an error. -1 on error or timeout, with the sclVal string containing the error message text.
Sends a query command to the Si microstep drive, then calls SCLReadPort() to get the reply (or bomb out after a timeout), and then strips the parameter value out of the reply string and returns it to the calling program. Since the Si microstep drive can send strings, ints, and floats as replies, we let the calling program handle interpretation of the reply (but see SCLReadStatus() for a function specifically to pull apart input status bit strings).

See also:
SCLReadPort()

int SCLSendCommand int  portFD,
char *  sclCmd,
char *  errstr
 

Send a command to the Si microstep drive.

Parameters:
portFD File descriptor of the Si microstep drive's comm port
sclCmd Character string with the parameter query command
errstr Character string to contain any error messages
Returns:
0 if successful, -1 if an error, at which point the errstr string contains the error message text.
Sends a command to the Si microstep drive and returns. Most SCL commands do not generate replies from the microstep drive unless they are query commands (at which point you should use the SCLSendQuery() function). This routine makes sure the commands are in uppercase, and terminated with \r (ASCII 13 = Ctrl+M) as required. A errstr string argument is used to contain detailed error messages if needed.

In general, an application would send a command, then send a query to check up on it. We don't place that burder on this routine since not all commands have query versions (i.e., they do not generate a response from the microstep drive when sent with no arguments).

See also:
SCLSendQuery()

int SCLReqStatus int  portFD,
char *  errstr,
long  timeout
 

Query the Si microstep drive for the request status.

Parameters:
portFD File descriptor of the Si microstep drive's comm port
errstr Error string if there are problems
timeout Timeout interval in seconds
Returns:
An integer code indicating the request status, or -1 if an error occurred (read/write/timeout) with an error message in errstr. If successful, errstr contains a description of the state as a convenience.
Sends the Si microstep drive an RS (Request Status) command to ask what it is doing right now. The RS command returns one of 5 responses:
        R = microstep drive ready (to receive commands)
        M = move in progress
        W = wait input (WI) command executing
        T = wait time (WT) command executing (aka, a sleep)
        E = servo positioning fault, requires power cycling to clear (bad)
   
These are translated into integer codes, defined in siutils.h as follows:
  • SI_READY Ready: Drive is idle and ready to receive commands
  • SI_MOVING Moving: Motion in progress
  • SI_WIEXEC Wait-for-Input: Executing wait-until-input (WI) command
  • SI_WTEXEC Wait-for-Time: Executing a wait-for-time (WT) command
  • SI_SFAULT ServoFault: Servo positioning fault
RS is different from all other SCL queries in that it does not return an keyword=value pair, but just the value, hence it requires a separate handler. This function is provided to help applications monitor the progress of long moves. It would be called in a polling loop to monitor progress in a simple way (i.e., moving/not).

int SCLGetPos int  portFD,
char *  errstr,
long  timeout
 

Query the Si microstep drive for the immediate absolute position (IP).

Parameters:
portFD File descriptor of the Si microstep drive's comm port
errstr Error string if there are problems
timeout Timeout interval in seconds
Returns:
The integer absolute position in steps, or -1 if an error occurred, and errstr contains a verbose error message.
Sends the Si microstep drive an IP (Immediate Position) query. This returns the immediate position as a hexadecimal-coded string. This function converts this string into an integer to return to the calling application using SCLHexToInt(). This function is useful for monitoring the progress of a move.

Calls:
SCLSendQuery() and SCLHexToInt()
See also:
SCLGetDist()

int SCLGetDist int  portFD,
char *  errstr,
long  timeout
 

Query the Si microstep drive for the immediate distance (ID).

Parameters:
portFD File descriptor of the Si microstep drive's comm port
errstr Error string if there are problems
timeout Timeout interval in seconds
Returns:
The integer distance in steps. If an error occured, the distance is 0, and errstr contains a verbose error message. Note that move distances may be positive or negative, so -1 does not imply errors.
Sends the Si microstep drive an ID (Immediate Distance) query. This returns the immediate distance as a hexadecimal-coded string. This function converts this string into an integer to return to the calling application using SCLHexToInt(). This function is useful for monitoring the progress of a move.

Calls:
SCLSendQuery() and SCLHexToInt()
See also:
SCLGetPos()

int SCLInStatus int  portFD,
char *  bitstr,
long  timeout
 

Query the Si microstep drive for the Input Status (IS).

Parameters:
portFD File descriptor of the Si microstep drive's comm port
bitstr String to contain the input status string
timeout Timeout interval in seconds
Returns:
0 if successful with bitstr containing the input status -1 if an error occurred, and bitstr contains a verbose error message. bitstr should be made large enough by the calling application to handle the error message.
Sends the Si microstep drive an IS (Input Status) query. This returns a string in bitstr with 1s and 0s. The order of the bits returned is the same as that received from the controller:
     IS=10000001
        ||||||||
        |||||||+- IN1
        ||||||+-- IN2
        |||||+--- IN3
        ||||+---- IN4
        |||+----- IN5 (or cw jog if enabled) 
        ||+------ IN6 (or ccw jog if enabled)
        |+------- IN7 (cw limit  - RESERVED) 
        +-------- IN8 (ccw limit - RESERVED) 
  
The SCLReadStatus() function is provided to parse this string into an integer array of 0/1 flags making it more useful for applications. Unless the calling application is simply interested in displaying the raw input bit pattern, a call to SCLInStatus() is usually followed by a call to SCLReadStatus().

Calls:
SCLSendQuery()
See also:
SCLReadStatus()

int SCLReadStatus char *  bitstr,
int *  inbits,
int  ndata,
char *  ismask
 

Read and interpret a controller Input Status (IS) bit string.

Parameters:
bitstr String of 1s and 0s returned by the IS command (see SCLInStatus())
inbits Array of type int and size 8 to hold the input status bits
ndata Number of data bits
ismask String with the input status (IS) bit mask
Returns:
0 on success if ndata=0, otherwise it returns the decimal representation of the ndata bits starting with IN1. It also replaces bitstr by the masked version for better readability. If an error occurs, it returns -1.
This function interprets a string of 1s and 0s returned from the microstep controller by the IS (Input Status) command, for example as returned by a call to SCLInStatus(). For example:
     IS=11111001
        ||||||||
        |||||||+- IN1
        ||||||+-- IN2
        |||||+--- IN3
        ||||+---- IN4
        |||+----- IN5 (or cw jog if enabled) 
        ||+------ IN6 (or ccw jog if enabled)
        |+------- IN7 (cw limit  - RESERVED) 
        +-------- IN8 (ccw limit - RESERVED) 
   

This function traverses bitstr and creates an inbits[] array of integers containing 1 if the input is asserted, 0 if the input is not asserted. The Si series of microstep controllers gives INi=0 when current is flowing through the sensor ("closed"), and INi=1 if no current is flowing ("open").

It is considered a "good practice" to connect device inputs (e.g., position encoder sensors) starting with IN1 in the order IN1=LSB ... IN(ndata)=MSB, where "ndata" is the number of data bits passed to this routine by the ndata variable. If ndata>0, the bits inbit[0] through inbit[ndata-1] are converted into a decimal integer and returned by the function, assuming IN1 = LSB and IN<ndata> = MSB for the conversion.

Input Status Masking
Since in practice inputs may be either normally open or normally closed depending on the application, we must be able to distinguish between these when translating the input status string. We accomplish this by using an input status mask (ismask), a string of eight (8) 1s and 0s, defined as follows. For the i-th mask bit,
   0  means the input is asserted (true) when INi=0 (closed)
   1  means the input is asserted (true) when INi=1 (open)
   
Beware: the order of bits in ismask is identical to the order of bits in the raw IS input string above (i.e., IN8..IN1).

Input Status Mask Example:
An 8-position filter wheel uses normally-open proximity sensors as position encoders. Each discrete position is encoded by drilling a pattern of holes representing the 3 bits at each valid filter position: open hole=1, closed-hole=0. For each filter, a 4th "in-position" bit is drilled that is always open below the in-position sensor when that filter is centered in a valid position. The 3 position bit sensors are connected to IN1..IN3 (ndata=3), and the in-position sensor is connected to IN4. IN5..IN8 are unused, and since they are unconnected and therefore are always open, they will always appear as 1s in IN5..IN8 in the IS query string. The ismask to use with this device would be:
 
   ismask=00001111;
   
IN1..IN4 is 1 if there is a hole under the proximity sensor (binary 1 = "asserted"), and 0 if there is metal under the sensor (binary 0 = "deasserted"). We mask IN5..IN8 as 0 so that they always be deasserted 0 since they are unused. The result of using this mask on the above IS string is as follows:
   bitstr = 11111001
   ismask = 00001111
   result = 00001001
   
The final output mask makes it easy to see that only IN1 (position 1s bit) and IN4 (the in-position bit) are asserted. This means the filter wheel is in position "1". The resulting 1s and 0s are loaded into inbits[0..7] for return to the calling routine for subsequent use. Because ndata=3, the function returns 1. bitstr is replaced by the "result" string when the function returns.

Without input masks we'd have to interpret each bit depending on detailed mechanism configuration in the code, greatly complicating coding. In practice, a device input mask is usually provided for the application by way of an external runtime configuration file. This obviates the need to hardcode the input mask (and thus obviating the need to recompile to make changes to the mask).

See also:
SCLInStatus()

void SCLAbort int  portFD  ) 
 

Abort a move (Stop/Kill).

Parameters:
portFD File descriptor of the Si microstep drive's comm port
Sends the Si microstep drive an SK (Stop/Kill) command. This will abort the motion in progress and clear any pending move commands from the command buffer. This is a simple wrapper for the SK command. It uses a low-level write() call to the specified file descriptor. No return reply is serviced.

Note that it is harmless to send an SK command to an idle microstep drive.

int SCLGetParams int  portFD,
si_drivepars_t dpars,
char *  reply,
long  timeout
 

Query the Si microstep drive for all drive parameters.

Parameters:
portFD File descriptor of the Si microstep drive's comm port
dpars Pointer to an si_drivepars struct to hold the drive parameters
reply Character string to contain status/error messages generated.
timeout Timeout interval in seconds
Returns:
0 if successful, -1 if an error occured during parameter query, with the error state described by reply. On success, reply contains a bland congratulatory notice of success.
Queries the Si microstep drive and retrieves all of the relevant drive parameters, loading them into the slc_drivepars struct. This is a passive query, no changes are made to the drive.

This function makes 20 queries of the drive (note that IP and SP are redundant, so only IP is called via SCLGetPos()). Since typical queries require ~40-50msec to work through the serial communications, this function takes approximately 1 second to execute.

Calls:
SCLReqStatus(), SCLSendQuery(), SCLGetDist(), and SCLGetPos()

int SCLHexToInt char *  hexstr  ) 
 

Convert Hexadecimal output from an Si microstep drive to decimal.

Parameters:
hexstr String with a hexadecimal number to convert
Returns:
Decimal integer equivalent of hexstr, or 0 if garbage.
During a move, the Si microstep drive can be queried to give the immediate absolute position (IP), the immediate distance moved (ID), and the immediate encoder value (IE). Because conversion from hex to an integer would tax the Si microstep drive's CPU during a move, it instead delivers a raw hexadecimal value and expects (rightly) that the calling application can do the conversion trivially.

Well, not so trivial, there is a sign offset that must be dealt with. This function handles that conversion transparently. It requires that the limits.h header be included.

This function assumes that hexstr is raw SCL format hex output of the form FFFFD8F0, without the 0x preamble more often used in C-language applications. Note that hextstr must be no longer than 8+1 chars otherwise the data value will be out of range.

This function is used internally by the SCLGetPos() and SCLGetDist() functions.

char* SCLStatus int  status  ) 
 

Convert SCL mechanism status codes into text.

Parameters:
status SCL mechanism status code
Returns:
Pointer to text string with message text.
Convert the mechanism status code returned by an SCLResStatus() query into human-readable text. Motion status codes are defined in siutils.h as follows:
  • SI_READY Ready: Drive is idle and ready to receive commands
  • SI_MOVING Moving: Motion in progress
  • SI_WIEXEC Wait-for-Input: Executing wait-until-input (WI) command
  • SI_WTEXEC Wait-for-Time: Executing a wait-for-time (WT) command
  • SI_SFAULT ServoFault: Servo positioning fault
This helper function is used to make for more human-readable output, whereas typical internal functions would make use of the integer codes.

See also:
SCLReqStatus()

int SCLSleep long  msec  ) 
 

Pause execution for a certain number of milliseconds.

Parameters:
msec Time to sleep in milliseconds
Returns:
0 if successful, -1 if there were problems. errno says what is bothering it.
This function provides a simple way to use nanosleep() for timed pauses. nanosleep is the POSIX.1b conformal way of suspending a process for a certain time. nanosleep() is a replacement for the obsolete usleep() when a sleep interval more fine-grained than sleep() is required. sleep() only allows intervals in integer seconds, which is not short enough for some applications. For most of what we do, msec are the appropriate interval, and nanosleep() can be somewhat involved to setup, as the code below should reveal.

See "man 2 nanosleep" for details on the nanosleep() function.

double SCLTimeStamp void   ) 
 

Create a numerical timestamp by reading the system clock.

Returns:
Double-precision float with the number of seconds elapsed since 1970 January 1.
Reads the system's time clock and returns a double-precision float with the time in seconds to microsecond precision since UTC 1970 January 1. This provides us with a fine-grained numerical timestamp for applications that call these utilities.

Note that while the precision is in microseconds, accuracy is quite a different question...

void SCLUpper char *  str  ) 
 

Convert all characters in a string to uppercase.

Parameters:
str String to be converted to uppercase. Changed by this function.
Helper utility to convert all characters in a string to uppercase. All SCL commands are required to be in uppercase.


Generated on Mon Jul 19 16:32:37 2004 for Si Microstep Controller API by doxygen 1.3.7