Mindstorms 3rd Party ROBOTC Drivers RobotC
[Home] [Download] [Submit a bug/suggestion] [ROBOTC Forums] [Blog] [Support this project]

MSMMUX-driver.h

Go to the documentation of this file.
00001 /*!@addtogroup mindsensors
00002  * @{
00003  * @defgroup msmmux NXT Motor MUX
00004  * NXT Motor MUX
00005  * @{
00006  */
00007 
00008 /*
00009  * $Id: MSMMUX-driver.h 56 2011-05-30 19:47:12Z xander $
00010  */
00011 
00012 #ifndef __MSMMUX_H__
00013 #define __MSMMUX_H__
00014 /** \file MSMMUX-driver.h
00015  * \brief Mindsensors Motor MUX driver
00016  *
00017  * MSMMUX-driver.h provides an API for the Mindsensors Motor MUX.
00018  *
00019  * Changelog:
00020  * - 0.1: Initial release
00021  *
00022  * Credits:
00023  * - Big thanks to Mindsensors for providing me with the hardware necessary to write and test this.
00024  *
00025  * License: You may use this code as you wish, provided you give credit where its due.
00026  *
00027  * THIS CODE WILL ONLY WORK WITH ROBOTC VERSION 2.00 AND HIGHER.
00028  * \author Xander Soldaat (mightor_at_gmail.com)
00029  * \date 05 April 2010
00030  * \version 0.1
00031  * \example MSMMUX-test1.c
00032  * \example MSMMUX-test2.c
00033  */
00034 
00035 #pragma systemFile
00036 
00037 #ifndef __COMMON_H__
00038 #include "common.h"
00039 #endif
00040 
00041 #ifndef __MMUX_H__
00042 #include "MMUX-common.h"
00043 #endif
00044 
00045 #define MSMMUX_I2C_ADDR         0x06  /*!< MSMMUX I2C device address */
00046 
00047 // Motor control registers
00048 #define MSMMUX_REG_CMD          0x41  /*!< Command register */
00049 
00050 #define MSMMUX_MOT_OFFSET       0x42  /*!< Motor regiser offset */
00051 #define MSMMUX_TARG_ENC         0x00  /*!< Target encoder value */
00052 #define MSMMUX_POWER            0x04  /*!< Motor power */
00053 #define MSMMUX_TARG_TIME        0x05  /*!< Time target value */
00054 #define MSMMUX_CMD_B            0x06  /*!< Command B register - for future use */
00055 #define MSMMUX_CMD_A            0x07  /*!< Command A regiser */
00056 #define MSMMUX_ENTRY_SIZE       0x08  /*!< Number of registers per motor channel */
00057 #define MSMMUX_TACHO_MOT1       0x62  /*!< Tacho count for motor 1 */
00058 #define MSMMUX_TACHO_MOT2       0x66  /*!< Tacho count for motor 2 */
00059 #define MSMMUX_STATUS_MOT1      0x72  /*!< Status for motor 1 */
00060 #define MSMMUX_STATUS_MOT2      0x73  /*!< Status for motor 2 */
00061 
00062 // PID registers
00063 #define MSMMUX_KP_TACHO         0x7A  /*!< Kp for Tachometer Position Control */
00064 #define MSMMUX_KI_TACHO         0x7C  /*!< Ki for Tachometer Position Control */
00065 #define MSMMUX_KD_TACHO         0x7E  /*!< Kd for Tachometer Position Control */
00066 #define MSMMUX_KP_SPEED         0x80  /*!< Kp for Speed Control */
00067 #define MSMMUX_KI_SPEED         0x82  /*!< Ki for Speed Control */
00068 #define MSMMUX_KD_SPEED         0x84  /*!< Kd for Speed Control */
00069 #define MSMMUX_PASSCOUNT        0x86  /*!< Encoder count tolerance when motor is moving */
00070 #define MSMMUX_TOLERANCE        0x87  /*!< Encoder count tolerance when motor is getting close to target */
00071 
00072 // Motor mode commands
00073 #define MSMMUX_CMD_RESET_ALL    0x52  /*!< Reset the tachos and motor values */
00074 #define MSMMUX_CMD_START_BOTH   0x53  /*!< Start both motors with parameters in motor registers */
00075 #define MSMMUX_CMD_FLOAT_MOT1   0x61  /*!< Stop motor 1 and allow to float */
00076 #define MSMMUX_CMD_FLOAT_MOT2   0x62  /*!< Stop motor 2 and allow to float */
00077 #define MSMMUX_CMD_FLOAT_BOTH   0x63  /*!< Stop both motors and allow to float */
00078 #define MSMMUX_CMD_BRAKE_MOT1   0x41  /*!< Stop motor 1 and brake */
00079 #define MSMMUX_CMD_BRAKE_MOT2   0x42  /*!< Stop motor 2 and brake */
00080 #define MSMMUX_CMD_BRAKE_BOTH   0x43  /*!< Stop both motors and brake */
00081 #define MSMMUX_CMD_RESET_MOT1   0x72  /*!< Reset the encoder count for motor 1 */
00082 #define MSMMUX_CMD_RESET_MOT2   0x73  /*!< Reset the encoder count for motor 2 */
00083 
00084 // Motor status fields
00085 #define MSMMUX_STAT_SPEED_CTRL  (0x01 << 0) /*!< Motor is programmed to move at a fixed speed. */
00086 #define MSMMUX_STAT_RAMPING     (0x01 << 1) /*!< Motor is currently ramping up or down */
00087 #define MSMMUX_STAT_POWERED     (0x01 << 2) /*!< Motor is powered, does not imply movement */
00088 #define MSMMUX_STAT_POS_CTRL    (0x01 << 3) /*!< Motor is either moving towards target or holding position. */
00089 #define MSMMUX_STAT_BRAKED      (0x01 << 4) /*!< Motor is braked.  0 means motor is floating */
00090 #define MSMMUX_STAT_OVERLOADED  (0x01 << 5) /*!< Set to 1 when motor can't achieve desired speed */
00091 #define MSMMUX_STAT_TIMED       (0x01 << 6) /*!< Motor is running for a specified duration */
00092 #define MSMMUX_STAT_STALLED     (0x01 << 7) /*!< Motor is stalled */
00093 
00094 // commandA fields
00095 #define MSMMUX_CMD_SPEED        0x01  /*!< Speed control of your motor */
00096 #define MSMMUX_CMD_RAMP         0x02  /*!< Ramp the speed up or down */
00097 #define MSMMUX_CMD_RELATIVE     0x04  /*!< Make encoder target relative to current position */
00098 #define MSMMUX_CMD_TACHO        0x08  /*!< Use the encoder target to control motor */
00099 #define MSMMUX_CMD_BRK          0x10  /*!< Whether to brake (1) or float (0) when motor has reached its target */
00100 #define MSMMUX_CMD_HOLDPOS      0x20  /*!< Motor will hold position when this is enabled and push back when moved */
00101 #define MSMMUX_CMD_TIME         0x40  /*!< Use the time target to control the motor */
00102 #define MSMMUX_CMD_GO           0x80  /*!< Instruct the MUX to start the motors using the current registers */
00103 
00104 #define MSMMUX_RAMP_NONE        0x00  /*!< Use no ramping at all */
00105 #define MSMMUX_RAMP_UP_DOWN     0x03  /*!< Use ramping to bring motor up to speed or to a halt */
00106 
00107 #define MSMMUX_ROT_UNLIMITED    0x00  /*!< Allow motor to rotate forever (or until batteries run out, of course) */
00108 #define MSMMUX_ROT_DEGREES      0x01  /*!< Use encoder target to control motor (ie rotate motor X number of degrees) */
00109 //#define MSMMUX_ROT_ROTATIONS    0x02
00110 #define MSMMUX_ROT_SECONDS      0x03  /*!< Use time target to control motor (ie run for X seconds) */
00111 
00112 
00113 tByteArray MSMMUX_I2CRequest;    /*!< Array to hold I2C command data */
00114 tByteArray MSMMUX_I2CReply;      /*!< Array to hold I2C reply data */
00115 
00116 // Function prototypes
00117 void MSMMUXinit();
00118 bool MSMMUXreadStatus(tMUXmotor muxmotor, ubyte &motorStatus);
00119 bool MSMMUXsendCommand(tSensors link, ubyte channel, long setpoint, byte speed, ubyte seconds, ubyte commandA);
00120 bool MSMMUXsendCommand(tSensors link, ubyte command);
00121 bool MSMMUXsetPID(tSensors link, int kpTacho, int kiTacho, int kdTacho, int kpSpeed, int kiSpeed, int kdSpeed, ubyte passCount, ubyte tolerance);
00122 bool MSMMotor(tMUXmotor muxmotor, byte power);
00123 bool MSMotorStop(tMUXmotor muxmotor);
00124 bool MSMotorStop(tMUXmotor muxmotor, bool brake);
00125 void MSMMotorSetRotationTarget(tMUXmotor muxmotor, long target);
00126 void MSMMotorSetTimeTarget(tMUXmotor muxmotor, int target);
00127 void MSMMotorSetEncoderTarget(tMUXmotor muxmotor, long target);
00128 void MSMMotorSetEncoderTarget(tMUXmotor muxmotor, long target, bool relative);
00129 long MSMMotorEncoder(tMUXmotor muxmotor);
00130 bool MSMMotorEncoderReset(tMUXmotor muxmotor);
00131 bool MSMMotorEncoderResetAll(tSensors link);
00132 bool MSMMotorBusy(tMUXmotor muxmotor);
00133 bool MSMMotorStalled(tMUXmotor muxmotor);
00134 void MSMMotorSetBrake(tMUXmotor muxmotor);
00135 void MSMMotorSetFloat(tMUXmotor muxmotor);
00136 void MSMMotorSetSpeedCtrl(tMUXmotor muxmotor, bool constspeed);
00137 void MSMMotorSetRamping(tMUXmotor muxmotor, bool ramping);
00138 
00139 
00140 /*
00141  * Initialise the mmuxData array needed for keeping track of motor settings
00142  */
00143 void MSMMUXinit(){
00144   for (int i = 0; i < 4; i++) {
00145     memset(mmuxData[i].runToTarget[0], false, 4);
00146     memset(mmuxData[i].brake[0], true, 4);
00147     memset(mmuxData[i].pidcontrol[0], true, 4);
00148     memset(mmuxData[i].target[0], 0, 4*4);
00149     memset(mmuxData[i].ramping[0], MSMMUX_RAMP_NONE, 4);
00150     memset(mmuxData[i].targetUnit[0], MSMMUX_ROT_UNLIMITED, 4);
00151     mmuxData[i].initialised = true;
00152   }
00153 }
00154 
00155 
00156 /**
00157  * Read the status byte of the specified motor
00158  *
00159  * @param muxmotor the motor-MUX motor
00160  * @param motorStatus status of the motor
00161  * @return true if no error occured, false if it did
00162  */
00163 bool MSMMUXreadStatus(tMUXmotor muxmotor, ubyte &motorStatus) {
00164 
00165   memset(MSMMUX_I2CRequest, 0, sizeof(tByteArray));
00166 
00167   MSMMUX_I2CRequest[0] = 2;               // Message size
00168   MSMMUX_I2CRequest[1] = MSMMUX_I2C_ADDR; // I2C Address
00169 
00170   switch ((byte)MPORT(muxmotor)) {
00171     case 0: MSMMUX_I2CRequest[2] = MSMMUX_STATUS_MOT1; break;
00172     case 1: MSMMUX_I2CRequest[2] = MSMMUX_STATUS_MOT2; break;
00173   }
00174 
00175   if (!writeI2C((tSensors)SPORT(muxmotor), MSMMUX_I2CRequest, 1))
00176     return false;
00177 
00178   if (!readI2C((tSensors)SPORT(muxmotor), MSMMUX_I2CReply, 1))
00179     return false;
00180 
00181   motorStatus = MSMMUX_I2CReply[0];
00182 
00183   return true;
00184 }
00185 
00186 
00187 /**
00188  * Send a command to the MMUX.
00189  *
00190  * Note: this is an internal function and shouldn't be used directly
00191  * @param link the MMUX port number
00192  * @param channel the channel the command should apply to
00193  * @param setpoint the encoder count the motor should move to
00194  * @param speed the speed the motor should move at
00195  * @param seconds the number of seconds the motor should run for.  Note that this takes precedence over the encoder target
00196  * @param commandA the command to be sent to the motor
00197  * @return true if no error occured, false if it did
00198  */
00199 bool MSMMUXsendCommand(tSensors link, ubyte channel, long setpoint, byte speed, ubyte seconds, ubyte commandA) {
00200   memset(MSMMUX_I2CRequest, 0, sizeof(tByteArray));
00201 
00202   MSMMUX_I2CRequest[0] = 10;               // Message size
00203   MSMMUX_I2CRequest[1] = MSMMUX_I2C_ADDR; // I2C Address
00204   MSMMUX_I2CRequest[2] = MSMMUX_MOT_OFFSET + (channel * MSMMUX_ENTRY_SIZE);
00205   MSMMUX_I2CRequest[3] = (setpoint >>  0) & 0xFF;
00206   MSMMUX_I2CRequest[4] = (setpoint >>  8) & 0xFF;
00207   MSMMUX_I2CRequest[5] = (setpoint >> 16) & 0xFF;
00208   MSMMUX_I2CRequest[6] = (setpoint >> 24) & 0xFF;
00209   MSMMUX_I2CRequest[7] = (speed & 0xFF);
00210   MSMMUX_I2CRequest[8] = seconds;
00211   MSMMUX_I2CRequest[9] = 0;
00212   MSMMUX_I2CRequest[10] = commandA;
00213 
00214   // make sure the targetUnit is reset for the next time
00215   mmuxData[link].targetUnit[channel] = MSMMUX_ROT_UNLIMITED;
00216 
00217   // send the command to the mmux
00218   return writeI2C(link, MSMMUX_I2CRequest, 0);
00219 
00220 }
00221 
00222 
00223 /**
00224  * Send a command to the MMUX.
00225  *
00226  * Note: this is an internal function and shouldn't be used directly
00227  * @param link the MMUX port number
00228  * @param command the command to be sent to the motor
00229  * @return true if no error occured, false if it did
00230  */
00231 bool MSMMUXsendCommand(tSensors link, ubyte command) {
00232   memset(MSMMUX_I2CRequest, 0, sizeof(tByteArray));
00233 
00234   MSMMUX_I2CRequest[0] = 3;               // Message size
00235   MSMMUX_I2CRequest[1] = MSMMUX_I2C_ADDR; // I2C Address
00236   MSMMUX_I2CRequest[2] = MSMMUX_REG_CMD;
00237   MSMMUX_I2CRequest[3] = command;
00238 
00239   return writeI2C(link, MSMMUX_I2CRequest, 0);
00240 }
00241 
00242 
00243 /**
00244  * Configure the internal PID controller.  Tweaking these values will change the
00245  * behaviour of the motors, how they approach their target, how they maintain speed, etc.
00246  * These settings do not persist, disconnecting the MUX will reset these values to their
00247  * defaults.  These settings are MUX-wide, so will apply to how BOTH motors are controlled.
00248  *
00249  * Please refer to the User Guide for more detailed information on how these parameters
00250  * should be used.
00251  *
00252  * @param link the MMUX port number
00253  * @param kpTacho Kp for Tachometer Position Control
00254  * @param kiTacho Ki for Tachometer Position Control
00255  * @param kdTacho Kd for Tachometer Position Control
00256  * @param kpSpeed Kp for Speed Control
00257  * @param kiSpeed Ki for Speed Control
00258  * @param kdSpeed Kd for Speed Control
00259  * @param passCount Encoder count tolerance when motor is moving
00260  * @param tolerance Encoder count tolerance when motor is getting close to target
00261  *
00262  * @return true if no error occured, false if it did
00263  */
00264 bool MSMMUXsetPID(tSensors link, int kpTacho, int kiTacho, int kdTacho, int kpSpeed, int kiSpeed, int kdSpeed, ubyte passCount, ubyte tolerance) {
00265   memset(MSMMUX_I2CRequest, 0, sizeof(tByteArray));
00266 
00267   MSMMUX_I2CRequest[0] = 16;               // Message size
00268   MSMMUX_I2CRequest[1] = MSMMUX_I2C_ADDR; // I2C Address
00269   MSMMUX_I2CRequest[2] = MSMMUX_KP_TACHO;
00270   MSMMUX_I2CRequest[3] = kpTacho & 0xFF;
00271   MSMMUX_I2CRequest[4] = (kpTacho >> 8) & 0xFF;
00272   MSMMUX_I2CRequest[5] = kiTacho & 0xFF;
00273   MSMMUX_I2CRequest[6] = (kiTacho >> 8) & 0xFF;
00274   MSMMUX_I2CRequest[7] = kdTacho & 0xFF;
00275   MSMMUX_I2CRequest[8] = (kdTacho >> 8) & 0xFF;
00276   MSMMUX_I2CRequest[9] = kpSpeed & 0xFF;
00277   MSMMUX_I2CRequest[10] = (kpSpeed >> 8) & 0xFF;
00278   MSMMUX_I2CRequest[11] = kiSpeed & 0xFF;
00279   MSMMUX_I2CRequest[12] = (kiSpeed >> 8) & 0xFF;
00280   MSMMUX_I2CRequest[13] = kdSpeed & 0xFF;
00281   MSMMUX_I2CRequest[14] = (kdSpeed >> 8) & 0xFF;
00282   MSMMUX_I2CRequest[15] = passCount;
00283   MSMMUX_I2CRequest[16] = tolerance;
00284 
00285   return writeI2C(link, MSMMUX_I2CRequest, 0);
00286 }
00287 
00288 
00289 /**
00290  * Run motor with specified speed.
00291  *
00292  * @param muxmotor the motor-MUX motor
00293  * @param power power the amount of power to apply to the motor, value between -100 and +100
00294  * @return true if no error occured, false if it did
00295  */
00296 bool MSMMotor(tMUXmotor muxmotor, byte power) {
00297   ubyte commandA = 0;
00298   commandA += (mmuxData[SPORT(muxmotor)].pidcontrol[MPORT(muxmotor)]) ? MSMMUX_CMD_SPEED : 0;
00299   commandA += (mmuxData[SPORT(muxmotor)].ramping[MPORT(muxmotor)] != MSMMUX_RAMP_NONE) ? MSMMUX_CMD_RAMP : 0;
00300   commandA += (mmuxData[SPORT(muxmotor)].brake[MPORT(muxmotor)]) ? MSMMUX_CMD_BRK : 0;
00301   commandA += (mmuxData[SPORT(muxmotor)].targetUnit[MPORT(muxmotor)] == MSMMUX_ROT_DEGREES) ? MSMMUX_CMD_TACHO : 0;
00302   commandA += (mmuxData[SPORT(muxmotor)].targetUnit[MPORT(muxmotor)] == MSMMUX_ROT_SECONDS) ? MSMMUX_CMD_TIME : 0;
00303   commandA += (mmuxData[SPORT(muxmotor)].relTarget[MPORT(muxmotor)]) ? MSMMUX_CMD_RELATIVE : 0;
00304   commandA += MSMMUX_CMD_GO;
00305 
00306   switch (mmuxData[SPORT(muxmotor)].targetUnit[MPORT(muxmotor)]) {
00307     case MSMMUX_ROT_UNLIMITED: return MSMMUXsendCommand((tSensors)SPORT(muxmotor), (ubyte)MPORT(muxmotor), 0, power, 0, commandA);
00308     case MSMMUX_ROT_DEGREES:   return MSMMUXsendCommand((tSensors)SPORT(muxmotor), (ubyte)MPORT(muxmotor), mmuxData[SPORT(muxmotor)].target[MPORT(muxmotor)], power, 0, commandA);
00309     case MSMMUX_ROT_SECONDS:   return MSMMUXsendCommand((tSensors)SPORT(muxmotor), (ubyte)MPORT(muxmotor), 0, power, mmuxData[SPORT(muxmotor)].target[MPORT(muxmotor)], commandA);
00310   }
00311   return true;
00312 }
00313 
00314 
00315 /**
00316  * Stop the motor. Uses the brake method specified with MSMMotorSetBrake or MSMMotorSetFloat.
00317  * The default is to use braking.
00318  *
00319  * @param muxmotor the motor-MUX motor
00320  * @return true if no error occured, false if it did
00321  */
00322 bool MSMotorStop(tMUXmotor muxmotor) {
00323   if (MPORT(muxmotor) == 0)
00324     return MSMotorStop(muxmotor, mmuxData[SPORT(muxmotor)].brake[MPORT(muxmotor)]);
00325   else if (MPORT(muxmotor) == 1)
00326     return MSMotorStop(muxmotor, mmuxData[SPORT(muxmotor)].brake[MPORT(muxmotor)]);
00327   return true;
00328 }
00329 
00330 
00331 /**
00332  * Stop the motor. This function overrides the preconfigured braking method.
00333  *
00334  * @param muxmotor the motor-MUX motor
00335  * @param brake when set to true: use brake, false: use float
00336  * @return true if no error occured, false if it did
00337  */
00338 bool MSMotorStop(tMUXmotor muxmotor, bool brake) {
00339   if (MPORT(muxmotor) == 0)
00340     return MSMMUXsendCommand(MSMMUX, brake ? MSMMUX_CMD_BRAKE_MOT1 : MSMMUX_CMD_FLOAT_MOT1);
00341   else if (MPORT(muxmotor) == 1)
00342     return MSMMUXsendCommand(MSMMUX, brake ? MSMMUX_CMD_BRAKE_MOT2 : MSMMUX_CMD_FLOAT_MOT2);
00343   return true;
00344 }
00345 
00346 
00347 /**
00348  * Set rotation target for specified mux motor.
00349  *
00350  * @param muxmotor the motor-MUX motor
00351  * @param target the rotation target value
00352  * @return true if no error occured, false if it did
00353  */
00354 void MSMMotorSetRotationTarget(tMUXmotor muxmotor, long target) {
00355   mmuxData[SPORT(muxmotor)].target[MPORT(muxmotor)] = target * 360;
00356   mmuxData[SPORT(muxmotor)].targetUnit[MPORT(muxmotor)] = MSMMUX_ROT_DEGREES;
00357 }
00358 
00359 
00360 /**
00361  * Set time target for specified mux motor. Seconds can be specified in
00362  * increments of 1 second with an upper limit of 255 seconds.
00363  *
00364  * @param muxmotor the motor-MUX motor
00365  * @param target the time target value in seconds [1-255]
00366  * @return true if no error occured, false if it did
00367  */
00368 void MSMMotorSetTimeTarget(tMUXmotor muxmotor, int target) {
00369   mmuxData[SPORT(muxmotor)].target[MPORT(muxmotor)] = target;
00370   mmuxData[SPORT(muxmotor)].targetUnit[MPORT(muxmotor)] = MSMMUX_ROT_SECONDS;
00371 }
00372 
00373 
00374 /**
00375  * Set encoder target for specified mux motor.  Target is relative to current position.
00376  *
00377  * @param muxmotor the motor-MUX motor
00378  * @param target the encoder target value in degrees.
00379  * @return true if no error occured, false if it did
00380  */
00381 void MSMMotorSetEncoderTarget(tMUXmotor muxmotor, long target) {
00382   mmuxData[SPORT(muxmotor)].target[MPORT(muxmotor)] = target;
00383   mmuxData[SPORT(muxmotor)].targetUnit[MPORT(muxmotor)] = MSMMUX_ROT_DEGREES;
00384   mmuxData[SPORT(muxmotor)].relTarget[MPORT(muxmotor)] = true;
00385 }
00386 
00387 
00388 /**
00389  * Set encoder target for specified mux motor.
00390  *
00391  * @param muxmotor the motor-MUX motor
00392  * @param target the encoder target value in degrees.
00393  * @param relative specified target is relative to current position.
00394  * @return true if no error occured, false if it did
00395  */
00396 void MSMMotorSetEncoderTarget(tMUXmotor muxmotor, long target, bool relative) {
00397   mmuxData[SPORT(muxmotor)].target[MPORT(muxmotor)] = target;
00398   mmuxData[SPORT(muxmotor)].targetUnit[MPORT(muxmotor)] = MSMMUX_ROT_DEGREES;
00399   mmuxData[SPORT(muxmotor)].relTarget[MPORT(muxmotor)] = relative;
00400 }
00401 
00402 
00403 /**
00404  * Fetch the current encoder value for specified motor channel
00405  *
00406  * @param muxmotor the motor-MUX motor
00407  * @return the current value of the encoder
00408  */
00409 long MSMMotorEncoder(tMUXmotor muxmotor) {
00410   long result;
00411 
00412   memset(MSMMUX_I2CRequest, 0, sizeof(tByteArray));
00413 
00414   MSMMUX_I2CRequest[0] = 2;               // Message size
00415   MSMMUX_I2CRequest[1] = MSMMUX_I2C_ADDR; // I2C Address
00416 
00417   switch ((byte)MPORT(muxmotor)) {
00418     case 0: MSMMUX_I2CRequest[2] = MSMMUX_TACHO_MOT1; break;
00419     case 1: MSMMUX_I2CRequest[2] = MSMMUX_TACHO_MOT2; break;
00420   }
00421 
00422   if (!writeI2C((tSensors)SPORT(muxmotor), MSMMUX_I2CRequest, 4))
00423     return 0;
00424 
00425   if (!readI2C((tSensors)SPORT(muxmotor), MSMMUX_I2CReply, 4))
00426     return 0;
00427 
00428   result = MSMMUX_I2CReply[0] + (MSMMUX_I2CReply[1]<<8) + (MSMMUX_I2CReply[2]<<16) + (MSMMUX_I2CReply[3]<<24);
00429 
00430   return result;
00431 }
00432 
00433 
00434 /**
00435  * Reset target encoder for specified motor channel, use only at
00436  * the start of your program.  If you are using the standard NXT wheels
00437  * you will not run into problems with a wrap-around for the first 500kms
00438  * or so.
00439  *
00440  * @param muxmotor the motor-MUX motor
00441  * @return true if no error occured, false if it did
00442  */
00443 
00444 bool MSMMotorEncoderReset(tMUXmotor muxmotor) {
00445   switch((byte)MPORT(muxmotor)) {
00446     case 0: return MSMMUXsendCommand((tSensors)SPORT(muxmotor), MSMMUX_CMD_RESET_MOT1); break;
00447     case 1: return MSMMUXsendCommand((tSensors)SPORT(muxmotor), MSMMUX_CMD_RESET_MOT2); break;
00448   }
00449   return false;
00450 }
00451 
00452 
00453 /**
00454  * Reset all encoders on the specified motor-MUX. Use only at
00455  * the start of your program.  If you are using the standard NXT wheels
00456  * you will not run into problems with a wrap-around for the first 500kms
00457  * or so.
00458  *
00459  * @param link the MMUX port number
00460  * @return true if no error occured, false if it did
00461  */
00462 bool MSMMotorEncoderResetAll(tSensors link) {
00463   return MSMMUXsendCommand(link, MSMMUX_CMD_RESET_ALL);
00464 }
00465 
00466 
00467 /**
00468  * Check if the specified motor is running or not.
00469  *
00470  * @param muxmotor the motor-MUX motor
00471  * @return true if the motor is still running, false if it's idle
00472  */
00473 bool MSMMotorBusy(tMUXmotor muxmotor) {
00474   ubyte status = 0;
00475   ubyte commandA = 0;
00476 
00477   // Fetch the last sent commandA
00478   memset(MSMMUX_I2CRequest, 0, sizeof(tByteArray));
00479 
00480   MSMMUX_I2CRequest[0] = 2;               // Message size
00481   MSMMUX_I2CRequest[1] = MSMMUX_I2C_ADDR; // I2C Address
00482   MSMMUX_I2CRequest[2] = MSMMUX_MOT_OFFSET + (MPORT(muxmotor) * MSMMUX_ENTRY_SIZE) + MSMMUX_CMD_A;
00483 
00484   if (!writeI2C((tSensors)SPORT(muxmotor), MSMMUX_I2CRequest, 1))
00485     return false;
00486 
00487   if (!readI2C((tSensors)SPORT(muxmotor), MSMMUX_I2CReply, 1))
00488     return false;
00489 
00490   commandA = MSMMUX_I2CReply[0];
00491 
00492   // If commandA is 0 then the motor can't be busy.
00493   if (commandA == 0)
00494     return false;
00495 
00496   if (!MSMMUXreadStatus(muxmotor, status))
00497     return false;
00498 
00499   if ((commandA & MSMMUX_ROT_UNLIMITED) == MSMMUX_ROT_UNLIMITED)
00500     return ((status & MSMMUX_STAT_POWERED) != 0);
00501   else if ((commandA & MSMMUX_ROT_DEGREES) == MSMMUX_ROT_DEGREES)
00502     return ((status & MSMMUX_STAT_POS_CTRL) != 0);
00503   else if ((commandA & MSMMUX_ROT_SECONDS) == MSMMUX_ROT_SECONDS)
00504     return ((status & MSMMUX_STAT_TIMED) != 0);
00505 
00506   return false;
00507 }
00508 
00509 
00510 /**
00511  * Check if the specified motor is running or not.
00512  *
00513  * @param muxmotor the motor-MUX motor
00514  * @return true if the motor is still running, false if it's idle
00515  */
00516 bool MSMMotorStalled(tMUXmotor muxmotor) {
00517   ubyte status = 0;
00518   if (!MSMMUXreadStatus(muxmotor, status))
00519     return false;
00520 
00521   return ((status & MSMMUX_STAT_STALLED) != 0);
00522 }
00523 
00524 
00525 /**
00526  * Set the stopping method for the specified motor to brake.
00527  *
00528  * @param muxmotor the motor-MUX motor
00529  */
00530 void MSMMotorSetBrake(tMUXmotor muxmotor) {
00531   mmuxData[SPORT(muxmotor)].brake[MPORT(muxmotor)] = true;
00532 }
00533 
00534 
00535 /**
00536  * Set the stopping method for the specified motor to float.
00537  *
00538  * @param muxmotor the motor-MUX motor
00539  */
00540 void MSMMotorSetFloat(tMUXmotor muxmotor) {
00541   mmuxData[SPORT(muxmotor)].brake[MPORT(muxmotor)] = false;
00542 }
00543 
00544 
00545 /**
00546  * Set the motor speed control for the specified motor.
00547  *
00548  * @param muxmotor the motor-MUX motor
00549  * @param constspeed use speed control to ensure motor speed stays constant under varying load
00550  */
00551 void MSMMotorSetSpeedCtrl(tMUXmotor muxmotor, bool constspeed) {
00552   mmuxData[SPORT(muxmotor)].pidcontrol[MPORT(muxmotor)] = true;
00553 }
00554 
00555 
00556 /**
00557  * Set the ramping control for the specified motor.
00558  *
00559  * @param muxmotor the motor-MUX motor
00560  * @param ramping use ramping for starting and stopping the motor
00561  */
00562 void MSMMotorSetRamping(tMUXmotor muxmotor, bool ramping) {
00563   mmuxData[SPORT(muxmotor)].ramping[MPORT(muxmotor)] = (ramping) ? MSMMUX_RAMP_UP_DOWN : MSMMUX_RAMP_NONE;
00564 }
00565 
00566 #endif //  __MSMMUX_H__
00567 
00568 /*
00569  * $Id: MSMMUX-driver.h 56 2011-05-30 19:47:12Z xander $
00570  */
00571 /* @} */
00572 /* @} */