Skip to content

Commit 55bc035

Browse files
authored
Merge pull request #14 from sparkfun/kdb_concept
Move the concept to main for completion
2 parents d116d33 + 9352fa8 commit 55bc035

File tree

16 files changed

+1167
-457
lines changed

16 files changed

+1167
-457
lines changed

docs/ar_ibus.md

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
# Overview - Device Bus interface - sfeTkIBus
2+
3+
One of the foundational capabilities of the SparkFun Toolkit is bus communication with devices. This is a common task almost all libraries implement using their own implementation for I2C, SPI or UART bus communication.
4+
5+
For bus communication, the SparkFun Toolkit is designed to provide a common implementation for use across all SparkFun libraries. Additionally, the bus architecture is modeled on a *driver* pattern, separating the individual bus setup/configuration from data communication, enabling a single device implementation to easily support a variety of device bus types.
6+
7+
The key goals set for the Bus implementation in the Toolkit include:
8+
9+
* Separate device setup from device communication
10+
* Define a common bus interface for use across a variety of common device bus types
11+
* Deliver support for both SPI and I2C bus types initially, focusing on Arduino
12+
* Structure the bus/toolkit implementation such that it's platform independent
13+
14+
## Architecture Overview
15+
16+
To meet the goals for this subsystem, the Flux framework follows a ***Driver Pattern***, defining a common interface for bus communication. Device drivers are designed around this interface, leaving bus configuration and implementation to platform specific implementation.
17+
18+
The key class to support this pattern are:
19+
20+
| | |
21+
|------|-------|
22+
**sfeTkIBus** | A virtual C++ class that device the bus ```sfeTkIBus``` interface |
23+
**sfeTkII2C** | Sub-class of the ```sfeTkIIBus``` interface, it provides an interface for I2C devices|
24+
**sfeTkISPI** | Sub-class of the ```sfeTkIIBus``` interface, it provides an interface for SPI devices |
25+
26+
### The sfeTkIBus Interface
27+
28+
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.
29+
30+
The interface methods:
31+
32+
| Method| Definition |
33+
|------|-------|
34+
**writeRegisterByte** | Write a byte of data to a particular register of a device |
35+
**writeRegisterWord** | Write a word of data to a particular register of a device |
36+
**writeRegisterRegion** | Write an array of data to a particular register of a device|
37+
**readRegisterByte** | Read a byte of data from a particular register of a device |
38+
**readRegisterWord** | Read a word of data from a particular register of a device |
39+
**readRegisterRegion** | Read an array of data from a particular register of a device |
40+
41+
> [!NOTE]
42+
> 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.
43+
44+
### The sfeTkII2C Implementation
45+
46+
This class sub-classes from the ```sfeTkIBus``` interface adding additional functionally focused on supporting an I2C implementation. This interface provides the additional functionality.
47+
48+
| Method| Definition |
49+
|------|-------|
50+
**ping** | Determine if a devices is connected to the I2C device at the address set on this bus object. This is an interface method |
51+
**setAddress** | Set the I2C address to use for this I2C object |
52+
**address** | Returns the address used by this I2C object |
53+
54+
> [!NOTE]
55+
> The ```sfeTkII2C``` class manages the device address for the I2C bus. As such, each I2C device instantiates/uses an instance of the ```sfeTkII2C``` class.
56+
57+
### The sfeTkISPI Implementation
58+
59+
This class sub-classes from the ```sfeTkIBus``` interface adding additional functionally focused on supporting an SPI implementation. This interface provides the additional functionality.
60+
61+
| Method| Definition |
62+
|------|-------|
63+
**setCS** | Set the CS Pin to use for this SPI object |
64+
**cs** | Returns the CS Pin used by this SPI object |
65+
66+
> [!NOTE]
67+
> The ```sfeTkISPI``` class manages CS Pin for the SPI bus. As such, each SPI device instantiates/uses an instance of the ```sfeTkISPI``` class.
68+
69+
The class diagram of these base class interfaces/implementation:
70+
71+
![IBus diagram](images/tk_IBUS.png)
72+
73+
## sfeTkIIBus - Arduino Implementation
74+
75+
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.
76+
77+
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.
78+
79+
> [!IMPORTANT]
80+
> The intent is that each user of an particular bus - a device in most cases - contains an instance of the specific bus object.
81+
82+
The class diagram for the Arduino implementation is as follows:
83+
84+
![Arduino IBus Implementation](images/tk_ibus_ard.png)
85+
86+
### The sfeTkArdI2C Class
87+
88+
This class provides the Arduino implementation of I2C in the SparkFun Toolkit. It implements the methods of the ```sfeTkIIBus``` and ```sfeTkII2C``` interfaces, as well as manages any Arduino specific state.
89+
90+
### The sfeTkArdSPI Class
91+
92+
This class provides the Arduino implementation of SPI in the SparkFun Toolkit. It implements the methods of the ```sfeTkIIBus``` and ```sfeTkISPI``` interfaces, as well as manages any Arduino specific state for the SPI bus - namely the SPISettings class.
93+
94+
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.
95+
96+
## sfeTkIBus Use
97+
98+
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.
99+
100+
The general pattern for a device driver implementation that uses the SparkFun Toolkit is the following:
101+
102+
### Implement a Platform Independent Driver
103+
104+
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 ```sfeTkIIBus``` interface.
105+
106+
>[!IMPORTANT]
107+
> At this level, the driver is only using a ```sfeTkIBus``` interface, not any specific bus implementation.
108+
109+
This driver has the following unique functionality:
110+
111+
1) A method to set the object that implements the ```sfeTkIBus``` interface object should use. Since
112+
1) If the device supports identification capabilities, the driver provides this functionality.
113+
114+
#### SImple Example of an Independent Driver Implementation
115+
116+
This implementation would take the following form:
117+
118+
```c++
119+
120+
class myDriverClass
121+
{
122+
public:
123+
124+
myDriverClass(uint8_t address) : _addr{address}{}
125+
126+
bool begin()
127+
{
128+
// initialize things ...
129+
130+
return true;
131+
}
132+
void setCommunicationBus(sfeTkIBus *theBus)
133+
{
134+
_theBus = theBus;
135+
}
136+
137+
bool updateDeviceData(uint8_t *data, size_t len)
138+
{
139+
if (!_theBus || !data || len == 0)
140+
return false;
141+
142+
int status = _theBus->writeRegisterRegion(THE_REG, data, len);
143+
144+
return (status == 0);
145+
}
146+
147+
bool checkDeviceID()
148+
{
149+
// do some device ID checks in registers ...etc
150+
return true;
151+
}
152+
private:
153+
sfeTkIBus *_theBus;
154+
};
155+
```
156+
157+
### Write a Platform Specific Driver, based on the core driver
158+
159+
This driver sub-classes from the general/core driver class, builds and configures the desired bus object and passes this into the core driver.
160+
161+
The key concepts for these Platform specific drivers include:
162+
163+
1) Perform any platform specific bus setup during the instantiation of the device. This might just be setting the target (pin, address) for the device on the bus.
164+
1) Implement any bus specific device identification use at this level. For example, on I2C, a ping call might be made on the bus before a more detailed identification method is used.
165+
166+
#### Basic concept - creating an I2C class in Arduino
167+
168+
The following is an example of an I2C class in Arduino based on the previous platform independent driver.
169+
170+
> [!NOTE]
171+
> This class implements a ```isConnected()``` method that calls the ```ping()``` method of the I2C bus class being used, and if this passes, then calls the ```checkDeviceID()``` method of the superclass.
172+
173+
```c++
174+
175+
class myArduinoDriverI2C : public myDriverClass
176+
{
177+
public:
178+
myArduinoDriverI2C()
179+
{}
180+
181+
bool begin()
182+
{
183+
if (!_theI2CBus.init(MY_DEVICE_ADDRESS))
184+
return false;
185+
setCommunicationBus(&_theI2CBus);
186+
187+
return myDriverClass::begin();
188+
}
189+
190+
bool isConnected()
191+
{
192+
if (!_theI2CBus.ping())
193+
return false;
194+
195+
return checkDeviceID();
196+
}
197+
198+
private:
199+
sfeTkArdI2C _theI2CBus;
200+
};
201+
```
202+
203+
#### Basic concept - creating an SPI class in Arduino
204+
205+
The following is a SPI version of the driver implemented in Arduino. While similar to the I2C implementation, it focuses on the specific needs of the SPI bus, specifically the ```SPISettings``` this particular device requires when using the SPI bus.
206+
207+
> [!NOTE]
208+
> This class implements a ```isConnected()``` method that just calls the superclasses ```checkDeviceID()``` method to determine if the device is available on the bus.
209+
210+
```c++
211+
212+
class myArduinoDriveSPI : public myDriverClass
213+
{
214+
public:
215+
myArduinoDriverSPI()
216+
{}
217+
218+
bool begin()
219+
{
220+
SPISettings spiSettings = SPISettings(4000000, MSBFIRST, SPI_MODE3);
221+
222+
if (!_theSPIBus.init(SPI, spiSettings, MY_DEFAULT_CS, true))
223+
return false;
224+
setCommunicationBus(&_theSPIBus);
225+
226+
return myDriverClass::begin();
227+
}
228+
229+
bool isConnected()
230+
{
231+
return checkDeviceID();
232+
}
233+
234+
private:
235+
sfeTkArdSPI _theSPIBus;
236+
};
237+
```

