This library provides simplified I2C access to a Microchip MCP23x17 GPIO expender device, including a general interface for any GPIO expender

Dependents:   MCP23017App

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MCP23017_I2C.cpp Source File

MCP23017_I2C.cpp

00001 /* mbed simplified access to Microchip MCP23x17 GPIO expender devices (I2C)
00002  * Copyright (c) 2010-2012 ygarcia, MIT License
00003  *
00004  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
00005  * and associated documentation files (the "Software"), to deal in the Software without restriction, 
00006  * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
00007  * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
00008  * furnished to do so, subject to the following conditions:
00009  *
00010  * The above copyright notice and this permission notice shall be included in all copies or 
00011  * substantial pinions of the Software.
00012  *
00013  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
00014  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
00015  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
00016  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
00017  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00018  */
00019 #include <iostream>
00020 #include <sstream>
00021 
00022 #include "MCP23017_I2C.h"
00023 
00024 #define IODIRA      0x00
00025 #define IODIRB      0x01
00026 #define IPOLA       0x02
00027 #define IPOLB       0x03
00028 #define GPINTENA    0x04
00029 #define GPINTENB    0x05
00030 #define DEFVALA     0x06
00031 #define DEFVALB     0x07
00032 #define INTCONA     0x08
00033 #define INTCONB     0x09
00034 #define IOCONA      0x0a
00035 #define IOCONB      0x0b
00036 #define GPPUA       0x0c
00037 #define GPPUB       0x0d
00038 #define INTFA       0x0e
00039 #define INTFB       0x0f
00040 #define INTCAPA     0x10
00041 #define INTCAPB     0x11
00042 #define GPIOA       0x12
00043 #define GPIOB       0x13
00044 #define OLATA       0x14
00045 #define OLATB       0x15
00046 
00047 namespace MCP23017_I2C {
00048 
00049     unsigned char CMCP23017_I2C::I2CModuleRefCounter = 0;
00050 
00051     CMCP23017_I2C::CMCP23017_I2C(const PinName p_sda, const PinName p_scl, const unsigned char p_address, const PinName p_intA, const PinName p_intB, const PinName p_reset, const bool p_internalPullUp, const unsigned int p_frequency) : _gpioAFlags(0x00), _gpioBFlags(0x00), _buses(), _busesIndex(0x00), _internalId("") {
00052 //        DEBUG_ENTER("CMCP23017_I2C")
00053 
00054         if (CMCP23017_I2C::I2CModuleRefCounter != 0) {
00055             error("CMCP23017_I2C: Wrong params");
00056         }
00057 #ifdef __DEBUG
00058         std::ostringstream out(std::ostringstream::out);
00059         out << "CMCP23017_I2C #" << CMCP23017_I2C::I2CModuleRefCounter;
00060         _internalId.assign(out.str());
00061 //        DEBUG("CMCP23017_I2C: _internalId='%s'", _internalId.c_str())
00062 #endif // __DEBUG
00063         _i2cInstance = new I2C(p_sda, p_scl);
00064         CMCP23017_I2C::I2CModuleRefCounter += 1;
00065 //        DEBUG_ENTER("CMCP23017_I2C: refCounter=%d", CMCP23017_I2C::I2CModuleRefCounter)
00066 
00067         _slaveAddress = (p_address << 1) | 0x40; // Slave address format is: 0 0 1 0 A3 A2 A1 R/W
00068 //        DEBUG("CMCP23017_I2C: I2C slave adress: 0x%02x", _slaveAddress)
00069         _i2cInstance->frequency(p_frequency); // Set the frequency of the I2C interface
00070         
00071         if (p_intA != NC) {
00072 //            DEBUG("CMCP23017_I2C: INTA managed");
00073             _intA = new InterruptIn(p_intA);
00074             if (p_internalPullUp) _intA->mode(::PullDown);
00075             _intA->enable_irq(); // Enable interrupt
00076         } else {
00077 //            DEBUG("CMCP23017_I2C: INTA not managed");
00078             _intA = NULL; // Not used
00079         }
00080         if (p_intB != NC) {
00081 //            DEBUG("CMCP23017_I2C: INTB managed");
00082             _intB = new InterruptIn(p_intB);
00083             if (p_internalPullUp) _intB->mode(::PullDown);
00084             _intB->enable_irq(); // Enable interrupt
00085         } else {
00086 //            DEBUG("CMCP23017_I2C: INTB not managed");
00087             _intB = NULL; // Not used
00088         }
00089         if (p_reset != NC) {
00090 //            DEBUG("CMCP23017_I2C: RESET managed");
00091             _reset = new DigitalOut(p_reset);
00092             _reset->write(1); // Disable reset
00093         } else {
00094 //            DEBUG("CMCP23017_I2C: RESET not managed");
00095             _reset = NULL; // Not used
00096         }
00097     
00098 //        DEBUG_LEAVE("CMCP23017_I2C")
00099     }
00100 
00101     CMCP23017_I2C::~CMCP23017_I2C() {
00102 //        DEBUG_ENTER("~CMCP23017_I2C")
00103     
00104         // Release I2C instance
00105 //        DEBUG("~CMCP23017_I2C: refCounter=%d", CMCP23017_I2C::I2CModuleRefCounter)
00106         CMCP23017_I2C::I2CModuleRefCounter -= 1;
00107         if (CMCP23017_I2C::I2CModuleRefCounter == 0) {
00108             delete _i2cInstance;
00109             _i2cInstance = NULL;
00110         }
00111         // Release _wp if required
00112         if (_intA != NULL) {
00113             delete _intA;
00114         }
00115         if (_intB != NULL) {
00116             delete _intB;
00117         }
00118         if (_reset != NULL) {
00119             delete _reset;
00120         }
00121     
00122 //        DEBUG_LEAVE("~CMCP23017_I2C")
00123     }
00124     
00125     bool CMCP23017_I2C::Initialize(const unsigned char p_gpioAFlags, const unsigned char p_gpioBFlags) {
00126         
00127         // Configure default behavior
00128         _gpioAFlags = p_gpioAFlags;
00129         _gpioBFlags = p_gpioBFlags;
00130         configure(_gpioAFlags, _gpioBFlags);
00131         
00132         return true;
00133     }
00134     
00135     void CMCP23017_I2C::configure(const unsigned char p_gpioAFlags, const unsigned char p_gpioBFlags) { // TODO Optimization with sequential access
00136 //        DEBUG_ENTER("CMCP23017_I2C::configure: 0x%02x 0x%02x", p_gpioAFlags, p_gpioBFlags)
00137         
00138         // Setup IOCON - See REGISTER 1-6: IOCON – I/O EXPANDER CONFIGURATION REGISTER
00139         writeRegister(IOCONA, 0x10); // Sequential operation disabled
00140         writeRegister(IOCONB, 0x10); // Sequential operation disabled
00141         // Setup IODIR - See REGISTER 1-1: IODIR – I/O DIRECTION REGISTER (ADDR 0x00)
00142         writeRegister(IODIRA, p_gpioAFlags);
00143         writeRegister(IODIRB, p_gpioBFlags);
00144         // Setup IPOL - See REGISTER 1-2: IPOL – INPUT POLARITY PORT REGISTER
00145         writeRegister(IPOLA, 0x00); // GPIO register bit will reflect the same logic state of the input pin
00146         writeRegister(IPOLB, 0x00);
00147         // Setup GPPU - See REGISTER 1-7: GPPU – GPIO PULL-UP RESISTOR REGISTER
00148         writeRegister(GPPUA, 0x00);
00149         writeRegister(GPPUB, 0x00);
00150         
00151         // Setup interrupt       
00152         if (_intA != NULL) {
00153 //            DEBUG("CMCP23017_I2C::configure: Setup INTA")
00154             // Setup GPINTEN - See GPINTEN – INTERRUPT-ON-CHANGE PINS
00155             writeRegister(GPINTENA, 0x00); // Disable GPIO interrupt-on-change events
00156             // Setup DEFVAL - See REGISTER 1-4: DEFVAL – DEFAULT VALUE REGISTER
00157             writeRegister(DEFVALA, 0x00); // Pin level change from 0 to 1 raises an interrupt
00158             // Setup INTCON - REGISTER 1-5: INTCON – INTERRUPT-ON-CHANGE CONTROL REGISTER
00159             writeRegister(INTCONA, 0xff); // Pin level change from 0 to 1 raises an interrupt
00160         }
00161         if (_intB != NULL) {
00162 //            DEBUG("CMCP23017_I2C::configure: Setup INTB")
00163             // Setup GPINTEN - See GPINTEN – INTERRUPT-ON-CHANGE PINS
00164             writeRegister(GPINTENB, 0x00); // Disable GPIO interrupt-on-change events
00165             // Setup DEFVAL - See REGISTER 1-4: DEFVAL – DEFAULT VALUE REGISTER
00166             writeRegister(DEFVALB, 0x00); // Pin level change from 0 to 1 raises an interrupt
00167             // Setup INTCON - REGISTER 1-5: INTCON – INTERRUPT-ON-CHANGE CONTROL REGISTER
00168             writeRegister(INTCONB, 0xff); // Pin level change from 0 to 1 raises an interrupt
00169         }
00170         
00171 //        DumpRegisters();
00172         
00173 //        DEBUG_LEAVE("CMCP23017_I2C::configure")
00174     }
00175     
00176     void CMCP23017_I2C::reset() {
00177 //        DEBUG_ENTER("CMCP23017_I2C::reset")
00178         if (_reset != NULL) {
00179             _reset->write(0);
00180             wait_us(1);
00181             _reset->write(1);
00182             wait_us(1);
00183             if ((_gpioAFlags != 0x00) || (_gpioBFlags != 0x00)) { // Apply configuration
00184                 configure(_gpioAFlags, _gpioBFlags);
00185             } // else, POR reset values, see DS21952B-page 10 Clause 1.6 Configuration and Control Registers
00186         }
00187 //        DEBUG_LEAVE("CMCP23017_I2C::reset")
00188     }
00189     
00190     void CMCP23017_I2C::setIntrACallback(void (* p_fptr)(void)) {
00191         if (_intA != NULL) {
00192             unsigned char vregister;
00193             if (!readRegister(IOCONA, &vregister)) {
00194                 return;    
00195             }
00196             if (isBitSet(vregister, 1)) {
00197                 _intA->rise(p_fptr);
00198             } else {
00199                 _intA->fall(p_fptr);
00200             }
00201         }
00202     }
00203     
00204     void CMCP23017_I2C::setIntrBCallback(void (* p_fptr)(void)) {
00205         if (_intB != NULL) {
00206             unsigned char vregister;
00207             if (!readRegister(IOCONB, &vregister)) {
00208                 return;    
00209             }
00210             if (isBitSet(vregister, 1)) {
00211                 _intB->rise(p_fptr);
00212             } else {
00213                 _intB->fall(p_fptr);
00214             }
00215         }
00216     }
00217         
00218     template<typename T> 
00219     void CMCP23017_I2C::setIntrACallback (const T * p_tptr, void(T::* p_mptr)(void)) {
00220         if (_intA != NULL) {
00221             unsigned char vregister;
00222             if (!readRegister(IOCONA, &vregister)) {
00223                 return;    
00224             }
00225             if (isBitSet(vregister, 1)) {
00226                 _intA->rise(p_tptr, p_mptr);
00227             } else {
00228                 _intA->fall(p_tptr, p_mptr);
00229             }
00230         }
00231     }
00232     
00233     template<typename T> 
00234     void CMCP23017_I2C::setIntrBCallback (const T * p_tptr, void(T::* p_mptr)(void)) {
00235             unsigned char vregister;
00236             if (!readRegister(IOCONB, &vregister)) {
00237                 return;    
00238             }
00239             if (isBitSet(vregister, 1)) {
00240                 _intB->rise(p_tptr, p_mptr);
00241             } else {
00242                 _intB->fall(p_tptr, p_mptr);
00243             }
00244     }
00245     
00246     void CMCP23017_I2C::setupInterrupts(const unsigned char p_mirroring, const unsigned char p_openDrain, const unsigned char p_polarity) {
00247         DEBUG_ENTER("CMCP23017_I2C::setupInterrupts: %02x, %02x, %02x", p_mirroring, p_openDrain, p_polarity)
00248         
00249         // Setup IOCONA
00250         unsigned char vregister;
00251         if (!readRegister(INTCONA, &vregister)) {
00252             return;    
00253         }
00254         // Setup INTCON - REGISTER 1-5: INTCON – INTERRUPT-ON-CHANGE CONTROL REGISTER
00255         vregister = setBit(vregister, 6, p_mirroring);
00256         vregister = setBit(vregister, 2, p_openDrain);
00257         vregister = setBit(vregister, 1, p_polarity);        
00258         writeRegister(INTCONA, vregister);
00259         
00260         // Setup IOCONB
00261         if (!readRegister(INTCONB, &vregister)) {
00262             return;    
00263         }
00264         // Setup INTCON - REGISTER 1-5: INTCON – INTERRUPT-ON-CHANGE CONTROL REGISTER
00265         vregister = setBit(vregister, 6, p_mirroring);
00266         vregister = setBit(vregister, 2, p_openDrain);
00267         vregister = setBit(vregister, 1, p_polarity);        
00268         writeRegister(INTCONB, vregister);
00269         
00270     }
00271     
00272     int CMCP23017_I2C::setupInterruptPin(const unsigned char p_gpioId, const InterruptModes p_mode) {
00273         DEBUG_ENTER("CMCP23017_I2C::setupInterruptPin: %02x, %02x", p_gpioId, p_mode)
00274         
00275         // Retrieve the register address
00276         unsigned char gpioIntconId, gpioDefvalId, gpioGpintenId;
00277         if (!registerIdFromGpioId(p_gpioId, &gpioIntconId)) {
00278 //            DEBUG_LEAVE("CMCP23017_I2C::setupInterruptPin: -1")
00279             return -1;
00280         }
00281         unsigned char gpioFlags;
00282         if (gpioIntconId == GPIOA) {
00283             gpioIntconId = INTCONA;
00284             gpioDefvalId = DEFVALA; 
00285             gpioGpintenId = GPINTENA;
00286             gpioFlags = _gpioAFlags;
00287         } else {
00288             gpioIntconId = INTCONB;
00289             gpioDefvalId = DEFVALB; 
00290             gpioGpintenId = GPINTENB;
00291             gpioFlags = _gpioBFlags;
00292         }
00293         DEBUG("CMCP23017_I2C::setupInterruptPin: gpioIntconId=%02x gpioDefvalId=%02x gpioGpintenId=%02x gpioFlags=%02x", gpioIntconId, gpioDefvalId, gpioGpintenId, gpioFlags)
00294         
00295         // Retrieve the GPIO pin number
00296         unsigned char gpioBit = gpioBitFromGpioId(p_gpioId);
00297         DEBUG("CMCP23017_I2C::setupInterruptPin: gpioBit=%02x", gpioBit)
00298         if (!isBitEqual(gpioFlags, gpioBit, 0x01)) { // Port pin is not configure as input
00299 //            DEBUG_LEAVE("CMCP23017_I2C::setupPullPin: -1")
00300             return -1;
00301         }        
00302         // Read it
00303         unsigned char gpioIntconValue, gpioDefvalValue, gpioGpintenValue;
00304         if (!readRegister(gpioIntconId, &gpioIntconValue)) {
00305 //            DEBUG_LEAVE("CMCP23017_I2C::setupInterruptPin: -2")
00306             return -2;
00307         }
00308         if (!readRegister(gpioDefvalId, &gpioDefvalValue)) {
00309 //            DEBUG_LEAVE("CMCP23017_I2C::setupInterruptPin: -2")
00310             return -2;
00311         }
00312         if (!readRegister(gpioGpintenId, &gpioGpintenValue)) {
00313 //            DEBUG_LEAVE("CMCP23017_I2C::setupInterruptPin: -2")
00314             return -2;
00315         }
00316         DEBUG("CMCP23017_I2C::setupInterruptPin: gpioIntconValue=%02x gpioDefvalValue=%02x gpioGpintenValue=%02x", gpioIntconValue, gpioDefvalValue, gpioGpintenValue)
00317         
00318         //         
00319         switch (static_cast<unsigned char>(p_mode)) {
00320             case static_cast<unsigned char>(OnChange):
00321                 gpioIntconValue = setBit(gpioIntconValue, gpioBit, 0x00);
00322                 gpioDefvalValue = setBit(gpioDefvalValue, gpioBit, 0x00);
00323                 break;
00324             case static_cast<unsigned char>(OnRising):
00325                 gpioIntconValue = setBit(gpioIntconValue, gpioBit, 0x01);
00326                 gpioDefvalValue = setBit(gpioDefvalValue, gpioBit, 0x00);
00327                 break;
00328             case static_cast<unsigned char>(OnFalling):
00329                 gpioIntconValue = setBit(gpioIntconValue, gpioBit, 0x01);
00330                 gpioDefvalValue = setBit(gpioDefvalValue, gpioBit, 0x01);
00331                 break;
00332         } // End of 'switch' statement
00333         
00334         // Enable interrupt
00335         gpioGpintenValue = setBit(gpioGpintenValue, gpioBit, 0x01); 
00336         
00337         // Write register
00338         DEBUG("CMCP23017_I2C::setupInterruptPin: gpioIntconValue=%02x gpioDefvalValue=%02x gpioGpintenValue=%02x", gpioIntconValue, gpioDefvalValue, gpioGpintenValue)
00339         writeRegister(gpioDefvalId, gpioDefvalValue);
00340         writeRegister(gpioIntconId, gpioIntconValue);
00341         writeRegister(gpioGpintenId, gpioGpintenValue);
00342         
00343 //        DEBUG_LEAVE("CMCP23017_I2C::setupInterruptPin: 0")
00344         return 0;
00345     }
00346     
00347     int CMCP23017_I2C::setupPullPin(const unsigned char p_gpioId, const PullModes p_mode) {
00348 //        DEBUG_ENTER("CMCP23017_I2C::setupPullPin: %02x, %02x", p_gpioId, p_mode)
00349         
00350         // Retrieve the register address
00351         unsigned char gpioGppuId;
00352         if (!registerIdFromGpioId(p_gpioId, &gpioGppuId)) {
00353 //            DEBUG_LEAVE("CMCP23017_I2C::setupPullPin: -1")
00354             return -1;
00355         }
00356         unsigned char gpioFlags;
00357         if (gpioGppuId == GPIOA) {
00358             gpioGppuId = GPPUA;
00359             gpioFlags = _gpioAFlags;
00360         } else {
00361             gpioGppuId = GPPUB;
00362             gpioFlags = _gpioBFlags;
00363         }
00364 //        DEBUG("CMCP23017_I2C::setupPullPin: gpioGppuId=%02x gpioFlags=%02x", gpioGppuId, gpioFlags)
00365         
00366         // Retrieve the GPIO pin number
00367         unsigned char gpioBit = gpioBitFromGpioId(p_gpioId);
00368 //        DEBUG("CMCP23017_I2C::setupPullPin: gpioBit=%02x", gpioBit)
00369         if (!isBitEqual(gpioFlags, gpioBit, 0x01)) { // Port pin is not configure as input
00370 //            DEBUG_LEAVE("CMCP23017_I2C::setupPullPin: -1")
00371             return -1;
00372         }
00373         
00374         // Read it
00375         unsigned char gpioGppuValue;
00376         if (!readRegister(gpioGppuId, &gpioGppuValue)) {
00377 //            DEBUG_LEAVE("CMCP23017_I2C::setupPullPin: -2")
00378             return -2;
00379         }
00380 //        DEBUG("CMCP23017_I2C::setupPullPin: gpioGppuId=%02x", gpioGppuId)
00381         
00382         //         
00383         switch (static_cast<unsigned char>(p_mode)) {
00384             case static_cast<unsigned char>(AbstractGpioExpender::PullOff):
00385                 gpioGppuValue = setBit(gpioGppuValue, gpioBit, 0x00);
00386                 break;
00387             case static_cast<unsigned char>(AbstractGpioExpender::PullUp):
00388                 gpioGppuValue = setBit(gpioGppuValue, gpioBit, 0x01);
00389                 break;
00390             case static_cast<unsigned char>(AbstractGpioExpender::PullDown):
00391                 // Not supporte, nothing to do
00392                 break;
00393         } // End of 'switch' statement
00394         
00395         // Write register
00396 //        DEBUG("CMCP23017_I2C::setupPullPin: gpioGppuValue=%02x", gpioGppuValue)
00397         writeRegister(gpioGppuId, gpioGppuValue);
00398         
00399         
00400 //        DEBUG_LEAVE("CMCP23017_I2C::setupPullPin: 0")
00401         return 0;
00402     }
00403     
00404     int CMCP23017_I2C::getLastInterruptPinAndValue(unsigned char * p_gpioId, unsigned char * p_value) {
00405 //        DEBUG_ENTER("CMCP23017_I2C::getLastInterruptPinAndValue")
00406         
00407         // Read first INTFA if required
00408         unsigned char vregister;
00409         if (_gpioAFlags != 0x00) {
00410             if (!readRegister(INTFA, &vregister)) {
00411 //                DEBUG_LEAVE("CMCP23017_I2C::setupInterruptPin: -1")
00412                 return -1;    
00413             }
00414             vregister &= _gpioAFlags; // Cannot have interrupt on output port
00415             for (unsigned char bit = 0; bit < GPIO_SIZE; bit++) {
00416                 if (isBitSet(vregister, bit)) {
00417                     *p_gpioId = bit;
00418                     readRegister(INTCAPA, p_value);
00419                     *p_value = (*p_value >> bit) & 0x01;
00420                     
00421 //                    DEBUG_LEAVE("CMCP23017_I2C::getLastInterruptPinAndValue (A): %02x %02x", *p_gpioId, *p_value)
00422                     return 0;
00423                 }
00424             } // End of 'for' statement
00425         }
00426         
00427         // If not interrupt on GPIOA, try with GPIOB
00428         if (_gpioBFlags != 0x00) {
00429             if (!readRegister(INTFB, &vregister)) {
00430 //                DEBUG_LEAVE("CMCP23017_I2C::setupInterruptPin: -2")
00431                 return -2;    
00432             }
00433             vregister &= _gpioBFlags; // Cannot have interrupt on output port
00434             for (unsigned char bit = 0; bit < GPIO_SIZE; bit++) {
00435                 if (isBitSet(vregister, bit)) {
00436                     *p_gpioId = bit + GPIO_SIZE;
00437                     readRegister(INTCAPB, p_value);
00438                     *p_value = (*p_value >> bit) & 0x01;
00439                     
00440 //                    DEBUG_LEAVE("CMCP23017_I2C::getLastInterruptPinAndValue (B): %02x %02x", *p_gpioId, *p_value)
00441                     return 0;
00442                 }
00443             } // End of 'for' statement
00444         }
00445         
00446 //        DEBUG_LEAVE("CMCP23017_I2C::getLastInterruptPinAndValue: 0")
00447         return 0;
00448     }
00449     
00450     int CMCP23017_I2C::read(const unsigned char p_gpioId, unsigned char * p_value) {
00451 //        DEBUG_ENTER("CMCP23017_I2C::read: 0x%02x", p_gpioId)
00452         
00453         // Retrieve the register address
00454         unsigned char gpioRegisterId;
00455         if (!registerIdFromGpioId(p_gpioId, &gpioRegisterId)) {
00456 //            DEBUG_LEAVE("CMCP23017_I2C::read: -1")
00457             return -1;
00458         }
00459 //        DEBUG("CMCP23017_I2C::read: gpioRegisterId=%02x", gpioRegisterId)
00460         unsigned char gpioBit = gpioBitFromGpioId(p_gpioId);
00461 //        DEBUG("CMCP23017_I2C::read: gpioBit=%02x", gpioBit)
00462         
00463         // Read it
00464         unsigned char gpioRegisterValue;
00465         if (!readRegister(gpioRegisterId, &gpioRegisterValue)) {
00466 //            DEBUG_LEAVE("CMCP23017_I2C::read: -2")
00467             return -2;
00468         }
00469 //        DEBUG("CMCP23017_I2C::read: gpioRegisterValue=%02x", gpioRegisterValue)
00470         
00471         *p_value = (isBitSet(gpioRegisterValue, gpioBit)) ? 0x01 : 0x00;
00472 //        DEBUG("CMCP23017_I2C::read: p_value=%02x", *p_value)
00473         
00474 //        DEBUG_LEAVE("CMCP23017_I2C::read: 0")
00475         return 0;
00476     }
00477     
00478     bool CMCP23017_I2C::registerIdFromGpioId(const unsigned char p_gpioId, unsigned char * p_gpioRegisterId) {
00479 //        DEBUG_ENTER("CMCP23017_I2C::registerIdFromGpioId: 0x%02x", p_gpioId)
00480         
00481         // Sanity check
00482         if (p_gpioId > GPIO_MAX) {
00483 //            DEBUG_ENTER("CMCP23017_I2C::registerIdFromGpioId: false")
00484             return false;
00485         }
00486         
00487         *p_gpioRegisterId = (p_gpioId < GPIO_MED) ? GPIOA : GPIOB;
00488         
00489 //        DEBUG_ENTER("CMCP23017_I2C::registerIdFromGpioId: true")
00490         return true;
00491     }
00492     
00493     int CMCP23017_I2C::write(const unsigned char p_gpioId, const unsigned char p_value) {
00494 //        DEBUG_ENTER("CMCP23017_I2C::write: 0x%02x 0x%02x", p_gpioId, p_value)
00495         
00496         // Retrieve the register address
00497         unsigned char gpioRegisterId;
00498         if (!registerIdFromGpioId(p_gpioId, &gpioRegisterId)) {
00499 //            DEBUG_LEAVE("CMCP23017_I2C::write: -1")
00500             return -1;
00501         }
00502 //        DEBUG("CMCP23017_I2C::write: gpioRegisterId=%02x", gpioRegisterId)
00503         
00504         // Retrieve the GPIO pin number
00505         unsigned char gpioBit = gpioBitFromGpioId(p_gpioId);
00506 //        DEBUG("CMCP23017_I2C::write: gpioBit=%02x", gpioBit)
00507         
00508         // Read it
00509         unsigned char gpioRegisterValue;
00510         if (!readRegister(gpioRegisterId, &gpioRegisterValue)) {
00511 //            DEBUG_LEAVE("CMCP23017_I2C::write: -2")
00512             return -2;
00513         }
00514 //        DEBUG("CMCP23017_I2C::write: gpioRegisterValue=%02x", gpioRegisterValue)
00515         
00516         // Update GPIO bit
00517         if (!isBitEqual(gpioRegisterValue, gpioBit, p_value)) {
00518             // Write it if required
00519             gpioRegisterValue = setBit(gpioRegisterValue, gpioBit, p_value);
00520 //            DEBUG("CMCP23017_I2C::write: New gpioRegisterValue=%02x", gpioRegisterValue)
00521             if (!writeRegister(gpioRegisterId, gpioRegisterValue)) {
00522 //                DEBUG_LEAVE("CMCP23017_I2C::write: -3")
00523                 return -3;
00524             }
00525         }
00526         
00527 //        DEBUG_LEAVE("CMCP23017_I2C::write: 0")
00528         return 0;
00529     }
00530     
00531     unsigned char CMCP23017_I2C::createBus(const std::list<unsigned char> p_lines, const PinMode p_mode) {
00532         unsigned char busId = _busesIndex++;
00533         
00534         _buses.insert(_buses.end(), std::pair<unsigned char, std::list<unsigned char> >(busId, p_lines));
00535         
00536         return busId;
00537     }
00538 
00539     void CMCP23017_I2C::deleteBus(const unsigned char p_busId) {
00540         // Sanity check
00541         std::map<unsigned char, std::list<unsigned char> >::iterator result = _buses.find(p_busId);
00542         if (result == _buses.end()) { // Invalid bus identifier
00543             return;
00544         }
00545         
00546         _buses.erase(p_busId);
00547     }
00548 
00549     int CMCP23017_I2C::busRead(const unsigned char p_busId, unsigned short * p_value) {
00550 //        DEBUG_ENTER("CMCP23017_I2C::busRead: 0x%02x", p_busId)
00551 
00552         // Sanity checks
00553         if (_buses.size() == 0) {
00554 //            DEBUG_LEAVE("CMCP23017_I2C::busRead: -1")
00555             return -1;
00556         }
00557         std::map<unsigned char, std::list<unsigned char> >::iterator result = _buses.find(p_busId);
00558         if (result == _buses.end()) { // Invalid bus identifier
00559 //            DEBUG_LEAVE("CMCP23017_I2C::busRead: -1")
00560             return -1;
00561         }
00562         
00563         std::list<unsigned char>::reverse_iterator rit;
00564         for (std::list<unsigned char>::reverse_iterator rit = result->second.rbegin(); rit != result->second.rend(); ++rit) {
00565             unsigned char regvalue;
00566             if (read(*rit, &regvalue) == 0) {
00567                 *p_value = (*p_value | regvalue) << 1;
00568             } else {
00569                 *p_value <<= 1;
00570             }
00571         } // End of 'for' statement
00572         
00573 //        DEBUG_LEAVE("CMCP23017_I2C::busRead: 0")
00574         return 0;
00575     }
00576 
00577     int CMCP23017_I2C::busWrite(const unsigned char p_busId, const unsigned short p_value) {
00578 //        DEBUG_ENTER("CMCP23017_I2C::busWrite: 0x%02x - 0x%02x", p_busId, p_value)
00579 
00580         // Sanity checks
00581         if (_buses.size() == 0) {
00582             return -1;
00583         }
00584         std::map<unsigned char, std::list<unsigned char> >::iterator result = _buses.find(p_busId);
00585         if (result == _buses.end()) { // Invalid bus identifier
00586 //            DEBUG_LEAVE("CMCP23017_I2C::busWrite: -1")
00587             return -1;
00588         }
00589         
00590         std::list<unsigned char>::reverse_iterator rit;
00591         unsigned short value = p_value;
00592         for (std::list<unsigned char>::reverse_iterator rit = result->second.rbegin(); rit != result->second.rend(); ++rit) {
00593             write(*rit, value & 0x01);
00594             value >>= 1;
00595         } // End of 'for' statement
00596         
00597 //        DEBUG_LEAVE("CMCP23017_I2C::busWrite: 0")
00598         return 0;
00599     }
00600 
00601     bool CMCP23017_I2C::writeRegister(const unsigned char p_registerId, const unsigned char p_value) {
00602 //        DEBUG_ENTER("CMCP23017_I2C::writeRegister: Memory address: 0x%02x - 0x%02x", p_registerId, p_value)
00603     
00604         // 1.Prepare buffer
00605         char i2cBuffer[2]; // Register address + one byte of data
00606         // 1.1. Memory address
00607         i2cBuffer[0] = p_registerId;
00608         // 1.2. Datas
00609         i2cBuffer[1] = p_value;
00610 //        DEBUG("CMCP23017_I2C::writeRegister: Data=0x%02x 0x%02x", i2cBuffer[0], i2cBuffer[1])
00611     
00612         // 2. Send I2C start + I2C address + Memory Address + Datas + I2C stop
00613         int result = _i2cInstance->write(_slaveAddress, i2cBuffer, 2);
00614 //        wait(0.02);
00615     
00616 //        DEBUG_LEAVE("CMCP23017_I2C::writeRegister %x", (bool)(result == 0))
00617         return (bool)(result == 0);
00618     }
00619     
00620     bool CMCP23017_I2C::readRegister(const unsigned char p_registerId, unsigned char * p_value) {
00621 //        DEBUG_ENTER("CMCP23017_I2C::readRegister: Memory address: 0x%02x", p_registerId)
00622     
00623         // 1.Prepare buffer
00624         char i2cBuffer[1]; // Register address + one byte of data
00625         // 1.1. Memory address
00626         i2cBuffer[0] = p_registerId;
00627 //        DEBUG("CMCP23017_I2C::readRegister: Data=0x%02x", i2cBuffer[0])
00628     
00629         // 2. Send I2C start + memory address
00630         if (_i2cInstance->write(_slaveAddress, i2cBuffer, 1, true) == 0) {
00631 //            wait(0.02);
00632 //            DEBUG("CMCP23017_I2C::readRegister: Write memory done")
00633             // 2. Read data + I2C stop
00634             int result = _i2cInstance->read(_slaveAddress, (char *)p_value, 1);
00635 //            wait(0.02);
00636     
00637 //            DEBUG_LEAVE("C24LCXX_I2C::readRegister (byte): %x", (bool)(result == 0))
00638             return (bool)(result == 0);
00639         }
00640             
00641 //        DEBUG_LEAVE("CMCP23017_I2C::readRegister false")
00642         return false;
00643     }
00644     
00645     void CMCP23017_I2C::DumpRegisters() {
00646         
00647         unsigned char value;
00648         for (unsigned int registerId = 0; registerId < 0x16; registerId++) {
00649             readRegister(registerId, &value);
00650 //            DEBUG("CMCP23017_I2C::DumpRegisters: register[%d] = 0x%02x", registerId, value)
00651         }
00652     }
00653     
00654     void CMCP23017_I2C::DumpRegister(unsigned int p_registerId) {
00655         
00656         unsigned char value;
00657         readRegister(p_registerId, &value);
00658 //        DEBUG("CMCP23017_I2C::DumpRegister: register[%d] = 0x%02x", p_registerId, value)
00659     }
00660     
00661 } // End of namespace MCP23017_I2C