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 // 15 #pragma once 16 17 #include "pw_bytes/span.h" 18 #include "pw_chrono/system_clock.h" 19 #include "pw_i2c/address.h" 20 #include "pw_i2c/initiator.h" 21 #include "pw_status/status.h" 22 23 namespace pw { 24 namespace i2c { 25 26 // Device is used to write/read arbitrary chunks of data over a bus to a device. 27 // This object essentially just wrap the Initiator API with a fixed I2C device 28 // address. 29 class Device { 30 public: Device(Initiator & initiator,Address device_address)31 constexpr Device(Initiator& initiator, Address device_address) 32 : initiator_(initiator), device_address_(device_address) {} 33 34 Device(const Device&) = delete; 35 ~Device() = default; 36 37 // Write bytes and then read bytes as either one atomic or two independent I2C 38 // transaction. 39 // The signal on the bus should appear as follows: 40 // 1) Write Only: 41 // START + I2C Address + WRITE(0) + TX_BUFFER_BYTES + STOP 42 // 2) Read Only: 43 // START + I2C Address + READ(1) + RX_BUFFER_BYTES + STOP 44 // 3A) Write + Read (atomic): 45 // START + I2C Address + WRITE(0) + TX_BUFFER_BYTES + 46 // START + I2C Address + READ(1) + RX_BUFFER_BYTES + STOP 47 // 3B) Write + Read (separate): 48 // START + I2C Address + WRITE(0) + TX_BUFFER_BYTES + STOP 49 // START + I2C Address + READ(1) + RX_BUFFER_BYTES + STOP 50 // 51 // The timeout defines the minimum duration one may block waiting for both 52 // exclusive bus access and the completion of the I2C transaction. 53 // 54 // Preconditions: 55 // The Address must be supported by the Initiator, i.e. do not use a 10 56 // address if the Initiator only supports 7 bit. This will assert. 57 // 58 // Returns: 59 // Ok - Success. 60 // InvalidArgument - device_address is larger than the 10 bit address space. 61 // DeadlineExceeded - Was unable to acquire exclusive Initiator access 62 // and complete the I2C transaction in time. 63 // Unavailable - NACK condition occurred, meaning the addressed device did 64 // not respond or was unable to process the request. 65 // FailedPrecondition - The interface is not currently initialized and/or 66 // enabled. WriteReadFor(ConstByteSpan tx_buffer,ByteSpan rx_buffer,chrono::SystemClock::duration timeout)67 Status WriteReadFor(ConstByteSpan tx_buffer, 68 ByteSpan rx_buffer, 69 chrono::SystemClock::duration timeout) { 70 return initiator_.WriteReadFor( 71 device_address_, tx_buffer, rx_buffer, timeout); 72 } WriteReadFor(const void * tx_buffer,size_t tx_size_bytes,void * rx_buffer,size_t rx_size_bytes,chrono::SystemClock::duration timeout)73 Status WriteReadFor(const void* tx_buffer, 74 size_t tx_size_bytes, 75 void* rx_buffer, 76 size_t rx_size_bytes, 77 chrono::SystemClock::duration timeout) { 78 return initiator_.WriteReadFor(device_address_, 79 tx_buffer, 80 tx_size_bytes, 81 rx_buffer, 82 rx_size_bytes, 83 timeout); 84 } 85 86 // Write bytes. The signal on the bus should appear as follows: 87 // START + I2C Address + WRITE(0) + TX_BUFFER_BYTES + STOP 88 // 89 // The timeout defines the minimum duration one may block waiting for both 90 // exclusive bus access and the completion of the I2C transaction. 91 // 92 // Preconditions: 93 // The Address must be supported by the Initiator, i.e. do not use a 10 94 // address if the Initiator only supports 7 bit. This will assert. 95 // 96 // Returns: 97 // Ok - Success. 98 // InvalidArgument - device_address is larger than the 10 bit address space. 99 // DeadlineExceeded - Was unable to acquire exclusive Initiator access 100 // and complete the I2C transaction in time. 101 // Unavailable - NACK condition occurred, meaning the addressed device did 102 // not respond or was unable to process the request. 103 // FailedPrecondition - The interface is not currently initialized and/or 104 // enabled. WriteFor(ConstByteSpan tx_buffer,chrono::SystemClock::duration timeout)105 Status WriteFor(ConstByteSpan tx_buffer, 106 chrono::SystemClock::duration timeout) { 107 return initiator_.WriteFor(device_address_, tx_buffer, timeout); 108 } WriteFor(const void * tx_buffer,size_t tx_size_bytes,chrono::SystemClock::duration timeout)109 Status WriteFor(const void* tx_buffer, 110 size_t tx_size_bytes, 111 chrono::SystemClock::duration timeout) { 112 return initiator_.WriteFor( 113 device_address_, tx_buffer, tx_size_bytes, timeout); 114 } 115 116 // Read bytes. The signal on the bus should appear as follows: 117 // START + I2C Address + READ(1) + RX_BUFFER_BYTES + STOP 118 // 119 // The timeout defines the minimum duration one may block waiting for both 120 // exclusive bus access and the completion of the I2C transaction. 121 // 122 // Preconditions: 123 // The Address must be supported by the Initiator, i.e. do not use a 10 124 // address if the Initiator only supports 7 bit. This will assert. 125 // 126 // Returns: 127 // Ok - Success. 128 // InvalidArgument - device_address is larger than the 10 bit address space. 129 // DeadlineExceeded - Was unable to acquire exclusive Initiator access 130 // and complete the I2C transaction in time. 131 // Unavailable - NACK condition occurred, meaning the addressed device did 132 // not respond or was unable to process the request. 133 // FailedPrecondition - The interface is not currently initialized and/or 134 // enabled. ReadFor(ByteSpan rx_buffer,chrono::SystemClock::duration timeout)135 Status ReadFor(ByteSpan rx_buffer, chrono::SystemClock::duration timeout) { 136 return initiator_.ReadFor(device_address_, rx_buffer, timeout); 137 } ReadFor(void * rx_buffer,size_t rx_size_bytes,chrono::SystemClock::duration timeout)138 Status ReadFor(void* rx_buffer, 139 size_t rx_size_bytes, 140 chrono::SystemClock::duration timeout) { 141 return initiator_.ReadFor( 142 device_address_, rx_buffer, rx_size_bytes, timeout); 143 } 144 145 // Probes the device for an I2C ACK after only writing the address. 146 // This is done by attempting to read a single byte from the specified device. 147 // 148 // The timeout defines the minimum duration one may block waiting for both 149 // exclusive bus access and the completion of the I2C transaction. 150 // 151 // Preconditions: 152 // The Address must be supported by the Initiator, i.e. do not use a 10 153 // address if the Initiator only supports 7 bit. This will assert. 154 // 155 // Returns: 156 // Ok - Success. 157 // InvalidArgument - device_address is larger than the 10 bit address space. 158 // DeadlineExceeded - Was unable to acquire exclusive Initiator access 159 // and complete the I2C transaction in time. 160 // Unavailable - NACK condition occurred, meaning the addressed device did 161 // not respond or was unable to process the request. 162 // FailedPrecondition - The interface is not currently initialized and/or 163 // enabled. ProbeFor(chrono::SystemClock::duration timeout)164 Status ProbeFor(chrono::SystemClock::duration timeout) { 165 return initiator_.ProbeDeviceFor(device_address_, timeout); 166 } 167 168 private: 169 Initiator& initiator_; 170 const Address device_address_; 171 }; 172 173 } // namespace i2c 174 } // namespace pw 175