docs/docs.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

docs/images/tk_IBUS.png

100 KB
Loading

docs/images/tk_ibus_ard.png

198 KB
Loading

src/SparkFun_Toolkit.h

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,33 @@
1-
// Code!
1+
2+
/*
3+
SparkFun_Toolkit.h
4+
5+
The MIT License (MIT)
6+
7+
Copyright (c) 2022 SparkFun Electronics
8+
Permission is hereby granted, free of charge, to any person obtaining a
9+
copy of this software and associated documentation files (the "Software"),
10+
to deal in the Software without restriction, including without limitation
11+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
12+
and/or sell copies of the Software, and to permit persons to whom the
13+
Software is furnished to do so, subject to the following conditions: The
14+
above copyright notice and this permission notice shall be included in all
15+
copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
16+
"AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
17+
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
18+
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
19+
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
SOFTWARE.
21+
*/
22+
23+
#pragma once
24+
25+
// Purpose:
26+
//
27+
// The SparkFun Toolkit provides a set of common implementations used throughout our (and others)
28+
// Arduino Libraries.
29+
30+
// Just include the toolkit headers
31+
32+
#include "sfeTkArdI2C.h"
33+
#include "sfeTkArdSPI.h"
Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
2+
// sfeTkIBus.h
3+
//
4+
// Defines the communication bus interface for the SparkFun Electronics Toolkit -> sfeTk
15
/*
2-
sfe_bus.h
36
47
The MIT License (MIT)
58
@@ -18,46 +21,70 @@ PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
1821
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
1922
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2023
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21-
22-
The following virtual class provides an abstract communication interface.
23-
2424
*/
2525

