Class for representing and controlling entire I2C transactions (the master side). This class allows one to separate in code the configuration of I2C transactions from their use. This property simplifies the process of executing transactions in, for example, the body of a real-time control loop.

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers I2CTransaction.cpp Source File

I2CTransaction.cpp

00001 #include "I2CTransaction.h"
00002 #include "rtos.h"
00003 
00004 /**
00005     I2C Transaction Class.
00006 
00007     Author: Andrew H. Fagg  (May, 2014)
00008 
00009     TODO: finish this description
00010 
00011     This class provides:
00012     - Interrupt-driven I2C master functionality
00013     - Representations of whole transactions
00014 
00015     I2C Transactions generally come in two varieties: a write and a write followed by a read
00016 
00017 
00018 
00019 Notes:
00020     I2C Status codes:
00021     - 32: write NO-ACK
00022     - 72: read NO-ACK
00023     - 40: write ACK
00024     - 48: ??
00025     - 88: read ACK
00026 */
00027 
00028 // Initialization of static member (kind of gross to do it this way - need to find another solution)
00029 //MODI2C* I2CTransaction::i2c = new MODI2C(p9, p10);
00030 MODI2C* I2CTransaction::i2c = NULL; //new MODI2C(p28, p27);
00031 int I2CTransaction::maxRetryCount = -1;  // No recovery by default
00032 
00033 /**
00034     Transaction constructor
00035 
00036     @param I2C address (7-bit address)
00037     @param writePacket Pointer to the data structure to be written
00038     @param writePacketLength Number of bytes to be written
00039     @param readPacket Pointer to the data structure to be filled during the read (NULL = none)
00040     @param readPacketLength Number of bytes to read
00041 */
00042 
00043 I2CTransaction::I2CTransaction(int address, char* writePacket, int writePacketLength, char* readPacket, int readPacketLength)
00044 {
00045     this->address = address;
00046     this->writePacket = writePacket;
00047     this->writePacketLength = writePacketLength;
00048     this->readPacket = readPacket;
00049     this->readPacketLength = readPacketLength;
00050     if(readPacket == NULL) this->readPacketLength = 0;
00051     status[0] = status[1] = -1;
00052 }
00053 
00054 /**
00055     Set the I2C bus frequency
00056 
00057     @param frequency in Hertz
00058 */
00059 
00060 void I2CTransaction::setFrequency(int frequency)
00061 {
00062     i2c->frequency(frequency);
00063 }
00064 
00065 
00066 void I2CTransaction::setMaxRetry(int maxRetry)
00067 {
00068     maxRetryCount = maxRetry;
00069 }
00070 
00071 /**
00072     Indicate whether the transaction has completed (whether successful or not)
00073 
00074     Note: assumes that for the case with no read part of the transaction, status[1]
00075     has been left in its initial state (-1)
00076 */
00077 
00078 bool I2CTransaction::completed()
00079 {
00080     return(status[0] != 0 && status[1] != 0);
00081 }
00082 
00083 /**
00084     Return the specified status code for this transaction
00085 
00086     @param i 0 = write status code; 1 = read status code
00087     @return Status code (see documentation at top of this file)
00088 */
00089 
00090 int I2CTransaction::getStatus(int i)
00091 {
00092     if(i >= 0 && i <= 1) return status[i];
00093     else return -1;
00094 }
00095 
00096 /**
00097     Start a transaction.
00098 
00099     Does not initiate a transaction if it is already in progress.
00100 
00101     Note: no error checking yet on the read and write calls
00102 
00103     @return true if transaction has been initiated; false if it is already in progress
00104 */
00105 
00106 bool I2CTransaction::initiateTransaction()
00107 {
00108     if(!completed()) {
00109         // Already in progress: bail
00110 
00111         return false;
00112     } else {
00113         // Start the write
00114         i2c->write(address << 1, writePacket, writePacketLength, false, &(status[0]));
00115 
00116         // Start the read if it exists
00117         if(readPacket != NULL) {
00118             i2c->read_nb(address << 1, readPacket, readPacketLength, false, &(status[1]));
00119         }
00120         // Reset the retry count;
00121         retryCount = 0;
00122         return true;
00123     }
00124 }
00125 
00126 bool I2CTransaction::checkTransaction()
00127 {
00128     // Increment the counter for number of times we have tried to initiate this transaction.
00129     ++retryCount;
00130 
00131     // Have we exceeded the maximum number of allowed retries
00132     if(maxRetryCount != -1 && retryCount >= maxRetryCount) {
00133         // Yes: reset so next time we can try again
00134         status[0] = status[1] = -1;
00135         retryCount = 0;
00136         return true;
00137     }
00138     return false;
00139 }
00140 
00141 /**
00142     Wait until the transaction has completed, up to the specified number of milliseconds
00143 
00144     @param timeout Number of milliseconds to wait
00145 
00146     @return true if transaction completed; false if timed out
00147 */
00148 
00149 bool I2CTransaction::waitForCompletion(int timeout)
00150 {
00151     for(int i = 0; i < timeout; ++i) {
00152         if(this->completed()) return true;
00153         wait_ms(1);
00154     }
00155     return(false);
00156 }
00157 
00158 /**
00159     Display the transaction status codes
00160 
00161     @param pc Pointer to an initialized serial handler
00162     @param strg String description of this transaction
00163 */
00164 
00165 void I2CTransaction::displayStatus(Serial *pc, char* strg)
00166 {
00167     if(readPacket == NULL) {
00168         // Write only
00169         pc->printf("%s\t%x\n\r", strg, status[0]);
00170     } else {
00171         // Write - Read
00172         pc->printf("%s\t%x\t%x\n\r", strg, status[0], status[1]);
00173     }
00174 }
00175 
00176 /**
00177     Check that the transaction was successfully completed.
00178 
00179     @return true if successful, false if not
00180 */
00181 
00182 bool I2CTransaction::success()
00183 {
00184     // Write transaction must have completed with the correct status code (40)
00185     // Read transaction, if it exists, must also complete correctly (88)
00186     return (status[0] == 40) && (readPacket == NULL || status[1] == 88);
00187 }
00188 
00189 
00190 /**
00191     Check that the transaction has an error
00192 
00193     @return true if error, false if not
00194 */
00195 
00196 bool I2CTransaction::transmissionError()
00197 {
00198     // Write transaction has completed with an error code (can't be 0 (in progress) or 40 (correct))
00199     // Read transaction, if it exists, has completed with an error code (can't be 0 (in progress) or 88 (correct))
00200     return (status[0] != 0 && status[0] != 40) || (readPacket != NULL && status[1] != 0 && status[1] != 88);
00201 }
00202 
00203 /**
00204     Report the number of I2C transactions that are in the queue
00205 
00206     @return Number of items
00207 */
00208 
00209 int I2CTransaction::getI2CQueueLength()
00210 {
00211     return(i2c->getQueue());
00212 }
00213 
00214 /**
00215     Attempt a reset of the I2C bus by forcing a STOP message.  Use with caution.
00216     **/
00217 
00218 void I2CTransaction::reset()
00219 {
00220     delete i2c;
00221     i2c = new MODI2C(p28, p27);
00222 }
00223 
00224 void I2CTransaction::resetBus()
00225 {
00226     i2c->stop();
00227     i2c->start();
00228     i2c->stop();
00229 }
00230 
00231 void I2CTransaction::cycleBus()
00232 {
00233     i2c->start();
00234     Thread::wait(1);
00235     i2c->stop();
00236 }
00237 
00238 /**
00239     Set the status of the transaction back to -1 (usable).
00240 
00241     Use at your own risk
00242 */
00243 
00244 void I2CTransaction::clearStatus()
00245 {
00246     status[0] = status[1] = -1;
00247 }
00248 
00249 /**
00250     Initialize the I2C pins and other hardware.  If it has already been initialized, then
00251     we will re-initialize.
00252     
00253     @param sda Name of the pin that is used for data
00254     @param scl Name of the pin that is used for the clock
00255 */
00256 
00257 void I2CTransaction::initI2C(PinName sda, PinName scl)
00258 {
00259     if(i2c) {
00260         delete i2c;
00261     }
00262     i2c = new MODI2C(sda, scl); //p28, p27);
00263 }