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

common.h

Go to the documentation of this file.
00001 /*!@addtogroup common_includes
00002  * @{
00003  * @defgroup common Main common include
00004  * Commonly used functions used by drivers
00005  * @{
00006  */
00007 
00008 /*
00009  * $Id: common.h 56 2011-05-30 19:47:12Z xander $
00010  */
00011 
00012 /** \file common.h
00013  * \brief Commonly used functions used by drivers.
00014  *
00015  * common.h provides a number of frequently used functions that are useful for writing
00016  * drivers.
00017  * License: You may use this code as you wish, provided you give credit where its due.
00018  *
00019  * THIS CODE WILL ONLY WORK WITH ROBOTC VERSION 2.00 AND HIGHER.
00020  *
00021  * Changelog:
00022  * - 0.1: Initial release
00023  * - 0.2: Added version check to issue error when compiling with RobotC < 1.46
00024  * - 0.2: Added __COMMON_H_DEBUG__ to enable/disable sounds when an I2C error occurs
00025  * - 0.2: Removed bool waitForI2CBus(tSensors link, bool silent)
00026  * - 0.3: clearI2CError() added to make writeI2C more robust, I2C bus errors are now handled
00027  *        better.
00028  * - 0.4: Added HiTechnic SMUX functions
00029  * - 0.5: Added clip function (Tom Roach)
00030  * - 0.6: clearI2CBus is now conditionally compiled into the FW.  Only RobotC < 1.57 needs it.
00031  * - 0.7: ubyteToInt(byte byteVal) modified, works better with 1.57+
00032  * - 0.8: ubyte used for arrays for firmware version 770 and higher<br>
00033  *        added support for new colour sensor<br>
00034  *        added better handling for when sensor is not configured properly
00035  * - 0.9: added bool HTSMUXsetMode(tSensors link, byte channel, byte mode) prototype<br>
00036  *        added int HTSMUXreadAnalogue(tMUXSensor muxsensor)<br>
00037  *        added HTSMUXSensorType HTSMUXreadSensorType(tMUXSensor muxsensor)<br>
00038  *        added bool HTSMUXreadPort(tMUXSensor muxsensor, tByteArray &result, int numbytes, int offset)<br>
00039  *        added bool HTSMUXreadPort(tMUXSensor muxsensor, tByteArray &result, int numbytes)<br>
00040  *        added bool HTSMUXsetMode(tMUXSensor muxsensor, byte mode)<br>
00041  *        added bool HTSMUXsetAnalogueActive(tMUXSensor muxsensor)<br>
00042  *        added bool HTSMUXsetAnalogueInactive(tMUXSensor muxsensor)<br>
00043  *        corrected function description for HTSMUXSensorType()
00044  * - 0.10: Removed unnecessary read from HTSMUXsendCommand()
00045  * - 0.11: Added long uByteToLong(byte a1, byte a2, byte a3, byte a4);
00046  * - 0.12: Added HTSMUXreadPowerStatus(tSensors link)<br>
00047  *         Added int round(float fl)
00048  * - 0.13: Added motor mux types and data structs
00049  * - 0.14: Added check for digital sensors to prevent conflict with built-in drivers\n
00050  *         Changed clearI2CError to take ubyte for address, thanks Aswin
00051  * - 0.15: Removed motor mux and sensor mux functions and types out
00052  * - 0.16: Added max() and min() functions by Mike Henning, Max Bareiss
00053  *
00054  * \author Xander Soldaat (mightor_at_gmail.com)
00055  * \date 27 April 2011
00056  * \version 0.16
00057  */
00058 
00059 #pragma systemFile
00060 
00061 #ifndef __COMMON_H__
00062 #define __COMMON_H__
00063 
00064 #undef __COMMON_H_DEBUG__
00065 //#define __COMMON_H_DEBUG__
00066 
00067 /*!< define this as 0 to remove the check  */
00068 #ifndef __COMMON_H_SENSOR_CHECK__
00069 #define __COMMON_H_SENSOR_CHECK__ 1
00070 #else
00071 #warn "sensor checking disabled, I hope you know what you are doing!"
00072 #endif
00073 
00074 #include "firmwareVersion.h"
00075 #if (kFirmwareVersion < 785)
00076 #error "These drivers are only supported on RobotC version 2.0 or higher"
00077 #endif
00078 
00079 #ifndef MAX_ARR_SIZE
00080 /**
00081  * Maximum buffer size for byte_array, can be overridden in your own program.
00082  * It's 17 bytes big because the max I2C buffer size is 16, plus 1 byte to denote
00083  * packet length.
00084  */
00085 #define MAX_ARR_SIZE 17
00086 #endif
00087 
00088 
00089 /**
00090  * This define returns the smaller of the two numbers
00091  */
00092 #define min2(a, b) (a < b ? a : b)
00093 
00094 
00095 /**
00096  * This define returns the smallest of the three numbers
00097  */
00098 #define min3(a, b, c) (a < b) ? ((a < c) ? a : c) : ((b < c) ? b : c)
00099 
00100 /**
00101  * This function returns the bigger of the two numbers
00102  */
00103 #define max2(a, b) (a > b ? a : b)
00104 
00105 
00106 /**
00107  * This function returns the biggest of the three numbers
00108  */
00109 #define max3(a, b, c) (a > b) ? ((a > c) ? a : c) : ((b > c) ? b : c)
00110 
00111 
00112 /**
00113  * Returns x if it is between min and max. If outside the range,
00114  * it returns min or max.
00115  */
00116 #define clip(a, b, c) min2(c, max2(b, a))
00117 
00118 
00119 /**
00120  * Returns a rounded int from a float.
00121  */
00122 #define round(x) (int)(x + 0.5)
00123 
00124 
00125 /**
00126  * Array of bytes as a struct, this is a work around for RobotC's inability to pass an array to
00127  * a function.
00128  */
00129 typedef ubyte tByteArray[MAX_ARR_SIZE];
00130 typedef sbyte tsByteArray[MAX_ARR_SIZE];
00131 
00132 /**
00133  * Array of ints as a struct, this is a work around for RobotC's inability to pass an array to
00134  * a function.
00135  */
00136 typedef int tIntArray[MAX_ARR_SIZE];
00137 
00138 void clearI2CError(tSensors link, ubyte address);
00139 bool waitForI2CBus(tSensors link);
00140 bool writeI2C(tSensors link, tByteArray &data, int replylen);
00141 bool readI2C(tSensors link, tByteArray &data, int replylen);
00142 
00143 
00144 /**
00145  * Clear out the error state on I2C bus by sending a bunch of dummy
00146  * packets.
00147  * @param link the port number
00148  * @param address the I2C address we're sending to
00149  */
00150 void clearI2CError(tSensors link, ubyte address) {
00151   ubyte error_array[2];
00152   error_array[0] = 1;           // Message size
00153   error_array[1] = address; // I2C Address
00154 
00155 #ifdef __COMMON_H_DEBUG__
00156   eraseDisplay();
00157   nxtDisplayTextLine(3, "rxmit: %d", ubyteToInt(error_array[1]));
00158   wait1Msec(2000);
00159 #endif // __COMMON_H_DEBUG__
00160 
00161   for (int i = 0; i < 5; i++) {
00162     sendI2CMsg(link, error_array[0], 0);
00163     wait1Msec(5);
00164   }
00165 }
00166 
00167 
00168 /**
00169  * Wait for the I2C bus to be ready for the next message
00170  * @param link the port number
00171  * @return true if no error occured, false if it did
00172  */
00173 bool waitForI2CBus(tSensors link)
00174 {
00175   //TI2CStatus i2cstatus;
00176   while (true)
00177   {
00178     //i2cstatus = nI2CStatus[link];
00179     switch (nI2CStatus[link])
00180     //switch(i2cstatus)
00181     {
00182     case NO_ERR:
00183       return true;
00184 
00185     case STAT_COMM_PENDING:
00186       break;
00187 
00188     case ERR_COMM_CHAN_NOT_READY:
00189       break;
00190 
00191     case ERR_COMM_BUS_ERR:
00192 #ifdef __COMMON_H_DEBUG__
00193       PlaySound(soundLowBuzz);
00194       while (bSoundActive) {}
00195 #endif // __COMMON_H_DEBUG__
00196       return false;
00197     }
00198   }
00199 }
00200 
00201 
00202 /**
00203  * Write to the I2C bus. This function will clear the bus and wait for it be ready
00204  * before any bytes are sent.
00205  * @param link the port number
00206  * @param data the data to be sent
00207  * @param replylen the number of bytes (if any) expected in reply to this command
00208  * @return true if no error occured, false if it did
00209  */
00210 bool writeI2C(tSensors link, tByteArray &data, int replylen) {
00211 
00212 #if (__COMMON_H_SENSOR_CHECK__ == 1)
00213   TSensorTypes type = SensorType[link];
00214   if ((type != sensorI2CCustom) &&
00215       (type != sensorI2CCustom9V) &&
00216       (type != sensorI2CCustomFast) &&
00217       (type != sensorI2CCustomFast9V) &&
00218       (type != sensorI2CCustomFastSkipStates9V) &&
00219       (type != sensorI2CCustomFastSkipStates)) {
00220     hogCPU();
00221     PlaySound(soundException);
00222     eraseDisplay();
00223     nxtDisplayCenteredTextLine(0, "3rd Party Driver");
00224     nxtDisplayCenteredTextLine(1, "ERROR");
00225     nxtDisplayCenteredTextLine(2, "You have not");
00226     nxtDisplayCenteredTextLine(3, "setup the sensor");
00227     nxtDisplayCenteredTextLine(4, "port correctly. ");
00228     nxtDisplayCenteredTextLine(5, "Please refer to");
00229     nxtDisplayCenteredTextLine(6, "one of the");
00230     nxtDisplayCenteredTextLine(7, "examples.");
00231     wait1Msec(10000);
00232     StopAllTasks();
00233   }
00234 #endif
00235 
00236   if (!waitForI2CBus(link)) {
00237     clearI2CError(link, data[1]);
00238 
00239     // Let's try the bus again, see if the above packets flushed it out
00240     // clearI2CBus(link);
00241     if (!waitForI2CBus(link))
00242       return false;
00243   }
00244 
00245   sendI2CMsg(link, data[0], replylen);
00246 
00247   if (!waitForI2CBus(link)) {
00248     clearI2CError(link, data[1]);
00249     sendI2CMsg(link, data[0], replylen);
00250     if (!waitForI2CBus(link))
00251       return false;
00252   }
00253   return true;
00254 }
00255 
00256 
00257 /**
00258  * Read from the I2C bus.  This function will wait for the bus to be ready before reading
00259  * from it.
00260  * @param link the port number
00261  * @param data holds the data from the reply
00262  * @param replylen the number of bytes in the reply
00263  * @return true if no error occured, false if it did
00264  */
00265 bool readI2C(tSensors link, tByteArray &data, int replylen) {
00266 
00267 #if (__COMMON_H_SENSOR_CHECK__ == 1)
00268   TSensorTypes type = SensorType[link];
00269   if ((type != sensorI2CCustom) &&
00270       (type != sensorI2CCustom9V) &&
00271       (type != sensorI2CCustomFast) &&
00272       (type != sensorI2CCustomFast9V) &&
00273       (type != sensorI2CCustomFastSkipStates9V) &&
00274       (type != sensorI2CCustomFastSkipStates)) {
00275     hogCPU();
00276     PlaySound(soundException);
00277     eraseDisplay();
00278     nxtDisplayCenteredTextLine(0, "3rd Party Driver");
00279     nxtDisplayCenteredTextLine(1, "ERROR");
00280     nxtDisplayCenteredTextLine(2, "You have not");
00281     nxtDisplayCenteredTextLine(3, "setup the sensor");
00282     nxtDisplayCenteredTextLine(4, "port correctly. ");
00283     nxtDisplayCenteredTextLine(5, "Please refer to");
00284     nxtDisplayCenteredTextLine(6, "one of the");
00285     nxtDisplayCenteredTextLine(7, "examples.");
00286     wait1Msec(10000);
00287     StopAllTasks();
00288   }
00289 #endif
00290 
00291   // clear the input data buffer
00292   memset(data, 0, sizeof(tByteArray));
00293 
00294   // wait for the bus to be done receiving data
00295   if (!waitForI2CBus(link))
00296     return false;
00297 
00298   // ask for the input to put into the data array
00299   readI2CReply(link, data[0], replylen);
00300 
00301   return true;
00302 }
00303 
00304 #endif // __COMMON_H__
00305 
00306 /*
00307  * $Id: common.h 56 2011-05-30 19:47:12Z xander $
00308  */
00309 /* @} */
00310 /* @} */