/*********************************************************************** * * File name: SmarActMCS_lib.h * Author : Wayne Glettig, Marco Salathe * Version : Dez. 2011 * * Libray containing Methods to communicate with SmarActs Motor * Control System (MCS) * *********************************************************************** * Description of Error Nos: * * Most functions return an int, which corresponds to an error message. * 0: OK! (no errors, operation successful) * Scan Port Errors * 2: After automatic scan, no SmarAct MCS module could be found. * Serial Connection issues: * 10: /dev/ttyS0 cannot be opened * 11: /dev/ttyS1 cannot be opened * 12: /dev/ttyS2 cannot be opened * 13: /dev/ttyS3 cannot be opened * 14: Invalid TTY number specified. (only 0-3 are supported) * Baud rate setting * 15: Invalid Baud Rate (see table for valid entries) * Closing Serial Port errors: * 16: EBADF fd isn't a valid open file descriptor * 17: EINTR * 18: EIO * 19: Other close error. * Writing to Serial Port errors: * 20: EAGAIN * 21: EBADF fd is not open for writing (->try opening serial port) * 22: EFAULT * 23: EFBIG * 24: EINTR * 25: EINVAL * 26: EIO * 27: ENOSPC * 28: EPIPE * 29: Other write error. * Reading from Serial Port errors: * 30: EAGAIN nothing in input buffer (->MCS might be unplugged or on * another serial port) * 31: EBADF fd is not open for reading (->try opening serial port * read mode) * 32: EFAULT * 33: EINTR * 34: EINVAL * 35: EIO * 36: EISDIR * 37: Other read error. * Problems with reading Status back: (in readGS()) * 41: parseInput(): Reading from serial port worked, but could not * detect command beginning ':'. * 42: read.. in: channelIndex invalid (must be 0-5) * **********************************************************************/ //#define VERBOSE //#define REALTIME //use this if rtai serial port access is required // Includes: #include /* Standard input/output definitions */ #include #ifndef REALTIME #include /* Standard input/output definitions */ #include /* String function definitions */ #include /* UNIX standard function definitions */ #include /* File control definitions */ #include /* Error number definitions */ #include /* POSIX terminal control definitions */ #endif #ifdef REALTIME //realtime libraries are build in C, it doesn't understand C++ (badly build) hence this extern is important extern "C" { #include /*RTAI Serial Port Access*/ #include /*RTAI Linux Realtime*/ } #endif #define BUFFER_SIZE 2048 using namespace std; // Definition of structure "state" used in SmaractMCS struct state { double lastupdated; double value; }; /*********************************************************************** * SmaractMCS class definition: **********************************************************************/ class SmarActMCS { private: // Serial Connection Parameters: int fd; // file descriptor unsigned int TTY; // Serial Port No. unsigned int baudrate; // Baud Rate (speed_t is unsigned int) char readBuffer[BUFFER_SIZE]; // Buffer for serial in reading. unsigned int insBuf; // current insert position for new entries into Buffer // if insBuf>=BUFFER_SIZE // MCS State Variables: double currentTime; // To be used with state.lastupdated int MCS_IV[3]; // Interface Version: High, low, Build char MCS_ID [50]; // System ID String int MCS_NC; // Number of Channels // Axis state variables that are updated in parseInput() state statePPK[6]; // Physical Position known Status ("initialized?" Status) state stateP[6]; // Position State of Axes state stateS[6]; // State of Axes state lastError[6]; // Last Error no. public: // Input handling and Synchronisation int setTimestamp(double timestamp); // Set the timestamp int parseInput(); // empty input buffer and process replies (using currentTime variable) int parseInput(double timestamp); // empty input buffer and process replies int parseMCSReplyStr(char* str, double timestamp); SmarActMCS(); //Constructor ~SmarActMCS(); //Destructor // Serial Port Commands int initialize(int port, int baud); // Opens and configures serial port int initialize(); // Opens and configures serial port (using default values) int openSerialPort(); // Opens Serial Port Connection int openSerialPort(int tty); // Opens Serial Port Connection (ttyS0, 1, 2, 3) int openSerialPort(int tty, int baud); // Opens Serial Port Connection (with tty & baudrate) int setBaudRate(int baud); // Set baud rate variable. int closeSerialPort(); // Close Serial Port int clearBuf(); // Clear Buffer int sendMCS (char* cmd); // Send Command to MCS #ifdef REALTIME int readMCS (); // Read Result from MCS -> fill up readBuffer[] #endif #ifndef REALTIME int readMCS(char* buf, int* len); #endif // SmarAct MCS Commands: (See MCS RS232 Interface Documentation for details) int FRM(int channelIndex, int direction, int holdTime, int autoZero); // Find Reference Marks int sendGS(int channelIndex); // send Get Status Command int readGS(int channelIndex,double* status); // read Get Status Command reply int readGS(int channelIndex,double* status, double timestamp, double* delay); int sendGP(int channelIndex); // send Get Position Command int readGP(int channelIndex,double* status); // read Get Position Command reply int readGP(int channelIndex,double* status, double timestamp, double* delay); int sendGA(int channelIndex); // send Get Angle Command int readGA(int channelIndex,double* status); // read Get Angle Command reply int readGA(int channelIndex,double* status, double timestamp, double* delay); int sendGPPK(int channelIndex); // send Get Physical Position known? int readGPPK(int channelIndex,double* status); // read Get Physical Position known? reply int readGPPK(int channelIndex,double* status, double timestamp, double* delay); int sendGSI(); // send Get System ID int readGSI(char* ID); // read Get System ID reply int sendGNC(); // send Get Number of channels int readGNC(char* ID); // read Get Number of channels reply int SCLF(int channelIndex, int frequency); // Set Closed Loop Max Frequency (50-10'000) int SCLS(int channelIndex, int speed); // Set Closed Loop Speed int MPA(int channelIndex, int position, int holdTime); // Move to Position Absolute int MAA(int channelIndex, int position, int holdTime); // Move to Angle Absolute int MPR(int channelIndex, int position, int holdTime); int MAR(int channelIndex, int position, int holdTime); int SCM(int mode); // Set Communication Mode (0: Sync, 1:Async (no reply)) int SHE(int mode); // Set hand control module enable int S(); // Stop All Channels int S(int channelIndex); // Stop Channel int SP(int channelIndex, int position); // Set Position if channel int R(); // Reset int CB(int baudrate); // set Baudrate int CS(int channelIndex); // Calibrate sensor }; /*********************************************************************** * Definition of methods: **********************************************************************/ SmarActMCS::SmarActMCS() { strcpy(MCS_ID, "Not Set"); fd=0; memset(readBuffer,NULL, BUFFER_SIZE); // initialize read string to NUL NUL NUL NUL insBuf=0; } SmarActMCS::~SmarActMCS() { closeSerialPort(); } int SmarActMCS::initialize() { /* //AUTOMATIC INITIALISATION (Find port & baud rate automatically) //List possible ports & baudrates: int ports [] = {0,1}; //int bauds [] = {50,300,1200,2400,4800,9600,19200,38400,57600,115200};//aufsteigend //int bauds [] = {115200,57600,38400,19200,9600,4800,2400,1200,300,50};//absteigend int bauds [] = {115200,57600,38400,19200,9600};//absteigend //calculate lengths of above arrays. int num_ports = sizeof(ports)/sizeof(int); int num_bauds = sizeof(bauds)/sizeof(int); //set flags to -1: nothing found. int found_port = -1; int found_baud = -1; //scan ports & baudrates. for (int i=0; i 10) done=true; #ifdef VERBOSE printf("parseinput read: '%s'\n",sInput); #endif } #ifdef VERBOSE printf("parseinput counter: '%d'\n",counter); #endif // while (((err = readMCS(sInput,&len)) == 0)&&counter<10) { //#ifdef VERBOSE // printf("parseinput read: '%s'\n",sInput); //#endif // parseMCSReplyStr(sInput, timestamp); // counter++; // } return counter; } #endif #ifdef REALTIME int SmarActMCS::parseInput(double timestamp){ // read all contents from RS232 Serial Port to readBuffer readMCS(); /* Isolate the commands and pass to parseMCSReplyStr() * What to do: * - Find first occurence of ':' * if no occurence found, empty buffer (make buffer[0] = NULL). return. * if occurence found, ignore all before that ':'. (memmove(str, pStart, strlen(pStart)); * - Find first occurance of '\n'; * if no occurence found, return * if occurence found, isolate command: (from pStart to pStop)=>char Command[]. * Then remove command from buffer (memmove(str, pStop, strlen(pStop)); * Then further treat command: * go back to step 1. */ readBuffer[BUFFER_SIZE-1]=NULL; // make sure last element of readBuffer is NULL (string termination) // replace all NULL chars in buffer (from 0 to insBuf) with \n // (in case a ASCII 0 was sent via RS232.) for (unsigned int i=0;ichar Command[]. char command[BUFFER_SIZE]; size_t length = pStop+1-pStart; memcpy(command, pStart, length); command[length]=NULL; // terminate with NULL // Then remove command from buffer (memmove(str, pStop, strlen(pStop)); strcpy(readBuffer, pStop+1); insBuf=insBuf-((pStop+1)-readBuffer); // Then further treat command: #ifdef VERBOSE printf("DETECTED COMMAND: '%s'\n",command); printf("insBuf:%d, Buf:%s\n",insBuf, readBuffer); #endif // Send command to MCS Reply Parser. parseMCSReplyStr(command, timestamp); } } } return 0; } #endif int SmarActMCS::parseMCSReplyStr(char* str, double timestamp) { // Start Processing input string char *start = str; char sCommand [256]=""; char sArg1 [256]=""; char sArg2 [256]=""; char sArg3 [256]=""; int no_of_terms; // move start pointer to begging of command ':', if not found -> error if ((start = strchr(str,':'))==NULL) { return 41; } // Process command: Split up into Command, Arg1, Arg2, .... no_of_terms = sscanf(start,":%12[^1234567890-]%12[^,\n],%12[^,\n],%12[^,\n]", sCommand,sArg1,sArg2,sArg3); #ifdef VERBOSE printf("parsedInput: Number of terms: '%d'\n",no_of_terms); printf("parsedInput: String :'%s'\n",sCommand); printf("parsedInput: arg1 :'%s'\n",sArg1); printf("parsedInput: arg2 :'%s'\n",sArg2); #endif /* React according to Command: * E, * IV,, (reply of GIV Get Interface Version) * ID (reply of GSI, Get System ID) * NC (reply of GNC, Get Number of Channels) * P, (reply of GP, Get Position, position in nm) * A (reply of GA, Get Angle, angle in micro degrees) * S (reply of GS, Get Status) * PPK, (reply of GPPK, Get Physical Position Known, 0:unknown, 1: known) * * Not yet Supported: * CLS (reply of GCLS, Get closed loop speed) * SE (reply of GSE, Get Sensor Enabled) * ST, (Reply of GST, Get Sensor Type) * VL, (reply of GVL, Get Voltage Level) * BR (reply of CB, Configure Baudrate) * ESM (reply of GESM, get Emergency Stop Mode) * * IGNORE: * E-1,0 * E Channelindex, 0 */ // E, : if (strcmp(sCommand,"E")==0) { int channel = atoi(sArg1); double errorcode = atof(sArg2); if (channel == -1) { #ifdef VERBOSE printf("UNDERSTOOD: E-1,%s (Acknowledge message)\n",sArg2); #endif } else if (channel>=0&&channel<=5) { // update Last Error State lastError[channel].lastupdated = timestamp; lastError[channel].value = errorcode; #ifdef VERBOSE printf("UNDERSTOOD: E %lf\n", errorcode); #endif return 0; } } // IV,, (reply of GIV Get Interface Version) else if (strcmp(sCommand,"IV")==0) { MCS_IV[0] = atoi(sArg1); MCS_IV[1] = atoi(sArg2); MCS_IV[2] = atoi(sArg3); #ifdef VERBOSE printf("UNDERSTOOD: IV %d, %d, %d\n", MCS_IV[0], MCS_IV[1], MCS_IV[2]); #endif return 0; } // ID (reply of GSI, Get System ID) else if (strcmp(sCommand,"ID")==0) { strcpy(MCS_ID, sArg1); #ifdef VERBOSE printf("UNDERSTOOD: ID %s\n", MCS_ID); #endif return 0; } // NC (reply of GNC, Get Number of Channels) else if (strcmp(sCommand,"NC")==0) { MCS_NC = atoi(sArg1); #ifdef VERBOSE printf("UNDERSTOOD: NC %d\n", MCS_NC); #endif return 0; } // P, (reply of GP, Get Position, position in nm) else if (strcmp(sCommand,"P")==0) { int channelIndex = atoi(sArg1); double postion = atof(sArg2); if (channelIndex>=0&&channelIndex<=5) { // update Position State stateP[channelIndex].lastupdated = timestamp; stateP[channelIndex].value = postion; #ifdef VERBOSE printf("UNDERSTOOD: P %d %lf\n", channelIndex, postion); #endif return 0; } } // A (reply of GA, Get Angle, angle in micro degrees) else if (strcmp(sCommand,"A")==0) { int channelIndex = atoi(sArg1); double angle = atof(sArg2) + atof(sArg3)*360000000; if (channelIndex>=0&&channelIndex<=5) { // update Position State stateP[channelIndex].lastupdated = timestamp; stateP[channelIndex].value = angle; #ifdef VERBOSE printf("UNDERSTOOD: A %d %lf\n", channelIndex, angle); #endif return 0; } } // PPK, (reply of GPPK, Get Physical Position Known, 0:unknown, 1: known) else if (strcmp(sCommand,"PPK")==0) { int channelIndex = atoi(sArg1); double known = atof(sArg2); if (channelIndex>=0&&channelIndex<=5) { // update Position State statePPK[channelIndex].lastupdated = timestamp; statePPK[channelIndex].value = known; #ifdef VERBOSE printf("UNDERSTOOD: PPK %d %lf\n", channelIndex, known); #endif return 0; } } // S, (reply of GS, Get Status) else if (strcmp(sCommand,"S")==0) { int channelIndex = atoi(sArg1); double status = atof(sArg2); if (channelIndex>=0&&channelIndex<=5) { // update Position State stateS[channelIndex].lastupdated = timestamp; stateS[channelIndex].value = status; #ifdef VERBOSE printf("UNDERSTOOD: S %d %lf\n", channelIndex, status); #endif return 0; } } return 1; } int SmarActMCS::FRM(int channelIndex, int direction, int holdTime, int autoZero) { char cmd[254]; sprintf(cmd, "FRM%d,%d,%d,%d",channelIndex, direction, holdTime, autoZero); return sendMCS(cmd); } int SmarActMCS::sendGS(int channelIndex) { char cmd[254]; sprintf(cmd, "GS%d",channelIndex); return sendMCS(cmd); } int SmarActMCS::readGS(int channelIndex, double* status) { double delay; return readGS(channelIndex, status, currentTime, &delay); } int SmarActMCS::readGS(int channelIndex, double* status, double timestamp, double* delay) { // get new messages from input parseInput(); // channelIndex validtiy check (must be 0-5) if (channelIndex<0 && channelIndex>5) return 42; // read back status *delay = timestamp - stateS[channelIndex].lastupdated; *status = stateS[channelIndex].value; return 0; } int SmarActMCS::sendGP(int channelIndex) { char cmd[254]; sprintf(cmd, "GP%d",channelIndex); return sendMCS(cmd); } int SmarActMCS::readGP(int channelIndex, double* status) { double delay; return readGP(channelIndex, status, currentTime, &delay); } int SmarActMCS::readGP(int channelIndex, double* status, double timestamp, double* delay) { // get new messages from input parseInput(); // channelIndex validtiy check (must be 0-5) if (channelIndex<0 && channelIndex>5) return 42; // read back status *delay = timestamp - stateP[channelIndex].lastupdated; *status = stateP[channelIndex].value; return 0; } int SmarActMCS::sendGA(int channelIndex) { char cmd[254]; sprintf(cmd, "GA%d",channelIndex); return sendMCS(cmd); } int SmarActMCS::readGA(int channelIndex, double* status) { double delay; return readGA(channelIndex, status, currentTime, &delay); } int SmarActMCS::readGA(int channelIndex, double* status, double timestamp, double* delay) { // get new messages from input parseInput(); // channelIndex validtiy check (must be 0-5) if (channelIndex<0 && channelIndex>5) return 42; // read back status *delay = timestamp - stateP[channelIndex].lastupdated; *status = stateP[channelIndex].value; return 0; } int SmarActMCS::sendGPPK(int channelIndex) { char cmd[254]; sprintf(cmd, "GPPK%d",channelIndex); return sendMCS(cmd); } int SmarActMCS::readGPPK(int channelIndex, double* status) { double delay; return readGPPK(channelIndex, status, currentTime, &delay); } int SmarActMCS::readGPPK(int channelIndex, double* status, double timestamp, double* delay) { // get new messages from input parseInput(); // channelIndex validtiy check (must be 0-5) if (channelIndex<0 && channelIndex>5) return 42; // read back status *delay = timestamp - statePPK[channelIndex].lastupdated; *status = statePPK[channelIndex].value; return 0; } int SmarActMCS::sendGSI() { char cmd[254]; sprintf(cmd, "GSI"); return sendMCS(cmd); } int SmarActMCS::readGSI(char* ID) { parseInput(); strcpy(ID, MCS_ID); return 0; } int SmarActMCS::sendGNC() { char cmd[254]; sprintf(cmd, "GNC"); return sendMCS(cmd); } int SmarActMCS::readGNC(char* ID) { parseInput(); strcpy(ID, MCS_ID); return 0; } int SmarActMCS::SCLF(int channelIndex, int frequency) { char cmd[254]; sprintf(cmd, "SCLF%d,%d",channelIndex, frequency); return sendMCS(cmd); } int SmarActMCS::SCLS(int channelIndex, int speed) { char cmd[254]; sprintf(cmd, "SCLS%d,%d",channelIndex, speed); return sendMCS(cmd); } int SmarActMCS::MPA(int channelIndex, int position, int holdTime) { char cmd[254]; sprintf(cmd, "MPA%d,%d,%d",channelIndex, position,holdTime); return sendMCS(cmd); } int SmarActMCS::MPR(int channelIndex, int position, int holdTime) { char cmd[254]; sprintf(cmd, "MPR%d,%d,%d",channelIndex, position,holdTime); return sendMCS(cmd); } int SmarActMCS::MAA(int channelIndex, int position, int holdTime) { int period = (int) position / 360000000; int angle = position % 360000000; if(angle<0){ angle = 360000000 + angle; period--; } char cmd[254]; sprintf(cmd, "MAA%d,%d,%d,%d",channelIndex, angle, period, holdTime); return sendMCS(cmd); } int SmarActMCS::MAR(int channelIndex, int position, int holdTime) { int period = (int) position / 360000000; int angle = position % 360000000; if(angle<0){ angle = 360000000 + angle; period--; } char cmd[254]; sprintf(cmd, "MAR%d,%d,%d,%d",channelIndex, angle, period, holdTime); return sendMCS(cmd); } int SmarActMCS::SCM(int mode) { char cmd[254]; sprintf(cmd, "SCM%d",mode); return sendMCS(cmd); } int SmarActMCS::SHE(int mode) { /*0: In this mode the Hand Control Module is disabled. It may not be used to control positioners. *1: This is the default setting where the Hand Control Module may be used to control the positioners. *2: In this mode the Hand Control Module cannot be used to control the positioners. However, if there * are positioners with sensors attached, their position data will still be displayed. */ if (mode<3 && mode>=0){ char cmd[254]; sprintf(cmd, "SHE%d",mode); return sendMCS(cmd); } return 1; } int SmarActMCS::S() { char cmd[254]; sprintf(cmd, "S"); return sendMCS(cmd); } int SmarActMCS::S(int channelIndex) { char cmd[254]; sprintf(cmd, "S%d",channelIndex); return sendMCS(cmd); } int SmarActMCS::SP(int channelIndex, int position) { char cmd[254]; sprintf(cmd, "sP%d,%d",channelIndex, position); return sendMCS(cmd); } int SmarActMCS::R() { char cmd[254]; sprintf(cmd, "R"); return sendMCS(cmd); } int SmarActMCS::CB(int baudrate) { char cmd[254]; sprintf(cmd, "CB%d",baudrate); return sendMCS(cmd); } int SmarActMCS::CS(int channelIndex) { char cmd[254]; sprintf(cmd, "CS%d",channelIndex); return sendMCS(cmd); }