Krolyxon
Commit 1d55752

Branches

Tags

Refs →

orion-rf.piolibdepsesp32-s3-n16r8Adafruit BusIOAdafruit_BusIO_Register.cpp

384 lines · 12.2 KB · C++

1#include <Adafruit_BusIO_Register.h>
2
3#if !defined(SPI_INTERFACES_COUNT) || \
4 (defined(SPI_INTERFACES_COUNT) && (SPI_INTERFACES_COUNT > 0))
5
6/*!
7 * @brief Create a register we access over an I2C Device (which defines the
8 * bus and address)
9 * @param i2cdevice The I2CDevice to use for underlying I2C access
10 * @param reg_addr The address pointer value for the I2C/SMBus register, can
11 * be 8 or 16 bits
12 * @param width The width of the register data itself, defaults to 1 byte
13 * @param byteorder The byte order of the register (used when width is > 1),
14 * defaults to LSBFIRST
15 * @param address_width The width of the register address itself, defaults
16 * to 1 byte
17 */
18Adafruit_BusIO_Register::Adafruit_BusIO_Register(Adafruit_I2CDevice *i2cdevice,
19 uint16_t reg_addr,
20 uint8_t width,
21 uint8_t byteorder,
22 uint8_t address_width) {
23 _i2cdevice = i2cdevice;
24 _spidevice = nullptr;
25 _addrwidth = address_width;
26 _address = reg_addr;
27 _byteorder = byteorder;
28 _width = width;
29}
30
31/*!
32 * @brief Create a register we access over an SPI Device (which defines the
33 * bus and CS pin)
34 * @param spidevice The SPIDevice to use for underlying SPI access
35 * @param reg_addr The address pointer value for the SPI register, can
36 * be 8 or 16 bits
37 * @param type The method we use to read/write data to SPI (which is not
38 * as well defined as I2C)
39 * @param width The width of the register data itself, defaults to 1 byte
40 * @param byteorder The byte order of the register (used when width is > 1),
41 * defaults to LSBFIRST
42 * @param address_width The width of the register address itself, defaults
43 * to 1 byte
44 */
45Adafruit_BusIO_Register::Adafruit_BusIO_Register(Adafruit_SPIDevice *spidevice,
46 uint16_t reg_addr,
47 Adafruit_BusIO_SPIRegType type,
48 uint8_t width,
49 uint8_t byteorder,
50 uint8_t address_width) {
51 _spidevice = spidevice;
52 _spiregtype = type;
53 _i2cdevice = nullptr;
54 _addrwidth = address_width;
55 _address = reg_addr;
56 _byteorder = byteorder;
57 _width = width;
58}
59
60/*!
61 * @brief Create a register we access over an I2C or SPI Device. This is a
62 * handy function because we can pass in nullptr for the unused interface,
63 * allowing libraries to mass-define all the registers
64 * @param i2cdevice The I2CDevice to use for underlying I2C access, if
65 * nullptr we use SPI
66 * @param spidevice The SPIDevice to use for underlying SPI access, if
67 * nullptr we use I2C
68 * @param reg_addr The address pointer value for the I2C/SMBus/SPI register,
69 * can be 8 or 16 bits
70 * @param type The method we use to read/write data to SPI (which is not
71 * as well defined as I2C)
72 * @param width The width of the register data itself, defaults to 1 byte
73 * @param byteorder The byte order of the register (used when width is > 1),
74 * defaults to LSBFIRST
75 * @param address_width The width of the register address itself, defaults
76 * to 1 byte
77 */
78Adafruit_BusIO_Register::Adafruit_BusIO_Register(
79 Adafruit_I2CDevice *i2cdevice, Adafruit_SPIDevice *spidevice,
80 Adafruit_BusIO_SPIRegType type, uint16_t reg_addr, uint8_t width,
81 uint8_t byteorder, uint8_t address_width) {
82 _spidevice = spidevice;
83 _i2cdevice = i2cdevice;
84 _spiregtype = type;
85 _addrwidth = address_width;
86 _address = reg_addr;
87 _byteorder = byteorder;
88 _width = width;
89}
90
91/*!
92 * @brief Create a register we access over a GenericDevice
93 * @param genericdevice Generic device to use
94 * @param reg_addr Register address we will read/write
95 * @param width Width of the register in bytes (1-4)
96 * @param byteorder Byte order of register data (LSBFIRST or MSBFIRST)
97 * @param address_width Width of the register address in bytes (1 or 2)
98 */
99Adafruit_BusIO_Register::Adafruit_BusIO_Register(
100 Adafruit_GenericDevice *genericdevice, uint16_t reg_addr, uint8_t width,
101 uint8_t byteorder, uint8_t address_width) {
102 _i2cdevice = nullptr;
103 _spidevice = nullptr;
104 _genericdevice = genericdevice;
105 _addrwidth = address_width;
106 _address = reg_addr;
107 _byteorder = byteorder;
108 _width = width;
109}
110
111/*!
112 * @brief Write a buffer of data to the register location
113 * @param buffer Pointer to data to write
114 * @param len Number of bytes to write
115 * @return True on successful write (only really useful for I2C as SPI is
116 * uncheckable)
117 */
118bool Adafruit_BusIO_Register::write(uint8_t *buffer, uint8_t len) {
119 uint8_t addrbuffer[2] = {(uint8_t)(_address & 0xFF),
120 (uint8_t)(_address >> 8)};
121 if (_i2cdevice) {
122 return _i2cdevice->write(buffer, len, true, addrbuffer, _addrwidth);
123 }
124 if (_spidevice) {
125 if (_spiregtype == ADDRESSED_OPCODE_BIT0_LOW_TO_WRITE) {
126 // very special case!
127 // pass the special opcode address which we set as the high byte of the
128 // regaddr
129 addrbuffer[0] =
130 (uint8_t)(_address >> 8) & ~0x01; // set bottom bit low to write
131 // the 'actual' reg addr is the second byte then
132 addrbuffer[1] = (uint8_t)(_address & 0xFF);
133 // the address appears to be a byte longer
134 return _spidevice->write(buffer, len, addrbuffer, _addrwidth + 1);
135 }
136 if (_spiregtype == ADDRBIT8_HIGH_TOREAD) {
137 addrbuffer[0] &= ~0x80;
138 }
139 if (_spiregtype == ADDRBIT8_HIGH_TOWRITE) {
140 addrbuffer[0] |= 0x80;
141 }
142 if (_spiregtype == AD8_HIGH_TOREAD_AD7_HIGH_TOINC) {
143 addrbuffer[0] &= ~0x80;
144 addrbuffer[0] |= 0x40;
145 }
146 return _spidevice->write(buffer, len, addrbuffer, _addrwidth);
147 }
148 if (_genericdevice) {
149 return _genericdevice->writeRegister(addrbuffer, _addrwidth, buffer, len);
150 }
151 return false;
152}
153
154/*!
155 * @brief Write up to 4 bytes of data to the register location
156 * @param value Data to write
157 * @param numbytes How many bytes from 'value' to write
158 * @return True on successful write (only really useful for I2C as SPI is
159 * uncheckable)
160 */
161bool Adafruit_BusIO_Register::write(uint32_t value, uint8_t numbytes) {
162 if (numbytes == 0) {
163 numbytes = _width;
164 }
165 if (numbytes > 4) {
166 return false;
167 }
168
169 // store a copy
170 _cached = value;
171
172 for (int i = 0; i < numbytes; i++) {
173 if (_byteorder == LSBFIRST) {
174 _buffer[i] = value & 0xFF;
175 } else {
176 _buffer[numbytes - i - 1] = value & 0xFF;
177 }
178 value >>= 8;
179 }
180 return write(_buffer, numbytes);
181}
182
183/*!
184 * @brief Read data from the register location. This does not do any error
185 * checking!
186 * @return Returns 0xFFFFFFFF on failure, value otherwise
187 */
188uint32_t Adafruit_BusIO_Register::read(void) {
189 if (!read(_buffer, _width)) {
190 return -1;
191 }
192
193 uint32_t value = 0;
194
195 for (int i = 0; i < _width; i++) {
196 value <<= 8;
197 if (_byteorder == LSBFIRST) {
198 value |= _buffer[_width - i - 1];
199 } else {
200 value |= _buffer[i];
201 }
202 }
203
204 return value;
205}
206
207/*!
208 * @brief Read cached data from last time we wrote to this register
209 * @return Returns 0xFFFFFFFF on failure, value otherwise
210 */
211uint32_t Adafruit_BusIO_Register::readCached(void) { return _cached; }
212
213/*!
214 @brief Read a number of bytes from a register into a buffer
215 @param buffer Buffer to read data into
216 @param len Number of bytes to read into the buffer
217 @return true on successful read, otherwise false
218*/
219bool Adafruit_BusIO_Register::read(uint8_t *buffer, uint8_t len) {
220 uint8_t addrbuffer[2] = {(uint8_t)(_address & 0xFF),
221 (uint8_t)(_address >> 8)};
222 if (_i2cdevice) {
223 return _i2cdevice->write_then_read(addrbuffer, _addrwidth, buffer, len);
224 }
225 if (_spidevice) {
226 if (_spiregtype == ADDRESSED_OPCODE_BIT0_LOW_TO_WRITE) {
227 // very special case!
228 // pass the special opcode address which we set as the high byte of the
229 // regaddr
230 addrbuffer[0] =
231 (uint8_t)(_address >> 8) | 0x01; // set bottom bit high to read
232 // the 'actual' reg addr is the second byte then
233 addrbuffer[1] = (uint8_t)(_address & 0xFF);
234 // the address appears to be a byte longer
235 return _spidevice->write_then_read(addrbuffer, _addrwidth + 1, buffer,
236 len);
237 }
238 if (_spiregtype == ADDRBIT8_HIGH_TOREAD) {
239 addrbuffer[0] |= 0x80;
240 }
241 if (_spiregtype == ADDRBIT8_HIGH_TOWRITE) {
242 addrbuffer[0] &= ~0x80;
243 }
244 if (_spiregtype == AD8_HIGH_TOREAD_AD7_HIGH_TOINC) {
245 addrbuffer[0] |= 0x80 | 0x40;
246 }
247 return _spidevice->write_then_read(addrbuffer, _addrwidth, buffer, len);
248 }
249 if (_genericdevice) {
250 return _genericdevice->readRegister(addrbuffer, _addrwidth, buffer, len);
251 }
252 return false;
253}
254
255/*!
256 * @brief Read 2 bytes of data from the register location
257 * @param value Pointer to uint16_t variable to read into
258 * @return True on successful write (only really useful for I2C as SPI is
259 * uncheckable)
260 */
261bool Adafruit_BusIO_Register::read(uint16_t *value) {
262 if (!read(_buffer, 2)) {
263 return false;
264 }
265
266 if (_byteorder == LSBFIRST) {
267 *value = _buffer[1];
268 *value <<= 8;
269 *value |= _buffer[0];
270 } else {
271 *value = _buffer[0];
272 *value <<= 8;
273 *value |= _buffer[1];
274 }
275 return true;
276}
277
278/*!
279 * @brief Read 1 byte of data from the register location
280 * @param value Pointer to uint8_t variable to read into
281 * @return True on successful write (only really useful for I2C as SPI is
282 * uncheckable)
283 */
284bool Adafruit_BusIO_Register::read(uint8_t *value) {
285 if (!read(_buffer, 1)) {
286 return false;
287 }
288
289 *value = _buffer[0];
290 return true;
291}
292
293/*!
294 * @brief Pretty printer for this register
295 * @param s The Stream to print to, defaults to &Serial
296 */
297void Adafruit_BusIO_Register::print(Stream *s) {
298 uint32_t val = read();
299 s->print("0x");
300 s->print(val, HEX);
301}
302
303/*!
304 * @brief Pretty printer for this register
305 * @param s The Stream to print to, defaults to &Serial
306 */
307void Adafruit_BusIO_Register::println(Stream *s) {
308 print(s);
309 s->println();
310}
311
312/*!
313 * @brief Create a slice of the register that we can address without
314 * touching other bits
315 * @param reg The Adafruit_BusIO_Register which defines the bus/register
316 * @param bits The number of bits wide we are slicing
317 * @param shift The number of bits that our bit-slice is shifted from LSB
318 */
319Adafruit_BusIO_RegisterBits::Adafruit_BusIO_RegisterBits(
320 Adafruit_BusIO_Register *reg, uint8_t bits, uint8_t shift) {
321 _register = reg;
322 _bits = bits;
323 _shift = shift;
324}
325
326/*!
327 * @brief Read 4 bytes of data from the register
328 * @return data The 4 bytes to read
329 */
330uint32_t Adafruit_BusIO_RegisterBits::read(void) {
331 uint32_t val = _register->read();
332 val >>= _shift;
333 return val & ((1 << (_bits)) - 1);
334}
335
336/*!
337 * @brief Write 4 bytes of data to the register
338 * @param data The 4 bytes to write
339 * @return True on successful write (only really useful for I2C as SPI is
340 * uncheckable)
341 */
342bool Adafruit_BusIO_RegisterBits::write(uint32_t data) {
343 uint32_t val = _register->read();
344
345 // mask off the data before writing
346 uint32_t mask = (1 << (_bits)) - 1;
347 data &= mask;
348
349 mask <<= _shift;
350 val &= ~mask; // remove the current data at that spot
351 val |= data << _shift; // and add in the new data
352
353 return _register->write(val, _register->width());
354}
355
356/*!
357 * @brief The width of the register data, helpful for doing calculations
358 * @returns The data width used when initializing the register
359 */
360uint8_t Adafruit_BusIO_Register::width(void) { return _width; }
361
362/*!
363 * @brief Set the default width of data
364 * @param width the default width of data read from register
365 */
366void Adafruit_BusIO_Register::setWidth(uint8_t width) { _width = width; }
367
368/*!
369 * @brief Set register address
370 * @param address the address from register
371 */
372void Adafruit_BusIO_Register::setAddress(uint16_t address) {
373 _address = address;
374}
375
376/*!
377 * @brief Set the width of register address
378 * @param address_width the width for register address
379 */
380void Adafruit_BusIO_Register::setAddressWidth(uint16_t address_width) {
381 _addrwidth = address_width;
382}
383
384#endif // SPI exists