2626
#pragma once
2727

2828
#include <cstdint>
2929

30-
// To repeatedly use this toolkit, you may need to wrap this class in a namespace.
31-
// namespace sfe_XXX {
32-
33-
// The following abstract class is used an interface for upstream implementation.
34-
class SfeBus
30+
class sfeTkIBus
3531
{
3632
public:
37-
/// @brief A simple ping of the device at the given address.
38-
/// @param devAddr Address of the device
39-
virtual bool ping(uint8_t devAddr) = 0;
40-
4133
/// @brief Write a single byte to the given register
42-
/// @param devAddr The device's I2C address.
34+
///
35+
/// @param devReg The device's register's address.
36+
/// @param data Data to write.
37+
///
38+
/// @retval bool - true on successful execution.
39+
///
40+
virtual bool writeRegisterByte(uint8_t devReg, uint8_t data) = 0;
41+
42+
/// @brief Write a single word (16 bit) to the given register
43+
///
4344
/// @param devReg The device's register's address.
4445
/// @param data Data to write.
45-
/// @brief returns true on successful execution.
46-
virtual bool writeRegisterByte(uint8_t devAddr, uint8_t devReg, uint8_t data) = 0;
46+
///
47+
/// @retval bool - true on successful execution.
48+
///
49+
virtual bool writeRegisterWord(uint8_t devReg, uint16_t data) = 0;
4750

4851
/// @brief Writes a number of bytes starting at the given register's address.
49-
/// @param devAddr The device's I2C address.
52+
///
53+
/// @param devAddr The device's address/pin
5054
/// @param devReg The device's register's address.
5155
/// @param data Data to write.
52-
/// @brief returns true on successful execution.
53-
virtual int writeRegisterRegion(uint8_t devAddr, uint8_t devReg, const uint8_t *data, uint16_t length) = 0;
56+
///
57+
/// @retval int returns the number of bytes written, < 0 on error
58+
///
59+
virtual int writeRegisterRegion(uint8_t devReg, const uint8_t *data, size_t length) = 0;
60+
61+
/// @brief Read a single byte from the given register
62+
///
63+
/// @param devReg The device's register's address.
64+
/// @param data Data to read.
65+
///
66+
/// @retval bool - true on successful execution.
67+
///
68+
virtual bool readRegisterByte(uint8_t devReg, uint8_t &data) = 0;
69+
70+
/// @brief Read a single word (16 bit) from the given register
71+
///
72+
/// @param devReg The device's register's address.
73+
/// @param data Data to read.
74+
///
75+
/// @retval bool - true on successful execution.
76+
///
77+
virtual bool readRegisterWord(uint8_t devReg, uint16_t &data) = 0;
5478

5579
/// @brief Reads a block of data from the given register.
80+
///
5681
/// @param devAddr The device's I2C address.
5782
/// @param devReg The device's register's address.
5883
/// @param data Data to write.
59-
/// @brief returns true on successful execution.
60-
virtual int readRegisterRegion(uint8_t addr, uint8_t reg, uint8_t *data, uint16_t numBytes) = 0;
84+
///
85+
/// @retval int returns 0 on success, or error code
86+
///
87+
virtual int readRegisterRegion(uint8_t reg, uint8_t *data, size_t numBytes) = 0;
6188
};
6289

6390
//};

0 commit comments

Comments
 (0)