1 // Copyright 2021 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15
16 #include "pw_bytes/endian.h"
17 #include "pw_bytes/span.h"
18 #include "pw_chrono/system_clock.h"
19 #include "pw_i2c/address.h"
20 #include "pw_i2c/device.h"
21 #include "pw_i2c/initiator.h"
22 #include "pw_result/result.h"
23 #include "pw_status/status.h"
24 #include "pw_status/try.h"
25
26 namespace pw {
27 namespace i2c {
28
29 enum class RegisterAddressSize {
30 k1Byte = 1,
31 k2Bytes = 2,
32 k4Bytes = 4,
33 };
34
35 // RegisterDevice is used to write/read registers, chunks of data
36 // or just an array of bytes over a bus to a device.
37 //
38 // DISCLAIMER:
39 // It is important to note that bulk write/read may not be supported for every
40 // device and that it's up to the user to know the capabilities of their device.
41 // Users should also be aware of the register and address size and use the
42 // appropriate methods for their device.
43 //
44 // - WriteRegisters*
45 // Write to a set of registers starting at a specific address/offset.
46 // Endianness will be applied to data that's read or written.
47 //
48 // - WriteRegister*
49 // Write data to a register where the max register size is 4 bytes.
50 // Endianness will be applied to data that's read or written.
51 //
52 // - ReadRegisters*
53 // Read a set of registers starting at a specific address/offset.
54 // Endianness will be applied to data that's read or written.
55 //
56 // - ReadRegister*
57 // Read data to a register where the max register size is 4 bytes.
58 // Endianness will be applied to data that's read or written.
59 class RegisterDevice : public Device {
60 public:
61 // Args:
62 // initiator: I2C initiator for the bus the device is on.
63 // address: I2C device address.
64 // register_address_order: Endianness of the register address.
65 // data_order: Endianness of the data.
66 // register_address_size: Size of the register address.
RegisterDevice(Initiator & initiator,Address address,endian register_address_order,endian data_order,RegisterAddressSize register_address_size)67 constexpr RegisterDevice(Initiator& initiator,
68 Address address,
69 endian register_address_order,
70 endian data_order,
71 RegisterAddressSize register_address_size)
72 : Device(initiator, address),
73 register_address_order_(register_address_order),
74 data_order_(data_order),
75 register_address_size_(register_address_size) {}
76
77 // Args:
78 // initiator: I2C initiator for the bus the device is on.
79 // address: I2C device address.
80 // order: Endianness of the register address and data.
81 // register_address_size: Size of the register address.
RegisterDevice(Initiator & initiator,Address address,endian order,RegisterAddressSize register_address_size)82 constexpr RegisterDevice(Initiator& initiator,
83 Address address,
84 endian order,
85 RegisterAddressSize register_address_size)
86 : Device(initiator, address),
87 register_address_order_(order),
88 data_order_(order),
89 register_address_size_(register_address_size) {}
90
91 // Writes data to multiple contiguous registers starting at specific register.
92 // WriteRegisters has byte addressable capabilities and it is up to the user
93 // to determine the appropriate size based on the features of the device. The
94 // amount of data to write is the size of the span. Endianness is taken into
95 // account if register_data_size is 2 bytes or 4 bytes. Both address and
96 // data will use the same endianness provided by the constructor.
97 //
98 // It is important to note that bulk write may not be supported for every
99 // device and that it's up to the user to know the capabilities of their
100 // device. Args:
101 // register_address: Register address to send.
102 // register_data: Data to write.
103 // buffer: Since we need a buffer to construct the write data that consists
104 // of the register address and the register data, the buffer should
105 // be big enough such that the two can be concatenated.
106 // timeout: timeout that's used for both lock and transaction.
107 // Returns:
108 // Ok: Successful.
109 // DeadlineExceeded: Unable to acquire exclusive Initiator access and
110 // complete the I2C transaction in time.
111 // FailedPrecondition: Interface is not initialized and/or enabled.
112 // Internal: Building data for the write buffer has an issue.
113 // InvalidArgument: Device_address is larger than the 10 bit address space.
114 // OutOfRange: if buffer size is too small for data and register_address.
115 // Unavailable: if NACK and device did not respond in time.
116 Status WriteRegisters(uint32_t register_address,
117 ConstByteSpan register_data,
118 ByteSpan buffer,
119 chrono::SystemClock::duration timeout);
120
121 Status WriteRegisters8(uint32_t register_address,
122 span<const uint8_t> register_data,
123 ByteSpan buffer,
124 chrono::SystemClock::duration timeout);
125
126 Status WriteRegisters16(uint32_t register_address,
127 span<const uint16_t> register_data,
128 ByteSpan buffer,
129 chrono::SystemClock::duration timeout);
130
131 Status WriteRegisters32(uint32_t register_address,
132 span<const uint32_t> register_data,
133 ByteSpan buffer,
134 chrono::SystemClock::duration timeout);
135
136 // Reads data chunk starting at specific offset or register.
137 // ReadRegisters has byte addressable capabilities and it is up to the user
138 // to determine the appropriate size based on the features of the device. The
139 // amount of data to read is the size of the span. Endianness is taken into
140 // account for the *16 and *32 bit methods. Both address and data will use
141 // the same endianness provided by the constructor.
142 //
143 // It is important to note that bulk read may not be supported for every
144 // device and that it's up to the user to know the capabilities of their
145 // device. Args:
146 // register_address: Register address to send.
147 // return_data: Area to read data to.
148 // timeout: Timeout that's used for both lock and transaction.
149 // Returns:
150 // Ok: Successful.
151 // DeadlineExceeded: Unable to acquire exclusive Initiator access and
152 // complete the I2C transaction in time.
153 // FailedPrecondition: Interface is not initialized and/or enabled.
154 // Internal: Building data for the write buffer has an issue.
155 // InvalidArgument: Device_address is larger than the 10 bit address space.
156 // Unavailable: if NACK and device did not respond in time.
157 Status ReadRegisters(uint32_t register_address,
158 ByteSpan return_data,
159 chrono::SystemClock::duration timeout);
160
161 Status ReadRegisters8(uint32_t register_address,
162 span<uint8_t> return_data,
163 chrono::SystemClock::duration timeout);
164
165 Status ReadRegisters16(uint32_t register_address,
166 span<uint16_t> return_data,
167 chrono::SystemClock::duration timeout);
168
169 Status ReadRegisters32(uint32_t register_address,
170 span<uint32_t> return_data,
171 chrono::SystemClock::duration timeout);
172
173 // Writes the register address first before data.
174 // User should be careful which WriteRegister* API is used and should use
175 // the one that matches their register data size if not byte addressable.
176 //
177 // Both address and data will use the same endianness provided by the
178 // constructor.
179 // Args:
180 // register_address: Register address to send.
181 // register_data: Data to write.
182 // timeout: Timeout that's used for both lock and transaction.
183 // Returns:
184 // Ok: Successful.
185 // DeadlineExceeded: Unable to acquire exclusive Initiator access and
186 // complete the I2C transaction in time.
187 // FailedPrecondition: Interface is not initialized and/or enabled.
188 // Internal: Building data for the write buffer has an issue.
189 // InvalidArgument: Device_address is larger than the 10 bit address space.
190 // Unavailable: if NACK and device did not respond in time.
191 Status WriteRegister(uint32_t register_address,
192 std::byte register_data,
193 chrono::SystemClock::duration timeout);
194
195 Status WriteRegister8(uint32_t register_address,
196 uint8_t register_data,
197 chrono::SystemClock::duration timeout);
198
199 Status WriteRegister16(uint32_t register_address,
200 uint16_t register_data,
201 chrono::SystemClock::duration timeout);
202
203 Status WriteRegister32(uint32_t register_address,
204 uint32_t register_data,
205 chrono::SystemClock::duration timeout);
206
207 // Reads data from the device after sending the register address first.
208 // User should be careful which ReadRegister* API is used and should use
209 // the one that matches their register data size if not byte addressable.
210 //
211 // Both address and data will use the same endianness provided by the
212 // constructor.
213 // Args:
214 // register_address: Register address to send.
215 // timeout: Timeout that's used for both lock and transaction.
216 // Returns:
217 // Ok: Successful.
218 // DeadlineExceeded: Unable to acquire exclusive Initiator access and
219 // complete the I2C transaction in time.
220 // FailedPrecondition: Interface is not initialized and/or enabled.
221 // Internal: Building data for the write buffer has an issue.
222 // InvalidArgument: Device_address is larger than the 10 bit address space.
223 // Unavailable: if NACK and device did not respond in time.
224 Result<std::byte> ReadRegister(uint32_t register_address,
225 chrono::SystemClock::duration timeout);
226
227 Result<uint8_t> ReadRegister8(uint32_t register_address,
228 chrono::SystemClock::duration timeout);
229
230 Result<uint16_t> ReadRegister16(uint32_t register_address,
231 chrono::SystemClock::duration timeout);
232
233 Result<uint32_t> ReadRegister32(uint32_t register_address,
234 chrono::SystemClock::duration timeout);
235
236 private:
237 // Helper write registers.
238 Status WriteRegisters(uint32_t register_address,
239 ConstByteSpan register_data,
240 const size_t register_data_size,
241 ByteSpan buffer,
242 chrono::SystemClock::duration timeout);
243
244 const endian register_address_order_;
245 const endian data_order_;
246 const RegisterAddressSize register_address_size_;
247 };
248
WriteRegisters(uint32_t register_address,ConstByteSpan register_data,ByteSpan buffer,chrono::SystemClock::duration timeout)249 inline Status RegisterDevice::WriteRegisters(
250 uint32_t register_address,
251 ConstByteSpan register_data,
252 ByteSpan buffer,
253 chrono::SystemClock::duration timeout) {
254 return WriteRegisters(register_address,
255 register_data,
256 sizeof(decltype(register_data)::value_type),
257 buffer,
258 timeout);
259 }
260
WriteRegisters8(uint32_t register_address,span<const uint8_t> register_data,ByteSpan buffer,chrono::SystemClock::duration timeout)261 inline Status RegisterDevice::WriteRegisters8(
262 uint32_t register_address,
263 span<const uint8_t> register_data,
264 ByteSpan buffer,
265 chrono::SystemClock::duration timeout) {
266 return WriteRegisters(register_address,
267 as_bytes(register_data),
268 sizeof(decltype(register_data)::value_type),
269 buffer,
270 timeout);
271 }
272
WriteRegisters16(uint32_t register_address,span<const uint16_t> register_data,ByteSpan buffer,chrono::SystemClock::duration timeout)273 inline Status RegisterDevice::WriteRegisters16(
274 uint32_t register_address,
275 span<const uint16_t> register_data,
276 ByteSpan buffer,
277 chrono::SystemClock::duration timeout) {
278 return WriteRegisters(register_address,
279 as_bytes(register_data),
280 sizeof(decltype(register_data)::value_type),
281 buffer,
282 timeout);
283 }
284
WriteRegisters32(uint32_t register_address,span<const uint32_t> register_data,ByteSpan buffer,chrono::SystemClock::duration timeout)285 inline Status RegisterDevice::WriteRegisters32(
286 uint32_t register_address,
287 span<const uint32_t> register_data,
288 ByteSpan buffer,
289 chrono::SystemClock::duration timeout) {
290 return WriteRegisters(register_address,
291 as_bytes(register_data),
292 sizeof(decltype(register_data)::value_type),
293 buffer,
294 timeout);
295 }
296
WriteRegister(uint32_t register_address,std::byte register_data,chrono::SystemClock::duration timeout)297 inline Status RegisterDevice::WriteRegister(
298 uint32_t register_address,
299 std::byte register_data,
300 chrono::SystemClock::duration timeout) {
301 std::array<std::byte, sizeof(register_data) + sizeof(register_address)>
302 byte_buffer;
303 return WriteRegisters(register_address,
304 span(®ister_data, 1),
305 sizeof(register_data),
306 byte_buffer,
307 timeout);
308 }
309
WriteRegister8(uint32_t register_address,uint8_t register_data,chrono::SystemClock::duration timeout)310 inline Status RegisterDevice::WriteRegister8(
311 uint32_t register_address,
312 uint8_t register_data,
313 chrono::SystemClock::duration timeout) {
314 std::array<std::byte, sizeof(register_data) + sizeof(register_address)>
315 byte_buffer;
316 return WriteRegisters(register_address,
317 as_bytes(span(®ister_data, 1)),
318 sizeof(register_data),
319 byte_buffer,
320 timeout);
321 }
322
WriteRegister16(uint32_t register_address,uint16_t register_data,chrono::SystemClock::duration timeout)323 inline Status RegisterDevice::WriteRegister16(
324 uint32_t register_address,
325 uint16_t register_data,
326 chrono::SystemClock::duration timeout) {
327 std::array<std::byte, sizeof(register_data) + sizeof(register_address)>
328 byte_buffer;
329 return WriteRegisters(register_address,
330 as_bytes(span(®ister_data, 1)),
331 sizeof(register_data),
332 byte_buffer,
333 timeout);
334 }
335
WriteRegister32(uint32_t register_address,uint32_t register_data,chrono::SystemClock::duration timeout)336 inline Status RegisterDevice::WriteRegister32(
337 uint32_t register_address,
338 uint32_t register_data,
339 chrono::SystemClock::duration timeout) {
340 std::array<std::byte, sizeof(register_data) + sizeof(register_address)>
341 byte_buffer;
342 return WriteRegisters(register_address,
343 as_bytes(span(®ister_data, 1)),
344 sizeof(register_data),
345 byte_buffer,
346 timeout);
347 }
348
ReadRegisters8(uint32_t register_address,span<uint8_t> return_data,chrono::SystemClock::duration timeout)349 inline Status RegisterDevice::ReadRegisters8(
350 uint32_t register_address,
351 span<uint8_t> return_data,
352 chrono::SystemClock::duration timeout) {
353 // For a single byte, there's no endian data, and so we can return the
354 // data as is.
355 return ReadRegisters(
356 register_address, as_writable_bytes(return_data), timeout);
357 }
358
ReadRegisters16(uint32_t register_address,span<uint16_t> return_data,chrono::SystemClock::duration timeout)359 inline Status RegisterDevice::ReadRegisters16(
360 uint32_t register_address,
361 span<uint16_t> return_data,
362 chrono::SystemClock::duration timeout) {
363 PW_TRY(
364 ReadRegisters(register_address, as_writable_bytes(return_data), timeout));
365
366 // Post process endian information.
367 for (uint16_t& register_value : return_data) {
368 register_value = bytes::ReadInOrder<uint16_t>(data_order_, ®ister_value);
369 }
370
371 return pw::OkStatus();
372 }
373
ReadRegisters32(uint32_t register_address,span<uint32_t> return_data,chrono::SystemClock::duration timeout)374 inline Status RegisterDevice::ReadRegisters32(
375 uint32_t register_address,
376 span<uint32_t> return_data,
377 chrono::SystemClock::duration timeout) {
378 PW_TRY(
379 ReadRegisters(register_address, as_writable_bytes(return_data), timeout));
380
381 // TODO(b/185952662): Extend endian in pw_byte to support this conversion
382 // as optimization.
383 // Post process endian information.
384 for (uint32_t& register_value : return_data) {
385 register_value = bytes::ReadInOrder<uint32_t>(data_order_, ®ister_value);
386 }
387
388 return pw::OkStatus();
389 }
390
ReadRegister(uint32_t register_address,chrono::SystemClock::duration timeout)391 inline Result<std::byte> RegisterDevice::ReadRegister(
392 uint32_t register_address, chrono::SystemClock::duration timeout) {
393 std::byte data = {};
394 PW_TRY(ReadRegisters(register_address, span(&data, 1), timeout));
395 return data;
396 }
397
ReadRegister8(uint32_t register_address,chrono::SystemClock::duration timeout)398 inline Result<uint8_t> RegisterDevice::ReadRegister8(
399 uint32_t register_address, chrono::SystemClock::duration timeout) {
400 uint8_t data = 0;
401 PW_TRY(ReadRegisters8(register_address, span(&data, 1), timeout));
402 return data;
403 }
404
ReadRegister16(uint32_t register_address,chrono::SystemClock::duration timeout)405 inline Result<uint16_t> RegisterDevice::ReadRegister16(
406 uint32_t register_address, chrono::SystemClock::duration timeout) {
407 std::array<uint16_t, 1> data = {};
408 PW_TRY(ReadRegisters16(register_address, data, timeout));
409 return data[0];
410 }
411
ReadRegister32(uint32_t register_address,chrono::SystemClock::duration timeout)412 inline Result<uint32_t> RegisterDevice::ReadRegister32(
413 uint32_t register_address, chrono::SystemClock::duration timeout) {
414 std::array<uint32_t, 1> data = {};
415 PW_TRY(ReadRegisters32(register_address, data, timeout));
416 return data[0];
417 }
418
419 } // namespace i2c
420 } // namespace pw
421
422 // TODO (zengk): Register modification.
423