diff --git a/.github/workflows/build-deploy-ghpages.yml b/.github/workflows/build-deploy-ghpages.yml index b69a484..655e3ff 100644 --- a/.github/workflows/build-deploy-ghpages.yml +++ b/.github/workflows/build-deploy-ghpages.yml @@ -1,4 +1,4 @@ -name: Build Documentation and Deploy +name: Documentation on: push: diff --git a/.github/workflows/compile-sketch.yml b/.github/workflows/compile-sketch.yml index 6deb49f..86fcf45 100644 --- a/.github/workflows/compile-sketch.yml +++ b/.github/workflows/compile-sketch.yml @@ -44,12 +44,12 @@ jobs: - name: esp32:esp32 source-url: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json - # Artemis / Apollo3 + # Artemis / Apollo3 Feb 25 - there some issue here -- will need to look at # https://github.com/sparkfun/Arduino_Apollo3/blob/main/boards.txt - - fqbn: SparkFun:apollo3:sfe_artemis_atp - platforms: | - - name: SparkFun:apollo3 - source-url: https://raw.githubusercontent.com/sparkfun/Arduino_Apollo3/master/package_sparkfun_apollo3_index.json + # - fqbn: SparkFun:apollo3:sfe_artemis_atp + # platforms: | + # - name: SparkFun:apollo3 + # source-url: https://raw.githubusercontent.com/sparkfun/Arduino_Apollo3/master/package_sparkfun_apollo3_index.json # ESP8266 # https://github.com/esp8266/Arduino/blob/master/boards.txt diff --git a/README.md b/README.md index 64df0b3..f9bbb5a 100644 --- a/README.md +++ b/README.md @@ -7,22 +7,89 @@ ![GitHub (Pre-)Release Date](https://img.shields.io/github/release-date-pre/sparkfun/SparkFun_Toolkit) ![Documentation Build](https://github.com/sparkfun/SparkFun_Toolkit/actions/workflows/build-deploy-ghpages.yml/badge.svg) -The SparkFun Toolkit provides a common set of core functionality for use across the SparkFun Arduino Driver library. Instead of each device driver library implementing it's own communication layers, error types and design, the SparkFun Toolkit library is used. +The SparkFun Toolkit provides a common set of core functionality for use across the spectrum of SparkFun developed embedded libraries and applications. It provides a well tested, extensively used, and abstract foundational layer of functionality to use across a wide-range of solutions. + +This, the first iteration of the SparkFun Toolkit focuses on device communication - namely the communication between a embedded microprocessor and a peripheral devices. Focusing on the *communication bus* aspect of embedded development, the toolkit simplifies system development by providing a proven bus implementation, as well as a set of abstract interfaces that enable rapid development of multi-bus type implementations. + +In addition to providing a set of common device bus communication functionality, the SparkFun Toolkit is structure to provide a *platform independent* solution. While the initial implementation targets Arduino development, the architecture is patterned to define a common core of functionality and interfaces that are platform agnostic. Use of the SparkFun Toolkit within a non-Arduino, c++ environment, requires the implementation of small set of platform specific functionality. ## Motivation -Often, the same core functionality is implemented with a majority of our Arduino libraries, each implementation providing the same functionality, but implemented differently. The result is solutions that have different quirks, and impossible to maintain/support effectively. The SparkFun Toolkit solves this issue. +Often, the same core functionality is implemented within a majority of our Arduino libraries, with each implementation providing the same functionality, but implemented differently. The result of this are different solutions that delivery the same functionality, but each have their unique quirks and behavior oddities. As this implementation patter expands, it becomes impossible to maintain/support effectively. + +An example of this is software libraries provided in support of the SparkFun qwiic ecosystem. With over 200 sensors, input devices and accessories, the implementation and maintenance of the driver communication layers are difficult burden that the SparkFun Toolkit addresses. + +## The SparkFun Toolkit The SparkFun Toolkit provides a single implementation of common functionality used in the software developed for SparkFun boards. Initially targeted at the Arduino development environment, the SparkFun Toolkit delivers the following benefits: * Use a well-tested and validated implementation * Reduce development effort * Implement functionality following a common structure +* Designed following a platform independent architectural pattern * Set the foundation for future enhancements - as the capabilities of the toolkit grow, these features become available with little to any implementation effort. +### General Architecture + +Implemented using C++, the SparkFun toolkit follows a simple two layered approach in it's design: A core foundational layer, and a platform specific layer. + +```mermaid +--- +title: General Architecture Structure +--- +classDiagram + class CoreToolkit["Core Toolkit Interfaces"] + class PlatformOne["Platform Implementation"] + CoreToolkit <|-- PlatformOne + +``` +And as additional plaforms are added, they also implement/inherit from the SparkFun Toolkit Core. +```mermaid +--- +title: Multi-Platform Structure +--- +classDiagram + class CoreToolkit["Core Toolkit Interfaces"] + class PlatformOne["Platform One"] + class PlatformTwo["Platform Two"] + + CoreToolkit <|-- PlatformOne + CoreToolkit <|-- PlatformTwo +``` + +When using the SparkFun Toolkit, the intent is for the implementation to follow the same pattern: A platform independent layer that works with the SparkFun Toolkit core, and a platform specific layer that utilizes the SparkFun Toolkit platform specific implementation. + +```mermaid +--- +title: Application Structure +--- +classDiagram + direction TD + note for ApplicationCore "Application Logic" + class ApplicationCore["Application Core"] + class CoreToolkit["Core Toolkit Interfaces"] + + note for CoreToolkit "SparkFun Toolkit" + class ApplicationPlatform["Application Platform"] + style ApplicationPlatform fill:#909090 + class PlatformOne["Platform Implementation"] + style PlatformOne fill:#909090 + + CoreToolkit <|-- PlatformOne + ApplicationCore <--> Application Platform + +``` + +If/when the application is moved to another platform, just the platform specific logic needs implementation. + ## Documentation -The SparkFun Toolkit Development documentation is available [here](https://docs.sparkfun.com/SparkFun_Toolkit) +The SparkFun Toolkit Development documentation is available [here](https://docs.sparkfun.com/SparkFun_Toolkit). This includes doxygen generated class/API documentation, as well as additional architectural details. + +## Examples + +The best way to understand and use the SparkFun Toolkit is to see it being used on other libraries. For our SparkFun developed libraries and firmware that use the SparkFun Toolkit, their associated github repositories are tagged with [sparkfun-toolkit](https://github.com/topics/sparkfun-toolkit) tag. + ## Installation and Use @@ -30,15 +97,12 @@ To use the SparkFun Toolkit directly, or in library development kit is installab However, for solutions that use the SparkFun Toolkit, it is installed automatically during the Arduino library installation process, by marking the Toolkit as a dependency when publishing your library. -To mark the `SparkFun Toolkit` as a dependency, add the following line to the `library.properties` file for your library. +To mark the `SparkFun Toolkit` as a dependency, add the following line to the `library.properties` file for your library. ```INI -depends=SparkFun Toolkit +depends=SparkFun Toolkit (>=1.0.0) ``` -## Examples - -The following Arduino Libraries are making use of the SparkFun Toolkit: +> [!NOTE] +> A version indicator is included to ensure your library uses the correct version of the toolkit. -* [SparkFun Qwiic Pulsed Coherent Radar Sensor XM125](https://github.com/sparkfun/SparkFun_Qwiic_XM125_Arduino_Library) -* [SparkFun Qwiic AS7331 Spectral UV Sensor](https://github.com/sparkfun/SparkFun_AS7331_Arduino_Library) diff --git a/docs/ar_ibus.md b/docs/ar_ibus.md index 187f3cf..c2f23ca 100644 --- a/docs/ar_ibus.md +++ b/docs/ar_ibus.md @@ -35,35 +35,32 @@ The key class to support this pattern are: | | | |------|-------| -|**sfeTkIBus** | A virtual C++ class that device the bus ```sfeTkIBus``` interface | -|**sfeTkII2C** | Sub-class of the ```sfeTkIIBus``` interface, it provides an interface for I2C devices| -|**sfeTkISPI** | Sub-class of the ```sfeTkIIBus``` interface, it provides an interface for SPI devices | +|**sfTkIBus** | A virtual C++ class that device the bus ```sfeTkIBus``` interface | +|**sfTkII2C** | Sub-class of the ```sfeTkIIBus``` interface, it provides an interface for I2C devices| +|**sfTkISPI** | Sub-class of the ```sfeTkIIBus``` interface, it provides an interface for SPI devices | -### The sfeTkIBus Interface +### The sfTkIBus Interface The key to meeting the goals of the Toolkit is the IBus interface. This interface defines the methods used to communicate with a device. The setup, configuration and implementation of this interface is performed by platform specific implementations of the interface. -The interface methods: +The bus implements methods that perform the following | Method| Definition | |------|-------| -|**writeRegisterByte** | Write a byte of data to a particular register of a device | -|**writeRegisterWord** | Write a word of data to a particular register of a device | -|**writeRegisterRegion** | Write an array of data to a particular register of a device| -|**readRegisterByte** | Read a byte of data from a particular register of a device | -|**readRegisterWord** | Read a word of data from a particular register of a device | -|**readRegisterRegion** | Read an array of data from a particular register of a device | +|**writeRegister(...)** | Overloaded set of methods to write data to a specified register| +|**readRegister(...)** | Overloaded set of methods to read data from a specified register| +|**writeData(...)** | An overloaded set of methods to write data directly to the device| + +Additionally a set of explicitly named methods for different core types are provided. > [!NOTE] > This interface only defines the methods to read and write data on the given bus. Any address, or bus specific settings is provided/implemented by the implementation/specialization of this interface. -The Inteface diagram for the ```sfeTkIBus``` is: - -![IIBus Interface](images/tk_uml_ibus.png) +Specific details for this class are detailed [here](https://docs.sparkfun.com/SparkFun_Toolkit/classsf_tk_i_bus.html) -### The sfeTkII2C Implementation +### The sfTkII2C Implementation -This class sub-classes from the ```sfeTkIBus``` interface adding additional functionally focused on supporting an I2C implementation. This class does not implement the IIBus interface, so it's abstract, but the class adds the additional functionality. +This class sub-classes from the ```sfTkIBus``` interface adding additional functionally focused on supporting an I2C implementation. This class does not implement the IIBus interface, so it's abstract, but the class adds the additional functionality. | Method| Definition | |------|-------| @@ -72,15 +69,13 @@ This class sub-classes from the ```sfeTkIBus``` interface adding additional func |**address** | Returns the address used by this I2C object | > [!NOTE] -> The ```sfeTkII2C``` class manages the device address for the I2C bus. As such, each I2C device instantiates/uses an instance of the ```sfeTkII2C``` class. +> The ```sfTkII2C``` class manages the device address for the I2C bus. As such, each I2C device instantiates/uses an instance of the ```sfTkII2C``` class. -The class diagram for the ```sfeTkII2C``` interface is the following: - -![II2C Class Diagram](images/tk_uml_ii2c.png) +The details for the ```sfeTkII2C``` interface are [here](https://docs.sparkfun.com/SparkFun_Toolkit/classsf_tk_i_i2_c.html) ### The sfeTkISPI Implementation -This class sub-classes from the ```sfeTkIBus``` interface adding additional functionally focused on supporting an SPI implementation. This interface provides the additional functionality. +This class sub-classes from the ```sfTkIBus``` interface adding additional functionally focused on supporting an SPI implementation. This interface provides the additional functionality. | Method| Definition | |------|-------| @@ -90,53 +85,47 @@ This class sub-classes from the ```sfeTkIBus``` interface adding additional func > [!NOTE] > The ```sfeTkISPI``` class manages CS Pin for the SPI bus. As such, each SPI device instantiates/uses an instance of the ```sfeTkISPI``` class. -The class diagram of these base class interfaces/implementation: - -![ISPI Class Diagram](images/tk_uml_ispi.png) +The details for the ```sfTkII2C``` interface are [here](https://docs.sparkfun.com/SparkFun_Toolkit/classsf_tk_i_s_p_i.html) -## sfeTkIBus - Arduino Implementation +## sfTkIBus - Arduino Implementation -The initial implementation of the toolkit IBus interface is for the Arduino environment. This implementation consists of two classes, ```sfeTkArdI2C``` and ```sfeTkArdSPI```, each of which sub-class from their respective bus type interfaces within the core toolkit. +The initial implementation of the toolkit IBus interface is for the Arduino environment. This implementation consists of two classes, ```sfTkArdI2C``` and ```sfTkArdSPI```, each of which sub-class from their respective bus type interfaces within the core toolkit. These driver implementations provide the platform specific implementation for the toolkit bus interfaces, supporting the methods defined by the interfaces, as well as contain and manage the platform specific settings and attributes for each bus type. > [!IMPORTANT] > The intent is that each user of an particular - a device in most cases - contains an instance of the specific bus class. -### The sfeTkArdI2C Class +### The sfTkArdI2C Class -This class provides the Arduino implementation of I2C in the SparkFun Toolkit. It implements the methods of the ```sfeTkIBus``` and ```sfeTkII2C``` interfaces, as well as manages any Arduino specific state. +This class provides the Arduino implementation of I2C in the SparkFun Toolkit. It implements the methods of the ```sfTkIBus``` and ```sfTkII2C``` interfaces, as well as manages any Arduino specific state. -The class diagram for the sfeTkArdI2C class: +Details for this class are located [here](https://docs.sparkfun.com/SparkFun_Toolkit/classsf_tk_ard_i2_c.html) -![Arduino I2C Class Diagram](images/tk_uml_ardi2c.png) +### The sfTkArdSPI Class -### The sfeTkArdSPI Class +This class provides the Arduino implementation of SPI in the SparkFun Toolkit. It implements the methods of the ```sfTkIBus``` and ```sfTkISPI``` interfaces, as well as manages any Arduino specific state for the SPI bus - namely the SPISettings class. -This class provides the Arduino implementation of SPI in the SparkFun Toolkit. It implements the methods of the ```sfeTkIBus``` and ```sfeTkISPI``` interfaces, as well as manages any Arduino specific state for the SPI bus - namely the SPISettings class. +Before each use of the SPI bus, the methods of the ```sfTkArdSPI``` uses an internal SPISettings class to ensure the SPI bus is operating in the desired mode for the device. -Before each use of the SPI bus, the methods of the ```sfeTkArdSPI``` uses an internal SPISettings class to ensure the SPI bus is operating in the desired mode for the device. +Details for this class are located [here](https://docs.sparkfun.com/SparkFun_Toolkit/classsf_tk_ard_s_p_i.html) -The class diagram for the sfeTkArdSPI class: +## sfTkIBus Use -![Arduino SPI Class Diagram](images/tk_uml_ardspi.png) - -## sfeTkIBus Use - -The general steps when using the sfeTkIBus in device development are outlined in the following steps. This example uses the Arduino implementation of the bus. +The general steps when using the sfTkIBus in device development are outlined in the following steps. This example uses the Arduino implementation of the bus. The general pattern for a device driver implementation that uses the SparkFun Toolkit is the following: ### Implement a Platform Independent Driver -The first step is to implement a core, platform independent version of the driver that communicates to the target device using the methods of a ```sfeTkIBus``` interface. By limiting use to the IBus interface, the core implementation can use any bus type or platform that implements the sfeTkIBus interface. +The first step is to implement a core, platform independent version of the driver that communicates to the target device using the methods of a ```sfTkIBus``` interface. By limiting use to the IBus interface, the core implementation can use any bus type or platform that implements the sfeTkIBus interface. > [!IMPORTANT] -> At this level, the driver is only using a ```sfeTkIBus``` interface, not any specific bus implementation. +> At this level, the driver is only using a ```sfTkIBus``` interface, not any specific bus implementation. This driver has the following unique functionality: -1) A method to set the object that implements the ```sfeTkIBus``` interface object should use. Since +1) A method to set the object that implements the ```sfTkIBus``` interface object should use or sets the bus in a ```begin()``` method. 1) If the device supports identification capabilities, the driver provides this functionality. #### Simple Example of an Independent Driver Implementation @@ -152,36 +141,42 @@ class myDriverClass { public: - myDriverClass(uint8_t address) : _addr{address}, _theBus{nullptr}{} + myDriverClass() : _theBus{nullptr}{} - bool begin() + sfTkError_t begin(sfTkBus *theBus = nullptr) { // initialize things ... - return true; - } - void setCommunicationBus(sfeTkIBus *theBus) - { + if (_theBus == nullptr) + return ksfTkErrFail; + _theBus = theBus; + return ksfTkErrOk; } - bool updateDeviceData(uint8_t *data, size_t len) + sfTkError_t updateDeviceData(uint8_t *data, size_t len) { if (!_theBus || !data || len == 0) - return false; + return ksfTkErrFail; - sfeTkError_t status = _theBus->writeRegisterRegion(THE_REG, data, len); + return _theBus->writeRegister(THE_REG, data, len); return (status == kSTkErrOk); } - bool checkDeviceID() + sfTkError_t checkDeviceID() { // do some device ID checks in registers ...etc - return true; + return kSTkErrOk; } + // and additional methods for the driver .. + sfTkError_t doSomethingA(int32_t); + sfTkError_t getValueA(uint32_t&); + sfTkError_t setPropertyB(double); + + private: - uint8_t _addr; + sfeTkIBus *_theBus; }; ``` @@ -213,29 +208,27 @@ class myArduinoDriverI2C : public myDriverClass myArduinoDriverI2C() {} - bool begin() + bool begin(const uint8_t address = SF_BMV080_DEFAULT_ADDRESS, TwoWire &wirePort = Wire) { - if (_theI2CBus.init(MY_DEVICE_ADDRESS) != kSTkErrOk) + if (_theI2CBus.init(wirePOrt, MY_DEVICE_ADDRESS) != ksfTkErrOk) return false; // OPTIONAL: If your device supports repeat starts. _theI2CBus.setStop(false); - setCommunicationBus(&_theI2CBus); - - return myDriverClass::begin(); + return myDriverClass::begin(&_theI2CBus); } bool isConnected() { - if (_theI2CBus.ping() != kSTkErrOk) + if (_theI2CBus.ping() != ksfTkErrOk) return false; - return checkDeviceID(); + return checkDeviceID() == kstTkErrOk; } private: - sfeTkArdI2C _theI2CBus; + sfTkArdI2C _theI2CBus; }; ``` @@ -254,27 +247,30 @@ class myArduinoDriveSPI : public myDriverClass myArduinoDriverSPI() {} - bool begin() + bool begin(uint8_t csPin, SPIClass &spiPort = SPI, + SPISettings spiSettings = SPISettings(4000000, MSBFIRST, SPI_MODE0)) + { - SPISettings spiSettings = SPISettings(4000000, MSBFIRST, SPI_MODE3); - if (_theSPIBus.init(SPI, spiSettings, MY_DEFAULT_CS, true) != kSTkErrOk) + if (_theSPIBus.init(spiPort, spiSettings, csPin, true) != ksfTkErrOk) return false; - setCommunicationBus(&_theSPIBus); - return myDriverClass::begin(); + return myDriverClass::begin(&_theSPIBus) == ksfTkErrOk; } bool isConnected() { - return checkDeviceID(); + return checkDeviceID() == ksfTkErrOk; } private: - sfeTkArdSPI _theSPIBus; + sfTkArdSPI _theSPIBus; }; ``` +> [!IMPORTANT] +>The I2C and SPI versions of the driver just manage the specific bus setup and initialization - beyond that, the core class, which ***only*** operates using the bus interface class forms the core of both implementations. + ## Summary In summary, the SparkFun Toolkit Bus Interface sets a standard that device drivers can implement against without concern for platform or bus type. Using common interface implementation patterns, the implementation delivers on the goals for this subsystem - namely: diff --git a/docs/doxygen/doxygen-config b/docs/doxygen/doxygen-config index f81a64b..7b98063 100644 --- a/docs/doxygen/doxygen-config +++ b/docs/doxygen/doxygen-config @@ -289,7 +289,7 @@ TAB_SIZE = 4 # with the commands \{ and \} for these it is advised to use the version @{ and # @} or use a double escape (\\{ and \\}) -ALIASES = +ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For @@ -1046,7 +1046,7 @@ EXCLUDE_SYMBOLS = # that contain example code fragments that are included (see the \include # command). -EXAMPLE_PATH = +EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and @@ -1297,7 +1297,7 @@ HTML_HEADER = ./docs/doxygen/doxygen-custom/header.html # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_FOOTER = +HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of diff --git a/docs/images/tk_uml_ardi2c.png b/docs/images/tk_uml_ardi2c.png deleted file mode 100644 index 7b3b20d..0000000 Binary files a/docs/images/tk_uml_ardi2c.png and /dev/null differ diff --git a/docs/images/tk_uml_ardspi.png b/docs/images/tk_uml_ardspi.png deleted file mode 100644 index 1ced665..0000000 Binary files a/docs/images/tk_uml_ardspi.png and /dev/null differ diff --git a/docs/images/tk_uml_ibus.png b/docs/images/tk_uml_ibus.png deleted file mode 100644 index 8a7dfbd..0000000 Binary files a/docs/images/tk_uml_ibus.png and /dev/null differ diff --git a/docs/images/tk_uml_ii2c.png b/docs/images/tk_uml_ii2c.png deleted file mode 100644 index a8b6bae..0000000 Binary files a/docs/images/tk_uml_ii2c.png and /dev/null differ diff --git a/docs/images/tk_uml_ispi.png b/docs/images/tk_uml_ispi.png deleted file mode 100644 index c5e97a8..0000000 Binary files a/docs/images/tk_uml_ispi.png and /dev/null differ diff --git a/library.properties b/library.properties index 5201f0f..8584b70 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=SparkFun Toolkit -version=0.9.2 +version=1.0.0 author=SparkFun Electronics maintainer=SparkFun Electronics sentence=A utility library that other SparkFun libraries can take advantage of. diff --git a/src/sfTk/sfTkError.h b/src/sfTk/sfTkError.h index c4e4632..bb505bb 100644 --- a/src/sfTk/sfTkError.h +++ b/src/sfTk/sfTkError.h @@ -1,4 +1,4 @@ - /** +/** * @file sfTkError.h * @brief Header file for the SparkFun Toolkit - Base Error Code defines. * @@ -11,7 +11,6 @@ * SPDX-License-Identifier: MIT */ - #pragma once #include @@ -46,6 +45,11 @@ const sfTkError_t ksfTkErrFail = -1; // general fail */ const sfTkError_t ksfTkErrOk = 0; // success +/** + * @brief Invalid parameter error + */ +const sfTkError_t ksfTkErrInvalidParam = -2; // invalid parameter error + /** * @brief A base value for bus errors. All bus errors are greater than this value, in the 1000 range */ diff --git a/src/sfTk/sfTkIBus.h b/src/sfTk/sfTkIBus.h index 16bc09e..5536dff 100644 --- a/src/sfTk/sfTkIBus.h +++ b/src/sfTk/sfTkIBus.h @@ -75,69 +75,216 @@ class sfTkIBus /** * @brief Constructor */ - sfTkIBus() { + sfTkIBus() + { _byteOrder = sftk_system_byteorder(); } + + /** + * @brief Writes an array of bytes to a register on the target address. Supports any address size + * @note This is the minimum required write method to implement for a driver + * + * @param devReg The device's register's address - can be any size, If nullptr, address is not sent + * @param regLength The length of the register address. If 0, address is not sent + * @param data The data to write + * @param length The length of the data buffer + * @return sfTkError_t Returns ksfTkErrOk on success, or ksfTkErrFail code + */ + virtual sfTkError_t writeRegister(uint8_t *devReg, size_t regLength, const uint8_t *data, size_t length) = 0; + /**-------------------------------------------------------------------------- - * @brief Send a single byte to the device* - * @param data Data to write. + * @brief Writes a 8-bit data value. * - * @retval sfTkError_t - ksfTkErrOk on successful execution. + * This function writes a 8-bit data value * + * @param data The 8-bit data value to be written. + * @return sfTkError_t The status of the write operation. */ - virtual sfTkError_t writeByte(uint8_t data) = 0; + virtual sfTkError_t writeData(uint8_t data) + { + return writeRegister(nullptr, 0, &data, sizeof(uint8_t)); + } /**-------------------------------------------------------------------------- - * @brief Send a word to the device. - * @param data Data to write. + * @brief Writes a 8-bit data value. + * + * This function writes a 8-bit data value + * + * @param data The 8-bit data value to be written. + * @return sfTkError_t The status of the write operation. + */ + sfTkError_t writeUInt8(uint8_t data) + { + return writeData(data); + } + + /**-------------------------------------------------------------------------- + * @brief Send a 16 bit value to the device. + * @param data Data to write. If the byte order is different than system byteorder, data is byteswapped * * @retval sfTkError_t - ksfTkErrOk on successful execution. * */ - virtual sfTkError_t writeWord(uint16_t data) = 0; + virtual sfTkError_t writeData(uint16_t data) + { + // byte swap? + if (sftk_system_byteorder() != _byteOrder) + data = sftk_byte_swap(data); + + return writeRegister(nullptr, 0, (uint8_t *)&data, sizeof(uint16_t)); + } /**-------------------------------------------------------------------------- - * @brief Send an array of data to the device. - * @param data Data to write. - * @param length - length of data. + * @brief Send a 16 bit value to the device. + * @param data Data to write. If the byte order is different than system byteorder, data is byteswapped * * @retval sfTkError_t - ksfTkErrOk on successful execution. * */ - virtual sfTkError_t writeRegion(const uint8_t *data, size_t length) = 0; + sfTkError_t writeUInt16(uint16_t data) + { + return writeData(data); + } + + /**-------------------------------------------------------------------------- + * @brief Writes a 32-bit data value. + * + * This function writes a 32-bit data value + * + * @param data The 32-bit data value to be written. The data is byteswapped if needed. + * @return sfTkError_t The status of the write operation. + */ + virtual sfTkError_t writeData(uint32_t data) + { + // byte swap? + if (sftk_system_byteorder() != _byteOrder) + data = sftk_byte_swap(data); + + return writeRegister(nullptr, 0, (uint8_t *)&data, sizeof(uint32_t)); + } /**-------------------------------------------------------------------------- - * @brief Write a single byte to the given register + * @brief Writes a 32-bit data value. + * + * This function writes a 32-bit data value + * + * @param data The 32-bit data value to be written. The data is byteswapped if needed. + * @return sfTkError_t The status of the write operation. + */ + sfTkError_t writeUInt32(uint32_t data) + { + return writeData(data); + } + /**-------------------------------------------------------------------------- + * @brief Writes an array + * + * This function writes a 8-bit data array + * + * @param data The 8-bit data array to be written. The data is byteswapped if needed. + * @param length The length of the data array to be written. + * @return sfTkError_t The status of the write operation. + */ + virtual sfTkError_t writeData(const uint8_t *data, size_t length) + { + return writeRegister(nullptr, 0, data, length); + } + + /**-------------------------------------------------------------------------- + * @brief Write a single byte (8 bit) to the given register * * @param devReg The device's register's address. - * @param data Data to write. + * @param data Data to write. Note - if byte order differs, swap the data before writing. * * @retval sfTkError_t - ksfTkErrOk on successful execution. * */ - virtual sfTkError_t writeRegisterByte(uint8_t devReg, uint8_t data) = 0; - - // Overload version sfTkError_t writeRegister(uint8_t devReg, uint8_t data) { - return writeRegisterByte(devReg, data); + return writeRegister(&devReg, sizeof(devReg), &data, sizeof(uint8_t)); + } + + /**-------------------------------------------------------------------------- + * @brief Write a single byte (8 bit) to the given register + * + * @param devReg The device's register's address. + * @param data Data to write. Note - if byte order differs, swap the data before writing. + * + * @retval sfTkError_t - ksfTkErrOk on successful execution. + * + */ + sfTkError_t writeRegisterUInt8(uint8_t reg, uint8_t data) + { + return writeRegister(reg, data); } /**-------------------------------------------------------------------------- * @brief Write a single word (16 bit) to the given register * * @param devReg The device's register's address. - * @param data Data to write. + * @param data Data to write. Note - if byte order differs, swap the data before writing. * * @retval sfTkError_t - ksfTkErrOk on successful execution. * */ - virtual sfTkError_t writeRegisterWord(uint8_t devReg, uint16_t data) = 0; + virtual sfTkError_t writeRegister(uint8_t devReg, const uint16_t data) + { + // swap the data? + uint16_t value = data; + if (sftk_system_byteorder() != _byteOrder) + value = sftk_byte_swap(value); - // Overload version - sfTkError_t writeRegister(uint8_t devReg, uint16_t data) + return writeRegister(&devReg, sizeof(devReg), (uint8_t *)&value, sizeof(value)); + } + + /**-------------------------------------------------------------------------- + * @brief Write a single word (16 bit) to the given register + * + * @param devReg The device's register's address. + * @param data Data to write. Note - if byte order differs, swap the data before writing. + * + * @retval sfTkError_t - ksfTkErrOk on successful execution. + * + */ + sfTkError_t writeRegisterUInt16(uint8_t reg, uint16_t data) + { + return writeRegister(reg, data); + } + + /** + * @brief Writes a 32-bit data value to a specified device register. + * + * This function writes a 32-bit data value to a specified device register. + * If the system byte order differs from the byte order expected by the device, + * the data value is byte-swapped before being written. + * + * @param devReg The register address to write to. + * @param data The 32-bit data value to write. + * @return sfTkError_t Error code indicating the success or failure of the operation. + */ + virtual sfTkError_t writeRegister(uint8_t devReg, const uint32_t data) { - return writeRegisterWord(devReg, data); + uint32_t value = data; + // swap the data? + if (sftk_system_byteorder() != _byteOrder) + value = sftk_byte_swap(value); + + return writeRegister(&devReg, sizeof(devReg), (uint8_t *)&value, sizeof(data)); + } + + /** + * @brief Writes a 32-bit data value to a specified device register. + * + * This function writes a 32-bit data value to a specified device register. + * If the system byte order differs from the byte order expected by the device, + * the data value is byte-swapped before being written. + * + * @param devReg The register address to write to. + * @param data The 32-bit data value to write. + * @return sfTkError_t Error code indicating the success or failure of the operation. + */ + sfTkError_t writeRegisterUInt32(uint8_t reg, uint32_t data) + { + return writeRegister(reg, data); } /**-------------------------------------------------------------------------- @@ -150,49 +297,192 @@ class sfTkIBus * @retval sfTkError_t ksfTkErrOk on successful execution * */ - virtual sfTkError_t writeRegisterRegion(uint8_t devReg, const uint8_t *data, size_t length) = 0; - - // Overload version - sfTkError_t writeRegister(uint8_t devReg, const uint8_t *data, size_t length) + virtual sfTkError_t writeRegister(uint8_t devReg, const uint8_t *data, size_t length) { - return writeRegisterRegion(devReg, data, length); + return writeRegister(&devReg, sizeof(devReg), data, length); } /**-------------------------------------------------------------------------- * @brief Writes a number of bytes starting at the given register's 16-bit address. * - * @param devReg The device's register's address. + * @param devReg The device's register's 16 bit address. If the byteorder is different than the systems, the + * address is byteswapped * @param data Data to write. * @param length - length of data * * @retval sfTkError_t ksfTkErrOk on successful execution * */ - virtual sfTkError_t writeRegister16Region(uint16_t devReg, const uint8_t *data, size_t length) = 0; + virtual sfTkError_t writeRegister(uint16_t devReg, const uint8_t *data, size_t length) + { + if (sftk_system_byteorder() != _byteOrder) + devReg = sftk_byte_swap(devReg); - // Overload version - sfTkError_t writeRegister(uint16_t devReg, const uint8_t *data, size_t length) + return writeRegister((uint8_t *)&devReg, sizeof(devReg), data, length); + } + + /** + * @brief Writes a 8-bit data value to a specified device register. + * + * This function writes a 16-bit data value to a specified device register. + * If the system byte order differs from the byte order expected by the device, + * the data value is byte-swapped before being written. + * + * @param devReg The device's register's 16 bit address. If the byteorder is different than the systems, the address + * is byteswapped + * @param data The 8-bit data value to write. + * @return sfTkError_t Error code indicating the success or failure of the operation. + */ + virtual sfTkError_t writeRegister(uint16_t devReg, const uint8_t data) { - return writeRegister16Region(devReg, data, length); + return writeRegister(devReg, &data, 1); } + /** + * @brief Writes a 8-bit data value to a specified device register. + * + * This function writes a 16-bit data value to a specified device register. + * If the system byte order differs from the byte order expected by the device, + * the data value is byte-swapped before being written. + * + * @param devReg The device's register's 16 bit address. If the byteorder is different than the systems, the address + * is byteswapped + * @param data The 8-bit data value to write. + * @return sfTkError_t Error code indicating the success or failure of the operation. + */ + sfTkError_t writeRegisterUInt8(uint16_t reg, const uint8_t data) + { + return writeRegister(reg, data); + } + /** + * @brief Writes a 16-bit data value to a specified device 16bit register. + * + * This function writes a 16-bit data value to a specified device register. + * If the system byte order differs from the byte order expected by the device, + * the data value is byte-swapped before being written. + * + * @param devReg The 16 bit register address to write to. + * @param data The 16-bit data value to write. + * @return sfTkError_t Error code indicating the success or failure of the operation. + */ + virtual sfTkError_t writeRegister(uint16_t devReg, const uint16_t data) + { + return writeRegister(devReg, &data, sizeof(data)); + } + + /** + * @brief Writes a 16-bit data value to a specified device 16bit register. + * + * This function writes a 16-bit data value to a specified device register. + * If the system byte order differs from the byte order expected by the device, + * the data value is byte-swapped before being written. + * + * @param devReg The 16 bit register address to write to. + * @param data The 16-bit data value to write. + * @return sfTkError_t Error code indicating the success or failure of the operation. + */ + sfTkError_t writeRegisterUInt16(uint16_t reg, const uint16_t data) + { + return writeRegister(reg, data); + } + + /** + * @brief Writes a 32-bit data value to a specified device register. + * + * This function writes a 32-bit data value to a specified device register. + * If the system byte order differs from the byte order expected by the device, + * the data value is byte-swapped before being written. + * + * @param devReg The register address to write to. + * @param data The 32-bit data value to write. This value is byteswapped if the byteorder set is different that the + * systems byteorder + * @return sfTkError_t Error code indicating the success or failure of the operation. + */ + virtual sfTkError_t writeRegister(uint16_t devReg, const uint32_t data) + { + uint32_t value = data; + // do we need to swap the data value? Note the address is swapped in the called writeReg16 method + if (sftk_system_byteorder() != _byteOrder) + value = sftk_byte_swap(data); + + return writeRegister(devReg, (const uint8_t *)&value, sizeof(uint32_t)); + } + + /** + * @brief Writes a 32-bit data value to a specified device register. + * + * This function writes a 32-bit data value to a specified device register. + * If the system byte order differs from the byte order expected by the device, + * the data value is byte-swapped before being written. + * + * @param devReg The register address to write to. + * @param data The 32-bit data value to write. This value is byteswapped if the byteorder set is different that the + * systems byteorder + * @return sfTkError_t Error code indicating the success or failure of the operation. + */ + sfTkError_t writeRegisterUInt32(uint16_t reg, const uint32_t data) + { + return writeRegister(reg, data); + } /**-------------------------------------------------------------------------- * @brief Writes a number of uint16's starting at the given register's 16-bit address. * * @param devReg The device's register's address. - * @param data Data to write. + * @param data 16 bit Data to write. This value is byteswapped if the byteorder set is different than the + * systems byteorder * @param length - length of data * * @retval sfTkError_t ksfTkErrOk on successful execution * */ - virtual sfTkError_t writeRegister16Region16(uint16_t devReg, const uint16_t *data, size_t length) = 0; + virtual sfTkError_t writeRegister(uint16_t devReg, const uint16_t *data, size_t length) + { + // if the system byte order is the same as the desired order, just send the buffer + if (sftk_system_byteorder() == _byteOrder) + return writeRegister(devReg, (const uint8_t *)data, length * sizeof(uint16_t)); - // Overload version - sfTkError_t writeRegister(uint16_t devReg, const uint16_t *data, size_t length) + // swap data + uint16_t data16[length]; + + for (size_t i = 0; i < length; i++) + data16[i] = sftk_byte_swap(data[i]); + return writeRegister(devReg, (const uint8_t *)data16, length * sizeof(uint16_t)); + } + + //--------------------------------------------------------------------------- + // Read Methods + //--------------------------------------------------------------------------- + + // The method that must be implemented - at a minimum. + /** + * @brief Reads an array of bytes to a register on the target address. Supports any address size + * + * @param devReg The device's register's address - can be any size + * @param regLength The length of the register address + * @param data The data to buffer to read into + * @param numBytes The length of the data buffer + * @param readBytes[out] The number of bytes read + * @return sfTkError_t Returns ksfTkErrOk on success, or ksfTkErrFail code + */ + virtual sfTkError_t readRegister(uint8_t *devReg, size_t regLength, uint8_t *data, size_t numBytes, + size_t &readBytes) = 0; + /**-------------------------------------------------------------------------- + * @brief Read a single byte from the given register + * + * @param devReg The device's register's address. + * @param data Data to read. + * + * @retval sfTkError_t - ksfTkErrOk on successful execution. + * + */ + virtual sfTkError_t readRegister(uint8_t devReg, uint8_t &data) { - return writeRegister16Region16(devReg, data, length); + size_t nRead; + sfTkError_t retVal = readRegister(&devReg, sizeof(devReg), &data, sizeof(data), nRead); + + return (retVal == ksfTkErrOk && nRead == sizeof(uint8_t) ? ksfTkErrOk : retVal); } + /**-------------------------------------------------------------------------- * @brief Read a single byte from the given register * @@ -202,86 +492,264 @@ class sfTkIBus * @retval sfTkError_t - ksfTkErrOk on successful execution. * */ - virtual sfTkError_t readRegisterByte(uint8_t devReg, uint8_t &data) = 0; + sfTkError_t readRegisterUInt8(uint8_t devReg, uint8_t &data) + { + return readRegister(devReg, data); + } - // Overload version - sfTkError_t readRegister(uint8_t devReg, uint8_t &data) + /**-------------------------------------------------------------------------- + * @brief Read a single word (16 bit) from the given register + * + * @param devReg The device's register's address. + * @param data Data to read.-- the data value is byteswapped if needed + * + * @retval sfTkError_t - ksfTkErrOk on successful execution. + */ + virtual sfTkError_t readRegister(uint8_t devReg, uint16_t &data) { - return readRegisterByte(devReg, data); + size_t nRead; + sfTkError_t retVal = readRegister(&devReg, sizeof(devReg), (uint8_t *)&data, sizeof(data), nRead); + + // The data is a uint16 - byte swap the result? + if (retVal == ksfTkErrOk && sftk_system_byteorder() != _byteOrder) + data = sftk_byte_swap(data); + + return (retVal == ksfTkErrOk && nRead == sizeof(uint16_t) ? ksfTkErrOk : retVal); } /**-------------------------------------------------------------------------- * @brief Read a single word (16 bit) from the given register * * @param devReg The device's register's address. - * @param data Data to read. + * @param data Data to read.-- the data value is byteswapped if needed * * @retval sfTkError_t - ksfTkErrOk on successful execution. */ - virtual sfTkError_t readRegisterWord(uint8_t devReg, uint16_t &data) = 0; + sfTkError_t readRegisterUInt16(uint8_t devReg, uint16_t &data) + { + return readRegister(devReg, data); + } - // Overload version - sfTkError_t readRegister(uint8_t devReg, uint16_t &data) + /**-------------------------------------------------------------------------- + * @brief Read a 32 bit value from the given register + * + * @param devReg The device's register's address. + * @param data Data to read. The data value is byteswapped if needed + * + * @retval sfTkError_t - ksfTkErrOk on successful execution. + */ + virtual sfTkError_t readRegister(uint8_t devReg, uint32_t &data) { - return readRegisterWord(devReg, data); + size_t nRead; + sfTkError_t retVal = readRegister(&devReg, sizeof(devReg), (uint8_t *)&data, sizeof(data), nRead); + + // The data is a uint32 - byte swap the result? + if (retVal == ksfTkErrOk && sftk_system_byteorder() != _byteOrder) + data = sftk_byte_swap(data); + + return (retVal == ksfTkErrOk && nRead == sizeof(uint32_t) ? ksfTkErrOk : retVal); } /**-------------------------------------------------------------------------- - * @brief Reads a block of data from the given register. + * @brief Read a 32 bit value from the given register * - * @param reg The device's register's address. - * @param data Data to write. - * @param numBytes - length of data - * @param[out] readBytes - number of bytes read + * @param devReg The device's register's address. + * @param data Data to read. The data value is byteswapped if needed * - * @retval int returns ksfTkErrOk on success, or ksfTkErrFail code + * @retval sfTkError_t - ksfTkErrOk on successful execution. + */ + sfTkError_t readRegisterUInt32(uint8_t devReg, uint32_t &data) + { + return readRegister(devReg, data); + } + + /** + * @brief Reads data from a specified register. + * + * This function reads a specified number of bytes from a given register and stores the data in the provided buffer. * + * @param devReg The register address to read from. + * @param data Pointer to the buffer where the read data will be stored. + * @param numBytes The number of bytes to read from the register. + * @param readBytes Reference to a variable where the number of bytes actually read will be stored. + * @return sfTkError_t Error code indicating the success or failure of the read operation. */ - virtual sfTkError_t readRegisterRegion(uint8_t reg, uint8_t *data, size_t numBytes, size_t &readBytes) = 0; + virtual sfTkError_t readRegister(uint8_t devReg, uint8_t *data, size_t numBytes, size_t &readBytes) + { + return readRegister(&devReg, sizeof(devReg), data, numBytes, readBytes); + } - // Overload version - sfTkError_t readRegister(uint8_t reg, uint8_t *data, size_t numBytes, size_t &readBytes) + /** + * @brief Overloaded function to read a 8-bit value from the given 16-bit register address. + * + * This function reads a 8-bit value from the specified 16-bit register address. + * + * @param reg The device's 16-bit register's address. The address is byteswapped if needed + * @param[out] value The 8-bit value read from the register. + * + * @return sfTkError_t Returns ksfTkErrOk on success, or an error code on failure. + */ + virtual sfTkError_t readRegister(uint16_t reg, uint8_t &value) { - return readRegisterRegion(reg, data, numBytes, readBytes); + size_t readBytes = 0; + + // this is a reg 16 address - so call the method to manage this. Note - it manages the + // byte swapping of the address. + sfTkError_t retValue = readRegister(reg, (uint8_t *)&value, sizeof(value), readBytes); + + return retValue; } - /**-------------------------------------------------------------------------- - * @brief Reads a block of data from the given 16-bit register address. + /** + * @brief Overloaded function to read a 8-bit value from the given 16-bit register address. * - * @param reg The device's 16 bit register's address. - * @param data Data to write. - * @param numBytes - length of data - * @param[out] readBytes - number of bytes read + * This function reads a 8-bit value from the specified 16-bit register address. * - * @retval int returns ksfTkErrOk on success, or ksfTkErrFail code + * @param reg The device's 16-bit register's address. The address is byteswapped if needed + * @param[out] value The 8-bit value read from the register. + * + * @return sfTkError_t Returns ksfTkErrOk on success, or an error code on failure. + */ + sfTkError_t readRegisterUInt8(uint16_t devReg, uint8_t &data) + { + return readRegister(devReg, data); + } + + /** + * @brief Overloaded function to read a 16-bit value from the given 16-bit register address. + * + * This function reads a 16-bit value from the specified 16-bit register address. + * + * @param reg The device's 16-bit register's address. The address is byteswapped if needed. + * @param[out] value The 16-bit value read from the register. The value is byte swapped if needed. + * + * @return sfTkError_t Returns ksfTkErrOk on success, or an error code on failure. + */ + virtual sfTkError_t readRegister(uint16_t reg, uint16_t &value) + { + size_t readBytes = 0; + + // this is a reg 16 address - so call the method to manage this. Note - it manages the + // byte swapping of the address. + sfTkError_t retValue = readRegister(reg, (uint8_t *)&value, sizeof(value), readBytes); + + // The data is a uint16 - byte swap the result? + if (retValue == ksfTkErrOk && sftk_system_byteorder() != _byteOrder) + value = sftk_byte_swap(value); + + return retValue; + } + + /** + * @brief Overloaded function to read a 16-bit value from the given 16-bit register address. + * + * This function reads a 16-bit value from the specified 16-bit register address. + * + * @param reg The device's 16-bit register's address. The address is byteswapped if needed. + * @param[out] value The 16-bit value read from the register. The value is byte swapped if needed. + * + * @return sfTkError_t Returns ksfTkErrOk on success, or an error code on failure. + */ + sfTkError_t readRegisterUInt16(uint16_t devReg, uint16_t &data) + { + return readRegister(devReg, data); + } + + /** + * @brief Overloaded function to read a 32-bit value from the given 16-bit register address. * + * This function reads a 32-bit value from the specified 16-bit register address. + * + * @param reg The device's 16-bit register's address. The address is byteswapped if needed. + * @param[out] value The 32-bit value read from the register. The value is byte swapped if needed. + * + * @return sfTkError_t Returns ksfTkErrOk on success, or an error code on failure. + */ + virtual sfTkError_t readRegister(uint16_t reg, uint32_t &value) + { + size_t readBytes = 0; + + // this is a reg 16 address - so call the method to manage this. Note - it manages the + // byte swapping of the address. + sfTkError_t retValue = readRegister(reg, (uint8_t *)&value, sizeof(uint32_t), readBytes); + + // The data is a uint32 - byte swap the result? + if (retValue == ksfTkErrOk && sftk_system_byteorder() != _byteOrder) + value = sftk_byte_swap(value); + + return retValue; + } + + /** + * @brief Overloaded function to read a 32-bit value from the given 16-bit register address. + * + * This function reads a 32-bit value from the specified 16-bit register address. + * + * @param reg The device's 16-bit register's address. The address is byteswapped if needed. + * @param[out] value The 32-bit value read from the register. The value is byte swapped if needed. + * + * @return sfTkError_t Returns ksfTkErrOk on success, or an error code on failure. */ - virtual sfTkError_t readRegister16Region(uint16_t reg, uint8_t *data, size_t numBytes, size_t &readBytes) = 0; + sfTkError_t readRegisterUInt32(uint16_t devReg, uint32_t &data) + { + return readRegister(devReg, data); + } // Overload version - sfTkError_t readRegister(uint16_t reg, uint8_t *data, size_t numBytes, size_t &readBytes) + /** + * @brief Reads a specified number of bytes from a given register with a 16bit address + * + * This function reads data from a 16-bit register and stores it in the provided buffer. + * + * @param devReg The 16-bit register address to read from. Byteswapped if needed. + * @param data Pointer to the buffer where the read data will be stored. + * @param numBytes The number of bytes to read from the register. + * @param readBytes Reference to a variable where the number of bytes actually read will be stored. + * @return sfTkError_t Error code indicating the success or failure of the read operation. + */ + sfTkError_t readRegister(uint16_t devReg, uint8_t *data, size_t numBytes, size_t &readBytes) { - return readRegister16Region(reg, data, numBytes, readBytes); + // The address is a uint16 - byte swap? + if (sftk_system_byteorder() != _byteOrder) + devReg = sftk_byte_swap(devReg); + + return readRegister((uint8_t *)&devReg, sizeof(devReg), data, numBytes, readBytes); } + /**-------------------------------------------------------------------------- - * @brief Reads a block of data from the given 16-bit register address. + * @brief Reads a 16-bit block of data from the given 16-bit register address. * - * @param reg The device's 16 bit register's address. - * @param data Data to write. - * @param numBytes - length of data - * @param[out] readBytes - number of bytes read + * @param reg The device's 16 bit register's address. Byteswapped if needed + * @param data Data area to read into - byteswapped if needed + * @param length - length of data (16 bit element count) + * @param[out] read16 - number of 16 bit words read * * @retval int returns ksfTkErrOk on success, or ksfTkErrFail code * */ - virtual sfTkError_t readRegister16Region16(uint16_t reg, uint16_t *data, size_t numBytes, size_t &readBytes) = 0; - - // Overload version - sfTkError_t readRegister(uint16_t reg, uint16_t *data, size_t numBytes, size_t &readBytes) + virtual sfTkError_t readRegister(uint16_t reg, uint16_t *data, size_t length, size_t &read16) { - return readRegister16Region16(reg, data, numBytes, readBytes); + sfTkError_t retValue = readRegister(reg, (uint8_t *)data, length * 2, read16); + + // Do we need to flip the byte order? + if (retValue == ksfTkErrOk && sftk_system_byteorder() != _byteOrder) + { + for (size_t i = 0; i < length; i++) + data[i] = sftk_byte_swap(data[i]); + } + read16 = read16 / 2; // convert to words + return retValue; // added return statement to return status } + /** + * @brief Get the type of the object. + * + * This virtual function returns the type of the object as an 8-bit unsigned integer. + * The default implementation returns 0. It is expected that the subclass will define and + * implement a type methodology + * + * @return uint8_t The type of the object. + */ virtual uint8_t type(void) { return 0; @@ -289,8 +757,8 @@ class sfTkIBus /** * @brief Set the byte order for multi-byte data transfers * - * @param order The byte order to set - set to either SFTK_MSBFIRST or SFTK_LSBFIRST. The default is SFTK_LSBFIRST - * + * @param order The byte order to set - set to either sfTkByteOrder::BigEndian or + * sfTkByteOrder::LittleEndian */ void setByteOrder(sfTkByteOrder order) { @@ -308,7 +776,8 @@ class sfTkIBus } protected: - /** flag to manage byte swapping */ + /** + * Flag to manage byte swapping + */ sfTkByteOrder _byteOrder; }; - diff --git a/src/sfTk/sfToolkit.cpp b/src/sfTk/sfToolkit.cpp index 593d46c..2a116ee 100644 --- a/src/sfTk/sfToolkit.cpp +++ b/src/sfTk/sfToolkit.cpp @@ -8,37 +8,12 @@ * @author SparkFun Electronics * @date 2024-2025 * @copyright Copyright (c) 2024-2025, SparkFun Electronics Inc. This project is released under the MIT License. - * + * * SPDX-License-Identifier: MIT */ -// File: sfToolkit.cpp -// -// General impl file for the SparkFun Toolkit -/* - -The MIT License (MIT) - -Copyright (c) 2024 SparkFun Electronics - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: The -above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED -"AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ #include "sfToolkit.h" - #ifdef ARDUINO #include #endif @@ -87,3 +62,23 @@ uint32_t sftk_byte_swap(uint32_t i) return ((i << 24) & 0xff000000) | ((i << 8) & 0x00ff0000) | ((i >> 8) & 0x0000ff00) | ((i >> 24) & 0x000000ff); #endif } + +//--------------------------------------------------------------------------------- +/** + * @brief function - Byte swap an int 16 + */ +int16_t sftk_byte_swap(int16_t i) +{ + uint16_t tmp = sftk_byte_swap(*(uint16_t *)&i); + return *(int16_t *)&tmp; +} + +//--------------------------------------------------------------------------------- +/** + * @brief function - Byte swap an int 32 + */ +int32_t sftk_byte_swap(int32_t i) +{ + uint32_t tmp = sftk_byte_swap(*(uint32_t *)&i); + return *(int32_t *)&tmp; +} \ No newline at end of file diff --git a/src/sfTk/sfToolkit.h b/src/sfTk/sfToolkit.h index 1295601..c8b15ba 100644 --- a/src/sfTk/sfToolkit.h +++ b/src/sfTk/sfToolkit.h @@ -9,11 +9,10 @@ * @author SparkFun Electronics * @date 2024-2025 * @copyright Copyright (c) 2024-2025, SparkFun Electronics Inc. This project is released under the MIT License. - * + * * SPDX-License-Identifier: MIT */ - #pragma once #include @@ -23,7 +22,6 @@ */ #include "sfTkError.h" - // byte order types/enum enum class sfTkByteOrder : uint8_t { @@ -39,13 +37,36 @@ sfTkByteOrder sftk_system_byteorder(void); uint8_t sftk_byte_swap(uint8_t i); uint16_t sftk_byte_swap(uint16_t i); uint32_t sftk_byte_swap(uint32_t i); +int16_t sftk_byte_swap(int16_t i); +int32_t sftk_byte_swap(int32_t i); - -// Area for platform specific implementations. The interface/functions are +// Area for platform specific implementations. The interface/functions are // defined here, with the expectation that the platform provides the implementation. // delay in milliseconds void sftk_delay_ms(uint32_t ms); // ticks in milliseconds -uint32_t sftk_ticks_ms(void); \ No newline at end of file +uint32_t sftk_ticks_ms(void); + +/** + * @brief Check if specific bits are set in a value. + * + * This macro checks if the bits specified by the bitmask are set in the given value. + * + * @param __value__ The value to check. + * @param __bitmask__ The bitmask specifying which bits to check. + * @return True if all bits specified by the bitmask are set, false otherwise. + */ +#define SFTK_CHECK_BITS_SET(__value__, __bitmask__) (((__value__) & (__bitmask__)) == __bitmask__) + +/** + * @brief Check if specific bits are cleared in a value. + * + * This macro checks if the bits specified by the bitmask are cleared in the given value. + * + * @param __value__ The value to check. + * @param __bitmask__ The bitmask specifying which bits to check. + * @return True if all bits specified by the bitmask are cleared, false otherwise. + */ +#define SFTK_CHECK_BITS_CLEARED(__value__, __bitmask__) (((__value__) & (__bitmask__)) == 0) diff --git a/src/sfTkArdI2C.cpp b/src/sfTkArdI2C.cpp index 216db72..422ffa8 100644 --- a/src/sfTkArdI2C.cpp +++ b/src/sfTkArdI2C.cpp @@ -11,14 +11,25 @@ * SPDX-License-Identifier: MIT */ - #include "sfTkArdI2C.h" //--------------------------------------------------------------------------------- -// init() -// -// Arduino version of init - pass in already setup wire port ... -// + +/** + * @brief Initializes the I2C communication for the sfTkArdI2C object. + * + * This function sets up the I2C communication by assigning the provided TwoWire + * object to the internal _i2cPort pointer. If the I2C port is not already set, + * it will use the provided wirePort and optionally initialize it by calling + * its begin() method. It also sets the I2C address for communication. + * + * @param wirePort Reference to a TwoWire object representing the I2C port. + * @param addr The I2C address to be used for communication. + * @param bInit Boolean flag indicating whether to initialize the I2C port by + * calling its begin() method. If true, begin() will be called. + * + * @return sfTkError_t Returns ksfTkErrOk on successful initialization. + */ sfTkError_t sfTkArdI2C::init(TwoWire &wirePort, uint8_t addr, bool bInit) { // if we don't have a wire port already @@ -36,10 +47,17 @@ sfTkError_t sfTkArdI2C::init(TwoWire &wirePort, uint8_t addr, bool bInit) } //--------------------------------------------------------------------------------- -// init() -// -// no parameters version of init. Setups a a wire port if needed. -// +/** + * @brief Initializes the I2C communication with the specified address. + * + * This function initializes the I2C communication for the device. If no I2C port + * is specified, it defaults to using the Wire library. If an I2C port is already + * specified, it assumes the initialization is already done. + * + * @param addr The I2C address of the device. + * @return sfTkError_t Returns ksfTkErrOk if the initialization is successful, + * otherwise returns an error code. + */ sfTkError_t sfTkArdI2C::init(uint8_t addr) { // no port yet, do the default version of it @@ -51,20 +69,33 @@ sfTkError_t sfTkArdI2C::init(uint8_t addr) } //--------------------------------------------------------------------------------- -// init() -// -// no parameters version of init. Setups a a wire port if needed. -// + +/** + * @brief Initializes the I2C communication with the currently set address. + * + * This function initializes the I2C communication by calling the init function + * with the address that is currently set for the I2C device. + * + * @return sfTkError_t Returns an error code indicating the success or failure of the initialization. + */ sfTkError_t sfTkArdI2C::init(void) { // call with our currently set address ... return init(address()); } //--------------------------------------------------------------------------------- -// ping() -// -// Ping an I2C address to see if something is there. -// +/** + * @brief Pings the I2C device to check if it is responsive. + * + * This function attempts to initiate a transmission to the I2C device + * and checks if the device acknowledges the transmission. It can be + * used to verify that the device is properly connected and responsive. + * + * @return sfTkError_t + * - ksfTkErrOk: if the device acknowledges the transmission. + * - ksfTkErrFail: if the device does not acknowledge the transmission. + * - ksfTkErrBusNotInit: if the I2C bus is not initialized. + */ sfTkError_t sfTkArdI2C::ping() { // no port, no @@ -75,85 +106,6 @@ sfTkError_t sfTkArdI2C::ping() return _i2cPort->endTransmission() == 0 ? ksfTkErrOk : ksfTkErrFail; } -//--------------------------------------------------------------------------------- -// writeByte() -// -// Writes a single byte to the device, without indexing to a register. -// -// Returns true on success, false on failure -// -sfTkError_t sfTkArdI2C::writeByte(uint8_t dataToWrite) -{ - if (!_i2cPort) - return ksfTkErrBusNotInit; - - // do the Arduino I2C work - _i2cPort->beginTransmission(address()); - _i2cPort->write(dataToWrite); - return _i2cPort->endTransmission() == 0 ? ksfTkErrOk : ksfTkErrFail; -} - -//--------------------------------------------------------------------------------- -// writeWord() -// -// Writes a word to the device, without indexing to a register. -// -// Returns true on success, false on failure -// -sfTkError_t sfTkArdI2C::writeWord(uint16_t dataToWrite) -{ - if (!_i2cPort) - return ksfTkErrBusNotInit; - - return writeRegion((uint8_t *)&dataToWrite, sizeof(uint16_t)); -} - -//--------------------------------------------------------------------------------- -// writeRegion() -// -// Writes a word to the device, without indexing to a register. -// -// Returns true on success, false on failure -// -sfTkError_t sfTkArdI2C::writeRegion(const uint8_t *data, size_t length) -{ - return writeRegisterRegionAddress(nullptr, 0, data, length) == 0 ? ksfTkErrOk : ksfTkErrFail; -} - -//--------------------------------------------------------------------------------- -// writeRegisterByte() -// -// Writes a byte to a given register. -// -// Returns true on success, false on failure -// -sfTkError_t sfTkArdI2C::writeRegisterByte(uint8_t devReg, uint8_t dataToWrite) -{ - if (!_i2cPort) - return ksfTkErrBusNotInit; - - // do the Arduino I2C work - _i2cPort->beginTransmission(address()); - _i2cPort->write(devReg); - _i2cPort->write(dataToWrite); - return _i2cPort->endTransmission() == 0 ? ksfTkErrOk : ksfTkErrFail; -} - -//--------------------------------------------------------------------------------- -// writeRegisterWord() -// -// Writes a word to a given register. -// -// Returns true on success, false on failure -// -sfTkError_t sfTkArdI2C::writeRegisterWord(uint8_t devReg, uint16_t dataToWrite) -{ - if (!_i2cPort) - return ksfTkErrBusNotInit; - - return writeRegisterRegion(devReg, (uint8_t *)&dataToWrite, sizeof(uint16_t)); -} - /** * @brief Writes an array of bytes to a register on the target address. Supports any address size * @@ -163,8 +115,7 @@ sfTkError_t sfTkArdI2C::writeRegisterWord(uint8_t devReg, uint16_t dataToWrite) * @param length The length of the data buffer * @return sfTkError_t Returns ksfTkErrOk on success, or ksfTkErrFail code */ -sfTkError_t sfTkArdI2C::writeRegisterRegionAddress(uint8_t *devReg, size_t regLength, const uint8_t *data, - size_t length) +sfTkError_t sfTkArdI2C::writeRegister(uint8_t *devReg, size_t regLength, const uint8_t *data, size_t length) { if (!_i2cPort) return ksfTkErrBusNotInit; @@ -179,56 +130,6 @@ sfTkError_t sfTkArdI2C::writeRegisterRegionAddress(uint8_t *devReg, size_t regLe return _i2cPort->endTransmission() ? ksfTkErrFail : ksfTkErrOk; } -//--------------------------------------------------------------------------------- -// writeRegisterRegion() -// -// Writes an array of bytes to a given register on the target address -// -// Returns the number of bytes written, < 0 is an error -// -sfTkError_t sfTkArdI2C::writeRegisterRegion(uint8_t devReg, const uint8_t *data, size_t length) -{ - return writeRegisterRegionAddress(&devReg, 1, data, length); -} - -//--------------------------------------------------------------------------------- -// write16BitRegisterRegion() -// -// Writes an array of bytes to a given 16-bit register on the target address -// -// Returns the number of bytes written, < 0 is an error -// -sfTkError_t sfTkArdI2C::writeRegister16Region(uint16_t devReg, const uint8_t *data, size_t length) -{ - // Byteorder check - if (sftk_system_byteorder() != _byteOrder) - devReg = sftk_byte_swap(devReg); - return writeRegisterRegionAddress((uint8_t *)&devReg, 2, data, length); -} - -//--------------------------------------------------------------------------------- -// write16BitRegisterRegion16() -// -// Writes an array of bytes to a given 16-bit register on the target address -// -// Returns the number of bytes written, < 0 is an error -// -sfTkError_t sfTkArdI2C::writeRegister16Region16(uint16_t devReg, const uint16_t *data, size_t length) -{ - // if the system byte order is the same as the desired order, just send the buffer - if (sftk_system_byteorder() == _byteOrder) - return writeRegisterRegionAddress((uint8_t *)&devReg, 2, (uint8_t *)data, length * 2); - - // okay, we need to swap - devReg = sftk_byte_swap(devReg); - - uint16_t data16[length]; - for (size_t i = 0; i < length; i++) - data16[i] = sftk_byte_swap(data[i]); - - return writeRegisterRegionAddress((uint8_t *)&devReg, 2, (uint8_t *)data16, length * 2); -} - /** * @brief Reads an array of bytes to a register on the target address. Supports any address size * @@ -239,10 +140,9 @@ sfTkError_t sfTkArdI2C::writeRegister16Region16(uint16_t devReg, const uint16_t * @param readBytes[out] The number of bytes read * @return sfTkError_t Returns ksfTkErrOk on success, or ksfTkErrFail code */ -sfTkError_t sfTkArdI2C::readRegisterRegionAnyAddress(uint8_t *devReg, size_t regLength, uint8_t *data, size_t numBytes, - size_t &readBytes) +sfTkError_t sfTkArdI2C::readRegister(uint8_t *devReg, size_t regLength, uint8_t *data, size_t numBytes, + size_t &readBytes) { - // got port if (!_i2cPort) return ksfTkErrBusNotInit; @@ -296,107 +196,3 @@ sfTkError_t sfTkArdI2C::readRegisterRegionAnyAddress(uint8_t *devReg, size_t reg return (readBytes == nOrig) ? ksfTkErrOk : ksfTkErrBusUnderRead; // Success } - -//--------------------------------------------------------------------------------- -// readRegisterByte() -// -// Reads a byte to a given register. -// -// Returns true on success, false on failure -// -sfTkError_t sfTkArdI2C::readRegisterByte(uint8_t devReg, uint8_t &dataToRead) -{ - if (!_i2cPort) - return ksfTkErrBusNotInit; - - // Return value - uint8_t result = 0; - - int nData = 0; - - _i2cPort->beginTransmission(address()); - _i2cPort->write(devReg); - _i2cPort->endTransmission(stop()); - _i2cPort->requestFrom(address(), (uint8_t)1); - - while (_i2cPort->available()) // slave may send less than requested - { - result = _i2cPort->read(); // receive a byte as a proper uint8_t - nData++; - } - - if (nData == sizeof(uint8_t)) // Only update outputPointer if a single byte was returned - dataToRead = result; - - return (nData == sizeof(uint8_t) ? ksfTkErrOk : ksfTkErrFail); -} - -//--------------------------------------------------------------------------------- -// readRegisterWord() -// -// Reads a word to a given register. -// -// Returns true on success, false on failure -// -sfTkError_t sfTkArdI2C::readRegisterWord(uint8_t devReg, uint16_t &dataToRead) -{ - if (!_i2cPort) - return ksfTkErrBusNotInit; - - size_t nRead; - sfTkError_t retval = readRegisterRegion(devReg, (uint8_t *)&dataToRead, sizeof(uint16_t), nRead); - - return (retval == ksfTkErrOk && nRead == sizeof(uint16_t) ? ksfTkErrOk : retval); -} - -//--------------------------------------------------------------------------------- -// readRegisterRegion() -// -// Reads an array of bytes to a given register on the target address -// -// Returns the number of bytes read, < 0 is an error -// -sfTkError_t sfTkArdI2C::readRegisterRegion(uint8_t devReg, uint8_t *data, size_t numBytes, size_t &readBytes) -{ - return readRegisterRegionAnyAddress(&devReg, 1, data, numBytes, readBytes); -} - -//--------------------------------------------------------------------------------- -// read16BitRegisterRegion() -// -// Reads an array of bytes to a given 16-bit register on the target address -// -// Returns the number of bytes read, < 0 is an error -// -sfTkError_t sfTkArdI2C::readRegister16Region(uint16_t devReg, uint8_t *data, size_t numBytes, size_t &readBytes) -{ - // if the system byte order is the same as the desired order, flip the address - if (sftk_system_byteorder() != _byteOrder) - devReg = sftk_byte_swap(devReg); - - return readRegisterRegionAnyAddress((uint8_t *)&devReg, 2, data, numBytes, readBytes); -} -//--------------------------------------------------------------------------------- -// read16BitRegisterRegion16() -// -// Reads an array of bytes to a given 16-bit register on the target address -// -// Returns the number of bytes read, < 0 is an error -// -sfTkError_t sfTkArdI2C::readRegister16Region16(uint16_t devReg, uint16_t *data, size_t numBytes, size_t &readWords) -{ - // if the system byte order is the same as the desired order, flip the address - if (sftk_system_byteorder() != _byteOrder) - devReg = sftk_byte_swap(devReg); - - sfTkError_t status = readRegisterRegionAnyAddress((uint8_t *)&devReg, 2, (uint8_t *)data, numBytes * 2, readWords); - - // Do we need to flip the byte order? - if (status == ksfTkErrOk && sftk_system_byteorder() != _byteOrder) - { - for (size_t i = 0; i < numBytes; i++) - data[i] = sftk_byte_swap(data[i]); - } - readWords = readWords / 2; // convert to words - return status; -} \ No newline at end of file diff --git a/src/sfTkArdI2C.h b/src/sfTkArdI2C.h index 9eb0e6b..e24a494 100644 --- a/src/sfTkArdI2C.h +++ b/src/sfTkArdI2C.h @@ -97,162 +97,27 @@ class sfTkArdI2C : public sfTkII2C sfTkError_t ping(); /** - @brief Sends a single byte to the device - @note sfTkIBus interface method - - @param data Data to write. - - @retval returns ksfTkErrOk on success - */ - sfTkError_t writeByte(uint8_t data); - - /** - @brief Sends a word to the device. - @note sfTkIBus interface method - - @param data Data to write. - - @retval returns ksfTkErrOk on success - */ - sfTkError_t writeWord(uint16_t data); - - /** - @brief Sends a block of data to the device. - @note sfTkIBus interface method - - @param data Data to write. - @param length - length of data - - @retval returns ksfTkErrOk on success - */ - sfTkError_t writeRegion(const uint8_t *data, size_t length); - - /** - @brief Write a single byte to the given register - @note sfTkIBus interface method - - @param devReg The device's register's address. - @param data Data to write. - - @retval returns ksfTkErrOk on success - */ - sfTkError_t writeRegisterByte(uint8_t devReg, uint8_t data); - - /** - @brief Write a single word to the given register - @note sfTkIBus interface method - - @param devReg The device's register's address. - @param data Data to write. - - @retval returns ksfTkErrOk on success - */ - sfTkError_t writeRegisterWord(uint8_t devReg, uint16_t data); - - /** - @brief Writes a number of bytes starting at the given register's address. - - @note sfTkIBus interface method - @note This method is virtual to allow it to be overridden to support a device that requires a unique impl - - @param devReg The device's register's address. - @param data Data to write. - @param length - length of data - - @retval ksfTkErrOk on success - */ - sfTkError_t writeRegisterRegion(uint8_t devReg, const uint8_t *data, size_t length); - - /** - @brief Writes a number of bytes starting at the given register's 16-bit address. - - @param devReg The device's register's address - 16 bit. - @param data Data to write. - @param length - length of data - - @retval sfTkError_t ksfTkErrOk on successful execution - - */ - sfTkError_t writeRegister16Region(uint16_t devReg, const uint8_t *data, size_t length); - - /** - @brief Writes a number of bytes starting at the given register's 16-bit address. - - @param devReg The device's register's address - 16 bit. - @param data Data to write. - @param length - length of data - - @retval sfTkError_t ksfTkErrOk on successful execution - - */ - sfTkError_t writeRegister16Region16(uint16_t devReg, const uint16_t *data, size_t length); - - /** - @brief Reads a byte of data from the given register. - - @note sfTkIBus interface method - - @param devReg The device's register's address. - @param[out] data Data to read. - - @retval ksfTkErrOk on success - */ - sfTkError_t readRegisterByte(uint8_t devReg, uint8_t &data); - - /** - @brief Reads a word of data from the given register. - - @note sfTkIBus interface method - - @param devReg The device's register's address. - @param[out] data Data to read. - - @retval ksfTkErrOk on success - */ - sfTkError_t readRegisterWord(uint8_t devReg, uint16_t &data); - - /** - @brief Reads a block of data from the given register. - - @note sfTkIBus interface method - @note This method is virtual to allow it to be overridden to support a device that requires a unique impl - - @param devReg The device's register's address. - @param[out] data Data buffer to read into - @param numBytes Number of bytes to read/length of data buffer - @param[out] readBytes - Number of bytes read - - - @retval ksfTkErrOk on success - */ - sfTkError_t readRegisterRegion(uint8_t devReg, uint8_t *data, size_t numBytes, size_t &readBytes); - - /** - @brief Reads a block of data from the given 16-bit register address. - - @param reg The device's 16 bit register's address. - @param data Data buffer to read into - @param numBytes - Number of bytes to read/length of data buffer - @param[out] readBytes - number of bytes read - - @retval int returns ksfTkErrOk on success, or ksfTkErrFail code - - */ - sfTkError_t readRegister16Region(uint16_t reg, uint8_t *data, size_t numBytes, size_t &readBytes); + * @brief Writes data to a specified register on an I2C device. + * + * @param devReg Pointer to the register address on the I2C device. + * @param regLength Length of the register address in bytes. + * @param data Pointer to the data to be written to the register. + * @param length Length of the data to be written in bytes. + * @return sfTkError_t Error code indicating the success or failure of the operation. + */ + sfTkError_t writeRegister(uint8_t *devReg, size_t regLength, const uint8_t *data, size_t length); /** - @brief Reads a block of data from the given 16-bit register address. - - @param reg The device's 16 bit register's address. - @param data Data buffer to read into - @param numBytes - Number of bytes to read/length of data buffer - @param[out] readBytes - number of bytes read - - @retval int returns ksfTkErrOk on success, or ksfTkErrFail code - - */ - sfTkError_t readRegister16Region16(uint16_t reg, uint16_t *data, size_t numBytes, size_t &readBytes); - + * @brief Reads data from a specified register of an I2C device. + * + * @param devReg Pointer to the register address to read from. + * @param regLength Length of the register address. + * @param data Pointer to the buffer where the read data will be stored. + * @param numBytes Number of bytes to read from the register. + * @param readBytes Reference to a variable where the number of bytes actually read will be stored. + * @return sfTkError_t Error code indicating the success or failure of the read operation. + */ + sfTkError_t readRegister(uint8_t *devReg, size_t regLength, uint8_t *data, size_t numBytes, size_t &readBytes); // Buffer size chunk getter/setter /** @brief set the buffer chunk size @@ -279,7 +144,9 @@ class sfTkArdI2C : public sfTkII2C return _bufferChunkSize; } - + // For overloaded virtual methods, make sure our subclass methods appear on this object + using sfTkIBus::readRegister; + using sfTkIBus::writeRegister; protected: // note: The wire port is protected, allowing access if a sub-class is @@ -289,15 +156,9 @@ class sfTkArdI2C : public sfTkII2C TwoWire *_i2cPort; private: - sfTkError_t writeRegisterRegionAddress(uint8_t *devReg, size_t regLength, const uint8_t *data, size_t length); - - sfTkError_t readRegisterRegionAnyAddress(uint8_t *devReg, size_t regLength, uint8_t *data, size_t numBytes, - size_t &readBytes); - /** Default buffer chunk size*/ static constexpr size_t kDefaultBufferChunk = 32; /** The I2C buffer chunker - chunk size*/ size_t _bufferChunkSize; - }; diff --git a/src/sfTkArdSPI.cpp b/src/sfTkArdSPI.cpp index a630d8c..0434df8 100644 --- a/src/sfTkArdSPI.cpp +++ b/src/sfTkArdSPI.cpp @@ -70,118 +70,13 @@ sfTkError_t sfTkArdSPI::init(bool bInit) } //--------------------------------------------------------------------------------- -// writeByte() -// -// Writes a single byte to the device. -// -// Returns ksfTkErrOk on success -// -sfTkError_t sfTkArdSPI::writeByte(uint8_t dataToWrite) -{ - - if (!_spiPort) - return ksfTkErrBusNotInit; - - // Apply settings - _spiPort->beginTransaction(_sfeSPISettings); - // Signal communication start - digitalWrite(cs(), LOW); - - _spiPort->transfer(dataToWrite); - - // End communication - digitalWrite(cs(), HIGH); - _spiPort->endTransaction(); - - return ksfTkErrOk; -} - -//--------------------------------------------------------------------------------- -// writeWord() -// -// Writes a word to the device without indexing to a register. -// -// Returns ksfTkErrOk on success -// -sfTkError_t sfTkArdSPI::writeWord(uint16_t dataToWrite) -{ - return writeRegion((uint8_t *)&dataToWrite, sizeof(uint8_t)) > 0; -} - -//--------------------------------------------------------------------------------- -// writeRegion() -// -// Writes an array of data to the device without indexing to a register. -// -// Returns ksfTkErrOk on success -// -sfTkError_t sfTkArdSPI::writeRegion(const uint8_t *dataToWrite, size_t length) -{ - - if (!_spiPort) - return ksfTkErrBusNotInit; - - _spiPort->beginTransaction(_sfeSPISettings); - // Signal communication start - digitalWrite(cs(), LOW); - - for (size_t i = 0; i < length; i++) - _spiPort->transfer(*dataToWrite++); - - // End communication - digitalWrite(cs(), HIGH); - _spiPort->endTransaction(); - - return ksfTkErrOk; -} - -//--------------------------------------------------------------------------------- -// writeRegisterByte() -// -// Writes a byte to a given register. -// -// Returns ksfTkErrOk on success -// -sfTkError_t sfTkArdSPI::writeRegisterByte(uint8_t devReg, uint8_t dataToWrite) -{ - - if (!_spiPort) - return ksfTkErrBusNotInit; - - // Apply settings - _spiPort->beginTransaction(_sfeSPISettings); - // Signal communication start - digitalWrite(cs(), LOW); - - _spiPort->transfer(devReg); - _spiPort->transfer(dataToWrite); - - // End communication - digitalWrite(cs(), HIGH); - _spiPort->endTransaction(); - - return ksfTkErrOk; -} - -//--------------------------------------------------------------------------------- -// writeRegisterWord() -// -// Writes a world to a given register. -// -// Returns ksfTkErrOk on success -// -sfTkError_t sfTkArdSPI::writeRegisterWord(uint8_t devReg, uint16_t dataToWrite) -{ - return writeRegisterRegion(devReg, (uint8_t *)&dataToWrite, sizeof(uint8_t)) > 0; -} -//--------------------------------------------------------------------------------- -// writeRegisterRegion() +// writeRegister() // // Writes an array of bytes to a given register on the target address // // Returns ksfTkErrOk on success // -sfTkError_t sfTkArdSPI::writeRegisterRegion(uint8_t devReg, const uint8_t *data, size_t length) +sfTkError_t sfTkArdSPI::writeRegister(uint8_t *devReg, size_t regLength, const uint8_t *data, size_t length) { if (!_spiPort) return ksfTkErrBusNotInit; @@ -192,8 +87,14 @@ sfTkError_t sfTkArdSPI::writeRegisterRegion(uint8_t devReg, const uint8_t *data, // Signal communication start digitalWrite(cs(), LOW); - _spiPort->transfer(devReg); + // send over the address + if (devReg != nullptr && regLength > 0) + { + for (size_t i = 0; i < regLength; i++) + _spiPort->transfer(devReg[i]); + } + // now the data for (size_t i = 0; i < length; i++) _spiPort->transfer(*data++); @@ -204,8 +105,10 @@ sfTkError_t sfTkArdSPI::writeRegisterRegion(uint8_t devReg, const uint8_t *data, return ksfTkErrOk; } +//--------------------------------------------------------------------------------- // 16 bit address version ... -sfTkError_t sfTkArdSPI::writeRegister16Region(uint16_t devReg, const uint8_t *data, size_t length) +// override the interface version of this method -- to make use of the vast 16 bit xfer with arduino SPI +sfTkError_t sfTkArdSPI::writeRegister(uint16_t devReg, const uint8_t *data, size_t length) { if (!_spiPort) return ksfTkErrBusNotInit; @@ -229,7 +132,8 @@ sfTkError_t sfTkArdSPI::writeRegister16Region(uint16_t devReg, const uint8_t *da //--------------------------------------------------------------------------------- // 16 bit address and data version ... -sfTkError_t sfTkArdSPI::writeRegister16Region16(uint16_t devReg, const uint16_t *data, size_t length) +// override the interface version of this method -- to make use of the vast 16 bit xfer with arduino SPI +sfTkError_t sfTkArdSPI::writeRegister(uint16_t devReg, const uint16_t *data, size_t length) { if (!_spiPort) return ksfTkErrBusNotInit; @@ -250,23 +154,7 @@ sfTkError_t sfTkArdSPI::writeRegister16Region16(uint16_t devReg, const uint16_t return ksfTkErrOk; } -//--------------------------------------------------------------------------------- -sfTkError_t sfTkArdSPI::readRegisterByte(uint8_t devReg, uint8_t &data) -{ - size_t nRead; - sfTkError_t retval = readRegisterRegion(devReg, (uint8_t *)&data, sizeof(uint8_t), nRead); - return (retval == ksfTkErrOk && nRead == sizeof(uint8_t) ? ksfTkErrOk : retval); -} - -//--------------------------------------------------------------------------------- -sfTkError_t sfTkArdSPI::readRegisterWord(uint8_t devReg, uint16_t &data) -{ - size_t nRead; - sfTkError_t retval = readRegisterRegion(devReg, (uint8_t *)&data, sizeof(uint16_t), nRead); - - return (retval == ksfTkErrOk && nRead == sizeof(uint16_t) ? ksfTkErrOk : retval); -} //--------------------------------------------------------------------------------- // readRegisterRegion() // @@ -274,20 +162,36 @@ sfTkError_t sfTkArdSPI::readRegisterWord(uint8_t devReg, uint16_t &data) // // Returns ksfTkErrOk on success // -sfTkError_t sfTkArdSPI::readRegisterRegion(uint8_t devReg, uint8_t *data, size_t numBytes, size_t &readBytes) +sfTkError_t sfTkArdSPI::readRegister(uint8_t *devReg, size_t regLength, uint8_t *data, size_t numBytes, + size_t &readBytes) { + if (!_spiPort) return ksfTkErrBusNotInit; + if (devReg == nullptr || regLength == 0) + return ksfTkErrInvalidParam; + // Apply settings _spiPort->beginTransaction(_sfeSPISettings); // Signal communication start digitalWrite(cs(), LOW); - // A leading "1" must be added to transfer with devRegister to indicate a "read" - _spiPort->transfer(devReg | kSPIReadBit); + // we really just 1 or two byte addresses + if (regLength == 1) // 1 byte - A leading "1" must be added to transfer with devRegister to indicate a "read" + _spiPort->transfer(*devReg | kSPIReadBit); + else if (regLength == 2) + _spiPort->transfer16(*(uint16_t *)devReg); + else + { + // End transaction + digitalWrite(cs(), HIGH); + _spiPort->endTransaction(); + return ksfTkErrInvalidParam; + } + // data now! for (size_t i = 0; i < numBytes; i++) *data++ = _spiPort->transfer(0x00); @@ -307,30 +211,12 @@ sfTkError_t sfTkArdSPI::readRegisterRegion(uint8_t devReg, uint8_t *data, size_t // // Returns ksfTkErrOk on success // -sfTkError_t sfTkArdSPI::readRegister16Region(uint16_t devReg, uint8_t *data, size_t numBytes, size_t &readBytes) +sfTkError_t sfTkArdSPI::readRegister(uint16_t devReg, uint8_t *data, size_t numBytes, size_t &readBytes) { if (!_spiPort) return ksfTkErrBusNotInit; - // Apply settings - _spiPort->beginTransaction(_sfeSPISettings); - - // Signal communication start - digitalWrite(cs(), LOW); - - // A leading "1" must be added to transfer with devRegister to indicate a "read" - _spiPort->transfer16(devReg | kSPIReadBit); - - for (size_t i = 0; i < numBytes; i++) - *data++ = _spiPort->transfer(0x00); - - // End transaction - digitalWrite(cs(), HIGH); - _spiPort->endTransaction(); - - readBytes = numBytes; - - return ksfTkErrOk; + return readRegister((uint8_t *)&devReg, sizeof(uint16_t), data, numBytes, readBytes); } //--------------------------------------------------------------------------------- @@ -340,7 +226,7 @@ sfTkError_t sfTkArdSPI::readRegister16Region(uint16_t devReg, uint8_t *data, siz // // Returns ksfTkErrOk on success // -sfTkError_t sfTkArdSPI::readRegister16Region16(uint16_t devReg, uint16_t *data, size_t numBytes, size_t &readWords) +sfTkError_t sfTkArdSPI::readRegister(uint16_t devReg, uint16_t *data, size_t numBytes, size_t &readWords) { if (!_spiPort) return ksfTkErrBusNotInit; diff --git a/src/sfTkArdSPI.h b/src/sfTkArdSPI.h index 95f44d3..1998adc 100644 --- a/src/sfTkArdSPI.h +++ b/src/sfTkArdSPI.h @@ -93,24 +93,6 @@ class sfTkArdSPI : public sfTkISPI */ sfTkError_t init(SPIClass &spiPort, SPISettings &busSPISettings, uint8_t csPin, bool bInit = false); - /** - @brief Write a single byte to the device - - @param data Data to write. - - @retval sfTkError_t - ksfTkErrOk on success - */ - sfTkError_t writeByte(uint8_t data); - - /** - @brief Write a word to the device without indexing to a register. - - @param data Data to write. - - @retval sfTkError_t - ksfTkErrOk on success - */ - sfTkError_t writeWord(uint16_t data); - /** @brief Write an array of data to the device without indexing to a register. @@ -121,37 +103,18 @@ class sfTkArdSPI : public sfTkISPI */ sfTkError_t writeRegion(const uint8_t *data, size_t length); - /** - @brief Write a single byte to the given register - - @param devReg The device's register's address. - @param data Data to write. - - @retval sfTkError_t - ksfTkErrOk on success - */ - sfTkError_t writeRegisterByte(uint8_t devReg, uint8_t data); - - /** - @brief Write a single word to the given register - - @param devReg The device's register's address. - @param data Data to write. - - @retval sfTkError_t - ksfTkErrOk on success - */ - sfTkError_t writeRegisterWord(uint8_t devReg, uint16_t data); - /** @brief Writes a number of bytes starting at the given register's address. @note This method is virtual to allow it to be overridden to support a device that requires a unique impl @param devReg The device's register's address. + @param regLength Size of the address - value of 1 or 2 are only accepted @param data Data to write. @param length - length of data @retval sfTkError_t - ksfTkErrOk on success */ - sfTkError_t writeRegisterRegion(uint8_t devReg, const uint8_t *data, size_t length); + sfTkError_t writeRegister(uint8_t *devReg, size_t regLength, const uint8_t *data, size_t length); /** @brief Writes a number of bytes starting at the given register's address. @@ -163,7 +126,7 @@ class sfTkArdSPI : public sfTkISPI @retval sfTkError_t - ksfTkErrOk on success */ - sfTkError_t writeRegister16Region(uint16_t devReg, const uint8_t *data, size_t length); + sfTkError_t writeRegister(uint16_t devReg, const uint8_t *data, size_t length); /** @brief Writes a number of uint16s starting at the given register's address. @@ -175,40 +138,19 @@ class sfTkArdSPI : public sfTkISPI @retval sfTkError_t - ksfTkErrOk on success */ - sfTkError_t writeRegister16Region16(uint16_t devReg, const uint16_t *data, size_t length); - - /** - @brief Read a single byte from the given register - - @param devReg The device's register's address. - @param[out] data Data to read. - - @retval sfTkError_t - ksfTkErrOk on success - */ - sfTkError_t readRegisterByte(uint8_t devReg, uint8_t &data); - - /** - @brief read a single word to the given register - - @param devReg The device's register's address. - @param[out] data Data to write. - - @retval sfTkError_t - true on success - */ - sfTkError_t readRegisterWord(uint8_t devReg, uint16_t &data); + sfTkError_t writeRegister(uint16_t devReg, const uint16_t *data, size_t length); /** - @brief Reads a block of data from the given register. - @note This method is virtual to allow it to be overridden to support a device that requires a unique impl - - @param reg The device's register's address. - @param[out] data Data buffer to read into - @param numBytes - length of data/size of data buffer - @param[out] readBytes - Number of bytes read - - @retval sfTkError_t - true on success - */ - virtual sfTkError_t readRegisterRegion(uint8_t reg, uint8_t *data, size_t numBytes, size_t &readBytes); + * @brief Reads data from a specified register of an I2C device. + * + * @param devReg Pointer to the register address to read from. + * @param regLength Length of the register address. + * @param data Pointer to the buffer where the read data will be stored. + * @param numBytes Number of bytes to read from the register. + * @param readBytes Reference to a variable where the number of bytes actually read will be stored. + * @return sfTkError_t Error code indicating the success or failure of the read operation. + */ + sfTkError_t readRegister(uint8_t *devReg, size_t regLength, uint8_t *data, size_t numBytes, size_t &readBytes); /** @brief Reads a block of data from the given register. @@ -221,7 +163,7 @@ class sfTkArdSPI : public sfTkISPI @retval sfTkError_t - true on success */ - virtual sfTkError_t readRegister16Region(uint16_t reg, uint8_t *data, size_t numBytes, size_t &readBytes); + virtual sfTkError_t readRegister(uint16_t reg, uint8_t *data, size_t numBytes, size_t &readBytes); /** @brief Reads a block of data from the given register. @@ -229,12 +171,16 @@ class sfTkArdSPI : public sfTkISPI @param reg The device's register's 16 bit address. @param[out] data Data buffer to read into - @param numBytes - Length of data to read/size of data buffer - @param[out] readBytes - Number of bytes read + @param length - Length of data to read/size of data buffer + @param[out] readWords - Number of words read @retval sfTkError_t - true on success */ - virtual sfTkError_t readRegister16Region16(uint16_t reg, uint16_t *data, size_t numBytes, size_t &readBytes); + virtual sfTkError_t readRegister(uint16_t reg, uint16_t *data, size_t length, size_t &readWords); + + // For overloaded virtual methods, make sure to elevate our subclass methods. + using sfTkIBus::readRegister; + using sfTkIBus::writeRegister; protected: // note: The instance data is protected, allowing access if a sub-class is @@ -243,6 +189,6 @@ class sfTkArdSPI : public sfTkISPI /** Pointer to the spi port being used */ SPIClass *_spiPort; - /** This objects spi settings are used for every transaction. */ + /** This object's spi settings are used for every transaction. */ SPISettings _sfeSPISettings; }; diff --git a/tests/test_bus01/test_bus01.ino b/tests/test_bus01/test_bus01.ino index 217ad37..a25dec6 100644 --- a/tests/test_bus01/test_bus01.ino +++ b/tests/test_bus01/test_bus01.ino @@ -4,8 +4,8 @@ #include "SparkFun_Toolkit.h" -sfeTkArdI2C myI2C; -sfeTkArdSPI mySPI; +sfTkArdI2C myI2C; +sfTkArdSPI mySPI; void setup() { @@ -13,4 +13,5 @@ void setup() void loop() { + sftk_delay_ms(1000); }