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/README.md b/README.md index 147b794..f9bbb5a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ +![SparkFun ToolKit](docs/images/gh-banner-2025-banner-toolkit.png "SparkFun Toolkit") # SparkFun Toolkit Arduino Library ![Toolkit Tests Builds](https://github.com/sparkfun/SparkFun_Toolkit/actions/workflows/compile-sketch.yml/badge.svg) @@ -6,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 @@ -29,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/images/gh-banner-2025-banner-toolkit.png b/docs/images/gh-banner-2025-banner-toolkit.png new file mode 100644 index 0000000..d0a144f Binary files /dev/null and b/docs/images/gh-banner-2025-banner-toolkit.png differ 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/SparkFun_Toolkit.h b/src/SparkFun_Toolkit.h index ffe3da6..b2c293b 100644 --- a/src/SparkFun_Toolkit.h +++ b/src/SparkFun_Toolkit.h @@ -1,27 +1,15 @@ - -/* -SparkFun_Toolkit.h - -The MIT License (MIT) - -Copyright (c) 2023 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. - -*/ +/** + * @file SparkFun_Toolkit.h + * @brief Arduino style header file for the SparkFun Toolkit + * + * This file contains the Arduino style header for the SparkFun Toolkit library + * + * @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 @@ -31,7 +19,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // Arduino Libraries. // Just include the toolkit headers - -#include -#include "sfeTkArdI2C.h" -#include "sfeTkArdSPI.h" \ No newline at end of file +#include "sfTkArdI2C.h" +#include "sfTkArdSPI.h" +#include "sfTkArduino.h" diff --git a/src/sfTk/sfTkError.h b/src/sfTk/sfTkError.h new file mode 100644 index 0000000..bb505bb --- /dev/null +++ b/src/sfTk/sfTkError.h @@ -0,0 +1,56 @@ +/** + * @file sfTkError.h + * @brief Header file for the SparkFun Toolkit - Base Error Code defines. + * + * This file contains the base error code definitions for the SparkFun Toolkit library. + * + * @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 + +/** + * General Concept + * A SparkFun Toolkit error system. The goal is to keep this simple. + * + * This mimics a variety of systems, using an int type for error codes, + * where: + * 0 = okay + * -1 = general failure + * >0 = an informative error + * + * Since *subsystems* in the toolkit can have their own errors, + * A start range for these errors are defined. Values > than this value + * define the errors for the set subsystem. These start ranges are set + * in this file, with actual error values defined in the the respective + * subsystem header files. + * + */ +typedef int32_t sfTkError_t; + +// General errors + +/** + * @brief General error code for a failure. Note all errors are negative. + */ +const sfTkError_t ksfTkErrFail = -1; // general fail +/** + * @brief The error code value for success. This is always 0. + */ +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 + */ +const sfTkError_t ksfTkErrBaseBus = 0x1000; diff --git a/src/sfTk/sfTkIBus.h b/src/sfTk/sfTkIBus.h new file mode 100644 index 0000000..5536dff --- /dev/null +++ b/src/sfTk/sfTkIBus.h @@ -0,0 +1,783 @@ +/** + * @file sfTkIBus.h + * @brief Header file for the SparkFun Toolkit Device Bus Interface Definition. + * + * This file contains the interface declaration for the Communication Bus Interface + * + * @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 "sfToolkit.h" +#include + +/** + * @brief Define our error codes for the bus. Note Errors are negative, warnings/info positive, + * but keep the same increment on the base. + * + */ + +/** + * @brief Error code for when a bus system is not initalized. + */ +const sfTkError_t ksfTkErrBusNotInit = ksfTkErrFail * (ksfTkErrBaseBus + 1); + +/** + * @brief Returned when a bus system times out. + */ +const sfTkError_t ksfTkErrBusTimeout = ksfTkErrFail * (ksfTkErrBaseBus + 2); + +/** + * @brief Returned when a bus system does not respond. + */ +const sfTkError_t ksfTkErrBusNoResponse = ksfTkErrFail * (ksfTkErrBaseBus + 3); + +/** + * @brief Returned when the data to be sent is too long or received is too short. + */ +const sfTkError_t ksfTkErrBusDataTooLong = ksfTkErrFail * (ksfTkErrBaseBus + 4); + +/** + * @brief Returned when the bus settings are null, invalid or on set/initialised + */ +const sfTkError_t ksfTkErrBusNullSettings = ksfTkErrFail * (ksfTkErrBaseBus + 5); + +/** + * @brief Returned when the buffer is null or invalid. + */ +const sfTkError_t ksfTkErrBusNullBuffer = ksfTkErrFail * (ksfTkErrBaseBus + 6); + +/** + * @brief Returned when the bus is under read. Warning + */ +const sfTkError_t ksfTkErrBusUnderRead = ksfTkErrBaseBus + 7; + +/** + * @brief Returned when the bus is not enabled. Warning + */ +const sfTkError_t ksfTkErrBusNotEnabled = ksfTkErrBaseBus + 8; + +/** + * @brief Interface that defines the communication bus for the SparkFun Electronics Toolkit. + * + * The bus interface defines the basic methods for reading and writing data to a device. Specific + * bus implementations will extend this interface to provide the necessary functionality for the + * desired bus type. + */ +class sfTkIBus +{ + public: + /** + * @brief Constructor + */ + 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 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. + */ + virtual sfTkError_t writeData(uint8_t data) + { + return writeRegister(nullptr, 0, &data, sizeof(uint8_t)); + } + + /**-------------------------------------------------------------------------- + * @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 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 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. + * + */ + 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 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. Note - if byte order differs, swap the data before writing. + * + * @retval sfTkError_t - ksfTkErrOk on successful execution. + * + */ + sfTkError_t writeRegister(uint8_t devReg, uint8_t 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. Note - if byte order differs, swap the data before writing. + * + * @retval sfTkError_t - ksfTkErrOk on successful execution. + * + */ + 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); + + 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) + { + 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); + } + + /**-------------------------------------------------------------------------- + * @brief Writes a number of bytes starting at the given register's address. + * + * @param devReg The device's register's address. + * @param data Data to write. + * @param length - length of data + * + * @retval sfTkError_t ksfTkErrOk on successful execution + * + */ + virtual sfTkError_t writeRegister(uint8_t devReg, const uint8_t *data, size_t 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 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 writeRegister(uint16_t devReg, const uint8_t *data, size_t length) + { + if (sftk_system_byteorder() != _byteOrder) + devReg = sftk_byte_swap(devReg); + + 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 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 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 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)); + + // 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) + { + 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 + * + * @param devReg The device's register's address. + * @param data Data to read. + * + * @retval sfTkError_t - ksfTkErrOk on successful execution. + * + */ + sfTkError_t readRegisterUInt8(uint8_t devReg, uint8_t &data) + { + return readRegister(devReg, 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) + { + 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.-- the data value is byteswapped if needed + * + * @retval sfTkError_t - ksfTkErrOk on successful execution. + */ + sfTkError_t readRegisterUInt16(uint8_t devReg, uint16_t &data) + { + return readRegister(devReg, 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) + { + 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 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. + */ + 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 readRegister(uint8_t devReg, uint8_t *data, size_t numBytes, size_t &readBytes) + { + return readRegister(&devReg, sizeof(devReg), data, numBytes, 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) + { + 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 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. + */ + 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. + */ + sfTkError_t readRegisterUInt32(uint16_t devReg, uint32_t &data) + { + return readRegister(devReg, data); + } + + // Overload version + /** + * @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) + { + // 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 16-bit block of data from the given 16-bit register address. + * + * @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 readRegister(uint16_t reg, uint16_t *data, size_t length, size_t &read16) + { + 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; + } + /** + * @brief Set the byte order for multi-byte data transfers + * + * @param order The byte order to set - set to either sfTkByteOrder::BigEndian or + * sfTkByteOrder::LittleEndian + */ + void setByteOrder(sfTkByteOrder order) + { + _byteOrder = order; + } + + /** + * @brief Get the current byte order + * + * @retval The current byte order + */ + sfTkByteOrder byteOrder(void) + { + return _byteOrder; + } + + protected: + /** + * Flag to manage byte swapping + */ + sfTkByteOrder _byteOrder; +}; diff --git a/src/sfeTk/sfeTkII2C.h b/src/sfTk/sfTkII2C.h similarity index 57% rename from src/sfeTk/sfeTkII2C.h rename to src/sfTk/sfTkII2C.h index f9fdf57..2ecc379 100644 --- a/src/sfeTk/sfeTkII2C.h +++ b/src/sfTk/sfTkII2C.h @@ -1,32 +1,19 @@ - -// sfeTkII2C.h -// -// Defines the I2C communication bus interface for the SparkFun Electronics Toolkit -/* -The MIT License (MIT) - -Copyright (c) 2023 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. - -*/ +/** + * @file sfTkII2C.h + * @brief Header file for the SparkFun Toolkit I2C Interface Definition. + * + * This file contains the interface declaration for the I2C communication bus + * + * @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 "sfeTkIBus.h" +#include "sfTkIBus.h" /** * @brief Interface that defines the I2C communication bus for the SparkFun Electronics Toolkit. @@ -34,14 +21,16 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * The I2C bus interface extends the IBus interface and adds the ability to set and get the I2C * address and stop flag. */ -class sfeTkII2C : public sfeTkIBus +const uint8_t ksfTkBusTypeI2C = 0x01; + +class sfTkII2C : public sfTkIBus { public: // set the address to No address and stop flag to true /** * @brief Constructor for the I2C bus */ - sfeTkII2C() : _address{kNoAddress}, _stop{true} + sfTkII2C() : _address{kNoAddress}, _stop{true} { } /** @@ -49,17 +38,17 @@ class sfeTkII2C : public sfeTkIBus * * @param addr */ - sfeTkII2C(uint8_t addr) : _address{addr} + sfTkII2C(uint8_t addr) : _address{addr} { } /**-------------------------------------------------------------------------- @brief A simple ping of the device at the set address - @retval sfeTkError_t - ok on success + @retval sfTkError_t - ok on success */ - virtual sfeTkError_t ping() = 0; + virtual sfTkError_t ping() = 0; /**-------------------------------------------------------------------------- @brief setter for the I2C address @@ -109,6 +98,11 @@ class sfeTkII2C : public sfeTkIBus */ static constexpr uint8_t kNoAddress = 0; + virtual uint8_t type(void) + { + return ksfTkBusTypeI2C; + } + private: uint8_t _address; bool _stop; diff --git a/src/sfTk/sfTkISPI.h b/src/sfTk/sfTkISPI.h new file mode 100644 index 0000000..d063378 --- /dev/null +++ b/src/sfTk/sfTkISPI.h @@ -0,0 +1,83 @@ +/** + * @file sfTkISPI.h + * @brief Header file for the SparkFun Toolkit SPI Interface Definition. + * + * This file contains the interface declaration for the SPI communication bus + * + * @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 "sfTkIBus.h" + +/** + * @brief Interface that defines the SPI communication bus for the SparkFun Electronics Toolkit. + * + * The SPI bus interface extends the IBus interface and adds the ability to set and get the CS pin. + */ + +const uint8_t ksfTkBusTypeSPI = 0x02; +class sfTkISPI : public sfTkIBus +{ + public: + /**-------------------------------------------------------------------------- + @brief Constructor for the SPI bus + + */ + sfTkISPI() : _cs{kNoCSPin} + { + } + + /**-------------------------------------------------------------------------- + @brief Constructor for the SPI bus + + @param csPin The CS Pin for the device + + */ + sfTkISPI(uint8_t csPin) : _cs{csPin} + { + } + + /**-------------------------------------------------------------------------- + @brief setter for the CS Pin + + @param devCS The device's CS Pin + + */ + virtual void setCS(uint8_t devCS) + { + _cs = devCS; + } + + /**-------------------------------------------------------------------------- + @brief getter for the cs pin + + @retval uint8_t returns the CS pin for the device + + */ + virtual uint8_t cs(void) + { + return _cs; + } + + /**-------------------------------------------------------------------------- + @brief A constant for no CS pin + */ + static constexpr uint8_t kNoCSPin = 0; + + virtual uint8_t type(void) + { + return ksfTkBusTypeSPI; + } + + private: + /** The internal storage of the _cs value*/ + uint8_t _cs; +}; + +//}; diff --git a/src/sfTk/sfToolkit.cpp b/src/sfTk/sfToolkit.cpp new file mode 100644 index 0000000..2a116ee --- /dev/null +++ b/src/sfTk/sfToolkit.cpp @@ -0,0 +1,84 @@ +/** + * @file sfToolkit.cpp + * @brief Implementation file for the SparkFun Toolkit. + * + * This file contains the implementation of various utility functions + * for the SparkFun Toolkit library. + * + * @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 + */ + +#include "sfToolkit.h" + +#ifdef ARDUINO +#include +#endif +//--------------------------------------------------------------------------------- +/** + * @brief C function - Runtime check for system byte order + */ +sfTkByteOrder sftk_system_byteorder(void) +{ + uint16_t i = 1; + return *((uint8_t *)&i) == 0 ? sfTkByteOrder::BigEndian : sfTkByteOrder::LittleEndian; +} + +//--------------------------------------------------------------------------------- +/** + * @brief to catch 8 bit calls for byte swap + * + */ +uint8_t sftk_byte_swap(uint8_t i) +{ + return i; +} +//--------------------------------------------------------------------------------- +/** + * @brief function - Byte swap a 16 bit value + */ +uint16_t sftk_byte_swap(uint16_t i) +{ + // Use the fast intrinsic if available +#if defined(__clang__) || defined(__GNUC__) + return __builtin_bswap16(i); +#else + return (i << 8) | (i >> 8); +#endif +} + +//--------------------------------------------------------------------------------- +/** + * @brief function - Byte swap a 32 bit value + */ +uint32_t sftk_byte_swap(uint32_t i) +{ +#if defined(__clang__) || defined(__GNUC__) + return __builtin_bswap32(i); +#else + 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 new file mode 100644 index 0000000..c8b15ba --- /dev/null +++ b/src/sfTk/sfToolkit.h @@ -0,0 +1,72 @@ + +/** + * @file sfToolkit.h + * @brief Header file for the SparkFun Toolkit. + * + * This file contains the declarations of various utility functions + * and types for the SparkFun Toolkit library. + * + * @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 + +/** + @brief Common include file for the core of the SparkFun Electronics Toolkit +*/ +#include "sfTkError.h" + +// byte order types/enum +enum class sfTkByteOrder : uint8_t +{ + BigEndian = 0x01, + LittleEndian = 0x02 +}; + +// Note - toolkit *functions* start with sftk_ to avoid name collisions + +// Function to determine the byte order of the system +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 +// 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); + +/** + * @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 new file mode 100644 index 0000000..422ffa8 --- /dev/null +++ b/src/sfTkArdI2C.cpp @@ -0,0 +1,198 @@ +/** + * @file sfTkArdI2C.h + * @brief Implementation file for the SparkFun Toolkit Arduino I2C driver. + * + * This file contains the Arduino I2C driver for the SparkFun Toolkit library. + * + * @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 + */ + +#include "sfTkArdI2C.h" + +//--------------------------------------------------------------------------------- + +/** + * @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 + if (!_i2cPort) + { + // use the pass in port + _i2cPort = &wirePort; + + if (bInit) + _i2cPort->begin(); + } + + setAddress(addr); + return ksfTkErrOk; +} + +//--------------------------------------------------------------------------------- +/** + * @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 + if (!_i2cPort) + return init(Wire, addr); + + // We have a port, so arcady init'd - right? + return ksfTkErrOk; +} + +//--------------------------------------------------------------------------------- + +/** + * @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()); +} +//--------------------------------------------------------------------------------- +/** + * @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 + if (!_i2cPort) + return ksfTkErrBusNotInit; + + _i2cPort->beginTransmission(address()); + return _i2cPort->endTransmission() == 0 ? ksfTkErrOk : ksfTkErrFail; +} + +/** + * @brief Writes 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 write + * @param length The length of the data buffer + * @return sfTkError_t Returns ksfTkErrOk on success, or ksfTkErrFail code + */ +sfTkError_t sfTkArdI2C::writeRegister(uint8_t *devReg, size_t regLength, const uint8_t *data, size_t length) +{ + if (!_i2cPort) + return ksfTkErrBusNotInit; + + _i2cPort->beginTransmission(address()); + + if (devReg != nullptr && regLength > 0) + _i2cPort->write(devReg, regLength); + + _i2cPort->write(data, (int)length); + + return _i2cPort->endTransmission() ? ksfTkErrFail : ksfTkErrOk; +} + +/** + * @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 + */ +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; + + // Buffer valid? + if (!data) + return ksfTkErrBusNullBuffer; + + readBytes = 0; + + uint16_t nOrig = numBytes; // original number of bytes. + uint8_t nChunk; + uint16_t nReturned; + uint16_t i; // counter in loop + bool bFirstInter = true; // Flag for first iteration - used to send devRegister + + while (numBytes > 0) + { + if (bFirstInter) + { + _i2cPort->beginTransmission(address()); + + _i2cPort->write(devReg, regLength); + + if (_i2cPort->endTransmission(stop()) != 0) + return ksfTkErrFail; // error with the end transmission + + bFirstInter = false; + } + + // We're chunking in data - keeping the max chunk to kMaxI2CBufferLength + nChunk = numBytes > _bufferChunkSize ? _bufferChunkSize : numBytes; + + // Request the bytes. If this is the last chunk, always send a stop + nReturned = _i2cPort->requestFrom((int)address(), (int)nChunk, (int)(nChunk == numBytes ? true : stop())); + + // No data returned, no dice + if (nReturned == 0) + return ksfTkErrBusUnderRead; // error + + // Copy the retrieved data chunk to the current index in the data segment + for (i = 0; i < nReturned; i++) + *data++ = _i2cPort->read(); + + // Decrement the amount of data received from the overall data request amount + numBytes = numBytes - nReturned; + + } // end while + + readBytes = nOrig - numBytes; // Bytes read. + + return (readBytes == nOrig) ? ksfTkErrOk : ksfTkErrBusUnderRead; // Success +} diff --git a/src/sfTkArdI2C.h b/src/sfTkArdI2C.h new file mode 100644 index 0000000..e24a494 --- /dev/null +++ b/src/sfTkArdI2C.h @@ -0,0 +1,164 @@ +/** + * @file sfTkArdI2C.cpp + * @brief header file for the SparkFun Toolkit Arduino I2C driver. + * + * This file contains the Arduino I2C header for the SparkFun Toolkit library. + * + * @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 +#include + +// Include our platform I2C interface definition. +#include "sfTkArduino.h" +#include + +/** + * @brief The sfTkArdI2C implements an sfTkII2C interface, defining the Arduino implementation for I2C in the Toolkit + */ + +class sfTkArdI2C : public sfTkII2C +{ + public: + /** + @brief Constructor + */ + + sfTkArdI2C(void) : _i2cPort(nullptr), _bufferChunkSize{kDefaultBufferChunk} + { + } + /** + @brief Constructor + + @param addr The address of the device + */ + sfTkArdI2C(uint8_t addr) : sfTkII2C(addr) + { + } + + /** + * @brief copy constructor + */ + sfTkArdI2C(sfTkArdI2C const &rhs) : sfTkII2C(), _i2cPort{rhs._i2cPort} + { + } + + /** + * @brief Copy assignment + * + * @param rhs right hand side of the assignment + * @return value of the left hand side of the assignment + */ + sfTkArdI2C &operator=(const sfTkArdI2C &rhs) + { + _i2cPort = rhs._i2cPort; + return *this; + } + + /** + @brief Method sets up the required I2C settings. + @note This function provides a default I2C Port. + + @retval ksfTkErrOk on successful execution. + */ + sfTkError_t init(); + + /** + @brief - address version of the init method + + @param addr The address of the device + */ + sfTkError_t init(uint8_t addr); + + /** + @brief Method sets up the required I2C settings. + + @param wirePort Port for I2C communication. + @param addr The address of the device + @param bInit This flag tracks whether the bus has been initialized. + + @retval ksfTkErrOk on successful execution. + */ + sfTkError_t init(TwoWire &wirePort, uint8_t addr, bool bInit = false); + + /** + @brief A simple ping of the device at the given address. + @note sfTkIBus interface method + + @retval ksfTkErrOk on success, + */ + sfTkError_t ping(); + + /** + * @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 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 + + @note default size is 32 + + @param theChunk the new size - must be > 0 + + */ + void setBufferChunkSize(size_t theChunk) + { + if (theChunk > 0) + _bufferChunkSize = theChunk; + } + + /** + @brief set the buffer chunk size + + @retval The current chunk size + + */ + size_t bufferChunkSize(void) + { + 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 + // created to implement a special read/write routine + // + /** The actual Arduino i2c port */ + TwoWire *_i2cPort; + + private: + /** 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 new file mode 100644 index 0000000..0434df8 --- /dev/null +++ b/src/sfTkArdSPI.cpp @@ -0,0 +1,253 @@ +/** + * @file sfTkArdSPI.h + * @brief Implementation file for the SparkFun Toolkit Arduino SPI driver. + * + * This file contains the Arduino SPI driver for the SparkFun Toolkit library. + * + * @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 + */ + +#include "sfTkArdSPI.h" +#include + +// Note: A leading "1" must be added to transfer with register to indicate a "read" +// Note to our future selves: +// This works / is required on both the ISM330 and MMC5983, +// but will cause badness with other SPI devices. +// We may need to add an alternate method if we ever add another SPI device. +#define kSPIReadBit 0x80 + +//--------------------------------------------------------------------------------- +// init() +// +// Arduino version of init. Will take in a defined SPI port/settings +// +sfTkError_t sfTkArdSPI::init(SPIClass &spiPort, SPISettings &busSPISettings, uint8_t csPin, bool bInit) +{ + // if we don't have a SPI port already + if (!_spiPort) + { + _spiPort = &spiPort; + + if (bInit) + _spiPort->begin(); + } + + setCS(csPin); + + // SPI settings are needed for every transaction + _sfeSPISettings = busSPISettings; + + return ksfTkErrOk; +} + +//--------------------------------------------------------------------------------- +// init() +// +// Arduino version of init. +// +sfTkError_t sfTkArdSPI::init(uint8_t csPin, bool bInit) +{ + // If the transaction settings are not provided by the user they are built here. + SPISettings spiSettings = SPISettings(3000000, MSBFIRST, SPI_MODE3); + + // In addition of the port is not provided by the user, it defaults to SPI here. + return init(SPI, spiSettings, csPin, bInit); +} + +//--------------------------------------------------------------------------------- +// init() +// +// Arduino version of init. +// +sfTkError_t sfTkArdSPI::init(bool bInit) +{ + return init(cs(), bInit); +} + +//--------------------------------------------------------------------------------- +// writeRegister() +// +// Writes an array of bytes to a given register on the target address +// +// Returns ksfTkErrOk on success +// +sfTkError_t sfTkArdSPI::writeRegister(uint8_t *devReg, size_t regLength, const uint8_t *data, size_t length) +{ + if (!_spiPort) + return ksfTkErrBusNotInit; + + // Apply settings before work + _spiPort->beginTransaction(_sfeSPISettings); + + // Signal communication start + digitalWrite(cs(), LOW); + + // 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++); + + // End communication + digitalWrite(cs(), HIGH); + _spiPort->endTransaction(); + + return ksfTkErrOk; +} + +//--------------------------------------------------------------------------------- +// 16 bit address version ... +// 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; + + // Apply settings before work + _spiPort->beginTransaction(_sfeSPISettings); + + // Signal communication start + digitalWrite(cs(), LOW); + _spiPort->transfer16(devReg); + + for (size_t i = 0; i < length; i++) + _spiPort->transfer(*data++); + + // End communication + digitalWrite(cs(), HIGH); + _spiPort->endTransaction(); + + return ksfTkErrOk; +} + +//--------------------------------------------------------------------------------- +// 16 bit address and data version ... +// 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; + + // Apply settings before work + _spiPort->beginTransaction(_sfeSPISettings); + + // Signal communication start + digitalWrite(cs(), LOW); + _spiPort->transfer16(devReg); + + for (size_t i = 0; i < length; i++) + _spiPort->transfer16(*data++); + + // End communication + digitalWrite(cs(), HIGH); + _spiPort->endTransaction(); + + return ksfTkErrOk; +} + +//--------------------------------------------------------------------------------- +// readRegisterRegion() +// +// Reads an array of bytes to a given register on the target address +// +// Returns ksfTkErrOk on success +// +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); + + // 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); + + // End transaction + digitalWrite(cs(), HIGH); + _spiPort->endTransaction(); + + readBytes = numBytes; + + return ksfTkErrOk; +} + +//--------------------------------------------------------------------------------- +// readRegister16Region() +// +// Reads an array of bytes to a given a 16 bit register on the target address +// +// Returns ksfTkErrOk on success +// +sfTkError_t sfTkArdSPI::readRegister(uint16_t devReg, uint8_t *data, size_t numBytes, size_t &readBytes) +{ + if (!_spiPort) + return ksfTkErrBusNotInit; + + return readRegister((uint8_t *)&devReg, sizeof(uint16_t), data, numBytes, readBytes); +} + +//--------------------------------------------------------------------------------- +// readRegister16Region16() +// +// Reads an array of uint16 to a given a 16 bit register on the target address +// +// Returns ksfTkErrOk on success +// +sfTkError_t sfTkArdSPI::readRegister(uint16_t devReg, uint16_t *data, size_t numBytes, size_t &readWords) +{ + 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); + + for (size_t i = 0; i < numBytes; i++) + *data++ = _spiPort->transfer16(0x00); + + // End transaction + digitalWrite(cs(), HIGH); + _spiPort->endTransaction(); + + readWords = numBytes; + + return ksfTkErrOk; +} \ No newline at end of file diff --git a/src/sfTkArdSPI.h b/src/sfTkArdSPI.h new file mode 100644 index 0000000..1998adc --- /dev/null +++ b/src/sfTkArdSPI.h @@ -0,0 +1,194 @@ +/** + * @file sfTkArdSPI.cpp + * @brief header file for the SparkFun Toolkit Arduino SPI driver. + * + * This file contains the Arduino SPI header for the SparkFun Toolkit library. + * + * @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 "sfTkArduino.h" +#include +#include + +/** + @brief This class implements the IBus interface for an SPI Implementation on Arduino + */ +class sfTkArdSPI : public sfTkISPI +{ + public: + /** + @brief Constructor for Arduino SPI bus object of the toolkit + */ + sfTkArdSPI(void) : _spiPort(nullptr) + { + } + + /** + @brief Constructor for Arduino SPI bus object of the toolkit + + @param csPin The CS Pin for the device + */ + sfTkArdSPI(uint8_t csPin) : sfTkISPI(csPin) + { + } + /** + @brief Copy constructor for Arduino SPI bus object of the toolkit + + @param rhs source of the copy operation + */ + sfTkArdSPI(sfTkArdSPI const &rhs) : sfTkISPI(), _spiPort{rhs._spiPort}, _sfeSPISettings{rhs._sfeSPISettings} + { + } + + /** + @brief Assignment copy operator for Arduino SPI bus object of the toolkit + + @param rhs The right hand side of the assignment. + @return sfTkArdSPI& - The left hand side of the assignment. + */ + sfTkArdSPI &operator=(const sfTkArdSPI &rhs) + { + _spiPort = rhs._spiPort; + _sfeSPISettings = rhs._sfeSPISettings; + return *this; + } + + /** + @brief Method sets up the required SPI settings. + @note This function provides a default SPI Port. + + @param bInit Init the device - default is false. + + @retval sfTkError_t - ksfTkErrOk on success + */ + sfTkError_t init(bool bInit = false); + + /** + @brief Method sets up the required SPI settings. + @note This function provides a default SPI Port. + + @param csPin The CS Pin for the device + @param bInit Init the device - default is false. + + @retval sfTkError_t - ksfTkErrOk on success + */ + sfTkError_t init(uint8_t csPin, bool bInit = false); + + /** + @brief Method sets up the required SPI settings. + + @param spiPort Port for SPI communication. + @param busSPISettings Settings for speed, endianness, and spi mode of the SPI bus. + @param csPin The CS Pin for the device + @param bInit This flag tracks whether the bus has been initialized. + + @retval sfTkError_t - ksfTkErrOk on success + */ + sfTkError_t init(SPIClass &spiPort, SPISettings &busSPISettings, uint8_t csPin, bool bInit = false); + + /** + @brief Write an array of data to the device without indexing to a register. + + @param data Data to write + @param length Length of Data + + @retval sfTkError_t - ksfTkErrOk on success + */ + sfTkError_t writeRegion(const uint8_t *data, size_t length); + + /** + @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 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. + @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 sfTkError_t - ksfTkErrOk on success + */ + 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. + @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 sfTkError_t - ksfTkErrOk on success + */ + sfTkError_t writeRegister(uint16_t devReg, const uint16_t *data, size_t length); + + /** + * @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. + @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 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 + + @retval sfTkError_t - true on success + */ + 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. + @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 16 bit address. + @param[out] data Data buffer to read into + @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 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 + // created to implement a special read/write routine + // + /** Pointer to the spi port being used */ + SPIClass *_spiPort; + + /** This object's spi settings are used for every transaction. */ + SPISettings _sfeSPISettings; +}; diff --git a/src/sfTkArduino.cpp b/src/sfTkArduino.cpp new file mode 100644 index 0000000..49b5aef --- /dev/null +++ b/src/sfTkArduino.cpp @@ -0,0 +1,26 @@ +/** + * @file sfTkArduino.cpp + * @brief Implementation file for the SparkFun Toolkit Arduino layer + * + * This file contains the implementation for the SparkFun Toolkit library Arduino layer. + * + * @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 + */ + +#include + +// Implements the sfToolkit functions for the Arduino platform + +void sftk_delay_ms(uint32_t ms) +{ + delay(ms); +} + +uint32_t sftk_ticks_ms(void) +{ + return millis(); +} \ No newline at end of file diff --git a/src/sfTkArduino.h b/src/sfTkArduino.h new file mode 100644 index 0000000..f79ddcd --- /dev/null +++ b/src/sfTkArduino.h @@ -0,0 +1,28 @@ + +/** + * @file sfTkArduino.h + * @brief header file for the SparkFun Toolkit Arduino layer + * + * This file contains the header for the SparkFun Toolkit library Arduino layer. + * + * @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 + +// Purpose: +// +// "Arduino-ized" value of toolkit values constants" + +// Just include the toolkit headers + +#include + +// Arduino-ize our byte order types + +const sfTkByteOrder SFTK_MSBFIRST = sfTkByteOrder::BigEndian; +const sfTkByteOrder SFTK_LSBFIRST = sfTkByteOrder::LittleEndian; \ No newline at end of file diff --git a/src/sfeTk/sfeTkError.h b/src/sfeTk/sfeTkError.h deleted file mode 100644 index 3f00841..0000000 --- a/src/sfeTk/sfeTkError.h +++ /dev/null @@ -1,64 +0,0 @@ - -// sfeTkError.h -// -// General header file for the SparkFun Toolkit -/* -The MIT License (MIT) - -Copyright (c) 2023 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. - -*/ - -#pragma once - -#include - -/** - * General Concept - * A SparkFun Toolkit error system. The goal is to keep this simple. - * - * This mimics a variety of systems, using an int type for error codes, - * where: - * 0 = okay - * -1 = general failure - * >0 = an informative error - * - * Since *subsystems* in the toolkit can have their own errors, - * A start range for these errors are defined. Values > than this value - * define the errors for the set subsystem. These start ranges are set - * in this file, with actual error values defined in the the respective - * subsystem header files. - * - */ -typedef int32_t sfeTkError_t; - -// General errors - -/** - * @brief General error code for a failure. Note all errors are negative. - */ -const sfeTkError_t kSTkErrFail = -1; // general fail -/** - * @brief The error code value for success. This is always 0. - */ -const sfeTkError_t kSTkErrOk = 0; // success - -/** - * @brief A base value for bus errors. All bus errors are greater than this value, in the 1000 range - */ -const sfeTkError_t kSTkErrBaseBus = 0x1000; diff --git a/src/sfeTk/sfeTkIBus.h b/src/sfeTk/sfeTkIBus.h deleted file mode 100644 index c6ca7ab..0000000 --- a/src/sfeTk/sfeTkIBus.h +++ /dev/null @@ -1,211 +0,0 @@ - -// sfeTkIBus.h -// -// Defines the communication bus interface for the SparkFun Electronics Toolkit -> sfeTk -/* - -The MIT License (MIT) - -Copyright (c) 2023 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. - -*/ - -#pragma once - -#include "sfeTkError.h" -#include - -/** - * @brief Define our error codes for the bus. Note Errors are negative, warnings/info positive, - * but keep the same increment on the base. - * - */ - -/** - * @brief Error code for when a bus system is not initalized. - */ -const sfeTkError_t kSTkErrBusNotInit = kSTkErrFail * (kSTkErrBaseBus + 1); - -/** - * @brief Returned when a bus system times out. - */ -const sfeTkError_t kSTkErrBusTimeout = kSTkErrFail * (kSTkErrBaseBus + 2); - -/** - * @brief Returned when a bus system does not respond. - */ -const sfeTkError_t kSTkErrBusNoResponse = kSTkErrFail * (kSTkErrBaseBus + 3); - -/** - * @brief Returned when the data to be sent is too long or recieved is too short. - */ -const sfeTkError_t kSTkErrBusDataTooLong = kSTkErrFail * (kSTkErrBaseBus + 4); - -/** - * @brief Returned when the bus settings are null, invalid or on set/initialised - */ -const sfeTkError_t kSTkErrBusNullSettings = kSTkErrFail * (kSTkErrBaseBus + 5); - -/** - * @brief Returned when the buffer is null or invalid. - */ -const sfeTkError_t kSTkErrBusNullBuffer = kSTkErrFail * (kSTkErrBaseBus + 6); - -/** - * @brief Returned when the bus is under read. Warning - */ -const sfeTkError_t kSTkErrBusUnderRead = kSTkErrBaseBus + 7; - -/** - * @brief Returned when the bus is not enabled. Warning - */ -const sfeTkError_t kSTkErrBusNotEnabled = kSTkErrBaseBus + 8; - -/** - * @brief Interface that defines the communication bus for the SparkFun Electronics Toolkit. - * - * The bus interface defines the basic methods for reading and writing data to a device. Specific - * bus implementations will extend this interface to provide the necessary functionality for the - * desired bus type. - */ -class sfeTkIBus -{ - public: - /**-------------------------------------------------------------------------- - * @brief Send a single byte to the device* - * @param data Data to write. - * - * @retval sfeTkError_t - kSTkErrOk on successful execution. - * - */ - virtual sfeTkError_t writeByte(uint8_t data) = 0; - - /**-------------------------------------------------------------------------- - * @brief Send a word to the device. - * @param data Data to write. - * - * @retval sfeTkError_t - kSTkErrOk on successful execution. - * - */ - virtual sfeTkError_t writeWord(uint16_t data) = 0; - - /**-------------------------------------------------------------------------- - * @brief Send an array of data to the device. - * @param data Data to write. - * @param length - length of data. - * - * @retval sfeTkError_t - kSTkErrOk on successful execution. - * - */ - virtual sfeTkError_t writeRegion(const uint8_t *data, size_t length) = 0; - - /**-------------------------------------------------------------------------- - * @brief Write a single byte to the given register - * - * @param devReg The device's register's address. - * @param data Data to write. - * - * @retval sfeTkError_t - kSTkErrOk on successful execution. - * - */ - virtual sfeTkError_t writeRegisterByte(uint8_t devReg, uint8_t data) = 0; - - /**-------------------------------------------------------------------------- - * @brief Write a single word (16 bit) to the given register - * - * @param devReg The device's register's address. - * @param data Data to write. - * - * @retval sfeTkError_t - kSTkErrOk on successful execution. - * - */ - virtual sfeTkError_t writeRegisterWord(uint8_t devReg, uint16_t data) = 0; - - /**-------------------------------------------------------------------------- - * @brief Writes a number of bytes starting at the given register's address. - * - * @param devReg The device's register's address. - * @param data Data to write. - * @param length - length of data - * - * @retval sfeTkError_t kSTkErrOk on successful execution - * - */ - virtual sfeTkError_t writeRegisterRegion(uint8_t devReg, const uint8_t *data, size_t length) = 0; - - /**-------------------------------------------------------------------------- - * @brief Writes a number of bytes starting at the given register's 16-bit address. - * - * @param devReg The device's register's address. - * @param data Data to write. - * @param length - length of data - * - * @retval sfeTkError_t kSTkErrOk on successful execution - * - */ - virtual sfeTkError_t writeRegister16Region(uint16_t devReg, const uint8_t *data, size_t length) = 0; - - /**-------------------------------------------------------------------------- - * @brief Read a single byte from the given register - * - * @param devReg The device's register's address. - * @param data Data to read. - * - * @retval sfeTkError_t - kSTkErrOk on successful execution. - * - */ - virtual sfeTkError_t readRegisterByte(uint8_t devReg, uint8_t &data) = 0; - - /**-------------------------------------------------------------------------- - * @brief Read a single word (16 bit) from the given register - * - * @param devReg The device's register's address. - * @param data Data to read. - * - * @retval sfeTkError_t - kSTkErrOk on successful execution. - */ - virtual sfeTkError_t readRegisterWord(uint8_t devReg, uint16_t &data) = 0; - - /**-------------------------------------------------------------------------- - * @brief Reads a block of data 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 - * - * @retval int returns kSTkErrOk on success, or kSTkErrFail code - * - */ - virtual sfeTkError_t readRegisterRegion(uint8_t reg, uint8_t *data, size_t numBytes, size_t &readBytes) = 0; - - /**-------------------------------------------------------------------------- - * @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 to write. - * @param numBytes - length of data - * @param[out] readBytes - number of bytes read - * - * @retval int returns kSTkErrOk on success, or kSTkErrFail code - * - */ - virtual sfeTkError_t readRegister16Region(uint16_t reg, uint8_t *data, size_t numBytes, size_t &readBytes) = 0; -}; - -//}; diff --git a/src/sfeTk/sfeTkISPI.h b/src/sfeTk/sfeTkISPI.h deleted file mode 100644 index e9df115..0000000 --- a/src/sfeTk/sfeTkISPI.h +++ /dev/null @@ -1,90 +0,0 @@ - -// sfeTkISPI.h -// -// Defines the SPI communication bus interface for the SparkFun Electronics Toolkit -/* - -The MIT License (MIT) - -Copyright (c) 2023 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. - -*/ - -#pragma once - -#include "sfeTkIBus.h" - -/** - * @brief Interface that defines the SPI communication bus for the SparkFun Electronics Toolkit. - * - * The SPI bus interface extends the IBus interface and adds the ability to set and get the CS pin. - */ -class sfeTkISPI : public sfeTkIBus -{ - public: - /**-------------------------------------------------------------------------- - @brief Constructor for the SPI bus - - */ - sfeTkISPI() : _cs{kNoCSPin} - { - } - - /**-------------------------------------------------------------------------- - @brief Constructor for the SPI bus - - @param csPin The CS Pin for the device - - */ - sfeTkISPI(uint8_t csPin) : _cs{csPin} - { - } - - /**-------------------------------------------------------------------------- - @brief setter for the CS Pin - - @param devCS The device's CS Pin - - */ - virtual void setCS(uint8_t devCS) - { - _cs = devCS; - } - - /**-------------------------------------------------------------------------- - @brief getter for the cs pin - - @retval uint8_t returns the CS pin for the device - - */ - virtual uint8_t cs(void) - { - return _cs; - } - - /**-------------------------------------------------------------------------- - @brief A constant for no CS pin - */ - static constexpr uint8_t kNoCSPin = 0; - - private: - /** The internal storage of the _cs value*/ - uint8_t _cs; -}; - -//}; diff --git a/src/sfeTk/sfeToolkit.h b/src/sfeTk/sfeToolkit.h deleted file mode 100644 index da1ec00..0000000 --- a/src/sfeTk/sfeToolkit.h +++ /dev/null @@ -1,32 +0,0 @@ - -// sfeToolkit.h -// -// General header file for the SparkFun Toolkit -/* - -The MIT License (MIT) - -Copyright (c) 2023 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. -*/ - -#pragma once - -/** - @brief Common include file for the core of the SparkFun Electronics Toolkit -*/ -#include "sfeTkError.h" diff --git a/src/sfeTkArdI2C.cpp b/src/sfeTkArdI2C.cpp deleted file mode 100644 index ab7b20a..0000000 --- a/src/sfeTkArdI2C.cpp +++ /dev/null @@ -1,361 +0,0 @@ -/* -sfeTkArdI2C.cpp -The MIT License (MIT) - -Copyright (c) 2023 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 "sfeTkArdI2C.h" - -//--------------------------------------------------------------------------------- -// init() -// -// Arduino version of init - pass in already setup wire port ... -// -sfeTkError_t sfeTkArdI2C::init(TwoWire &wirePort, uint8_t addr, bool bInit) -{ - // if we don't have a wire port already - if (!_i2cPort) - { - // use the pass in port - _i2cPort = &wirePort; - - if (bInit) - _i2cPort->begin(); - } - - setAddress(addr); - return kSTkErrOk; -} - -//--------------------------------------------------------------------------------- -// init() -// -// no parameters version of init. Setups a a wire port if needed. -// -sfeTkError_t sfeTkArdI2C::init(uint8_t addr) -{ - // no port yet, do the default version of it - if (!_i2cPort) - return init(Wire, addr); - - // We have a port, so arcady init'd - right? - return kSTkErrOk; -} - -//--------------------------------------------------------------------------------- -// init() -// -// no parameters version of init. Setups a a wire port if needed. -// -sfeTkError_t sfeTkArdI2C::init(void) -{ - // call with our currently set address ... - return init(address()); -} -//--------------------------------------------------------------------------------- -// ping() -// -// Ping an I2C address to see if something is there. -// -sfeTkError_t sfeTkArdI2C::ping() -{ - // no port, no - if (!_i2cPort) - return kSTkErrBusNotInit; - - _i2cPort->beginTransmission(address()); - return _i2cPort->endTransmission() == 0 ? kSTkErrOk : kSTkErrFail; -} - -//--------------------------------------------------------------------------------- -// writeByte() -// -// Writes a single byte to the device, without indexing to a register. -// -// Returns true on success, false on failure -// -sfeTkError_t sfeTkArdI2C::writeByte(uint8_t dataToWrite) -{ - if (!_i2cPort) - return kSTkErrBusNotInit; - - // do the Arduino I2C work - _i2cPort->beginTransmission(address()); - _i2cPort->write(dataToWrite); - return _i2cPort->endTransmission() == 0 ? kSTkErrOk : kSTkErrFail; -} - -//--------------------------------------------------------------------------------- -// writeWord() -// -// Writes a word to the device, without indexing to a register. -// -// Returns true on success, false on failure -// -sfeTkError_t sfeTkArdI2C::writeWord(uint16_t dataToWrite) -{ - if (!_i2cPort) - return kSTkErrBusNotInit; - - 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 -// -sfeTkError_t sfeTkArdI2C::writeRegion(const uint8_t *data, size_t length) -{ - return writeRegisterRegionAddress(nullptr, 0, data, length) == 0 ? kSTkErrOk : kSTkErrFail; -} - -//--------------------------------------------------------------------------------- -// writeRegisterByte() -// -// Writes a byte to a given register. -// -// Returns true on success, false on failure -// -sfeTkError_t sfeTkArdI2C::writeRegisterByte(uint8_t devReg, uint8_t dataToWrite) -{ - if (!_i2cPort) - return kSTkErrBusNotInit; - - // do the Arduino I2C work - _i2cPort->beginTransmission(address()); - _i2cPort->write(devReg); - _i2cPort->write(dataToWrite); - return _i2cPort->endTransmission() == 0 ? kSTkErrOk : kSTkErrFail; -} - -//--------------------------------------------------------------------------------- -// writeRegisterWord() -// -// Writes a word to a given register. -// -// Returns true on success, false on failure -// -sfeTkError_t sfeTkArdI2C::writeRegisterWord(uint8_t devReg, uint16_t dataToWrite) -{ - if (!_i2cPort) - return kSTkErrBusNotInit; - - 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 - * - * @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 write - * @param length The length of the data buffer - * @return sfeTkError_t Returns kSTkErrOk on success, or kSTkErrFail code - */ -sfeTkError_t sfeTkArdI2C::writeRegisterRegionAddress(uint8_t *devReg, size_t regLength, const uint8_t *data, - size_t length) -{ - if (!_i2cPort) - return kSTkErrBusNotInit; - - _i2cPort->beginTransmission(address()); - - if(devReg != nullptr && regLength > 0) - _i2cPort->write(devReg, regLength); - - _i2cPort->write(data, (int)length); - - return _i2cPort->endTransmission() ? kSTkErrFail : kSTkErrOk; -} - -//--------------------------------------------------------------------------------- -// writeRegisterRegion() -// -// Writes an array of bytes to a given register on the target address -// -// Returns the number of bytes written, < 0 is an error -// -sfeTkError_t sfeTkArdI2C::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 -// -sfeTkError_t sfeTkArdI2C::writeRegister16Region(uint16_t devReg, const uint8_t *data, size_t length) -{ - devReg = ((devReg << 8) & 0xff00) | ((devReg >> 8) & 0x00ff); - return writeRegisterRegionAddress((uint8_t *)&devReg, 2, data, length); -} - - - -/** - * @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 sfeTkError_t Returns kSTkErrOk on success, or kSTkErrFail code - */ -sfeTkError_t sfeTkArdI2C::readRegisterRegionAnyAddress(uint8_t *devReg, size_t regLength, uint8_t *data, - size_t numBytes, size_t &readBytes) -{ - - // got port - if (!_i2cPort) - return kSTkErrBusNotInit; - - // Buffer valid? - if (!data) - return kSTkErrBusNullBuffer; - - readBytes = 0; - - uint16_t nOrig = numBytes; // original number of bytes. - uint8_t nChunk; - uint16_t nReturned; - uint16_t i; // counter in loop - bool bFirstInter = true; // Flag for first iteration - used to send devRegister - - while (numBytes > 0) - { - if (bFirstInter) - { - _i2cPort->beginTransmission(address()); - - _i2cPort->write(devReg, regLength); - - if (_i2cPort->endTransmission(stop()) != 0) - return kSTkErrFail; // error with the end transmission - - bFirstInter = false; - } - - // We're chunking in data - keeping the max chunk to kMaxI2CBufferLength - nChunk = numBytes > _bufferChunkSize ? _bufferChunkSize : numBytes; - - // Request the bytes. If this is the last chunk, always send a stop - nReturned = _i2cPort->requestFrom((int)address(), (int)nChunk, (int)(nChunk == numBytes ? true : stop())); - - // No data returned, no dice - if (nReturned == 0) - return kSTkErrBusUnderRead; // error - - // Copy the retrieved data chunk to the current index in the data segment - for (i = 0; i < nReturned; i++) - *data++ = _i2cPort->read(); - - // Decrement the amount of data received from the overall data request amount - numBytes = numBytes - nReturned; - - } // end while - - readBytes = nOrig - numBytes; // Bytes read. - - return (readBytes == nOrig) ? kSTkErrOk : kSTkErrBusUnderRead; // Success -} - -//--------------------------------------------------------------------------------- -// readRegisterByte() -// -// Reads a byte to a given register. -// -// Returns true on success, false on failure -// -sfeTkError_t sfeTkArdI2C::readRegisterByte(uint8_t devReg, uint8_t &dataToRead) -{ - if (!_i2cPort) - return kSTkErrBusNotInit; - - // 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) ? kSTkErrOk : kSTkErrFail); -} - -//--------------------------------------------------------------------------------- -// readRegisterWord() -// -// Reads a word to a given register. -// -// Returns true on success, false on failure -// -sfeTkError_t sfeTkArdI2C::readRegisterWord(uint8_t devReg, uint16_t &dataToRead) -{ - if (!_i2cPort) - return kSTkErrBusNotInit; - - size_t nRead; - sfeTkError_t retval = readRegisterRegion(devReg, (uint8_t *)&dataToRead, sizeof(uint16_t), nRead); - - return (retval == kSTkErrOk && nRead == sizeof(uint16_t) ? kSTkErrOk : 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 -// -sfeTkError_t sfeTkArdI2C::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 -// -sfeTkError_t sfeTkArdI2C::readRegister16Region(uint16_t devReg, uint8_t *data, size_t numBytes, size_t &readBytes) -{ - devReg = ((devReg << 8) & 0xff00) | ((devReg >> 8) & 0x00ff); - return readRegisterRegionAnyAddress((uint8_t *)&devReg, 2, data, numBytes, readBytes); -} diff --git a/src/sfeTkArdI2C.h b/src/sfeTkArdI2C.h deleted file mode 100644 index dc73432..0000000 --- a/src/sfeTkArdI2C.h +++ /dev/null @@ -1,287 +0,0 @@ -/* -sfeTkArdI2c.h - -The MIT License (MIT) - -Copyright (c) 2023 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. - -The following classes specify the behavior for communicating -over Inter-Integrated Circuit (I2C) in Arduino - -*/ - -#pragma once - -#include -#include - -// Include our platform I2C interface definition. -#include - -/** - * @brief The sfeTkArdI2C implements an sfeTkII2C interface, defining the Arduino implementation for I2C in the Toolkit - */ - -class sfeTkArdI2C : public sfeTkII2C -{ - public: - /** - @brief Constructor - */ - sfeTkArdI2C(void) : _i2cPort(nullptr), _bufferChunkSize{kDefaultBufferChunk} - { - } - /** - @brief Constructor - - @param addr The address of the device - */ - sfeTkArdI2C(uint8_t addr) : sfeTkII2C(addr) - { - } - - /** - * @brief copy constructor - */ - sfeTkArdI2C(sfeTkArdI2C const &rhs) : sfeTkII2C(), _i2cPort{rhs._i2cPort} - { - } - - /** - * @brief Copy assignment - * - * @param rhs right hand side of the assignment - * @return value of the left hand side of the assignment - */ - sfeTkArdI2C &operator=(const sfeTkArdI2C &rhs) - { - _i2cPort = rhs._i2cPort; - return *this; - } - - /** - @brief Method sets up the required I2C settings. - @note This function provides a default I2C Port. - - @retval kSTkErrOk on successful execution. - */ - sfeTkError_t init(); - - /** - @brief - address version of the init method - - @param addr The address of the device - */ - sfeTkError_t init(uint8_t addr); - - /** - @brief Method sets up the required I2C settings. - - @param wirePort Port for I2C communication. - @param addr The address of the device - @param bInit This flag tracks whether the bus has been initialized. - - @retval kSTkErrOk on successful execution. - */ - sfeTkError_t init(TwoWire &wirePort, uint8_t addr, bool bInit = false); - - /** - @brief A simple ping of the device at the given address. - @note sfeTkIBus interface method - - @retval kSTkErrOk on success, - */ - sfeTkError_t ping(); - - /** - @brief Sends a single byte to the device - @note sfeTkIBus interface method - - @param data Data to write. - - @retval returns kStkErrOk on success - */ - sfeTkError_t writeByte(uint8_t data); - - /** - @brief Sends a word to the device. - @note sfeTkIBus interface method - - @param data Data to write. - - @retval returns kStkErrOk on success - */ - sfeTkError_t writeWord(uint16_t data); - - /** - @brief Sends a block of data to the device. - @note sfeTkIBus interface method - - @param data Data to write. - @param length - length of data - - @retval returns kStkErrOk on success - */ - sfeTkError_t writeRegion(const uint8_t *data, size_t length); - - /** - @brief Write a single byte to the given register - @note sfeTkIBus interface method - - @param devReg The device's register's address. - @param data Data to write. - - @retval returns kStkErrOk on success - */ - sfeTkError_t writeRegisterByte(uint8_t devReg, uint8_t data); - - /** - @brief Write a single word to the given register - @note sfeTkIBus interface method - - @param devReg The device's register's address. - @param data Data to write. - - @retval returns kStkErrOk on success - */ - sfeTkError_t writeRegisterWord(uint8_t devReg, uint16_t data); - - /** - @brief Writes a number of bytes starting at the given register's address. - - @note sfeTkIBus 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 kStkErrOk on success - */ - sfeTkError_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 sfeTkError_t kSTkErrOk on successful execution - - */ - sfeTkError_t writeRegister16Region(uint16_t devReg, const uint8_t *data, size_t length); - - /** - @brief Reads a byte of data from the given register. - - @note sfeTkIBus interface method - - @param devReg The device's register's address. - @param[out] data Data to read. - - @retval kStkErrOk on success - */ - sfeTkError_t readRegisterByte(uint8_t devReg, uint8_t &data); - - /** - @brief Reads a word of data from the given register. - - @note sfeTkIBus interface method - - @param devReg The device's register's address. - @param[out] data Data to read. - - @retval kSTkErrOk on success - */ - sfeTkError_t readRegisterWord(uint8_t devReg, uint16_t &data); - - /** - @brief Reads a block of data from the given register. - - @note sfeTkIBus 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 kSTkErrOk on success - */ - sfeTkError_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 kSTkErrOk on success, or kSTkErrFail code - - */ - sfeTkError_t readRegister16Region(uint16_t reg, uint8_t *data, size_t numBytes, size_t &readBytes); - - // Buffer size chunk getter/setter - /** - @brief set the buffer chunk size - - @note default size is 32 - - @param theChunk the new size - must be > 0 - - */ - void setBufferChunkSize(size_t theChunk) - { - if (theChunk > 0) - _bufferChunkSize = theChunk; - } - - /** - @brief set the buffer chunk size - - @retval The current chunk size - - */ - size_t bufferChunkSize(void) - { - return _bufferChunkSize; - } - - protected: - // note: The wire port is protected, allowing access if a sub-class is - // created to implement a special read/write routine - // - /** The actual Arduino i2c port */ - TwoWire *_i2cPort; - - private: - sfeTkError_t writeRegisterRegionAddress(uint8_t *devReg, size_t regLength, const uint8_t *data, size_t length); - - sfeTkError_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/sfeTkArdSPI.cpp b/src/sfeTkArdSPI.cpp deleted file mode 100644 index 276e3eb..0000000 --- a/src/sfeTkArdSPI.cpp +++ /dev/null @@ -1,322 +0,0 @@ - -// sfeTkArdSPI.cpp - Arduino SPI implementation for the toolkit - -/* -The MIT License (MIT) - -Copyright (c) 2023 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 "sfeTkArdSPI.h" -#include - -// Note: A leading "1" must be added to transfer with register to indicate a "read" -// Note to our future selves: -// This works / is required on both the ISM330 and MMC5983, -// but will cause badness with other SPI devices. -// We may need to add an alternate method if we ever add another SPI device. -#define kSPIReadBit 0x80 - -//--------------------------------------------------------------------------------- -// init() -// -// Arduino version of init. Will take in a defined SPI port/settings -// -sfeTkError_t sfeTkArdSPI::init(SPIClass &spiPort, SPISettings &busSPISettings, uint8_t csPin, bool bInit) -{ - // if we don't have a SPI port already - if (!_spiPort) - { - _spiPort = &spiPort; - - if (bInit) - _spiPort->begin(); - } - - setCS(csPin); - - // SPI settings are needed for every transaction - _sfeSPISettings = busSPISettings; - - return kSTkErrOk; -} - -//--------------------------------------------------------------------------------- -// init() -// -// Arduino version of init. -// -sfeTkError_t sfeTkArdSPI::init(uint8_t csPin, bool bInit) -{ - // If the transaction settings are not provided by the user they are built here. - SPISettings spiSettings = SPISettings(3000000, MSBFIRST, SPI_MODE3); - - // In addition of the port is not provided by the user, it defaults to SPI here. - return init(SPI, spiSettings, csPin, bInit); -} - -//--------------------------------------------------------------------------------- -// init() -// -// Arduino version of init. -// -sfeTkError_t sfeTkArdSPI::init(bool bInit) -{ - return init(cs(), bInit); -} - -//--------------------------------------------------------------------------------- -// writeByte() -// -// Writes a single byte to the device. -// -// Returns kSTkErrOk on success -// -sfeTkError_t sfeTkArdSPI::writeByte(uint8_t dataToWrite) -{ - - if (!_spiPort) - return kSTkErrBusNotInit; - - // Apply settings - _spiPort->beginTransaction(_sfeSPISettings); - // Signal communication start - digitalWrite(cs(), LOW); - - _spiPort->transfer(dataToWrite); - - // End communication - digitalWrite(cs(), HIGH); - _spiPort->endTransaction(); - - return kSTkErrOk; -} - -//--------------------------------------------------------------------------------- -// writeWord() -// -// Writes a word to the device without indexing to a register. -// -// Returns kSTkErrOk on success -// -sfeTkError_t sfeTkArdSPI::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 kSTkErrOk on success -// -sfeTkError_t sfeTkArdSPI::writeRegion(const uint8_t *dataToWrite, size_t length) -{ - - if (!_spiPort) - return kSTkErrBusNotInit; - - _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 kSTkErrOk; -} - -//--------------------------------------------------------------------------------- -// writeRegisterByte() -// -// Writes a byte to a given register. -// -// Returns kSTkErrOk on success -// -sfeTkError_t sfeTkArdSPI::writeRegisterByte(uint8_t devReg, uint8_t dataToWrite) -{ - - if (!_spiPort) - return kSTkErrBusNotInit; - - // 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 kSTkErrOk; -} - -//--------------------------------------------------------------------------------- -// writeRegisterWord() -// -// Writes a world to a given register. -// -// Returns kSTkErrOk on success -// -sfeTkError_t sfeTkArdSPI::writeRegisterWord(uint8_t devReg, uint16_t dataToWrite) -{ - return writeRegisterRegion(devReg, (uint8_t *)&dataToWrite, sizeof(uint8_t)) > 0; -} -//--------------------------------------------------------------------------------- -// writeRegisterRegion() -// -// Writes an array of bytes to a given register on the target address -// -// Returns kSTkErrOk on success -// -sfeTkError_t sfeTkArdSPI::writeRegisterRegion(uint8_t devReg, const uint8_t *data, size_t length) -{ - if (!_spiPort) - return kSTkErrBusNotInit; - - // Apply settings before work - _spiPort->beginTransaction(_sfeSPISettings); - - // Signal communication start - digitalWrite(cs(), LOW); - - _spiPort->transfer(devReg); - - for (size_t i = 0; i < length; i++) - _spiPort->transfer(*data++); - - // End communication - digitalWrite(cs(), HIGH); - _spiPort->endTransaction(); - - return kSTkErrOk; -} - -// 16 bit address version ... -sfeTkError_t sfeTkArdSPI::writeRegister16Region(uint16_t devReg, const uint8_t *data, size_t length) -{ - if (!_spiPort) - return kSTkErrBusNotInit; - - // Apply settings before work - _spiPort->beginTransaction(_sfeSPISettings); - - // Signal communication start - digitalWrite(cs(), LOW); - _spiPort->transfer16(devReg); - - for (size_t i = 0; i < length; i++) - _spiPort->transfer(*data++); - - // End communication - digitalWrite(cs(), HIGH); - _spiPort->endTransaction(); - - return kSTkErrOk; -} - -sfeTkError_t sfeTkArdSPI::readRegisterByte(uint8_t devReg, uint8_t &data) -{ - size_t nRead; - sfeTkError_t retval = readRegisterRegion(devReg, (uint8_t *)&data, sizeof(uint8_t), nRead); - - return (retval == kSTkErrOk && nRead == sizeof(uint8_t) ? kSTkErrOk : retval); -} - -sfeTkError_t sfeTkArdSPI::readRegisterWord(uint8_t devReg, uint16_t &data) -{ - size_t nRead; - sfeTkError_t retval = readRegisterRegion(devReg, (uint8_t *)&data, sizeof(uint16_t), nRead); - - return (retval == kSTkErrOk && nRead == sizeof(uint16_t) ? kSTkErrOk : retval); -} -//--------------------------------------------------------------------------------- -// readRegisterRegion() -// -// Reads an array of bytes to a given register on the target address -// -// Returns kSTkErrOk on success -// -sfeTkError_t sfeTkArdSPI::readRegisterRegion(uint8_t devReg, uint8_t *data, size_t numBytes, size_t &readBytes) -{ - if (!_spiPort) - return kSTkErrBusNotInit; - - // 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); - - for (size_t i = 0; i < numBytes; i++) - *data++ = _spiPort->transfer(0x00); - - // End transaction - digitalWrite(cs(), HIGH); - _spiPort->endTransaction(); - - readBytes = numBytes; - - return kSTkErrOk; -} - -//--------------------------------------------------------------------------------- -// readRegister16Region() -// -// Reads an array of bytes to a given a 16 bit register on the target address -// -// Returns kSTkErrOk on success -// -sfeTkError_t sfeTkArdSPI::readRegister16Region(uint16_t devReg, uint8_t *data, size_t numBytes, size_t &readBytes) -{ - if (!_spiPort) - return kSTkErrBusNotInit; - - // 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 kSTkErrOk; -} diff --git a/src/sfeTkArdSPI.h b/src/sfeTkArdSPI.h deleted file mode 100644 index 113853e..0000000 --- a/src/sfeTkArdSPI.h +++ /dev/null @@ -1,236 +0,0 @@ - - -// sfeTkBusSPI.h - Defines the Arduino SPI interface for the SparkFun Toolkit SDK - -/* - -The MIT License (MIT) - -Copyright (c) 2023 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. - -*/ - -#pragma once - -#include -#include - -/** - @brief This class implements the IBus interface for an SPI Implementation on Arduino - */ -class sfeTkArdSPI : public sfeTkISPI -{ - public: - /** - @brief Constructor for Arduino SPI bus object of the toolkit - */ - sfeTkArdSPI(void) : _spiPort(nullptr) - { - } - - /** - @brief Constructor for Arduino SPI bus object of the toolkit - - @param csPin The CS Pin for the device - */ - sfeTkArdSPI(uint8_t csPin) : sfeTkISPI(csPin) - { - } - /** - @brief Copy constructor for Arduino SPI bus object of the toolkit - - @param rhs source of the copy operation - */ - sfeTkArdSPI(sfeTkArdSPI const &rhs) : sfeTkISPI(), _spiPort{rhs._spiPort}, _sfeSPISettings{rhs._sfeSPISettings} - { - } - - /** - @brief Assignment copy operator for Arduino SPI bus object of the toolkit - - @param rhs The right hand side of the assignment. - @return sfeTkArdSPI& - The left hand side of the assignment. - */ - sfeTkArdSPI &operator=(const sfeTkArdSPI &rhs) - { - _spiPort = rhs._spiPort; - _sfeSPISettings = rhs._sfeSPISettings; - return *this; - } - - /** - @brief Method sets up the required SPI settings. - @note This function provides a default SPI Port. - - @param bInit Init the device - default is false. - - @retval sfeTkError_t - kSTkErrOk on success - */ - sfeTkError_t init(bool bInit = false); - - /** - @brief Method sets up the required SPI settings. - @note This function provides a default SPI Port. - - @param csPin The CS Pin for the device - @param bInit Init the device - default is false. - - @retval sfeTkError_t - kSTkErrOk on success - */ - sfeTkError_t init(uint8_t csPin, bool bInit = false); - - /** - @brief Method sets up the required SPI settings. - - @param spiPort Port for SPI communication. - @param busSPISettings Settings for speed, endianness, and spi mode of the SPI bus. - @param csPin The CS Pin for the device - @param bInit This flag tracks whether the bus has been initialized. - - @retval sfeTkError_t - kSTkErrOk on success - */ - sfeTkError_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 sfeTkError_t - kSTkErrOk on success - */ - sfeTkError_t writeByte(uint8_t data); - - /** - @brief Write a word to the device without indexing to a register. - - @param data Data to write. - - @retval sfeTkError_t - kSTkErrOk on success - */ - sfeTkError_t writeWord(uint16_t data); - - /** - @brief Write an array of data to the device without indexing to a register. - - @param data Data to write - @param length Length of Data - - @retval sfeTkError_t - kSTkErrOk on success - */ - sfeTkError_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 sfeTkError_t - kSTkErrOk on success - */ - sfeTkError_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 sfeTkError_t - kSTkErrOk on success - */ - sfeTkError_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 data Data to write. - @param length - length of data - - @retval sfeTkError_t - kSTkErrOk on success - */ - sfeTkError_t writeRegisterRegion(uint8_t devReg, const uint8_t *data, size_t length); - - /** - @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 data Data to write. - @param length - length of data - - @retval sfeTkError_t - kSTkErrOk on success - */ - sfeTkError_t writeRegister16Region(uint16_t devReg, const uint8_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 sfeTkError_t - kSTkErrOk on success - */ - sfeTkError_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 sfeTkError_t - true on success - */ - sfeTkError_t readRegisterWord(uint8_t devReg, uint16_t &data); - - /** - @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 sfeTkError_t - true on success - */ - virtual sfeTkError_t readRegisterRegion(uint8_t reg, uint8_t *data, size_t numBytes, size_t &readBytes); - - /** - @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 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 - - @retval sfeTkError_t - true on success - */ - virtual sfeTkError_t readRegister16Region(uint16_t reg, uint8_t *data, size_t numBytes, size_t &readBytes); - - protected: - // note: The instance data is protected, allowing access if a sub-class is - // created to implement a special read/write routine - // - /** Pointer to the spi port being used */ - SPIClass *_spiPort; - - /** This objects 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..03cb287 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) }